diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/statemachine/qabstractstate_p.h | 3 | ||||
-rw-r--r-- | src/corelib/statemachine/qabstracttransition.cpp | 11 | ||||
-rw-r--r-- | src/corelib/statemachine/qhistorystate.cpp | 65 | ||||
-rw-r--r-- | src/corelib/statemachine/qhistorystate.h | 6 | ||||
-rw-r--r-- | src/corelib/statemachine/qhistorystate_p.h | 22 | ||||
-rw-r--r-- | src/corelib/statemachine/qstatemachine.cpp | 25 |
6 files changed, 111 insertions, 21 deletions
diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h index 660371b80c..1eb3cbd420 100644 --- a/src/corelib/statemachine/qabstractstate_p.h +++ b/src/corelib/statemachine/qabstractstate_p.h @@ -46,12 +46,13 @@ // #include <private/qobject_p.h> +#include <QtCore/qabstractstate.h> QT_BEGIN_NAMESPACE class QStateMachine; -class QAbstractState; +class QState; class QAbstractStatePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QAbstractState) diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 92a5d373fe..5a7a95883b 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -37,6 +37,7 @@ #include "qabstracttransition_p.h" #include "qabstractstate.h" +#include "qhistorystate.h" #include "qstate.h" #include "qstatemachine.h" @@ -135,10 +136,12 @@ QAbstractTransitionPrivate::QAbstractTransitionPrivate() QStateMachine *QAbstractTransitionPrivate::machine() const { - QState *source = sourceState(); - if (!source) - return 0; - return source->machine(); + if (QState *source = sourceState()) + return source->machine(); + Q_Q(const QAbstractTransition); + if (QHistoryState *parent = qobject_cast<QHistoryState *>(q->parent())) + return parent->machine(); + return 0; } bool QAbstractTransitionPrivate::callEventTest(QEvent *e) diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index b6384a159a..a0ebb9d239 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE A history state is a pseudo-state that represents the child state that the parent state was in the last time the parent state was exited. A transition - with a history state as its target is in fact a transition to one of the + with a history state as its target is in fact a transition to one or more other child states of the parent state. QHistoryState is part of \l{The State Machine Framework}. @@ -79,11 +79,22 @@ QT_BEGIN_NAMESPACE s1->addTransition(button, SIGNAL(clicked()), s1h); \endcode + If more than one default state has to be entered, or if the transition to the default state(s) + has to be acted upon, the defaultTransition should be set instead. Note that the eventTest() + method of that transition will never be called: the selection and execution of the transition is + done automatically when entering the history state. + By default a history state is shallow, meaning that it won't remember nested states. This can be configured through the historyType property. */ /*! + \property QHistoryState::defaultTransition + + \brief the default transition of this history state +*/ + +/*! \property QHistoryState::defaultState \brief the default state of this history state @@ -113,11 +124,19 @@ QT_BEGIN_NAMESPACE */ QHistoryStatePrivate::QHistoryStatePrivate() - : QAbstractStatePrivate(HistoryState), - defaultState(0), historyType(QHistoryState::ShallowHistory) + : QAbstractStatePrivate(HistoryState) + , defaultTransition(0) + , historyType(QHistoryState::ShallowHistory) { } +DefaultStateTransition::DefaultStateTransition(QHistoryState *source, QAbstractState *target) + : QAbstractTransition() +{ + setParent(source); + setTargetState(target); +} + /*! Constructs a new shallow history state with the given \a parent state. */ @@ -144,13 +163,40 @@ QHistoryState::~QHistoryState() } /*! + Returns this history state's default transition. The default transition is + taken when the history state has never been entered before. The target states + of the default transition therefore make up the default state. +*/ +QAbstractTransition *QHistoryState::defaultTransition() const +{ + Q_D(const QHistoryState); + return d->defaultTransition; +} + +/*! + Sets this history state's default transition to be the given \a transition. + This will set the source state of the \a transition to the history state. + + Note that the eventTest method of the \a transition will never be called. +*/ +void QHistoryState::setDefaultTransition(QAbstractTransition *transition) +{ + Q_D(QHistoryState); + if (d->defaultTransition != transition) { + d->defaultTransition = transition; + transition->setParent(this); + emit defaultTransitionChanged(QHistoryState::QPrivateSignal()); + } +} + +/*! Returns this history state's default state. The default state indicates the state to transition to if the parent state has never been entered before. */ QAbstractState *QHistoryState::defaultState() const { Q_D(const QHistoryState); - return d->defaultState; + return d->defaultTransition ? d->defaultTransition->targetState() : Q_NULLPTR; } /*! @@ -168,8 +214,15 @@ void QHistoryState::setDefaultState(QAbstractState *state) "to this history state's group (%p)", state, parentState()); return; } - if (d->defaultState != state) { - d->defaultState = state; + if (!d->defaultTransition + || d->defaultTransition->targetStates().size() != 1 + || d->defaultTransition->targetStates().first() != state) { + if (!d->defaultTransition || !qobject_cast<DefaultStateTransition*>(d->defaultTransition)) { + d->defaultTransition = new DefaultStateTransition(this, state); + emit defaultTransitionChanged(QHistoryState::QPrivateSignal()); + } else { + d->defaultTransition->setTargetState(state); + } emit defaultStateChanged(QHistoryState::QPrivateSignal()); } } diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h index 97ac376688..2f2081bf9c 100644 --- a/src/corelib/statemachine/qhistorystate.h +++ b/src/corelib/statemachine/qhistorystate.h @@ -41,11 +41,13 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_STATEMACHINE +class QAbstractTransition; class QHistoryStatePrivate; class Q_CORE_EXPORT QHistoryState : public QAbstractState { Q_OBJECT Q_PROPERTY(QAbstractState* defaultState READ defaultState WRITE setDefaultState NOTIFY defaultStateChanged) + Q_PROPERTY(QAbstractTransition* defaultTransition READ defaultTransition WRITE setDefaultTransition NOTIFY defaultTransitionChanged) Q_PROPERTY(HistoryType historyType READ historyType WRITE setHistoryType NOTIFY historyTypeChanged) public: enum HistoryType { @@ -58,6 +60,9 @@ public: QHistoryState(HistoryType type, QState *parent = Q_NULLPTR); ~QHistoryState(); + QAbstractTransition *defaultTransition() const; + void setDefaultTransition(QAbstractTransition *transition); + QAbstractState *defaultState() const; void setDefaultState(QAbstractState *state); @@ -65,6 +70,7 @@ public: void setHistoryType(HistoryType type); Q_SIGNALS: + void defaultTransitionChanged(QPrivateSignal); void defaultStateChanged(QPrivateSignal); void historyTypeChanged(QPrivateSignal); diff --git a/src/corelib/statemachine/qhistorystate_p.h b/src/corelib/statemachine/qhistorystate_p.h index 57149e3f86..b0865f7f46 100644 --- a/src/corelib/statemachine/qhistorystate_p.h +++ b/src/corelib/statemachine/qhistorystate_p.h @@ -47,11 +47,12 @@ #include "private/qabstractstate_p.h" +#include <QtCore/qabstracttransition.h> +#include <QtCore/qhistorystate.h> #include <QtCore/qlist.h> QT_BEGIN_NAMESPACE -class QHistoryState; class QHistoryStatePrivate : public QAbstractStatePrivate { Q_DECLARE_PUBLIC(QHistoryState) @@ -62,11 +63,28 @@ public: static QHistoryStatePrivate *get(QHistoryState *q) { return q->d_func(); } - QAbstractState *defaultState; + QAbstractTransition *defaultTransition; QHistoryState::HistoryType historyType; QList<QAbstractState*> configuration; }; +class DefaultStateTransition: public QAbstractTransition +{ + Q_OBJECT + +public: + DefaultStateTransition(QHistoryState *source, QAbstractState *target); + +protected: + // It doesn't matter whether this transition matches any event or not. It is always associated + // with a QHistoryState, and as soon as the state-machine detects that it enters a history + // state, it will handle this transition as a special case. The history state itself is never + // entered either: either the stored configuration will be used, or the target(s) of this + // transition are used. + virtual bool eventTest(QEvent *event) { Q_UNUSED(event); return false; } + virtual void onTransition(QEvent *event) { Q_UNUSED(event); } +}; + QT_END_NAMESPACE #endif diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 335610dac6..237b19bc0e 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -365,9 +365,9 @@ static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *tra if (!historyConfiguration.isEmpty()) { // There is a saved history, so apply that. targets.unite(historyConfiguration.toSet()); - } else if (QAbstractState *defaultState = historyState->defaultState()) { - // Qt does not support initial transitions, but uses the default state of the history state for this. - targets.insert(defaultState); + } else if (QAbstractTransition *defaultTransition = historyState->defaultTransition()) { + // No saved history, take all default transition targets. + targets.unite(defaultTransition->targetStates().toSet()); } else { // Woops, we found a history state without a default state. That's not valid! QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine()); @@ -978,9 +978,16 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState QAbstractStatePrivate::get(s)->callOnEntry(event); QAbstractStatePrivate::get(s)->emitEntered(); - if (statesForDefaultEntry.contains(s)) { - // ### executeContent(s.initial.transition.children()) - } + + // FIXME: + // See the "initial transitions" comment in addDescendantStatesToEnter first, then implement: +// if (statesForDefaultEntry.contains(s)) { +// // ### executeContent(s.initial.transition.children()) +// } + Q_UNUSED(statesForDefaultEntry); + + if (QHistoryState *h = toHistoryState(s)) + QAbstractTransitionPrivate::get(h->defaultTransition())->callOnTransition(event); // Emit propertiesAssigned signal if the state has no animated properties. { @@ -1091,8 +1098,8 @@ void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state, #endif } else { QList<QAbstractState*> defaultHistoryContent; - if (QHistoryStatePrivate::get(h)->defaultState) - defaultHistoryContent.append(QHistoryStatePrivate::get(h)->defaultState); + if (QAbstractTransition *t = QHistoryStatePrivate::get(h)->defaultTransition) + defaultHistoryContent = t->targetStates(); if (defaultHistoryContent.isEmpty()) { setError(QStateMachine::NoDefaultStateInHistoryStateError, h); @@ -1118,8 +1125,10 @@ void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state, if (QAbstractState *initial = toStandardState(state)->initialState()) { Q_ASSERT(initial->machine() == q_func()); + // FIXME: // Qt does not support initial transitions (which is a problem for parallel states). // The way it simulates this for other states, is by having a single initial state. + // See also the FIXME in enterStates. statesForDefaultEntry.insert(initial); addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry); |