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     if(mybeh!=NULL)
00050       stop();
00051     if(behgrp!=NULL) {
00052       behgrp->RemoveReference();
00053       behgrp=NULL;
00054     }
00055     if(mybeh!=NULL)
00056       mybeh->RemoveReference();
00057   }
00058 
00059   //! activates the behavior, handy for making start-up behaviors that you can turn off again with the Controller
00060   /*! If you start twice without stopping (ie it's already running), shouldn't do anything */
00061   virtual BehaviorSwitchControlBase* start() { if(!isRunning()) { stopother(); startmine(); } return this; }
00062 
00063   //! stops the behavior
00064   virtual BehaviorSwitchControlBase* stop() { if(isRunning()) stopother(); return this; }
00065 
00066   //! toggles the behavior
00067   virtual BehaviorSwitchControlBase* toggle() { if(isRunning()) stopother(); else { stopother(); startmine(); } return this; }
00068 
00069   //! tells the current behavior (if there is one) to stop then loads its own
00070   /*! @return NULL unless there are submenus */
00071   virtual ControlBase * activate(MotionManager::MC_ID display, Socket * gui) {
00072     if(slotsSize()==0) {
00073       toggle();
00074       return NULL;
00075     } else
00076       return ControlBase::activate(display,gui);
00077   }
00078 
00079   //! adds a status to the name: - if in memory, # if running
00080   virtual std::string getName() const {
00081     return (mybeh->isActive()?'#':'-')+mybeh->getName();
00082   }
00083   virtual std::string getDescription() const {
00084     return mybeh->getDescription();
00085   }
00086   
00087 protected:
00088   //! Stops the "other" guy's behavior - if ::behgrp is NULL, stops ourselves
00089   virtual void stopother() {
00090     if(behgrp==NULL) {
00091       if(mybeh->isActive())
00092         mybeh->DoStop();
00093     } else if(behgrp->curBehavior!=NULL) {
00094       behgrp->curBehavior->DoStop();
00095       behgrp->curBehavior=NULL;
00096     }
00097   }
00098 
00099   //! Starts our behavior
00100   virtual void startmine() {
00101     if(behgrp!=NULL)
00102       behgrp->curBehavior=mybeh;
00103     mybeh->DoStart();
00104   }
00105 
00106   //! Returns true if the associated behavior is running
00107   virtual bool isRunning() const {
00108     if(mybeh==NULL) //not created or has been destroyed, definitely not running
00109       return false;
00110     // so, beh has been created (but may have been stopped by another in the group)
00111     if(behgrp==NULL) //no group
00112       return mybeh->isActive(); //just check active flag (is valid object, we would have set it to NULL if we stopped it ourselves)
00113     // so, we're in a group, someone else could have stopped us
00114     return (behgrp->curBehavior==mybeh); //all we can see is if the current behavior is ours.  If it is, it'll be active
00115   }
00116 
00117   BehaviorGroup * behgrp; //!< the behavior group this belongs to.  Uses this to track the "current" behavior
00118   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
00119 
00120 private:
00121   BehaviorSwitchControlBase(const BehaviorSwitchControlBase&); //!< shouldn't copy these
00122   BehaviorSwitchControlBase operator=(const BehaviorSwitchControlBase&); //!< shouldn't assign these
00123 };
00124 
00125 
00126 
00127 
00128 //! Allows proper switching between major behaviors, calling DoStart and DoStop
00129 template < class B, class Al = Factory< B > >
00130 class BehaviorSwitchControl : public BehaviorSwitchControlBase {
00131 public:
00132   //! constructor, can use this to toggle a single behavior on and off
00133   BehaviorSwitchControl(const std::string& n, bool retain=false)
00134     : BehaviorSwitchControlBase(n,NULL,NULL), retained(retain)
00135   {}
00136   //! constructor, if you want to use an already constructed behavior
00137   BehaviorSwitchControl(B* beh, BehaviorGroup* bg=NULL)
00138     : BehaviorSwitchControlBase(beh,bg), retained(true)
00139   {}
00140   //! 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)
00141   BehaviorSwitchControl(const std::string& n, B* beh, BehaviorGroup* bg=NULL, bool retain=false)
00142     : BehaviorSwitchControlBase(n,beh,bg), retained(retain)
00143   {
00144     if(!retained) {
00145       // have to make sure behavior is started to maintain invariants
00146       if(!mybeh->isActive()) {
00147         //keep reference from superclass's constructor in case mybeh stops itself right away
00148         mybeh->DoStart();
00149         bool stopped=!mybeh->isActive();
00150         mybeh->RemoveReference(); //cancels reference from BehaviorSwitchControlBase's constructor
00151         if(stopped)
00152           mybeh=NULL;
00153       } else
00154         mybeh->RemoveReference(); //cancels reference from BehaviorSwitchControlBase's constructor
00155     }
00156     if(behgrp!=NULL) {
00157       if(mybeh->isActive()) {
00158         if(behgrp->curBehavior!=NULL)
00159           behgrp->curBehavior->DoStop();
00160         behgrp->curBehavior=mybeh;
00161       } else if(!retained) {
00162         if(behgrp->curBehavior!=NULL)
00163           behgrp->curBehavior->DoStop();
00164         behgrp->curBehavior=NULL;
00165       }
00166     }
00167   }
00168   //! constructor, needs to know what group its in and whether to retain its behavior
00169   BehaviorSwitchControl(const std::string& n, BehaviorGroup* bg, bool retain=false)
00170     : BehaviorSwitchControlBase(n,NULL,bg), retained(retain)
00171   {}
00172   
00173   //! destructor
00174   virtual ~BehaviorSwitchControl() {
00175     stop();
00176     if(behgrp!=NULL) {
00177       behgrp->RemoveReference();
00178       behgrp=NULL;
00179     }
00180     if(mybeh!=NULL && retained)
00181       mybeh->RemoveReference();
00182     mybeh=NULL;
00183   }
00184 
00185   virtual std::string getName() const {
00186     if(!isValid())
00187       return ControlBase::getName();
00188     else
00189       return BehaviorSwitchControlBase::getName();
00190   }
00191   virtual std::string getDescription() const {
00192     if(!isValid() || mybeh->getDescription().size()==0)
00193       return B::getClassDescription();
00194     else
00195       return BehaviorSwitchControlBase::getDescription();
00196   }
00197   
00198 
00199 protected:
00200 
00201   virtual void stopother() {
00202     if(behgrp==NULL) {
00203       if(mybeh!=NULL) {
00204         if(mybeh->isActive()) {
00205           mybeh->DoStop();
00206           if(!retained)
00207             mybeh=NULL;
00208         } else
00209           ASSERT(retained,"null group, non-null not retained beh, not active, did you call inherited DoStart/DoStop in your Behavior?");
00210       }
00211     } else if(behgrp->curBehavior!=NULL) {
00212       behgrp->curBehavior->DoStop();
00213       if(behgrp->curBehavior==mybeh)
00214         mybeh=NULL;
00215       behgrp->curBehavior=NULL;
00216     }
00217   }
00218 
00219   virtual void startmine() {
00220     if(!retained) {
00221       mybeh=Al::construct();
00222       if(behgrp!=NULL)
00223         behgrp->curBehavior=mybeh;
00224     } else {
00225       if(mybeh==NULL) {
00226         mybeh=Al::construct();
00227         mybeh->AddReference();
00228       }
00229       if(behgrp!=NULL)
00230         behgrp->curBehavior=mybeh;
00231     }
00232     mybeh->AddReference(); //temporary reference in case mybeh stops itself right away
00233     mybeh->DoStart();
00234     bool stopped=(!mybeh->isActive() && !retained);
00235     mybeh->RemoveReference();
00236     if(stopped) {
00237       if(behgrp!=NULL && behgrp->curBehavior==mybeh)
00238         behgrp->curBehavior=NULL;
00239       mybeh=NULL;
00240     }
00241   }
00242 
00243   //! Returns true if mybeh is pointing to a valid object
00244   virtual bool isValid() const {
00245     if(isRunning())
00246       return true;
00247     return retained;
00248   }
00249 
00250 private:
00251   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
00252   BehaviorSwitchControl(const BehaviorSwitchControl&); //!< shouldn't call this
00253   BehaviorSwitchControl operator=(const BehaviorSwitchControl&); //!<shouldn't call this
00254 };
00255 
00256 /*! @file
00257  * @brief Defines BehaviorSwitchControl and the BehaviorSwitch namespace - a control for turning behaviors on and off
00258  * @author ejt (Creator)
00259  *
00260  * $Author: ejt $
00261  * $Name: tekkotsu-2_0 $
00262  * $Revision: 1.12 $
00263  * $State: Exp $
00264  * $Date: 2003/12/13 05:00:25 $
00265  */
00266 
00267 #endif

Tekkotsu v2.0
Generated Wed Jan 21 03:20:27 2004 by Doxygen 1.3.4