diff options
-rw-r--r-- | src/corelib/statemachine/qstatemachine.cpp | 37 | ||||
-rw-r--r-- | tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp | 64 |
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" |