/*************************************************************************** * (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License (LGPL) * * as published by the Free Software Foundation; either version 2 of * * the License, or (at your option) any later version. * * for detail see the LICENCE text file. * * * * FreeCAD is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with FreeCAD; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * * USA * * * * Juergen Riegel 2002 * ***************************************************************************/ #ifndef BASE_OBSERVER_H #define BASE_OBSERVER_H // Std. configurations #include #include #include #include #include #include "Exception.h" #include "Console.h" namespace Base { template class Subject; /** Observer class * Implementation of the well known Observer Design Pattern. * The observed object, which inherit FCSubject, will call all * its observers in case of changes. A observer class has to * Attach itself to the observed object. * @see FCSubject */ template class Observer { public: /** * A constructor. * No special function so far. */ Observer(){} /** * A destructor. * No special function so far. */ virtual ~Observer(){} /** * This method need to be reimplemented from the concrete Observer * and get called by the observed class * @param rCaller a reference to the calling object * @param rcReason * \todo undocumented parameter 2 */ virtual void OnChange(Subject<_MessageType>& rCaller,_MessageType rcReason)=0; /** * This method need to be reimplemented from the concrete Observer * and get called by the observed class * @param rCaller a reference to the calling object */ virtual void OnDestroy(Subject<_MessageType> & rCaller) { (void)rCaller; } /** * This method can be reimplemented from the concrete Observer * and returns the name of the observer. Needed to use the Get * Method of the Subject. */ virtual const char *Name(void){return 0L;} }; /** Subject class * Implementation of the well known Observer Design Pattern. * The observed object, which inherit FCSubject, will call all * its observers in case of changes. A observer class has to * Attach itself to the observed object. * @see FCObserver */ template class Subject { public: typedef Observer<_MessageType> ObserverType; typedef _MessageType MessageType; typedef Subject<_MessageType> SubjectType; /** * A constructor. * No special function so far. */ Subject(){} /** * A destructor. * No special function so far. */ virtual ~Subject() { if (_ObserverSet.size() > 0) { printf("Not detached all observers yet\n"); assert(0); } } /** Attach an Observer * Attach an Observer to the list of Observers which get * called when Notify is called. * @param ToObserv A pointer to a concrete Observer * @see Notify */ void Attach(Observer<_MessageType> *ToObserv) { #ifdef FC_DEBUG size_t count = _ObserverSet.size(); //printf("Attach observer %p\n", ToObserv); _ObserverSet.insert(ToObserv); if ( _ObserverSet.size() == count ) printf("Observer %p already attached\n", ToObserv); #else _ObserverSet.insert(ToObserv); #endif } /** Detach an Observer * Detach an Observer from the list of Observers which get * called when Notify is called. * @param ToObserv A pointer to a concrete Observer * @see Notify */ void Detach(Observer<_MessageType> *ToObserv) { #ifdef FC_DEBUG size_t count = _ObserverSet.size(); //printf("Detach observer %p\n", ToObserv); _ObserverSet.erase(ToObserv); if ( _ObserverSet.size() == count ) printf("Observer %p already detached\n", ToObserv); #else _ObserverSet.erase(ToObserv); #endif } /** Notify all Observers * Send a message to all Observers attached to this subject. * The Message depends on the implementation of a concrete * Oberserver and Subject. * @see Notify */ void Notify(_MessageType rcReason) { for(typename std::set * >::iterator Iter=_ObserverSet.begin();Iter!=_ObserverSet.end();++Iter) { try { (*Iter)->OnChange(*this,rcReason); // send OnChange-signal } catch (Base::Exception &e) { Base::Console().Error("Unhandled Base::Exception caught when notifying observer.\n" "The error message is: %s\n", e.what()); } catch (std::exception &e) { Base::Console().Error("Unhandled std::exception caught when notifying observer\n" "The error message is: %s\n", e.what()); } catch (...) { Base::Console().Error("Unhandled unknown exception caught in when notifying observer.\n"); } } } /** Get an Observer by name * Get a observer by name if the observer reimplements the Name() mthode. * @see Observer */ Observer<_MessageType> * Get(const char *Name) { const char* OName; for(typename std::set * >::iterator Iter=_ObserverSet.begin();Iter!=_ObserverSet.end();++Iter) { OName = (*Iter)->Name(); // get the name if(OName && strcmp(OName,Name) == 0) return *Iter; } return 0L; } /** Clears the list of all registered observers. * @note Using this function in your code may be an indication of design problems. */ void ClearObserver() { _ObserverSet.clear(); } protected: /// Vector of attached observers std::set *> _ObserverSet; }; } //namespace Base #endif // BASE_OBSERVER_H