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