statemachine: Support parallel root state

QStateMachine inherits from QState, so it should be possible to set
its childMode to ParallelStates, and it should behave as expected
(the machine should emit the finished() signal when all its child
states are in final states).

Task-number: QTBUG-22931
Change-Id: Ic436351be0be69e3b01ae9984561132cd9839fa7
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
This commit is contained in:
Kent Hansen 2012-07-07 06:07:11 +02:00 committed by Qt by Nokia
parent 28e9a602cb
commit d281aa6936
2 changed files with 36 additions and 15 deletions

View File

@ -639,10 +639,17 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState
{
QSet<QAbstractState*>::const_iterator it;
for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
if (isFinal(*it) && (*it)->parentState() == rootState()) {
processing = false;
stopProcessingReason = Finished;
break;
if (isFinal(*it)) {
QState *parent = (*it)->parentState();
if (((parent == rootState())
&& (rootState()->childMode() == QState::ExclusiveStates))
|| ((parent->parentState() == rootState())
&& (rootState()->childMode() == QState::ParallelStates)
&& isInFinalState(rootState()))) {
processing = false;
stopProcessingReason = Finished;
break;
}
}
}
}
@ -754,8 +761,7 @@ bool QStateMachinePrivate::isCompound(const QAbstractState *s) const
// Don't treat the machine as compound if it's a sub-state of this machine
if (isMachine && (group != rootState()))
return false;
return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty())
|| isMachine;
return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty());
}
bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const
@ -1286,16 +1292,26 @@ QAbstractTransition *QStateMachinePrivate::createInitialTransition() const
class InitialTransition : public QAbstractTransition
{
public:
InitialTransition(QAbstractState *target)
InitialTransition(const QList<QAbstractState *> &targets)
: QAbstractTransition()
{ setTargetState(target); }
{ setTargetStates(targets); }
protected:
virtual bool eventTest(QEvent *) { return true; }
virtual void onTransition(QEvent *) {}
};
Q_ASSERT(rootState() != 0);
return new InitialTransition(rootState()->initialState());
QState *root = rootState();
Q_ASSERT(root != 0);
QList<QAbstractState *> targets;
switch (root->childMode()) {
case QState::ExclusiveStates:
targets.append(root->initialState());
break;
case QState::ParallelStates:
targets = QStatePrivate::get(root)->childStates();
break;
}
return new InitialTransition(targets);
}
void QStateMachinePrivate::clearHistory()
@ -2039,7 +2055,7 @@ void QStateMachine::start()
{
Q_D(QStateMachine);
if (initialState() == 0) {
if ((childMode() == QState::ExclusiveStates) && (initialState() == 0)) {
qWarning("QStateMachine::start: No initial state set for machine. Refusing to start.");
return;
}

View File

@ -1912,11 +1912,16 @@ void tst_QStateMachine::parallelRootState()
QSignalSpy startedSpy(&machine, SIGNAL(started()));
QVERIFY(startedSpy.isValid());
QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start.");
QSignalSpy finishedSpy(&machine, SIGNAL(finished()));
QVERIFY(finishedSpy.isValid());
machine.start();
QCoreApplication::processEvents();
QEXPECT_FAIL("", "parallel root state is not supported (QTBUG-22931)", Continue);
QCOMPARE(startedSpy.count(), 1);
QTRY_COMPARE(startedSpy.count(), 1);
QCOMPARE(machine.configuration().size(), 4);
QVERIFY(machine.configuration().contains(s1));
QVERIFY(machine.configuration().contains(s1_f));
QVERIFY(machine.configuration().contains(s2));
QVERIFY(machine.configuration().contains(s2_f));
QTRY_COMPARE(finishedSpy.count(), 1);
}
void tst_QStateMachine::allSourceToTargetConfigurations()