summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2012-07-12 03:12:06 +0200
committerQt by Nokia <qt-info@nokia.com>2012-07-12 20:38:02 +0200
commitc4cef6fae9f2a55f21fc9517855dfcf659c89081 (patch)
tree6013a60155c3f949d9db4661c9bdcfff5cb4b20b /src
parentb76014b8ef3862b4168148cb20e1108d9c0df5f6 (diff)
statemachine: Fix state entry bug for parallel state groups
The SCXML spec had a bug that would cause the initial state of a compound state within a parallel state group to be entered even if the transition specified another (non-initial) state of the compound state as its target. This only happened if the transition had multiple target states. The bug has been fixed in recent revisions of the SCXML spec. This commit implements the fix, which is to walk the ancestors of the transition's target states only after all the target states themselves have been added, so that the default initial states are correctly overridden/ignored. Task-number: QTBUG-25958 Change-Id: Iac532047678c483a4a3996e24dacf30e00f6bbe0 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp57
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h3
2 files changed, 37 insertions, 23 deletions
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index ccc40ac9b4..5adb6c3fb1 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -518,6 +518,10 @@ QList<QAbstractState*> QStateMachinePrivate::computeStatesToEnter(const QList<QA
QAbstractState *s = lst.at(j);
addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
}
+ for (int j = src ? 1 : 0; j < lst.size(); ++j) {
+ QAbstractState *s = lst.at(j);
+ addAncestorStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
+ }
if (isParallel(lca)) {
QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates();
foreach (QAbstractState* child,lcac) {
@@ -715,32 +719,38 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
return;
}
}
- QList<QState*> ancs = properAncestors(s, root);
- for (int i = 0; i < ancs.size(); ++i) {
- QState *anc = ancs.at(i);
- if (!anc->parentState())
- continue;
- statesToEnter.insert(anc);
- if (isParallel(anc)) {
- QList<QAbstractState*> lst = QStatePrivate::get(anc)->childStates();
- for (int j = 0; j < lst.size(); ++j) {
- QAbstractState *child = lst.at(j);
- bool hasDescendantInList = false;
- QSet<QAbstractState*>::const_iterator it;
- for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) {
- if (isDescendantOf(*it, child)) {
- hasDescendantInList = true;
- break;
- }
- }
- if (!hasDescendantInList)
- addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry);
- }
- }
- }
}
}
+void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QState *root,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry)
+{
+ QList<QState*> ancs = properAncestors(s, root);
+ for (int i = 0; i < ancs.size(); ++i) {
+ QState *anc = ancs.at(i);
+ if (!anc->parentState())
+ continue;
+ statesToEnter.insert(anc);
+ if (isParallel(anc)) {
+ QList<QAbstractState*> lst = QStatePrivate::get(anc)->childStates();
+ for (int j = 0; j < lst.size(); ++j) {
+ QAbstractState *child = lst.at(j);
+ bool hasDescendantInList = false;
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) {
+ if (isDescendantOf(*it, child)) {
+ hasDescendantInList = true;
+ break;
+ }
+ }
+ if (!hasDescendantInList)
+ addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+}
+
bool QStateMachinePrivate::isFinal(const QAbstractState *s)
{
return s && (QAbstractStatePrivate::get(s)->stateType == QAbstractStatePrivate::FinalState);
@@ -1077,6 +1087,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
if (currentErrorState != 0) {
QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ addAncestorStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
} else {
qWarning("Unrecoverable error detected in running state machine: %s",
qPrintable(errorString));
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index 423c077a83..113f17f973 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -150,6 +150,9 @@ public:
void addStatesToEnter(QAbstractState *s, QState *root,
QSet<QAbstractState*> &statesToEnter,
QSet<QAbstractState*> &statesForDefaultEntry);
+ void addAncestorStatesToEnter(QAbstractState *s, QState *root,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry);
static QState *toStandardState(QAbstractState *state);
static const QState *toStandardState(const QAbstractState *state);