signal.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004-2006 by Dr. Marc Boris Duerner
3  * Copyright (C) 2005 Stephan Beal
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * As a special exception, you may use this file as part of a free
11  * software library without restriction. Specifically, if other files
12  * instantiate templates or use macros or inline functions from this
13  * file, or you compile this file and link it with other files to
14  * produce an executable, this file does not by itself cause the
15  * resulting executable to be covered by the GNU General Public
16  * License. This exception does not however invalidate any other
17  * reasons why the executable file might be covered by the GNU Library
18  * General Public License.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28  */
29 
30 #ifndef cxxtools_Signal_h
31 #define cxxtools_Signal_h
32 
33 #include <cxxtools/void.h>
34 #include <cxxtools/event.h>
35 #include <cxxtools/function.h>
36 #include <cxxtools/method.h>
37 #include <cxxtools/constmethod.h>
38 #include <cxxtools/connectable.h>
39 #include <list>
40 #include <map>
41 
42 
43 namespace cxxtools {
44 
47  class SignalBase : public Connectable
48  {
49  public:
50  struct Sentry
51  {
52  Sentry(const SignalBase* signal);
53 
54  ~Sentry();
55 
56  void detach();
57 
58  bool operator!() const
59  { return _signal == 0; }
60 
62  };
63 
64  SignalBase();
65 
66  ~SignalBase();
67 
68  SignalBase& operator=(const SignalBase& other);
69 
70  virtual void onConnectionOpen(const Connection& c);
71 
72  virtual void onConnectionClose(const Connection& c);
73 
74  void disconnectSlot(const Slot& slot);
75 
76  private:
77  mutable Sentry* _sentry;
78  mutable bool _sending;
79  mutable bool _dirty;
80  };
81 
82 
83 #include <cxxtools/signal.tpp>
84 
86 {
87  bool operator()( const std::type_info* t1,
88  const std::type_info* t2 ) const;
89 };
90 
91 template <>
92 class Signal<const cxxtools::Event&> : public Connectable
93  , protected NonCopyable
94 {
95  struct Sentry
96  {
97  Sentry(const Signal* signal);
98 
99  ~Sentry();
100 
101  void detach();
102 
103  bool operator!() const
104  { return _signal == 0; }
105 
106  const Signal* _signal;
107  };
108 
109  class IEventRoute
110  {
111  public:
112  IEventRoute(Connection& target)
113  : _target(target)
114  { }
115 
116  virtual ~IEventRoute() {}
117 
118  virtual void route(const cxxtools::Event& ev)
119  {
120  typedef Invokable<const cxxtools::Event&> InvokableT;
121  const InvokableT* invokable = static_cast<const InvokableT*>( _target.slot().callable() );
122  invokable->invoke(ev);
123  }
124 
126  { return _target; }
127 
128  bool valid() const
129  { return _target.valid(); }
130 
131  private:
132  Connection _target;
133  };
134 
135  template <typename EventT>
136  class EventRoute : public IEventRoute
137  {
138  public:
139  EventRoute(Connection& target)
140  : IEventRoute(target)
141  { }
142 
143  virtual void route(const cxxtools::Event& ev)
144  {
145  typedef Invokable<const cxxtools::Event&> InvokableT;
146  const InvokableT* invokable = static_cast<const InvokableT*>( connection().slot().callable() );
147 
148  const EventT& event = static_cast<const EventT&>(ev);
149  invokable->invoke(event);
150  }
151  };
152 
153  typedef std::multimap< const std::type_info*,
154  IEventRoute*,
155  CompareEventTypeInfo > RouteMap;
156 
157  public:
158  Signal();
159 
160  ~Signal();
161 
162  void send(const cxxtools::Event& ev) const;
163 
164  template <typename R>
165  Connection connect(const BasicSlot<R, const cxxtools::Event&>& slot)
166  {
167  Connection conn( *this, slot.clone() );
168  this->addRoute( 0, new IEventRoute(conn) );
169  return conn;
170  }
171 
172  template <typename R>
173  void disconnect(const BasicSlot<R, const cxxtools::Event&>& slot)
174  {
175  this->removeRoute(slot);
176  }
177 
178  template <typename EventT>
179  void subscribe( const BasicSlot<void, const EventT&>& slot )
180  {
181  Connection conn( *this, slot.clone() );
182  const std::type_info& ti = typeid(EventT);
183  this->addRoute( &ti, new EventRoute<EventT>(conn) );
184  }
185 
186  template <typename EventT>
187  void unsubscribe( const BasicSlot<void, const EventT&>& slot )
188  {
189  const std::type_info& ti = typeid(EventT);
190  this->removeRoute(&ti, slot);
191  }
192 
193  virtual void onConnectionOpen(const Connection& c);
194 
195  virtual void onConnectionClose(const Connection& c);
196 
197  protected:
198  void addRoute(const std::type_info* ti, IEventRoute* route);
199 
200  void removeRoute(const Slot& slot);
201 
202  void removeRoute(const std::type_info* ti, const Slot& slot);
203 
204  private:
205  mutable RouteMap _routes;
206  mutable Sentry* _sentry;
207  mutable bool _sending;
208  mutable bool _dirty;
209 };
210 
211 template <typename R>
213 {
214  return signal.connect( slot(func) );
215 }
216 
217 template <typename R, class BaseT, class ClassT>
219  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) )
220 {
221  return signal.connect( slot(object, memFunc) );
222 }
223 
224 template <typename R, class BaseT, class ClassT>
225 Connection connect( Signal<const cxxtools::Event&>& signal,
226  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) const )
227 {
228  return signal.connect( slot(object, memFunc) );
229 }
230 
232 {
233  return sender.connect( slot(receiver) );
234 }
235 
236 template <typename R>
238 {
239  signal.disconnect( slot(func) );
240 }
241 
242 template <typename R, class BaseT, class ClassT>
244  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) )
245 {
246  signal.disconnect( slot(object, memFunc) );
247 }
248 
249 template <typename R, class BaseT, class ClassT>
250 void disconnect( Signal<const cxxtools::Event&>& signal,
251  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) const )
252 {
253  signal.disconnect( slot(object, memFunc) );
254 }
255 
257 {
258  sender.disconnect( slot(receiver) );
259 }
260 
261 } // !namespace cxxtools
262 
263 #endif