IT++ Logo Newcom Logo

signals_slots.h

Go to the documentation of this file.
00001 
00033 #ifndef SIGNAL_SLOT_H
00034 #define SIGNAL_SLOT_H
00035 
00036 #include <itpp/protocol/events.h>
00037 #include <list>
00038 #include <iostream>
00039 
00040 
00041 namespace itpp {
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:
00150     typedef typename std::list<Base_Slot<DataType>*, std::allocator< Base_Slot<DataType>* > >::iterator Base_Slot_Iterator;
00151     void _disconnect(Base_Slot<DataType>* slot);
00152     std::list<Base_Slot<DataType>*, std::allocator<Base_Slot<DataType>* > > connected_slots;
00153     std::string name;
00154 
00155   private:
00156     bool armed; 
00157     bool debug;
00158     bool single;
00159     Data_Event<Signal, DataType> *e;
00160   };
00161 
00162 
00167   template<class DataType> 
00168     class Base_Slot{
00169   public:
00170     friend class Signal<DataType>;
00171 
00173     Base_Slot(const std::string slot_name = "Unamed Base_Slot");
00174 
00176     virtual ~Base_Slot();
00177 
00179     void set_name(const std::string &slot_name);
00180 
00182     virtual void operator()(DataType signal) = 0;
00183 
00184   protected:
00185     //   virtual void exec(DataType signal) = 0;
00186     typedef typename std::list<Signal<DataType>*, std::allocator< Signal<DataType>* > >::iterator Signal_Iterator;
00187     std::string name;
00188     void _connect(Signal<DataType>* signal);
00189     void _disconnect(Signal<DataType>* signal);
00190     std::list<Signal<DataType>*, std::allocator<Signal<DataType>* > > connected_signals;
00191   };
00192 
00197   template<class ObjectType, class DataType>
00198     class Slot : public Base_Slot<DataType> {
00199   public:
00201     Slot(const std::string _name = "Unamed Slot");
00202 
00204     void forward(ObjectType *object_pointer, void(ObjectType::*object_function_pointer)(DataType u));
00205     
00207     ~Slot();
00208 
00210     void operator()(DataType u);
00211 
00212     //void exec(DataType signal);
00213 
00214   private:
00215     ObjectType *po;
00216     void(ObjectType::*pm)(DataType signal); 
00217   };
00218 
00219 
00223   template<class ObjectType, class DataType>
00224     class ATimer {
00225   public:
00227     ATimer(const std::string Name = "Unamed ATimer") {    
00228       time_out_signal = new Signal<DataType>(Name, true);
00229       time_out_slot = new Slot<ObjectType, DataType>(Name);
00230       time_out_signal->connect(time_out_slot); 
00231       set_name(Name);
00232     }
00233 
00235     void forward(ObjectType *po, void(ObjectType::*pm)(DataType u)) { time_out_slot->forward(po, pm); }
00236 
00238     void set(DataType u, const Ttype delta_t) {
00239       time_out_signal->operator()(u, delta_t);
00240     }
00241 
00243     void cancel() { time_out_signal->cancel(); }
00244 
00246     void set_name(const std::string Name) {
00247       name = Name;
00248       time_out_signal->set_name(name);
00249       time_out_slot->set_name(name);
00250     }
00251 
00252   protected:
00253     std::string name;
00254 
00255   private:
00256     Signal<DataType> *time_out_signal;
00257     Slot<ObjectType, DataType> *time_out_slot;
00258   };
00259 
00260 
00261 
00270   template <class THandler>
00271     class TTimer {
00272   public:
00273     TTimer(THandler & handler, void (THandler::*handlerFunction) (Ttype time)) :
00274       signal("timer_signal", true)
00275     {
00276       fPending = false;
00277       fExpirationTime = 0;
00278 
00279       registered_handler = &handler;
00280       registered_handler_function = handlerFunction;
00281 
00282       slot.forward(this, &TTimer<THandler>::HandleProcessEvent);
00283       slot.set_name("timer_slot");
00284       signal.set_debug(false);
00285       signal.connect(&slot);  
00286     }
00287 
00288     virtual ~TTimer() {
00289       if (fPending)
00290         signal.cancel();   
00291     }
00292     
00293     void  Set(Ttype time, bool relative = true) {
00294         if (fPending)
00295           signal.cancel();   
00296 
00297         fPending = true;
00298         double current_time = Event_Queue::now();
00299         double delta_time;
00300         if (relative) {
00301           fExpirationTime = current_time + time;
00302           delta_time = time;
00303         } else {
00304           fExpirationTime = time;
00305           delta_time = time - current_time;
00306         }
00307         signal(fExpirationTime, delta_time);
00308       }
00309 
00310     void  Reset() {
00311         if (fPending) {
00312           signal.cancel();
00313           fPending = false; // TODO: Added this myself. Didn't work otherwise.
00314         }
00315       }
00316 
00317     Ttype  ExpirationTime() const
00318     {
00319       it_assert(fPending, "TTimer<>::ExpirationTime: timer not set");
00320       return fExpirationTime;
00321     }
00322 
00323     bool  IsPending() const { return fPending; }
00324 
00325   protected:
00326     virtual void HandleProcessEvent (Ttype currentTime) {
00327         fPending = false;
00328         (*registered_handler.*registered_handler_function)(currentTime);
00329       }
00330 
00331     virtual void HandleCancelEvent (Ttype) {
00332         if (fPending)
00333           signal.cancel();   
00334 
00335         fPending = false;
00336       }
00337 
00338     bool  fPending;    
00339     Ttype  fExpirationTime;
00340 
00341   private:
00342     THandler *registered_handler;
00343     void(THandler::*registered_handler_function)(Ttype expiry_time);
00344 
00345     Signal<double> signal;     // Used internally
00346     Slot<TTimer, double> slot; // Used internally
00347   };
00348 
00349 
00350 
00351 
00352 
00353 
00354     // -----------------------------------------------------------------------------------------------
00355 
00356     template<class DataType>
00357       Signal<DataType>::Signal(const std::string signal_name, const bool single_shot, const bool enable_debug) 
00358       {
00359         armed = false;
00360         e = NULL;
00361         single = single_shot;
00362         set_name(signal_name);
00363         set_debug(enable_debug);
00364       }
00365 
00366     template<class DataType>
00367       Signal<DataType>::~Signal()
00368       {
00369         Base_Slot_Iterator
00370           begin = connected_slots.begin(),
00371           end   = connected_slots.end(),
00372           i;
00373 
00374         for(i=begin; i!=end; i++)
00375           (*i)->_disconnect(this);
00376   
00377         connected_slots.clear();
00378 
00379         if(e!=NULL) // Cancel a possibly pending event since we are about to die!
00380           e->cancel();  
00381       }
00382 
00383     template<class DataType>
00384       void Signal<DataType>::set_name(const std::string &signal_name) 
00385       {
00386         name = signal_name;
00387       }
00388 
00389     template<class DataType>
00390       void Signal<DataType>::set_debug(const bool enable_debug)
00391       {
00392         debug = enable_debug;
00393       }
00394 
00395     template<class DataType>
00396       void Signal<DataType>::connect(Base_Slot<DataType>* slot)
00397       {
00398         Base_Slot_Iterator
00399           begin = connected_slots.begin(),
00400           end   = connected_slots.end(),
00401           i;  
00402 
00403         bool is_already_connected = false;
00404 
00405         for(i=begin; i!=end; i++)
00406           if((*i) == slot)
00407             is_already_connected = true;  
00408 
00409         if(!is_already_connected) { // Multiple connections is meaningless.
00410           connected_slots.push_back(slot);
00411           slot->_connect(this); // Needed if a connected slot is deleted during run time.
00412         } else {
00413           std::cout<<"Signal '"<< name <<"' and Slot '"<< slot->name<<"' are already connected. Multiple connections have no effect!"<< std::endl;    
00414         }
00415       }
00416 
00417     template<class DataType>
00418       void Signal<DataType>::disconnect(Base_Slot<DataType>* slot)
00419       {
00420         Base_Slot_Iterator
00421           begin = connected_slots.begin(),
00422           end   = connected_slots.end(),
00423           i;
00424 
00425         for(i=begin; i!=end; i++)
00426           if((*i) == slot) {
00427             (*i)->_disconnect(this);
00428             connected_slots.erase(i);
00429             break;
00430           }                
00431       }
00432 
00433     template<class DataType>
00434       Base_Event* Signal<DataType>::operator()(DataType signal, const Ttype delta_time)
00435       {
00436         // Signal will trigger in 'delta_time' time units.
00437         if(single){ // We are operating in single-shot mode.
00438           if(armed){ // Cancel and schedule again with the new 'delta_time'.
00439             if(debug)
00440               std::cout<<"Warning: Changing time for Signal '"<<name<<"'."<< std::endl;
00441             cancel();
00442             operator()(signal, delta_time);
00443           } else {
00444             e = new Data_Event<Signal, DataType>(this, &Signal<DataType>::trigger, signal, delta_time);
00445             armed = true;
00446             Event_Queue::add(e);    
00447           }
00448         } else { // Continious mode (cancel() has no effect).
00449           e = new Data_Event<Signal, DataType>(this, &Signal<DataType>::trigger, signal, delta_time);
00450           armed = true;
00451           Event_Queue::add(e);       
00452         }
00453         return e;
00454       }
00455 
00456     template<class DataType>
00457       void Signal<DataType>::cancel()
00458       {
00459         if(armed&&single){
00460           e->cancel();
00461           e = NULL;
00462           armed = false;
00463         }
00464       }
00465 
00466 
00467     template<class DataType>
00468       void Signal<DataType>::trigger(DataType u)
00469       {
00470         armed = false;
00471         e = NULL;
00472         Base_Slot_Iterator
00473           begin = connected_slots.begin(),
00474           end   = connected_slots.end(),
00475           i;
00476 
00477         for(i=begin; i!=end; i++) { // Execute all the functions of the connected slots.
00478           if(debug)
00479             std::cout << "Time = " << Event_Queue::now() << ". Signal '" << name << "' was sent to Slot '" << (*i)->name<< "'." << std::endl;
00480           (*i)->operator()(u);      
00481         }
00482       }
00483 
00484     template<class DataType>
00485       void Signal<DataType>::_disconnect(Base_Slot<DataType>* slot)
00486       {
00487         Base_Slot_Iterator
00488           begin = connected_slots.begin(),
00489           end   = connected_slots.end(),
00490           i;
00491 
00492         for(i=begin; i!=end; i++)
00493           if((*i) == slot) {
00494             connected_slots.erase(i);
00495             break;
00496           }                
00497       }
00498 
00499 
00500     template<class DataType>
00501       Base_Slot<DataType>::Base_Slot(const std::string slot_name)
00502       {
00503         set_name(slot_name);
00504       }
00505 
00506     template<class DataType>
00507       void Base_Slot<DataType>::set_name(const std::string &slot_name)
00508       {
00509         name = slot_name;
00510       }
00511 
00512     template<class DataType>
00513       Base_Slot<DataType>::~Base_Slot()
00514       { // Notify all signals connect that we are being deleted ...
00515 
00516         Signal_Iterator
00517           begin = connected_signals.begin(),
00518           end   = connected_signals.end(),
00519           i;
00520 
00521         for(i=begin; i!=end; i++)
00522           (*i)->_disconnect(this);  
00523   
00524         connected_signals.clear();
00525       }
00526 
00527     template<class DataType>
00528       void Base_Slot<DataType>::_connect(Signal<DataType>* signal)
00529       { // A signal is being connected to us.
00530         connected_signals.push_back(signal);
00531       }
00532 
00533     template<class DataType>
00534       void Base_Slot<DataType>::_disconnect(Signal<DataType>* signal)
00535       { // A signal is being disconnected from us.
00536 
00537         Signal_Iterator
00538           begin = connected_signals.begin(),
00539           end   = connected_signals.end(),
00540           i;
00541 
00542         for(i=begin; i!=end; i++)
00543           if((*i) == signal) {
00544             connected_signals.erase(i);
00545             break;
00546           }
00547       }
00548 
00549     template<class ObjectType, class DataType>
00550       Slot<ObjectType, DataType>::Slot(const std::string slot_name) : Base_Slot<DataType>(slot_name)
00551       {
00552         pm = NULL;    
00553         po = NULL;      
00554       }
00555 
00556       template<class ObjectType, class DataType>
00557         Slot<ObjectType, DataType>::~Slot(){}
00558 
00559       template<class ObjectType, class DataType>
00560         void Slot<ObjectType, DataType>::forward(ObjectType *object_pointer, void(ObjectType::*object_function_pointer)(DataType u))
00561         {
00562           pm = object_function_pointer;    
00563           po = object_pointer;
00564         }
00565 
00566       // template<class ObjectType, class DataType>
00567       // void Slot<ObjectType, DataType>::exec(DataType signal){
00568       //   if(pm&&po) 
00569       //     (*po.*pm)(signal);
00570       // } 
00571 
00572       template<class ObjectType, class DataType>
00573         void Slot<ObjectType, DataType>::operator()(DataType signal)
00574         {
00575           if(pm&&po) 
00576             (*po.*pm)(signal);
00577         }
00578 
00579 } // namespace itpp
00580 
00581 #endif // #ifndef SIGNAL_SLOT_H
00582 
SourceForge Logo

Generated on Sat Aug 25 23:40:28 2007 for IT++ by Doxygen 1.5.2