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