summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp37
-rw-r--r--tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp64
2 files changed, 96 insertions, 5 deletions
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 7e9d99a416..25c9343943 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -299,6 +299,17 @@ static bool containsDecendantOf(const QSet<QAbstractState *> &states, const QAbs
return false;
}
+static int descendantDepth(const QAbstractState *state, const QAbstractState *ancestor)
+{
+ int depth = 0;
+ for (const QAbstractState *it = state; it != 0; it = it->parentState()) {
+ if (it == ancestor)
+ break;
+ ++depth;
+ }
+ return depth;
+}
+
/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
function getProperAncestors(state1, state2)
@@ -451,10 +462,25 @@ static int indexOfDescendant(QState *s, QAbstractState *desc)
bool QStateMachinePrivate::transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2)
{
QState *s1 = t1->sourceState(), *s2 = t2->sourceState();
- if (s1 == s2)
- return QStatePrivate::get(s1)->transitions().indexOf(t1) < QStatePrivate::get(s2)->transitions().indexOf(t2);
- else
- return stateEntryLessThan(t1->sourceState(), t2->sourceState());
+ if (s1 == s2) {
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(s1)->transitions();
+ return transitions.indexOf(t1) < transitions.indexOf(t2);
+ } else if (isDescendant(s1, s2)) {
+ return true;
+ } else if (isDescendant(s2, s1)) {
+ return false;
+ } else {
+ Q_ASSERT(s1->machine() != 0);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != 0);
+ int s1Depth = descendantDepth(s1, lca);
+ int s2Depth = descendantDepth(s2, lca);
+ if (s1Depth == s2Depth)
+ return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
+ else
+ return s1Depth > s2Depth;
+ }
}
bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2)
@@ -594,7 +620,7 @@ void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransitio
{
Q_ASSERT(cache);
- if (enabledTransitions.size() == 1)
+ if (enabledTransitions.size() < 2)
return; // There is no transition to conflict with.
QList<QAbstractTransition*> filteredTransitions;
@@ -2081,6 +2107,7 @@ void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guil
Q_ASSERT(guiltyState);
#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
qDebug() << q << ": emitting finished signal for" << forState;
#endif
diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp
index 6ddfb828e8..3718b07b33 100644
--- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp
+++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp
@@ -248,6 +248,7 @@ private slots:
void qtbug_44963();
void qtbug_44783();
void internalTransition();
+ void conflictingTransition();
};
class TestState : public QState
@@ -6382,5 +6383,68 @@ void tst_QStateMachine::internalTransition()
TEST_ACTIVE_CHANGED(s, 1);
}
+void tst_QStateMachine::conflictingTransition()
+{
+ SignalEmitter emitter;
+
+ QStateMachine machine;
+ QState b(QState::ParallelStates, &machine);
+ QState c(&b);
+ QState d(QState::ParallelStates, &b);
+ QState e(&d);
+ QState e1(&e);
+ QState e2(&e);
+ QState f(&d);
+ QState f1(&f);
+ QState f2(&f);
+ QState a1(&machine);
+
+ machine.setInitialState(&b);
+ e.setInitialState(&e1);
+ f.setInitialState(&f1);
+ c.addTransition(&emitter, SIGNAL(signalWithNoArg()), &a1)->setObjectName("c->a1");
+ e1.addTransition(&emitter, SIGNAL(signalWithNoArg()), &e2)->setObjectName("e1->e2");
+ f1.addTransition(&emitter, SIGNAL(signalWithNoArg()), &f2)->setObjectName("f1->f2");
+
+ b.setObjectName("b");
+ c.setObjectName("c");
+ d.setObjectName("d");
+ e.setObjectName("e");
+ e1.setObjectName("e1");
+ e2.setObjectName("e2");
+ f.setObjectName("f");
+ f1.setObjectName("f1");
+ f2.setObjectName("f2");
+ a1.setObjectName("a1");
+
+ machine.start();
+
+ QTRY_COMPARE(machine.configuration().contains(&b), true);
+ QTRY_COMPARE(machine.configuration().contains(&c), true);
+ QTRY_COMPARE(machine.configuration().contains(&d), true);
+ QTRY_COMPARE(machine.configuration().contains(&e), true);
+ QTRY_COMPARE(machine.configuration().contains(&e1), true);
+ QTRY_COMPARE(machine.configuration().contains(&e2), false);
+ QTRY_COMPARE(machine.configuration().contains(&f), true);
+ QTRY_COMPARE(machine.configuration().contains(&f1), true);
+ QTRY_COMPARE(machine.configuration().contains(&f2), false);
+ QTRY_COMPARE(machine.configuration().contains(&a1), false);
+
+ emitter.emitSignalWithNoArg();
+
+ QTRY_COMPARE(machine.configuration().contains(&b), true);
+ QTRY_COMPARE(machine.configuration().contains(&c), true);
+ QTRY_COMPARE(machine.configuration().contains(&d), true);
+ QTRY_COMPARE(machine.configuration().contains(&e), true);
+ QTRY_COMPARE(machine.configuration().contains(&e1), false);
+ QTRY_COMPARE(machine.configuration().contains(&e2), true);
+ QTRY_COMPARE(machine.configuration().contains(&f), true);
+ QTRY_COMPARE(machine.configuration().contains(&f1), false);
+ QTRY_COMPARE(machine.configuration().contains(&f2), true);
+ QTRY_COMPARE(machine.configuration().contains(&a1), false);
+
+ QVERIFY(machine.isRunning());
+}
+
QTEST_MAIN(tst_QStateMachine)
#include "tst_qstatemachine.moc"