/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "../../shared/util.h" #include #include //TESTED_CLASS=QSequentialAnimationGroup //TESTED_FILES= Q_DECLARE_METATYPE(QAbstractAnimation::State) Q_DECLARE_METATYPE(QAbstractAnimation*) class tst_QSequentialAnimationGroup : public QObject { Q_OBJECT public: tst_QSequentialAnimationGroup(); virtual ~tst_QSequentialAnimationGroup(); public Q_SLOTS: void init(); void cleanup(); private slots: void construction(); void setCurrentTime(); void setCurrentTimeWithUncontrolledAnimation(); void seekingForwards(); void seekingBackwards(); void pauseAndResume(); void restart(); void looping(); void startDelay(); void clearGroup(); void groupWithZeroDurationAnimations(); void propagateGroupUpdateToChildren(); void updateChildrenWithRunningGroup(); void deleteChildrenWithRunningGroup(); void startChildrenWithStoppedGroup(); void stopGroupWithRunningChild(); void startGroupWithRunningChild(); void zeroDurationAnimation(); void stopUncontrolledAnimations(); void finishWithUncontrolledAnimation(); void addRemoveAnimation(); void currentAnimation(); void currentAnimationWithZeroDuration(); void insertAnimation(); void clearAnimations(); void pauseResume(); }; tst_QSequentialAnimationGroup::tst_QSequentialAnimationGroup() { } tst_QSequentialAnimationGroup::~tst_QSequentialAnimationGroup() { } void tst_QSequentialAnimationGroup::init() { qRegisterMetaType("QAbstractAnimation::State"); qRegisterMetaType("QAbstractAnimation*"); } void tst_QSequentialAnimationGroup::cleanup() { } void tst_QSequentialAnimationGroup::construction() { QSequentialAnimationGroup animationgroup; } class AnimationObject : public QObject { Q_OBJECT Q_PROPERTY(int value READ value WRITE setValue) public: AnimationObject(int startValue = 0) : v(startValue) { } int value() const { return v; } void setValue(int value) { v = value; } int v; }; class TestAnimation : public QVariantAnimation { Q_OBJECT public: virtual void updateCurrentValue(const QVariant &value) { Q_UNUSED(value)}; virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState) { Q_UNUSED(oldState) Q_UNUSED(newState) }; }; class UncontrolledAnimation : public QPropertyAnimation { Q_OBJECT public: UncontrolledAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0) : QPropertyAnimation(target, propertyName, parent) { setDuration(250); } int duration() const { return -1; /* not time driven */ } protected: void updateCurrentTime(int msecs) { QPropertyAnimation::updateCurrentTime(msecs); if (msecs >= QPropertyAnimation::duration()) stop(); } }; void tst_QSequentialAnimationGroup::setCurrentTime() { AnimationObject s_o1; AnimationObject s_o2; AnimationObject s_o3; // sequence operating on same object/property QAnimationGroup *sequence = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value"); a2_s_o1->setLoopCount(3); sequence->addAnimation(a1_s_o1); sequence->addAnimation(a2_s_o1); sequence->addAnimation(a3_s_o1); // sequence operating on different object/properties QAnimationGroup *sequence2 = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value"); QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value"); sequence2->addAnimation(a1_s_o2); sequence2->addAnimation(a1_s_o3); QSequentialAnimationGroup group; group.addAnimation(sequence); group.addAnimation(sequence2); // Current time = 1 group.setCurrentTime(1); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(sequence2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(group.currentTime(), 1); QCOMPARE(sequence->currentTime(), 1); QCOMPARE(a1_s_o1->currentTime(), 1); QCOMPARE(a2_s_o1->currentTime(), 0); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 250 group.setCurrentTime(250); QCOMPARE(group.currentTime(), 250); QCOMPARE(sequence->currentTime(), 250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 0); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 251 group.setCurrentTime(251); QCOMPARE(group.currentTime(), 251); QCOMPARE(sequence->currentTime(), 251); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 1); QCOMPARE(a2_s_o1->currentLoop(), 0); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 750 group.setCurrentTime(750); QCOMPARE(group.currentTime(), 750); QCOMPARE(sequence->currentTime(), 750); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 0); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 1000 group.setCurrentTime(1000); QCOMPARE(group.currentTime(), 1000); QCOMPARE(sequence->currentTime(), 1000); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 1010 group.setCurrentTime(1010); QCOMPARE(group.currentTime(), 1010); QCOMPARE(sequence->currentTime(), 1010); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 10); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 1250 group.setCurrentTime(1250); QCOMPARE(group.currentTime(), 1250); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 1500 group.setCurrentTime(1500); QCOMPARE(group.currentTime(), 1500); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 1750 group.setCurrentTime(1750); QCOMPARE(group.currentTime(), 1750); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 500); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 250); // Current time = 2000 group.setCurrentTime(2000); QCOMPARE(group.currentTime(), 1750); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 500); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 250); } void tst_QSequentialAnimationGroup::setCurrentTimeWithUncontrolledAnimation() { AnimationObject s_o1; AnimationObject s_o2; AnimationObject t_o1; AnimationObject t_o2; // sequence operating on different object/properties QAnimationGroup *sequence = new QSequentialAnimationGroup(); QAbstractAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value"); QAbstractAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value"); sequence->addAnimation(a1_s_o1); sequence->addAnimation(a1_s_o2); QAbstractAnimation *notTimeDriven = new UncontrolledAnimation(&t_o1, "value"); QCOMPARE(notTimeDriven->totalDuration(), -1); QAbstractAnimation *loopsForever = new QPropertyAnimation(&t_o2, "value"); loopsForever->setLoopCount(-1); QCOMPARE(loopsForever->totalDuration(), -1); QSequentialAnimationGroup group; group.addAnimation(sequence); group.addAnimation(notTimeDriven); group.addAnimation(loopsForever); group.start(); group.pause(); // this allows the group to listen for the finish signal of its children // Current time = 1 group.setCurrentTime(1); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(sequence->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped); QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped); QCOMPARE(group.currentTime(), 1); QCOMPARE(sequence->currentTime(), 1); QCOMPARE(a1_s_o1->currentTime(), 1); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(notTimeDriven->currentTime(), 0); QCOMPARE(loopsForever->currentTime(), 0); // Current time = 250 group.setCurrentTime(250); QCOMPARE(group.currentTime(), 250); QCOMPARE(sequence->currentTime(), 250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(notTimeDriven->currentTime(), 0); QCOMPARE(loopsForever->currentTime(), 0); // Current time = 500 group.setCurrentTime(500); QCOMPARE(group.currentTime(), 500); QCOMPARE(sequence->currentTime(), 500); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(notTimeDriven->currentTime(), 0); QCOMPARE(loopsForever->currentTime(), 0); QCOMPARE(group.currentAnimation(), notTimeDriven); // Current time = 505 group.setCurrentTime(505); QCOMPARE(group.currentTime(), 505); QCOMPARE(sequence->currentTime(), 500); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(notTimeDriven->currentTime(), 5); QCOMPARE(loopsForever->currentTime(), 0); QCOMPARE(group.currentAnimation(), notTimeDriven); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(notTimeDriven->state(), QAnimationGroup::Paused); QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped); // Current time = 750 (end of notTimeDriven animation) group.setCurrentTime(750); QCOMPARE(group.currentTime(), 750); QCOMPARE(sequence->currentTime(), 500); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(notTimeDriven->currentTime(), 250); QCOMPARE(loopsForever->currentTime(), 0); QCOMPARE(group.currentAnimation(), loopsForever); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped); QCOMPARE(loopsForever->state(), QAnimationGroup::Paused); // Current time = 800 (as notTimeDriven was finished at 750, loopsforever should still run) group.setCurrentTime(800); QCOMPARE(group.currentTime(), 800); QCOMPARE(group.currentAnimation(), loopsForever); QCOMPARE(sequence->currentTime(), 500); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(notTimeDriven->currentTime(), 250); QCOMPARE(loopsForever->currentTime(), 50); loopsForever->stop(); // this should stop the group QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped); QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::seekingForwards() { AnimationObject s_o1; AnimationObject s_o2; AnimationObject s_o3; // sequence operating on same object/property QAnimationGroup *sequence = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value"); a2_s_o1->setLoopCount(3); sequence->addAnimation(a1_s_o1); sequence->addAnimation(a2_s_o1); sequence->addAnimation(a3_s_o1); // sequence operating on different object/properties QAnimationGroup *sequence2 = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value"); QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value"); sequence2->addAnimation(a1_s_o2); sequence2->addAnimation(a1_s_o3); QSequentialAnimationGroup group; group.addAnimation(sequence); group.addAnimation(sequence2); // Current time = 1 group.setCurrentTime(1); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(sequence2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped); QCOMPARE(group.currentTime(), 1); QCOMPARE(sequence->currentTime(), 1); QCOMPARE(a1_s_o1->currentTime(), 1); QCOMPARE(a2_s_o1->currentTime(), 0); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); // Current time = 1500 group.setCurrentTime(1500); QCOMPARE(group.currentTime(), 1500); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 250); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 0); // this will restart the group group.start(); group.pause(); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(sequence->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Paused); QCOMPARE(sequence2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped); // Current time = 1750 group.setCurrentTime(1750); QCOMPARE(group.currentTime(), 1750); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 500); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 250); } void tst_QSequentialAnimationGroup::seekingBackwards() { AnimationObject s_o1; AnimationObject s_o2; AnimationObject s_o3; // sequence operating on same object/property QAnimationGroup *sequence = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value"); a2_s_o1->setLoopCount(3); sequence->addAnimation(a1_s_o1); sequence->addAnimation(a2_s_o1); sequence->addAnimation(a3_s_o1); // sequence operating on different object/properties QAnimationGroup *sequence2 = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value"); QVariantAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value"); sequence2->addAnimation(a1_s_o2); sequence2->addAnimation(a1_s_o3); QSequentialAnimationGroup group; group.addAnimation(sequence); group.addAnimation(sequence2); group.start(); // Current time = 1600 group.setCurrentTime(1600); QCOMPARE(group.currentTime(), 1600); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 350); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 100); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(sequence2->state(), QAnimationGroup::Running); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o3->state(), QAnimationGroup::Running); // Seeking backwards, current time = 1 group.setCurrentTime(1); QCOMPARE(group.currentTime(), 1); QCOMPARE(sequence->currentTime(), 1); QCOMPARE(a1_s_o1->currentTime(), 1); QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children," "hence they don't reset from their current animation", Continue); QCOMPARE(a2_s_o1->currentTime(), 0); QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children," "hence they don't reset from their current animation", Continue); QCOMPARE(a2_s_o1->currentLoop(), 0); QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children," "hence they don't reset from their current animation", Continue); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(sequence2->currentTime(), 0); QCOMPARE(a1_s_o2->currentTime(), 0); QCOMPARE(a1_s_o3->currentTime(), 0); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(sequence->state(), QAnimationGroup::Running); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Running); QCOMPARE(sequence2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped); // Current time = 2000 group.setCurrentTime(2000); QCOMPARE(group.currentTime(), 1750); QCOMPARE(sequence->currentTime(), 1250); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 2); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(sequence2->currentTime(), 500); QCOMPARE(a1_s_o2->currentTime(), 250); QCOMPARE(a1_s_o3->currentTime(), 250); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(sequence->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(sequence2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped); QCOMPARE(a1_s_o3->state(), QAnimationGroup::Stopped); } typedef QList StateList; static bool compareStates(const QSignalSpy& spy, const StateList &expectedStates) { bool equals = true; for (int i = 0; i < qMax(expectedStates.count(), spy.count()); ++i) { if (i >= spy.count() || i >= expectedStates.count()) { equals = false; break; } QList args = spy.at(i); QAbstractAnimation::State st = expectedStates.at(i); QAbstractAnimation::State actual = qVariantValue(args.value(1)); if (equals && actual != st) { equals = false; break; } } if (!equals) { const char *stateStrings[] = {"Stopped", "Paused", "Running"}; QString e,a; for (int i = 0; i < qMax(expectedStates.count(), spy.count()); ++i) { if (i < expectedStates.count()) { int exp = int(expectedStates.at(i)); if (!e.isEmpty()) e += QLatin1String(", "); e += QLatin1String(stateStrings[exp]); } if (i < spy.count()) { QList args = spy.at(i); QAbstractAnimation::State actual = qVariantValue(args.value(1)); if (!a.isEmpty()) a += QLatin1String(", "); if (int(actual) >= 0 && int(actual) <= 2) { a += QLatin1String(stateStrings[int(actual)]); } else { a += QLatin1String("NaN"); } } } qDebug("\n" "expected (count == %d): %s\n" "actual (count == %d): %s\n", expectedStates.count(), qPrintable(e), spy.count(), qPrintable(a)); } return equals; } void tst_QSequentialAnimationGroup::pauseAndResume() { AnimationObject s_o1; // sequence operating on same object/property QAnimationGroup *sequence = new QSequentialAnimationGroup(); QVariantAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value"); QVariantAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value"); a2_s_o1->setLoopCount(2); sequence->addAnimation(a1_s_o1); sequence->addAnimation(a2_s_o1); sequence->addAnimation(a3_s_o1); sequence->setLoopCount(2); QSignalSpy a1StateChangedSpy(a1_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSignalSpy seqStateChangedSpy(sequence, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSequentialAnimationGroup group; group.addAnimation(sequence); group.start(); group.pause(); // Current time = 1751 group.setCurrentTime(1751); QCOMPARE(group.currentTime(), 1751); QCOMPARE(sequence->currentTime(), 751); QCOMPARE(sequence->currentLoop(), 1); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 1); QCOMPARE(a3_s_o1->currentLoop(), 0); QCOMPARE(a3_s_o1->currentTime(), 1); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(sequence->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a3_s_o1->state(), QAnimationGroup::Paused); QCOMPARE(a1StateChangedSpy.count(), 5); // Running,Paused,Stopped,Running,Stopped QCOMPARE(seqStateChangedSpy.count(), 2); // Running,Paused QVERIFY(compareStates(a1StateChangedSpy, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Paused << QAbstractAnimation::Stopped << QAbstractAnimation::Running << QAbstractAnimation::Stopped))); QCOMPARE(qVariantValue(a1StateChangedSpy.at(0).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(a1StateChangedSpy.at(1).at(1)), QAnimationGroup::Paused); QCOMPARE(qVariantValue(a1StateChangedSpy.at(2).at(1)), QAnimationGroup::Stopped); QCOMPARE(qVariantValue(a1StateChangedSpy.at(3).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(a1StateChangedSpy.at(4).at(1)), QAnimationGroup::Stopped); QCOMPARE(qVariantValue(seqStateChangedSpy.at(0).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(seqStateChangedSpy.at(1).at(1)), QAnimationGroup::Paused); group.resume(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(sequence->state(), QAnimationGroup::Running); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a3_s_o1->state(), QAnimationGroup::Running); QVERIFY(group.currentTime() >= 1751); QVERIFY(sequence->currentTime() >= 751); QCOMPARE(sequence->currentLoop(), 1); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 1); QCOMPARE(a3_s_o1->currentLoop(), 0); QVERIFY(a3_s_o1->currentTime() >= 1); QCOMPARE(seqStateChangedSpy.count(), 3); // Running,Paused,Running QCOMPARE(qVariantValue(seqStateChangedSpy.at(2).at(1)), QAnimationGroup::Running); group.pause(); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(sequence->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a3_s_o1->state(), QAnimationGroup::Paused); QVERIFY(group.currentTime() >= 1751); QVERIFY(sequence->currentTime() >= 751); QCOMPARE(sequence->currentLoop(), 1); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 1); QCOMPARE(a3_s_o1->currentLoop(), 0); QVERIFY(a3_s_o1->currentTime() >= 1); QCOMPARE(seqStateChangedSpy.count(), 4); // Running,Paused,Running,Paused QCOMPARE(qVariantValue(seqStateChangedSpy.at(3).at(1)), QAnimationGroup::Paused); group.stop(); QCOMPARE(seqStateChangedSpy.count(), 5); // Running,Paused,Running,Paused,Stopped QCOMPARE(qVariantValue(seqStateChangedSpy.at(4).at(1)), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::restart() { AnimationObject s_o1; // sequence operating on same object/property QAnimationGroup *sequence = new QSequentialAnimationGroup(); QSignalSpy seqCurrentAnimChangedSpy(sequence, SIGNAL(currentAnimationChanged(QAbstractAnimation*))); QSignalSpy seqStateChangedSpy(sequence, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QVariantAnimation *anims[3]; QSignalSpy *animsStateChanged[3]; for (int i = 0; i < 3; i++) { anims[i] = new QPropertyAnimation(&s_o1, "value"); anims[i]->setDuration(100); animsStateChanged[i] = new QSignalSpy(anims[i], SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); } anims[1]->setLoopCount(2); sequence->addAnimation(anims[0]); sequence->addAnimation(anims[1]); sequence->addAnimation(anims[2]); sequence->setLoopCount(2); QSequentialAnimationGroup group; group.addAnimation(sequence); group.start(); QTest::qWait(500); QCOMPARE(group.state(), QAnimationGroup::Running); QTest::qWait(300); QTRY_COMPARE(group.state(), QAnimationGroup::Stopped); for (int i = 0; i < 3; i++) { QCOMPARE(animsStateChanged[i]->count(), 4); QCOMPARE(qVariantValue(animsStateChanged[i]->at(0).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(animsStateChanged[i]->at(1).at(1)), QAnimationGroup::Stopped); QCOMPARE(qVariantValue(animsStateChanged[i]->at(2).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(animsStateChanged[i]->at(3).at(1)), QAnimationGroup::Stopped); } QCOMPARE(seqStateChangedSpy.count(), 2); QCOMPARE(qVariantValue(seqStateChangedSpy.at(0).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(seqStateChangedSpy.at(1).at(1)), QAnimationGroup::Stopped); QCOMPARE(seqCurrentAnimChangedSpy.count(), 6); for(int i=0; i(anims[i%3]), qVariantValue(seqCurrentAnimChangedSpy.at(i).at(0))); group.start(); QCOMPARE(animsStateChanged[0]->count(), 5); QCOMPARE(animsStateChanged[1]->count(), 4); QCOMPARE(animsStateChanged[2]->count(), 4); QCOMPARE(seqStateChangedSpy.count(), 3); } void tst_QSequentialAnimationGroup::looping() { AnimationObject s_o1; AnimationObject s_o2; AnimationObject s_o3; // sequence operating on same object/property QSequentialAnimationGroup *sequence = new QSequentialAnimationGroup(); QAbstractAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value"); QAbstractAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value"); QAbstractAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value"); QSignalSpy a1Spy(a1_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSignalSpy a2Spy(a2_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSignalSpy a3Spy(a3_s_o1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSignalSpy seqSpy(sequence, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); a2_s_o1->setLoopCount(2); sequence->addAnimation(a1_s_o1); sequence->addAnimation(a2_s_o1); sequence->addAnimation(a3_s_o1); sequence->setLoopCount(2); QSequentialAnimationGroup group; QSignalSpy groupSpy(&group, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); group.addAnimation(sequence); group.setLoopCount(2); group.start(); group.pause(); // Current time = 1750 group.setCurrentTime(1750); QCOMPARE(group.currentTime(), 1750); QCOMPARE(sequence->currentTime(), 750); QCOMPARE(sequence->currentLoop(), 1); QCOMPARE(a1_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 1); // this animation is at the beginning because it is the current one inside sequence QCOMPARE(a3_s_o1->currentLoop(), 0); QCOMPARE(a3_s_o1->currentTime(), 0); QCOMPARE(sequence->currentAnimation(), a3_s_o1); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(sequence->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a3_s_o1->state(), QAnimationGroup::Paused); QCOMPARE(a1Spy.count(), 5); // Running,Paused,Stopped,Running,Stopped QVERIFY(compareStates(a1Spy, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Paused << QAbstractAnimation::Stopped << QAbstractAnimation::Running << QAbstractAnimation::Stopped))); QCOMPARE(a2Spy.count(), 4); // Running,Stopped,Running,Stopped QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Stopped << QAbstractAnimation::Running << QAbstractAnimation::Paused))); QCOMPARE(seqSpy.count(), 2); // Running,Paused QCOMPARE(groupSpy.count(), 2); // Running,Paused // Looping, current time = duration + 1 group.setCurrentTime(group.duration() + 1); QCOMPARE(group.currentTime(), 1); QCOMPARE(group.currentLoop(), 1); QCOMPARE(sequence->currentTime(), 1); QCOMPARE(sequence->currentLoop(), 0); QCOMPARE(a1_s_o1->currentTime(), 1); QCOMPARE(a2_s_o1->currentTime(), 250); QCOMPARE(a2_s_o1->currentLoop(), 1); // this animation is at the end because it was run on the previous loop QCOMPARE(a3_s_o1->currentLoop(), 0); QCOMPARE(a3_s_o1->currentTime(), 250); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(sequence->state(), QAnimationGroup::Paused); QCOMPARE(a1_s_o1->state(), QAnimationGroup::Paused); QCOMPARE(a2_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a3_s_o1->state(), QAnimationGroup::Stopped); QCOMPARE(a1Spy.count(), 7); // Running,Paused,Stopped,Running,Stopped,Running,Stopped QCOMPARE(a2Spy.count(), 4); // Running, Stopped, Running, Stopped QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Stopped << QAbstractAnimation::Running << QAbstractAnimation::Paused << QAbstractAnimation::Stopped))); QVERIFY(compareStates(seqSpy, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Paused << QAbstractAnimation::Stopped << QAbstractAnimation::Running << QAbstractAnimation::Paused))); QCOMPARE(groupSpy.count(), 2); } void tst_QSequentialAnimationGroup::startDelay() { QSequentialAnimationGroup group; group.addPause(250); group.addPause(125); QCOMPARE(group.totalDuration(), 375); QEventLoop loop; QObject::connect(&group, SIGNAL(finished()), &loop, SLOT(quit())); QTime time; time.start(); group.start(); loop.exec(); QVERIFY(time.elapsed() >= 375); QVERIFY(time.elapsed() < 1000); } void tst_QSequentialAnimationGroup::clearGroup() { QSequentialAnimationGroup group; static const int animationCount = 20; for (int i = 0; i < animationCount/2; ++i) { QSequentialAnimationGroup *subGroup = new QSequentialAnimationGroup(&group); group.addPause(100); subGroup->addPause(10); } QCOMPARE(group.animationCount(), animationCount); QPointer children[animationCount]; for (int i = 0; i < animationCount; ++i) { QVERIFY(group.animationAt(i) != 0); children[i] = group.animationAt(i); } group.clearAnimations(); QCOMPARE(group.animationCount(), 0); QCOMPARE(group.currentTime(), 0); for (int i = 0; i < animationCount; ++i) QVERIFY(children[i].isNull()); } void tst_QSequentialAnimationGroup::groupWithZeroDurationAnimations() { QObject o; QObject o2; o.setProperty("myProperty", 42); o.setProperty("myOtherProperty", 13); o2.setProperty("myProperty", 42); o2.setProperty("myOtherProperty", 13); QSequentialAnimationGroup group; QVariantAnimation *a1 = new QPropertyAnimation(&o, "myProperty"); a1->setDuration(0); a1->setEndValue(43); group.addAnimation(a1); //this should just run fine and change nothing group.setCurrentTime(0); QCOMPARE(group.currentAnimation(), static_cast(a1)); QVariantAnimation *a2 = new QPropertyAnimation(&o2, "myOtherProperty"); a2->setDuration(500); a2->setEndValue(31); group.addAnimation(a2); QVariantAnimation *a3 = new QPropertyAnimation(&o, "myProperty"); a3->setDuration(0); a3->setEndValue(44); group.addAnimation(a3); QVariantAnimation *a4 = new QPropertyAnimation(&o, "myOtherProperty"); a4->setDuration(250); a4->setEndValue(75); group.addAnimation(a4); QVariantAnimation *a5 = new QPropertyAnimation(&o2, "myProperty"); a5->setDuration(0); a5->setEndValue(12); group.addAnimation(a5); QCOMPARE(o.property("myProperty").toInt(), 42); QCOMPARE(o.property("myOtherProperty").toInt(), 13); QCOMPARE(o2.property("myProperty").toInt(), 42); QCOMPARE(o2.property("myOtherProperty").toInt(), 13); group.start(); QCOMPARE(o.property("myProperty").toInt(), 43); QCOMPARE(o.property("myOtherProperty").toInt(), 13); QCOMPARE(o2.property("myProperty").toInt(), 42); QCOMPARE(o2.property("myOtherProperty").toInt(), 13); QTest::qWait(50); int o2val = o2.property("myOtherProperty").toInt(); QVERIFY(o2val > 13); QVERIFY(o2val < 31); QCOMPARE(o.property("myProperty").toInt(), 43); QCOMPARE(o.property("myOtherProperty").toInt(), 13); QTest::qWait(500); QCOMPARE(o.property("myProperty").toInt(), 44); QCOMPARE(o2.property("myProperty").toInt(), 42); QCOMPARE(o2.property("myOtherProperty").toInt(), 31); QCOMPARE(a1->state(), QAnimationGroup::Stopped); QCOMPARE(a2->state(), QAnimationGroup::Stopped); QCOMPARE(a3->state(), QAnimationGroup::Stopped); QCOMPARE(a4->state(), QAnimationGroup::Running); QCOMPARE(a5->state(), QAnimationGroup::Stopped); QCOMPARE(group.state(), QAnimationGroup::Running); QTest::qWait(500); QTRY_COMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(o.property("myProperty").toInt(), 44); QCOMPARE(o.property("myOtherProperty").toInt(), 75); QCOMPARE(o2.property("myProperty").toInt(), 12); QCOMPARE(o2.property("myOtherProperty").toInt(), 31); QCOMPARE(a1->state(), QAnimationGroup::Stopped); QCOMPARE(a2->state(), QAnimationGroup::Stopped); QCOMPARE(a3->state(), QAnimationGroup::Stopped); QCOMPARE(a4->state(), QAnimationGroup::Stopped); QCOMPARE(a5->state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::propagateGroupUpdateToChildren() { // this test verifies if group state changes are updating its children correctly QSequentialAnimationGroup group; QObject o; o.setProperty("ole", 42); QCOMPARE(o.property("ole").toInt(), 42); QPropertyAnimation anim1(&o, "ole"); anim1.setEndValue(43); anim1.setDuration(100); QVERIFY(!anim1.currentValue().isValid()); QCOMPARE(anim1.currentValue().toInt(), 0); QCOMPARE(o.property("ole").toInt(), 42); TestAnimation anim2; anim2.setStartValue(0); anim2.setEndValue(100); anim2.setDuration(200); QVERIFY(anim2.currentValue().isValid()); QCOMPARE(anim2.currentValue().toInt(), 0); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Stopped); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); group.addAnimation(&anim1); group.addAnimation(&anim2); group.start(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim1.state(), QAnimationGroup::Running); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); group.pause(); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(anim1.state(), QAnimationGroup::Paused); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); group.stop(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Stopped); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::updateChildrenWithRunningGroup() { // assert that its possible to modify a child's state directly while their group is running QSequentialAnimationGroup group; TestAnimation anim; anim.setStartValue(0); anim.setEndValue(100); anim.setDuration(200); QSignalSpy groupStateChangedSpy(&group, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSignalSpy childStateChangedSpy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QCOMPARE(groupStateChangedSpy.count(), 0); QCOMPARE(childStateChangedSpy.count(), 0); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim.state(), QAnimationGroup::Stopped); group.addAnimation(&anim); group.start(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim.state(), QAnimationGroup::Running); QCOMPARE(groupStateChangedSpy.count(), 1); QCOMPARE(childStateChangedSpy.count(), 1); QCOMPARE(qVariantValue(groupStateChangedSpy.at(0).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(childStateChangedSpy.at(0).at(1)), QAnimationGroup::Running); // starting directly a running child will not have any effect anim.start(); QCOMPARE(groupStateChangedSpy.count(), 1); QCOMPARE(childStateChangedSpy.count(), 1); anim.pause(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim.state(), QAnimationGroup::Paused); // in the animation stops directly, the group will still be running anim.stop(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim.state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::deleteChildrenWithRunningGroup() { // test if children can be activated when their group is stopped QSequentialAnimationGroup group; QVariantAnimation *anim1 = new TestAnimation; anim1->setStartValue(0); anim1->setEndValue(100); anim1->setDuration(200); group.addAnimation(anim1); QCOMPARE(group.duration(), anim1->duration()); group.start(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim1->state(), QAnimationGroup::Running); QTest::qWait(50); QVERIFY(group.currentTime() > 0); delete anim1; QCOMPARE(group.animationCount(), 0); QCOMPARE(group.duration(), 0); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(group.currentTime(), 0); //that's the invariant } void tst_QSequentialAnimationGroup::startChildrenWithStoppedGroup() { // test if children can be activated when their group is stopped QSequentialAnimationGroup group; TestAnimation anim1; anim1.setStartValue(0); anim1.setEndValue(100); anim1.setDuration(200); TestAnimation anim2; anim2.setStartValue(0); anim2.setEndValue(100); anim2.setDuration(200); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Stopped); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); group.addAnimation(&anim1); group.addAnimation(&anim2); group.stop(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Stopped); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); anim1.start(); anim2.start(); anim2.pause(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Running); QCOMPARE(anim2.state(), QAnimationGroup::Paused); } void tst_QSequentialAnimationGroup::stopGroupWithRunningChild() { // children that started independently will not be affected by a group stop QSequentialAnimationGroup group; TestAnimation anim1; anim1.setStartValue(0); anim1.setEndValue(100); anim1.setDuration(200); TestAnimation anim2; anim2.setStartValue(0); anim2.setEndValue(100); anim2.setDuration(200); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Stopped); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); group.addAnimation(&anim1); group.addAnimation(&anim2); anim1.start(); anim2.start(); anim2.pause(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Running); QCOMPARE(anim2.state(), QAnimationGroup::Paused); group.stop(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Running); QCOMPARE(anim2.state(), QAnimationGroup::Paused); anim1.stop(); anim2.stop(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1.state(), QAnimationGroup::Stopped); QCOMPARE(anim2.state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::startGroupWithRunningChild() { // as the group has precedence over its children, starting a group will restart all the children QSequentialAnimationGroup group; TestAnimation *anim1 = new TestAnimation(); anim1->setStartValue(0); anim1->setEndValue(100); anim1->setDuration(200); TestAnimation *anim2 = new TestAnimation(); anim2->setStartValue(0); anim2->setEndValue(100); anim2->setDuration(200); QSignalSpy stateChangedSpy1(anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QSignalSpy stateChangedSpy2(anim2, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QCOMPARE(stateChangedSpy1.count(), 0); QCOMPARE(stateChangedSpy2.count(), 0); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1->state(), QAnimationGroup::Stopped); QCOMPARE(anim2->state(), QAnimationGroup::Stopped); group.addAnimation(anim1); group.addAnimation(anim2); anim1->start(); anim2->start(); anim2->pause(); QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimation::Running))); QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Paused))); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1->state(), QAnimationGroup::Running); QCOMPARE(anim2->state(), QAnimationGroup::Paused); group.start(); QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Stopped << QAbstractAnimation::Running))); QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimation::Running << QAbstractAnimation::Paused))); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim1->state(), QAnimationGroup::Running); QCOMPARE(anim2->state(), QAnimationGroup::Paused); QTest::qWait(300); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim1->state(), QAnimationGroup::Stopped); QCOMPARE(anim2->state(), QAnimationGroup::Running); QCOMPARE(stateChangedSpy2.count(), 4); QCOMPARE(qVariantValue(stateChangedSpy2.at(2).at(1)), QAnimationGroup::Stopped); QCOMPARE(qVariantValue(stateChangedSpy2.at(3).at(1)), QAnimationGroup::Running); group.stop(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(anim1->state(), QAnimationGroup::Stopped); QCOMPARE(anim2->state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::zeroDurationAnimation() { QSequentialAnimationGroup group; TestAnimation *anim1 = new TestAnimation(); anim1->setStartValue(0); anim1->setEndValue(100); anim1->setDuration(0); TestAnimation *anim2 = new TestAnimation(); anim2->setStartValue(0); anim2->setEndValue(100); anim2->setDuration(100); AnimationObject o1; QPropertyAnimation *anim3 = new QPropertyAnimation(&o1, "value"); anim3->setEndValue(100); anim3->setDuration(0); QSignalSpy stateChangedSpy(anim1, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); group.addAnimation(anim1); group.addAnimation(anim2); group.addAnimation(anim3); group.setLoopCount(2); group.start(); QCOMPARE(stateChangedSpy.count(), 2); QCOMPARE(qVariantValue(stateChangedSpy.at(0).at(1)), QAnimationGroup::Running); QCOMPARE(qVariantValue(stateChangedSpy.at(1).at(1)), QAnimationGroup::Stopped); QCOMPARE(anim1->state(), QAnimationGroup::Stopped); QCOMPARE(anim2->state(), QAnimationGroup::Running); QCOMPARE(group.state(), QAnimationGroup::Running); //now let's try to seek to the next loop group.setCurrentTime(group.duration() + 1); QCOMPARE(anim1->state(), QAnimationGroup::Stopped); QCOMPARE(anim2->state(), QAnimationGroup::Running); QCOMPARE(anim3->state(), QAnimationGroup::Stopped); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(o1.value(), 100); //anim3 should have been run } void tst_QSequentialAnimationGroup::stopUncontrolledAnimations() { QSequentialAnimationGroup group; AnimationObject o1; UncontrolledAnimation notTimeDriven(&o1, "value"); QCOMPARE(notTimeDriven.totalDuration(), -1); TestAnimation loopsForever; loopsForever.setStartValue(0); loopsForever.setEndValue(100); loopsForever.setDuration(100); loopsForever.setLoopCount(-1); group.addAnimation(¬TimeDriven); group.addAnimation(&loopsForever); group.start(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running); QCOMPARE(loopsForever.state(), QAnimationGroup::Stopped); notTimeDriven.stop(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped); QCOMPARE(loopsForever.state(), QAnimationGroup::Running); loopsForever.stop(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped); QCOMPARE(loopsForever.state(), QAnimationGroup::Stopped); } void tst_QSequentialAnimationGroup::finishWithUncontrolledAnimation() { AnimationObject o1; //1st case: //first we test a group with one uncontrolled animation QSequentialAnimationGroup group; UncontrolledAnimation notTimeDriven(&o1, "value", &group); QSignalSpy spy(&group, SIGNAL(finished())); group.start(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running); QCOMPARE(group.currentTime(), 0); QCOMPARE(notTimeDriven.currentTime(), 0); QTest::qWait(300); //wait for the end of notTimeDriven QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped); const int actualDuration = notTimeDriven.currentTime(); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(group.currentTime(), actualDuration); QCOMPARE(spy.count(), 1); //2nd case: // lets make sure the seeking will work again spy.clear(); QPropertyAnimation anim(&group); QSignalSpy animStateChangedSpy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); group.setCurrentTime(300); QCOMPARE(group.state(), QAnimationGroup::Stopped); QCOMPARE(notTimeDriven.currentTime(), actualDuration); QCOMPARE(group.currentAnimation(), static_cast(&anim)); //3rd case: //now let's add a perfectly defined animation at the end QCOMPARE(animStateChangedSpy.count(), 0); group.start(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(notTimeDriven.state(), QAnimationGroup::Running); QCOMPARE(group.currentTime(), 0); QCOMPARE(notTimeDriven.currentTime(), 0); QCOMPARE(animStateChangedSpy.count(), 0); QTest::qWait(300); //wait for the end of notTimeDriven QCOMPARE(notTimeDriven.state(), QAnimationGroup::Stopped); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim.state(), QAnimationGroup::Running); QCOMPARE(group.currentAnimation(), static_cast(&anim)); QCOMPARE(animStateChangedSpy.count(), 1); QTest::qWait(300); //wait for the end of anim QCOMPARE(anim.state(), QAnimationGroup::Stopped); QCOMPARE(anim.currentTime(), anim.duration()); //we should simply be at the end QCOMPARE(spy.count(), 1); QCOMPARE(animStateChangedSpy.count(), 2); QCOMPARE(group.currentTime(), notTimeDriven.currentTime() + anim.currentTime()); } void tst_QSequentialAnimationGroup::addRemoveAnimation() { //this test is specific to the sequential animation group QSequentialAnimationGroup group; QCOMPARE(group.duration(), 0); QCOMPARE(group.currentTime(), 0); QAbstractAnimation *anim1 = new QPropertyAnimation; group.addAnimation(anim1); QCOMPARE(group.duration(), 250); QCOMPARE(group.currentTime(), 0); QCOMPARE(group.currentAnimation(), anim1); //let's append an animation QAbstractAnimation *anim2 = new QPropertyAnimation; group.addAnimation(anim2); QCOMPARE(group.duration(), 500); QCOMPARE(group.currentTime(), 0); QCOMPARE(group.currentAnimation(), anim1); //let's prepend an animation QAbstractAnimation *anim0 = new QPropertyAnimation; group.insertAnimationAt(0, anim0); QCOMPARE(group.duration(), 750); QCOMPARE(group.currentTime(), 0); QCOMPARE(group.currentAnimation(), anim0); //anim0 has become the new currentAnimation group.setCurrentTime(300); //anim0 | anim1 | anim2 QCOMPARE(group.currentTime(), 300); QCOMPARE(group.currentAnimation(), anim1); QCOMPARE(anim1->currentTime(), 50); group.removeAnimation(anim0); //anim1 | anim2 QCOMPARE(group.currentTime(), 50); QCOMPARE(group.currentAnimation(), anim1); QCOMPARE(anim1->currentTime(), 50); group.setCurrentTime(0); group.insertAnimationAt(0, anim0); //anim0 | anim1 | anim2 group.setCurrentTime(300); QCOMPARE(group.currentTime(), 300); QCOMPARE(group.currentAnimation(), anim1); QCOMPARE(anim1->currentTime(), 50); group.removeAnimation(anim1); //anim0 | anim2 QCOMPARE(group.currentTime(), 250); QCOMPARE(group.currentAnimation(), anim2); QCOMPARE(anim0->currentTime(), 250); } void tst_QSequentialAnimationGroup::currentAnimation() { QSequentialAnimationGroup group; QVERIFY(group.currentAnimation() == 0); QPropertyAnimation anim; anim.setDuration(0); group.addAnimation(&anim); QCOMPARE(group.currentAnimation(), static_cast(&anim)); } void tst_QSequentialAnimationGroup::currentAnimationWithZeroDuration() { QSequentialAnimationGroup group; QVERIFY(group.currentAnimation() == 0); QPropertyAnimation zero1; zero1.setDuration(0); QPropertyAnimation zero2; zero2.setDuration(0); QPropertyAnimation anim; QPropertyAnimation zero3; zero3.setDuration(0); QPropertyAnimation zero4; zero4.setDuration(0); group.addAnimation(&zero1); group.addAnimation(&zero2); group.addAnimation(&anim); group.addAnimation(&zero3); group.addAnimation(&zero4); QCOMPARE(group.currentAnimation(), static_cast(&zero1)); group.setCurrentTime(0); QCOMPARE(group.currentAnimation(), static_cast(&anim)); group.setCurrentTime(group.duration()); QCOMPARE(group.currentAnimation(), static_cast(&zero4)); group.setDirection(QAbstractAnimation::Backward); group.setCurrentTime(0); QCOMPARE(group.currentAnimation(), static_cast(&zero1)); group.setCurrentTime(group.duration()); QCOMPARE(group.currentAnimation(), static_cast(&anim)); } void tst_QSequentialAnimationGroup::insertAnimation() { QSequentialAnimationGroup group; group.setLoopCount(2); QPropertyAnimation *anim = new QPropertyAnimation(&group); QCOMPARE(group.duration(), anim->duration()); group.setCurrentTime(300); QCOMPARE(group.currentLoop(), 1); //this will crash if the sequential group calls duration on the created animation new QPropertyAnimation(&group); } class SequentialAnimationGroup : public QSequentialAnimationGroup { Q_OBJECT public slots: void clearAnimations() { QSequentialAnimationGroup::clearAnimations(); } void refill() { stop(); clearAnimations(); new QPropertyAnimation(this); start(); } }; void tst_QSequentialAnimationGroup::clearAnimations() { SequentialAnimationGroup group; QPointer anim1 = new QPropertyAnimation(&group); group.connect(anim1, SIGNAL(finished()), SLOT(clearAnimations())); new QPropertyAnimation(&group); QCOMPARE(group.animationCount(), 2); group.start(); QTest::qWait(anim1->duration() + 100); QCOMPARE(group.animationCount(), 0); QCOMPARE(group.state(), QAbstractAnimation::Stopped); QCOMPARE(group.currentTime(), 0); anim1 = new QPropertyAnimation(&group); group.connect(anim1, SIGNAL(finished()), SLOT(refill())); group.start(); QTest::qWait(anim1->duration() + 100); QVERIFY(anim1 == 0); //anim1 should have been deleted QCOMPARE(group.state(), QAbstractAnimation::Running); } void tst_QSequentialAnimationGroup::pauseResume() { QObject dummy; dummy.setProperty("foo", 0); QParallelAnimationGroup group; QPropertyAnimation *anim = new QPropertyAnimation(&dummy, "foo", &group); anim->setDuration(250); anim->setEndValue(250); QSignalSpy spy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QCOMPARE(group.duration(), 250); group.start(); QTest::qWait(100); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(anim->state(), QAnimationGroup::Running); QCOMPARE(spy.count(), 1); spy.clear(); const int currentTime = group.currentTime(); QCOMPARE(anim->currentTime(), currentTime); group.pause(); QCOMPARE(group.state(), QAnimationGroup::Paused); QCOMPARE(group.currentTime(), currentTime); QCOMPARE(anim->state(), QAnimationGroup::Paused); QCOMPARE(anim->currentTime(), currentTime); QCOMPARE(spy.count(), 1); spy.clear(); group.resume(); QCOMPARE(group.state(), QAnimationGroup::Running); QCOMPARE(group.currentTime(), currentTime); QCOMPARE(anim->state(), QAnimationGroup::Running); QCOMPARE(anim->currentTime(), currentTime); QCOMPARE(spy.count(), 1); } QTEST_MAIN(tst_QSequentialAnimationGroup) #include "tst_qsequentialanimationgroup.moc"