QStateMachine: add internal transitions.
The behavior of "external" and "internal" transitions is identical, except in the case of a transition whose source state is a compound state and whose target(s) is a descendant of the source. In such a case, an internal transition will not exit and re-enter its source state, while an external one will. [ChangeLog][State machine] Added support for internal transitions. Change-Id: I9efb1e7368ee52aa2544eb84709a00ae3d5350d3 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
This commit is contained in:
parent
bd15b23987
commit
c07f5b801b
@ -101,7 +101,35 @@ QT_BEGIN_NAMESPACE
|
||||
parallel group state.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\property QAbstractTransition::transitionType
|
||||
|
||||
\brief indicates whether this transition is an internal transition, or an external transition.
|
||||
|
||||
Internal and external transitions behave the same, except for the case of a transition whose
|
||||
source state is a compound state and whose target(s) is a descendant of the source. In such a
|
||||
case, an internal transition will not exit and re-enter its source state, while an external one
|
||||
will.
|
||||
|
||||
By default, the type is an external transition.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QAbstractTransition::TransitionType
|
||||
|
||||
This enum specifies the kind of transition. By default, the type is an external transition.
|
||||
|
||||
\value ExternalTransition Any state that is the source state of a transition (which is not a
|
||||
target-less transition) is left, and re-entered when necessary.
|
||||
\value InternalTransition If the target state of a transition is a sub-state of a compound state,
|
||||
and that compound state is the source state, an internal transition will
|
||||
not leave the source state.
|
||||
|
||||
\sa QAbstractTransition::transitionType
|
||||
*/
|
||||
|
||||
QAbstractTransitionPrivate::QAbstractTransitionPrivate()
|
||||
: transitionType(QAbstractTransition::ExternalTransition)
|
||||
{
|
||||
}
|
||||
|
||||
@ -248,6 +276,24 @@ void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
|
||||
emit targetStatesChanged(QPrivateSignal());
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the type of the transition.
|
||||
*/
|
||||
QAbstractTransition::TransitionType QAbstractTransition::transitionType() const
|
||||
{
|
||||
Q_D(const QAbstractTransition);
|
||||
return d->transitionType;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the type of the transition to \a type.
|
||||
*/
|
||||
void QAbstractTransition::setTransitionType(TransitionType type)
|
||||
{
|
||||
Q_D(QAbstractTransition);
|
||||
d->transitionType = type;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the state machine that this transition is part of, or 0 if the
|
||||
transition is not part of a state machine.
|
||||
|
@ -59,7 +59,14 @@ class Q_CORE_EXPORT QAbstractTransition : public QObject
|
||||
Q_PROPERTY(QState* sourceState READ sourceState)
|
||||
Q_PROPERTY(QAbstractState* targetState READ targetState WRITE setTargetState NOTIFY targetStateChanged)
|
||||
Q_PROPERTY(QList<QAbstractState*> targetStates READ targetStates WRITE setTargetStates NOTIFY targetStatesChanged)
|
||||
Q_PROPERTY(TransitionType transitionType READ transitionType WRITE setTransitionType)
|
||||
public:
|
||||
enum TransitionType {
|
||||
ExternalTransition,
|
||||
InternalTransition
|
||||
};
|
||||
Q_ENUM(TransitionType)
|
||||
|
||||
QAbstractTransition(QState *sourceState = 0);
|
||||
virtual ~QAbstractTransition();
|
||||
|
||||
@ -69,6 +76,9 @@ public:
|
||||
QList<QAbstractState*> targetStates() const;
|
||||
void setTargetStates(const QList<QAbstractState*> &targets);
|
||||
|
||||
TransitionType transitionType() const;
|
||||
void setTransitionType(TransitionType type);
|
||||
|
||||
QStateMachine *machine() const;
|
||||
|
||||
#ifndef QT_NO_ANIMATION
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
void emitTriggered();
|
||||
|
||||
QList<QPointer<QAbstractState> > targetStates;
|
||||
QAbstractTransition::TransitionType transitionType;
|
||||
|
||||
#ifndef QT_NO_ANIMATION
|
||||
QList<QAbstractAnimation*> animations;
|
||||
|
@ -889,23 +889,22 @@ QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t
|
||||
if (cache->transitionDomain(t, &domain))
|
||||
return domain;
|
||||
|
||||
#if 0
|
||||
// Qt only has external transitions, so skip the special case for the internal transitions
|
||||
if (QState *tSource = t->sourceState()) {
|
||||
if (isCompound(tSource)) {
|
||||
bool allDescendants = true;
|
||||
foreach (QAbstractState *s, effectiveTargetStates) {
|
||||
if (!isDescendant(s, tSource)) {
|
||||
allDescendants = false;
|
||||
break;
|
||||
if (t->transitionType() == QAbstractTransition::InternalTransition) {
|
||||
if (QState *tSource = t->sourceState()) {
|
||||
if (isCompound(tSource)) {
|
||||
bool allDescendants = true;
|
||||
foreach (QAbstractState *s, effectiveTargetStates) {
|
||||
if (!isDescendant(s, tSource)) {
|
||||
allDescendants = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allDescendants)
|
||||
return tSource;
|
||||
if (allDescendants)
|
||||
return tSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QList<QAbstractState *> states(effectiveTargetStates);
|
||||
if (QAbstractState *src = t->sourceState())
|
||||
|
@ -247,6 +247,7 @@ private slots:
|
||||
|
||||
void qtbug_44963();
|
||||
void qtbug_44783();
|
||||
void internalTransition();
|
||||
};
|
||||
|
||||
class TestState : public QState
|
||||
@ -6338,5 +6339,48 @@ void tst_QStateMachine::qtbug_44783()
|
||||
QVERIFY(machine.isRunning());
|
||||
}
|
||||
|
||||
void tst_QStateMachine::internalTransition()
|
||||
{
|
||||
SignalEmitter emitter;
|
||||
|
||||
QStateMachine machine;
|
||||
QState *s = new QState(&machine);
|
||||
QState *s1 = new QState(s);
|
||||
QState *s11 = new QState(s1);
|
||||
|
||||
DEFINE_ACTIVE_SPY(s);
|
||||
DEFINE_ACTIVE_SPY(s1);
|
||||
DEFINE_ACTIVE_SPY(s11);
|
||||
|
||||
machine.setInitialState(s);
|
||||
s->setInitialState(s1);
|
||||
s1->setInitialState(s11);
|
||||
QSignalTransition *t = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s11);
|
||||
t->setObjectName("s1->s11");
|
||||
t->setTransitionType(QAbstractTransition::InternalTransition);
|
||||
|
||||
s->setObjectName("s");
|
||||
s1->setObjectName("s1");
|
||||
s11->setObjectName("s11");
|
||||
|
||||
machine.start();
|
||||
|
||||
QTRY_COMPARE(machine.configuration().contains(s), true);
|
||||
QTRY_COMPARE(machine.configuration().contains(s1), true);
|
||||
QTRY_COMPARE(machine.configuration().contains(s11), true);
|
||||
TEST_ACTIVE_CHANGED(s, 1);
|
||||
TEST_ACTIVE_CHANGED(s1, 1);
|
||||
TEST_ACTIVE_CHANGED(s11, 1);
|
||||
|
||||
emitter.emitSignalWithNoArg();
|
||||
|
||||
QTRY_COMPARE(machine.configuration().contains(s), true);
|
||||
QTRY_COMPARE(machine.configuration().contains(s1), true);
|
||||
QTRY_COMPARE(machine.configuration().contains(s11), true);
|
||||
TEST_ACTIVE_CHANGED(s11, 3);
|
||||
TEST_ACTIVE_CHANGED(s1, 1); // external transitions will return 3, internal transitions should return 1.
|
||||
TEST_ACTIVE_CHANGED(s, 1);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QStateMachine)
|
||||
#include "tst_qstatemachine.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user