diff options
Diffstat (limited to 'src')
30 files changed, 272 insertions, 145 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 440a37d..6a824b6 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -156,13 +156,13 @@ #include <QtCore/qcoreevent.h> #include <QtCore/qpointer.h> -#define TIMER_INTERVAL 16 +#define DEFAULT_TIMER_INTERVAL 16 QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer); -QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0) +QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), consistentTiming(false) { } @@ -189,12 +189,38 @@ void QUnifiedTimer::updateRecentlyStartedAnimations() animationsToStart.clear(); } +/* + defines the timing interval. Default is DEFAULT_TIMER_INTERVAL +*/ +void QUnifiedTimer::setTimingInterval(int interval) +{ + timingInterval = interval; + if (animationTimer.isActive()) { + //we changed the timing interval + animationTimer.start(timingInterval, this); + } +} + +/* + this allows to have a consistent timer interval at each tick from the timer + not taking the real time that passed into account. +*/ +void QUnifiedTimer::setConsitentTiming(bool b) +{ + consistentTiming = b; +} + +int QUnifiedTimer::elapsedTime() const +{ + return lastTick; +} + void QUnifiedTimer::timerEvent(QTimerEvent *event) { //this is simply the time we last received a tick - int oldLastTick = lastTick; + const int oldLastTick = lastTick; if (time.isValid()) - lastTick = time.elapsed(); + lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed(); //we transfer the waiting animations into the "really running" state updateRecentlyStartedAnimations(); @@ -205,7 +231,7 @@ void QUnifiedTimer::timerEvent(QTimerEvent *event) animationTimer.stop(); time = QTime(); } else { - animationTimer.start(TIMER_INTERVAL, this); + animationTimer.start(timingInterval, this); lastTick = 0; time.start(); } diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index 666e6a7..49c0195 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -110,7 +110,7 @@ private: }; -class QUnifiedTimer : public QObject +class Q_CORE_EXPORT QUnifiedTimer : public QObject { private: QUnifiedTimer(); @@ -118,11 +118,17 @@ private: public: static QUnifiedTimer *instance(); - void timerEvent(QTimerEvent *); - void updateTimer(); void registerAnimation(QAbstractAnimation *animation); void unregisterAnimation(QAbstractAnimation *animation); + void setTimingInterval(int interval); + void setConsitentTiming(bool consistent); + + int elapsedTime() const; + +protected: + void timerEvent(QTimerEvent *); + void updateTimer(); private: void updateRecentlyStartedAnimations(); @@ -130,6 +136,8 @@ private: QBasicTimer animationTimer, startStopAnimationTimer; QTime time; int lastTick; + int timingInterval; + bool consistentTiming; QList<QAbstractAnimation*> animations, animationsToStart; }; diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 8abdacc..96cfa6b 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -118,6 +118,8 @@ void QPropertyAnimationPrivate::updateMetaProperty() property = mo->property(propertyIndex); propertyType = property.userType(); } else { + if (!target->dynamicPropertyNames().contains(propertyName)) + qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData()); hasMetaProperty = 2; } } diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp index cc6f0f9..3f84314 100644 --- a/src/corelib/statemachine/qabstractstate.cpp +++ b/src/corelib/statemachine/qabstractstate.cpp @@ -101,16 +101,16 @@ QStateMachine *QAbstractStatePrivate::machine() const return 0; } -void QAbstractStatePrivate::callOnEntry() +void QAbstractStatePrivate::callOnEntry(QEvent *e) { Q_Q(QAbstractState); - q->onEntry(); + q->onEntry(e); } -void QAbstractStatePrivate::callOnExit() +void QAbstractStatePrivate::callOnExit(QEvent *e) { Q_Q(QAbstractState); - q->onExit(); + q->onExit(e); } void QAbstractStatePrivate::emitEntered() @@ -190,17 +190,19 @@ QStateMachine *QAbstractState::machine() const } /*! - \fn QAbstractState::onExit() + \fn QAbstractState::onExit(QEvent *event) - This function is called when the state is exited. Reimplement this function - to perform custom processing when the state is exited. + This function is called when the state is exited. The given \a event is what + caused the state to be exited. Reimplement this function to perform custom + processing when the state is exited. */ /*! - \fn QAbstractState::onEntry() + \fn QAbstractState::onEntry(QEvent *event) - This function is called when the state is entered. Reimplement this function - to perform custom processing when the state is entered. + This function is called when the state is entered. The given \a event is + what caused the state to be entered. Reimplement this function to perform + custom processing when the state is entered. */ /*! diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h index 30a68ff..f6b4b21 100644 --- a/src/corelib/statemachine/qabstractstate.h +++ b/src/corelib/statemachine/qabstractstate.h @@ -70,8 +70,8 @@ Q_SIGNALS: protected: QAbstractState(QState *parent = 0); - virtual void onEntry() = 0; - virtual void onExit() = 0; + virtual void onEntry(QEvent *event) = 0; + virtual void onExit(QEvent *event) = 0; bool event(QEvent *e); diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h index bbe12d6..6c09696 100644 --- a/src/corelib/statemachine/qabstractstate_p.h +++ b/src/corelib/statemachine/qabstractstate_p.h @@ -77,8 +77,8 @@ public: QStateMachine *machine() const; - void callOnEntry(); - void callOnExit(); + void callOnEntry(QEvent *e); + void callOnExit(QEvent *e); void emitEntered(); void emitExited(); diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 5fa1742..1897aa6 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -131,10 +131,10 @@ bool QAbstractTransitionPrivate::callEventTest(QEvent *e) const return q->eventTest(e); } -void QAbstractTransitionPrivate::callOnTransition() +void QAbstractTransitionPrivate::callOnTransition(QEvent *e) { Q_Q(QAbstractTransition); - q->onTransition(); + q->onTransition(e); } QState *QAbstractTransitionPrivate::sourceState() const @@ -353,10 +353,11 @@ QList<QAbstractAnimation*> QAbstractTransition::animations() const */ /*! - \fn QAbstractTransition::onTransition() + \fn QAbstractTransition::onTransition(QEvent *event) - This function is called when the transition is triggered. Reimplement this - function to perform custom processing when the transition is triggered. + This function is called when the transition is triggered. The given \a event + is what caused the transition to trigger. Reimplement this function to + perform custom processing when the transition is triggered. */ /*! diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h index 79ab808..e207944 100644 --- a/src/corelib/statemachine/qabstracttransition.h +++ b/src/corelib/statemachine/qabstracttransition.h @@ -90,7 +90,7 @@ public: protected: virtual bool eventTest(QEvent *event) const = 0; - virtual void onTransition() = 0; + virtual void onTransition(QEvent *event) = 0; bool event(QEvent *e); diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h index a48a09c..b4e1c88 100644 --- a/src/corelib/statemachine/qabstracttransition_p.h +++ b/src/corelib/statemachine/qabstracttransition_p.h @@ -79,7 +79,7 @@ public: static const QAbstractTransitionPrivate *get(const QAbstractTransition *q); bool callEventTest(QEvent *e) const; - void callOnTransition(); + void callOnTransition(QEvent *e); QState *sourceState() const; QStateMachine *machine() const; diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp index cbd03bd..86259e4 100644 --- a/src/corelib/statemachine/qeventtransition.cpp +++ b/src/corelib/statemachine/qeventtransition.cpp @@ -270,8 +270,9 @@ bool QEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QEventTransition::onTransition() +void QEventTransition::onTransition(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h index 484602c..a128cee 100644 --- a/src/corelib/statemachine/qeventtransition.h +++ b/src/corelib/statemachine/qeventtransition.h @@ -78,7 +78,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp index 6a1b608..0980336 100644 --- a/src/corelib/statemachine/qfinalstate.cpp +++ b/src/corelib/statemachine/qfinalstate.cpp @@ -55,9 +55,9 @@ QT_BEGIN_NAMESPACE A final state is used to communicate that (part of) a QStateMachine has finished its work. When a final top-level state is entered, the state machine's \l{QStateMachine::finished()}{finished}() signal is emitted. In - general, when a final substate (a child of a QState) is entered, a - QStateFinishedEvent is generated for the final state's parent - state. QFinalState is part of \l{The State Machine Framework}. + general, when a final substate (a child of a QState) is entered, the parent + state's \l{QState::finished()}{finished}() signal is emitted. QFinalState + is part of \l{The State Machine Framework}. To use a final state, you create a QFinalState object and add a transition to it from another state. Example: @@ -76,6 +76,8 @@ QT_BEGIN_NAMESPACE machine.setInitialState(s1); machine.start(); \endcode + + \sa QStateMachine::finished(), QState::finished() */ class QFinalStatePrivate : public QAbstractStatePrivate @@ -108,15 +110,17 @@ QFinalState::~QFinalState() /*! \reimp */ -void QFinalState::onEntry() +void QFinalState::onEntry(QEvent *event) { + Q_UNUSED(event); } /*! \reimp */ -void QFinalState::onExit() +void QFinalState::onExit(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h index 726a399..eb8aa0f 100644 --- a/src/corelib/statemachine/qfinalstate.h +++ b/src/corelib/statemachine/qfinalstate.h @@ -63,8 +63,8 @@ public: ~QFinalState(); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *event); + void onExit(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index 4e3db08..d1b2391 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -58,9 +58,8 @@ QT_BEGIN_NAMESPACE other child states of the parent state. QHistoryState is part of \l{The State Machine Framework}. - Use QState::addHistoryState() to construct a history state. Use the - setDefaultState() function to set the state that should be entered if the - parent state has never been entered. Example: + Use the setDefaultState() function to set the state that should be entered + if the parent state has never been entered. Example: \code QStateMachine machine; @@ -69,7 +68,7 @@ QT_BEGIN_NAMESPACE QState *s11 = new QState(s1); QState *s12 = new QState(s1); - QState *s1h = s1->addHistoryState(); + QHistoryState *s1h = new QHistoryState(s1); s1h->setDefaultState(s11); machine.addState(s1); @@ -83,6 +82,9 @@ QT_BEGIN_NAMESPACE // state if s1 has never been entered. s1->addTransition(button, SIGNAL(clicked()), s1h); \endcode + + By default a history state is shallow, meaning that it won't remember nested + states. This can be configured through the historyType property. */ /*! @@ -95,6 +97,8 @@ QT_BEGIN_NAMESPACE \property QHistoryState::historyType \brief the type of history that this history state records + + The default value of this property is QHistoryState::ShallowHistory. */ /*! @@ -200,15 +204,17 @@ void QHistoryState::setHistoryType(HistoryType type) /*! \reimp */ -void QHistoryState::onEntry() +void QHistoryState::onEntry(QEvent *event) { + Q_UNUSED(event); } /*! \reimp */ -void QHistoryState::onExit() +void QHistoryState::onExit(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h index c7648bc..d0f75de 100644 --- a/src/corelib/statemachine/qhistorystate.h +++ b/src/corelib/statemachine/qhistorystate.h @@ -78,8 +78,8 @@ public: void setHistoryType(HistoryType type); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *event); + void onExit(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp index e9e248f..d5833bd 100644 --- a/src/corelib/statemachine/qsignaltransition.cpp +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -245,8 +245,9 @@ bool QSignalTransition::eventTest(QEvent *event) const /*! \reimp */ -void QSignalTransition::onTransition() +void QSignalTransition::onTransition(QEvent *event) { + Q_UNUSED(event); } /*! diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h index b8e8fc6..98a9ae7 100644 --- a/src/corelib/statemachine/qsignaltransition.h +++ b/src/corelib/statemachine/qsignaltransition.h @@ -77,7 +77,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 2d59ab8..4c9e033 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -68,22 +68,30 @@ QT_BEGIN_NAMESPACE The assignProperty() function is used for defining property assignments that should be performed when a state is entered. + Top-level states must be passed QStateMachine::rootState() as their parent + state, or added to a state machine using QStateMachine::addState(). + \section1 States with Child States - For non-parallel state groups, the setInitialState() function must be called - to set the initial state. The child states are mutually exclusive states, - and the state machine needs to know which child state to enter when the - parent state is the target of a transition. + The childMode property determines how child states are treated. For + non-parallel state groups, the setInitialState() function must be called to + set the initial state. The child states are mutually exclusive states, and + the state machine needs to know which child state to enter when the parent + state is the target of a transition. + + The state emits the QState::finished() signal when a final child state + (QFinalState) is entered. The setErrorState() sets the state's error state. The error state is the state that the state machine will transition to if an error is detected when attempting to enter the state (e.g. because no initial state has been set). + */ /*! \property QState::initialState - \brief the initial state of this state + \brief the initial state of this state (one of its child states) */ /*! @@ -96,6 +104,8 @@ QT_BEGIN_NAMESPACE \property QState::childMode \brief the child mode of this state + + The default value of this property is QState::ExclusiveStates. */ /*! @@ -235,6 +245,10 @@ void QState::assignProperty(QObject *object, const char *name, const QVariant &value) { Q_D(QState); + if (!object) { + qWarning("QState::assignProperty: cannot assign property '%s' of null object", name); + return; + } for (int i = 0; i < d->propertyAssignments.size(); ++i) { QPropertyAssignment &assn = d->propertyAssignments[i]; if ((assn.object == object) && (assn.propertyName == name)) { @@ -335,7 +349,7 @@ public: UnconditionalTransition(QAbstractState *target) : QAbstractTransition(QList<QAbstractState*>() << target) {} protected: - void onTransition() {} + void onTransition(QEvent *) {} bool eventTest(QEvent *) const { return true; } }; @@ -380,15 +394,17 @@ void QState::removeTransition(QAbstractTransition *transition) /*! \reimp */ -void QState::onEntry() +void QState::onEntry(QEvent *event) { + Q_UNUSED(event); } /*! \reimp */ -void QState::onExit() +void QState::onExit(QEvent *event) { + Q_UNUSED(event); } /*! @@ -450,6 +466,8 @@ bool QState::event(QEvent *e) \fn QState::finished() This signal is emitted when a final child state of this state is entered. + + \sa QFinalState */ /*! diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h index 9faef26..73955d7 100644 --- a/src/corelib/statemachine/qstate.h +++ b/src/corelib/statemachine/qstate.h @@ -97,8 +97,8 @@ Q_SIGNALS: void polished(); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *event); + void onExit(QEvent *event); bool event(QEvent *e); diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 9060f0e..21e564c 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -163,6 +163,8 @@ QT_BEGIN_NAMESPACE \property QStateMachine::initialState \brief the initial state of this state machine + + The initial state must be one of the rootState()'s child states. */ /*! @@ -181,6 +183,9 @@ QT_BEGIN_NAMESPACE \property QStateMachine::globalRestorePolicy \brief the restore policy for states of this state machine. + + The default value of this property is + QStateMachine::DoNotRestoreProperties. */ #ifndef QT_NO_ANIMATION @@ -188,6 +193,10 @@ QT_BEGIN_NAMESPACE \property QStateMachine::animationsEnabled \brief whether animations are enabled + + The default value of this property is true. + + \sa QAbstractTransition::addAnimation() */ #endif @@ -369,18 +378,18 @@ QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event return enabledTransitions; } -void QStateMachinePrivate::microstep(const QList<QAbstractTransition*> &enabledTransitions) +void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ")"; qDebug() << q_func() << ": configuration before exiting states:" << configuration; #endif - QList<QAbstractState*> exitedStates = exitStates(enabledTransitions); + QList<QAbstractState*> exitedStates = exitStates(event, enabledTransitions); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": configuration after exiting states:" << configuration; #endif - executeTransitionContent(enabledTransitions); - QList<QAbstractState*> enteredStates = enterStates(enabledTransitions); + executeTransitionContent(event, enabledTransitions); + QList<QAbstractState*> enteredStates = enterStates(event, enabledTransitions); applyProperties(enabledTransitions, exitedStates, enteredStates); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": configuration after entering states:" << configuration; @@ -388,7 +397,7 @@ void QStateMachinePrivate::microstep(const QList<QAbstractTransition*> &enabledT #endif } -QList<QAbstractState*> QStateMachinePrivate::exitStates(const QList<QAbstractTransition*> &enabledTransitions) +QList<QAbstractState*> QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) { // qDebug() << "exitStates(" << enabledTransitions << ")"; QSet<QAbstractState*> statesToExit; @@ -400,6 +409,15 @@ QList<QAbstractState*> QStateMachinePrivate::exitStates(const QList<QAbstractTra continue; lst.prepend(t->sourceState()); QAbstractState *lca = findLCA(lst); + if (lca == 0) { + setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); + lst = pendingErrorStates.toList(); + lst.prepend(t->sourceState()); + + lca = findLCA(lst); + Q_ASSERT(lca != 0); + } + { QSet<QAbstractState*>::const_iterator it; for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { @@ -440,25 +458,25 @@ QList<QAbstractState*> QStateMachinePrivate::exitStates(const QList<QAbstractTra #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": exiting" << s; #endif - QAbstractStatePrivate::get(s)->callOnExit(); + QAbstractStatePrivate::get(s)->callOnExit(event); configuration.remove(s); QAbstractStatePrivate::get(s)->emitExited(); } return statesToExit_sorted; } -void QStateMachinePrivate::executeTransitionContent(const QList<QAbstractTransition*> &enabledTransitions) +void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) { for (int i = 0; i < enabledTransitions.size(); ++i) { QAbstractTransition *t = enabledTransitions.at(i); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": triggering" << t; #endif - QAbstractTransitionPrivate::get(t)->callOnTransition(); + QAbstractTransitionPrivate::get(t)->callOnTransition(event); } } -QList<QAbstractState*> QStateMachinePrivate::enterStates(const QList<QAbstractTransition*> &enabledTransitions) +QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions) { #ifdef QSTATEMACHINE_DEBUG Q_Q(QStateMachine); @@ -467,21 +485,23 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(const QList<QAbstractTr QSet<QAbstractState*> statesToEnter; QSet<QAbstractState*> statesForDefaultEntry; - for (int i = 0; i < enabledTransitions.size(); ++i) { - QAbstractTransition *t = enabledTransitions.at(i); - QList<QAbstractState*> lst = t->targetStates(); - if (lst.isEmpty()) - continue; - lst.prepend(t->sourceState()); - QState *lca = findLCA(lst); - for (int j = 1; j < lst.size(); ++j) { - QAbstractState *s = lst.at(j); - addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry); - if (isParallel(lca)) { - QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates(); - foreach (QAbstractState* child,lcac) { - if (!statesToEnter.contains(child)) - addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry); + if (pendingErrorStates.isEmpty()) { + for (int i = 0; i < enabledTransitions.size(); ++i) { + QAbstractTransition *t = enabledTransitions.at(i); + QList<QAbstractState*> lst = t->targetStates(); + if (lst.isEmpty()) + continue; + lst.prepend(t->sourceState()); + QState *lca = findLCA(lst); + for (int j = 1; j < lst.size(); ++j) { + QAbstractState *s = lst.at(j); + addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry); + if (isParallel(lca)) { + QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates(); + foreach (QAbstractState* child,lcac) { + if (!statesToEnter.contains(child)) + addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry); + } } } } @@ -506,7 +526,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(const QList<QAbstractTr #endif configuration.insert(s); registerTransitions(s); - QAbstractStatePrivate::get(s)->callOnEntry(); + QAbstractStatePrivate::get(s)->callOnEntry(event); QAbstractStatePrivate::get(s)->emitEntered(); if (statesForDefaultEntry.contains(s)) { // ### executeContent(s.initial.transition.children()) @@ -573,8 +593,9 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, QList<QAbstractState*> hlst; if (QHistoryStatePrivate::get(h)->defaultState) hlst.append(QHistoryStatePrivate::get(h)->defaultState); + if (hlst.isEmpty()) { - setError(QStateMachine::NoDefaultStateInHistoryState, h); + setError(QStateMachine::NoDefaultStateInHistoryStateError, h); } else { for (int k = 0; k < hlst.size(); ++k) { QAbstractState *s0 = hlst.at(k); @@ -656,6 +677,20 @@ void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &tr pendingRestorables.remove(RestorableId(assn.object, assn.propertyName)); propertyAssignmentsForState[s].append(assn); } + + // Remove pending restorables for all parent states to avoid restoring properties + // before the state that assigned them is exited. If state does not explicitly + // assign a property which is assigned by the parent, it inherits the parent's assignment. + QState *parentState = s; + while ((parentState = parentState->parentState()) != 0) { + assignments = QStatePrivate::get(parentState)->propertyAssignments; + for (int j=0; j<assignments.size(); ++j) { + const QPropertyAssignment &assn = assignments.at(j); + int c = pendingRestorables.remove(RestorableId(assn.object, assn.propertyName)); + if (c > 0) + propertyAssignmentsForState[s].append(assn); + } + } } if (!pendingRestorables.isEmpty()) { QAbstractState *s; @@ -675,6 +710,14 @@ void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &tr QAbstractAnimation *anim = animations.at(j); QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished())); stateForAnimation.remove(anim); + + // Stop the (top-level) animation. + // ### Stopping nested animation has weird behavior. + QAbstractAnimation *topLevelAnim = anim; + while (QAnimationGroup *group = topLevelAnim->group()) + topLevelAnim = group; + topLevelAnim->stop(); + if (resetAnimationEndValues.contains(anim)) { qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize resetAnimationEndValues.remove(anim); @@ -698,11 +741,6 @@ void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &tr if (!found) { assn.object->setProperty(assn.propertyName, assn.value); } - // Stop the (top-level) animation. - // ### Stopping nested animation has weird behavior. - while (QAnimationGroup *group = anim->group()) - anim = group; - anim->stop(); } } @@ -921,15 +959,15 @@ QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context) // Find error state recursively in parent hierarchy if not set explicitly for context state QAbstractState *errorState = 0; + QState *s = qobject_cast<QState*>(context); - if (s) { + if (s) errorState = s->errorState(); - if (!errorState) - errorState = findErrorState(s->parentState()); - return errorState; - } - return errorState; + if (!errorState) + errorState = findErrorState(context->parentState()); + + return errorState; } void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext) @@ -944,12 +982,19 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta .arg(currentContext->objectName()); break; - case QStateMachine::NoDefaultStateInHistoryState: + case QStateMachine::NoDefaultStateInHistoryStateError: Q_ASSERT(currentContext != 0); errorString = QStateMachine::tr("Missing default state in history state '%1'") .arg(currentContext->objectName()); break; + + case QStateMachine::NoCommonAncestorForTransitionError: + Q_ASSERT(currentContext != 0); + + errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'") + .arg(currentContext->objectName()); + break; default: errorString = QStateMachine::tr("Unknown error"); }; @@ -965,10 +1010,9 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta currentErrorState = initialErrorStateForRoot; } - if (currentErrorState) { - QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext); - addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); - } + Q_ASSERT(currentErrorState != 0); + QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext); + addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); } #ifndef QT_NO_ANIMATION @@ -994,13 +1038,6 @@ QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation, && prop.object == animation->targetObject() && prop.propertyName == animation->propertyName()) { - if (!animation->startValue().isValid()) { - QByteArray propertyName = animation->propertyName(); - QVariant currentValue = animation->targetObject()->property(propertyName); - - QVariantAnimationPrivate::get(animation)->setDefaultStartValue(currentValue); - } - // Only change end value if it is undefined if (!animation->endValue().isValid()) { animation->setEndValue(prop.value); @@ -1053,8 +1090,8 @@ public: StartState(QState *parent) : QState(parent) {} protected: - void onEntry() {} - void onExit() {} + void onEntry(QEvent *) {} + void onExit(QEvent *) {} }; class InitialTransition : public QAbstractTransition @@ -1064,7 +1101,7 @@ public: : QAbstractTransition(QList<QAbstractState*>() << target) {} protected: virtual bool eventTest(QEvent *) const { return true; } - virtual void onTransition() {} + virtual void onTransition(QEvent *) {} }; } // namespace @@ -1099,8 +1136,9 @@ void QStateMachinePrivate::_q_start() start->addTransition(initialTransition); QList<QAbstractTransition*> transitions; transitions.append(initialTransition); - executeTransitionContent(transitions); - enterStates(transitions); + QEvent nullEvent(QEvent::None); + executeTransitionContent(&nullEvent, transitions); + enterStates(&nullEvent, transitions); applyProperties(transitions, QList<QAbstractState*>() << start, QList<QAbstractState*>() << initial); delete start; @@ -1166,7 +1204,7 @@ void QStateMachinePrivate::_q_process() } if (!enabledTransitions.isEmpty()) { q->beginMicrostep(e); - microstep(enabledTransitions.toList()); + microstep(e, enabledTransitions.toList()); q->endMicrostep(e); } #ifdef QSTATEMACHINE_DEBUG @@ -1441,7 +1479,7 @@ public: setObjectName(QString::fromLatin1("DefaultErrorState")); } - void onEntry() + void onEntry(QEvent *) { QAbstractStatePrivate *d = QAbstractStatePrivate::get(this); QStateMachine *machine = d->machine(); @@ -1450,7 +1488,7 @@ public: qPrintable(machine->errorString())); } - void onExit() {} + void onExit(QEvent *) {} }; class RootState : public QState @@ -1461,8 +1499,8 @@ public: { } - void onEntry() {} - void onExit() {} + void onEntry(QEvent *) {} + void onExit(QEvent *) {} }; } // namespace @@ -1531,9 +1569,14 @@ void QStateMachine::setErrorState(QAbstractState *state) \value NoInitialStateError The machine has entered a QState with children which does not have an initial state set. The context of this error is the state which is missing an initial state. - \value NoDefaultStateInHistoryState The machine has entered a QHistoryState which does not have + \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have a default state set. The context of this error is the QHistoryState which is missing a - default state. + default state. + \value NoCommonAncestorForTransitionError The machine has selected a transition whose source + and targets are not part of the same tree of states, and thus are not part of the same + state machine. Commonly, this could mean that one of the states has not been given + any parent or added to any machine. The context of this error is the source state of + the transition. \sa setErrorState() */ @@ -1648,7 +1691,7 @@ void QStateMachine::setInitialState(QAbstractState *state) If the state is already in a different machine, it will first be removed from its old machine, and then added to this machine. - \sa removeState(), rootState() + \sa removeState(), rootState(), setInitialState() */ void QStateMachine::addState(QAbstractState *state) { @@ -1685,10 +1728,20 @@ void QStateMachine::removeState(QAbstractState *state) } /*! - Starts this state machine. - The machine will reset its configuration and transition to the initial - state. When a final top-level state is entered, the machine will emit the - finished() signal. + Returns whether this state machine is running. + + start(), stop() +*/ +bool QStateMachine::isRunning() const +{ + Q_D(const QStateMachine); + return (d->state == QStateMachinePrivate::Running); +} + +/*! + Starts this state machine. The machine will reset its configuration and + transition to the initial state. When a final top-level state (QFinalState) + is entered, the machine will emit the finished() signal. \sa started(), finished(), stop(), initialState() */ @@ -1715,9 +1768,10 @@ void QStateMachine::start() } /*! - Stops this state machine. + Stops this state machine. The state machine will stop processing events and + then emit the stopped() signal. - \sa stopped() + \sa stopped(), start() */ void QStateMachine::stop() { @@ -1798,7 +1852,8 @@ QSet<QAbstractState*> QStateMachine::configuration() const /*! \fn QStateMachine::started() - This signal is emitted when the state machine has entered its initial state. + This signal is emitted when the state machine has entered its initial state + (QStateMachine::initialState). \sa QStateMachine::finished(), QStateMachine::start() */ @@ -1807,7 +1862,7 @@ QSet<QAbstractState*> QStateMachine::configuration() const \fn QStateMachine::finished() This signal is emitted when the state machine has reached a top-level final - state. + state (QFinalState). \sa QStateMachine::started() */ @@ -1817,7 +1872,7 @@ QSet<QAbstractState*> QStateMachine::configuration() const This signal is emitted when the state machine has stopped. - \sa QStateMachine::stop() + \sa QStateMachine::stop(), QStateMachine::finished() */ /*! @@ -2095,7 +2150,7 @@ QSignalEvent::~QSignalEvent() Returns the index of the signal. - \sa QMetaObject::indexOfSignal() + \sa QMetaObject::indexOfSignal(), QMetaObject::method() */ /*! diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 10bd443..5dc6c0b 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -86,7 +86,8 @@ public: enum Error { NoError, NoInitialStateError, - NoDefaultStateInHistoryState, + NoDefaultStateInHistoryStateError, + NoCommonAncestorForTransitionError }; QStateMachine(QObject *parent = 0); @@ -107,6 +108,8 @@ public: QString errorString() const; void clearError(); + bool isRunning() const; + #ifndef QT_NO_ANIMATION bool animationsEnabled() const; void setAnimationsEnabled(bool enabled); diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index b3707ea..bb4a78c 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -120,12 +120,12 @@ public: void _q_animationFinished(); #endif - void microstep(const QList<QAbstractTransition*> &transitionList); + void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList); bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const; QSet<QAbstractTransition*> selectTransitions(QEvent *event) const; - QList<QAbstractState*> exitStates(const QList<QAbstractTransition*> &transitionList); - void executeTransitionContent(const QList<QAbstractTransition*> &transitionList); - QList<QAbstractState*> enterStates(const QList<QAbstractTransition*> &enabledTransitions); + QList<QAbstractState*> exitStates(QEvent *event, const QList<QAbstractTransition*> &transitionList); + void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList); + QList<QAbstractState*> enterStates(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions); void addStatesToEnter(QAbstractState *s, QState *root, QSet<QAbstractState*> &statesToEnter, QSet<QAbstractState*> &statesForDefaultEntry); diff --git a/src/gui/statemachine/qbasickeyeventtransition.cpp b/src/gui/statemachine/qbasickeyeventtransition.cpp index 4e3fa11..7821feb 100644 --- a/src/gui/statemachine/qbasickeyeventtransition.cpp +++ b/src/gui/statemachine/qbasickeyeventtransition.cpp @@ -170,7 +170,7 @@ bool QBasicKeyEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QBasicKeyEventTransition::onTransition() +void QBasicKeyEventTransition::onTransition(QEvent *) { } diff --git a/src/gui/statemachine/qbasickeyeventtransition_p.h b/src/gui/statemachine/qbasickeyeventtransition_p.h index de49eac..0d08da0 100644 --- a/src/gui/statemachine/qbasickeyeventtransition_p.h +++ b/src/gui/statemachine/qbasickeyeventtransition_p.h @@ -56,7 +56,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *); private: Q_DISABLE_COPY(QBasicKeyEventTransition) diff --git a/src/gui/statemachine/qbasicmouseeventtransition.cpp b/src/gui/statemachine/qbasicmouseeventtransition.cpp index 83254dc..0cb727e 100644 --- a/src/gui/statemachine/qbasicmouseeventtransition.cpp +++ b/src/gui/statemachine/qbasicmouseeventtransition.cpp @@ -174,7 +174,7 @@ bool QBasicMouseEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QBasicMouseEventTransition::onTransition() +void QBasicMouseEventTransition::onTransition(QEvent *) { } diff --git a/src/gui/statemachine/qbasicmouseeventtransition_p.h b/src/gui/statemachine/qbasicmouseeventtransition_p.h index 77fbd58..20c7f8f 100644 --- a/src/gui/statemachine/qbasicmouseeventtransition_p.h +++ b/src/gui/statemachine/qbasicmouseeventtransition_p.h @@ -59,7 +59,7 @@ public: protected: bool eventTest(QEvent *event) const; - void onTransition(); + void onTransition(QEvent *); private: Q_DISABLE_COPY(QBasicMouseEventTransition) diff --git a/src/gui/statemachine/qkeyeventtransition.cpp b/src/gui/statemachine/qkeyeventtransition.cpp index 37f4dd9..e6ab11b 100644 --- a/src/gui/statemachine/qkeyeventtransition.cpp +++ b/src/gui/statemachine/qkeyeventtransition.cpp @@ -153,9 +153,9 @@ bool QKeyEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QKeyEventTransition::onTransition() +void QKeyEventTransition::onTransition(QEvent *event) { - QEventTransition::onTransition(); + QEventTransition::onTransition(event); } QT_END_NAMESPACE diff --git a/src/gui/statemachine/qkeyeventtransition.h b/src/gui/statemachine/qkeyeventtransition.h index fa95c1b..3f797f1 100644 --- a/src/gui/statemachine/qkeyeventtransition.h +++ b/src/gui/statemachine/qkeyeventtransition.h @@ -45,7 +45,7 @@ public: void setModifiersMask(Qt::KeyboardModifiers modifiers); protected: - void onTransition(); + void onTransition(QEvent *event); bool eventTest(QEvent *event) const; private: diff --git a/src/gui/statemachine/qmouseeventtransition.cpp b/src/gui/statemachine/qmouseeventtransition.cpp index 353b833..3191a2f 100644 --- a/src/gui/statemachine/qmouseeventtransition.cpp +++ b/src/gui/statemachine/qmouseeventtransition.cpp @@ -183,9 +183,9 @@ bool QMouseEventTransition::eventTest(QEvent *event) const /*! \reimp */ -void QMouseEventTransition::onTransition() +void QMouseEventTransition::onTransition(QEvent *event) { - QEventTransition::onTransition(); + QEventTransition::onTransition(event); } QT_END_NAMESPACE diff --git a/src/gui/statemachine/qmouseeventtransition.h b/src/gui/statemachine/qmouseeventtransition.h index d5fb565..eee971e 100644 --- a/src/gui/statemachine/qmouseeventtransition.h +++ b/src/gui/statemachine/qmouseeventtransition.h @@ -51,7 +51,7 @@ public: void setPath(const QPainterPath &path); protected: - void onTransition(); + void onTransition(QEvent *event); bool eventTest(QEvent *event) const; private: |