summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/statemachine/qabstractstate_p.h3
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp11
-rw-r--r--src/corelib/statemachine/qhistorystate.cpp65
-rw-r--r--src/corelib/statemachine/qhistorystate.h6
-rw-r--r--src/corelib/statemachine/qhistorystate_p.h22
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp25
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);