Files
create/src/Base/Observer.h
2016-09-21 20:54:52 +02:00

214 lines
6.5 KiB
C++

/***************************************************************************
* (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 <assert.h>
#include <set>
#include <cstring>
#include <cstdio>
namespace Base
{
template <class MessageType> 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 _MessageType>
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 _MessageType>
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<Observer<_MessageType> * >::iterator Iter=_ObserverSet.begin();Iter!=_ObserverSet.end();++Iter)
(*Iter)->OnChange(*this,rcReason); // send OnChange-signal
}
/** 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<Observer<_MessageType> * >::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<Observer <_MessageType> *> _ObserverSet;
};
} //namespace Base
#endif // BASE_OBSERVER_H