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

Tekkotsu v2.1
Generated Tue Mar 16 23:19:12 2004 by Doxygen 1.3.5