1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QSTATEMACHINE_P_H
5#define QSTATEMACHINE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "private/qstate_p.h"
19
20#include <QtCore/qcoreevent.h>
21#include <QtCore/qhash.h>
22#include <QtCore/qlist.h>
23#include <QtCore/qmutex.h>
24#include <QtCore/qpair.h>
25#include <QtCore/qpointer.h>
26#include <QtCore/qset.h>
27
28#include <QtCore/private/qfreelist_p.h>
29
30QT_REQUIRE_CONFIG(statemachine);
31
32QT_BEGIN_NAMESPACE
33
34class QEvent;
35#if QT_CONFIG(qeventtransition)
36class QEventTransition;
37#endif
38class QSignalEventGenerator;
39class QSignalTransition;
40class QAbstractState;
41class QAbstractTransition;
42class QFinalState;
43class QHistoryState;
44class QState;
45
46#if QT_CONFIG(animation)
47class QAbstractAnimation;
48#endif
49
50struct CalculationCache;
51class QStateMachine;
52class Q_STATEMACHINE_EXPORT QStateMachinePrivate : public QStatePrivate
53{
54 Q_DECLARE_PUBLIC(QStateMachine)
55public:
56 enum State {
57 NotRunning,
58 Starting,
59 Running
60 };
61 enum EventProcessingMode {
62 DirectProcessing,
63 QueuedProcessing
64 };
65 enum StopProcessingReason {
66 EventQueueEmpty,
67 Finished,
68 Stopped
69 };
70
71 QStateMachinePrivate();
72 ~QStateMachinePrivate();
73
74 static QStateMachinePrivate *get(QStateMachine *q)
75 { return q ? q->d_func() : nullptr; }
76
77 QState *findLCA(const QList<QAbstractState*> &states, bool onlyCompound = false);
78 QState *findLCCA(const QList<QAbstractState*> &states);
79
80 static bool transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2);
81 static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
82 static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2);
83
84 QAbstractState *findErrorState(QAbstractState *context);
85 void setError(QStateMachine::Error error, QAbstractState *currentContext);
86
87 // private slots
88 void _q_start();
89 void _q_process();
90#if QT_CONFIG(animation)
91 void _q_animationFinished();
92#endif
93 void _q_startDelayedEventTimer(int id, int delay);
94 void _q_killDelayedEventTimer(int id, int timerId);
95
96 QState *rootState() const;
97
98 void clearHistory();
99 QAbstractTransition *createInitialTransition() const;
100
101 void removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
102 void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList, CalculationCache *cache);
103 QList<QAbstractTransition *> selectTransitions(QEvent *event, CalculationCache *cache);
104 virtual void noMicrostep();
105 virtual void processedPendingEvents(bool didChange);
106 virtual void beginMacrostep();
107 virtual void endMacrostep(bool didChange);
108 virtual void exitInterpreter();
109 virtual void exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,
110 const QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates);
111 QList<QAbstractState*> computeExitSet(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
112 QSet<QAbstractState*> computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
113 QSet<QAbstractState*> computeExitSet_Unordered(QAbstractTransition *t, CalculationCache *cache);
114 void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList);
115 virtual void enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
116 const QList<QAbstractState*> &statesToEnter_sorted,
117 const QSet<QAbstractState*> &statesForDefaultEntry,
118 QHash<QAbstractState *, QList<QPropertyAssignment>> &propertyAssignmentsForState
119#if QT_CONFIG(animation)
120 , const QList<QAbstractAnimation*> &selectedAnimations
121#endif
122 );
123 QList<QAbstractState*> computeEntrySet(const QList<QAbstractTransition*> &enabledTransitions,
124 QSet<QAbstractState*> &statesForDefaultEntry, CalculationCache *cache);
125 QAbstractState *getTransitionDomain(QAbstractTransition *t,
126 const QList<QAbstractState *> &effectiveTargetStates,
127 CalculationCache *cache);
128 void addDescendantStatesToEnter(QAbstractState *state,
129 QSet<QAbstractState*> &statesToEnter,
130 QSet<QAbstractState*> &statesForDefaultEntry);
131 void addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor,
132 QSet<QAbstractState*> &statesToEnter,
133 QSet<QAbstractState*> &statesForDefaultEntry);
134
135 static QState *toStandardState(QAbstractState *state);
136 static const QState *toStandardState(const QAbstractState *state);
137 static QFinalState *toFinalState(QAbstractState *state);
138 static QHistoryState *toHistoryState(QAbstractState *state);
139
140 bool isInFinalState(QAbstractState *s) const;
141 static bool isFinal(const QAbstractState *s);
142 static bool isParallel(const QAbstractState *s);
143 bool isCompound(const QAbstractState *s) const;
144 bool isAtomic(const QAbstractState *s) const;
145
146 void goToState(QAbstractState *targetState);
147
148 void registerTransitions(QAbstractState *state);
149 void maybeRegisterTransition(QAbstractTransition *transition);
150 void registerTransition(QAbstractTransition *transition);
151 void maybeRegisterSignalTransition(QSignalTransition *transition);
152 void registerSignalTransition(QSignalTransition *transition);
153 void unregisterSignalTransition(QSignalTransition *transition);
154 void registerMultiThreadedSignalTransitions();
155#if QT_CONFIG(qeventtransition)
156 void maybeRegisterEventTransition(QEventTransition *transition);
157 void registerEventTransition(QEventTransition *transition);
158 void unregisterEventTransition(QEventTransition *transition);
159 void handleFilteredEvent(QObject *watched, QEvent *event);
160#endif
161 void unregisterTransition(QAbstractTransition *transition);
162 void unregisterAllTransitions();
163 void handleTransitionSignal(QObject *sender, int signalIndex,
164 void **args);
165
166 void postInternalEvent(QEvent *e);
167 void postExternalEvent(QEvent *e);
168 QEvent *dequeueInternalEvent();
169 QEvent *dequeueExternalEvent();
170 bool isInternalEventQueueEmpty();
171 bool isExternalEventQueueEmpty();
172 void processEvents(EventProcessingMode processingMode);
173 void cancelAllDelayedEvents();
174
175 virtual void emitStateFinished(QState *forState, QFinalState *guiltyState);
176 virtual void startupHook();
177
178#ifndef QT_NO_PROPERTIES
179 class RestorableId {
180 QPointer<QObject> guard;
181 QObject *obj;
182 QByteArray prop;
183 friend size_t qHash(const RestorableId &key, size_t seed)
184 noexcept(noexcept(qHash(key: std::declval<QByteArray>())))
185 { return qHash(key: qMakePair(value1: key.obj, value2: key.prop), seed); }
186 friend bool operator==(const RestorableId &lhs, const RestorableId &rhs) noexcept
187 { return lhs.obj == rhs.obj && lhs.prop == rhs.prop; }
188 friend bool operator!=(const RestorableId &lhs, const RestorableId &rhs) noexcept
189 { return !operator==(lhs, rhs); }
190 public:
191 explicit RestorableId(QObject *o, QByteArray p) noexcept : guard(o), obj(o), prop(std::move(p)) {}
192 QObject *object() const noexcept { return guard; }
193 QByteArray propertyName() const noexcept { return prop; }
194 };
195 QHash<QAbstractState*, QHash<RestorableId, QVariant> > registeredRestorablesForState;
196 bool hasRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName) const;
197 QVariant savedValueForRestorable(const QList<QAbstractState*> &exitedStates_sorted,
198 QObject *object, const QByteArray &propertyName) const;
199 void registerRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName,
200 const QVariant &value);
201 void unregisterRestorables(const QList<QAbstractState*> &states, QObject *object,
202 const QByteArray &propertyName);
203 QList<QPropertyAssignment> restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const;
204 QHash<RestorableId, QVariant> computePendingRestorables(const QList<QAbstractState*> &statesToExit_sorted) const;
205 QHash<QAbstractState *, QList<QPropertyAssignment>> computePropertyAssignments(
206 const QList<QAbstractState*> &statesToEnter_sorted,
207 QHash<RestorableId, QVariant> &pendingRestorables) const;
208#endif
209
210 State state;
211 bool processing;
212 bool processingScheduled;
213 bool stop;
214 StopProcessingReason stopProcessingReason;
215 QSet<QAbstractState*> configuration;
216 QList<QEvent*> internalEventQueue;
217 QList<QEvent*> externalEventQueue;
218 QMutex internalEventMutex;
219 QMutex externalEventMutex;
220
221 QStateMachine::Error error;
222 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStateMachinePrivate, QState::RestorePolicy,
223 globalRestorePolicy, QState::DontRestoreProperties);
224 Q_OBJECT_BINDABLE_PROPERTY(QStateMachinePrivate, QString, errorString);
225
226 QSet<QAbstractState *> pendingErrorStates;
227 QSet<QAbstractState *> pendingErrorStatesForDefaultEntry;
228
229#if QT_CONFIG(animation)
230 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStateMachinePrivate, bool, animated, true);
231
232 struct InitializeAnimationResult {
233 QList<QAbstractAnimation*> handledAnimations;
234 QList<QAbstractAnimation*> localResetEndValues;
235
236 void swap(InitializeAnimationResult &other) noexcept
237 {
238 qSwap(value1&: handledAnimations, value2&: other.handledAnimations);
239 qSwap(value1&: localResetEndValues, value2&: other.localResetEndValues);
240 }
241 };
242
243 InitializeAnimationResult
244 initializeAnimation(QAbstractAnimation *abstractAnimation,
245 const QPropertyAssignment &prop);
246
247 QHash<QAbstractState*, QList<QAbstractAnimation*> > animationsForState;
248 QHash<QAbstractAnimation*, QPropertyAssignment> propertyForAnimation;
249 QHash<QAbstractAnimation*, QAbstractState*> stateForAnimation;
250 QSet<QAbstractAnimation*> resetAnimationEndValues;
251
252 QList<QAbstractAnimation *> defaultAnimations;
253 QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForSource;
254 QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForTarget;
255
256 QList<QAbstractAnimation *> selectAnimations(const QList<QAbstractTransition *> &transitionList) const;
257 void terminateActiveAnimations(QAbstractState *state,
258 const QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates);
259 void initializeAnimations(QAbstractState *state, const QList<QAbstractAnimation*> &selectedAnimations,
260 const QList<QAbstractState *> &exitedStates_sorted,
261 QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates);
262#endif // animation
263
264 QSignalEventGenerator *signalEventGenerator;
265
266 QHash<const QObject *, QList<int>> connections;
267 QMutex connectionsMutex;
268#if QT_CONFIG(qeventtransition)
269 QHash<QObject*, QHash<QEvent::Type, int> > qobjectEvents;
270#endif
271 struct FreeListDefaultConstants
272 {
273 // used by QFreeList, make sure to define all of when customizing
274 enum {
275 InitialNextValue = 0,
276 IndexMask = 0x00ffffff,
277 SerialMask = ~IndexMask & ~0x80000000,
278 SerialCounter = IndexMask + 1,
279 MaxIndex = IndexMask,
280 BlockCount = 4
281 };
282
283 static const int Sizes[BlockCount];
284 };
285 QFreeList<void, FreeListDefaultConstants> delayedEventIdFreeList;
286
287 struct DelayedEvent {
288 QEvent *event;
289 int timerId;
290 DelayedEvent(QEvent *e, int tid)
291 : event(e), timerId(tid) {}
292 DelayedEvent()
293 : event(nullptr), timerId(0) {}
294 };
295 QHash<int, DelayedEvent> delayedEvents;
296 QHash<int, int> timerIdToDelayedEventId;
297 QMutex delayedEventsMutex;
298};
299#if QT_CONFIG(animation)
300Q_DECLARE_SHARED(QStateMachinePrivate::InitializeAnimationResult)
301#endif
302
303QT_END_NAMESPACE
304
305#endif
306

source code of qtscxml/src/statemachine/qstatemachine_p.h