IT++ Logo

signals_slots.h

Go to the documentation of this file.
00001 
00030 #ifndef SIGNAL_SLOT_H
00031 #define SIGNAL_SLOT_H
00032 
00033 #include <itpp/protocol/events.h>
00034 #include <list>
00035 #include <iostream>
00036 
00037 
00038 namespace itpp
00039 {
00040 
00042 
00043 
00044 class Base_Signal;
00045 template<class DataType> class Signal;
00046 template<class DataType> class Base_Slot;
00047 template<class ObjectType, class DataType> class Slot;
00048 
00049 
00113 template<class DataType>
00114 class Signal
00115 {
00116 public:
00117   friend class Base_Slot<DataType>;
00118 
00120   Signal(const std::string signal_name = "Unamed Signal", const bool single_shot = false, const bool enable_debug = false);
00121 
00122   //  Signal(const std::string signal_name = "Unamed Signal", const bool single_shot = false, const bool enable_debug = true);
00123 
00125   ~Signal();
00126 
00128   void connect(Base_Slot<DataType>* slot);
00129 
00131   void disconnect(Base_Slot<DataType>* slot = NULL);
00132 
00133   //  Base_Event* arm(const Ttype delta_time, DataType signal); // Signal will trigger in 'delta_time' time units carrying data signal.
00134 
00135 
00137   Base_Event* operator()(DataType signal, const Ttype delta_time = 0);
00138 
00140   void cancel();
00141 
00143   void set_name(const std::string &signal_name);
00144 
00146   void set_debug(const bool enable_debug = true);
00147 
00149   void trigger(DataType u);
00150 
00151 protected:
00153   typedef typename std::list<Base_Slot<DataType>*, std::allocator< Base_Slot<DataType>* > >::iterator Base_Slot_Iterator;
00155   void _disconnect(Base_Slot<DataType>* slot);
00157   std::list<Base_Slot<DataType>*, std::allocator<Base_Slot<DataType>* > > connected_slots;
00159   std::string name;
00160 
00161 private:
00162   bool armed;
00163   bool debug;
00164   bool single;
00165   Data_Event<Signal, DataType> *e;
00166 };
00167 
00168 
00173 template<class DataType>
00174 class Base_Slot
00175 {
00176 public:
00177   friend class Signal<DataType>;
00178 
00180   Base_Slot(const std::string slot_name = "Unamed Base_Slot");
00181 
00183   virtual ~Base_Slot();
00184 
00186   void set_name(const std::string &slot_name);
00187 
00189   virtual void operator()(DataType signal) = 0;
00190 
00191 protected:
00192   //   virtual void exec(DataType signal) = 0;
00194   typedef typename std::list<Signal<DataType>*, std::allocator< Signal<DataType>* > >::iterator Signal_Iterator;
00196   std::string name;
00198   void _connect(Signal<DataType>* signal);
00200   void _disconnect(Signal<DataType>* signal);
00202   std::list<Signal<DataType>*, std::allocator<Signal<DataType>* > > connected_signals;
00203 };
00204 
00209 template<class ObjectType, class DataType>
00210 class Slot : public Base_Slot<DataType>
00211 {
00212 public:
00214   Slot(const std::string _name = "Unamed Slot");
00215 
00217   void forward(ObjectType *object_pointer, void(ObjectType::*object_function_pointer)(DataType u));
00218 
00220   ~Slot();
00221 
00223   void operator()(DataType u);
00224 
00225   //void exec(DataType signal);
00226 
00227 private:
00228   ObjectType *po;
00229   void(ObjectType::*pm)(DataType signal);
00230 };
00231 
00232 
00236 template<class ObjectType, class DataType>
00237 class ATimer
00238 {
00239 public:
00241   ATimer(const std::string Name = "Unamed ATimer") {
00242     time_out_signal = new Signal<DataType>(Name, true);
00243     time_out_slot = new Slot<ObjectType, DataType>(Name);
00244     time_out_signal->connect(time_out_slot);
00245     set_name(Name);
00246   }
00247 
00249   void forward(ObjectType *po, void(ObjectType::*pm)(DataType u)) { time_out_slot->forward(po, pm); }
00250 
00252   void set(DataType u, const Ttype delta_t) {
00253     time_out_signal->operator()(u, delta_t);
00254   }
00255 
00257   void cancel() { time_out_signal->cancel(); }
00258 
00260   void set_name(const std::string Name) {
00261     name = Name;
00262     time_out_signal->set_name(name);
00263     time_out_slot->set_name(name);
00264   }
00265 
00266 protected:
00268   std::string name;
00269 
00270 private:
00271   Signal<DataType> *time_out_signal;
00272   Slot<ObjectType, DataType> *time_out_slot;
00273 };
00274 
00275 
00276 
00285 template <class THandler>
00286 class TTimer
00287 {
00288 public:
00290   TTimer(THandler & handler, void (THandler::*handlerFunction)(Ttype time)) :
00291       signal("timer_signal", true) {
00292     fPending = false;
00293     fExpirationTime = 0;
00294 
00295     registered_handler = &handler;
00296     registered_handler_function = handlerFunction;
00297 
00298     slot.forward(this, &TTimer<THandler>::HandleProcessEvent);
00299     slot.set_name("timer_slot");
00300     signal.set_debug(false);
00301     signal.connect(&slot);
00302   }
00303 
00305   virtual ~TTimer() {
00306     if (fPending)
00307       signal.cancel();
00308   }
00309 
00311   void  Set(Ttype time, bool relative = true) {
00312     if (fPending)
00313       signal.cancel();
00314 
00315     fPending = true;
00316     double current_time = Event_Queue::now();
00317     double delta_time;
00318     if (relative) {
00319       fExpirationTime = current_time + time;
00320       delta_time = time;
00321     }
00322     else {
00323       fExpirationTime = time;
00324       delta_time = time - current_time;
00325     }
00326     signal(fExpirationTime, delta_time);
00327   }
00328 
00330   void  Reset() {
00331     if (fPending) {
00332       signal.cancel();
00333       fPending = false; // TODO: Added this myself. Didn't work otherwise.
00334     }
00335   }
00336 
00338   Ttype  ExpirationTime() const {
00339     it_assert(fPending, "TTimer<>::ExpirationTime: timer not set");
00340     return fExpirationTime;
00341   }
00342 
00344   bool  IsPending() const { return fPending; }
00345 
00346 protected:
00348   virtual void HandleProcessEvent(Ttype currentTime) {
00349     fPending = false;
00350     (*registered_handler.*registered_handler_function)(currentTime);
00351   }
00352 
00354   virtual void HandleCancelEvent(Ttype) {
00355     if (fPending)
00356       signal.cancel();
00357 
00358     fPending = false;
00359   }
00360 
00362   bool  fPending;
00364   Ttype  fExpirationTime;
00365 
00366 private:
00367   THandler *registered_handler;
00368   void(THandler::*registered_handler_function)(Ttype expiry_time);
00369 
00370   Signal<double> signal;     // Used internally
00371   Slot<TTimer, double> slot; // Used internally
00372 };
00373 
00374 
00375 
00376 
00377 
00378 
00379 // -----------------------------------------------------------------------------------------------
00380 
00381 template<class DataType>
00382 Signal<DataType>::Signal(const std::string signal_name, const bool single_shot, const bool enable_debug)
00383 {
00384   armed = false;
00385   e = NULL;
00386   single = single_shot;
00387   set_name(signal_name);
00388   set_debug(enable_debug);
00389 }
00390 
00391 template<class DataType>
00392 Signal<DataType>::~Signal()
00393 {
00394   Base_Slot_Iterator
00395   begin = connected_slots.begin(),
00396           end   = connected_slots.end(),
00397                   i;
00398 
00399   for (i = begin; i != end; i++)
00400     (*i)->_disconnect(this);
00401 
00402   connected_slots.clear();
00403 
00404   if (e != NULL) // Cancel a possibly pending event since we are about to die!
00405     e->cancel();
00406 }
00407 
00408 template<class DataType>
00409 void Signal<DataType>::set_name(const std::string &signal_name)
00410 {
00411   name = signal_name;
00412 }
00413 
00414 template<class DataType>
00415 void Signal<DataType>::set_debug(const bool enable_debug)
00416 {
00417   debug = enable_debug;
00418 }
00419 
00420 template<class DataType>
00421 void Signal<DataType>::connect(Base_Slot<DataType>* slot)
00422 {
00423   Base_Slot_Iterator
00424   begin = connected_slots.begin(),
00425           end   = connected_slots.end(),
00426                   i;
00427 
00428   bool is_already_connected = false;
00429 
00430   for (i = begin; i != end; i++)
00431     if ((*i) == slot)
00432       is_already_connected = true;
00433 
00434   if (!is_already_connected) { // Multiple connections is meaningless.
00435     connected_slots.push_back(slot);
00436     slot->_connect(this); // Needed if a connected slot is deleted during run time.
00437   }
00438   else {
00439     std::cout << "Signal '" << name << "' and Slot '" << slot->name << "' are already connected. Multiple connections have no effect!" << std::endl;
00440   }
00441 }
00442 
00443 template<class DataType>
00444 void Signal<DataType>::disconnect(Base_Slot<DataType>* slot)
00445 {
00446   Base_Slot_Iterator
00447   begin = connected_slots.begin(),
00448           end   = connected_slots.end(),
00449                   i;
00450 
00451   for (i = begin; i != end; i++)
00452     if ((*i) == slot) {
00453       (*i)->_disconnect(this);
00454       connected_slots.erase(i);
00455       break;
00456     }
00457 }
00458 
00459 template<class DataType>
00460 Base_Event* Signal<DataType>::operator()(DataType signal, const Ttype delta_time)
00461 {
00462   // Signal will trigger in 'delta_time' time units.
00463   if (single) { // We are operating in single-shot mode.
00464     if (armed) { // Cancel and schedule again with the new 'delta_time'.
00465       if (debug)
00466         std::cout << "Warning: Changing time for Signal '" << name << "'." << std::endl;
00467       cancel();
00468       operator()(signal, delta_time);
00469     }
00470     else {
00471       e = new Data_Event<Signal, DataType>(this, &Signal<DataType>::trigger, signal, delta_time);
00472       armed = true;
00473       Event_Queue::add(e);
00474     }
00475   }
00476   else { // Continious mode (cancel() has no effect).
00477     e = new Data_Event<Signal, DataType>(this, &Signal<DataType>::trigger, signal, delta_time);
00478     armed = true;
00479     Event_Queue::add(e);
00480   }
00481   return e;
00482 }
00483 
00484 template<class DataType>
00485 void Signal<DataType>::cancel()
00486 {
00487   if (armed && single) {
00488     e->cancel();
00489     e = NULL;
00490     armed = false;
00491   }
00492 }
00493 
00494 
00495 template<class DataType>
00496 void Signal<DataType>::trigger(DataType u)
00497 {
00498   armed = false;
00499   e = NULL;
00500   Base_Slot_Iterator
00501   begin = connected_slots.begin(),
00502           end   = connected_slots.end(),
00503                   i;
00504 
00505   for (i = begin; i != end; i++) { // Execute all the functions of the connected slots.
00506     if (debug)
00507       std::cout << "Time = " << Event_Queue::now() << ". Signal '" << name << "' was sent to Slot '" << (*i)->name << "'." << std::endl;
00508     (*i)->operator()(u);
00509   }
00510 }
00511 
00512 template<class DataType>
00513 void Signal<DataType>::_disconnect(Base_Slot<DataType>* slot)
00514 {
00515   Base_Slot_Iterator
00516   begin = connected_slots.begin(),
00517           end   = connected_slots.end(),
00518                   i;
00519 
00520   for (i = begin; i != end; i++)
00521     if ((*i) == slot) {
00522       connected_slots.erase(i);
00523       break;
00524     }
00525 }
00526 
00527 
00528 template<class DataType>
00529 Base_Slot<DataType>::Base_Slot(const std::string slot_name)
00530 {
00531   set_name(slot_name);
00532 }
00533 
00534 template<class DataType>
00535 void Base_Slot<DataType>::set_name(const std::string &slot_name)
00536 {
00537   name = slot_name;
00538 }
00539 
00540 template<class DataType>
00541 Base_Slot<DataType>::~Base_Slot()
00542 { // Notify all signals connect that we are being deleted ...
00543 
00544   Signal_Iterator
00545   begin = connected_signals.begin(),
00546           end   = connected_signals.end(),
00547                   i;
00548 
00549   for (i = begin; i != end; i++)
00550     (*i)->_disconnect(this);
00551 
00552   connected_signals.clear();
00553 }
00554 
00555 template<class DataType>
00556 void Base_Slot<DataType>::_connect(Signal<DataType>* signal)
00557 { // A signal is being connected to us.
00558   connected_signals.push_back(signal);
00559 }
00560 
00561 template<class DataType>
00562 void Base_Slot<DataType>::_disconnect(Signal<DataType>* signal)
00563 { // A signal is being disconnected from us.
00564 
00565   Signal_Iterator
00566   begin = connected_signals.begin(),
00567           end   = connected_signals.end(),
00568                   i;
00569 
00570   for (i = begin; i != end; i++)
00571     if ((*i) == signal) {
00572       connected_signals.erase(i);
00573       break;
00574     }
00575 }
00576 
00577 template<class ObjectType, class DataType>
00578 Slot<ObjectType, DataType>::Slot(const std::string slot_name) : Base_Slot<DataType>(slot_name)
00579 {
00580   pm = NULL;
00581   po = NULL;
00582 }
00583 
00584 template<class ObjectType, class DataType>
00585 Slot<ObjectType, DataType>::~Slot() {}
00586 
00587 template<class ObjectType, class DataType>
00588 void Slot<ObjectType, DataType>::forward(ObjectType *object_pointer, void(ObjectType::*object_function_pointer)(DataType u))
00589 {
00590   pm = object_function_pointer;
00591   po = object_pointer;
00592 }
00593 
00594 // template<class ObjectType, class DataType>
00595 // void Slot<ObjectType, DataType>::exec(DataType signal){
00596 //   if(pm&&po)
00597 //     (*po.*pm)(signal);
00598 // }
00599 
00600 template<class ObjectType, class DataType>
00601 void Slot<ObjectType, DataType>::operator()(DataType signal)
00602 {
00603   if (pm&&po)
00604     (*po.*pm)(signal);
00605 }
00606 
00608 
00609 } // namespace itpp
00610 
00611 #endif // #ifndef SIGNAL_SLOT_H
00612 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
SourceForge Logo

Generated on Wed Feb 9 2011 13:47:17 for IT++ by Doxygen 1.7.3