1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qstatemachine.h"
41 #include "qstate.h"
42 #include "qstate_p.h"
43 #include "qstatemachine_p.h"
44 #include "qabstracttransition.h"
45 #include "qabstracttransition_p.h"
46 #include "qsignaltransition.h"
47 #include "qsignaltransition_p.h"
48 #include "qsignaleventgenerator_p.h"
49 #include "qabstractstate.h"
50 #include "qabstractstate_p.h"
51 #include "qfinalstate.h"
52 #include "qhistorystate.h"
53 #include "qhistorystate_p.h"
54 #include "private/qobject_p.h"
55 #include "private/qthread_p.h"
56 
57 #if QT_CONFIG(qeventtransition)
58 #include "qeventtransition.h"
59 #include "qeventtransition_p.h"
60 #endif
61 
62 #if QT_CONFIG(animation)
63 #include "qpropertyanimation.h"
64 #include "qanimationgroup.h"
65 #include <private/qvariantanimation_p.h>
66 #endif
67 
68 #include <QtCore/qmetaobject.h>
69 #include <qdebug.h>
70 
71 #include <algorithm>
72 
73 QT_BEGIN_NAMESPACE
74 
75 /*!
76     \class QStateMachine
77     \inmodule QtCore
78     \reentrant
79 
80     \brief The QStateMachine class provides a hierarchical finite state machine.
81 
82     \since 4.6
83     \ingroup statemachine
84 
85     QStateMachine is based on the concepts and notation of
86     \l{http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf}{Statecharts}.
87     QStateMachine is part of \l{The State Machine Framework}.
88 
89     A state machine manages a set of states (classes that inherit from
90     QAbstractState) and transitions (descendants of
91     QAbstractTransition) between those states; these states and
92     transitions define a state graph. Once a state graph has been
93     built, the state machine can execute it. QStateMachine's
94     execution algorithm is based on the \l{http://www.w3.org/TR/scxml/}{State Chart XML (SCXML)}
95     algorithm. The framework's \l{The State Machine
96     Framework}{overview} gives several state graphs and the code to
97     build them.
98 
99     Use the addState() function to add a top-level state to the state machine.
100     States are removed with the removeState() function. Removing states while
101     the machine is running is discouraged.
102 
103     Before the machine can be started, the \l{initialState}{initial
104     state} must be set. The initial state is the state that the
105     machine enters when started. You can then start() the state
106     machine. The started() signal is emitted when the initial state is
107     entered.
108 
109     The machine is event driven and keeps its own event loop. Events
110     are posted to the machine through postEvent(). Note that this
111     means that it executes asynchronously, and that it will not
112     progress without a running event loop. You will normally not have
113     to post events to the machine directly as Qt's transitions, e.g.,
114     QEventTransition and its subclasses, handle this. But for custom
115     transitions triggered by events, postEvent() is useful.
116 
117     The state machine processes events and takes transitions until a
118     top-level final state is entered; the state machine then emits the
119     finished() signal. You can also stop() the state machine
120     explicitly. The stopped() signal is emitted in this case.
121 
122     The following snippet shows a state machine that will finish when a button
123     is clicked:
124 
125     \snippet code/src_corelib_statemachine_qstatemachine.cpp simple state machine
126 
127     This code example uses QState, which inherits QAbstractState. The
128     QState class provides a state that you can use to set properties
129     and invoke methods on \l{QObject}s when the state is entered or
130     exited. It also contains convenience functions for adding
131     transitions, e.g., \l{QSignalTransition}s as in this example. See
132     the QState class description for further details.
133 
134     If an error is encountered, the machine will look for an
135     \l{errorState}{error state}, and if one is available, it will
136     enter this state. The types of errors possible are described by the
137     \l{QStateMachine::}{Error} enum. After the error state is entered,
138     the type of the error can be retrieved with error(). The execution
139     of the state graph will not stop when the error state is entered. If
140     no error state applies to the erroneous state, the machine will stop
141     executing and an error message will be printed to the console.
142 
143     \note Important: setting the \l{ChildMode} of a state machine to parallel (\l{ParallelStates})
144           results in an invalid state machine. It can only be set to (or kept as)
145           \l{ExclusiveStates}.
146 
147     \sa QAbstractState, QAbstractTransition, QState, {The State Machine Framework}
148 */
149 
150 /*!
151     \property QStateMachine::errorString
152 
153     \brief the error string of this state machine
154 */
155 
156 /*!
157     \property QStateMachine::globalRestorePolicy
158 
159     \brief the restore policy for states of this state machine.
160 
161     The default value of this property is
162     QState::DontRestoreProperties.
163 */
164 
165 /*!
166     \property QStateMachine::running
167     \since 5.4
168 
169     \brief the running state of this state machine
170 
171     \sa start(), stop(), started(), stopped(), runningChanged()
172 */
173 
174 #if QT_CONFIG(animation)
175 /*!
176     \property QStateMachine::animated
177 
178     \brief whether animations are enabled
179 
180     The default value of this property is \c true.
181 
182     \sa QAbstractTransition::addAnimation()
183 */
184 #endif
185 
186 // #define QSTATEMACHINE_DEBUG
187 // #define QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
188 
189 struct CalculationCache {
190     struct TransitionInfo {
191         QList<QAbstractState*> effectiveTargetStates;
192         QSet<QAbstractState*> exitSet;
193         QAbstractState *transitionDomain;
194 
195         bool effectiveTargetStatesIsKnown: 1;
196         bool exitSetIsKnown              : 1;
197         bool transitionDomainIsKnown     : 1;
198 
TransitionInfoCalculationCache::TransitionInfo199         TransitionInfo()
200             : transitionDomain(nullptr)
201             , effectiveTargetStatesIsKnown(false)
202             , exitSetIsKnown(false)
203             , transitionDomainIsKnown(false)
204         {}
205     };
206 
207     typedef QHash<QAbstractTransition *, TransitionInfo> TransitionInfoCache;
208     TransitionInfoCache cache;
209 
effectiveTargetStatesCalculationCache210     bool effectiveTargetStates(QAbstractTransition *t, QList<QAbstractState *> *targets) const
211     {
212         Q_ASSERT(targets);
213 
214         TransitionInfoCache::const_iterator cacheIt = cache.find(t);
215         if (cacheIt == cache.end() || !cacheIt->effectiveTargetStatesIsKnown)
216             return false;
217 
218         *targets = cacheIt->effectiveTargetStates;
219         return true;
220     }
221 
insertCalculationCache222     void insert(QAbstractTransition *t, const QList<QAbstractState *> &targets)
223     {
224         TransitionInfoCache::iterator cacheIt = cache.find(t);
225         TransitionInfo &ti = cacheIt == cache.end()
226                 ? *cache.insert(t, TransitionInfo())
227                 : *cacheIt;
228 
229         Q_ASSERT(!ti.effectiveTargetStatesIsKnown);
230         ti.effectiveTargetStates = targets;
231         ti.effectiveTargetStatesIsKnown = true;
232     }
233 
exitSetCalculationCache234     bool exitSet(QAbstractTransition *t, QSet<QAbstractState *> *exits) const
235     {
236         Q_ASSERT(exits);
237 
238         TransitionInfoCache::const_iterator cacheIt = cache.find(t);
239         if (cacheIt == cache.end() || !cacheIt->exitSetIsKnown)
240             return false;
241 
242         *exits = cacheIt->exitSet;
243         return true;
244     }
245 
insertCalculationCache246     void insert(QAbstractTransition *t, const QSet<QAbstractState *> &exits)
247     {
248         TransitionInfoCache::iterator cacheIt = cache.find(t);
249         TransitionInfo &ti = cacheIt == cache.end()
250                 ? *cache.insert(t, TransitionInfo())
251                 : *cacheIt;
252 
253         Q_ASSERT(!ti.exitSetIsKnown);
254         ti.exitSet = exits;
255         ti.exitSetIsKnown = true;
256     }
257 
transitionDomainCalculationCache258     bool transitionDomain(QAbstractTransition *t, QAbstractState **domain) const
259     {
260         Q_ASSERT(domain);
261 
262         TransitionInfoCache::const_iterator cacheIt = cache.find(t);
263         if (cacheIt == cache.end() || !cacheIt->transitionDomainIsKnown)
264             return false;
265 
266         *domain = cacheIt->transitionDomain;
267         return true;
268     }
269 
insertCalculationCache270     void insert(QAbstractTransition *t, QAbstractState *domain)
271     {
272         TransitionInfoCache::iterator cacheIt = cache.find(t);
273         TransitionInfo &ti = cacheIt == cache.end()
274                 ? *cache.insert(t, TransitionInfo())
275                 : *cacheIt;
276 
277         Q_ASSERT(!ti.transitionDomainIsKnown);
278         ti.transitionDomain = domain;
279         ti.transitionDomainIsKnown = true;
280     }
281 };
282 
283 /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
284 
285 function isDescendant(state1, state2)
286 
287 Returns 'true' if state1 is a descendant of state2 (a child, or a child of a child, or a child of a
288 child of a child, etc.) Otherwise returns 'false'.
289 */
isDescendant(const QAbstractState * state1,const QAbstractState * state2)290 static inline bool isDescendant(const QAbstractState *state1, const QAbstractState *state2)
291 {
292     Q_ASSERT(state1 != nullptr);
293 
294     for (QAbstractState *it = state1->parentState(); it != nullptr; it = it->parentState()) {
295         if (it == state2)
296             return true;
297     }
298 
299     return false;
300 }
301 
containsDecendantOf(const QSet<QAbstractState * > & states,const QAbstractState * node)302 static bool containsDecendantOf(const QSet<QAbstractState *> &states, const QAbstractState *node)
303 {
304     for (QAbstractState *s : states)
305         if (isDescendant(s, node))
306             return true;
307 
308     return false;
309 }
310 
descendantDepth(const QAbstractState * state,const QAbstractState * ancestor)311 static int descendantDepth(const QAbstractState *state, const QAbstractState *ancestor)
312 {
313     int depth = 0;
314     for (const QAbstractState *it = state; it != nullptr; it = it->parentState()) {
315         if (it == ancestor)
316             break;
317         ++depth;
318     }
319     return depth;
320 }
321 
322 /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
323 
324 function getProperAncestors(state1, state2)
325 
326 If state2 is null, returns the set of all ancestors of state1 in ancestry order (state1's parent
327 followed by the parent's parent, etc. up to an including the <scxml> element). If state2 is
328 non-null, returns in ancestry order the set of all ancestors of state1, up to but not including
329 state2. (A "proper ancestor" of a state is its parent, or the parent's parent, or the parent's
330 parent's parent, etc.))If state2 is state1's parent, or equal to state1, or a descendant of state1,
331 this returns the empty set.
332 */
getProperAncestors(const QAbstractState * state,const QAbstractState * upperBound)333 static QVector<QState*> getProperAncestors(const QAbstractState *state, const QAbstractState *upperBound)
334 {
335     Q_ASSERT(state != nullptr);
336     QVector<QState*> result;
337     result.reserve(16);
338     for (QState *it = state->parentState(); it && it != upperBound; it = it->parentState()) {
339         result.append(it);
340     }
341     return result;
342 }
343 
344 /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
345 
346 function getEffectiveTargetStates(transition)
347 
348 Returns the states that will be the target when 'transition' is taken, dereferencing any history states.
349 
350 function getEffectiveTargetStates(transition)
351     targets = new OrderedSet()
352     for s in transition.target
353         if isHistoryState(s):
354             if historyValue[s.id]:
355                 targets.union(historyValue[s.id])
356             else:
357                 targets.union(getEffectiveTargetStates(s.transition))
358         else:
359             targets.add(s)
360     return targets
361 */
getEffectiveTargetStates(QAbstractTransition * transition,CalculationCache * cache)362 static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *transition, CalculationCache *cache)
363 {
364     Q_ASSERT(cache);
365 
366     QList<QAbstractState *> targetsList;
367     if (cache->effectiveTargetStates(transition, &targetsList))
368         return targetsList;
369 
370     QSet<QAbstractState *> targets;
371     const auto targetStates = transition->targetStates();
372     for (QAbstractState *s : targetStates) {
373         if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) {
374             QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(historyState)->configuration;
375             if (!historyConfiguration.isEmpty()) {
376                 // There is a saved history, so apply that.
377                 targets.unite(QSet<QAbstractState *>(historyConfiguration.constBegin(), historyConfiguration.constEnd()));
378             } else if (QAbstractTransition *defaultTransition = historyState->defaultTransition()) {
379                 // No saved history, take all default transition targets.
380                 const auto &targetStates = defaultTransition->targetStates();
381                 targets.unite(QSet<QAbstractState *>(targetStates.constBegin(), targetStates.constEnd()));
382             } else {
383                 // Woops, we found a history state without a default state. That's not valid!
384                 QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine());
385                 m->setError(QStateMachine::NoDefaultStateInHistoryStateError, historyState);
386             }
387         } else {
388             targets.insert(s);
389         }
390     }
391 
392     targetsList = targets.values();
393     cache->insert(transition, targetsList);
394     return targetsList;
395 }
396 
QStateMachinePrivate()397 QStateMachinePrivate::QStateMachinePrivate()
398 {
399     isMachine = true;
400 
401     state = NotRunning;
402     processing = false;
403     processingScheduled = false;
404     stop = false;
405     stopProcessingReason = EventQueueEmpty;
406     error = QStateMachine::NoError;
407     globalRestorePolicy = QState::DontRestoreProperties;
408     signalEventGenerator = nullptr;
409 #if QT_CONFIG(animation)
410     animated = true;
411 #endif
412 }
413 
~QStateMachinePrivate()414 QStateMachinePrivate::~QStateMachinePrivate()
415 {
416     qDeleteAll(internalEventQueue);
417     qDeleteAll(externalEventQueue);
418 
419     for (QHash<int, DelayedEvent>::const_iterator it = delayedEvents.cbegin(), eit = delayedEvents.cend(); it != eit; ++it) {
420         delete it.value().event;
421     }
422 }
423 
rootState() const424 QState *QStateMachinePrivate::rootState() const
425 {
426     return const_cast<QStateMachine*>(q_func());
427 }
428 
cloneEvent(QEvent * e)429 static QEvent *cloneEvent(QEvent *e)
430 {
431     switch (e->type()) {
432     case QEvent::None:
433         return new QEvent(*e);
434     case QEvent::Timer:
435         return new QTimerEvent(*static_cast<QTimerEvent*>(e));
436     default:
437         Q_ASSERT_X(false, "cloneEvent()", "not implemented");
438         break;
439     }
440     return nullptr;
441 }
442 
443 const QStateMachinePrivate::Handler qt_kernel_statemachine_handler = {
444     cloneEvent
445 };
446 
447 const QStateMachinePrivate::Handler *QStateMachinePrivate::handler = &qt_kernel_statemachine_handler;
448 
qcoreStateMachineHandler()449 Q_CORE_EXPORT const QStateMachinePrivate::Handler *qcoreStateMachineHandler()
450 {
451     return &qt_kernel_statemachine_handler;
452 }
453 
indexOfDescendant(QState * s,QAbstractState * desc)454 static int indexOfDescendant(QState *s, QAbstractState *desc)
455 {
456     QList<QAbstractState*> childStates = QStatePrivate::get(s)->childStates();
457     for (int i = 0; i < childStates.size(); ++i) {
458         QAbstractState *c = childStates.at(i);
459         if ((c == desc) || isDescendant(desc, c)) {
460             return i;
461         }
462     }
463     return -1;
464 }
465 
transitionStateEntryLessThan(QAbstractTransition * t1,QAbstractTransition * t2)466 bool QStateMachinePrivate::transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2)
467 {
468     QState *s1 = t1->sourceState(), *s2 = t2->sourceState();
469     if (s1 == s2) {
470         QList<QAbstractTransition*> transitions = QStatePrivate::get(s1)->transitions();
471         return transitions.indexOf(t1) < transitions.indexOf(t2);
472     } else if (isDescendant(s1, s2)) {
473         return true;
474     } else if (isDescendant(s2, s1)) {
475         return false;
476     } else {
477         Q_ASSERT(s1->machine() != nullptr);
478         QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
479         QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
480         Q_ASSERT(lca != nullptr);
481         int s1Depth = descendantDepth(s1, lca);
482         int s2Depth = descendantDepth(s2, lca);
483         if (s1Depth == s2Depth)
484             return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
485         else
486             return s1Depth > s2Depth;
487     }
488 }
489 
stateEntryLessThan(QAbstractState * s1,QAbstractState * s2)490 bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2)
491 {
492     if (s1->parent() == s2->parent()) {
493         return s1->parent()->children().indexOf(s1)
494             < s2->parent()->children().indexOf(s2);
495     } else if (isDescendant(s1, s2)) {
496         return false;
497     } else if (isDescendant(s2, s1)) {
498         return true;
499     } else {
500         Q_ASSERT(s1->machine() != nullptr);
501         QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
502         QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
503         Q_ASSERT(lca != nullptr);
504         return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
505     }
506 }
507 
stateExitLessThan(QAbstractState * s1,QAbstractState * s2)508 bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState *s2)
509 {
510     if (s1->parent() == s2->parent()) {
511         return s2->parent()->children().indexOf(s2)
512             < s1->parent()->children().indexOf(s1);
513     } else if (isDescendant(s1, s2)) {
514         return true;
515     } else if (isDescendant(s2, s1)) {
516         return false;
517     } else {
518         Q_ASSERT(s1->machine() != nullptr);
519         QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
520         QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
521         Q_ASSERT(lca != nullptr);
522         return (indexOfDescendant(lca, s2) < indexOfDescendant(lca, s1));
523     }
524 }
525 
findLCA(const QList<QAbstractState * > & states,bool onlyCompound)526 QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states, bool onlyCompound)
527 {
528     if (states.isEmpty())
529         return nullptr;
530     QVector<QState*> ancestors = getProperAncestors(states.at(0), rootState()->parentState());
531     for (int i = 0; i < ancestors.size(); ++i) {
532         QState *anc = ancestors.at(i);
533         if (onlyCompound && !isCompound(anc))
534             continue;
535 
536         bool ok = true;
537         for (int j = states.size() - 1; (j > 0) && ok; --j) {
538             const QAbstractState *s = states.at(j);
539             if (!isDescendant(s, anc))
540                 ok = false;
541         }
542         if (ok)
543             return anc;
544     }
545 
546     // Oops, this should never happen! The state machine itself is a common ancestor of all states,
547     // no matter what. But, for the onlyCompound case: we probably have a state machine whose
548     // childMode is set to parallel, which is illegal. However, we're stuck with it (and with
549     // exposing this invalid/dangerous API to users), so recover in the least horrible way.
550     setError(QStateMachine::StateMachineChildModeSetToParallelError, q_func());
551     return q_func(); // make the statemachine the LCA/LCCA (which it should have been anyway)
552 }
553 
findLCCA(const QList<QAbstractState * > & states)554 QState *QStateMachinePrivate::findLCCA(const QList<QAbstractState*> &states)
555 {
556     return findLCA(states, true);
557 }
558 
selectTransitions(QEvent * event,CalculationCache * cache)559 QList<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event, CalculationCache *cache)
560 {
561     Q_ASSERT(cache);
562     Q_Q(const QStateMachine);
563 
564     QVarLengthArray<QAbstractState *> configuration_sorted;
565     for (QAbstractState *s : qAsConst(configuration)) {
566         if (isAtomic(s))
567             configuration_sorted.append(s);
568     }
569     std::sort(configuration_sorted.begin(), configuration_sorted.end(), stateEntryLessThan);
570 
571     QList<QAbstractTransition*> enabledTransitions;
572     const_cast<QStateMachine*>(q)->beginSelectTransitions(event);
573     for (QAbstractState *state : qAsConst(configuration_sorted)) {
574         QVector<QState*> lst = getProperAncestors(state, nullptr);
575         if (QState *grp = toStandardState(state))
576             lst.prepend(grp);
577         bool found = false;
578         for (int j = 0; (j < lst.size()) && !found; ++j) {
579             QState *s = lst.at(j);
580             QList<QAbstractTransition*> transitions = QStatePrivate::get(s)->transitions();
581             for (int k = 0; k < transitions.size(); ++k) {
582                 QAbstractTransition *t = transitions.at(k);
583                 if (QAbstractTransitionPrivate::get(t)->callEventTest(event)) {
584 #ifdef QSTATEMACHINE_DEBUG
585                     qDebug() << q << ": selecting transition" << t;
586 #endif
587                     enabledTransitions.append(t);
588                     found = true;
589                     break;
590                 }
591             }
592         }
593     }
594 
595     if (!enabledTransitions.isEmpty()) {
596         removeConflictingTransitions(enabledTransitions, cache);
597 #ifdef QSTATEMACHINE_DEBUG
598         qDebug() << q << ": enabled transitions after removing conflicts:" << enabledTransitions;
599 #endif
600     }
601     const_cast<QStateMachine*>(q)->endSelectTransitions(event);
602     return enabledTransitions;
603 }
604 
605 /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
606 
607 function removeConflictingTransitions(enabledTransitions):
608     filteredTransitions = new OrderedSet()
609  // toList sorts the transitions in the order of the states that selected them
610     for t1 in enabledTransitions.toList():
611         t1Preempted = false;
612         transitionsToRemove = new OrderedSet()
613         for t2 in filteredTransitions.toList():
614             if computeExitSet([t1]).hasIntersection(computeExitSet([t2])):
615                 if isDescendant(t1.source, t2.source):
616                     transitionsToRemove.add(t2)
617                 else:
618                     t1Preempted = true
619                     break
620         if not t1Preempted:
621             for t3 in transitionsToRemove.toList():
622                 filteredTransitions.delete(t3)
623             filteredTransitions.add(t1)
624 
625     return filteredTransitions
626 
627 Note: the implementation below does not build the transitionsToRemove, but removes them in-place.
628 */
removeConflictingTransitions(QList<QAbstractTransition * > & enabledTransitions,CalculationCache * cache)629 void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache)
630 {
631     Q_ASSERT(cache);
632 
633     if (enabledTransitions.size() < 2)
634         return; // There is no transition to conflict with.
635 
636     QList<QAbstractTransition*> filteredTransitions;
637     filteredTransitions.reserve(enabledTransitions.size());
638     std::sort(enabledTransitions.begin(), enabledTransitions.end(), transitionStateEntryLessThan);
639 
640     for (QAbstractTransition *t1 : qAsConst(enabledTransitions)) {
641         bool t1Preempted = false;
642         const QSet<QAbstractState*> exitSetT1 = computeExitSet_Unordered(t1, cache);
643         QList<QAbstractTransition*>::iterator t2It = filteredTransitions.begin();
644         while (t2It != filteredTransitions.end()) {
645             QAbstractTransition *t2 = *t2It;
646             if (t1 == t2) {
647                 // Special case: someone added the same transition object to a state twice. In this
648                 // case, t2 (which is already in the list) "preempts" t1.
649                 t1Preempted = true;
650                 break;
651             }
652 
653             QSet<QAbstractState*> exitSetT2 = computeExitSet_Unordered(t2, cache);
654             if (!exitSetT1.intersects(exitSetT2)) {
655                 // No conflict, no cry. Next patient please.
656                 ++t2It;
657             } else {
658                 // Houston, we have a conflict. Check which transition can be removed.
659                 if (isDescendant(t1->sourceState(), t2->sourceState())) {
660                     // t1 preempts t2, so we can remove t2
661                     t2It = filteredTransitions.erase(t2It);
662                 } else {
663                     // t2 preempts t1, so there's no use in looking further and we don't need to add
664                     // t1 to the list.
665                     t1Preempted = true;
666                     break;
667                 }
668             }
669         }
670         if (!t1Preempted)
671             filteredTransitions.append(t1);
672     }
673 
674     enabledTransitions = filteredTransitions;
675 }
676 
microstep(QEvent * event,const QList<QAbstractTransition * > & enabledTransitions,CalculationCache * cache)677 void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions,
678                                      CalculationCache *cache)
679 {
680     Q_ASSERT(cache);
681 
682 #ifdef QSTATEMACHINE_DEBUG
683     qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')';
684     qDebug() << q_func() << ": configuration before exiting states:" << configuration;
685 #endif
686     QList<QAbstractState*> exitedStates = computeExitSet(enabledTransitions, cache);
687     QHash<RestorableId, QVariant> pendingRestorables = computePendingRestorables(exitedStates);
688 
689     QSet<QAbstractState*> statesForDefaultEntry;
690     QList<QAbstractState*> enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry, cache);
691 
692 #ifdef QSTATEMACHINE_DEBUG
693     qDebug() << q_func() << ": computed exit set:" << exitedStates;
694     qDebug() << q_func() << ": computed entry set:" << enteredStates;
695 #endif
696 
697     QHash<QAbstractState*, QVector<QPropertyAssignment> > assignmentsForEnteredStates =
698             computePropertyAssignments(enteredStates, pendingRestorables);
699     if (!pendingRestorables.isEmpty()) {
700         // Add "implicit" assignments for restored properties to the first
701         // (outermost) entered state
702         Q_ASSERT(!enteredStates.isEmpty());
703         QAbstractState *s = enteredStates.constFirst();
704         assignmentsForEnteredStates[s] << restorablesToPropertyList(pendingRestorables);
705     }
706 
707     exitStates(event, exitedStates, assignmentsForEnteredStates);
708 #ifdef QSTATEMACHINE_DEBUG
709     qDebug() << q_func() << ": configuration after exiting states:" << configuration;
710 #endif
711 
712     executeTransitionContent(event, enabledTransitions);
713 
714 #if QT_CONFIG(animation)
715     QList<QAbstractAnimation *> selectedAnimations = selectAnimations(enabledTransitions);
716 #endif
717 
718     enterStates(event, exitedStates, enteredStates, statesForDefaultEntry, assignmentsForEnteredStates
719 #if QT_CONFIG(animation)
720                 , selectedAnimations
721 #endif
722                 );
723 #ifdef QSTATEMACHINE_DEBUG
724     qDebug() << q_func() << ": configuration after entering states:" << configuration;
725     qDebug() << q_func() << ": end microstep";
726 #endif
727 }
728 
729 /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
730 
731 procedure computeExitSet(enabledTransitions)
732 
733 For each transition t in enabledTransitions, if t is targetless then do nothing, else compute the
734 transition's domain. (This will be the source state in the case of internal transitions) or the
735 least common compound ancestor state of the source state and target states of t (in the case of
736 external transitions. Add to the statesToExit set all states in the configuration that are
737 descendants of the domain.
738 
739 function computeExitSet(transitions)
740    statesToExit = new OrderedSet
741      for t in transitions:
742        if (t.target):
743           domain = getTransitionDomain(t)
744           for s in configuration:
745              if isDescendant(s,domain):
746                statesToExit.add(s)
747    return statesToExit
748 */
computeExitSet(const QList<QAbstractTransition * > & enabledTransitions,CalculationCache * cache)749 QList<QAbstractState*> QStateMachinePrivate::computeExitSet(const QList<QAbstractTransition*> &enabledTransitions,
750                                                             CalculationCache *cache)
751 {
752     Q_ASSERT(cache);
753 
754     QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).values();
755     std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
756     return statesToExit_sorted;
757 }
758 
computeExitSet_Unordered(const QList<QAbstractTransition * > & enabledTransitions,CalculationCache * cache)759 QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions,
760                                                                      CalculationCache *cache)
761 {
762     Q_ASSERT(cache);
763 
764     QSet<QAbstractState*> statesToExit;
765     for (QAbstractTransition *t : enabledTransitions)
766         statesToExit.unite(computeExitSet_Unordered(t, cache));
767     return statesToExit;
768 }
769 
computeExitSet_Unordered(QAbstractTransition * t,CalculationCache * cache)770 QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(QAbstractTransition *t,
771                                                                      CalculationCache *cache)
772 {
773     Q_ASSERT(cache);
774 
775     QSet<QAbstractState*> statesToExit;
776     if (cache->exitSet(t, &statesToExit))
777         return statesToExit;
778 
779     QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
780     QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates, cache);
781     if (domain == nullptr && !t->targetStates().isEmpty()) {
782         // So we didn't find the least common ancestor for the source and target states of the
783         // transition. If there were not target states, that would be fine: then the transition
784         // will fire any events or signals, but not exit the state.
785         //
786         // However, there are target states, so it's either a node without a parent (or parent's
787         // parent, etc), or the state belongs to a different state machine. Either way, this
788         // makes the state machine invalid.
789         if (error == QStateMachine::NoError)
790             setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
791         QList<QAbstractState *> lst = pendingErrorStates.values();
792         lst.prepend(t->sourceState());
793 
794         domain = findLCCA(lst);
795         Q_ASSERT(domain != nullptr);
796     }
797 
798     for (QAbstractState* s : qAsConst(configuration)) {
799         if (isDescendant(s, domain))
800             statesToExit.insert(s);
801     }
802 
803     cache->insert(t, statesToExit);
804     return statesToExit;
805 }
806 
exitStates(QEvent * event,const QList<QAbstractState * > & statesToExit_sorted,const QHash<QAbstractState *,QVector<QPropertyAssignment>> & assignmentsForEnteredStates)807 void QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractState*> &statesToExit_sorted,
808                                       const QHash<QAbstractState*, QVector<QPropertyAssignment> > &assignmentsForEnteredStates)
809 {
810     for (int i = 0; i < statesToExit_sorted.size(); ++i) {
811         QAbstractState *s = statesToExit_sorted.at(i);
812         if (QState *grp = toStandardState(s)) {
813             QList<QHistoryState*> hlst = QStatePrivate::get(grp)->historyStates();
814             for (int j = 0; j < hlst.size(); ++j) {
815                 QHistoryState *h = hlst.at(j);
816                 QHistoryStatePrivate::get(h)->configuration.clear();
817                 QSet<QAbstractState*>::const_iterator it;
818                 for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
819                     QAbstractState *s0 = *it;
820                     if (QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) {
821                         if (isAtomic(s0) && isDescendant(s0, s))
822                             QHistoryStatePrivate::get(h)->configuration.append(s0);
823                     } else if (s0->parentState() == s) {
824                         QHistoryStatePrivate::get(h)->configuration.append(s0);
825                     }
826                 }
827 #ifdef QSTATEMACHINE_DEBUG
828                 qDebug() << q_func() << ": recorded" << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
829                          << "history for" << s << "in" << h << ':' << QHistoryStatePrivate::get(h)->configuration;
830 #endif
831             }
832         }
833     }
834     for (int i = 0; i < statesToExit_sorted.size(); ++i) {
835         QAbstractState *s = statesToExit_sorted.at(i);
836 #ifdef QSTATEMACHINE_DEBUG
837         qDebug() << q_func() << ": exiting" << s;
838 #endif
839         QAbstractStatePrivate::get(s)->callOnExit(event);
840 
841 #if QT_CONFIG(animation)
842         terminateActiveAnimations(s, assignmentsForEnteredStates);
843 #else
844         Q_UNUSED(assignmentsForEnteredStates);
845 #endif
846 
847         configuration.remove(s);
848         QAbstractStatePrivate::get(s)->emitExited();
849     }
850 }
851 
executeTransitionContent(QEvent * event,const QList<QAbstractTransition * > & enabledTransitions)852 void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
853 {
854     for (int i = 0; i < enabledTransitions.size(); ++i) {
855         QAbstractTransition *t = enabledTransitions.at(i);
856 #ifdef QSTATEMACHINE_DEBUG
857         qDebug() << q_func() << ": triggering" << t;
858 #endif
859         QAbstractTransitionPrivate::get(t)->callOnTransition(event);
860         QAbstractTransitionPrivate::get(t)->emitTriggered();
861     }
862 }
863 
computeEntrySet(const QList<QAbstractTransition * > & enabledTransitions,QSet<QAbstractState * > & statesForDefaultEntry,CalculationCache * cache)864 QList<QAbstractState*> QStateMachinePrivate::computeEntrySet(const QList<QAbstractTransition *> &enabledTransitions,
865                                                              QSet<QAbstractState *> &statesForDefaultEntry,
866                                                              CalculationCache *cache)
867 {
868     Q_ASSERT(cache);
869 
870     QSet<QAbstractState*> statesToEnter;
871     if (pendingErrorStates.isEmpty()) {
872         for (QAbstractTransition *t : enabledTransitions) {
873             const auto targetStates = t->targetStates();
874             for (QAbstractState *s : targetStates)
875                 addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
876 
877             const QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
878             QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates, cache);
879             for (QAbstractState *s : effectiveTargetStates)
880                 addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry);
881         }
882     }
883 
884     // Did an error occur while selecting transitions? Then we enter the error state.
885     if (!pendingErrorStates.isEmpty()) {
886         statesToEnter.clear();
887         statesToEnter = pendingErrorStates;
888         statesForDefaultEntry = pendingErrorStatesForDefaultEntry;
889         pendingErrorStates.clear();
890         pendingErrorStatesForDefaultEntry.clear();
891     }
892 
893     QList<QAbstractState*> statesToEnter_sorted = statesToEnter.values();
894     std::sort(statesToEnter_sorted.begin(), statesToEnter_sorted.end(), stateEntryLessThan);
895     return statesToEnter_sorted;
896 }
897 
898 /* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
899 
900 function getTransitionDomain(transition)
901 
902 Return the compound state such that 1) all states that are exited or entered as a result of taking
903 'transition' are descendants of it 2) no descendant of it has this property.
904 
905 function getTransitionDomain(t)
906   tstates = getEffectiveTargetStates(t)
907   if not tstates:
908       return null
909   elif t.type == "internal" and isCompoundState(t.source) and tstates.every(lambda s: isDescendant(s,t.source)):
910       return t.source
911   else:
912       return findLCCA([t.source].append(tstates))
913 */
getTransitionDomain(QAbstractTransition * t,const QList<QAbstractState * > & effectiveTargetStates,CalculationCache * cache)914 QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t,
915                                                           const QList<QAbstractState *> &effectiveTargetStates,
916                                                           CalculationCache *cache)
917 {
918     Q_ASSERT(cache);
919 
920     if (effectiveTargetStates.isEmpty())
921         return nullptr;
922 
923     QAbstractState *domain = nullptr;
924     if (cache->transitionDomain(t, &domain))
925         return domain;
926 
927     if (t->transitionType() == QAbstractTransition::InternalTransition) {
928         if (QState *tSource = t->sourceState()) {
929             if (isCompound(tSource)) {
930                 bool allDescendants = true;
931                 for (QAbstractState *s : effectiveTargetStates) {
932                     if (!isDescendant(s, tSource)) {
933                         allDescendants = false;
934                         break;
935                     }
936                 }
937 
938                 if (allDescendants)
939                     return tSource;
940             }
941         }
942     }
943 
944     QList<QAbstractState *> states(effectiveTargetStates);
945     if (QAbstractState *src = t->sourceState())
946         states.prepend(src);
947     domain = findLCCA(states);
948     cache->insert(t, domain);
949     return domain;
950 }
951 
enterStates(QEvent * event,const QList<QAbstractState * > & exitedStates_sorted,const QList<QAbstractState * > & statesToEnter_sorted,const QSet<QAbstractState * > & statesForDefaultEntry,QHash<QAbstractState *,QVector<QPropertyAssignment>> & propertyAssignmentsForState,const QList<QAbstractAnimation * > & selectedAnimations)952 void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
953                                        const QList<QAbstractState*> &statesToEnter_sorted,
954                                        const QSet<QAbstractState*> &statesForDefaultEntry,
955                                        QHash<QAbstractState*, QVector<QPropertyAssignment> > &propertyAssignmentsForState
956 #if QT_CONFIG(animation)
957                                        , const QList<QAbstractAnimation *> &selectedAnimations
958 #endif
959                                        )
960 {
961 #ifdef QSTATEMACHINE_DEBUG
962     Q_Q(QStateMachine);
963 #endif
964     for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
965         QAbstractState *s = statesToEnter_sorted.at(i);
966 #ifdef QSTATEMACHINE_DEBUG
967         qDebug() << q << ": entering" << s;
968 #endif
969         configuration.insert(s);
970         registerTransitions(s);
971 
972 #if QT_CONFIG(animation)
973         initializeAnimations(s, selectedAnimations, exitedStates_sorted, propertyAssignmentsForState);
974 #endif
975 
976         // Immediately set the properties that are not animated.
977         {
978             QVector<QPropertyAssignment> assignments = propertyAssignmentsForState.value(s);
979             for (int i = 0; i < assignments.size(); ++i) {
980                 const QPropertyAssignment &assn = assignments.at(i);
981                 if (globalRestorePolicy == QState::RestoreProperties) {
982                     if (assn.explicitlySet) {
983                         if (!hasRestorable(s, assn.object, assn.propertyName)) {
984                             QVariant value = savedValueForRestorable(exitedStates_sorted, assn.object, assn.propertyName);
985                             unregisterRestorables(exitedStates_sorted, assn.object, assn.propertyName);
986                             registerRestorable(s, assn.object, assn.propertyName, value);
987                         }
988                     } else {
989                         // The property is being restored, hence no need to
990                         // save the current value. Discard any saved values in
991                         // exited states, since those are now stale.
992                         unregisterRestorables(exitedStates_sorted, assn.object, assn.propertyName);
993                     }
994                 }
995                 assn.write();
996             }
997         }
998 
999         QAbstractStatePrivate::get(s)->callOnEntry(event);
1000         QAbstractStatePrivate::get(s)->emitEntered();
1001 
1002         // FIXME:
1003         // See the "initial transitions" comment in addDescendantStatesToEnter first, then implement:
1004 //        if (statesForDefaultEntry.contains(s)) {
1005 //            // ### executeContent(s.initial.transition.children())
1006 //        }
1007         Q_UNUSED(statesForDefaultEntry);
1008 
1009         if (QHistoryState *h = toHistoryState(s))
1010             QAbstractTransitionPrivate::get(h->defaultTransition())->callOnTransition(event);
1011 
1012         // Emit propertiesAssigned signal if the state has no animated properties.
1013         {
1014             QState *ss = toStandardState(s);
1015             if (ss
1016     #if QT_CONFIG(animation)
1017                 && !animationsForState.contains(s)
1018     #endif
1019                 )
1020                 QStatePrivate::get(ss)->emitPropertiesAssigned();
1021         }
1022 
1023         if (isFinal(s)) {
1024             QState *parent = s->parentState();
1025             if (parent) {
1026                 if (parent != rootState()) {
1027                     QFinalState *finalState = qobject_cast<QFinalState *>(s);
1028                     Q_ASSERT(finalState);
1029                     emitStateFinished(parent, finalState);
1030                 }
1031                 QState *grandparent = parent->parentState();
1032                 if (grandparent && isParallel(grandparent)) {
1033                     bool allChildStatesFinal = true;
1034                     QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates();
1035                     for (int j = 0; j < childStates.size(); ++j) {
1036                         QAbstractState *cs = childStates.at(j);
1037                         if (!isInFinalState(cs)) {
1038                             allChildStatesFinal = false;
1039                             break;
1040                         }
1041                     }
1042                     if (allChildStatesFinal && (grandparent != rootState())) {
1043                         QFinalState *finalState = qobject_cast<QFinalState *>(s);
1044                         Q_ASSERT(finalState);
1045                         emitStateFinished(grandparent, finalState);
1046                     }
1047                 }
1048             }
1049         }
1050     }
1051     {
1052         QSet<QAbstractState*>::const_iterator it;
1053         for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
1054             if (isFinal(*it)) {
1055                 QState *parent = (*it)->parentState();
1056                 if (((parent == rootState())
1057                      && (rootState()->childMode() == QState::ExclusiveStates))
1058                     || ((parent->parentState() == rootState())
1059                         && (rootState()->childMode() == QState::ParallelStates)
1060                         && isInFinalState(rootState()))) {
1061                     processing = false;
1062                     stopProcessingReason = Finished;
1063                     break;
1064                 }
1065             }
1066         }
1067     }
1068 //    qDebug() << "configuration:" << configuration.toList();
1069 }
1070 
1071 /* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ has a bug. See
1072  * QTBUG-44963 for details. The algorithm here is as described in
1073  * http://www.w3.org/Voice/2013/scxml-irp/SCXML.htm as of Friday March 13, 2015.
1074 
1075 procedure addDescendantStatesToEnter(state,statesToEnter,statesForDefaultEntry, defaultHistoryContent):
1076     if isHistoryState(state):
1077         if historyValue[state.id]:
1078             for s in historyValue[state.id]:
1079                 addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
1080             for s in historyValue[state.id]:
1081                 addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
1082         else:
1083             defaultHistoryContent[state.parent.id] = state.transition.content
1084             for s in state.transition.target:
1085                 addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
1086             for s in state.transition.target:
1087                 addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
1088     else:
1089         statesToEnter.add(state)
1090         if isCompoundState(state):
1091             statesForDefaultEntry.add(state)
1092             for s in state.initial.transition.target:
1093                 addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
1094             for s in state.initial.transition.target:
1095                 addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
1096         else:
1097             if isParallelState(state):
1098                 for child in getChildStates(state):
1099                     if not statesToEnter.some(lambda s: isDescendant(s,child)):
1100                         addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
1101 */
addDescendantStatesToEnter(QAbstractState * state,QSet<QAbstractState * > & statesToEnter,QSet<QAbstractState * > & statesForDefaultEntry)1102 void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state,
1103                                                       QSet<QAbstractState*> &statesToEnter,
1104                                                       QSet<QAbstractState*> &statesForDefaultEntry)
1105 {
1106     if (QHistoryState *h = toHistoryState(state)) {
1107         const QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(h)->configuration;
1108         if (!historyConfiguration.isEmpty()) {
1109             for (QAbstractState *s : historyConfiguration)
1110                 addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
1111             for (QAbstractState *s : historyConfiguration)
1112                 addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry);
1113 
1114 #ifdef QSTATEMACHINE_DEBUG
1115             qDebug() << q_func() << ": restoring"
1116                      << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
1117                      << "history from" << state << ':' << historyConfiguration;
1118 #endif
1119         } else {
1120             QList<QAbstractState*> defaultHistoryContent;
1121             if (QAbstractTransition *t = QHistoryStatePrivate::get(h)->defaultTransition)
1122                 defaultHistoryContent = t->targetStates();
1123 
1124             if (defaultHistoryContent.isEmpty()) {
1125                 setError(QStateMachine::NoDefaultStateInHistoryStateError, h);
1126             } else {
1127                 for (QAbstractState *s : qAsConst(defaultHistoryContent))
1128                     addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
1129                 for (QAbstractState *s : qAsConst(defaultHistoryContent))
1130                     addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry);
1131 #ifdef QSTATEMACHINE_DEBUG
1132                 qDebug() << q_func() << ": initial history targets for" << state << ':' << defaultHistoryContent;
1133 #endif
1134            }
1135         }
1136     } else {
1137         if (state == rootState()) {
1138             // Error has already been set by exitStates().
1139             Q_ASSERT(error != QStateMachine::NoError);
1140             return;
1141         }
1142         statesToEnter.insert(state);
1143         if (isCompound(state)) {
1144             statesForDefaultEntry.insert(state);
1145             if (QAbstractState *initial = toStandardState(state)->initialState()) {
1146                 Q_ASSERT(initial->machine() == q_func());
1147 
1148                 // FIXME:
1149                 // Qt does not support initial transitions (which is a problem for parallel states).
1150                 // The way it simulates this for other states, is by having a single initial state.
1151                 // See also the FIXME in enterStates.
1152                 statesForDefaultEntry.insert(initial);
1153 
1154                 addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry);
1155                 addAncestorStatesToEnter(initial, state, statesToEnter, statesForDefaultEntry);
1156             } else {
1157                 setError(QStateMachine::NoInitialStateError, state);
1158                 return;
1159             }
1160         } else if (isParallel(state)) {
1161             QState *grp = toStandardState(state);
1162             const auto childStates = QStatePrivate::get(grp)->childStates();
1163             for (QAbstractState *child : childStates) {
1164                 if (!containsDecendantOf(statesToEnter, child))
1165                     addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry);
1166             }
1167         }
1168     }
1169 }
1170 
1171 
1172 /* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
1173 
1174 procedure addAncestorStatesToEnter(state, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
1175    for anc in getProperAncestors(state,ancestor):
1176        statesToEnter.add(anc)
1177        if isParallelState(anc):
1178            for child in getChildStates(anc):
1179                if not statesToEnter.some(lambda s: isDescendant(s,child)):
1180                   addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
1181 */
addAncestorStatesToEnter(QAbstractState * s,QAbstractState * ancestor,QSet<QAbstractState * > & statesToEnter,QSet<QAbstractState * > & statesForDefaultEntry)1182 void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor,
1183                                                     QSet<QAbstractState*> &statesToEnter,
1184                                                     QSet<QAbstractState*> &statesForDefaultEntry)
1185 {
1186     const auto properAncestors = getProperAncestors(s, ancestor);
1187     for (QState *anc : properAncestors) {
1188         if (!anc->parentState())
1189             continue;
1190         statesToEnter.insert(anc);
1191         if (isParallel(anc)) {
1192             const auto childStates = QStatePrivate::get(anc)->childStates();
1193             for (QAbstractState *child : childStates) {
1194                 if (!containsDecendantOf(statesToEnter, child))
1195                     addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry);
1196             }
1197         }
1198     }
1199 }
1200 
isFinal(const QAbstractState * s)1201 bool QStateMachinePrivate::isFinal(const QAbstractState *s)
1202 {
1203     return s && (QAbstractStatePrivate::get(s)->stateType == QAbstractStatePrivate::FinalState);
1204 }
1205 
isParallel(const QAbstractState * s)1206 bool QStateMachinePrivate::isParallel(const QAbstractState *s)
1207 {
1208     const QState *ss = toStandardState(s);
1209     return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates);
1210 }
1211 
isCompound(const QAbstractState * s) const1212 bool QStateMachinePrivate::isCompound(const QAbstractState *s) const
1213 {
1214     const QState *group = toStandardState(s);
1215     if (!group)
1216         return false;
1217     bool isMachine = QStatePrivate::get(group)->isMachine;
1218     // Don't treat the machine as compound if it's a sub-state of this machine
1219     if (isMachine && (group != rootState()))
1220         return false;
1221     return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty());
1222 }
1223 
isAtomic(const QAbstractState * s) const1224 bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const
1225 {
1226     const QState *ss = toStandardState(s);
1227     return (ss && QStatePrivate::get(ss)->childStates().isEmpty())
1228         || isFinal(s)
1229         // Treat the machine as atomic if it's a sub-state of this machine
1230         || (ss && QStatePrivate::get(ss)->isMachine && (ss != rootState()));
1231 }
1232 
toStandardState(QAbstractState * state)1233 QState *QStateMachinePrivate::toStandardState(QAbstractState *state)
1234 {
1235     if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::StandardState))
1236         return static_cast<QState*>(state);
1237     return nullptr;
1238 }
1239 
toStandardState(const QAbstractState * state)1240 const QState *QStateMachinePrivate::toStandardState(const QAbstractState *state)
1241 {
1242     if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::StandardState))
1243         return static_cast<const QState*>(state);
1244     return nullptr;
1245 }
1246 
toFinalState(QAbstractState * state)1247 QFinalState *QStateMachinePrivate::toFinalState(QAbstractState *state)
1248 {
1249     if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::FinalState))
1250         return static_cast<QFinalState*>(state);
1251     return nullptr;
1252 }
1253 
toHistoryState(QAbstractState * state)1254 QHistoryState *QStateMachinePrivate::toHistoryState(QAbstractState *state)
1255 {
1256     if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::HistoryState))
1257         return static_cast<QHistoryState*>(state);
1258     return nullptr;
1259 }
1260 
isInFinalState(QAbstractState * s) const1261 bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const
1262 {
1263     if (isCompound(s)) {
1264         QState *grp = toStandardState(s);
1265         QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
1266         for (int i = 0; i < lst.size(); ++i) {
1267             QAbstractState *cs = lst.at(i);
1268             if (isFinal(cs) && configuration.contains(cs))
1269                 return true;
1270         }
1271         return false;
1272     } else if (isParallel(s)) {
1273         QState *grp = toStandardState(s);
1274         QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
1275         for (int i = 0; i < lst.size(); ++i) {
1276             QAbstractState *cs = lst.at(i);
1277             if (!isInFinalState(cs))
1278                 return false;
1279         }
1280         return true;
1281     }
1282     else
1283         return false;
1284 }
1285 
1286 #ifndef QT_NO_PROPERTIES
1287 
1288 /*!
1289   \internal
1290   Returns \c true if the given state has saved the value of the given property,
1291   otherwise returns \c false.
1292 */
hasRestorable(QAbstractState * state,QObject * object,const QByteArray & propertyName) const1293 bool QStateMachinePrivate::hasRestorable(QAbstractState *state, QObject *object,
1294                                          const QByteArray &propertyName) const
1295 {
1296     RestorableId id(object, propertyName);
1297     return registeredRestorablesForState.value(state).contains(id);
1298 }
1299 
1300 /*!
1301   \internal
1302   Returns the value to save for the property identified by \a id.
1303   If an exited state (member of \a exitedStates_sorted) has saved a value for
1304   the property, the saved value from the last (outermost) state that will be
1305   exited is returned (in practice carrying the saved value on to the next
1306   state). Otherwise, the current value of the property is returned.
1307 */
savedValueForRestorable(const QList<QAbstractState * > & exitedStates_sorted,QObject * object,const QByteArray & propertyName) const1308 QVariant QStateMachinePrivate::savedValueForRestorable(const QList<QAbstractState*> &exitedStates_sorted,
1309                                                        QObject *object, const QByteArray &propertyName) const
1310 {
1311 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1312     qDebug() << q_func() << ": savedValueForRestorable(" << exitedStates_sorted << object << propertyName << ')';
1313 #endif
1314     for (int i = exitedStates_sorted.size() - 1; i >= 0; --i) {
1315         QAbstractState *s = exitedStates_sorted.at(i);
1316         QHash<RestorableId, QVariant> restorables = registeredRestorablesForState.value(s);
1317         QHash<RestorableId, QVariant>::const_iterator it = restorables.constFind(RestorableId(object, propertyName));
1318         if (it != restorables.constEnd()) {
1319 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1320             qDebug() << q_func() << ":   using" << it.value() << "from" << s;
1321 #endif
1322             return it.value();
1323         }
1324     }
1325 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1326     qDebug() << q_func() << ":   falling back to current value";
1327 #endif
1328     return object->property(propertyName);
1329 }
1330 
registerRestorable(QAbstractState * state,QObject * object,const QByteArray & propertyName,const QVariant & value)1331 void QStateMachinePrivate::registerRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName,
1332                                               const QVariant &value)
1333 {
1334 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1335     qDebug() << q_func() << ": registerRestorable(" << state << object << propertyName << value << ')';
1336 #endif
1337     RestorableId id(object, propertyName);
1338     QHash<RestorableId, QVariant> &restorables = registeredRestorablesForState[state];
1339     if (!restorables.contains(id))
1340         restorables.insert(id, value);
1341 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1342     else
1343         qDebug() << q_func() << ":   (already registered)";
1344 #endif
1345 }
1346 
unregisterRestorables(const QList<QAbstractState * > & states,QObject * object,const QByteArray & propertyName)1347 void QStateMachinePrivate::unregisterRestorables(const QList<QAbstractState *> &states, QObject *object,
1348                                                  const QByteArray &propertyName)
1349 {
1350 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1351     qDebug() << q_func() << ": unregisterRestorables(" << states << object << propertyName << ')';
1352 #endif
1353     RestorableId id(object, propertyName);
1354     for (int i = 0; i < states.size(); ++i) {
1355         QAbstractState *s = states.at(i);
1356         QHash<QAbstractState*, QHash<RestorableId, QVariant> >::iterator it;
1357         it = registeredRestorablesForState.find(s);
1358         if (it == registeredRestorablesForState.end())
1359             continue;
1360         QHash<RestorableId, QVariant> &restorables = it.value();
1361         const auto it2 = restorables.constFind(id);
1362         if (it2 == restorables.cend())
1363             continue;
1364 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1365         qDebug() << q_func() << ":   unregistered for" << s;
1366 #endif
1367         restorables.erase(it2);
1368         if (restorables.isEmpty())
1369             registeredRestorablesForState.erase(it);
1370     }
1371 }
1372 
restorablesToPropertyList(const QHash<RestorableId,QVariant> & restorables) const1373 QVector<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const
1374 {
1375     QVector<QPropertyAssignment> result;
1376     QHash<RestorableId, QVariant>::const_iterator it;
1377     for (it = restorables.constBegin(); it != restorables.constEnd(); ++it) {
1378         const RestorableId &id = it.key();
1379         if (!id.object()) {
1380             // Property object was deleted
1381             continue;
1382         }
1383 #ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
1384         qDebug() << q_func() << ": restoring" << id.object() << id.proertyName() << "to" << it.value();
1385 #endif
1386         result.append(QPropertyAssignment(id.object(), id.propertyName(), it.value(), /*explicitlySet=*/false));
1387     }
1388     return result;
1389 }
1390 
1391 /*!
1392   \internal
1393   Computes the set of properties whose values should be restored given that
1394   the states \a statesToExit_sorted will be exited.
1395 
1396   If a particular (object, propertyName) pair occurs more than once (i.e.,
1397   because nested states are being exited), the value from the last (outermost)
1398   exited state takes precedence.
1399 
1400   The result of this function must be filtered according to the explicit
1401   property assignments (QState::assignProperty()) of the entered states
1402   before the property restoration is actually performed; i.e., if an entered
1403   state assigns to a property that would otherwise be restored, that property
1404   should not be restored after all, but the saved value from the exited state
1405   should be remembered by the entered state (see registerRestorable()).
1406 */
computePendingRestorables(const QList<QAbstractState * > & statesToExit_sorted) const1407 QHash<QStateMachinePrivate::RestorableId, QVariant> QStateMachinePrivate::computePendingRestorables(
1408         const QList<QAbstractState*> &statesToExit_sorted) const
1409 {
1410     QHash<QStateMachinePrivate::RestorableId, QVariant> restorables;
1411     for (int i = statesToExit_sorted.size() - 1; i >= 0; --i) {
1412         QAbstractState *s = statesToExit_sorted.at(i);
1413         QHash<QStateMachinePrivate::RestorableId, QVariant> rs = registeredRestorablesForState.value(s);
1414         QHash<QStateMachinePrivate::RestorableId, QVariant>::const_iterator it;
1415         for (it = rs.constBegin(); it != rs.constEnd(); ++it) {
1416             if (!restorables.contains(it.key()))
1417                 restorables.insert(it.key(), it.value());
1418         }
1419     }
1420     return restorables;
1421 }
1422 
1423 /*!
1424   \internal
1425   Computes the ordered sets of property assignments for the states to be
1426   entered, \a statesToEnter_sorted. Also filters \a pendingRestorables (removes
1427   properties that should not be restored because they are assigned by an
1428   entered state).
1429 */
computePropertyAssignments(const QList<QAbstractState * > & statesToEnter_sorted,QHash<RestorableId,QVariant> & pendingRestorables) const1430 QHash<QAbstractState*, QVector<QPropertyAssignment> > QStateMachinePrivate::computePropertyAssignments(
1431         const QList<QAbstractState*> &statesToEnter_sorted, QHash<RestorableId, QVariant> &pendingRestorables) const
1432 {
1433     QHash<QAbstractState*, QVector<QPropertyAssignment> > assignmentsForState;
1434     for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
1435         QState *s = toStandardState(statesToEnter_sorted.at(i));
1436         if (!s)
1437             continue;
1438 
1439         QVector<QPropertyAssignment> &assignments = QStatePrivate::get(s)->propertyAssignments;
1440         for (int j = 0; j < assignments.size(); ++j) {
1441             const QPropertyAssignment &assn = assignments.at(j);
1442             if (assn.objectDeleted()) {
1443                 assignments.removeAt(j--);
1444             } else {
1445                 pendingRestorables.remove(RestorableId(assn.object, assn.propertyName));
1446                 assignmentsForState[s].append(assn);
1447             }
1448         }
1449     }
1450     return assignmentsForState;
1451 }
1452 
1453 #endif // QT_NO_PROPERTIES
1454 
findErrorState(QAbstractState * context)1455 QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context)
1456 {
1457     // Find error state recursively in parent hierarchy if not set explicitly for context state
1458     QAbstractState *errorState = nullptr;
1459     if (context != nullptr) {
1460         QState *s = toStandardState(context);
1461         if (s != nullptr)
1462             errorState = s->errorState();
1463 
1464         if (errorState == nullptr)
1465             errorState = findErrorState(context->parentState());
1466     }
1467 
1468     return errorState;
1469 }
1470 
setError(QStateMachine::Error errorCode,QAbstractState * currentContext)1471 void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext)
1472 {
1473     Q_Q(QStateMachine);
1474 
1475     error = errorCode;
1476     switch (errorCode) {
1477     case QStateMachine::NoInitialStateError:
1478         Q_ASSERT(currentContext != nullptr);
1479 
1480         errorString = QStateMachine::tr("Missing initial state in compound state '%1'")
1481                         .arg(currentContext->objectName());
1482 
1483         break;
1484     case QStateMachine::NoDefaultStateInHistoryStateError:
1485         Q_ASSERT(currentContext != nullptr);
1486 
1487         errorString = QStateMachine::tr("Missing default state in history state '%1'")
1488                         .arg(currentContext->objectName());
1489         break;
1490 
1491     case QStateMachine::NoCommonAncestorForTransitionError:
1492         Q_ASSERT(currentContext != nullptr);
1493 
1494         errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'")
1495                         .arg(currentContext->objectName());
1496         break;
1497 
1498     case QStateMachine::StateMachineChildModeSetToParallelError:
1499         Q_ASSERT(currentContext != nullptr);
1500 
1501         errorString = QStateMachine::tr("Child mode of state machine '%1' is not 'ExclusiveStates'.")
1502                         .arg(currentContext->objectName());
1503         break;
1504 
1505     default:
1506         errorString = QStateMachine::tr("Unknown error");
1507     };
1508 
1509     pendingErrorStates.clear();
1510     pendingErrorStatesForDefaultEntry.clear();
1511 
1512     QAbstractState *currentErrorState = findErrorState(currentContext);
1513 
1514     // Avoid infinite loop if the error state itself has an error
1515     if (currentContext == currentErrorState)
1516         currentErrorState = nullptr;
1517 
1518     Q_ASSERT(currentErrorState != rootState());
1519 
1520     if (currentErrorState != nullptr) {
1521 #ifdef QSTATEMACHINE_DEBUG
1522         qDebug() << q << ": entering error state" << currentErrorState << "from" << currentContext;
1523 #endif
1524         pendingErrorStates.insert(currentErrorState);
1525         addDescendantStatesToEnter(currentErrorState, pendingErrorStates, pendingErrorStatesForDefaultEntry);
1526         addAncestorStatesToEnter(currentErrorState, rootState(), pendingErrorStates, pendingErrorStatesForDefaultEntry);
1527         pendingErrorStates -= configuration;
1528     } else {
1529         qWarning("Unrecoverable error detected in running state machine: %ls",
1530                  qUtf16Printable(errorString));
1531         q->stop();
1532     }
1533 }
1534 
1535 #if QT_CONFIG(animation)
1536 
1537 QStateMachinePrivate::InitializeAnimationResult
initializeAnimation(QAbstractAnimation * abstractAnimation,const QPropertyAssignment & prop)1538 QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation,
1539                                           const QPropertyAssignment &prop)
1540 {
1541     InitializeAnimationResult result;
1542     QAnimationGroup *group = qobject_cast<QAnimationGroup*>(abstractAnimation);
1543     if (group) {
1544         for (int i = 0; i < group->animationCount(); ++i) {
1545             QAbstractAnimation *animationChild = group->animationAt(i);
1546             const auto ret = initializeAnimation(animationChild, prop);
1547             result.handledAnimations << ret.handledAnimations;
1548             result.localResetEndValues << ret.localResetEndValues;
1549         }
1550     } else {
1551         QPropertyAnimation *animation = qobject_cast<QPropertyAnimation *>(abstractAnimation);
1552         if (animation != nullptr
1553             && prop.object == animation->targetObject()
1554             && prop.propertyName == animation->propertyName()) {
1555 
1556             // Only change end value if it is undefined
1557             if (!animation->endValue().isValid()) {
1558                 animation->setEndValue(prop.value);
1559                 result.localResetEndValues.append(animation);
1560             }
1561             result.handledAnimations.append(animation);
1562         }
1563     }
1564     return result;
1565 }
1566 
_q_animationFinished()1567 void QStateMachinePrivate::_q_animationFinished()
1568 {
1569     Q_Q(QStateMachine);
1570     QAbstractAnimation *anim = qobject_cast<QAbstractAnimation*>(q->sender());
1571     Q_ASSERT(anim != nullptr);
1572     QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished()));
1573     if (resetAnimationEndValues.contains(anim)) {
1574         qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize
1575         resetAnimationEndValues.remove(anim);
1576     }
1577 
1578     QAbstractState *state = stateForAnimation.take(anim);
1579     Q_ASSERT(state != nullptr);
1580 
1581 #ifndef QT_NO_PROPERTIES
1582     // Set the final property value.
1583     QPropertyAssignment assn = propertyForAnimation.take(anim);
1584     assn.write();
1585     if (!assn.explicitlySet)
1586         unregisterRestorables(QList<QAbstractState*>() << state, assn.object, assn.propertyName);
1587 #endif
1588 
1589     QHash<QAbstractState*, QList<QAbstractAnimation*> >::iterator it;
1590     it = animationsForState.find(state);
1591     Q_ASSERT(it != animationsForState.end());
1592     QList<QAbstractAnimation*> &animations = it.value();
1593     animations.removeOne(anim);
1594     if (animations.isEmpty()) {
1595         animationsForState.erase(it);
1596         QStatePrivate::get(toStandardState(state))->emitPropertiesAssigned();
1597     }
1598 }
1599 
selectAnimations(const QList<QAbstractTransition * > & transitionList) const1600 QList<QAbstractAnimation *> QStateMachinePrivate::selectAnimations(const QList<QAbstractTransition *> &transitionList) const
1601 {
1602     QList<QAbstractAnimation *> selectedAnimations;
1603     if (animated) {
1604         for (int i = 0; i < transitionList.size(); ++i) {
1605             QAbstractTransition *transition = transitionList.at(i);
1606 
1607             selectedAnimations << transition->animations();
1608             selectedAnimations << defaultAnimationsForSource.values(transition->sourceState());
1609 
1610             QList<QAbstractState *> targetStates = transition->targetStates();
1611             for (int j=0; j<targetStates.size(); ++j)
1612                 selectedAnimations << defaultAnimationsForTarget.values(targetStates.at(j));
1613         }
1614         selectedAnimations << defaultAnimations;
1615     }
1616     return selectedAnimations;
1617 }
1618 
terminateActiveAnimations(QAbstractState * state,const QHash<QAbstractState *,QVector<QPropertyAssignment>> & assignmentsForEnteredStates)1619 void QStateMachinePrivate::terminateActiveAnimations(QAbstractState *state,
1620     const QHash<QAbstractState*, QVector<QPropertyAssignment> > &assignmentsForEnteredStates)
1621 {
1622     Q_Q(QStateMachine);
1623     QList<QAbstractAnimation*> animations = animationsForState.take(state);
1624     for (int i = 0; i < animations.size(); ++i) {
1625         QAbstractAnimation *anim = animations.at(i);
1626         QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished()));
1627         stateForAnimation.remove(anim);
1628 
1629         // Stop the (top-level) animation.
1630         // ### Stopping nested animation has weird behavior.
1631         QAbstractAnimation *topLevelAnim = anim;
1632         while (QAnimationGroup *group = topLevelAnim->group())
1633             topLevelAnim = group;
1634         topLevelAnim->stop();
1635 
1636         if (resetAnimationEndValues.contains(anim)) {
1637             qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize
1638             resetAnimationEndValues.remove(anim);
1639         }
1640         QPropertyAssignment assn = propertyForAnimation.take(anim);
1641         Q_ASSERT(assn.object != nullptr);
1642         // If there is no property assignment that sets this property,
1643         // set the property to its target value.
1644         bool found = false;
1645         QHash<QAbstractState*, QVector<QPropertyAssignment> >::const_iterator it;
1646         for (it = assignmentsForEnteredStates.constBegin(); it != assignmentsForEnteredStates.constEnd(); ++it) {
1647             const QVector<QPropertyAssignment> &assignments = it.value();
1648             for (int j = 0; j < assignments.size(); ++j) {
1649                 if (assignments.at(j).hasTarget(assn.object, assn.propertyName)) {
1650                     found = true;
1651                     break;
1652                 }
1653             }
1654         }
1655         if (!found) {
1656             assn.write();
1657             if (!assn.explicitlySet)
1658                 unregisterRestorables(QList<QAbstractState*>() << state, assn.object, assn.propertyName);
1659         }
1660     }
1661 }
1662 
initializeAnimations(QAbstractState * state,const QList<QAbstractAnimation * > & selectedAnimations,const QList<QAbstractState * > & exitedStates_sorted,QHash<QAbstractState *,QVector<QPropertyAssignment>> & assignmentsForEnteredStates)1663 void QStateMachinePrivate::initializeAnimations(QAbstractState *state, const QList<QAbstractAnimation *> &selectedAnimations,
1664                                                 const QList<QAbstractState*> &exitedStates_sorted,
1665                                                 QHash<QAbstractState*, QVector<QPropertyAssignment> > &assignmentsForEnteredStates)
1666 {
1667     Q_Q(QStateMachine);
1668     if (!assignmentsForEnteredStates.contains(state))
1669         return;
1670     QVector<QPropertyAssignment> &assignments = assignmentsForEnteredStates[state];
1671     for (int i = 0; i < selectedAnimations.size(); ++i) {
1672         QAbstractAnimation *anim = selectedAnimations.at(i);
1673         QVector<QPropertyAssignment>::iterator it;
1674         for (it = assignments.begin(); it != assignments.end(); ) {
1675             const QPropertyAssignment &assn = *it;
1676             const auto ret = initializeAnimation(anim, assn);
1677             if (!ret.handledAnimations.isEmpty()) {
1678                 for (int j = 0; j < ret.handledAnimations.size(); ++j) {
1679                     QAbstractAnimation *a = ret.handledAnimations.at(j);
1680                     propertyForAnimation.insert(a, assn);
1681                     stateForAnimation.insert(a, state);
1682                     animationsForState[state].append(a);
1683                     // ### connect to just the top-level animation?
1684                     QObject::connect(a, SIGNAL(finished()), q, SLOT(_q_animationFinished()), Qt::UniqueConnection);
1685                 }
1686                 if ((globalRestorePolicy == QState::RestoreProperties)
1687                         && !hasRestorable(state, assn.object, assn.propertyName)) {
1688                     QVariant value = savedValueForRestorable(exitedStates_sorted, assn.object, assn.propertyName);
1689                     unregisterRestorables(exitedStates_sorted, assn.object, assn.propertyName);
1690                     registerRestorable(state, assn.object, assn.propertyName, value);
1691                 }
1692                 it = assignments.erase(it);
1693             } else {
1694                 ++it;
1695             }
1696             for (int j = 0; j < ret.localResetEndValues.size(); ++j)
1697                 resetAnimationEndValues.insert(ret.localResetEndValues.at(j));
1698         }
1699         // We require that at least one animation is valid.
1700         // ### generalize
1701         QList<QVariantAnimation*> variantAnims = anim->findChildren<QVariantAnimation*>();
1702         if (QVariantAnimation *va = qobject_cast<QVariantAnimation*>(anim))
1703             variantAnims.append(va);
1704 
1705         bool hasValidEndValue = false;
1706         for (int j = 0; j < variantAnims.size(); ++j) {
1707             if (variantAnims.at(j)->endValue().isValid()) {
1708                 hasValidEndValue = true;
1709                 break;
1710             }
1711         }
1712 
1713         if (hasValidEndValue) {
1714             if (anim->state() == QAbstractAnimation::Running) {
1715                 // The animation is still running. This can happen if the
1716                 // animation is a group, and one of its children just finished,
1717                 // and that caused a state to emit its propertiesAssigned() signal, and
1718                 // that triggered a transition in the machine.
1719                 // Just stop the animation so it is correctly restarted again.
1720                 anim->stop();
1721             }
1722             anim->start();
1723         }
1724 
1725         if (assignments.isEmpty()) {
1726             assignmentsForEnteredStates.remove(state);
1727             break;
1728         }
1729     }
1730 }
1731 
1732 #endif // animation
1733 
createInitialTransition() const1734 QAbstractTransition *QStateMachinePrivate::createInitialTransition() const
1735 {
1736     class InitialTransition : public QAbstractTransition
1737     {
1738     public:
1739         InitialTransition(const QList<QAbstractState *> &targets)
1740             : QAbstractTransition()
1741         { setTargetStates(targets); }
1742     protected:
1743         bool eventTest(QEvent *) override { return true; }
1744         void onTransition(QEvent *) override {}
1745     };
1746 
1747     QState *root = rootState();
1748     Q_ASSERT(root != nullptr);
1749     QList<QAbstractState *> targets;
1750     switch (root->childMode()) {
1751     case QState::ExclusiveStates:
1752         targets.append(root->initialState());
1753         break;
1754     case QState::ParallelStates:
1755         targets = QStatePrivate::get(root)->childStates();
1756         break;
1757     }
1758     return new InitialTransition(targets);
1759 }
1760 
clearHistory()1761 void QStateMachinePrivate::clearHistory()
1762 {
1763     Q_Q(QStateMachine);
1764     QList<QHistoryState*> historyStates = q->findChildren<QHistoryState*>();
1765     for (int i = 0; i < historyStates.size(); ++i) {
1766         QHistoryState *h = historyStates.at(i);
1767         QHistoryStatePrivate::get(h)->configuration.clear();
1768     }
1769 }
1770 
1771 /*!
1772   \internal
1773 
1774   Registers all signal transitions whose sender object lives in another thread.
1775 
1776   Normally, signal transitions are lazily registered (when a state becomes
1777   active). But if the sender is in a different thread, the transition must be
1778   registered early to keep the state machine from "dropping" signals; e.g.,
1779   a second (transition-bound) signal could be emitted on the sender thread
1780   before the state machine gets to process the first signal.
1781 */
registerMultiThreadedSignalTransitions()1782 void QStateMachinePrivate::registerMultiThreadedSignalTransitions()
1783 {
1784     Q_Q(QStateMachine);
1785     QList<QSignalTransition*> transitions = rootState()->findChildren<QSignalTransition*>();
1786     for (int i = 0; i < transitions.size(); ++i) {
1787         QSignalTransition *t = transitions.at(i);
1788         if ((t->machine() == q) && t->senderObject() && (t->senderObject()->thread() != q->thread()))
1789             registerSignalTransition(t);
1790     }
1791 }
1792 
_q_start()1793 void QStateMachinePrivate::_q_start()
1794 {
1795     Q_Q(QStateMachine);
1796     Q_ASSERT(state == Starting);
1797     // iterate over a copy, since we emit signals which may cause
1798     // 'configuration' to change, resulting in undefined behavior when
1799     // iterating at the same time:
1800     const auto config = configuration;
1801     for (QAbstractState *state : config) {
1802         QAbstractStatePrivate *abstractStatePrivate = QAbstractStatePrivate::get(state);
1803         abstractStatePrivate->active = false;
1804         emit state->activeChanged(false);
1805     }
1806     configuration.clear();
1807     qDeleteAll(internalEventQueue);
1808     internalEventQueue.clear();
1809     qDeleteAll(externalEventQueue);
1810     externalEventQueue.clear();
1811     clearHistory();
1812 
1813     registerMultiThreadedSignalTransitions();
1814 
1815     startupHook();
1816 
1817 #ifdef QSTATEMACHINE_DEBUG
1818     qDebug() << q << ": starting";
1819 #endif
1820     state = Running;
1821     processingScheduled = true; // we call _q_process() below
1822 
1823     QList<QAbstractTransition*> transitions;
1824     CalculationCache calculationCache;
1825     QAbstractTransition *initialTransition = createInitialTransition();
1826     transitions.append(initialTransition);
1827 
1828     QEvent nullEvent(QEvent::None);
1829     executeTransitionContent(&nullEvent, transitions);
1830     QList<QAbstractState*> exitedStates = QList<QAbstractState*>();
1831     QSet<QAbstractState*> statesForDefaultEntry;
1832     QList<QAbstractState*> enteredStates = computeEntrySet(transitions, statesForDefaultEntry, &calculationCache);
1833     QHash<RestorableId, QVariant> pendingRestorables;
1834     QHash<QAbstractState*, QVector<QPropertyAssignment> > assignmentsForEnteredStates =
1835             computePropertyAssignments(enteredStates, pendingRestorables);
1836 #if QT_CONFIG(animation)
1837     QList<QAbstractAnimation*> selectedAnimations = selectAnimations(transitions);
1838 #endif
1839     // enterStates() will set stopProcessingReason to Finished if a final
1840     // state is entered.
1841     stopProcessingReason = EventQueueEmpty;
1842     enterStates(&nullEvent, exitedStates, enteredStates, statesForDefaultEntry,
1843                 assignmentsForEnteredStates
1844 #if QT_CONFIG(animation)
1845                 , selectedAnimations
1846 #endif
1847                 );
1848     delete initialTransition;
1849 
1850 #ifdef QSTATEMACHINE_DEBUG
1851     qDebug() << q << ": initial configuration:" << configuration;
1852 #endif
1853 
1854     emit q->started(QStateMachine::QPrivateSignal());
1855     emit q->runningChanged(true);
1856 
1857     if (stopProcessingReason == Finished) {
1858         // The state machine immediately reached a final state.
1859         processingScheduled = false;
1860         state = NotRunning;
1861         unregisterAllTransitions();
1862         emitFinished();
1863         emit q->runningChanged(false);
1864         exitInterpreter();
1865     } else {
1866         _q_process();
1867     }
1868 }
1869 
_q_process()1870 void QStateMachinePrivate::_q_process()
1871 {
1872     Q_Q(QStateMachine);
1873     Q_ASSERT(state == Running);
1874     Q_ASSERT(!processing);
1875     processing = true;
1876     processingScheduled = false;
1877     beginMacrostep();
1878 #ifdef QSTATEMACHINE_DEBUG
1879     qDebug() << q << ": starting the event processing loop";
1880 #endif
1881     bool didChange = false;
1882     while (processing) {
1883         if (stop) {
1884             processing = false;
1885             break;
1886         }
1887         QList<QAbstractTransition*> enabledTransitions;
1888         CalculationCache calculationCache;
1889 
1890         QEvent *e = new QEvent(QEvent::None);
1891         enabledTransitions = selectTransitions(e, &calculationCache);
1892         if (enabledTransitions.isEmpty()) {
1893             delete e;
1894             e = nullptr;
1895         }
1896         while (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != nullptr)) {
1897 #ifdef QSTATEMACHINE_DEBUG
1898             qDebug() << q << ": dequeued internal event" << e << "of type" << e->type();
1899 #endif
1900             enabledTransitions = selectTransitions(e, &calculationCache);
1901             if (enabledTransitions.isEmpty()) {
1902                 delete e;
1903                 e = nullptr;
1904             }
1905         }
1906         while (enabledTransitions.isEmpty() && ((e = dequeueExternalEvent()) != nullptr)) {
1907 #ifdef QSTATEMACHINE_DEBUG
1908                 qDebug() << q << ": dequeued external event" << e << "of type" << e->type();
1909 #endif
1910                 enabledTransitions = selectTransitions(e, &calculationCache);
1911                 if (enabledTransitions.isEmpty()) {
1912                     delete e;
1913                     e = nullptr;
1914                 }
1915         }
1916         if (enabledTransitions.isEmpty()) {
1917             if (isInternalEventQueueEmpty()) {
1918                 processing = false;
1919                 stopProcessingReason = EventQueueEmpty;
1920                 noMicrostep();
1921 #ifdef QSTATEMACHINE_DEBUG
1922                 qDebug() << q << ": no transitions enabled";
1923 #endif
1924             }
1925         } else {
1926             didChange = true;
1927             q->beginMicrostep(e);
1928             microstep(e, enabledTransitions, &calculationCache);
1929             q->endMicrostep(e);
1930         }
1931         delete e;
1932     }
1933 #ifdef QSTATEMACHINE_DEBUG
1934     qDebug() << q << ": finished the event processing loop";
1935 #endif
1936     if (stop) {
1937         stop = false;
1938         stopProcessingReason = Stopped;
1939     }
1940 
1941     switch (stopProcessingReason) {
1942     case EventQueueEmpty:
1943         processedPendingEvents(didChange);
1944         break;
1945     case Finished:
1946         state = NotRunning;
1947         cancelAllDelayedEvents();
1948         unregisterAllTransitions();
1949         emitFinished();
1950         emit q->runningChanged(false);
1951         break;
1952     case Stopped:
1953         state = NotRunning;
1954         cancelAllDelayedEvents();
1955         unregisterAllTransitions();
1956         emit q->stopped(QStateMachine::QPrivateSignal());
1957         emit q->runningChanged(false);
1958         break;
1959     }
1960     endMacrostep(didChange);
1961     if (stopProcessingReason == Finished)
1962         exitInterpreter();
1963 }
1964 
_q_startDelayedEventTimer(int id,int delay)1965 void QStateMachinePrivate::_q_startDelayedEventTimer(int id, int delay)
1966 {
1967     Q_Q(QStateMachine);
1968     QMutexLocker locker(&delayedEventsMutex);
1969     QHash<int, DelayedEvent>::iterator it = delayedEvents.find(id);
1970     if (it != delayedEvents.end()) {
1971         DelayedEvent &e = it.value();
1972         Q_ASSERT(!e.timerId);
1973         e.timerId = q->startTimer(delay);
1974         if (!e.timerId) {
1975             qWarning("QStateMachine::postDelayedEvent: failed to start timer (id=%d, delay=%d)", id, delay);
1976             delete e.event;
1977             delayedEvents.erase(it);
1978             delayedEventIdFreeList.release(id);
1979         } else {
1980             timerIdToDelayedEventId.insert(e.timerId, id);
1981         }
1982     } else {
1983         // It's been cancelled already
1984         delayedEventIdFreeList.release(id);
1985     }
1986 }
1987 
_q_killDelayedEventTimer(int id,int timerId)1988 void QStateMachinePrivate::_q_killDelayedEventTimer(int id, int timerId)
1989 {
1990     Q_Q(QStateMachine);
1991     q->killTimer(timerId);
1992     QMutexLocker locker(&delayedEventsMutex);
1993     delayedEventIdFreeList.release(id);
1994 }
1995 
postInternalEvent(QEvent * e)1996 void QStateMachinePrivate::postInternalEvent(QEvent *e)
1997 {
1998     QMutexLocker locker(&internalEventMutex);
1999     internalEventQueue.append(e);
2000 }
2001 
postExternalEvent(QEvent * e)2002 void QStateMachinePrivate::postExternalEvent(QEvent *e)
2003 {
2004     QMutexLocker locker(&externalEventMutex);
2005     externalEventQueue.append(e);
2006 }
2007 
dequeueInternalEvent()2008 QEvent *QStateMachinePrivate::dequeueInternalEvent()
2009 {
2010     QMutexLocker locker(&internalEventMutex);
2011     if (internalEventQueue.isEmpty())
2012         return nullptr;
2013     return internalEventQueue.takeFirst();
2014 }
2015 
dequeueExternalEvent()2016 QEvent *QStateMachinePrivate::dequeueExternalEvent()
2017 {
2018     QMutexLocker locker(&externalEventMutex);
2019     if (externalEventQueue.isEmpty())
2020         return nullptr;
2021     return externalEventQueue.takeFirst();
2022 }
2023 
isInternalEventQueueEmpty()2024 bool QStateMachinePrivate::isInternalEventQueueEmpty()
2025 {
2026     QMutexLocker locker(&internalEventMutex);
2027     return internalEventQueue.isEmpty();
2028 }
2029 
isExternalEventQueueEmpty()2030 bool QStateMachinePrivate::isExternalEventQueueEmpty()
2031 {
2032     QMutexLocker locker(&externalEventMutex);
2033     return externalEventQueue.isEmpty();
2034 }
2035 
processEvents(EventProcessingMode processingMode)2036 void QStateMachinePrivate::processEvents(EventProcessingMode processingMode)
2037 {
2038     Q_Q(QStateMachine);
2039     if ((state != Running) || processing || processingScheduled)
2040         return;
2041     switch (processingMode) {
2042     case DirectProcessing:
2043         if (QThread::currentThread() == q->thread()) {
2044             _q_process();
2045             break;
2046         }
2047         // processing must be done in the machine thread, so:
2048         Q_FALLTHROUGH();
2049     case QueuedProcessing:
2050         processingScheduled = true;
2051         QMetaObject::invokeMethod(q, "_q_process", Qt::QueuedConnection);
2052         break;
2053     }
2054 }
2055 
cancelAllDelayedEvents()2056 void QStateMachinePrivate::cancelAllDelayedEvents()
2057 {
2058     Q_Q(QStateMachine);
2059     QMutexLocker locker(&delayedEventsMutex);
2060     QHash<int, DelayedEvent>::const_iterator it;
2061     for (it = delayedEvents.constBegin(); it != delayedEvents.constEnd(); ++it) {
2062         const DelayedEvent &e = it.value();
2063         if (e.timerId) {
2064             timerIdToDelayedEventId.remove(e.timerId);
2065             q->killTimer(e.timerId);
2066             delayedEventIdFreeList.release(it.key());
2067         } else {
2068             // Cancellation will be detected in pending _q_startDelayedEventTimer() call
2069         }
2070         delete e.event;
2071     }
2072     delayedEvents.clear();
2073 }
2074 
2075 /*
2076   This function is called when the state machine is performing no
2077   microstep because no transition is enabled (i.e. an event is ignored).
2078 
2079   The default implementation does nothing.
2080 */
noMicrostep()2081 void QStateMachinePrivate::noMicrostep()
2082 { }
2083 
2084 /*
2085   This function is called when the state machine has reached a stable
2086   state (no pending events), and has not finished yet.
2087   For each event the state machine receives it is guaranteed that
2088   1) beginMacrostep is called
2089   2) selectTransition is called at least once
2090   3) begin/endMicrostep is called at least once or noMicrostep is called
2091      at least once (possibly both, but at least one)
2092   4) the state machine either enters an infinite loop, or stops (runningChanged(false),
2093      and either finished or stopped are emitted), or processedPendingEvents() is called.
2094   5) if the machine is not in an infinite loop endMacrostep is called
2095   6) when the machine is finished and all processing (like signal emission) is done,
2096      exitInterpreter() is called. (This is the same name as the SCXML specification uses.)
2097 
2098   didChange is set to true if at least one microstep was performed, it is possible
2099   that the machine returned to exactly the same state as before, but some transitions
2100   were triggered.
2101 
2102   The default implementation does nothing.
2103 */
processedPendingEvents(bool didChange)2104 void QStateMachinePrivate::processedPendingEvents(bool didChange)
2105 {
2106     Q_UNUSED(didChange);
2107 }
2108 
beginMacrostep()2109 void QStateMachinePrivate::beginMacrostep()
2110 { }
2111 
endMacrostep(bool didChange)2112 void QStateMachinePrivate::endMacrostep(bool didChange)
2113 {
2114     Q_UNUSED(didChange);
2115 }
2116 
exitInterpreter()2117 void QStateMachinePrivate::exitInterpreter()
2118 {
2119 }
2120 
emitStateFinished(QState * forState,QFinalState * guiltyState)2121 void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guiltyState)
2122 {
2123     Q_UNUSED(guiltyState);
2124     Q_ASSERT(guiltyState);
2125 
2126 #ifdef QSTATEMACHINE_DEBUG
2127     Q_Q(QStateMachine);
2128     qDebug() << q << ": emitting finished signal for" << forState;
2129 #endif
2130 
2131     QStatePrivate::get(forState)->emitFinished();
2132 }
2133 
startupHook()2134 void QStateMachinePrivate::startupHook()
2135 {
2136 }
2137 
2138 namespace _QStateMachine_Internal{
2139 
2140 class GoToStateTransition : public QAbstractTransition
2141 {
2142     Q_OBJECT
2143 public:
GoToStateTransition(QAbstractState * target)2144     GoToStateTransition(QAbstractState *target)
2145         : QAbstractTransition()
2146     { setTargetState(target); }
2147 protected:
onTransition(QEvent *)2148     void onTransition(QEvent *) override { deleteLater(); }
eventTest(QEvent *)2149     bool eventTest(QEvent *) override { return true; }
2150 };
2151 
2152 } // namespace
2153 // mingw compiler tries to export QObject::findChild<GoToStateTransition>(),
2154 // which doesn't work if its in an anonymous namespace.
2155 using namespace _QStateMachine_Internal;
2156 /*!
2157   \internal
2158 
2159   Causes this state machine to unconditionally transition to the given
2160   \a targetState.
2161 
2162   Provides a backdoor for using the state machine "imperatively"; i.e.  rather
2163   than defining explicit transitions, you drive the machine's execution by
2164   calling this function. It breaks the whole integrity of the
2165   transition-driven model, but is provided for pragmatic reasons.
2166 */
goToState(QAbstractState * targetState)2167 void QStateMachinePrivate::goToState(QAbstractState *targetState)
2168 {
2169     if (!targetState) {
2170         qWarning("QStateMachine::goToState(): cannot go to null state");
2171         return;
2172     }
2173 
2174     if (configuration.contains(targetState))
2175         return;
2176 
2177     Q_ASSERT(state == Running);
2178     QState *sourceState = nullptr;
2179     QSet<QAbstractState*>::const_iterator it;
2180     for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
2181         sourceState = toStandardState(*it);
2182         if (sourceState != nullptr)
2183             break;
2184     }
2185 
2186     Q_ASSERT(sourceState != nullptr);
2187     // Reuse previous GoToStateTransition in case of several calls to
2188     // goToState() in a row.
2189     GoToStateTransition *trans = sourceState->findChild<GoToStateTransition*>();
2190     if (!trans) {
2191         trans = new GoToStateTransition(targetState);
2192         sourceState->addTransition(trans);
2193     } else {
2194         trans->setTargetState(targetState);
2195     }
2196 
2197     processEvents(QueuedProcessing);
2198 }
2199 
registerTransitions(QAbstractState * state)2200 void QStateMachinePrivate::registerTransitions(QAbstractState *state)
2201 {
2202     QState *group = toStandardState(state);
2203     if (!group)
2204         return;
2205     QList<QAbstractTransition*> transitions = QStatePrivate::get(group)->transitions();
2206     for (int i = 0; i < transitions.size(); ++i) {
2207         QAbstractTransition *t = transitions.at(i);
2208         registerTransition(t);
2209     }
2210 }
2211 
maybeRegisterTransition(QAbstractTransition * transition)2212 void QStateMachinePrivate::maybeRegisterTransition(QAbstractTransition *transition)
2213 {
2214     if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
2215         maybeRegisterSignalTransition(st);
2216     }
2217 #if QT_CONFIG(qeventtransition)
2218     else if (QEventTransition *et = qobject_cast<QEventTransition*>(transition)) {
2219         maybeRegisterEventTransition(et);
2220     }
2221 #endif
2222 }
2223 
registerTransition(QAbstractTransition * transition)2224 void QStateMachinePrivate::registerTransition(QAbstractTransition *transition)
2225 {
2226     if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
2227         registerSignalTransition(st);
2228     }
2229 #if QT_CONFIG(qeventtransition)
2230     else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) {
2231         registerEventTransition(oet);
2232     }
2233 #endif
2234 }
2235 
unregisterTransition(QAbstractTransition * transition)2236 void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition)
2237 {
2238     if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
2239         unregisterSignalTransition(st);
2240     }
2241 #if QT_CONFIG(qeventtransition)
2242     else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) {
2243         unregisterEventTransition(oet);
2244     }
2245 #endif
2246 }
2247 
maybeRegisterSignalTransition(QSignalTransition * transition)2248 void QStateMachinePrivate::maybeRegisterSignalTransition(QSignalTransition *transition)
2249 {
2250     Q_Q(QStateMachine);
2251     if ((state == Running) && (configuration.contains(transition->sourceState())
2252             || (transition->senderObject() && (transition->senderObject()->thread() != q->thread())))) {
2253         registerSignalTransition(transition);
2254     }
2255 }
2256 
registerSignalTransition(QSignalTransition * transition)2257 void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition)
2258 {
2259     Q_Q(QStateMachine);
2260     if (QSignalTransitionPrivate::get(transition)->signalIndex != -1)
2261         return; // already registered
2262     const QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
2263     if (!sender)
2264         return;
2265     QByteArray signal = QSignalTransitionPrivate::get(transition)->signal;
2266     if (signal.isEmpty())
2267         return;
2268     if (signal.startsWith('0'+QSIGNAL_CODE))
2269         signal.remove(0, 1);
2270     const QMetaObject *meta = sender->metaObject();
2271     int signalIndex = meta->indexOfSignal(signal);
2272     int originalSignalIndex = signalIndex;
2273     if (signalIndex == -1) {
2274         signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal));
2275         if (signalIndex == -1) {
2276             qWarning("QSignalTransition: no such signal: %s::%s",
2277                      meta->className(), signal.constData());
2278             return;
2279         }
2280         originalSignalIndex = signalIndex;
2281     }
2282     // The signal index we actually want to connect to is the one
2283     // that is going to be sent, i.e. the non-cloned original index.
2284     while (meta->method(signalIndex).attributes() & QMetaMethod::Cloned)
2285         --signalIndex;
2286 
2287     connectionsMutex.lock();
2288     QVector<int> &connectedSignalIndexes = connections[sender];
2289     if (connectedSignalIndexes.size() <= signalIndex)
2290         connectedSignalIndexes.resize(signalIndex+1);
2291     if (connectedSignalIndexes.at(signalIndex) == 0) {
2292         if (!signalEventGenerator)
2293             signalEventGenerator = new QSignalEventGenerator(q);
2294         static const int generatorMethodOffset = QSignalEventGenerator::staticMetaObject.methodOffset();
2295         bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator, generatorMethodOffset);
2296         if (!ok) {
2297 #ifdef QSTATEMACHINE_DEBUG
2298             qDebug() << q << ": FAILED to add signal transition from" << transition->sourceState()
2299                      << ": ( sender =" << sender << ", signal =" << signal
2300                      << ", targets =" << transition->targetStates() << ')';
2301 #endif
2302             return;
2303         }
2304     }
2305     ++connectedSignalIndexes[signalIndex];
2306     connectionsMutex.unlock();
2307 
2308     QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex;
2309     QSignalTransitionPrivate::get(transition)->originalSignalIndex = originalSignalIndex;
2310 #ifdef QSTATEMACHINE_DEBUG
2311     qDebug() << q << ": added signal transition from" << transition->sourceState()
2312              << ": ( sender =" << sender << ", signal =" << signal
2313              << ", targets =" << transition->targetStates() << ')';
2314 #endif
2315 }
2316 
unregisterSignalTransition(QSignalTransition * transition)2317 void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transition)
2318 {
2319     int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex;
2320     if (signalIndex == -1)
2321         return; // not registered
2322     const QObject *sender = QSignalTransitionPrivate::get(transition)->sender;
2323     QSignalTransitionPrivate::get(transition)->signalIndex = -1;
2324 
2325     connectionsMutex.lock();
2326     QVector<int> &connectedSignalIndexes = connections[sender];
2327     Q_ASSERT(connectedSignalIndexes.size() > signalIndex);
2328     Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0);
2329     if (--connectedSignalIndexes[signalIndex] == 0) {
2330         Q_ASSERT(signalEventGenerator != nullptr);
2331         static const int generatorMethodOffset = QSignalEventGenerator::staticMetaObject.methodOffset();
2332         QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, generatorMethodOffset);
2333         int sum = 0;
2334         for (int i = 0; i < connectedSignalIndexes.size(); ++i)
2335             sum += connectedSignalIndexes.at(i);
2336         if (sum == 0)
2337             connections.remove(sender);
2338     }
2339     connectionsMutex.unlock();
2340 }
2341 
unregisterAllTransitions()2342 void QStateMachinePrivate::unregisterAllTransitions()
2343 {
2344     Q_Q(QStateMachine);
2345     {
2346         QList<QSignalTransition*> transitions = rootState()->findChildren<QSignalTransition*>();
2347         for (int i = 0; i < transitions.size(); ++i) {
2348             QSignalTransition *t = transitions.at(i);
2349             if (t->machine() == q)
2350                 unregisterSignalTransition(t);
2351         }
2352     }
2353 #if QT_CONFIG(qeventtransition)
2354     {
2355         QList<QEventTransition*> transitions = rootState()->findChildren<QEventTransition*>();
2356         for (int i = 0; i < transitions.size(); ++i) {
2357             QEventTransition *t = transitions.at(i);
2358             if (t->machine() == q)
2359                 unregisterEventTransition(t);
2360         }
2361     }
2362 #endif
2363 }
2364 
2365 #if QT_CONFIG(qeventtransition)
maybeRegisterEventTransition(QEventTransition * transition)2366 void QStateMachinePrivate::maybeRegisterEventTransition(QEventTransition *transition)
2367 {
2368     if ((state == Running) && configuration.contains(transition->sourceState()))
2369         registerEventTransition(transition);
2370 }
2371 
registerEventTransition(QEventTransition * transition)2372 void QStateMachinePrivate::registerEventTransition(QEventTransition *transition)
2373 {
2374     Q_Q(QStateMachine);
2375     if (QEventTransitionPrivate::get(transition)->registered)
2376         return;
2377     if (transition->eventType() >= QEvent::User) {
2378         qWarning("QObject event transitions are not supported for custom types");
2379         return;
2380     }
2381     QObject *object = QEventTransitionPrivate::get(transition)->object;
2382     if (!object)
2383         return;
2384     QObjectPrivate *od = QObjectPrivate::get(object);
2385     if (!od->extraData || !od->extraData->eventFilters.contains(q))
2386         object->installEventFilter(q);
2387     ++qobjectEvents[object][transition->eventType()];
2388     QEventTransitionPrivate::get(transition)->registered = true;
2389 #ifdef QSTATEMACHINE_DEBUG
2390     qDebug() << q << ": added event transition from" << transition->sourceState()
2391              << ": ( object =" << object << ", event =" << transition->eventType()
2392              << ", targets =" << transition->targetStates() << ')';
2393 #endif
2394 }
2395 
unregisterEventTransition(QEventTransition * transition)2396 void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transition)
2397 {
2398     Q_Q(QStateMachine);
2399     if (!QEventTransitionPrivate::get(transition)->registered)
2400         return;
2401     QObject *object = QEventTransitionPrivate::get(transition)->object;
2402     QHash<QEvent::Type, int> &events = qobjectEvents[object];
2403     Q_ASSERT(events.value(transition->eventType()) > 0);
2404     if (--events[transition->eventType()] == 0) {
2405         events.remove(transition->eventType());
2406         int sum = 0;
2407         QHash<QEvent::Type, int>::const_iterator it;
2408         for (it = events.constBegin(); it != events.constEnd(); ++it)
2409             sum += it.value();
2410         if (sum == 0) {
2411             qobjectEvents.remove(object);
2412             object->removeEventFilter(q);
2413         }
2414     }
2415     QEventTransitionPrivate::get(transition)->registered = false;
2416 }
2417 
handleFilteredEvent(QObject * watched,QEvent * event)2418 void QStateMachinePrivate::handleFilteredEvent(QObject *watched, QEvent *event)
2419 {
2420     if (qobjectEvents.value(watched).contains(event->type())) {
2421         postInternalEvent(new QStateMachine::WrappedEvent(watched, handler->cloneEvent(event)));
2422         processEvents(DirectProcessing);
2423     }
2424 }
2425 #endif
2426 
handleTransitionSignal(QObject * sender,int signalIndex,void ** argv)2427 void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalIndex,
2428                                                   void **argv)
2429 {
2430 #ifndef QT_NO_DEBUG
2431     connectionsMutex.lock();
2432     Q_ASSERT(connections[sender].at(signalIndex) != 0);
2433     connectionsMutex.unlock();
2434 #endif
2435     const QMetaObject *meta = sender->metaObject();
2436     QMetaMethod method = meta->method(signalIndex);
2437     int argc = method.parameterCount();
2438     QList<QVariant> vargs;
2439     vargs.reserve(argc);
2440     for (int i = 0; i < argc; ++i) {
2441         int type = method.parameterType(i);
2442         vargs.append(QVariant(type, argv[i+1]));
2443     }
2444 
2445 #ifdef QSTATEMACHINE_DEBUG
2446     qDebug() << q_func() << ": sending signal event ( sender =" << sender
2447              << ", signal =" << method.methodSignature().constData() << ')';
2448 #endif
2449     postInternalEvent(new QStateMachine::SignalEvent(sender, signalIndex, vargs));
2450     processEvents(DirectProcessing);
2451 }
2452 
2453 /*!
2454   Constructs a new state machine with the given \a parent.
2455 */
QStateMachine(QObject * parent)2456 QStateMachine::QStateMachine(QObject *parent)
2457     : QState(*new QStateMachinePrivate, /*parentState=*/nullptr)
2458 {
2459     // Can't pass the parent to the QState constructor, as it expects a QState
2460     // But this works as expected regardless of whether parent is a QState or not
2461     setParent(parent);
2462 }
2463 
2464 /*!
2465   \since 5.0
2466   \deprecated
2467 
2468   Constructs a new state machine with the given \a childMode
2469   and \a parent.
2470 
2471   \warning Do not set the \a childMode to anything else than \l{ExclusiveStates}, otherwise the
2472            state machine is invalid, and might work incorrectly.
2473 */
QStateMachine(QState::ChildMode childMode,QObject * parent)2474 QStateMachine::QStateMachine(QState::ChildMode childMode, QObject *parent)
2475     : QState(*new QStateMachinePrivate, /*parentState=*/nullptr)
2476 {
2477     Q_D(QStateMachine);
2478     d->childMode = childMode;
2479     setParent(parent); // See comment in constructor above
2480 
2481     if (childMode != ExclusiveStates) {
2482         //### FIXME for Qt6: remove this constructor completely, and hide the childMode property.
2483         // Yes, the StateMachine itself is conceptually a state, but it should only expose a limited
2484         // number of properties. The execution algorithm (in the URL below) treats a state machine
2485         // as a state, but from an API point of view, it's questionable if the QStateMachine should
2486         // inherit from QState.
2487         //
2488         // See function findLCCA in https://www.w3.org/TR/2014/WD-scxml-20140529/#AlgorithmforSCXMLInterpretation
2489         // to see where setting childMode to parallel will break down.
2490         qWarning() << "Invalid childMode for QStateMachine" << this;
2491     }
2492 }
2493 
2494 /*!
2495   \internal
2496 */
QStateMachine(QStateMachinePrivate & dd,QObject * parent)2497 QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent)
2498     : QState(dd, /*parentState=*/nullptr)
2499 {
2500     setParent(parent);
2501 }
2502 
2503 /*!
2504   Destroys this state machine.
2505 */
~QStateMachine()2506 QStateMachine::~QStateMachine()
2507 {
2508 }
2509 
2510 /*!
2511   \enum QStateMachine::EventPriority
2512 
2513   This enum type specifies the priority of an event posted to the state
2514   machine using postEvent().
2515 
2516   Events of high priority are processed before events of normal priority.
2517 
2518   \value NormalPriority The event has normal priority.
2519   \value HighPriority The event has high priority.
2520 */
2521 
2522 /*! \enum QStateMachine::Error
2523 
2524     This enum type defines errors that can occur in the state machine at run time. When the state
2525     machine encounters an unrecoverable error at run time, it will set the error code returned
2526     by error(), the error message returned by errorString(), and enter an error state based on
2527     the context of the error.
2528 
2529     \value NoError No error has occurred.
2530     \value NoInitialStateError The machine has entered a QState with children which does not have an
2531            initial state set. The context of this error is the state which is missing an initial
2532            state.
2533     \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have
2534            a default state set. The context of this error is the QHistoryState which is missing a
2535            default state.
2536     \value NoCommonAncestorForTransitionError The machine has selected a transition whose source
2537            and targets are not part of the same tree of states, and thus are not part of the same
2538            state machine. Commonly, this could mean that one of the states has not been given
2539            any parent or added to any machine. The context of this error is the source state of
2540            the transition.
2541     \value StateMachineChildModeSetToParallelError The machine's \l childMode
2542            property was set to \l{QState::ParallelStates}. This is illegal.
2543            Only states may be declared as parallel, not the state machine
2544            itself. This enum value was added in Qt 5.14.
2545 
2546     \sa setErrorState()
2547 */
2548 
2549 /*!
2550   Returns the error code of the last error that occurred in the state machine.
2551 */
error() const2552 QStateMachine::Error QStateMachine::error() const
2553 {
2554     Q_D(const QStateMachine);
2555     return d->error;
2556 }
2557 
2558 /*!
2559   Returns the error string of the last error that occurred in the state machine.
2560 */
errorString() const2561 QString QStateMachine::errorString() const
2562 {
2563     Q_D(const QStateMachine);
2564     return d->errorString;
2565 }
2566 
2567 /*!
2568   Clears the error string and error code of the state machine.
2569 */
clearError()2570 void QStateMachine::clearError()
2571 {
2572     Q_D(QStateMachine);
2573     d->errorString.clear();
2574     d->error = NoError;
2575 }
2576 
2577 /*!
2578    Returns the restore policy of the state machine.
2579 
2580    \sa setGlobalRestorePolicy()
2581 */
globalRestorePolicy() const2582 QState::RestorePolicy QStateMachine::globalRestorePolicy() const
2583 {
2584     Q_D(const QStateMachine);
2585     return d->globalRestorePolicy;
2586 }
2587 
2588 /*!
2589    Sets the restore policy of the state machine to \a restorePolicy. The default
2590    restore policy is QState::DontRestoreProperties.
2591 
2592    \sa globalRestorePolicy()
2593 */
setGlobalRestorePolicy(QState::RestorePolicy restorePolicy)2594 void QStateMachine::setGlobalRestorePolicy(QState::RestorePolicy restorePolicy)
2595 {
2596     Q_D(QStateMachine);
2597     d->globalRestorePolicy = restorePolicy;
2598 }
2599 
2600 /*!
2601   Adds the given \a state to this state machine. The state becomes a top-level
2602   state and the state machine takes ownership of the state.
2603 
2604   If the state is already in a different machine, it will first be removed
2605   from its old machine, and then added to this machine.
2606 
2607   \sa removeState(), setInitialState()
2608 */
addState(QAbstractState * state)2609 void QStateMachine::addState(QAbstractState *state)
2610 {
2611     if (!state) {
2612         qWarning("QStateMachine::addState: cannot add null state");
2613         return;
2614     }
2615     if (QAbstractStatePrivate::get(state)->machine() == this) {
2616         qWarning("QStateMachine::addState: state has already been added to this machine");
2617         return;
2618     }
2619     state->setParent(this);
2620 }
2621 
2622 /*!
2623   Removes the given \a state from this state machine.  The state machine
2624   releases ownership of the state.
2625 
2626   \sa addState()
2627 */
removeState(QAbstractState * state)2628 void QStateMachine::removeState(QAbstractState *state)
2629 {
2630     if (!state) {
2631         qWarning("QStateMachine::removeState: cannot remove null state");
2632         return;
2633     }
2634     if (QAbstractStatePrivate::get(state)->machine() != this) {
2635         qWarning("QStateMachine::removeState: state %p's machine (%p)"
2636                  " is different from this machine (%p)",
2637                  state, QAbstractStatePrivate::get(state)->machine(), this);
2638         return;
2639     }
2640     state->setParent(nullptr);
2641 }
2642 
isRunning() const2643 bool QStateMachine::isRunning() const
2644 {
2645     Q_D(const QStateMachine);
2646     return (d->state == QStateMachinePrivate::Running);
2647 }
2648 
2649 /*!
2650   Starts this state machine.  The machine will reset its configuration and
2651   transition to the initial state.  When a final top-level state (QFinalState)
2652   is entered, the machine will emit the finished() signal.
2653 
2654   \note A state machine will not run without a running event loop, such as
2655   the main application event loop started with QCoreApplication::exec() or
2656   QApplication::exec().
2657 
2658   \sa started(), finished(), stop(), initialState(), setRunning()
2659 */
start()2660 void QStateMachine::start()
2661 {
2662     Q_D(QStateMachine);
2663 
2664     if ((childMode() == QState::ExclusiveStates) && (initialState() == nullptr)) {
2665         qWarning("QStateMachine::start: No initial state set for machine. Refusing to start.");
2666         return;
2667     }
2668 
2669     switch (d->state) {
2670     case QStateMachinePrivate::NotRunning:
2671         d->state = QStateMachinePrivate::Starting;
2672         QMetaObject::invokeMethod(this, "_q_start", Qt::QueuedConnection);
2673         break;
2674     case QStateMachinePrivate::Starting:
2675         break;
2676     case QStateMachinePrivate::Running:
2677         qWarning("QStateMachine::start(): already running");
2678         break;
2679     }
2680 }
2681 
2682 /*!
2683   Stops this state machine. The state machine will stop processing events and
2684   then emit the stopped() signal.
2685 
2686   \sa stopped(), start(), setRunning()
2687 */
stop()2688 void QStateMachine::stop()
2689 {
2690     Q_D(QStateMachine);
2691     switch (d->state) {
2692     case QStateMachinePrivate::NotRunning:
2693         break;
2694     case QStateMachinePrivate::Starting:
2695         // the machine will exit as soon as it enters the event processing loop
2696         d->stop = true;
2697         break;
2698     case QStateMachinePrivate::Running:
2699         d->stop = true;
2700         d->processEvents(QStateMachinePrivate::QueuedProcessing);
2701         break;
2702     }
2703 }
2704 
setRunning(bool running)2705 void QStateMachine::setRunning(bool running)
2706 {
2707     if (running)
2708         start();
2709     else
2710         stop();
2711 }
2712 
2713 /*!
2714   \threadsafe
2715 
2716   Posts the given \a event of the given \a priority for processing by this
2717   state machine.
2718 
2719   This function returns immediately. The event is added to the state machine's
2720   event queue. Events are processed in the order posted. The state machine
2721   takes ownership of the event and deletes it once it has been processed.
2722 
2723   You can only post events when the state machine is running or when it is starting up.
2724 
2725   \sa postDelayedEvent()
2726 */
postEvent(QEvent * event,EventPriority priority)2727 void QStateMachine::postEvent(QEvent *event, EventPriority priority)
2728 {
2729     Q_D(QStateMachine);
2730     switch (d->state) {
2731     case QStateMachinePrivate::Running:
2732     case QStateMachinePrivate::Starting:
2733         break;
2734     default:
2735         qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running");
2736         return;
2737     }
2738     if (!event) {
2739         qWarning("QStateMachine::postEvent: cannot post null event");
2740         return;
2741     }
2742 #ifdef QSTATEMACHINE_DEBUG
2743     qDebug() << this << ": posting event" << event;
2744 #endif
2745     switch (priority) {
2746     case NormalPriority:
2747         d->postExternalEvent(event);
2748         break;
2749     case HighPriority:
2750         d->postInternalEvent(event);
2751         break;
2752     }
2753     d->processEvents(QStateMachinePrivate::QueuedProcessing);
2754 }
2755 
2756 /*!
2757   \threadsafe
2758 
2759   Posts the given \a event for processing by this state machine, with the
2760   given \a delay in milliseconds. Returns an identifier associated with the
2761   delayed event, or -1 if the event could not be posted.
2762 
2763   This function returns immediately. When the delay has expired, the event
2764   will be added to the state machine's event queue for processing. The state
2765   machine takes ownership of the event and deletes it once it has been
2766   processed.
2767 
2768   You can only post events when the state machine is running.
2769 
2770   \sa cancelDelayedEvent(), postEvent()
2771 */
postDelayedEvent(QEvent * event,int delay)2772 int QStateMachine::postDelayedEvent(QEvent *event, int delay)
2773 {
2774     Q_D(QStateMachine);
2775     if (d->state != QStateMachinePrivate::Running) {
2776         qWarning("QStateMachine::postDelayedEvent: cannot post event when the state machine is not running");
2777         return -1;
2778     }
2779     if (!event) {
2780         qWarning("QStateMachine::postDelayedEvent: cannot post null event");
2781         return -1;
2782     }
2783     if (delay < 0) {
2784         qWarning("QStateMachine::postDelayedEvent: delay cannot be negative");
2785         return -1;
2786     }
2787 #ifdef QSTATEMACHINE_DEBUG
2788     qDebug() << this << ": posting event" << event << "with delay" << delay;
2789 #endif
2790     QMutexLocker locker(&d->delayedEventsMutex);
2791     int id = d->delayedEventIdFreeList.next();
2792     bool inMachineThread = (QThread::currentThread() == thread());
2793     int timerId = inMachineThread ? startTimer(delay) : 0;
2794     if (inMachineThread && !timerId) {
2795         qWarning("QStateMachine::postDelayedEvent: failed to start timer with interval %d", delay);
2796         d->delayedEventIdFreeList.release(id);
2797         return -1;
2798     }
2799     QStateMachinePrivate::DelayedEvent delayedEvent(event, timerId);
2800     d->delayedEvents.insert(id, delayedEvent);
2801     if (timerId) {
2802         d->timerIdToDelayedEventId.insert(timerId, id);
2803     } else {
2804         Q_ASSERT(!inMachineThread);
2805         QMetaObject::invokeMethod(this, "_q_startDelayedEventTimer",
2806                                   Qt::QueuedConnection,
2807                                   Q_ARG(int, id),
2808                                   Q_ARG(int, delay));
2809     }
2810     return id;
2811 }
2812 
2813 /*!
2814   \threadsafe
2815 
2816   Cancels the delayed event identified by the given \a id. The id should be a
2817   value returned by a call to postDelayedEvent(). Returns \c true if the event
2818   was successfully cancelled, otherwise returns \c false.
2819 
2820   \sa postDelayedEvent()
2821 */
cancelDelayedEvent(int id)2822 bool QStateMachine::cancelDelayedEvent(int id)
2823 {
2824     Q_D(QStateMachine);
2825     if (d->state != QStateMachinePrivate::Running) {
2826         qWarning("QStateMachine::cancelDelayedEvent: the machine is not running");
2827         return false;
2828     }
2829     QMutexLocker locker(&d->delayedEventsMutex);
2830     QStateMachinePrivate::DelayedEvent e = d->delayedEvents.take(id);
2831     if (!e.event)
2832         return false;
2833     if (e.timerId) {
2834         d->timerIdToDelayedEventId.remove(e.timerId);
2835         bool inMachineThread = (QThread::currentThread() == thread());
2836         if (inMachineThread) {
2837             killTimer(e.timerId);
2838             d->delayedEventIdFreeList.release(id);
2839         } else {
2840             QMetaObject::invokeMethod(this, "_q_killDelayedEventTimer",
2841                                       Qt::QueuedConnection,
2842                                       Q_ARG(int, id),
2843                                       Q_ARG(int, e.timerId));
2844         }
2845     } else {
2846         // Cancellation will be detected in pending _q_startDelayedEventTimer() call
2847     }
2848     delete e.event;
2849     return true;
2850 }
2851 
2852 /*!
2853    Returns the maximal consistent set of states (including parallel and final
2854    states) that this state machine is currently in. If a state \c s is in the
2855    configuration, it is always the case that the parent of \c s is also in
2856    c. Note, however, that the machine itself is not an explicit member of the
2857    configuration.
2858 */
configuration() const2859 QSet<QAbstractState*> QStateMachine::configuration() const
2860 {
2861     Q_D(const QStateMachine);
2862     return d->configuration;
2863 }
2864 
2865 /*!
2866   \fn QStateMachine::started()
2867 
2868   This signal is emitted when the state machine has entered its initial state
2869   (QStateMachine::initialState).
2870 
2871   \sa QStateMachine::finished(), QStateMachine::start()
2872 */
2873 
2874 /*!
2875   \fn QStateMachine::stopped()
2876 
2877   This signal is emitted when the state machine has stopped.
2878 
2879   \sa QStateMachine::stop(), QStateMachine::finished()
2880 */
2881 
2882 /*!
2883   \reimp
2884 */
event(QEvent * e)2885 bool QStateMachine::event(QEvent *e)
2886 {
2887     Q_D(QStateMachine);
2888     if (e->type() == QEvent::Timer) {
2889         QTimerEvent *te = static_cast<QTimerEvent*>(e);
2890         int tid = te->timerId();
2891         if (d->state != QStateMachinePrivate::Running) {
2892             // This event has been cancelled already
2893             QMutexLocker locker(&d->delayedEventsMutex);
2894             Q_ASSERT(!d->timerIdToDelayedEventId.contains(tid));
2895             return true;
2896         }
2897         d->delayedEventsMutex.lock();
2898         int id = d->timerIdToDelayedEventId.take(tid);
2899         QStateMachinePrivate::DelayedEvent ee = d->delayedEvents.take(id);
2900         if (ee.event != nullptr) {
2901             Q_ASSERT(ee.timerId == tid);
2902             killTimer(tid);
2903             d->delayedEventIdFreeList.release(id);
2904             d->delayedEventsMutex.unlock();
2905             d->postExternalEvent(ee.event);
2906             d->processEvents(QStateMachinePrivate::DirectProcessing);
2907             return true;
2908         } else {
2909             d->delayedEventsMutex.unlock();
2910         }
2911     }
2912     return QState::event(e);
2913 }
2914 
2915 #if QT_CONFIG(qeventtransition)
2916 /*!
2917   \reimp
2918 */
eventFilter(QObject * watched,QEvent * event)2919 bool QStateMachine::eventFilter(QObject *watched, QEvent *event)
2920 {
2921     Q_D(QStateMachine);
2922     d->handleFilteredEvent(watched, event);
2923     return false;
2924 }
2925 #endif
2926 
2927 /*!
2928   \internal
2929 
2930   This function is called when the state machine is about to select
2931   transitions based on the given \a event.
2932 
2933   The default implementation does nothing.
2934 */
beginSelectTransitions(QEvent * event)2935 void QStateMachine::beginSelectTransitions(QEvent *event)
2936 {
2937     Q_UNUSED(event);
2938 }
2939 
2940 /*!
2941   \internal
2942 
2943   This function is called when the state machine has finished selecting
2944   transitions based on the given \a event.
2945 
2946   The default implementation does nothing.
2947 */
endSelectTransitions(QEvent * event)2948 void QStateMachine::endSelectTransitions(QEvent *event)
2949 {
2950     Q_UNUSED(event);
2951 }
2952 
2953 /*!
2954   \internal
2955 
2956   This function is called when the state machine is about to do a microstep.
2957 
2958   The default implementation does nothing.
2959 */
beginMicrostep(QEvent * event)2960 void QStateMachine::beginMicrostep(QEvent *event)
2961 {
2962     Q_UNUSED(event);
2963 }
2964 
2965 /*!
2966   \internal
2967 
2968   This function is called when the state machine has finished doing a
2969   microstep.
2970 
2971   The default implementation does nothing.
2972 */
endMicrostep(QEvent * event)2973 void QStateMachine::endMicrostep(QEvent *event)
2974 {
2975     Q_UNUSED(event);
2976 }
2977 
2978 /*!
2979   \reimp
2980     This function will call start() to start the state machine.
2981 */
onEntry(QEvent * event)2982 void QStateMachine::onEntry(QEvent *event)
2983 {
2984     start();
2985     QState::onEntry(event);
2986 }
2987 
2988 /*!
2989   \reimp
2990     This function will call stop() to stop the state machine and
2991     subsequently emit the stopped() signal.
2992 */
onExit(QEvent * event)2993 void QStateMachine::onExit(QEvent *event)
2994 {
2995     stop();
2996     QState::onExit(event);
2997 }
2998 
2999 #if QT_CONFIG(animation)
3000 
3001 /*!
3002   Returns whether animations are enabled for this state machine.
3003 */
isAnimated() const3004 bool QStateMachine::isAnimated() const
3005 {
3006     Q_D(const QStateMachine);
3007     return d->animated;
3008 }
3009 
3010 /*!
3011   Sets whether animations are \a enabled for this state machine.
3012 */
setAnimated(bool enabled)3013 void QStateMachine::setAnimated(bool enabled)
3014 {
3015     Q_D(QStateMachine);
3016     d->animated = enabled;
3017 }
3018 
3019 /*!
3020     Adds a default \a animation to be considered for any transition.
3021 */
addDefaultAnimation(QAbstractAnimation * animation)3022 void QStateMachine::addDefaultAnimation(QAbstractAnimation *animation)
3023 {
3024     Q_D(QStateMachine);
3025     d->defaultAnimations.append(animation);
3026 }
3027 
3028 /*!
3029     Returns the list of default animations that will be considered for any transition.
3030 */
defaultAnimations() const3031 QList<QAbstractAnimation*> QStateMachine::defaultAnimations() const
3032 {
3033     Q_D(const QStateMachine);
3034     return d->defaultAnimations;
3035 }
3036 
3037 /*!
3038     Removes \a animation from the list of default animations.
3039 */
removeDefaultAnimation(QAbstractAnimation * animation)3040 void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation)
3041 {
3042     Q_D(QStateMachine);
3043     d->defaultAnimations.removeAll(animation);
3044 }
3045 
3046 #endif // animation
3047 
3048 
3049 // Begin moc-generated code -- modify carefully (check "HAND EDIT" parts)!
3050 struct qt_meta_stringdata_QSignalEventGenerator_t {
3051     QByteArrayData data[3];
3052     char stringdata[32];
3053 };
3054 #define QT_MOC_LITERAL(idx, ofs, len) \
3055     Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
3056         offsetof(qt_meta_stringdata_QSignalEventGenerator_t, stringdata) + ofs \
3057         - idx * sizeof(QByteArrayData) \
3058     )
3059 static const qt_meta_stringdata_QSignalEventGenerator_t qt_meta_stringdata_QSignalEventGenerator = {
3060     {
3061 QT_MOC_LITERAL(0, 0, 21),
3062 QT_MOC_LITERAL(1, 22, 7),
3063 QT_MOC_LITERAL(2, 30, 0)
3064     },
3065     "QSignalEventGenerator\0execute\0\0"
3066 };
3067 #undef QT_MOC_LITERAL
3068 
3069 static const uint qt_meta_data_QSignalEventGenerator[] = {
3070 
3071  // content:
3072        7,       // revision
3073        0,       // classname
3074        0,    0, // classinfo
3075        1,   14, // methods
3076        0,    0, // properties
3077        0,    0, // enums/sets
3078        0,    0, // constructors
3079        0,       // flags
3080        0,       // signalCount
3081 
3082  // slots: name, argc, parameters, tag, flags
3083        1,    0,   19,    2, 0x0a,
3084 
3085  // slots: parameters
3086     QMetaType::Void,
3087 
3088        0        // eod
3089 };
3090 
qt_static_metacall(QObject * _o,QMetaObject::Call _c,int _id,void ** _a)3091 void QSignalEventGenerator::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
3092 {
3093     if (_c == QMetaObject::InvokeMetaMethod) {
3094         Q_ASSERT(staticMetaObject.cast(_o));
3095         QSignalEventGenerator *_t = static_cast<QSignalEventGenerator *>(_o);
3096         switch (_id) {
3097         case 0: _t->execute(_a); break; // HAND EDIT: add the _a parameter
3098         default: ;
3099         }
3100     }
3101     Q_UNUSED(_a);
3102 }
3103 
3104 const QMetaObject QSignalEventGenerator::staticMetaObject = {
3105     { &QObject::staticMetaObject, qt_meta_stringdata_QSignalEventGenerator.data,
3106       qt_meta_data_QSignalEventGenerator, qt_static_metacall, nullptr, nullptr }
3107 };
3108 
metaObject() const3109 const QMetaObject *QSignalEventGenerator::metaObject() const
3110 {
3111     return &staticMetaObject;
3112 }
3113 
qt_metacast(const char * _clname)3114 void *QSignalEventGenerator::qt_metacast(const char *_clname)
3115 {
3116     if (!_clname) return nullptr;
3117     if (!strcmp(_clname, qt_meta_stringdata_QSignalEventGenerator.stringdata))
3118         return static_cast<void*>(const_cast< QSignalEventGenerator*>(this));
3119     return QObject::qt_metacast(_clname);
3120 }
3121 
qt_metacall(QMetaObject::Call _c,int _id,void ** _a)3122 int QSignalEventGenerator::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
3123 {
3124     _id = QObject::qt_metacall(_c, _id, _a);
3125     if (_id < 0)
3126         return _id;
3127     if (_c == QMetaObject::InvokeMetaMethod) {
3128         if (_id < 1)
3129             qt_static_metacall(this, _c, _id, _a);
3130         _id -= 1;
3131     }
3132     return _id;
3133 }
3134 // End moc-generated code
3135 
execute(void ** _a)3136 void QSignalEventGenerator::execute(void **_a)
3137 {
3138     auto machinePrivate = QStateMachinePrivate::get(qobject_cast<QStateMachine*>(parent()));
3139     if (machinePrivate->state != QStateMachinePrivate::Running)
3140         return;
3141     int signalIndex = senderSignalIndex();
3142     Q_ASSERT(signalIndex != -1);
3143     machinePrivate->handleTransitionSignal(sender(), signalIndex, _a);
3144 }
3145 
QSignalEventGenerator(QStateMachine * parent)3146 QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent)
3147     : QObject(parent)
3148 {
3149 }
3150 
3151 /*!
3152   \class QStateMachine::SignalEvent
3153   \inmodule QtCore
3154 
3155   \brief The SignalEvent class represents a Qt signal event.
3156 
3157   \since 4.6
3158   \ingroup statemachine
3159 
3160   A signal event is generated by a QStateMachine in response to a Qt
3161   signal. The QSignalTransition class provides a transition associated with a
3162   signal event. QStateMachine::SignalEvent is part of \l{The State Machine Framework}.
3163 
3164   The sender() function returns the object that generated the signal. The
3165   signalIndex() function returns the index of the signal. The arguments()
3166   function returns the arguments of the signal.
3167 
3168   \sa QSignalTransition
3169 */
3170 
3171 /*!
3172   \internal
3173 
3174   Constructs a new SignalEvent object with the given \a sender, \a
3175   signalIndex and \a arguments.
3176 */
SignalEvent(QObject * sender,int signalIndex,const QList<QVariant> & arguments)3177 QStateMachine::SignalEvent::SignalEvent(QObject *sender, int signalIndex,
3178                                         const QList<QVariant> &arguments)
3179     : QEvent(QEvent::StateMachineSignal), m_sender(sender),
3180       m_signalIndex(signalIndex), m_arguments(arguments)
3181 {
3182 }
3183 
3184 /*!
3185   Destroys this SignalEvent.
3186 */
~SignalEvent()3187 QStateMachine::SignalEvent::~SignalEvent()
3188 {
3189 }
3190 
3191 /*!
3192   \fn QStateMachine::SignalEvent::sender() const
3193 
3194   Returns the object that emitted the signal.
3195 
3196   \sa QObject::sender()
3197 */
3198 
3199 /*!
3200   \fn QStateMachine::SignalEvent::signalIndex() const
3201 
3202   Returns the index of the signal.
3203 
3204   \sa QMetaObject::indexOfSignal(), QMetaObject::method()
3205 */
3206 
3207 /*!
3208   \fn QStateMachine::SignalEvent::arguments() const
3209 
3210   Returns the arguments of the signal.
3211 */
3212 
3213 
3214 /*!
3215   \class QStateMachine::WrappedEvent
3216   \inmodule QtCore
3217 
3218   \brief The WrappedEvent class inherits QEvent and holds a clone of an event associated with a QObject.
3219 
3220   \since 4.6
3221   \ingroup statemachine
3222 
3223   A wrapped event is generated by a QStateMachine in response to a Qt
3224   event. The QEventTransition class provides a transition associated with a
3225   such an event. QStateMachine::WrappedEvent is part of \l{The State Machine
3226   Framework}.
3227 
3228   The object() function returns the object that generated the event. The
3229   event() function returns a clone of the original event.
3230 
3231   \sa QEventTransition
3232 */
3233 
3234 /*!
3235   \internal
3236 
3237   Constructs a new WrappedEvent object with the given \a object
3238   and \a event.
3239 
3240   The WrappedEvent object takes ownership of \a event.
3241 */
WrappedEvent(QObject * object,QEvent * event)3242 QStateMachine::WrappedEvent::WrappedEvent(QObject *object, QEvent *event)
3243     : QEvent(QEvent::StateMachineWrapped), m_object(object), m_event(event)
3244 {
3245 }
3246 
3247 /*!
3248   Destroys this WrappedEvent.
3249 */
~WrappedEvent()3250 QStateMachine::WrappedEvent::~WrappedEvent()
3251 {
3252     delete m_event;
3253 }
3254 
3255 /*!
3256   \fn QStateMachine::WrappedEvent::object() const
3257 
3258   Returns the object that the event is associated with.
3259 */
3260 
3261 /*!
3262   \fn QStateMachine::WrappedEvent::event() const
3263 
3264   Returns a clone of the original event.
3265 */
3266 
3267 /*!
3268   \fn QStateMachine::runningChanged(bool running)
3269   \since 5.4
3270 
3271   This signal is emitted when the running property is changed with \a running as argument.
3272 
3273   \sa QStateMachine::running
3274 */
3275 
3276 /*!
3277   \fn QStateMachine::postDelayedEvent(QEvent *event, std::chrono::milliseconds delay)
3278   \since 5.15
3279   \overload
3280   \threadsafe
3281 
3282   Posts the given \a event for processing by this state machine, with the
3283   given \a delay in milliseconds. Returns an identifier associated with the
3284   delayed event, or -1 if the event could not be posted.
3285 
3286   This function returns immediately. When the delay has expired, the event
3287   will be added to the state machine's event queue for processing. The state
3288   machine takes ownership of the event and deletes it once it has been
3289   processed.
3290 
3291   You can only post events when the state machine is running.
3292 
3293   \sa cancelDelayedEvent(), postEvent()
3294 */
3295 
3296 QT_END_NAMESPACE
3297 
3298 #include "qstatemachine.moc"
3299 #include "moc_qstatemachine.cpp"
3300