Import fmit upstream version 0.97.6
[fmit.git] / libs / CppAddons / Observer.h
1 // Copyright 2003 "Gilles Degottex"
2
3 // This file is part of "CppAddons"
4
5 // "CppAddons" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or
8 // (at your option) any later version.
9 // 
10 // "CppAddons" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 // 
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
20 #ifndef _Observer_h_
21 #define _Observer_h_
22
23 #include <typeinfo>
24 #include <list>
25 #include <algorithm>    // for: find
26 using namespace std;
27
28 template<class Listener> class Talker;
29
30 template<class TListener>
31 class Listener
32 {
33         friend class Talker<TListener>;
34
35         bool m_isListenning;
36
37 protected:
38         void todo(const string& fn){cerr << typeid(this).name() << "::" << fn << " not yet implemented" << endl;}
39
40 public:
41         Listener() : m_isListenning(false) {}
42
43         bool isListenning()     {return m_isListenning;}
44 };
45
46 template<class TListener, class TypeEvent>
47 class FireFun
48 {
49         void (TListener::*m_pfOccured)(TypeEvent*);
50
51         TypeEvent* m_evt;
52
53 public:
54         explicit FireFun(void (TListener::*pfOccured)(TypeEvent*), TypeEvent* evt)
55                 : m_pfOccured(pfOccured), m_evt(evt)
56         {}
57
58         void operator()(TListener* l) const {(l->*m_pfOccured)(m_evt);}
59 };
60
61 template<class SourceType>
62 class EventObject
63 {
64         SourceType* m_obj;
65
66 public:
67         EventObject(SourceType* source) : m_obj(source) {}
68
69         SourceType* getSource() const {return m_obj;}
70 };
71
72 template<class Listener>
73 class Talker
74 {
75 public:
76         typedef Listener TypeListener;
77         typedef list<TypeListener*> ListenersList;
78         typedef typename ListenersList::iterator ListenersIterator;
79
80 private:
81         ListenersList m_removed;
82
83 protected:
84
85         ListenersList m_listeners;
86
87         bool m_firing;
88         void removeRemoved()
89         {
90                 while(!m_removed.empty())
91                 {
92                         m_removed.front()->m_isListenning = false;
93                         m_listeners.remove(m_removed.front());
94                         m_removed.pop_front();
95                 }
96         }
97
98         #define MFireEventL(s, L) {Talker<L>::m_firing=true;for(Talker<L>::ListenersList::iterator _listenerIterator_=(Talker<L>::m_listeners).begin(); _listenerIterator_!=(Talker<L>::m_listeners).end(); ++_listenerIterator_) (*_listenerIterator_)->s;Talker<L>::m_firing=false;Talker<L>::removeRemoved();}
99         #define MFireEvent(s) MFireEventL(s, TypeListener)
100
101         template<typename TypeEvent>
102         void fireEvent(void (Listener::*fOccured)(TypeEvent*), TypeEvent* evt)
103         {
104                 m_firing=true;
105                 for_each(       (Talker<Listener>::m_listeners).begin(),
106                                         (Talker<Listener>::m_listeners).end(),
107                                         FireFun<Listener, TypeEvent>(fOccured, evt));
108                 m_firing=false;
109                 removeRemoved();
110         }
111
112 public:
113         Talker() : m_firing(false) {}
114
115         bool hasListeners(){return !m_listeners.empty();}
116         bool hasListener(Listener* l)
117         {
118                 return find(m_listeners.begin(), m_listeners.end(), l)!=m_listeners.end();
119         }
120         void addListener(Listener* l)
121         {
122                 m_listeners.push_back(l);       // discutable: back/front
123                 
124                 l->m_isListenning = true;
125         }
126         void removeListener(Listener* l)
127         {
128                 if(m_firing)    m_removed.push_back(l);
129                 else
130                 {
131                         m_listeners.remove(l);
132                         l->m_isListenning = false;
133                 }
134         }
135         void toggleListener(Listener* l)
136         {
137                 if(hasListener(l))      addListener(l);
138                 else                    removeListener(l);
139         }
140
141         list<Listener*>& getListeners(){return m_listeners;}
142 };
143
144 #endif