diff options
Diffstat (limited to 'src/corelib/statemachine/qstatemachine.cpp')
-rw-r--r-- | src/corelib/statemachine/qstatemachine.cpp | 104 |
1 files changed, 95 insertions, 9 deletions
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index a02480b..9cb1d4d 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -205,6 +205,7 @@ This is QStateMachinePrivate::QStateMachinePrivate() { state = NotRunning; + _startState = 0; processing = false; processingScheduled = false; stop = false; @@ -1138,7 +1139,8 @@ class InitialTransition : public QAbstractTransition { public: InitialTransition(QAbstractState *target) - : QAbstractTransition(QList<QAbstractState*>() << target) {} + : QAbstractTransition() + { setTargetState(target); } protected: virtual bool eventTest(QEvent *) { return true; } virtual void onTransition(QEvent *) {} @@ -1146,6 +1148,20 @@ protected: } // namespace +QState *QStateMachinePrivate::startState() +{ + Q_Q(QStateMachine); + if (_startState == 0) + _startState = new StartState(q); + return _startState; +} + +void QStateMachinePrivate::removeStartState() +{ + delete _startState; + _startState = 0; +} + void QStateMachinePrivate::_q_start() { Q_Q(QStateMachine); @@ -1165,11 +1181,19 @@ void QStateMachinePrivate::_q_start() processingScheduled = true; // we call _q_process() below emit q->started(); - StartState *start = new StartState(rootState()); - QAbstractTransition *initialTransition = new InitialTransition(initial); - start->addTransition(initialTransition); - QList<QAbstractTransition*> transitions; - transitions.append(initialTransition); + QState *start = startState(); + Q_ASSERT(start != 0); + + QList<QAbstractTransition*> transitions = QStatePrivate::get(start)->transitions(); + + // If a transition has already been added, then we skip this step, as the + // initial transition in that case has been overridden. + if (transitions.isEmpty()) { + QAbstractTransition *initialTransition = new InitialTransition(initial); + start->addTransition(initialTransition); + transitions.append(initialTransition); + } + QEvent nullEvent(QEvent::None); executeTransitionContent(&nullEvent, transitions); QList<QAbstractState*> enteredStates = enterStates(&nullEvent, transitions); @@ -1177,7 +1201,7 @@ void QStateMachinePrivate::_q_start() applyProperties(transitions, QList<QAbstractState*>() << start, enteredStates); #endif - delete start; + removeStartState(); #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": initial configuration:" << configuration; @@ -1277,6 +1301,68 @@ void QStateMachinePrivate::scheduleProcess() QMetaObject::invokeMethod(q_func(), "_q_process", Qt::QueuedConnection); } +namespace { + +class GoToStateTransition : public QAbstractTransition +{ +public: + GoToStateTransition(QAbstractState *target) + : QAbstractTransition() + { setTargetState(target); } +protected: + void onTransition(QEvent *) { deleteLater(); } + bool eventTest(QEvent *) { return true; } +}; + +} // namespace + +/*! + \internal + + Causes this state machine to unconditionally transition to the given + \a targetState. + + Provides a backdoor for using the state machine "imperatively"; i.e. rather + than defining explicit transitions, you drive the machine's execution by + calling this function. It breaks the whole integrity of the + transition-driven model, but is provided for pragmatic reasons. +*/ +void QStateMachinePrivate::goToState(QAbstractState *targetState) +{ + if (!targetState) { + qWarning("QStateMachine::goToState(): cannot go to null state"); + return; + } + + if (configuration.contains(targetState)) + return; + + QState *sourceState = 0; + if (state == Running) { + QSet<QAbstractState*>::const_iterator it; + for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { + sourceState = qobject_cast<QState*>(*it); + if (sourceState != 0) + break; + } + } else { + sourceState = startState(); + } + + Q_ASSERT(sourceState != 0); + // Reuse previous GoToStateTransition in case of several calls to + // goToState() in a row. + GoToStateTransition *trans = qFindChild<GoToStateTransition*>(sourceState); + if (!trans) { + trans = new GoToStateTransition(targetState); + sourceState->addTransition(trans); + } else { + trans->setTargetState(targetState); + } + + scheduleProcess(); +} + void QStateMachinePrivate::registerTransitions(QAbstractState *state) { QState *group = qobject_cast<QState*>(state); @@ -1446,7 +1532,7 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio } #endif -void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int signalIndex, +void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalIndex, void **argv) { Q_ASSERT(connections[sender].at(signalIndex) != 0); @@ -2026,7 +2112,7 @@ QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent) Constructs a new QSignalEvent object with the given \a sender, \a signalIndex and \a arguments. */ -QSignalEvent::QSignalEvent(const QObject *sender, int signalIndex, +QSignalEvent::QSignalEvent(QObject *sender, int signalIndex, const QList<QVariant> &arguments) : QEvent(QEvent::Signal), m_sender(sender), m_signalIndex(signalIndex), m_arguments(arguments) |