0fd75ffae26a8393495f8dbc5bfed1911791e536
[platform/core/uifw/dali-core.git] / dali / public-api / signals / base-signal.h
1 #ifndef __DALI_BASE_SIGNAL_H__
2 #define __DALI_BASE_SIGNAL_H__
3
4 /*
5  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/signals/callback.h>
25 #include <dali/public-api/signals/connection-tracker-interface.h>
26 #include <dali/public-api/signals/signal-slot-connections.h>
27
28 namespace Dali
29 {
30 /**
31  * @addtogroup dali_core_signals
32  * @{
33  */
34
35 /**
36  * @brief Implementation class for Dali::Signal.
37  *
38  * A slot can be connected to many signals
39  * A signal can be connected to many slots
40  *
41  * To provide automatic disconnection when either a signal or the object owning the slot dies,
42  * observers are used.
43  *
44  * A signal is an object with state. It holds a list of SignalConnection%s.
45  *
46  * E.g.
47  *  Signal OnTouch. mSignalConnections contains
48  * <table>
49  * <tr><td> %Callback 0 </td><td> Signal Observer 0  </td></tr>
50  * <tr><td> %Callback 1 </td><td> Signal Observer 1  </td></tr>
51  * <tr><td> %Callback 2 </td><td> Signal Observer 2  </td></tr>
52  * </table>
53  *
54  * OnTouch.Emit() will run callbacks 0, 1 and 2.
55  *
56  * When the signal is destroyed. SignalDisconnected() is called on each Signal Observer.
57  *
58  * Slots are just static or member functions, so have no state. E.g. they can't keep
59  * track of how many signals they are connected to.
60  * If the object owning a slot dies, it must automatically disconnected from all signals.
61  * If it doesn't disconnect and the signal is emitted, there will be a crash.
62  *
63  * To keep track of connections between slots and signals, a Connection tracker is used.
64  * It holds a list of SlotConnections.
65  *
66  * <table>
67  * <tr><td> %Callback 0 </td><td> Slot Observer 0  </td></tr>
68  * <tr><td> %Callback 1 </td><td> Slot Observer 1  </td></tr>
69  * <tr><td> %Callback 2 </td><td> Slot Observer 2  </td></tr>
70  * </table>
71  *
72  * When the connection tracker is destroyed, SlotDisconnected() is called on every slot observer ( signal )
73  * Signals implement the Slot Observer interface, to be told when a slot has disconnected
74  * Connection tracker implements the Signal Observer interface, to be told when a signal has disconnected (died)
75  *
76  */
77 class DALI_IMPORT_API BaseSignal : public SlotObserver
78 {
79 public:
80
81   /**
82    * @brief Constructor.
83    */
84   BaseSignal();
85
86   /**
87    * @brief Virtual destructor.
88    */
89   virtual ~BaseSignal();
90
91   /**
92    * @brief Query whether there are any connected slots.
93    *
94    * @return True if there are any slots connected to the signal.
95    */
96   bool Empty() const;
97
98   /**
99    * @brief Query the number of slots.
100    *
101    * @return The number of slots connected to this signal.
102    */
103   std::size_t GetConnectionCount() const;
104
105   // Templated Emit functions for the Signal implementations
106
107   /**
108    * @brief Used to guard against nested Emit() calls.
109    */
110   struct EmitGuard
111   {
112     /**
113      * @brief Create the guard.
114      *
115      * @param[in,out] flag This flag will be set to true during Emit() calls.
116      */
117     EmitGuard( bool& flag );
118
119     /**
120      * @brief Non-virtual destructor.
121      *
122      */
123     ~EmitGuard();
124
125     /**
126      * @brief  Determine if an error occured.
127      *
128      * @return True if an error occurred i.e. if Emit() was called during Emit()
129      */
130     bool ErrorOccurred();
131
132     bool* mFlag; ///< Pointer to the emit guard flag.
133   };
134
135   /**
136    * @brief Emit a signal with no parameters.
137    *
138    * @pre Cannot be called from inside the same Signal's Emit methods.
139    */
140   void Emit();
141
142   /**
143    * @brief Emit a signal with no parameters.
144    *
145    * @pre Cannot be called from inside the same Signal's Emit methods.
146    * @return The value returned by the last callback.
147    */
148   template< typename Ret >
149   Ret EmitReturn()
150   {
151     Ret returnVal = Ret();
152
153     // Guards against nested Emit() calls
154     EmitGuard guard( mEmittingFlag );
155     if( guard.ErrorOccurred() )
156     {
157       return returnVal;
158     }
159
160     // If more connections are added by callbacks, these are ignore until the next Emit()
161     // Note that count cannot be reduced while iterating
162     const std::size_t initialCount( mSignalConnections.Count() );
163
164     for( std::size_t i = 0; i < initialCount; ++i )
165     {
166       CallbackBase* callback( GetCallback(i) );
167
168       // Note that connections will be set to NULL when disconnected
169       // This is preferable to reducing the connection count while iterating
170       if( callback )
171       {
172         returnVal = CallbackBase::ExecuteReturn<Ret>( *callback );
173       }
174     }
175
176     // Cleanup NULL values from Connection container
177     CleanupConnections();
178
179     return returnVal;
180   }
181
182   /**
183    * @brief Emit a signal with 1 parameter.
184    *
185    * @pre Cannot be called from inside the same Signal's Emit methods.
186    * @param[in] arg0 The first parameter.
187    */
188   template< typename Arg0 >
189   void Emit( Arg0 arg0 )
190   {
191     // Guards against nested Emit() calls
192     EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
193     if( guard.ErrorOccurred() )
194     {
195       return;
196     }
197
198     // If more connections are added by callbacks, these are ignore until the next Emit()
199     // Note that count cannot be reduced while iterating
200     const std::size_t initialCount( mSignalConnections.Count() );
201
202     for( std::size_t i = 0; i < initialCount; ++i )
203     {
204       CallbackBase* callback( GetCallback(i) );
205
206       // Note that connections will be set to NULL when disconnected
207       // This is preferable to reducing the connection count while iterating
208       if( callback )
209       {
210         CallbackBase::Execute<Arg0 >( *callback, arg0 );
211       }
212     }
213
214     // Cleanup NULL values from Connection container
215     CleanupConnections();
216   }
217
218   /**
219    * @brief Emit a signal with 1 parameter.
220    *
221    * @pre Cannot be called from inside the same Signal's Emit methods.
222    * @param[in] arg0 The first parameter.
223    * @return The value returned by the last callback.
224    */
225   template< typename Ret, typename Arg0 >
226   Ret EmitReturn( Arg0 arg0 )
227   {
228     Ret returnVal = Ret();
229
230     // Guards against nested Emit() calls
231     EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
232     if( guard.ErrorOccurred() )
233     {
234       return returnVal;
235     }
236
237     // If more connections are added by callbacks, these are ignore until the next Emit()
238     // Note that count cannot be reduced while iterating
239     const std::size_t initialCount( mSignalConnections.Count() );
240
241     for( std::size_t i = 0; i < initialCount; ++i )
242     {
243       CallbackBase* callback( GetCallback(i) );
244
245       // Note that connections will be set to NULL when disconnected
246       // This is preferable to reducing the connection count while iterating
247       if( callback )
248       {
249         returnVal = CallbackBase::ExecuteReturn<Ret,Arg0>( *callback, arg0 );
250       }
251     }
252
253     // Cleanup NULL values from Connection container
254     CleanupConnections();
255
256     return returnVal;
257   }
258
259   /**
260    * @brief Emit a signal with 2 parameters.
261    *
262    * @pre Cannot be called from inside the same Signal's Emit methods.
263    * @param[in] arg0 The first parameter.
264    * @param[in] arg1 The second parameter.
265    */
266   template< typename Arg0, typename Arg1 >
267   void Emit( Arg0 arg0, Arg1 arg1 )
268   {
269     // Guards against nested Emit() calls
270     EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
271     if( guard.ErrorOccurred() )
272     {
273       return;
274     }
275
276     // If more connections are added by callbacks, these are ignore until the next Emit()
277     // Note that count cannot be reduced while iterating
278     const std::size_t initialCount( mSignalConnections.Count() );
279
280     for( std::size_t i = 0; i < initialCount; ++i )
281     {
282       CallbackBase* callback( GetCallback(i) );
283
284       // Note that connections will be set to NULL when disconnected
285       // This is preferable to reducing the connection count while iterating
286       if( callback )
287       {
288         CallbackBase::Execute<Arg0,Arg1>( *callback, arg0, arg1 );
289       }
290     }
291
292     // Cleanup NULL values from Connection container
293     CleanupConnections();
294   }
295
296   /**
297    * @brief Emit a signal with 2 parameters.
298    *
299    * @pre Cannot be called from inside the same Signal's Emit methods.
300    * @param[in] arg0 The first parameter.
301    * @param[in] arg1 The second parameter.
302    * @return The value returned by the last callback.
303    */
304   template< typename Ret, typename Arg0, typename Arg1 >
305   Ret EmitReturn( Arg0 arg0, Arg1 arg1 )
306   {
307     Ret returnVal = Ret();
308
309     // Guards against nested Emit() calls
310     EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
311     if( guard.ErrorOccurred() )
312     {
313       return returnVal;
314     }
315
316     // If more connections are added by callbacks, these are ignore until the next Emit()
317     // Note that count cannot be reduced while iterating
318     const std::size_t initialCount( mSignalConnections.Count() );
319
320     for( std::size_t i = 0; i < initialCount; ++i )
321     {
322       CallbackBase* callback( GetCallback(i) );
323
324       // Note that connections will be set to NULL when disconnected
325       // This is preferable to reducing the connection count while iterating
326       if( callback )
327       {
328         returnVal = CallbackBase::ExecuteReturn<Ret,Arg0,Arg1>( *callback, arg0, arg1 );
329       }
330     }
331
332     // Cleanup NULL values from Connection container
333     CleanupConnections();
334
335     return returnVal;
336   }
337
338   /**
339    * @brief Emit a signal with 3 parameters.
340    *
341    * @pre Cannot be called from inside the same Signal's Emit methods.
342    * @param[in] arg0 The first parameter.
343    * @param[in] arg1 The second parameter.
344    * @param[in] arg2 The third parameter.
345    */
346   template< typename Arg0, typename Arg1, typename Arg2 >
347   void Emit( Arg0 arg0, Arg1 arg1, Arg2 arg2 )
348   {
349     // Guards against nested Emit() calls
350     EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
351     if( guard.ErrorOccurred() )
352     {
353       return;
354     }
355
356     // If more connections are added by callbacks, these are ignore until the next Emit()
357     // Note that count cannot be reduced while iterating
358     const std::size_t initialCount( mSignalConnections.Count() );
359
360     for( std::size_t i = 0; i < initialCount; ++i )
361     {
362       CallbackBase* callback( GetCallback(i) );
363
364       // Note that connections will be set to NULL when disconnected
365       // This is preferable to reducing the connection count while iterating
366       if( callback )
367       {
368         CallbackBase::Execute<Arg0,Arg1,Arg2>( *callback, arg0, arg1, arg2 );
369       }
370     }
371
372     // Cleanup NULL values from Connection container
373     CleanupConnections();
374   }
375
376   /**
377    * @brief Emit a signal with 3 parameters.
378    *
379    * @pre Cannot be called from inside the same Signal's Emit methods.
380    * @param[in] arg0 The first parameter.
381    * @param[in] arg1 The second parameter.
382    * @param[in] arg2 The third parameter.
383    * @return The value returned by the last callback.
384    */
385   template< typename Ret, typename Arg0, typename Arg1, typename Arg2 >
386   Ret EmitReturn( Arg0 arg0, Arg1 arg1, Arg2 arg2 )
387   {
388     Ret returnVal = Ret();
389
390     // Guards against nested Emit() calls
391     EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
392     if( guard.ErrorOccurred() )
393     {
394       return returnVal;
395     }
396
397     // If more connections are added by callbacks, these are ignore until the next Emit()
398     // Note that count cannot be reduced while iterating
399     const std::size_t initialCount( mSignalConnections.Count() );
400
401     for( std::size_t i = 0; i < initialCount; ++i )
402     {
403       CallbackBase* callback( GetCallback(i) );
404
405       // Note that connections will be set to NULL when disconnected
406       // This is preferable to reducing the connection count while iterating
407       if( callback )
408       {
409         returnVal = CallbackBase::ExecuteReturn<Ret,Arg0,Arg1,Arg2>( *callback, arg0, arg1, arg2 );
410       }
411     }
412
413     // Cleanup NULL values from Connection container
414     CleanupConnections();
415
416     return returnVal;
417   }
418
419   // Connect / Disconnect function for use by Signal implementations
420
421   /**
422    * @brief Called by Signal implementations, when the user calls Signal.Connect( ... )
423    *
424    * @param[in] callback A newly allocated callback object (takes ownership).
425    */
426   void OnConnect( CallbackBase* callback );
427
428   /**
429    * @brief Called by Signal implementations, when the user calls Signal.Disconnect( ... )
430    *
431    * @param[in] callback A newly allocated callback object (takes ownership).
432    */
433   void OnDisconnect( CallbackBase* callback );
434
435   /**
436    * @brief Called by Signal implementations, when the user calls Signal.Connect( ... )
437    *
438    * @param[in] tracker The connection tracker.
439    * @param[in] callback A newly allocated callback object (takes ownership).
440    */
441   void OnConnect( ConnectionTrackerInterface* tracker, CallbackBase* callback );
442
443   /**
444    * @brief Called by Signal implementations, when the user calls Signal.Disconnect( ... )
445    *
446    * @param[in] tracker The connection tracker.
447    * @param[in] callback A newly allocated callback object (takes ownership).
448    */
449   void OnDisconnect( ConnectionTrackerInterface* tracker, CallbackBase* callback );
450
451 private: // SlotObserver interface, to be told when a slot disconnects
452
453   /**
454    * @copydoc SlotObserver::SlotDisconnected
455    */
456   virtual void SlotDisconnected( CallbackBase* callback );
457
458 private:
459
460   /**
461    * @brief Returns a callback given an index in to the connection array.
462    *
463    * @param[in] connectionIndex The index of the callback.
464    * @return The callback, or NULL if the connection has been deleted.
465    */
466   CallbackBase* GetCallback( std::size_t connectionIndex ) const;
467
468   /**
469    * @brief Helper to find whether a callback is connected.
470    *
471    * @param[in] callback The call back object.
472    * @return A valid index if the callback is connected.
473    */
474   int FindCallback( CallbackBase* callback );
475
476   /**
477    * @brief Deletes a connection object from the list of connections.
478    *
479    * @param[in] connectionIndex The index of the callback.
480    */
481   void DeleteConnection( std::size_t connectionIndex );
482
483   /**
484    * @brief Helper to remove NULL items from mSignalConnections, which is only safe at the end of Emit()
485    * i.e. not from methods which can be called during a signal Emit(), such as Disconnect().
486    */
487   void CleanupConnections();
488
489   BaseSignal( const BaseSignal& );                   ///< undefined copy constructor, signals don't support copying.
490   BaseSignal& operator=( const BaseSignal& );        ///< undefined assignment operator
491
492 private:
493
494   Dali::Vector< SignalConnection* > mSignalConnections;   ///< Array of connections
495
496   bool mEmittingFlag; ///< Used to guard against nested Emit() calls
497 };
498
499 /**
500  * @}
501  */
502 } // namespace Dali
503
504 #endif // __DALI_BASE_SIGNAL_H__