File indexing completed on 2025-02-09 04:28:40
0001 /* 0002 This file is part of the KTextTemplate library 0003 0004 SPDX-FileCopyrightText: 2011 Stephen Kelly <steveire@gmail.com> 0005 0006 SPDX-License-Identifier: LGPL-2.1-or-later 0007 0008 */ 0009 0010 #ifndef KTEXTTEMPLATE_STATEMACHINE_P_H 0011 #define KTEXTTEMPLATE_STATEMACHINE_P_H 0012 0013 #include <QList> 0014 #include <QString> 0015 0016 namespace KTextTemplate 0017 { 0018 0019 template<typename TransitionInterface> 0020 class State 0021 { 0022 public: 0023 typedef TransitionInterface Type; 0024 class Transition : public TransitionInterface 0025 { 0026 public: 0027 typedef TransitionInterface Type; 0028 explicit Transition(State<TransitionInterface> *parent = {}) 0029 { 0030 if (parent) 0031 parent->addTransition(this); 0032 } 0033 void setTargetState(State<TransitionInterface> *state) 0034 { 0035 m_targetState = state; 0036 } 0037 State<TransitionInterface> *targetState() const 0038 { 0039 return m_targetState; 0040 } 0041 0042 private: 0043 State<TransitionInterface> *m_targetState; 0044 }; 0045 0046 explicit State(State<TransitionInterface> *parent = {}) 0047 : m_initialState(nullptr) 0048 , m_parent(parent) 0049 , m_endTransition(nullptr) 0050 , m_unconditionalTransition(nullptr) 0051 { 0052 if (parent) 0053 parent->addChild(this); 0054 } 0055 0056 virtual ~State() 0057 { 0058 qDeleteAll(m_transitions); 0059 qDeleteAll(m_children); 0060 } 0061 0062 void addChild(State<TransitionInterface> *state) 0063 { 0064 m_children.append(state); 0065 } 0066 QList<State<TransitionInterface> *> children() const 0067 { 0068 return m_children; 0069 } 0070 State<TransitionInterface> *parent() const 0071 { 0072 return m_parent; 0073 } 0074 0075 void setInitialState(State<TransitionInterface> *state) 0076 { 0077 m_initialState = state; 0078 } 0079 State<TransitionInterface> *initialState() 0080 { 0081 return m_initialState; 0082 } 0083 0084 void addTransition(Transition *transition) 0085 { 0086 m_transitions.append(transition); 0087 } 0088 QList<Transition *> transitions() 0089 { 0090 return m_transitions; 0091 } 0092 0093 void setEndTransition(Transition *transition) 0094 { 0095 delete m_endTransition; 0096 m_endTransition = transition; 0097 } 0098 Transition *endTransition() const 0099 { 0100 return m_endTransition; 0101 } 0102 0103 void setUnconditionalTransition(State<TransitionInterface> *transition) 0104 { 0105 delete m_unconditionalTransition; 0106 m_unconditionalTransition = transition; 0107 } 0108 State<TransitionInterface> *unconditionalTransition() const 0109 { 0110 return m_unconditionalTransition; 0111 } 0112 0113 void enter() 0114 { 0115 onEntry(); 0116 } 0117 void exit() 0118 { 0119 onExit(); 0120 } 0121 0122 protected: 0123 virtual void onEntry() 0124 { 0125 } 0126 virtual void onExit() 0127 { 0128 } 0129 0130 private: 0131 State<TransitionInterface> *m_initialState; 0132 QList<Transition *> m_transitions; 0133 QList<State<TransitionInterface> *> m_children; 0134 State<TransitionInterface> *const m_parent; 0135 Transition *m_endTransition = nullptr; 0136 State<TransitionInterface> *m_unconditionalTransition; 0137 QString m_stateName; 0138 }; 0139 0140 template<typename TransitionInterface> 0141 class StateMachine : public State<TransitionInterface> 0142 { 0143 public: 0144 typedef typename State<TransitionInterface>::Transition Transition; 0145 0146 explicit StateMachine(State<TransitionInterface> *parent = {}) 0147 : State<TransitionInterface>(parent) 0148 , m_currentState(nullptr) 0149 { 0150 } 0151 0152 void finished() 0153 { 0154 State<TransitionInterface> *s = m_currentState; 0155 Q_FOREVER { 0156 Q_ASSERT(s); 0157 if (!handleFinished(s)) 0158 s = s->parent(); 0159 else 0160 break; 0161 } 0162 } 0163 0164 void start() 0165 { 0166 m_currentState = this->initialState(); 0167 Q_ASSERT(m_currentState); 0168 performEnter(m_currentState); 0169 } 0170 0171 void stop() 0172 { 0173 performExit(this); 0174 m_currentState = nullptr; 0175 } 0176 0177 protected: 0178 State<TransitionInterface> *currentState() const 0179 { 0180 return m_currentState; 0181 } 0182 0183 void executeTransition(State<TransitionInterface> *sourceState, Transition *transition) 0184 { 0185 performExit(sourceState); 0186 transition->onTransition(); 0187 m_currentState = transition->targetState(); 0188 State<TransitionInterface> *enteredState = m_currentState; 0189 Q_ASSERT(enteredState); 0190 performEnter(enteredState); 0191 triggerUnconditionalTransition(enteredState); 0192 } 0193 0194 private: 0195 void performEnter(State<TransitionInterface> *toState) 0196 { 0197 toState->enter(); 0198 Q_FOREVER 0199 if (toState->initialState()) { 0200 toState = toState->initialState(); 0201 Q_ASSERT(toState); 0202 toState->enter(); 0203 m_currentState = toState; 0204 } else { 0205 Q_ASSERT(toState->children().isEmpty()); 0206 break; 0207 } 0208 } 0209 0210 void performExit(State<TransitionInterface> *fromState) 0211 { 0212 State<TransitionInterface> *exitedState = m_currentState; 0213 do { 0214 exitedState->exit(); 0215 exitedState = exitedState->parent(); 0216 } while (exitedState && exitedState != fromState); 0217 } 0218 0219 void triggerUnconditionalTransition(State<TransitionInterface> *enteredState) 0220 { 0221 State<TransitionInterface> *childState = m_currentState; 0222 do { 0223 Q_ASSERT(childState); 0224 0225 if (childState->unconditionalTransition()) { 0226 Transition *t = new Transition; 0227 t->setTargetState(childState->unconditionalTransition()); 0228 executeTransition(childState, t); 0229 delete t; 0230 return; 0231 } 0232 childState = childState->parent(); 0233 Q_ASSERT(childState != enteredState); 0234 Q_UNUSED(enteredState); 0235 } while (childState); 0236 } 0237 0238 bool handleFinished(State<TransitionInterface> *state) 0239 { 0240 Transition *handler = state->endTransition(); 0241 if (!handler) 0242 return false; 0243 0244 executeTransition(state, handler); 0245 return true; 0246 } 0247 0248 private: 0249 State<TransitionInterface> *m_currentState; 0250 }; 0251 } 0252 0253 #endif