From e339b7568774e0b26d3f57a7f4b791d39b44b450 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 21 Apr 2009 17:26:36 +0200 Subject: Add API for adding default animations to the state machine. This is especially useful when using the RestoreProperties policy, because this is intended to allow you to build a state machine without having each state consider all the possible properties that may be set by some state at some point. Default animations provide the same convenience for animated properties. --- src/corelib/statemachine/qstatemachine.cpp | 111 +++++++++++++++++++- src/corelib/statemachine/qstatemachine.h | 16 +++ src/corelib/statemachine/qstatemachine_p.h | 9 +- tests/auto/qstatemachine/tst_qstatemachine.cpp | 140 +++++++++++++++++++++++++ 4 files changed, 272 insertions(+), 4 deletions(-) diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 0a1d248..1f8d8a8 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -612,8 +612,17 @@ void QStateMachinePrivate::applyProperties(const QList &tr // Find the animations to use for the state change. QList selectedAnimations; - for (int i = 0; i < transitionList.size(); ++i) - selectedAnimations << transitionList.at(i)->animations(); + for (int i = 0; i < transitionList.size(); ++i) { + QAbstractTransition *transition = transitionList.at(i); + + selectedAnimations << transition->animations(); + selectedAnimations << defaultAnimationsForSource.values(transition->sourceState()); + + QList targetStates = transition->targetStates(); + for (int j=0; jdefaultAnimations.append(animation); +} + +/*! + Returns the list of default animations that will be considered for any transition. +*/ +QList QStateMachine::defaultAnimations() const +{ + Q_D(const QStateMachine); + return d->defaultAnimations; +} + +/*! + Removes \a animation from the list of default animations. +*/ +void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimations.removeAll(animation); +} + + +/*! + Adds a default \a animation to be considered for any transition with the source state + \a sourceState. +*/ +void QStateMachine::addDefaultAnimationForSourceState(QAbstractState *sourceState, + QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimationsForSource.insert(sourceState, animation); +} + + +/*! + Returns the list of default animations that will be considered for any transition with + the source state \a sourceState. +*/ +QList QStateMachine::defaultAnimationsForSourceState(QAbstractState *sourceState) const +{ + Q_D(const QStateMachine); + return d->defaultAnimationsForSource.values(sourceState); +} + +/*! + Removes \a animation from the list of default animations for the source state + \a sourceState. +*/ +void QStateMachine::removeDefaultAnimationForSourceState(QAbstractState *sourceState, + QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimationsForSource.remove(sourceState, animation); +} + +/*! + Adds a default \a animation to be considered for any transition with the target state + \a targetState. +*/ +void QStateMachine::addDefaultAnimationForTargetState(QAbstractState *targetState, + QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimationsForTarget.insert(targetState, animation); +} + +/*! + Returns the list of default animations that will be considered for any transition with + the target state \a targetState. +*/ +QList QStateMachine::defaultAnimationsForTargetState(QAbstractState *targetState) const +{ + Q_D(const QStateMachine); + return d->defaultAnimationsForTarget.values(targetState); +} + +/*! + Removes \a animation from the list of default animations for the target state + \a targetState. +*/ +void QStateMachine::removeDefaultAnimationForTargetState(QAbstractState *targetState, + QAbstractAnimation *animation) +{ + Q_D(QStateMachine); + d->defaultAnimationsForTarget.remove(targetState, animation); +} + +#endif // QT_NO_ANIMATION + + static const uint qt_meta_data_QSignalEventGenerator[] = { // content: diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index c7de171..f39efc7 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -63,6 +63,8 @@ class QAbstractState; class QState; class QStateMachinePrivate; +class QAbstractAnimation; +class QAbstractState; class Q_CORE_EXPORT QStateMachine : public QObject { Q_OBJECT @@ -96,6 +98,20 @@ public: QString errorString() const; void clearError(); +#ifndef QT_NO_ANIMATION + void addDefaultAnimation(QAbstractAnimation *animation); + QList defaultAnimations() const; + void removeDefaultAnimation(QAbstractAnimation *animation); + + void addDefaultAnimationForSourceState(QAbstractState *sourceState, QAbstractAnimation *animation); + QList defaultAnimationsForSourceState(QAbstractState *sourceState) const; + void removeDefaultAnimationForSourceState(QAbstractState *sourceState, QAbstractAnimation *animation); + + void addDefaultAnimationForTargetState(QAbstractState *targetState, QAbstractAnimation *animation); + QList defaultAnimationsForTargetState(QAbstractState *targetState) const; + void removeDefaultAnimationForTargetState(QAbstractState *targetState, QAbstractAnimation *animation); +#endif // QT_NO_ANIMATION + QAbstractState::RestorePolicy globalRestorePolicy() const; void setGlobalRestorePolicy(QAbstractState::RestorePolicy restorePolicy); diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 04dc71e..a9fd2de 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -169,7 +169,7 @@ public: QSet configuration; QList internalEventQueue; QList externalEventQueue; - + QStateMachine::Error error; QActionState::RestorePolicy globalRestorePolicy; @@ -186,7 +186,12 @@ public: QList > propertiesForAnimations; QList playingAnimations; QList resetEndValues; -#endif + + QList defaultAnimations; + QMultiHash defaultAnimationsForSource; + QMultiHash defaultAnimationsForTarget; + +#endif // QT_NO_ANIMATION #ifndef QT_STATEMACHINE_SOLUTION QSignalEventGenerator *signalEventGenerator; diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index be80bed..5796161 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -141,6 +141,10 @@ private slots: void nestedTargetStateForAnimation(); void animatedGlobalRestoreProperty(); void specificTargetValueOfAnimation(); + void addDefaultAnimation(); + void addDefaultAnimationWithUnusedAnimation(); + void addDefaultAnimationForSource(); + void addDefaultAnimationForTarget(); }; tst_QStateMachine::tst_QStateMachine() @@ -2437,6 +2441,142 @@ void tst_QStateMachine::specificTargetValueOfAnimation() QCOMPARE(anim->endValue().toDouble(), 10.0); } +void tst_QStateMachine::addDefaultAnimation() +{ + QStateMachine machine; + + QObject *object = new QObject(); + object->setProperty("foo", 1.0); + + QState *s1 = new QState(machine.rootState()); + + QState *s2 = new QState(machine.rootState()); + s2->assignProperty(object, "foo", 2.0); + + QState *s3 = new QState(machine.rootState()); + s3->invokeMethodOnEntry(QCoreApplication::instance(), "quit"); + + s1->addTransition(new EventTransition(QEvent::User, s2)); + + QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); + machine.addDefaultAnimation(pa); + s2->addTransition(pa, SIGNAL(finished()), s3); + + machine.setInitialState(s1); + machine.start(); + QCoreApplication::processEvents(); + + machine.postEvent(new QEvent(QEvent::User)); + QCOREAPPLICATION_EXEC(5000); + + QVERIFY(machine.configuration().contains(s3)); + QCOMPARE(object->property("foo").toDouble(), 2.0); +} + +void tst_QStateMachine::addDefaultAnimationWithUnusedAnimation() +{ + QStateMachine machine; + + QObject *object = new QObject(); + object->setProperty("foo", 1.0); + object->setProperty("bar", 2.0); + + SlotCalledCounter counter; + + QState *s1 = new QState(machine.rootState()); + + QState *s2 = new QState(machine.rootState()); + s2->assignProperty(object, "foo", 2.0); + + QState *s3 = new QState(machine.rootState()); + s3->invokeMethodOnEntry(QCoreApplication::instance(), "quit"); + + s1->addTransition(new EventTransition(QEvent::User, s2)); + + QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); + connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); + machine.addDefaultAnimation(pa); + s2->addTransition(pa, SIGNAL(finished()), s3); + + pa = new QPropertyAnimation(object, "bar", &machine); + connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); + machine.addDefaultAnimation(pa); + + machine.setInitialState(s1); + machine.start(); + QCoreApplication::processEvents(); + + machine.postEvent(new QEvent(QEvent::User)); + QCOREAPPLICATION_EXEC(5000); + + QVERIFY(machine.configuration().contains(s3)); + QCOMPARE(object->property("foo").toDouble(), 2.0); + QCOMPARE(counter.counter, 1); +} + +void tst_QStateMachine::addDefaultAnimationForSource() +{ + QStateMachine machine; + + QObject *object = new QObject(); + object->setProperty("foo", 1.0); + + QState *s1 = new QState(machine.rootState()); + + QState *s2 = new QState(machine.rootState()); + s2->assignProperty(object, "foo", 2.0); + + QState *s3 = new QState(machine.rootState()); + s3->invokeMethodOnEntry(QCoreApplication::instance(), "quit"); + + s1->addTransition(new EventTransition(QEvent::User, s2)); + + QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); + machine.addDefaultAnimationForSourceState(s1, pa); + s2->addTransition(pa, SIGNAL(finished()), s3); + + machine.setInitialState(s1); + machine.start(); + QCoreApplication::processEvents(); + + machine.postEvent(new QEvent(QEvent::User)); + QCOREAPPLICATION_EXEC(5000); + + QVERIFY(machine.configuration().contains(s3)); + QCOMPARE(object->property("foo").toDouble(), 2.0); +} + +void tst_QStateMachine::addDefaultAnimationForTarget() +{ + QStateMachine machine; + + QObject *object = new QObject(); + object->setProperty("foo", 1.0); + + QState *s1 = new QState(machine.rootState()); + + QState *s2 = new QState(machine.rootState()); + s2->assignProperty(object, "foo", 2.0); + + QState *s3 = new QState(machine.rootState()); + s3->invokeMethodOnEntry(QCoreApplication::instance(), "quit"); + + s1->addTransition(new EventTransition(QEvent::User, s2)); + + QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); + machine.addDefaultAnimationForTargetState(s2, pa); + s2->addTransition(pa, SIGNAL(finished()), s3); + + machine.setInitialState(s1); + machine.start(); + QCoreApplication::processEvents(); + + machine.postEvent(new QEvent(QEvent::User)); + QCOREAPPLICATION_EXEC(5000); + + QVERIFY(machine.configuration().contains(s3)); + QCOMPARE(object->property("foo").toDouble(), 2.0); +} QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc" -- cgit v0.12