]> git.mxchange.org Git - simgear.git/blobdiff - simgear/structure/StateMachine.cxx
Add smart pointer tests (finally using Boost.Test)
[simgear.git] / simgear / structure / StateMachine.cxx
index 76a00b291910a1de973cd0b85bd5529f522e9c6d..b9e540c8aa79ee8303f1e8700a5f96bc597c5b46 100644 (file)
@@ -25,6 +25,7 @@
      
 #include "StateMachine.hxx"
 
+#include <algorithm>
 #include <cassert>
 #include <set>
 #include <boost/foreach.hpp>
@@ -70,6 +71,7 @@ public:
     SGBindingList _bindings;
     std::set<State*> _sourceStates; ///< weak refs to source states
     State* _target;
+    bool _excludeTarget;
     SGSharedPtr<SGCondition> _condition;
 };
     
@@ -91,6 +93,7 @@ public:
     }
     
     StateMachine* _p;
+    bool _initialised;
     State_ptr _currentState;
     StatePtrVec _states;
     std::vector<Transition_ptr> _transitions;
@@ -174,6 +177,7 @@ StateMachine::Transition::Transition(const std::string& aName, State* aTarget) :
     assert(aTarget);
     d->_name = aName;
     d->_target = aTarget;
+    d->_excludeTarget = true;
 }
 
 StateMachine::Transition::~Transition()
@@ -196,6 +200,13 @@ void StateMachine::Transition::addSourceState(State* aSource)
 
 bool StateMachine::Transition::applicableForState(State* aCurrent) const
 {
+    if (d->_excludeTarget && (aCurrent == d->_target)) {
+        return false;
+    }
+    
+    if (d->_sourceStates.empty()) {
+        return true;
+    }
     return d->_sourceStates.count(aCurrent);
 } 
     
@@ -224,12 +235,19 @@ void StateMachine::Transition::addBinding(SGBinding* aBinding)
     d->_bindings.push_back(aBinding);
 }
     
+void StateMachine::Transition::setExcludeTarget(bool aExclude)
+{
+    d->_excludeTarget = aExclude;
+}
+    
 ///////////////////////////////////////////////////////////////////////////
 
 StateMachine::StateMachine() :
     d(new StateMachinePrivate(this))
 {
     d->_root = new SGPropertyNode();
+    d->_listenerLockout = false;
+    d->_initialised = false;
 }
 
 StateMachine::~StateMachine()
@@ -239,7 +257,13 @@ StateMachine::~StateMachine()
 
 void StateMachine::init()
 {
+    if (d->_initialised) {
+           return;
+    }
     
+    if (d->_states.empty()) {
+        throw sg_range_exception("StateMachine::init: no states defined");
+    }
     
     d->_currentStateIndex = d->_root->getChild("current-index", 0, true);
     d->_currentStateIndex->setIntValue(0);
@@ -254,8 +278,8 @@ void StateMachine::init()
     d->_timeInStateProp->setIntValue(0);
     
     // TODO go to default state if found
-    d->computeEligibleTransitions();
-    
+    innerChangeState(d->_states[0], NULL);
+    d->_initialised = true;
 }
 
 void StateMachine::shutdown()
@@ -267,7 +291,9 @@ void StateMachine::shutdown()
 
 void StateMachine::innerChangeState(State_ptr aState, Transition_ptr aTrans)
 {
-    d->_currentState->fireExitBindings();
+    if (d->_currentState) {
+        d->_currentState->fireExitBindings();
+    }
         
 // fire bindings before we change the state, hmmmm    
     if (aTrans) {
@@ -401,10 +427,13 @@ StateMachine::createTransition(const std::string& aName, State_ptr aTarget)
     return t;
 }
 
-StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
+void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
 {
-    StateMachine* sm = new StateMachine;
-    
+    std::string path = desc->getStringValue("branch");
+    if (!path.empty()) {
+        d->_root = root->getNode(path, 0, true);
+        assert(d->_root);
+    }
     
     BOOST_FOREACH(SGPropertyNode* stateDesc, desc->getChildren("state")) {
         std::string nm = stateDesc->getStringValue("name");
@@ -414,28 +443,36 @@ StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode
         readBindingList(stateDesc, "exit", root, st->d->_entryBindings);
         readBindingList(stateDesc, "update", root, st->d->_exitBindings);
         
-        sm->addState(st);
+        addState(st);
     } // of states iteration
     
     BOOST_FOREACH(SGPropertyNode* tDesc, desc->getChildren("transition")) {
         std::string nm = tDesc->getStringValue("name");
-        State_ptr target = sm->findStateByName(tDesc->getStringValue("target"));
+        State_ptr target = findStateByName(tDesc->getStringValue("target"));
         
         SGCondition* cond = sgReadCondition(root, tDesc->getChild("condition"));
         
         Transition_ptr t(new Transition(nm, target));
         t->setTriggerCondition(cond);
         
+        t->setExcludeTarget(tDesc->getBoolValue("exclude-target", true));
         BOOST_FOREACH(SGPropertyNode* src, desc->getChildren("source")) {
-            State_ptr srcState = sm->findStateByName(src->getStringValue());
+            State_ptr srcState = findStateByName(src->getStringValue());
             t->addSourceState(srcState);
         }
         
         readBindingList(tDesc, "binding", root, t->d->_bindings);
         
-        sm->addTransition(t);
+        addTransition(t);
     } // of states iteration
     
+    init();
+}
+
+StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
+{
+    StateMachine* sm = new StateMachine;
+    sm->initFromPlist(desc, root);
     return sm;
 }