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

Generated on Wed Jul 27 2011 16:27:05 for IT++ by Doxygen 1.7.4