From 5fd9fe02ff14438a2d0c93789be138a58583dbe8 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 18 Jun 2015 16:45:32 +0200 Subject: QStateMachine: add defaultTransition in QHistoryState The history state had the limitation that it was hard (or impossible) to use when more than one default state had to be entered. For example, using it in a parallel state was impossible without ending up in an infinite loop. This patch changes the QHistoryState to only have an initial transition, and the state selection algorithm is changed accordingly. It also brings QStateMachine closer to the SCXML standard. The existing defaultState is implemented on top of the defaultTransition: when used, a new transition, with the default state as its target, is set as the defaultTransition. Task-number: QTBUG-46703 Change-Id: Ifbb44e4f0f26b72e365af4c94753e4483f9850e7 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/statemachine/qstatemachine.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'src/corelib/statemachine/qstatemachine.cpp') diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 335610dac6..237b19bc0e 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -365,9 +365,9 @@ static QList getEffectiveTargetStates(QAbstractTransition *tra if (!historyConfiguration.isEmpty()) { // There is a saved history, so apply that. targets.unite(historyConfiguration.toSet()); - } else if (QAbstractState *defaultState = historyState->defaultState()) { - // Qt does not support initial transitions, but uses the default state of the history state for this. - targets.insert(defaultState); + } else if (QAbstractTransition *defaultTransition = historyState->defaultTransition()) { + // No saved history, take all default transition targets. + targets.unite(defaultTransition->targetStates().toSet()); } else { // Woops, we found a history state without a default state. That's not valid! QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine()); @@ -978,9 +978,16 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QListcallOnEntry(event); QAbstractStatePrivate::get(s)->emitEntered(); - if (statesForDefaultEntry.contains(s)) { - // ### executeContent(s.initial.transition.children()) - } + + // FIXME: + // See the "initial transitions" comment in addDescendantStatesToEnter first, then implement: +// if (statesForDefaultEntry.contains(s)) { +// // ### executeContent(s.initial.transition.children()) +// } + Q_UNUSED(statesForDefaultEntry); + + if (QHistoryState *h = toHistoryState(s)) + QAbstractTransitionPrivate::get(h->defaultTransition())->callOnTransition(event); // Emit propertiesAssigned signal if the state has no animated properties. { @@ -1091,8 +1098,8 @@ void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state, #endif } else { QList defaultHistoryContent; - if (QHistoryStatePrivate::get(h)->defaultState) - defaultHistoryContent.append(QHistoryStatePrivate::get(h)->defaultState); + if (QAbstractTransition *t = QHistoryStatePrivate::get(h)->defaultTransition) + defaultHistoryContent = t->targetStates(); if (defaultHistoryContent.isEmpty()) { setError(QStateMachine::NoDefaultStateInHistoryStateError, h); @@ -1118,8 +1125,10 @@ void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state, if (QAbstractState *initial = toStandardState(state)->initialState()) { Q_ASSERT(initial->machine() == q_func()); + // FIXME: // Qt does not support initial transitions (which is a problem for parallel states). // The way it simulates this for other states, is by having a single initial state. + // See also the FIXME in enterStates. statesForDefaultEntry.insert(initial); addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry); -- cgit v1.2.3