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 detach();
54 
55  bool operator!() const
56  { return _signal == 0; }
57 
58  SignalBase* _signal;
59  };
60 
61  SignalBase();
62 
63  ~SignalBase();
64 
65  SignalBase& operator=(const SignalBase& other);
66 
67  virtual void onConnectionOpen(const Connection& c);
68 
69  virtual void onConnectionClose(const Connection& c);
70 
71  protected:
72  void disconnectSlots();
73 
74  void disconnectSlot(const Slot&);
75 
76  private:
77  Sentry* _sentry;
78  bool _sending;
79  bool _dirty;
80 };
81 
82 #include <Pt/Signal.tpp>
83 
84 struct PT_API CompareEventTypeInfo
85 {
86  bool operator()( const std::type_info* t1,
87  const std::type_info* t2 ) const;
88 };
89 
90 template <>
91 class PT_API Signal<const Pt::Event&> : public Connectable
92  , protected NonCopyable
93 {
94  struct PT_API Sentry
95  {
96  Sentry(Signal* signal);
97 
98  ~Sentry();
99 
100  void detach();
101 
102  bool operator!() const
103  { return _signal == 0; }
104 
105  Signal* _signal;
106  };
107 
108  class IEventRoute
109  {
110  public:
111  IEventRoute(Connection& target)
112  : _target(target)
113  { }
114 
115  virtual ~IEventRoute() {}
116 
117  virtual void route(const Pt::Event& ev)
118  {
120  const InvokableT* invokable = static_cast<const InvokableT*>( _target.slot()->callable() );
121  invokable->invoke(ev);
122  }
123 
124  Connection& connection()
125  { return _target; }
126 
127  bool isValid() const
128  { return _target.isValid(); }
129 
130  private:
131  Connection _target;
132  };
133 
134  template <typename EventT>
135  class EventRoute : public IEventRoute
136  {
137  public:
138  EventRoute(Connection& target)
139  : IEventRoute(target)
140  { }
141 
142  virtual void route(const Pt::Event& ev)
143  {
144  typedef Invokable<const Pt::Event&> InvokableT;
145  const InvokableT* invokable = static_cast<const InvokableT*>( connection().slot()->callable() );
146 
147  const EventT& event = static_cast<const EventT&>(ev);
148  invokable->invoke(event);
149  }
150  };
151 
152  typedef std::multimap< const std::type_info*,
153  IEventRoute*,
154  CompareEventTypeInfo > RouteMap;
155 
156  public:
157  Signal();
158 
159  ~Signal();
160 
161  void send(const Pt::Event& ev);
163  template <typename EventT>
164  Connection connect( const BasicSlot<void, const EventT&>& slot )
165  {
166  Connection conn( *this, slot.clone() );
167  EventT* selectAddRouteOverload = 0;
168  this->addRoute(conn, selectAddRouteOverload);
169  return conn;
170  }
171 
172  void disconnect();
173 
174  template <typename R, typename EventT>
175  void disconnect(const BasicSlot<R, const EventT&>& slot)
176  {
177  this->removeRoute(slot);
178  }
179 
180  virtual void onConnectionOpen(const Connection& c);
181 
182  virtual void onConnectionClose(const Connection& c);
183 
184  protected:
185  void addRoute(Connection& conn, const Pt::Event*)
186  {
187  this->addRoute( 0, new IEventRoute(conn) );
188  }
189 
190  template <typename EventT>
191  void addRoute(Connection& conn, const EventT*)
192  {
193  const std::type_info& ti = typeid(EventT);
194  this->addRoute( &ti, new EventRoute<EventT>(conn) );
195  }
196 
197  void addRoute(const std::type_info* ti, IEventRoute* route);
198 
199  void removeRoute(const Slot& slot);
200 
201  void removeRoute(const std::type_info* ti, const Slot& slot);
202 
203  private:
204  RouteMap _routes;
205  Sentry* _sentry;
206  bool _sending;
207  bool _dirty;
208 };
209 
210 
211 template <typename R, class EventT>
212 Connection operator +=(Signal<const Pt::Event&>& signal, const BasicSlot<R, EventT>& slot)
213 {
214  return signal.connect( slot );
215 }
216 
217 template <typename R>
218 Connection operator +=(Signal<const Pt::Event&>& signal, const BasicSlot<R, const Pt::Event&>& slot)
219 {
220  return signal.connect( slot );
221 }
222 
223 
224 template <typename R, class EventT>
225 void operator -=(Signal<const Pt::Event&>& signal, const BasicSlot<R, EventT>& slot)
226 {
227  signal.disconnect( slot );
228 }
229 
230 template <typename R>
231 void operator -=(Signal<const Pt::Event&>& signal, const BasicSlot<R, const Pt::Event&>& slot)
232 {
233  signal.disconnect( slot );
234 }
235 
236 } // namespace Pt
237 
238 #endif
Interface for invokable entities.
Definition: Invokable.h:36
bool isValid() const
Returns true if not closed.
Definition: Connection.h:106
virtual void invoke(ARGUMENTS) const =0
Invokes the invokable entity with the given arguments.
Base class for all event types.
Definition: Event.h:49
Represents a connection between a Signal/Delegate and a slot.
Definition: Connection.h:90
virtual Slot * clone() const =0
Clone this object with new.
Base type for various "slot" types.
Definition: Slot.h:47