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

Generated on Sun Sep 14 18:52:28 2008 for IT++ by Doxygen 1.5.6