Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

BehaviorSwitchControl.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_BehaviorSwitchControl_h_
00003 #define INCLUDED_BehaviorSwitchControl_h_
00004 
00005 #include "ControlBase.h"
00006 #include "Behaviors/BehaviorBase.h"
00007 #include "Shared/ReferenceCounter.h"
00008 #include "Shared/Factories.h"
00009 #include "Shared/debuget.h"
00010 #include "Events/TextMsgEvent.h"
00011 
00012 //! Holds some utility classes and functions for BehaviorSwitchControl which shouldn't be stored in a templated class
00013 class BehaviorSwitchControlBase : public ControlBase {
00014 public:
00015   //! A simple utility class to allow the BehaviorSwitchControl's to be able to deactivate the current behavior when a new one becomes active
00016   /*! Most behaviors are either major actions which you'll only want one of active
00017    *  at a time, or else their background monitors of some sort, that can run in different
00018    *  combinations.  Think radio buttons vs. checkboxes.  This will help you implement the
00019    *  "radio button" style... just assign all the behaviors to the same group, they will
00020    *  automatically use it to turn the previous behavior off when a new one becomes active.\n
00021    *  Pass NULL instead of one of these to get checkbox-style. */
00022   class BehaviorGroup : public ReferenceCounter {
00023   public:
00024     BehaviorGroup() : curBehavior(NULL), members() { } //!< contructor
00025     ~BehaviorGroup() { if(curBehavior!=NULL) curBehavior->DoStop(); } //!< destructor, will stop the current behavior if it was a one-shot
00026     BehaviorBase * curBehavior; //!< pointer to current behavior
00027     std::set<BehaviorSwitchControlBase*> members; //!< set of members of the group
00028   private:
00029     BehaviorGroup(const BehaviorGroup&); //!< shouldn't be called
00030     BehaviorGroup operator=(const BehaviorGroup&); //!< shouldn't be called
00031   };
00032   
00033   //! constructor
00034   BehaviorSwitchControlBase(const std::string& n, BehaviorBase* beh, BehaviorGroup* bg=NULL)
00035     : ControlBase(n), behgrp(bg), mybeh(beh) {
00036     if(mybeh!=NULL) {
00037       mybeh->AddReference();
00038       mybeh->setName(n);
00039       if(mybeh->isActive())
00040         mybeh->AddReference();
00041     }
00042     if(behgrp!=NULL) {
00043       behgrp->AddReference();
00044       behgrp->members.insert(this);
00045       if(mybeh!=NULL && mybeh->isActive()) {
00046         if(behgrp->curBehavior!=NULL) {
00047           behgrp->curBehavior->DoStop();
00048           notifyGroupMembers();
00049         }
00050         behgrp->curBehavior=mybeh;
00051       }
00052     }
00053   }
00054   //! constructor, behavior must not be NULL
00055   BehaviorSwitchControlBase(BehaviorBase* beh, BehaviorGroup* bg=NULL)
00056     : ControlBase(beh->getName()), behgrp(bg), mybeh(beh) {
00057     mybeh->AddReference();
00058     if(mybeh->isActive())
00059       mybeh->AddReference();
00060     if(behgrp!=NULL) {
00061       behgrp->AddReference();
00062       behgrp->members.insert(this);
00063       if(mybeh!=NULL && mybeh->isActive()) {
00064         if(behgrp->curBehavior!=NULL) {
00065           behgrp->curBehavior->DoStop();
00066           notifyGroupMembers();
00067         }
00068         behgrp->curBehavior=mybeh;
00069       }
00070     }
00071   }
00072 
00073   //! destructor
00074   virtual ~BehaviorSwitchControlBase() {
00075     //cout << "~BehaviorSwitchControlBase(): " << getName() << endl;
00076     if(mybeh!=NULL)
00077       stop();
00078     if(behgrp!=NULL) {
00079       behgrp->members.erase(this);
00080       behgrp->RemoveReference();
00081       behgrp=NULL;
00082     }
00083     if(mybeh!=NULL)
00084       mybeh->RemoveReference();
00085   }
00086 
00087   //! activates the behavior, handy for making start-up behaviors that you can turn off again with the Controller
00088   /*! If you start twice without stopping (ie it's already running), shouldn't do anything */
00089   virtual BehaviorSwitchControlBase* start() { if(!isRunning()) { stopother(); startmine(); } return this; }
00090 
00091   //! stops the behavior
00092   virtual BehaviorSwitchControlBase* stop() { if(isRunning()) stopother(); return this; }
00093 
00094   //! toggles the behavior
00095   virtual BehaviorSwitchControlBase* toggle() { if(isRunning()) stopother(); else { stopother(); startmine(); } return this; }
00096 
00097   virtual ControlBase * takeInput(const std::string& msg) {
00098     if(options.size()>0)
00099       return ControlBase::takeInput(msg);
00100     if(!isRunning())
00101       startmine();
00102     mybeh->processEvent(TextMsgEvent(msg,1));
00103     return NULL;
00104   }
00105   
00106   //! tells the current behavior (if there is one) to stop then loads its own
00107   /*! @return NULL unless there are submenus */
00108   virtual ControlBase * activate(MotionManager::MC_ID display, Socket * gui) {
00109     if(slotsSize()==0) {
00110       toggle();
00111       return NULL;
00112     } else
00113       return ControlBase::activate(display,gui);
00114   }
00115 
00116   //! adds a status to the name: - if in memory, # if running
00117   virtual std::string getName() const {
00118     if(mybeh==NULL)
00119       return ControlBase::getName();
00120     return (mybeh->isActive()?'#':'-')+mybeh->getName();
00121   }
00122   virtual std::string getDescription() const {
00123     if(mybeh==NULL)
00124       return ControlBase::getDescription();
00125     return "Class "+mybeh->getClassName()+": "+mybeh->getDescription();
00126   }
00127   
00128   //! Returns true if the associated behavior is running
00129   virtual bool isRunning() const {
00130     if(mybeh==NULL) //not created or has been destroyed, definitely not running
00131       return false;
00132     // so, beh has been created (but may have been stopped by another in the group)
00133     return mybeh->isActive(); //just check active flag (is valid object, we would have set it to NULL if we stopped it ourselves)
00134   }
00135   
00136 protected:
00137   //! Stops the "other" guy's behavior - if ::behgrp is NULL, stops ourselves
00138   virtual void stopother() {
00139     if(behgrp==NULL) {
00140       if(mybeh!=NULL && mybeh->isActive()) {
00141         mybeh->DoStop();
00142         behaviorStopped();
00143       }
00144     } else if(behgrp->curBehavior!=NULL) {
00145       if(behgrp->curBehavior->isActive()) {
00146         behgrp->curBehavior->DoStop();
00147         notifyGroupMembers();
00148       }
00149       behgrp->curBehavior=NULL;
00150     }
00151   }
00152   
00153   //! Starts our behavior
00154   virtual void startmine() {
00155     if(behgrp!=NULL)
00156       behgrp->curBehavior=mybeh;
00157     mybeh->DoStart();
00158   }
00159   
00160   //! updates other members in the group that the current behavior stopped -- do not call if behgrp is NULL
00161   virtual void notifyGroupMembers() {
00162     for(std::set<BehaviorSwitchControlBase*>::iterator it=behgrp->members.begin(); it!=behgrp->members.end(); ++it)
00163       if((*it)->mybeh==behgrp->curBehavior)
00164         (*it)->behaviorStopped();
00165   }
00166   //! called by notifyGroupMembers if #mybeh was destructed when stopped
00167   virtual void behaviorStopped() {}
00168 
00169   BehaviorGroup * behgrp; //!< the behavior group this belongs to.  Uses this to track the "current" behavior
00170   BehaviorBase* mybeh; //!< used to store the behavior.  If retained and non-NULL, will be valid.  However, if not retained, only valid if equals behgrp->curBehavior
00171 
00172 private:
00173   BehaviorSwitchControlBase(const BehaviorSwitchControlBase&); //!< shouldn't copy these
00174   BehaviorSwitchControlBase operator=(const BehaviorSwitchControlBase&); //!< shouldn't assign these
00175 };
00176 
00177 
00178 
00179 
00180 //! Allows proper switching between major behaviors, calling DoStart and DoStop
00181 template < class B, class Al = typename Factory0Arg<B>::template Factory<B> >
00182 class BehaviorSwitchControl : public BehaviorSwitchControlBase {
00183 public:
00184   //! constructor, can use this to toggle a single behavior on and off
00185   BehaviorSwitchControl(const std::string& n, bool retain=false)
00186     : BehaviorSwitchControlBase(n,NULL,NULL), retained(retain), startref(NULL)
00187   {}
00188   //! constructor, if you want to use an already constructed behavior
00189   BehaviorSwitchControl(B* beh, BehaviorGroup* bg=NULL)
00190     : BehaviorSwitchControlBase(beh,bg), retained(true), startref(NULL)
00191   {}
00192   //! constructor, if you want to use an already constructed behavior, but unretain it if it's stopped (if not retaining, will start @a beh if it's not already started)
00193   BehaviorSwitchControl(const std::string& n, B* beh, BehaviorGroup* bg=NULL, bool retain=false)
00194     : BehaviorSwitchControlBase(n,beh,bg), retained(retain), startref(NULL)
00195   {
00196     if(!retained) {
00197       // have to make sure behavior is started to maintain invariants
00198       if(!mybeh->isActive()) {
00199         startmine();
00200       }
00201       mybeh->RemoveReference(); //cancels reference from BehaviorSwitchControlBase's constructor
00202     }
00203   }
00204   //! constructor, needs to know what group its in and whether to retain its behavior
00205   BehaviorSwitchControl(const std::string& n, BehaviorGroup* bg, bool retain=false)
00206     : BehaviorSwitchControlBase(n,NULL,bg), retained(retain), startref(NULL)
00207   {}
00208   
00209   //! destructor
00210   virtual ~BehaviorSwitchControl() {
00211     stop();
00212     if(behgrp!=NULL) {
00213       behgrp->members.erase(this);
00214       behgrp->RemoveReference();
00215       behgrp=NULL;
00216     }
00217     if(mybeh!=NULL && retained)
00218       mybeh->RemoveReference();
00219     mybeh=NULL;
00220   }
00221 
00222   virtual std::string getName() const {
00223     if(!isValid())
00224       return ControlBase::getName();
00225     else
00226       return BehaviorSwitchControlBase::getName();
00227   }
00228   virtual std::string getDescription() const {
00229     if(!isValid() || mybeh->getDescription().size()==0)
00230       return B::getClassDescription();
00231     else
00232       return BehaviorSwitchControlBase::getDescription();
00233   }
00234   
00235 protected:
00236 
00237   virtual void startmine() {
00238     if(!retained) {
00239       Al allocator;
00240       mybeh=allocator();
00241       mybeh->setName(getName());
00242       if(behgrp!=NULL)
00243         behgrp->curBehavior=mybeh;
00244     } else {
00245       if(mybeh==NULL) {
00246         Al allocator;
00247         mybeh=allocator();
00248         mybeh->setName(getName());
00249         mybeh->AddReference();
00250       }
00251       if(behgrp!=NULL)
00252         behgrp->curBehavior=mybeh;
00253     }
00254     startref=mybeh;
00255     startref->AddReference();
00256     mybeh->DoStart();
00257   }
00258 
00259   //! adds a check to see if behavior has stopped itself -- if so, remove startref
00260   virtual bool isRunning() const {
00261     if(BehaviorSwitchControlBase::isRunning())
00262       return true;
00263     else if(startref!=NULL)
00264       const_cast<BehaviorSwitchControl<B,Al>*>(this)->stopother();
00265     return false;
00266   }   
00267   
00268   //! Returns true if mybeh is pointing to a valid object
00269   virtual bool isValid() const {
00270     if(isRunning())
00271       return true;
00272     return retained;
00273   }
00274 
00275   virtual void behaviorStopped() {
00276     if(!retained)
00277       mybeh=NULL;
00278     if(startref!=NULL) {
00279       startref->RemoveReference();
00280       startref=NULL;
00281     }
00282   }
00283   
00284   bool retained; //!< true if the behavior should be generated once and retained after DoStop.  Otherwise, a new one is generated each time it is started
00285   BehaviorBase * startref; //!< true if a reference was added (and still current) from calling DoStart
00286   
00287 private:
00288   BehaviorSwitchControl(const BehaviorSwitchControl&); //!< shouldn't call this
00289   BehaviorSwitchControl operator=(const BehaviorSwitchControl&); //!<shouldn't call this
00290 };
00291 
00292 /*! @file
00293  * @brief Defines BehaviorSwitchControl and the BehaviorSwitch namespace - a control for turning behaviors on and off
00294  * @author ejt (Creator)
00295  *
00296  * $Author: ejt $
00297  * $Name: tekkotsu-4_0 $
00298  * $Revision: 1.25 $
00299  * $State: Exp $
00300  * $Date: 2007/05/22 04:24:26 $
00301  */
00302 
00303 #endif

Tekkotsu v4.0
Generated Thu Nov 22 00:54:51 2007 by Doxygen 1.5.4