summaryrefslogtreecommitdiffstats
path: root/src/corelib/statemachine
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/statemachine')
-rw-r--r--src/corelib/statemachine/qsignalevent.h6
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp100
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h16
3 files changed, 108 insertions, 14 deletions
diff --git a/src/corelib/statemachine/qsignalevent.h b/src/corelib/statemachine/qsignalevent.h
index c09c5a308..b7ca61f7f 100644
--- a/src/corelib/statemachine/qsignalevent.h
+++ b/src/corelib/statemachine/qsignalevent.h
@@ -58,16 +58,16 @@ QT_MODULE(Core)
class Q_CORE_EXPORT QSignalEvent : public QEvent
{
public:
- QSignalEvent(const QObject *sender, int signalIndex,
+ QSignalEvent(QObject *sender, int signalIndex,
const QList<QVariant> &arguments);
~QSignalEvent();
- inline const QObject *sender() const { return m_sender; }
+ inline QObject *sender() const { return m_sender; }
inline int signalIndex() const { return m_signalIndex; }
inline QList<QVariant> arguments() const { return m_arguments; }
private:
- const QObject *m_sender;
+ QObject *m_sender;
int m_signalIndex;
QList<QVariant> m_arguments;
};
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index a02480bff..5aa5917c5 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;
@@ -1146,6 +1147,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 +1180,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 +1200,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 +1300,67 @@ void QStateMachinePrivate::scheduleProcess()
QMetaObject::invokeMethod(q_func(), "_q_process", Qt::QueuedConnection);
}
+namespace {
+
+class GoToStateTransition : public QAbstractTransition
+{
+public:
+ GoToStateTransition(QAbstractState *target)
+ : QAbstractTransition(QList<QAbstractState*>() << 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 +1530,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 +2110,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)
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index cae21aad2..387e42e1d 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -79,7 +79,7 @@ class QAbstractAnimation;
#endif
class QStateMachine;
-class QStateMachinePrivate : public QStatePrivate
+class Q_AUTOTEST_EXPORT QStateMachinePrivate : public QStatePrivate
{
Q_DECLARE_PUBLIC(QStateMachine)
public:
@@ -116,6 +116,9 @@ public:
QState *rootState() const;
+ QState *startState();
+ void removeStartState();
+
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
@@ -138,6 +141,8 @@ public:
static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other);
static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound);
+ void goToState(QAbstractState *targetState);
+
void registerTransitions(QAbstractState *state);
void registerSignalTransition(QSignalTransition *transition);
void unregisterSignalTransition(QSignalTransition *transition);
@@ -147,7 +152,7 @@ public:
#endif
void unregisterTransition(QAbstractTransition *transition);
void unregisterAllTransitions();
- void handleTransitionSignal(const QObject *sender, int signalIndex,
+ void handleTransitionSignal(QObject *sender, int signalIndex,
void **args);
void scheduleProcess();
@@ -162,6 +167,7 @@ public:
#endif
State state;
+ QState *_startState;
bool processing;
bool processingScheduled;
bool stop;
@@ -208,7 +214,11 @@ public:
f_cloneEvent cloneEvent;
};
- static Q_CORE_EXPORT const Handler *handler;
+ static
+#ifndef QT_BUILD_INTERNAL // otherwise Q_AUTOTEST_EXPORT exports it all
+ Q_CORE_EXPORT
+#endif
+ const Handler *handler;
};
QT_END_NAMESPACE