1 /*
2   This file is part of the Grantlee template system.
3 
4   Copyright (c) 2011 Stephen Kelly <steveire@gmail.com>
5 
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either version
9   2.1 of the Licence, or (at your option) any later version.
10 
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 #ifndef GRANTLEE_STATEMACHINE_P_H
22 #define GRANTLEE_STATEMACHINE_P_H
23 
24 #include <QtCore/QString>
25 #include <QtCore/QVector>
26 
27 namespace Grantlee
28 {
29 
30 template <typename TransitionInterface> class State
31 {
32 public:
33   typedef TransitionInterface Type;
34   class Transition : public TransitionInterface
35   {
36   public:
37     typedef TransitionInterface Type;
38     explicit Transition(State<TransitionInterface> *parent = {})
39     {
40       if (parent)
41         parent->addTransition(this);
42     }
setTargetState(State<TransitionInterface> * state)43     void setTargetState(State<TransitionInterface> *state)
44     {
45       m_targetState = state;
46     }
targetState()47     State<TransitionInterface> *targetState() const { return m_targetState; }
48 
49   private:
50     State<TransitionInterface> *m_targetState;
51   };
52 
53   explicit State(State<TransitionInterface> *parent = {})
54       : m_initialState(0), m_parent(parent), m_endTransition(0),
55         m_unconditionalTransition(0)
56   {
57     if (parent)
58       parent->addChild(this);
59   }
60 
~State()61   virtual ~State()
62   {
63     qDeleteAll(m_transitions);
64     qDeleteAll(m_children);
65   }
66 
addChild(State<TransitionInterface> * state)67   void addChild(State<TransitionInterface> *state) { m_children.append(state); }
children()68   QVector<State<TransitionInterface> *> children() const { return m_children; }
parent()69   State<TransitionInterface> *parent() const { return m_parent; }
70 
setInitialState(State<TransitionInterface> * state)71   void setInitialState(State<TransitionInterface> *state)
72   {
73     m_initialState = state;
74   }
initialState()75   State<TransitionInterface> *initialState() { return m_initialState; }
76 
addTransition(Transition * transition)77   void addTransition(Transition *transition)
78   {
79     m_transitions.append(transition);
80   }
transitions()81   QVector<Transition *> transitions() { return m_transitions; }
82 
setEndTransition(Transition * transition)83   void setEndTransition(Transition *transition)
84   {
85     delete m_endTransition;
86     m_endTransition = transition;
87   }
endTransition()88   Transition *endTransition() const { return m_endTransition; }
89 
setUnconditionalTransition(State<TransitionInterface> * transition)90   void setUnconditionalTransition(State<TransitionInterface> *transition)
91   {
92     delete m_unconditionalTransition;
93     m_unconditionalTransition = transition;
94   }
unconditionalTransition()95   State<TransitionInterface> *unconditionalTransition() const
96   {
97     return m_unconditionalTransition;
98   }
99 
enter()100   void enter() { onEntry(); }
exit()101   void exit() { onExit(); }
102 
103 protected:
onEntry()104   virtual void onEntry() {}
onExit()105   virtual void onExit() {}
106 
107 private:
108   State<TransitionInterface> *m_initialState;
109   QVector<Transition *> m_transitions;
110   QVector<State<TransitionInterface> *> m_children;
111   State<TransitionInterface> *const m_parent;
112   Transition *m_endTransition;
113   State<TransitionInterface> *m_unconditionalTransition;
114   QString m_stateName;
115 };
116 
117 template <typename TransitionInterface>
118 class StateMachine : public State<TransitionInterface>
119 {
120 public:
121   typedef typename State<TransitionInterface>::Transition Transition;
122 
123   explicit StateMachine(State<TransitionInterface> *parent = {})
124       : State<TransitionInterface>(parent), m_currentState(0)
125   {
126   }
127 
finished()128   void finished()
129   {
130     State<TransitionInterface> *s = m_currentState;
131     Q_FOREVER
132     {
133       Q_ASSERT(s);
134       if (!handleFinished(s))
135         s = s->parent();
136       else
137         break;
138     }
139   }
140 
start()141   void start()
142   {
143     m_currentState = this->initialState();
144     Q_ASSERT(m_currentState);
145     performEnter(m_currentState);
146   }
147 
stop()148   void stop()
149   {
150     performExit(this);
151     m_currentState = 0;
152   }
153 
154 protected:
currentState()155   State<TransitionInterface> *currentState() const { return m_currentState; }
156 
executeTransition(State<TransitionInterface> * sourceState,Transition * transition)157   void executeTransition(State<TransitionInterface> *sourceState,
158                          Transition *transition)
159   {
160     performExit(sourceState);
161     transition->onTransition();
162     m_currentState = transition->targetState();
163     State<TransitionInterface> *enteredState = m_currentState;
164     Q_ASSERT(enteredState);
165     performEnter(enteredState);
166     triggerUnconditionalTransition(enteredState);
167   }
168 
169 private:
performEnter(State<TransitionInterface> * toState)170   void performEnter(State<TransitionInterface> *toState)
171   {
172     toState->enter();
173     Q_FOREVER if (toState->initialState())
174     {
175       toState = toState->initialState();
176       Q_ASSERT(toState);
177       toState->enter();
178       m_currentState = toState;
179     }
180     else
181     {
182       Q_ASSERT(toState->children().isEmpty());
183       break;
184     }
185   }
186 
performExit(State<TransitionInterface> * fromState)187   void performExit(State<TransitionInterface> *fromState)
188   {
189     State<TransitionInterface> *exitedState = m_currentState;
190     do {
191       exitedState->exit();
192       exitedState = exitedState->parent();
193     } while (exitedState && exitedState != fromState);
194   }
195 
triggerUnconditionalTransition(State<TransitionInterface> * enteredState)196   void triggerUnconditionalTransition(State<TransitionInterface> *enteredState)
197   {
198     State<TransitionInterface> *childState = m_currentState;
199     do {
200       Q_ASSERT(childState);
201 
202       if (childState->unconditionalTransition()) {
203         Transition *t = new Transition;
204         t->setTargetState(childState->unconditionalTransition());
205         executeTransition(childState, t);
206         delete t;
207         return;
208       }
209       childState = childState->parent();
210       Q_ASSERT(childState != enteredState);
211       Q_UNUSED(enteredState);
212     } while (childState);
213   }
214 
handleFinished(State<TransitionInterface> * state)215   bool handleFinished(State<TransitionInterface> *state)
216   {
217     Transition *handler = state->endTransition();
218     if (!handler)
219       return false;
220 
221     executeTransition(state, handler);
222     return true;
223   }
224 
225 private:
226   State<TransitionInterface> *m_currentState;
227 };
228 }
229 
230 #endif
231