aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/declarative
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2012-02-03 12:26:37 +1000
committerQt by Nokia <qt-info@nokia.com>2012-02-07 05:32:47 +0100
commitce3dee765c858a0b573d468ef8fee6b838e576d1 (patch)
treeb7026a061b0b58bac6af30eaab6e610c5ebeb504 /tests/auto/declarative
parent0ca9d3f0f720e1933379ef40bc5c29253e21cba0 (diff)
Add and use new animation backend.
The new backend improves performance, and allows us to create multiple running animation jobs from a single Transition. It is based off of the existing Qt animation framework. Change-Id: Id1d0162f6e5c65bf31267f3f9f2042c354375d57 Reviewed-by: Yunqiao Yin <charles.yin@nokia.com>
Diffstat (limited to 'tests/auto/declarative')
-rw-r--r--tests/auto/declarative/animation/animation.pro7
-rw-r--r--tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro5
-rw-r--r--tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp229
-rw-r--r--tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro5
-rw-r--r--tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp310
-rw-r--r--tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro5
-rw-r--r--tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp931
-rw-r--r--tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro5
-rw-r--r--tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp470
-rw-r--r--tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro5
-rw-r--r--tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp1617
-rw-r--r--tests/auto/declarative/declarative.pro1
12 files changed, 3590 insertions, 0 deletions
diff --git a/tests/auto/declarative/animation/animation.pro b/tests/auto/declarative/animation/animation.pro
new file mode 100644
index 0000000000..a9c0cee309
--- /dev/null
+++ b/tests/auto/declarative/animation/animation.pro
@@ -0,0 +1,7 @@
+TEMPLATE=subdirs
+SUBDIRS=\
+ qabstractanimationjob \
+ qanimationgroupjob \
+ qparallelanimationgroupjob \
+ qpauseanimationjob \
+ qsequentialanimationgroupjob
diff --git a/tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro b/tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro
new file mode 100644
index 0000000000..db8649bbb9
--- /dev/null
+++ b/tests/auto/declarative/animation/qabstractanimationjob/qabstractanimationjob.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase parallel_test
+macx:CONFIG -= app_bundle
+TARGET = tst_qabstractanimationjob
+QT = core-private declarative-private testlib
+SOURCES = tst_qabstractanimationjob.cpp
diff --git a/tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp b/tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp
new file mode 100644
index 0000000000..772605d494
--- /dev/null
+++ b/tests/auto/declarative/animation/qabstractanimationjob/tst_qabstractanimationjob.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtDeclarative/private/qabstractanimationjob_p.h>
+#include <QtDeclarative/private/qanimationgroupjob_p.h>
+#include <QtTest>
+
+class tst_QAbstractAnimationJob : public QObject
+{
+ Q_OBJECT
+private slots:
+ void construction();
+ void destruction();
+ void currentLoop();
+ void currentLoopTime();
+ void currentTime();
+ void direction();
+ void group();
+ void loopCount();
+ void state();
+ void totalDuration();
+ void avoidJumpAtStart();
+ void avoidJumpAtStartWithStop();
+ void avoidJumpAtStartWithRunning();
+};
+
+class TestableQAbstractAnimation : public QAbstractAnimationJob
+{
+public:
+ TestableQAbstractAnimation() : m_duration(10) {}
+ virtual ~TestableQAbstractAnimation() {};
+
+ int duration() const { return m_duration; }
+ virtual void updateCurrentTime(int) {}
+
+ void setDuration(int duration) { m_duration = duration; }
+private:
+ int m_duration;
+};
+
+class DummyQAnimationGroup : public QAnimationGroupJob
+{
+public:
+ int duration() const { return 10; }
+ virtual void updateCurrentTime(int) {}
+};
+
+void tst_QAbstractAnimationJob::construction()
+{
+ TestableQAbstractAnimation anim;
+}
+
+void tst_QAbstractAnimationJob::destruction()
+{
+ TestableQAbstractAnimation *anim = new TestableQAbstractAnimation;
+ delete anim;
+}
+
+void tst_QAbstractAnimationJob::currentLoop()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.currentLoop(), 0);
+}
+
+void tst_QAbstractAnimationJob::currentLoopTime()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.currentLoopTime(), 0);
+}
+
+void tst_QAbstractAnimationJob::currentTime()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.currentTime(), 0);
+ anim.setCurrentTime(10);
+ QCOMPARE(anim.currentTime(), 10);
+}
+
+void tst_QAbstractAnimationJob::direction()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.direction(), QAbstractAnimationJob::Forward);
+ anim.setDirection(QAbstractAnimationJob::Backward);
+ QCOMPARE(anim.direction(), QAbstractAnimationJob::Backward);
+ anim.setDirection(QAbstractAnimationJob::Forward);
+ QCOMPARE(anim.direction(), QAbstractAnimationJob::Forward);
+}
+
+void tst_QAbstractAnimationJob::group()
+{
+ TestableQAbstractAnimation *anim = new TestableQAbstractAnimation;
+ DummyQAnimationGroup group;
+ group.appendAnimation(anim);
+ QCOMPARE(anim->group(), &group);
+}
+
+void tst_QAbstractAnimationJob::loopCount()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.loopCount(), 1);
+ anim.setLoopCount(10);
+ QCOMPARE(anim.loopCount(), 10);
+}
+
+void tst_QAbstractAnimationJob::state()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.state(), QAbstractAnimationJob::Stopped);
+}
+
+void tst_QAbstractAnimationJob::totalDuration()
+{
+ TestableQAbstractAnimation anim;
+ QCOMPARE(anim.duration(), 10);
+ anim.setLoopCount(5);
+ QCOMPARE(anim.totalDuration(), 50);
+}
+
+void tst_QAbstractAnimationJob::avoidJumpAtStart()
+{
+ TestableQAbstractAnimation anim;
+ anim.setDuration(1000);
+
+ /*
+ the timer shouldn't actually start until we hit the event loop,
+ so the sleep should have no effect
+ */
+ anim.start();
+ QTest::qSleep(300);
+ QCoreApplication::processEvents();
+ QVERIFY(anim.currentTime() < 50);
+}
+
+void tst_QAbstractAnimationJob::avoidJumpAtStartWithStop()
+{
+ TestableQAbstractAnimation anim;
+ anim.setDuration(1000);
+
+ TestableQAbstractAnimation anim2;
+ anim2.setDuration(1000);
+
+ TestableQAbstractAnimation anim3;
+ anim3.setDuration(1000);
+
+ anim.start();
+ QTest::qWait(300);
+ anim.stop();
+
+ /*
+ same test as avoidJumpAtStart, but after there is a
+ running animation that is stopped
+ */
+ anim2.start();
+ QTest::qSleep(300);
+ anim3.start();
+ QCoreApplication::processEvents();
+ QVERIFY(anim2.currentTime() < 50);
+ QVERIFY(anim3.currentTime() < 50);
+}
+
+void tst_QAbstractAnimationJob::avoidJumpAtStartWithRunning()
+{
+ TestableQAbstractAnimation anim;
+ anim.setDuration(2000);
+
+ TestableQAbstractAnimation anim2;
+ anim2.setDuration(1000);
+
+ TestableQAbstractAnimation anim3;
+ anim3.setDuration(1000);
+
+ anim.start();
+ QTest::qWait(300); //make sure timer has started
+
+ /*
+ same test as avoidJumpAtStart, but with an
+ existing running animation
+ */
+ anim2.start();
+ QTest::qSleep(300); //force large delta for next tick
+ anim3.start();
+ QCoreApplication::processEvents();
+ QVERIFY(anim2.currentTime() < 50);
+ QVERIFY(anim3.currentTime() < 50);
+}
+
+
+QTEST_MAIN(tst_QAbstractAnimationJob)
+
+#include "tst_qabstractanimationjob.moc"
diff --git a/tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro b/tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro
new file mode 100644
index 0000000000..b9c9d2921d
--- /dev/null
+++ b/tests/auto/declarative/animation/qanimationgroupjob/qanimationgroupjob.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase parallel_test
+macx:CONFIG -= app_bundle
+TARGET = tst_qanimationgroupjob
+QT = core-private declarative-private testlib
+SOURCES = tst_qanimationgroupjob.cpp
diff --git a/tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp b/tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
new file mode 100644
index 0000000000..196f917a1f
--- /dev/null
+++ b/tests/auto/declarative/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtDeclarative/private/qanimationgroupjob_p.h>
+#include <QtDeclarative/private/qsequentialanimationgroupjob_p.h>
+#include <QtDeclarative/private/qparallelanimationgroupjob_p.h>
+
+Q_DECLARE_METATYPE(QAbstractAnimationJob::State)
+
+class tst_QAnimationGroupJob : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ void initTestCase();
+
+private slots:
+ void construction();
+ void emptyGroup();
+ void setCurrentTime();
+ void addChildTwice();
+};
+
+void tst_QAnimationGroupJob::initTestCase()
+{
+ qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State");
+}
+
+void tst_QAnimationGroupJob::construction()
+{
+ QSequentialAnimationGroupJob animationgroup;
+}
+
+class TestableGenericAnimation : public QAbstractAnimationJob
+{
+public:
+ TestableGenericAnimation(int duration = 250) : m_duration(duration) {}
+ int duration() const { return m_duration; }
+
+private:
+ int m_duration;
+};
+
+class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
+{
+ Q_OBJECT
+public:
+ UncontrolledAnimation()
+ : id(0)
+ {
+ }
+
+ int duration() const { return -1; /* not time driven */ }
+
+protected:
+ void timerEvent(QTimerEvent *event)
+ {
+ if (event->timerId() == id)
+ stop();
+ }
+
+ void updateRunning(bool running)
+ {
+ if (running) {
+ id = startTimer(500);
+ } else {
+ killTimer(id);
+ id = 0;
+ }
+ }
+
+private:
+ int id;
+};
+
+class StateChangeListener: public QAnimation2ChangeListener
+{
+public:
+ virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+ {
+ states << newState;
+ }
+
+ int count()
+ {
+ return states.count();
+ }
+
+ QList<QAbstractAnimationJob::State> states;
+};
+
+void tst_QAnimationGroupJob::emptyGroup()
+{
+ QSequentialAnimationGroupJob group;
+ StateChangeListener groupStateChangedSpy;
+ group.addAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ group.start();
+
+ QCOMPARE(groupStateChangedSpy.count(), 2);
+
+ QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(groupStateChangedSpy.states.at(1), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+
+ QTest::ignoreMessage(QtWarningMsg, "QAbstractAnimationJob::pause: Cannot pause a stopped animation");
+ group.pause();
+
+ QCOMPARE(groupStateChangedSpy.count(), 2);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+
+ group.start();
+
+ QCOMPARE(groupStateChangedSpy.states.at(2),
+ QAnimationGroupJob::Running);
+ QCOMPARE(groupStateChangedSpy.states.at(3),
+ QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+
+ group.stop();
+
+ QCOMPARE(groupStateChangedSpy.count(), 4);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QAnimationGroupJob::setCurrentTime()
+{
+ // was originally sequence operating on same object/property
+ QSequentialAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ QAbstractAnimationJob *a1_s_o1 = new TestableGenericAnimation;
+ QAbstractAnimationJob *a2_s_o1 = new TestableGenericAnimation;
+ QAbstractAnimationJob *a3_s_o1 = new TestableGenericAnimation;
+ a2_s_o1->setLoopCount(3);
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a2_s_o1);
+ sequence->appendAnimation(a3_s_o1);
+
+ // was originally sequence operating on different object/properties
+ QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob();
+ QAbstractAnimationJob *a1_s_o2 = new TestableGenericAnimation;
+ QAbstractAnimationJob *a1_s_o3 = new TestableGenericAnimation;
+ sequence2->appendAnimation(a1_s_o2);
+ sequence2->appendAnimation(a1_s_o3);
+
+ // was originally parallel operating on different object/properties
+ QAnimationGroupJob *parallel = new QParallelAnimationGroupJob();
+ QAbstractAnimationJob *a1_p_o1 = new TestableGenericAnimation;
+ QAbstractAnimationJob *a1_p_o2 = new TestableGenericAnimation;
+ QAbstractAnimationJob *a1_p_o3 = new TestableGenericAnimation;
+ a1_p_o2->setLoopCount(3);
+ parallel->appendAnimation(a1_p_o1);
+ parallel->appendAnimation(a1_p_o2);
+ parallel->appendAnimation(a1_p_o3);
+
+ QAbstractAnimationJob *notTimeDriven = new UncontrolledAnimation;
+ QCOMPARE(notTimeDriven->totalDuration(), -1);
+
+ QAbstractAnimationJob *loopsForever = new TestableGenericAnimation;
+ loopsForever->setLoopCount(-1);
+ QCOMPARE(loopsForever->totalDuration(), -1);
+
+ QParallelAnimationGroupJob group;
+ group.appendAnimation(sequence);
+ group.appendAnimation(sequence2);
+ group.appendAnimation(parallel);
+ group.appendAnimation(notTimeDriven);
+ group.appendAnimation(loopsForever);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(parallel->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_p_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_p_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_p_o3->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.currentLoopTime(), 1);
+ QCOMPARE(sequence->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+ QCOMPARE(a1_p_o1->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o2->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o3->currentLoopTime(), 1);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 1);
+ QCOMPARE(loopsForever->currentLoopTime(), 1);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentLoopTime(), 250);
+ QCOMPARE(sequence->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+ QCOMPARE(a1_p_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_p_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_p_o2->currentLoop(), 1);
+ QCOMPARE(a1_p_o3->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 250);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+ QCOMPARE(loopsForever->currentLoop(), 1);
+ QCOMPARE(sequence->currentAnimation(), a2_s_o1);
+
+ // Current time = 251
+ group.setCurrentTime(251);
+ QCOMPARE(group.currentLoopTime(), 251);
+ QCOMPARE(sequence->currentLoopTime(), 251);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a2_s_o1->currentLoop(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(sequence2->currentLoopTime(), 251);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_p_o2->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o2->currentLoop(), 1);
+ QCOMPARE(a1_p_o3->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 251);
+ QCOMPARE(loopsForever->currentLoopTime(), 1);
+ QCOMPARE(sequence->currentAnimation(), a2_s_o1);
+}
+
+void tst_QAnimationGroupJob::addChildTwice()
+{
+ QAbstractAnimationJob *subGroup;
+ QAbstractAnimationJob *subGroup2;
+ QAnimationGroupJob *parent = new QSequentialAnimationGroupJob();
+
+ subGroup = new QAbstractAnimationJob;
+ parent->appendAnimation(subGroup);
+ parent->appendAnimation(subGroup);
+ QVERIFY(parent->firstChild() && !parent->firstChild()->nextSibling());
+
+ parent->clear();
+
+ QVERIFY(!parent->firstChild());
+
+ // adding the same item twice to a group will remove the item from its current position
+ // and append it to the end
+ subGroup = new QAbstractAnimationJob;
+ parent->appendAnimation(subGroup);
+ subGroup2 = new QAbstractAnimationJob;
+ parent->appendAnimation(subGroup2);
+
+ QCOMPARE(parent->firstChild(), subGroup);
+ QCOMPARE(parent->lastChild(), subGroup2);
+
+ parent->appendAnimation(subGroup);
+
+ QCOMPARE(parent->firstChild(), subGroup2);
+ QCOMPARE(parent->lastChild(), subGroup);
+
+ delete parent;
+}
+
+QTEST_MAIN(tst_QAnimationGroupJob)
+#include "tst_qanimationgroupjob.moc"
diff --git a/tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro b/tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro
new file mode 100644
index 0000000000..332fa4554b
--- /dev/null
+++ b/tests/auto/declarative/animation/qparallelanimationgroupjob/qparallelanimationgroupjob.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+macx:CONFIG -= app_bundle
+TARGET = tst_qparallelanimationgroupjob
+QT = core-private gui declarative-private testlib
+SOURCES = tst_qparallelanimationgroupjob.cpp
diff --git a/tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp b/tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
new file mode 100644
index 0000000000..52c0ff284e
--- /dev/null
+++ b/tests/auto/declarative/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
@@ -0,0 +1,931 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtDeclarative/private/qparallelanimationgroupjob_p.h>
+
+Q_DECLARE_METATYPE(QAbstractAnimationJob::State)
+
+class tst_QParallelAnimationGroupJob : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ void initTestCase();
+
+private slots:
+ void construction();
+ void setCurrentTime();
+ void stateChanged();
+ void clearGroup();
+ void propagateGroupUpdateToChildren();
+ void updateChildrenWithRunningGroup();
+ void deleteChildrenWithRunningGroup();
+ void startChildrenWithStoppedGroup();
+ void stopGroupWithRunningChild();
+ void startGroupWithRunningChild();
+ void zeroDurationAnimation();
+ void stopUncontrolledAnimations();
+ void loopCount_data();
+ void loopCount();
+ void addAndRemoveDuration();
+ void pauseResume();
+
+ void crashWhenRemovingUncontrolledAnimation();
+};
+
+void tst_QParallelAnimationGroupJob::initTestCase()
+{
+ qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State");
+#if defined(Q_OS_MAC) || defined(Q_OS_WINCE)
+ // give the mac/wince app start event queue time to clear
+ QTest::qWait(1000);
+#endif
+}
+
+void tst_QParallelAnimationGroupJob::construction()
+{
+ QParallelAnimationGroupJob animationgroup;
+}
+
+class TestAnimation : public QAbstractAnimationJob
+{
+public:
+ TestAnimation(int duration = 250) : m_duration(duration) {}
+ int duration() const { return m_duration; }
+
+private:
+ int m_duration;
+};
+
+class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
+{
+ Q_OBJECT
+public:
+ UncontrolledAnimation()
+ : id(0)
+ {
+ }
+
+ int duration() const { return -1; /* not time driven */ }
+
+protected:
+ void timerEvent(QTimerEvent *event)
+ {
+ if (event->timerId() == id)
+ stop();
+ }
+
+ void updateRunning(bool running)
+ {
+ if (running) {
+ id = startTimer(500);
+ } else {
+ killTimer(id);
+ id = 0;
+ }
+ }
+
+private:
+ int id;
+};
+
+class StateChangeListener: public QAnimation2ChangeListener
+{
+public:
+ virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+ {
+ states << newState;
+ }
+
+ void clear() { states.clear(); }
+ int count() { return states.count(); }
+
+ QList<QAbstractAnimationJob::State> states;
+};
+
+class FinishedListener: public QAnimation2ChangeListener
+{
+public:
+ FinishedListener() : m_count(0) {}
+
+ virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; }
+ void clear() { m_count = 0; }
+ int count() { return m_count; }
+
+private:
+ int m_count;
+};
+
+void tst_QParallelAnimationGroupJob::setCurrentTime()
+{
+ // originally was parallel operating on different object/properties
+ QAnimationGroupJob *parallel = new QParallelAnimationGroupJob();
+ TestAnimation *a1_p_o1 = new TestAnimation;
+ TestAnimation *a1_p_o2 = new TestAnimation;
+ TestAnimation *a1_p_o3 = new TestAnimation;
+ a1_p_o2->setLoopCount(3);
+ parallel->appendAnimation(a1_p_o1);
+ parallel->appendAnimation(a1_p_o2);
+ parallel->appendAnimation(a1_p_o3);
+
+ UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation;
+ QCOMPARE(notTimeDriven->totalDuration(), -1);
+
+ TestAnimation *loopsForever = new TestAnimation;
+ loopsForever->setLoopCount(-1);
+ QCOMPARE(loopsForever->totalDuration(), -1);
+
+ QParallelAnimationGroupJob group;
+ group.appendAnimation(parallel);
+ group.appendAnimation(notTimeDriven);
+ group.appendAnimation(loopsForever);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(parallel->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_p_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_p_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_p_o3->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.currentLoopTime(), 1);
+ QCOMPARE(a1_p_o1->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o2->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o3->currentLoopTime(), 1);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 1);
+ QCOMPARE(loopsForever->currentLoopTime(), 1);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentLoopTime(), 250);
+ QCOMPARE(a1_p_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_p_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_p_o2->currentLoop(), 1);
+ QCOMPARE(a1_p_o3->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 250);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+ QCOMPARE(loopsForever->currentLoop(), 1);
+
+ // Current time = 251
+ group.setCurrentTime(251);
+ QCOMPARE(group.currentLoopTime(), 251);
+ QCOMPARE(a1_p_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_p_o2->currentLoopTime(), 1);
+ QCOMPARE(a1_p_o2->currentLoop(), 1);
+ QCOMPARE(a1_p_o3->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 251);
+ QCOMPARE(loopsForever->currentLoopTime(), 1);
+}
+
+void tst_QParallelAnimationGroupJob::stateChanged()
+{
+ //this ensures that the correct animations are started when starting the group
+ TestAnimation *anim1 = new TestAnimation(1000);
+ TestAnimation *anim2 = new TestAnimation(2000);
+ TestAnimation *anim3 = new TestAnimation(3000);
+ TestAnimation *anim4 = new TestAnimation(3000);
+
+ QParallelAnimationGroupJob group;
+ group.appendAnimation(anim1);
+ group.appendAnimation(anim2);
+ group.appendAnimation(anim3);
+ group.appendAnimation(anim4);
+
+ StateChangeListener spy1;
+ anim1->addAnimationChangeListener(&spy1, QAbstractAnimationJob::StateChange);
+ StateChangeListener spy2;
+ anim2->addAnimationChangeListener(&spy2, QAbstractAnimationJob::StateChange);
+ StateChangeListener spy3;
+ anim3->addAnimationChangeListener(&spy3, QAbstractAnimationJob::StateChange);
+ StateChangeListener spy4;
+ anim4->addAnimationChangeListener(&spy4, QAbstractAnimationJob::StateChange);
+
+ //first; let's start forward
+ group.start();
+ //all the animations should be started
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy1.states.last(), TestAnimation::Running);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy2.states.last(), TestAnimation::Running);
+ QCOMPARE(spy3.count(), 1);
+ QCOMPARE(spy3.states.last(), TestAnimation::Running);
+ QCOMPARE(spy4.count(), 1);
+ QCOMPARE(spy4.states.last(), TestAnimation::Running);
+
+ group.setCurrentTime(1500); //anim1 should be finished
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy1.states.last(), TestAnimation::Stopped);
+ QCOMPARE(spy2.count(), 1); //no change
+ QCOMPARE(spy3.count(), 1); //no change
+ QCOMPARE(spy4.count(), 1); //no change
+
+ group.setCurrentTime(2500); //anim2 should be finished
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy1.count(), 2); //no change
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy2.states.last(), TestAnimation::Stopped);
+ QCOMPARE(spy3.count(), 1); //no change
+ QCOMPARE(spy4.count(), 1); //no change
+
+ group.setCurrentTime(3500); //everything should be finished
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(spy1.count(), 2); //no change
+ QCOMPARE(spy2.count(), 2); //no change
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy3.states.last(), TestAnimation::Stopped);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy4.states.last(), TestAnimation::Stopped);
+
+ //cleanup
+ spy1.clear();
+ spy2.clear();
+ spy3.clear();
+ spy4.clear();
+
+ //now let's try to reverse that
+ group.setDirection(QAbstractAnimationJob::Backward);
+ group.start();
+
+ //only anim3 and anim4 should be started
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy1.count(), 0);
+ QCOMPARE(spy2.count(), 0);
+ QCOMPARE(spy3.count(), 1);
+ QCOMPARE(spy3.states.last(), TestAnimation::Running);
+ QCOMPARE(spy4.count(), 1);
+ QCOMPARE(spy4.states.last(), TestAnimation::Running);
+
+ group.setCurrentTime(1500); //anim2 should be started
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy1.count(), 0); //no change
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy2.states.last(), TestAnimation::Running);
+ QCOMPARE(spy3.count(), 1); //no change
+ QCOMPARE(spy4.count(), 1); //no change
+
+ group.setCurrentTime(500); //anim1 is finally also started
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy1.states.last(), TestAnimation::Running);
+ QCOMPARE(spy2.count(), 1); //no change
+ QCOMPARE(spy3.count(), 1); //no change
+ QCOMPARE(spy4.count(), 1); //no change
+
+ group.setCurrentTime(0); //everything should be stopped
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy1.states.last(), TestAnimation::Stopped);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy2.states.last(), TestAnimation::Stopped);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy3.states.last(), TestAnimation::Stopped);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy4.states.last(), TestAnimation::Stopped);
+}
+
+void tst_QParallelAnimationGroupJob::clearGroup()
+{
+ QParallelAnimationGroupJob group;
+ static const int animationCount = 10;
+
+ for (int i = 0; i < animationCount; ++i) {
+ group.appendAnimation(new QParallelAnimationGroupJob);
+ }
+
+ int count = 0;
+ for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling())
+ ++count;
+ QCOMPARE(count, animationCount);
+
+ group.clear();
+
+ QVERIFY(!group.firstChild() && !group.lastChild());
+ QCOMPARE(group.currentLoopTime(), 0);
+}
+
+void tst_QParallelAnimationGroupJob::propagateGroupUpdateToChildren()
+{
+ // this test verifies if group state changes are updating its children correctly
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(100);
+ TestAnimation anim2(200);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Running);
+
+ group.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QParallelAnimationGroupJob::updateChildrenWithRunningGroup()
+{
+ // assert that its possible to modify a child's state directly while their group is running
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim(200);
+
+ StateChangeListener groupStateChangedSpy;
+ group.addAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange);
+ StateChangeListener childStateChangedSpy;
+ anim.addAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ QCOMPARE(groupStateChangedSpy.count(), 0);
+ QCOMPARE(childStateChangedSpy.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Running);
+
+ QCOMPARE(groupStateChangedSpy.count(), 1);
+ QCOMPARE(childStateChangedSpy.count(), 1);
+
+ QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(childStateChangedSpy.states.at(0), QAnimationGroupJob::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(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Paused);
+
+ // in the animation stops directly, the group will still be running
+ anim.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Stopped);
+
+ //cleanup
+ group.removeAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange);
+ anim.removeAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QParallelAnimationGroupJob::deleteChildrenWithRunningGroup()
+{
+ // test if children can be activated when their group is stopped
+ QParallelAnimationGroupJob group;
+
+ TestAnimation *anim1 = new TestAnimation(200);
+ group.appendAnimation(anim1);
+
+ QCOMPARE(group.duration(), anim1->duration());
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
+
+ QTest::qWait(80);
+ QVERIFY(group.currentLoopTime() > 0);
+
+ delete anim1;
+ QVERIFY(!group.firstChild());
+ QCOMPARE(group.duration(), 0);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(group.currentLoopTime(), 0); //that's the invariant
+}
+
+void tst_QParallelAnimationGroupJob::startChildrenWithStoppedGroup()
+{
+ // test if children can be activated when their group is stopped
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(200);
+ TestAnimation anim2(200);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+}
+
+void tst_QParallelAnimationGroupJob::stopGroupWithRunningChild()
+{
+ // children that started independently will not be affected by a group stop
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(200);
+ TestAnimation anim2(200);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+
+ anim1.stop();
+ anim2.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QParallelAnimationGroupJob::startGroupWithRunningChild()
+{
+ // as the group has precedence over its children, starting a group will restart all the children
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(200);
+ TestAnimation anim2(200);
+
+ StateChangeListener stateChangedSpy1;
+ anim1.addAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange);
+ StateChangeListener stateChangedSpy2;
+ anim2.addAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange);
+
+ QCOMPARE(stateChangedSpy1.count(), 0);
+ QCOMPARE(stateChangedSpy2.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(stateChangedSpy1.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(stateChangedSpy2.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(stateChangedSpy2.states.at(1), QAnimationGroupJob::Paused);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+
+ group.start();
+
+ QCOMPARE(stateChangedSpy1.count(), 3);
+ QCOMPARE(stateChangedSpy1.states.at(1), QAnimationGroupJob::Stopped);
+ QCOMPARE(stateChangedSpy1.states.at(2), QAnimationGroupJob::Running);
+
+ QCOMPARE(stateChangedSpy2.count(), 4);
+ QCOMPARE(stateChangedSpy2.states.at(2), QAnimationGroupJob::Stopped);
+ QCOMPARE(stateChangedSpy2.states.at(3), QAnimationGroupJob::Running);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Running);
+
+ //cleanup
+ anim1.removeAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange);
+ anim2.removeAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QParallelAnimationGroupJob::zeroDurationAnimation()
+{
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(0);
+ TestAnimation anim2(100);
+ TestAnimation anim3(10);
+
+ StateChangeListener stateChangedSpy1;
+ anim1.addAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange);
+ FinishedListener finishedSpy1;
+ anim1.addAnimationChangeListener(&finishedSpy1, QAbstractAnimationJob::Completion);
+
+ StateChangeListener stateChangedSpy2;
+ anim2.addAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange);
+ FinishedListener finishedSpy2;
+ anim2.addAnimationChangeListener(&finishedSpy2, QAbstractAnimationJob::Completion);
+
+ StateChangeListener stateChangedSpy3;
+ anim3.addAnimationChangeListener(&stateChangedSpy3, QAbstractAnimationJob::StateChange);
+ FinishedListener finishedSpy3;
+ anim3.addAnimationChangeListener(&finishedSpy3, QAbstractAnimationJob::Completion);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+ group.appendAnimation(&anim3);
+ QCOMPARE(stateChangedSpy1.count(), 0);
+ group.start();
+ QCOMPARE(stateChangedSpy1.count(), 2);
+ QCOMPARE(finishedSpy1.count(), 1);
+ QCOMPARE(stateChangedSpy1.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(stateChangedSpy1.states.at(1), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(stateChangedSpy2.count(), 1);
+ QCOMPARE(finishedSpy2.count(), 0);
+ QCOMPARE(stateChangedSpy1.states.at(0), QAnimationGroupJob::Running);
+
+ QCOMPARE(stateChangedSpy3.count(), 1);
+ QCOMPARE(finishedSpy3.count(), 0);
+ QCOMPARE(stateChangedSpy3.states.at(0), QAnimationGroupJob::Running);
+
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim3.state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+
+ group.stop();
+ group.setLoopCount(4);
+ stateChangedSpy1.clear();
+ stateChangedSpy2.clear();
+ stateChangedSpy3.clear();
+
+ group.start();
+ QCOMPARE(stateChangedSpy1.count(), 2);
+ QCOMPARE(stateChangedSpy2.count(), 1);
+ QCOMPARE(stateChangedSpy3.count(), 1);
+ group.setCurrentTime(50);
+ QCOMPARE(stateChangedSpy1.count(), 2);
+ QCOMPARE(stateChangedSpy2.count(), 1);
+ QCOMPARE(stateChangedSpy3.count(), 2);
+ group.setCurrentTime(150);
+ QCOMPARE(stateChangedSpy1.count(), 4);
+ QCOMPARE(stateChangedSpy2.count(), 3);
+ QCOMPARE(stateChangedSpy3.count(), 4);
+ group.setCurrentTime(50);
+ QCOMPARE(stateChangedSpy1.count(), 6);
+ QCOMPARE(stateChangedSpy2.count(), 5);
+ QCOMPARE(stateChangedSpy3.count(), 6);
+
+ //cleanup
+ anim1.removeAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange);
+ anim1.removeAnimationChangeListener(&finishedSpy1, QAbstractAnimationJob::Completion);
+ anim2.removeAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange);
+ anim2.removeAnimationChangeListener(&finishedSpy2, QAbstractAnimationJob::Completion);
+ anim3.removeAnimationChangeListener(&stateChangedSpy3, QAbstractAnimationJob::StateChange);
+ anim3.removeAnimationChangeListener(&finishedSpy3, QAbstractAnimationJob::Completion);
+}
+
+void tst_QParallelAnimationGroupJob::stopUncontrolledAnimations()
+{
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(0);
+
+ UncontrolledAnimation notTimeDriven;
+ QCOMPARE(notTimeDriven.totalDuration(), -1);
+
+ TestAnimation loopsForever(100);
+ loopsForever.setLoopCount(-1);
+
+ StateChangeListener stateChangedSpy;
+ anim1.addAnimationChangeListener(&stateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&notTimeDriven);
+ group.appendAnimation(&loopsForever);
+
+ group.start();
+
+ QCOMPARE(stateChangedSpy.count(), 2);
+ QCOMPARE(stateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(stateChangedSpy.states.at(1), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
+ QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+
+ notTimeDriven.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running);
+
+ loopsForever.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped);
+}
+
+struct AnimState {
+ AnimState(int time = -1) : time(time), state(-1) {}
+ AnimState(int time, int state) : time(time), state(state) {}
+ int time;
+ int state;
+};
+
+#define Running QAbstractAnimationJob::Running
+#define Stopped QAbstractAnimationJob::Stopped
+
+Q_DECLARE_METATYPE(AnimState)
+void tst_QParallelAnimationGroupJob::loopCount_data()
+{
+ QTest::addColumn<bool>("directionBackward");
+ QTest::addColumn<int>("setLoopCount");
+ QTest::addColumn<int>("initialGroupTime");
+ QTest::addColumn<int>("currentGroupTime");
+ QTest::addColumn<AnimState>("expected1");
+ QTest::addColumn<AnimState>("expected2");
+ QTest::addColumn<AnimState>("expected3");
+
+ // D U R A T I O N
+ // 100 60*2 0
+ // direction = Forward
+ QTest::newRow("50") << false << 3 << 0 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("100") << false << 3 << 0 << 100 << AnimState(100 ) << AnimState( 40, Running) << AnimState( 0, Stopped);
+ QTest::newRow("110") << false << 3 << 0 << 110 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("120") << false << 3 << 0 << 120 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped);
+
+ QTest::newRow("170") << false << 3 << 0 << 170 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("220") << false << 3 << 0 << 220 << AnimState(100 ) << AnimState( 40, Running) << AnimState( 0, Stopped);
+ QTest::newRow("230") << false << 3 << 0 << 230 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("240") << false << 3 << 0 << 240 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped);
+
+ QTest::newRow("290") << false << 3 << 0 << 290 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("340") << false << 3 << 0 << 340 << AnimState(100 ) << AnimState( 40, Running) << AnimState( 0, Stopped);
+ QTest::newRow("350") << false << 3 << 0 << 350 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("360") << false << 3 << 0 << 360 << AnimState(100, Stopped) << AnimState( 60 ) << AnimState( 0, Stopped);
+
+ QTest::newRow("410") << false << 3 << 0 << 410 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped);
+ QTest::newRow("460") << false << 3 << 0 << 460 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped);
+ QTest::newRow("470") << false << 3 << 0 << 470 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped);
+ QTest::newRow("480") << false << 3 << 0 << 480 << AnimState(100, Stopped) << AnimState( 60, Stopped) << AnimState( 0, Stopped);
+
+ // direction = Forward, rewind
+ QTest::newRow("120-110") << false << 3 << 120 << 110 << AnimState( 0, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("120-50") << false << 3 << 120 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("120-0") << false << 3 << 120 << 0 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped);
+ QTest::newRow("300-110") << false << 3 << 300 << 110 << AnimState( 0, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("300-50") << false << 3 << 300 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("300-0") << false << 3 << 300 << 0 << AnimState( 0, Running) << AnimState( 0, Running) << AnimState( 0, Stopped);
+ QTest::newRow("115-105") << false << 3 << 115 << 105 << AnimState( 42, Stopped) << AnimState( 45, Running) << AnimState( 0, Stopped);
+
+ // direction = Backward
+ QTest::newRow("b120-120") << true << 3 << 120 << 120 << AnimState( 42, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b120-110") << true << 3 << 120 << 110 << AnimState( 42, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b120-100") << true << 3 << 120 << 100 << AnimState(100, Running) << AnimState( 40, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b120-50") << true << 3 << 120 << 50 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b120-0") << true << 3 << 120 << 0 << AnimState( 0, Stopped) << AnimState( 0, Stopped) << AnimState( 0, Stopped);
+ QTest::newRow("b360-170") << true << 3 << 360 << 170 << AnimState( 50, Running) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b360-220") << true << 3 << 360 << 220 << AnimState(100, Running) << AnimState( 40, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b360-210") << true << 3 << 360 << 210 << AnimState( 90, Running) << AnimState( 30, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b360-120") << true << 3 << 360 << 120 << AnimState( 0, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped);
+
+ // rewind, direction = Backward
+ QTest::newRow("b50-110") << true << 3 << 50 << 110 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b50-120") << true << 3 << 50 << 120 << AnimState(100, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b50-140") << true << 3 << 50 << 140 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b50-240") << true << 3 << 50 << 240 << AnimState(100, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b50-260") << true << 3 << 50 << 260 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b50-350") << true << 3 << 50 << 350 << AnimState(100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+
+ // infinite looping
+ QTest::newRow("inf1220") << false << -1 << 0 << 1220 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped);
+ QTest::newRow("inf1310") << false << -1 << 0 << 1310 << AnimState( 100, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+ // infinite looping, direction = Backward (will only loop once)
+ QTest::newRow("b.inf120-120") << true << -1 << 120 << 120 << AnimState( 42, Stopped) << AnimState( 60, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b.inf120-20") << true << -1 << 120 << 20 << AnimState( 20, Running) << AnimState( 20, Running) << AnimState( 0, Stopped);
+ QTest::newRow("b.inf120-110") << true << -1 << 120 << 110 << AnimState( 42, Stopped) << AnimState( 50, Running) << AnimState( 0, Stopped);
+
+
+}
+
+void tst_QParallelAnimationGroupJob::loopCount()
+{
+ QFETCH(bool, directionBackward);
+ QFETCH(int, setLoopCount);
+ QFETCH(int, initialGroupTime);
+ QFETCH(int, currentGroupTime);
+ QFETCH(AnimState, expected1);
+ QFETCH(AnimState, expected2);
+ QFETCH(AnimState, expected3);
+
+ QParallelAnimationGroupJob group;
+
+ TestAnimation anim1(100);
+ TestAnimation anim2(60); //total 120
+ anim2.setLoopCount(2);
+ TestAnimation anim3(0);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+ group.appendAnimation(&anim3);
+
+ group.setLoopCount(setLoopCount);
+ if (initialGroupTime >= 0)
+ group.setCurrentTime(initialGroupTime);
+ if (directionBackward)
+ group.setDirection(QAbstractAnimationJob::Backward);
+
+ group.start();
+ if (initialGroupTime >= 0)
+ group.setCurrentTime(initialGroupTime);
+
+ anim1.setCurrentTime(42); // 42 is "untouched"
+ anim2.setCurrentTime(42);
+
+ group.setCurrentTime(currentGroupTime);
+
+ QCOMPARE(anim1.currentLoopTime(), expected1.time);
+ QCOMPARE(anim2.currentLoopTime(), expected2.time);
+ QCOMPARE(anim3.currentLoopTime(), expected3.time);
+
+ if (expected1.state >=0)
+ QCOMPARE(int(anim1.state()), expected1.state);
+ if (expected2.state >=0)
+ QCOMPARE(int(anim2.state()), expected2.state);
+ if (expected3.state >=0)
+ QCOMPARE(int(anim3.state()), expected3.state);
+
+}
+
+void tst_QParallelAnimationGroupJob::addAndRemoveDuration()
+{
+ QParallelAnimationGroupJob group;
+ QCOMPARE(group.duration(), 0);
+ TestAnimation *test = new TestAnimation(250); // 0, duration = 250;
+ group.appendAnimation(test);
+ QCOMPARE(test->group(), static_cast<QAnimationGroupJob*>(&group));
+ QCOMPARE(test->duration(), 250);
+ QCOMPARE(group.duration(), 250);
+
+ TestAnimation *test2 = new TestAnimation(750); // 1
+ group.appendAnimation(test2);
+ QCOMPARE(test2->group(), static_cast<QAnimationGroupJob*>(&group));
+ QCOMPARE(group.duration(), 750);
+
+ TestAnimation *test3 = new TestAnimation(500); // 2
+ group.appendAnimation(test3);
+ QCOMPARE(test3->group(), static_cast<QAnimationGroupJob*>(&group));
+ QCOMPARE(group.duration(), 750);
+
+ group.removeAnimation(test2); // remove the one with duration = 750
+ delete test2;
+ QCOMPARE(group.duration(), 500);
+
+ group.removeAnimation(test3); // remove the one with duration = 500
+ delete test3;
+ QCOMPARE(group.duration(), 250);
+
+ group.removeAnimation(test); // remove the last one (with duration = 250)
+ QCOMPARE(test->group(), static_cast<QAnimationGroupJob*>(0));
+ QCOMPARE(group.duration(), 0);
+ delete test;
+}
+
+void tst_QParallelAnimationGroupJob::pauseResume()
+{
+ QParallelAnimationGroupJob group;
+ TestAnimation *anim = new TestAnimation(250); // 0, duration = 250;
+ group.appendAnimation(anim);
+ StateChangeListener spy;
+ anim->addAnimationChangeListener(&spy, QAbstractAnimationJob::StateChange);
+ QCOMPARE(group.duration(), 250);
+ group.start();
+ QTest::qWait(100);
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim->state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy.count(), 1);
+ spy.clear();
+ const int currentTime = group.currentLoopTime();
+ QCOMPARE(anim->currentLoopTime(), currentTime);
+
+ group.pause();
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(group.currentLoopTime(), currentTime);
+ QCOMPARE(anim->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(anim->currentLoopTime(), currentTime);
+ QCOMPARE(spy.count(), 1);
+ spy.clear();
+
+ group.resume();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.currentLoopTime(), currentTime);
+ QCOMPARE(anim->state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim->currentLoopTime(), currentTime);
+ QCOMPARE(spy.count(), 1);
+
+ group.stop();
+ spy.clear();
+ group.appendAnimation(new TestAnimation(500));
+ group.start();
+ QCOMPARE(spy.count(), 1); //the animation should have been started
+ QCOMPARE(spy.states.at(0), TestAnimation::Running);
+ group.setCurrentTime(250); //end of first animation
+ QCOMPARE(spy.count(), 2); //the animation should have been stopped
+ QCOMPARE(spy.states.at(1), TestAnimation::Stopped);
+ group.pause();
+ QCOMPARE(spy.count(), 2); //this shouldn't have changed
+ group.resume();
+ QCOMPARE(spy.count(), 2); //this shouldn't have changed
+}
+
+// This is a regression test for QTBUG-8910, where a crash occurred when the
+// last animation was removed from a group.
+void tst_QParallelAnimationGroupJob::crashWhenRemovingUncontrolledAnimation()
+{
+ QParallelAnimationGroupJob group;
+ TestAnimation *anim = new TestAnimation;
+ anim->setLoopCount(-1);
+ TestAnimation *anim2 = new TestAnimation;
+ anim2->setLoopCount(-1);
+ group.appendAnimation(anim);
+ group.appendAnimation(anim2);
+ group.start();
+ delete anim;
+ // it would crash here because the internals of the group would still have a reference to anim
+ delete anim2;
+}
+
+
+QTEST_MAIN(tst_QParallelAnimationGroupJob)
+#include "tst_qparallelanimationgroupjob.moc"
diff --git a/tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro b/tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro
new file mode 100644
index 0000000000..d2b48a6c74
--- /dev/null
+++ b/tests/auto/declarative/animation/qpauseanimationjob/qpauseanimationjob.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+macx:CONFIG -= app_bundle
+TARGET = tst_qpauseanimationjob
+QT = core-private gui-private declarative-private testlib
+SOURCES = tst_qpauseanimationjob.cpp
diff --git a/tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
new file mode 100644
index 0000000000..97be325017
--- /dev/null
+++ b/tests/auto/declarative/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
@@ -0,0 +1,470 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtDeclarative/private/qpauseanimationjob_p.h>
+#include <QtDeclarative/private/qsequentialanimationgroupjob_p.h>
+#include <QtDeclarative/private/qparallelanimationgroupjob_p.h>
+
+#ifdef Q_OS_WIN
+static const char winTimerError[] = "On windows, consistent timing is not working properly due to bad timer resolution";
+#endif
+
+class TestablePauseAnimation : public QPauseAnimationJob
+{
+public:
+ TestablePauseAnimation()
+ : m_updateCurrentTimeCount(0)
+ {
+ }
+
+ TestablePauseAnimation(int duration)
+ : QPauseAnimationJob(duration), m_updateCurrentTimeCount(0)
+ {
+ }
+
+ int m_updateCurrentTimeCount;
+protected:
+ void updateCurrentTime(int currentTime)
+ {
+ QPauseAnimationJob::updateCurrentTime(currentTime);
+ ++m_updateCurrentTimeCount;
+ }
+};
+
+class TestableGenericAnimation : public QAbstractAnimationJob
+{
+public:
+ TestableGenericAnimation(int duration = 250) : m_duration(duration) {}
+ int duration() const { return m_duration; }
+
+private:
+ int m_duration;
+};
+
+class EnableConsistentTiming
+{
+public:
+ EnableConsistentTiming()
+ {
+ QUnifiedTimer *timer = QUnifiedTimer::instance();
+ timer->setConsistentTiming(true);
+ }
+ ~EnableConsistentTiming()
+ {
+ QUnifiedTimer *timer = QUnifiedTimer::instance();
+ timer->setConsistentTiming(false);
+ }
+};
+
+class tst_QPauseAnimationJob : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ void initTestCase();
+
+private slots:
+ void changeDirectionWhileRunning();
+ void noTimerUpdates_data();
+ void noTimerUpdates();
+ void multiplePauseAnimations();
+ void pauseAndPropertyAnimations();
+ void pauseResume();
+ void sequentialPauseGroup();
+ void sequentialGroupWithPause();
+ void multipleSequentialGroups();
+ void zeroDuration();
+};
+
+void tst_QPauseAnimationJob::initTestCase()
+{
+// qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State");
+}
+
+void tst_QPauseAnimationJob::changeDirectionWhileRunning()
+{
+ EnableConsistentTiming enabled;
+
+ TestablePauseAnimation animation;
+ animation.setDuration(400);
+ animation.start();
+ QTest::qWait(100);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ animation.setDirection(QAbstractAnimationJob::Backward);
+ QTest::qWait(animation.totalDuration() + 50);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+}
+
+void tst_QPauseAnimationJob::noTimerUpdates_data()
+{
+ QTest::addColumn<int>("duration");
+ QTest::addColumn<int>("loopCount");
+
+ QTest::newRow("0") << 200 << 1;
+ QTest::newRow("1") << 160 << 1;
+ QTest::newRow("2") << 160 << 2;
+ QTest::newRow("3") << 200 << 3;
+}
+
+void tst_QPauseAnimationJob::noTimerUpdates()
+{
+ EnableConsistentTiming enabled;
+
+ QFETCH(int, duration);
+ QFETCH(int, loopCount);
+
+ TestablePauseAnimation animation;
+ animation.setDuration(duration);
+ animation.setLoopCount(loopCount);
+ animation.start();
+ QTest::qWait(animation.totalDuration() + 100);
+
+#ifdef Q_OS_WIN
+ if (animation.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ const int expectedLoopCount = 1 + loopCount;
+
+#ifdef Q_OS_WIN
+ if (animation.m_updateCurrentTimeCount != expectedLoopCount)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QCOMPARE(animation.m_updateCurrentTimeCount, expectedLoopCount);
+}
+
+void tst_QPauseAnimationJob::multiplePauseAnimations()
+{
+ EnableConsistentTiming enabled;
+
+ TestablePauseAnimation animation;
+ animation.setDuration(200);
+
+ TestablePauseAnimation animation2;
+ animation2.setDuration(800);
+
+ animation.start();
+ animation2.start();
+ QTest::qWait(animation.totalDuration() + 100);
+
+#ifdef Q_OS_WIN
+ if (animation.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (animation2.state() != QAbstractAnimationJob::Running)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(animation2.state() == QAbstractAnimationJob::Running);
+
+#ifdef Q_OS_WIN
+ if (animation.m_updateCurrentTimeCount != 2)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QCOMPARE(animation.m_updateCurrentTimeCount, 2);
+
+#ifdef Q_OS_WIN
+ if (animation2.m_updateCurrentTimeCount != 2)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
+
+ QTest::qWait(550);
+
+#ifdef Q_OS_WIN
+ if (animation2.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (animation2.m_updateCurrentTimeCount != 3)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QCOMPARE(animation2.m_updateCurrentTimeCount, 3);
+}
+
+void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
+{
+ EnableConsistentTiming enabled;
+
+ TestablePauseAnimation pause;
+ pause.setDuration(200);
+
+ TestableGenericAnimation animation;
+
+ pause.start();
+
+ QTest::qWait(100);
+ animation.start();
+
+ QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Running);
+ QCOMPARE(pause.m_updateCurrentTimeCount, 2);
+
+ QTest::qWait(animation.totalDuration() + 100);
+
+#ifdef Q_OS_WIN
+ if (animation.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(pause.m_updateCurrentTimeCount > 3);
+}
+
+void tst_QPauseAnimationJob::pauseResume()
+{
+ TestablePauseAnimation animation;
+ animation.setDuration(400);
+ animation.start();
+ QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ QTest::qWait(200);
+ animation.pause();
+ QVERIFY(animation.state() == QAbstractAnimationJob::Paused);
+ animation.start();
+ QTest::qWait(300);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (animation.m_updateCurrentTimeCount != 3)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QCOMPARE(animation.m_updateCurrentTimeCount, 3);
+}
+
+void tst_QPauseAnimationJob::sequentialPauseGroup()
+{
+ QSequentialAnimationGroupJob group;
+
+ TestablePauseAnimation animation1(200);
+ group.appendAnimation(&animation1);
+ TestablePauseAnimation animation2(200);
+ group.appendAnimation(&animation2);
+ TestablePauseAnimation animation3(200);
+ group.appendAnimation(&animation3);
+
+ group.start();
+ QCOMPARE(animation1.m_updateCurrentTimeCount, 1);
+ QCOMPARE(animation2.m_updateCurrentTimeCount, 0);
+ QCOMPARE(animation3.m_updateCurrentTimeCount, 0);
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation1.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(animation3.state() == QAbstractAnimationJob::Stopped);
+
+ group.setCurrentTime(250);
+ QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation2.m_updateCurrentTimeCount, 1);
+ QCOMPARE(animation3.m_updateCurrentTimeCount, 0);
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation1.state() == QAbstractAnimationJob::Stopped);
+ QCOMPARE((QAbstractAnimationJob*)&animation2, group.currentAnimation());
+ QVERIFY(animation2.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation3.state() == QAbstractAnimationJob::Stopped);
+
+ group.setCurrentTime(500);
+ QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation3.m_updateCurrentTimeCount, 1);
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation1.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
+ QCOMPARE((QAbstractAnimationJob*)&animation3, group.currentAnimation());
+ QVERIFY(animation3.state() == QAbstractAnimationJob::Running);
+
+ group.setCurrentTime(750);
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(animation1.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(animation3.state() == QAbstractAnimationJob::Stopped);
+
+ QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation3.m_updateCurrentTimeCount, 2);
+}
+
+void tst_QPauseAnimationJob::sequentialGroupWithPause()
+{
+ QSequentialAnimationGroupJob group;
+
+ TestableGenericAnimation animation;
+ group.appendAnimation(&animation);
+
+ TestablePauseAnimation pause;
+ pause.setDuration(250);
+ group.appendAnimation(&pause);
+
+ group.start();
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Stopped);
+
+ group.setCurrentTime(300);
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Running);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QCOMPARE((QAbstractAnimationJob*)&pause, group.currentAnimation());
+ QVERIFY(pause.state() == QAbstractAnimationJob::Running);
+
+ group.setCurrentTime(600);
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Stopped);
+
+ QCOMPARE(pause.m_updateCurrentTimeCount, 2);
+}
+
+void tst_QPauseAnimationJob::multipleSequentialGroups()
+{
+ EnableConsistentTiming enabled;
+
+ QParallelAnimationGroupJob group;
+ group.setLoopCount(2);
+
+ QSequentialAnimationGroupJob subgroup1;
+ group.appendAnimation(&subgroup1);
+
+ TestableGenericAnimation animation(300);
+ subgroup1.appendAnimation(&animation);
+
+ TestablePauseAnimation pause(200);
+ subgroup1.appendAnimation(&pause);
+
+ QSequentialAnimationGroupJob subgroup2;
+ group.appendAnimation(&subgroup2);
+
+ TestableGenericAnimation animation2(200);
+ subgroup2.appendAnimation(&animation2);
+
+ TestablePauseAnimation pause2(250);
+ subgroup2.appendAnimation(&pause2);
+
+ QSequentialAnimationGroupJob subgroup3;
+ group.appendAnimation(&subgroup3);
+
+ TestablePauseAnimation pause3(400);
+ subgroup3.appendAnimation(&pause3);
+
+ TestableGenericAnimation animation3(200);
+ subgroup3.appendAnimation(&animation3);
+
+ QSequentialAnimationGroupJob subgroup4;
+ group.appendAnimation(&subgroup4);
+
+ TestablePauseAnimation pause4(310);
+ subgroup4.appendAnimation(&pause4);
+
+ TestablePauseAnimation pause5(60);
+ subgroup4.appendAnimation(&pause5);
+
+ group.start();
+
+ QVERIFY(group.state() == QAbstractAnimationJob::Running);
+ QVERIFY(subgroup1.state() == QAbstractAnimationJob::Running);
+ QVERIFY(subgroup2.state() == QAbstractAnimationJob::Running);
+ QVERIFY(subgroup3.state() == QAbstractAnimationJob::Running);
+ QVERIFY(subgroup4.state() == QAbstractAnimationJob::Running);
+
+ // This is a pretty long animation so it tends to get rather out of sync
+ // when using the consistent timer, so run for an extra half second for good
+ // measure...
+ QTest::qWait(group.totalDuration() + 500);
+
+#ifdef Q_OS_WIN
+ if (group.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(group.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (subgroup1.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(subgroup1.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (subgroup2.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(subgroup2.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (subgroup3.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(subgroup3.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (subgroup4.state() != QAbstractAnimationJob::Stopped)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QVERIFY(subgroup4.state() == QAbstractAnimationJob::Stopped);
+
+#ifdef Q_OS_WIN
+ if (pause5.m_updateCurrentTimeCount != 4)
+ QEXPECT_FAIL("", winTimerError, Abort);
+#endif
+ QCOMPARE(pause5.m_updateCurrentTimeCount, 4);
+}
+
+void tst_QPauseAnimationJob::zeroDuration()
+{
+ TestablePauseAnimation animation;
+ animation.setDuration(0);
+ animation.start();
+ QTest::qWait(animation.totalDuration() + 100);
+ QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QCOMPARE(animation.m_updateCurrentTimeCount, 1);
+}
+
+QTEST_MAIN(tst_QPauseAnimationJob)
+#include "tst_qpauseanimationjob.moc"
diff --git a/tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro b/tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro
new file mode 100644
index 0000000000..914fc3ca62
--- /dev/null
+++ b/tests/auto/declarative/animation/qsequentialanimationgroupjob/qsequentialanimationgroupjob.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase parallel_test
+macx:CONFIG -= app_bundle
+TARGET = tst_qsequentialanimationgroupjob
+QT = core-private declarative-private testlib
+SOURCES = tst_qsequentialanimationgroupjob.cpp
diff --git a/tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp b/tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
new file mode 100644
index 0000000000..895e4f849e
--- /dev/null
+++ b/tests/auto/declarative/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
@@ -0,0 +1,1617 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.1, 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtDeclarative/private/qsequentialanimationgroupjob_p.h>
+#include <QtDeclarative/private/qparallelanimationgroupjob_p.h>
+#include <QtDeclarative/private/qpauseanimationjob_p.h>
+
+Q_DECLARE_METATYPE(QAbstractAnimationJob::State)
+Q_DECLARE_METATYPE(QAbstractAnimationJob*)
+
+class tst_QSequentialAnimationGroupJob : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ void initTestCase();
+
+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 clear();
+ void pauseResume();
+};
+
+void tst_QSequentialAnimationGroupJob::initTestCase()
+{
+ qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State");
+ qRegisterMetaType<QAbstractAnimationJob*>("QAbstractAnimationJob*");
+}
+
+void tst_QSequentialAnimationGroupJob::construction()
+{
+ QSequentialAnimationGroupJob animationgroup;
+}
+
+class TestAnimation : public QAbstractAnimationJob
+{
+public:
+ TestAnimation(int duration = 250) : m_duration(duration) {}
+ int duration() const { return m_duration; }
+
+private:
+ int m_duration;
+};
+
+class TestValueAnimation : public TestAnimation
+{
+public:
+ TestValueAnimation(int duration = 250)
+ : TestAnimation(duration), start(0), end(0), value(0) {}
+
+ void updateCurrentTime(int msecs)
+ {
+ if (msecs >= duration())
+ value = end;
+ else
+ value = start + (end - start) * (qreal(msecs) / duration());
+ }
+
+ qreal start, end;
+ qreal value;
+};
+
+class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
+{
+ Q_OBJECT
+public:
+ int duration() const { return -1; /* not time driven */ }
+
+protected:
+ void updateCurrentTime(int currentTime)
+ {
+ if (currentTime >= 250)
+ stop();
+ }
+};
+
+class StateChangeListener: public QAnimation2ChangeListener
+{
+public:
+ virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+ {
+ states << newState;
+ }
+
+ void clear() { states.clear(); }
+ int count() const { return states.count(); }
+
+ QList<QAbstractAnimationJob::State> states;
+};
+
+class FinishedListener: public QAnimation2ChangeListener
+{
+public:
+ FinishedListener() : m_count(0) {}
+
+ virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; }
+ void clear() { m_count = 0; }
+ int count() { return m_count; }
+
+private:
+ int m_count;
+};
+
+void tst_QSequentialAnimationGroupJob::setCurrentTime()
+{
+ // sequence operating on same object/property
+ QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ TestAnimation *a1_s_o1 = new TestAnimation;
+ TestAnimation *a2_s_o1 = new TestAnimation;
+ TestAnimation *a3_s_o1 = new TestAnimation;
+ a2_s_o1->setLoopCount(3);
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a2_s_o1);
+ sequence->appendAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob();
+ TestAnimation *a1_s_o2 = new TestAnimation;
+ TestAnimation *a1_s_o3 = new TestAnimation;
+ sequence2->appendAnimation(a1_s_o2);
+ sequence2->appendAnimation(a1_s_o3);
+
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(sequence);
+ group.appendAnimation(sequence2);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.currentLoopTime(), 1);
+ QCOMPARE(sequence->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentLoopTime(), 250);
+ QCOMPARE(sequence->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 251
+ group.setCurrentTime(251);
+ QCOMPARE(group.currentLoopTime(), 251);
+ QCOMPARE(sequence->currentLoopTime(), 251);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a2_s_o1->currentLoop(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 750
+ group.setCurrentTime(750);
+ QCOMPARE(group.currentLoopTime(), 750);
+ QCOMPARE(sequence->currentLoopTime(), 750);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 1000
+ group.setCurrentTime(1000);
+ QCOMPARE(group.currentLoopTime(), 1000);
+ QCOMPARE(sequence->currentLoopTime(), 1000);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 1010
+ group.setCurrentTime(1010);
+ QCOMPARE(group.currentLoopTime(), 1010);
+ QCOMPARE(sequence->currentLoopTime(), 1010);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 10);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 1250
+ group.setCurrentTime(1250);
+ QCOMPARE(group.currentLoopTime(), 1250);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 1500
+ group.setCurrentTime(1500);
+ QCOMPARE(group.currentLoopTime(), 1500);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 1750
+ group.setCurrentTime(1750);
+ QCOMPARE(group.currentLoopTime(), 1750);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 250);
+
+ // Current time = 2000
+ group.setCurrentTime(2000);
+ QCOMPARE(group.currentLoopTime(), 1750);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 250);
+}
+
+void tst_QSequentialAnimationGroupJob::setCurrentTimeWithUncontrolledAnimation()
+{
+ // sequence operating on different object/properties
+ QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ TestAnimation *a1_s_o1 = new TestAnimation;
+ TestAnimation *a1_s_o2 = new TestAnimation;
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a1_s_o2);
+
+ UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation;
+ QCOMPARE(notTimeDriven->totalDuration(), -1);
+
+ TestAnimation *loopsForever = new TestAnimation;
+ loopsForever->setLoopCount(-1);
+ QCOMPARE(loopsForever->totalDuration(), -1);
+
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(sequence);
+ group.appendAnimation(notTimeDriven);
+ group.appendAnimation(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(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.currentLoopTime(), 1);
+ QCOMPARE(sequence->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 0);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+
+ // Current time = 250
+ group.setCurrentTime(250);
+ QCOMPARE(group.currentLoopTime(), 250);
+ QCOMPARE(sequence->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 0);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+
+ // Current time = 500
+ group.setCurrentTime(500);
+ QCOMPARE(group.currentLoopTime(), 500);
+ QCOMPARE(sequence->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 0);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob *>(notTimeDriven));
+
+ // Current time = 505
+ group.setCurrentTime(505);
+ QCOMPARE(group.currentLoopTime(), 505);
+ QCOMPARE(sequence->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 5);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob *>(notTimeDriven));
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
+
+ // Current time = 750 (end of notTimeDriven animation)
+ group.setCurrentTime(750);
+ QCOMPARE(group.currentLoopTime(), 750);
+ QCOMPARE(sequence->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 250);
+ QCOMPARE(loopsForever->currentLoopTime(), 0);
+ QCOMPARE(group.currentAnimation(), loopsForever);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroupJob::Paused);
+
+ // Current time = 800 (as notTimeDriven was finished at 750, loopsforever should still run)
+ group.setCurrentTime(800);
+ QCOMPARE(group.currentLoopTime(), 800);
+ QCOMPARE(group.currentAnimation(), loopsForever);
+ QCOMPARE(sequence->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(notTimeDriven->currentLoopTime(), 250);
+ QCOMPARE(loopsForever->currentLoopTime(), 50);
+
+ loopsForever->stop(); // this should stop the group
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QSequentialAnimationGroupJob::seekingForwards()
+{
+
+ // sequence operating on same object/property
+ QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob;
+ TestAnimation *a1_s_o1 = new TestAnimation;
+ TestAnimation *a2_s_o1 = new TestAnimation;
+ TestAnimation *a3_s_o1 = new TestAnimation;
+ a2_s_o1->setLoopCount(3);
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a2_s_o1);
+ sequence->appendAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob;
+ TestAnimation *a1_s_o2 = new TestAnimation;
+ TestAnimation *a1_s_o3 = new TestAnimation;
+ sequence2->appendAnimation(a1_s_o2);
+ sequence2->appendAnimation(a1_s_o3);
+
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(sequence);
+ group.appendAnimation(sequence2);
+
+ // Current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(group.currentLoopTime(), 1);
+ QCOMPARE(sequence->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 0);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // Current time = 1500
+ group.setCurrentTime(1500);
+ QCOMPARE(group.currentLoopTime(), 1500);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ // this will restart the group
+ group.start();
+ group.pause();
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
+
+ // Current time = 1750
+ group.setCurrentTime(1750);
+ QCOMPARE(group.currentLoopTime(), 1750);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 250);
+}
+
+void tst_QSequentialAnimationGroupJob::seekingBackwards()
+{
+ // sequence operating on same object/property
+ QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ TestAnimation *a1_s_o1 = new TestAnimation;
+ TestAnimation *a2_s_o1 = new TestAnimation;
+ TestAnimation *a3_s_o1 = new TestAnimation;
+ a2_s_o1->setLoopCount(3);
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a2_s_o1);
+ sequence->appendAnimation(a3_s_o1);
+
+ // sequence operating on different object/properties
+ QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob();
+ TestAnimation *a1_s_o2 = new TestAnimation;
+ TestAnimation *a1_s_o3 = new TestAnimation;
+ sequence2->appendAnimation(a1_s_o2);
+ sequence2->appendAnimation(a1_s_o3);
+
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(sequence);
+ group.appendAnimation(sequence2);
+
+ group.start();
+
+ // Current time = 1600
+ group.setCurrentTime(1600);
+ QCOMPARE(group.currentLoopTime(), 1600);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 350);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 100);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Running);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Running);
+
+ // Seeking backwards, current time = 1
+ group.setCurrentTime(1);
+ QCOMPARE(group.currentLoopTime(), 1);
+ QCOMPARE(sequence->currentLoopTime(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 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->currentLoopTime(), 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->currentLoopTime(), 0);
+ QCOMPARE(sequence2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 0);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 0);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Running);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Running);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
+
+ // Current time = 2000
+ group.setCurrentTime(2000);
+ QCOMPARE(group.currentLoopTime(), 1750);
+ QCOMPARE(sequence->currentLoopTime(), 1250);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 2);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 250);
+ QCOMPARE(sequence2->currentLoopTime(), 500);
+ QCOMPARE(a1_s_o2->currentLoopTime(), 250);
+ QCOMPARE(a1_s_o3->currentLoopTime(), 250);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
+}
+
+typedef QList<QAbstractAnimationJob::State> StateList;
+
+static bool compareStates(const StateChangeListener& 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;
+ }
+ QAbstractAnimationJob::State st = expectedStates.at(i);
+ QAbstractAnimationJob::State actual = spy.states.at(i);
+ 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()) {
+ QAbstractAnimationJob::State actual = spy.states.at(i);
+ 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_QSequentialAnimationGroupJob::pauseAndResume()
+{
+ // sequence operating on same object/property
+ QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ TestAnimation *a1_s_o1 = new TestAnimation;
+ TestAnimation *a2_s_o1 = new TestAnimation;
+ TestAnimation *a3_s_o1 = new TestAnimation;
+ a2_s_o1->setLoopCount(2);
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a2_s_o1);
+ sequence->appendAnimation(a3_s_o1);
+ sequence->setLoopCount(2);
+
+ StateChangeListener a1StateChangedSpy;
+ a1_s_o1->addAnimationChangeListener(&a1StateChangedSpy, QAbstractAnimationJob::StateChange);
+ StateChangeListener seqStateChangedSpy;
+ sequence->addAnimationChangeListener(&seqStateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(sequence);
+
+ group.start();
+ group.pause();
+
+ // Current time = 1751
+ group.setCurrentTime(1751);
+ QCOMPARE(group.currentLoopTime(), 1751);
+ QCOMPARE(sequence->currentLoopTime(), 751);
+ QCOMPARE(sequence->currentLoop(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 1);
+ QCOMPARE(a3_s_o1->currentLoop(), 0);
+ QCOMPARE(a3_s_o1->currentLoopTime(), 1);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused);
+
+ QCOMPARE(a1StateChangedSpy.count(), 5); // Running,Paused,Stopped,Running,Stopped
+ QCOMPARE(seqStateChangedSpy.count(), 2); // Running,Paused
+
+ QVERIFY(compareStates(a1StateChangedSpy, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused
+ << QAbstractAnimationJob::Stopped
+ << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Stopped)));
+
+ //### is this the same test as compareStates test above?
+ QCOMPARE(a1StateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(a1StateChangedSpy.states.at(1), QAnimationGroupJob::Paused);
+ QCOMPARE(a1StateChangedSpy.states.at(2), QAnimationGroupJob::Stopped);
+ QCOMPARE(a1StateChangedSpy.states.at(3), QAnimationGroupJob::Running);
+ QCOMPARE(a1StateChangedSpy.states.at(4), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(seqStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(seqStateChangedSpy.states.at(1), QAnimationGroupJob::Paused);
+
+ group.resume();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Running);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Running);
+
+ QVERIFY(group.currentLoopTime() >= 1751);
+ QVERIFY(sequence->currentLoopTime() >= 751);
+ QCOMPARE(sequence->currentLoop(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 1);
+ QCOMPARE(a3_s_o1->currentLoop(), 0);
+ QVERIFY(a3_s_o1->currentLoopTime() >= 1);
+
+ QCOMPARE(seqStateChangedSpy.count(), 3); // Running,Paused,Running
+ QCOMPARE(seqStateChangedSpy.states.at(2), QAnimationGroupJob::Running);
+
+ group.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused);
+
+ QVERIFY(group.currentLoopTime() >= 1751);
+ QVERIFY(sequence->currentLoopTime() >= 751);
+ QCOMPARE(sequence->currentLoop(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoop(), 1);
+ QCOMPARE(a3_s_o1->currentLoop(), 0);
+ QVERIFY(a3_s_o1->currentLoopTime() >= 1);
+
+ QCOMPARE(seqStateChangedSpy.count(), 4); // Running,Paused,Running,Paused
+ QCOMPARE(seqStateChangedSpy.states.at(3), QAnimationGroupJob::Paused);
+
+ group.stop();
+
+ QCOMPARE(seqStateChangedSpy.count(), 5); // Running,Paused,Running,Paused,Stopped
+ QCOMPARE(seqStateChangedSpy.states.at(4), QAnimationGroupJob::Stopped);
+}
+
+void tst_QSequentialAnimationGroupJob::restart()
+{
+ // originally was sequence operating on same object/property
+ QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ //### no equivilant signal
+ //QSignalSpy seqCurrentAnimChangedSpy(sequence, SIGNAL(currentAnimationChanged(QAbstractAnimationJob*)));
+
+ StateChangeListener seqStateChangedSpy;
+ sequence->addAnimationChangeListener(&seqStateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ TestAnimation *anims[3];
+ StateChangeListener *animsStateChanged[3];
+
+ for (int i = 0; i < 3; i++) {
+ anims[i] = new TestAnimation(100);
+ animsStateChanged[i] = new StateChangeListener;
+ anims[i]->addAnimationChangeListener(animsStateChanged[i], QAbstractAnimationJob::StateChange);
+ }
+
+ anims[1]->setLoopCount(2);
+ sequence->appendAnimation(anims[0]);
+ sequence->appendAnimation(anims[1]);
+ sequence->appendAnimation(anims[2]);
+ sequence->setLoopCount(2);
+
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(sequence);
+
+ group.start();
+
+ QTest::qWait(500);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+
+ QTest::qWait(300);
+ QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped);
+
+ for (int i = 0; i < 3; i++) {
+ QCOMPARE(animsStateChanged[i]->count(), 4);
+ QCOMPARE(animsStateChanged[i]->states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(animsStateChanged[i]->states.at(1), QAnimationGroupJob::Stopped);
+ QCOMPARE(animsStateChanged[i]->states.at(2), QAnimationGroupJob::Running);
+ QCOMPARE(animsStateChanged[i]->states.at(3), QAnimationGroupJob::Stopped);
+ }
+
+ QCOMPARE(seqStateChangedSpy.count(), 2);
+ QCOMPARE(seqStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(seqStateChangedSpy.states.at(1), QAnimationGroupJob::Stopped);
+
+ //QCOMPARE(seqCurrentAnimChangedSpy.count(), 6);
+ //for(int i=0; i<seqCurrentAnimChangedSpy.count(); i++)
+ // QCOMPARE(static_cast<QAbstractAnimationJob*>(anims[i%3]), qVariantValue<QAbstractAnimationJob*>(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_QSequentialAnimationGroupJob::looping()
+{
+ // originally was sequence operating on same object/property
+ QSequentialAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
+ QAbstractAnimationJob *a1_s_o1 = new TestAnimation;
+ QAbstractAnimationJob *a2_s_o1 = new TestAnimation;
+ QAbstractAnimationJob *a3_s_o1 = new TestAnimation;
+
+ StateChangeListener a1Spy;
+ a1_s_o1->addAnimationChangeListener(&a1Spy, QAbstractAnimationJob::StateChange);
+ StateChangeListener a2Spy;
+ a2_s_o1->addAnimationChangeListener(&a2Spy, QAbstractAnimationJob::StateChange);
+ StateChangeListener a3Spy;
+ a3_s_o1->addAnimationChangeListener(&a3Spy, QAbstractAnimationJob::StateChange);
+ StateChangeListener seqSpy;
+ sequence->addAnimationChangeListener(&seqSpy, QAbstractAnimationJob::StateChange);
+
+ a2_s_o1->setLoopCount(2);
+ sequence->appendAnimation(a1_s_o1);
+ sequence->appendAnimation(a2_s_o1);
+ sequence->appendAnimation(a3_s_o1);
+ sequence->setLoopCount(2);
+
+ QSequentialAnimationGroupJob group;
+ StateChangeListener groupSpy;
+ group.addAnimationChangeListener(&groupSpy, QAbstractAnimationJob::StateChange);
+
+ group.appendAnimation(sequence);
+ group.setLoopCount(2);
+
+ group.start();
+ group.pause();
+
+ // Current time = 1750
+ group.setCurrentTime(1750);
+ QCOMPARE(group.currentLoopTime(), 1750);
+ QCOMPARE(sequence->currentLoopTime(), 750);
+ QCOMPARE(sequence->currentLoop(), 1);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 250);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 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->currentLoopTime(), 0);
+ QCOMPARE(sequence->currentAnimation(), a3_s_o1);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused);
+
+ QCOMPARE(a1Spy.count(), 5); // Running,Paused,Stopped,Running,Stopped
+ QVERIFY(compareStates(a1Spy, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused
+ << QAbstractAnimationJob::Stopped
+ << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Stopped)));
+
+ QCOMPARE(a2Spy.count(), 4); // Running,Stopped,Running,Stopped
+ QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Stopped
+ << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::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.currentLoopTime(), 1);
+ QCOMPARE(group.currentLoop(), 1);
+ QCOMPARE(sequence->currentLoopTime(), 1);
+ QCOMPARE(sequence->currentLoop(), 0);
+ QCOMPARE(a1_s_o1->currentLoopTime(), 1);
+ QCOMPARE(a2_s_o1->currentLoopTime(), 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->currentLoopTime(), 250);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(a1Spy.count(), 7); // Running,Paused,Stopped,Running,Stopped,Running,Stopped
+ QCOMPARE(a2Spy.count(), 4); // Running, Stopped, Running, Stopped
+ QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Stopped
+ << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused
+ << QAbstractAnimationJob::Stopped)));
+ QVERIFY(compareStates(seqSpy, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused
+ << QAbstractAnimationJob::Stopped
+ << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused)));
+ QCOMPARE(groupSpy.count(), 2);
+
+ //cleanup
+ a1_s_o1->removeAnimationChangeListener(&a1Spy, QAbstractAnimationJob::StateChange);
+ a2_s_o1->removeAnimationChangeListener(&a2Spy, QAbstractAnimationJob::StateChange);
+ a3_s_o1->removeAnimationChangeListener(&a3Spy, QAbstractAnimationJob::StateChange);
+ sequence->removeAnimationChangeListener(&seqSpy, QAbstractAnimationJob::StateChange);
+ group.removeAnimationChangeListener(&groupSpy, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QSequentialAnimationGroupJob::startDelay()
+{
+ QSequentialAnimationGroupJob group;
+ group.appendAnimation(new QPauseAnimationJob(250));
+ group.appendAnimation(new QPauseAnimationJob(125));
+ QCOMPARE(group.totalDuration(), 375);
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+
+ QTest::qWait(500);
+
+ QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QVERIFY(group.currentLoopTime() == 375);
+}
+
+void tst_QSequentialAnimationGroupJob::clearGroup()
+{
+ QSequentialAnimationGroupJob group;
+
+ static const int animationCount = 20;
+
+ for (int i = 0; i < animationCount/2; ++i) {
+ QSequentialAnimationGroupJob *subGroup = new QSequentialAnimationGroupJob;
+ group.appendAnimation(subGroup);
+ group.appendAnimation(new QPauseAnimationJob(100));
+ subGroup->appendAnimation(new QPauseAnimationJob(10));
+ }
+
+ int count = 0;
+ for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling())
+ ++count;
+ QCOMPARE(count, animationCount);
+
+ group.clear();
+
+ QVERIFY(!group.firstChild() && !group.lastChild());
+ QCOMPARE(group.currentLoopTime(), 0);
+}
+
+void tst_QSequentialAnimationGroupJob::groupWithZeroDurationAnimations()
+{
+ QSequentialAnimationGroupJob group;
+
+ TestValueAnimation *a1 = new TestValueAnimation(0);
+ a1->start = 42;
+ a1->end = 43;
+ group.appendAnimation(a1);
+
+ //this should just run fine and change nothing
+ group.setCurrentTime(0);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(a1));
+
+ TestValueAnimation *a2 = new TestValueAnimation(500);
+ a2->start = 13;
+ a2->end = 31;
+ group.appendAnimation(a2);
+
+ TestValueAnimation *a3 = new TestValueAnimation(0);
+ a3->start = 43;
+ a3->end = 44;
+ group.appendAnimation(a3);
+
+ TestValueAnimation *a4 = new TestValueAnimation(250);
+ a4->start = 13;
+ a4->end = 75;
+ group.appendAnimation(a4);
+
+ TestValueAnimation *a5 = new TestValueAnimation(0);
+ a5->start = 42;
+ a5->end = 12;
+ group.appendAnimation(a5);
+
+ QCOMPARE((int)a1->value, 43); //### is this actually the behavior we want?
+ QCOMPARE((int)a2->value, 0);
+ QCOMPARE((int)a3->value, 0);
+ QCOMPARE((int)a4->value, 0);
+ QCOMPARE((int)a5->value, 0);
+
+ group.start();
+
+ QCOMPARE((int)a1->value, 43); //### is this actually the behavior we want?
+ QCOMPARE((int)a2->value, 13);
+ QCOMPARE((int)a3->value, 0);
+ QCOMPARE((int)a4->value, 0);
+ QCOMPARE((int)a5->value, 0);
+
+ QTest::qWait(100);
+
+ QCOMPARE((int)a1->value, 43);
+ QVERIFY(a2->value > 13 && a2->value < 31);
+ QCOMPARE((int)a3->value, 0);
+ QCOMPARE((int)a4->value, 0);
+ QCOMPARE((int)a5->value, 0);
+
+ QTest::qWait(500);
+
+ QTRY_COMPARE((int)a3->value, 44);
+ QCOMPARE((int)a1->value, 43);
+ QCOMPARE((int)a2->value, 31);
+ //QCOMPARE((int)a4->value, 36);
+ QCOMPARE((int)a5->value, 0);
+ QCOMPARE(a1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a4->state(), QAnimationGroupJob::Running);
+ QCOMPARE(a5->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QTest::qWait(500);
+
+ QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE((int)a1->value, 43);
+ QCOMPARE((int)a2->value, 31);
+ QCOMPARE((int)a3->value, 44);
+ QCOMPARE((int)a4->value, 75);
+ QCOMPARE((int)a5->value, 12);
+ QCOMPARE(a1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a2->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a3->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a4->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(a5->state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QSequentialAnimationGroupJob::propagateGroupUpdateToChildren()
+{
+ // this test verifies if group state changes are updating its children correctly
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation anim1(100);
+ TestAnimation anim2(200);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QSequentialAnimationGroupJob::updateChildrenWithRunningGroup()
+{
+ // assert that its possible to modify a child's state directly while their group is running
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation anim(200);
+
+ StateChangeListener groupStateChangedSpy;
+ group.addAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange);
+ StateChangeListener childStateChangedSpy;
+ anim.addAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ QCOMPARE(groupStateChangedSpy.count(), 0);
+ QCOMPARE(childStateChangedSpy.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Running);
+
+ QCOMPARE(groupStateChangedSpy.count(), 1);
+ QCOMPARE(childStateChangedSpy.count(), 1);
+
+ QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(childStateChangedSpy.states.at(0), QAnimationGroupJob::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(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Paused);
+
+ // in the animation stops directly, the group will still be running
+ anim.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Stopped);
+
+ //cleanup
+ group.removeAnimationChangeListener(&groupStateChangedSpy, QAbstractAnimationJob::StateChange);
+ anim.removeAnimationChangeListener(&childStateChangedSpy, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QSequentialAnimationGroupJob::deleteChildrenWithRunningGroup()
+{
+ // test if children can be activated when their group is stopped
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation *anim1 = new TestAnimation(200);
+ group.appendAnimation(anim1);
+
+ QCOMPARE(group.duration(), anim1->duration());
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
+
+ QTest::qWait(100);
+ QTRY_VERIFY(group.currentLoopTime() > 0);
+
+ delete anim1;
+ QVERIFY(!group.firstChild());
+ QCOMPARE(group.duration(), 0);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(group.currentLoopTime(), 0); //that's the invariant
+}
+
+void tst_QSequentialAnimationGroupJob::startChildrenWithStoppedGroup()
+{
+ // test if children can be activated when their group is stopped
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation anim1(200);
+ TestAnimation anim2(200);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+}
+
+void tst_QSequentialAnimationGroupJob::stopGroupWithRunningChild()
+{
+ // children that started independently will not be affected by a group stop
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation anim1(200);
+ TestAnimation anim2(200);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(&anim1);
+ group.appendAnimation(&anim2);
+
+ anim1.start();
+ anim2.start();
+ anim2.pause();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
+
+ anim1.stop();
+ anim2.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QSequentialAnimationGroupJob::startGroupWithRunningChild()
+{
+ // as the group has precedence over its children, starting a group will restart all the children
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation *anim1 = new TestAnimation(200);
+ TestAnimation *anim2 = new TestAnimation(200);
+
+ StateChangeListener stateChangedSpy1;
+ anim1->addAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange);
+ StateChangeListener stateChangedSpy2;
+ anim2->addAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange);
+
+ QCOMPARE(stateChangedSpy1.count(), 0);
+ QCOMPARE(stateChangedSpy2.count(), 0);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Stopped);
+
+ group.appendAnimation(anim1);
+ group.appendAnimation(anim2);
+
+ anim1->start();
+ anim2->start();
+ anim2->pause();
+
+ QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimationJob::Running)));
+
+ QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused)));
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Paused);
+
+ group.start();
+
+ QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Stopped
+ << QAbstractAnimationJob::Running)));
+ QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimationJob::Running
+ << QAbstractAnimationJob::Paused)));
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Paused);
+
+ QTest::qWait(300);
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Running);
+
+ QCOMPARE(stateChangedSpy2.count(), 4);
+ QCOMPARE(stateChangedSpy2.states.at(2), QAnimationGroupJob::Stopped);
+ QCOMPARE(stateChangedSpy2.states.at(3), QAnimationGroupJob::Running);
+
+ group.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Stopped);
+
+ anim1->removeAnimationChangeListener(&stateChangedSpy1, QAbstractAnimationJob::StateChange);
+ anim2->removeAnimationChangeListener(&stateChangedSpy2, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QSequentialAnimationGroupJob::zeroDurationAnimation()
+{
+ QSequentialAnimationGroupJob group;
+
+ TestAnimation *anim1 = new TestAnimation(0);
+ TestAnimation *anim2 = new TestAnimation(100);
+ TestValueAnimation *anim3 = new TestValueAnimation(0);
+ anim3->end = 100;
+
+ StateChangeListener stateChangedSpy;
+ anim1->addAnimationChangeListener(&stateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ group.appendAnimation(anim1);
+ group.appendAnimation(anim2);
+ group.appendAnimation(anim3);
+ group.setLoopCount(2);
+ group.start();
+
+ QCOMPARE(stateChangedSpy.count(), 2);
+ QCOMPARE(stateChangedSpy.states.at(0), QAnimationGroupJob::Running);
+ QCOMPARE(stateChangedSpy.states.at(1), QAnimationGroupJob::Stopped);
+
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+
+ //now let's try to seek to the next loop
+ group.setCurrentTime(group.duration() + 1);
+ QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim2->state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim3->state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ //TODO: test that anim3 was run
+ QCOMPARE(anim3->value, qreal(100)); //anim3 should have been run
+
+ anim1->removeAnimationChangeListener(&stateChangedSpy, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QSequentialAnimationGroupJob::stopUncontrolledAnimations()
+{
+ QSequentialAnimationGroupJob group;
+
+ UncontrolledAnimation notTimeDriven;
+ QCOMPARE(notTimeDriven.totalDuration(), -1);
+
+ TestAnimation loopsForever(100);
+ loopsForever.setLoopCount(-1);
+
+ group.appendAnimation(&notTimeDriven);
+ group.appendAnimation(&loopsForever);
+
+ group.start();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
+ QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped);
+
+ notTimeDriven.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running);
+
+ loopsForever.stop();
+
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped);
+}
+
+void tst_QSequentialAnimationGroupJob::finishWithUncontrolledAnimation()
+{
+ //1st case:
+ //first we test a group with one uncontrolled animation
+ QSequentialAnimationGroupJob group;
+ UncontrolledAnimation notTimeDriven;
+ group.appendAnimation(&notTimeDriven);
+ FinishedListener spy;
+ group.addAnimationChangeListener(&spy, QAbstractAnimationJob::Completion);
+
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.currentLoopTime(), 0);
+ QCOMPARE(notTimeDriven.currentLoopTime(), 0);
+
+ QTest::qWait(300); //wait for the end of notTimeDriven
+ QTRY_COMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
+ const int actualDuration = notTimeDriven.currentLoopTime();
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(group.currentLoopTime(), actualDuration);
+ QCOMPARE(spy.count(), 1);
+
+ //2nd case:
+ // lets make sure the seeking will work again
+ spy.clear();
+ TestAnimation anim;
+ group.appendAnimation(&anim);
+ StateChangeListener animStateChangedSpy;
+ anim.addAnimationChangeListener(&animStateChangedSpy, QAbstractAnimationJob::StateChange);
+
+ group.setCurrentTime(300);
+ QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(notTimeDriven.currentLoopTime(), actualDuration);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
+
+ //3rd case:
+ //now let's add a perfectly defined animation at the end
+ QCOMPARE(animStateChangedSpy.count(), 0);
+ group.start();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.currentLoopTime(), 0);
+ QCOMPARE(notTimeDriven.currentLoopTime(), 0);
+
+ QCOMPARE(animStateChangedSpy.count(), 0);
+
+ QTest::qWait(300); //wait for the end of notTimeDriven
+ QTRY_COMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim.state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
+ QCOMPARE(animStateChangedSpy.count(), 1);
+ QTest::qWait(300); //wait for the end of anim
+
+ QTRY_COMPARE(anim.state(), QAnimationGroupJob::Stopped);
+ QCOMPARE(anim.currentLoopTime(), anim.duration());
+
+ //we should simply be at the end
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(animStateChangedSpy.count(), 2);
+ QCOMPARE(group.currentLoopTime(), notTimeDriven.currentLoopTime() + anim.currentLoopTime());
+
+ //cleanup
+ group.removeAnimationChangeListener(&spy, QAbstractAnimationJob::Completion);
+ anim.removeAnimationChangeListener(&animStateChangedSpy, QAbstractAnimationJob::StateChange);
+}
+
+void tst_QSequentialAnimationGroupJob::addRemoveAnimation()
+{
+ //this test is specific to the sequential animation group
+ QSequentialAnimationGroupJob group;
+
+ QCOMPARE(group.duration(), 0);
+ QCOMPARE(group.currentLoopTime(), 0);
+ QAbstractAnimationJob *anim1 = new TestAnimation;
+ group.appendAnimation(anim1);
+ QCOMPARE(group.duration(), 250);
+ QCOMPARE(group.currentLoopTime(), 0);
+ QCOMPARE(group.currentAnimation(), anim1);
+
+ //let's append an animation
+ QAbstractAnimationJob *anim2 = new TestAnimation;
+ group.appendAnimation(anim2);
+ QCOMPARE(group.duration(), 500);
+ QCOMPARE(group.currentLoopTime(), 0);
+ QCOMPARE(group.currentAnimation(), anim1);
+
+ //let's prepend an animation
+ QAbstractAnimationJob *anim0 = new TestAnimation;
+ group.prependAnimation(anim0);
+ QCOMPARE(group.duration(), 750);
+ QCOMPARE(group.currentLoopTime(), 0);
+ QCOMPARE(group.currentAnimation(), anim0); //anim0 has become the new currentAnimation
+
+ group.setCurrentTime(300); //anim0 | anim1 | anim2
+ QCOMPARE(group.currentLoopTime(), 300);
+ QCOMPARE(group.currentAnimation(), anim1);
+ QCOMPARE(anim1->currentLoopTime(), 50);
+
+ group.removeAnimation(anim0); //anim1 | anim2
+ QCOMPARE(group.currentLoopTime(), 50);
+ QCOMPARE(group.currentAnimation(), anim1);
+ QCOMPARE(anim1->currentLoopTime(), 50);
+
+ group.setCurrentTime(0);
+ group.prependAnimation(anim0); //anim0 | anim1 | anim2
+ group.setCurrentTime(300);
+ QCOMPARE(group.currentLoopTime(), 300);
+ QCOMPARE(group.currentAnimation(), anim1);
+ QCOMPARE(anim1->currentLoopTime(), 50);
+
+ group.removeAnimation(anim1); //anim0 | anim2
+ QCOMPARE(group.currentLoopTime(), 250);
+ QCOMPARE(group.currentAnimation(), anim2);
+ QCOMPARE(anim0->currentLoopTime(), 250);
+}
+
+void tst_QSequentialAnimationGroupJob::currentAnimation()
+{
+ QSequentialAnimationGroupJob group;
+ QVERIFY(group.currentAnimation() == 0);
+
+ TestAnimation anim(0);
+ group.appendAnimation(&anim);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
+}
+
+void tst_QSequentialAnimationGroupJob::currentAnimationWithZeroDuration()
+{
+ QSequentialAnimationGroupJob group;
+ QVERIFY(group.currentAnimation() == 0);
+
+ TestAnimation zero1(0);
+ TestAnimation zero2(0);
+
+ TestAnimation anim;
+
+ TestAnimation zero3(0);
+ TestAnimation zero4(0);
+
+ group.appendAnimation(&zero1);
+ group.appendAnimation(&zero2);
+ group.appendAnimation(&anim);
+ group.appendAnimation(&zero3);
+ group.appendAnimation(&zero4);
+
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero1));
+
+ group.setCurrentTime(0);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
+
+ group.setCurrentTime(group.duration());
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero4));
+
+ group.setDirection(QAbstractAnimationJob::Backward);
+
+ group.setCurrentTime(0);
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero1));
+
+ group.setCurrentTime(group.duration());
+ QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
+}
+
+void tst_QSequentialAnimationGroupJob::insertAnimation()
+{
+ QSequentialAnimationGroupJob group;
+ group.setLoopCount(2);
+ TestAnimation *anim = new TestAnimation;
+ group.appendAnimation(anim);
+ 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
+ group.appendAnimation(new TestAnimation);
+}
+
+class ClearFinishedListener: public QAnimation2ChangeListener
+{
+public:
+ ClearFinishedListener(QSequentialAnimationGroupJob *g) : group(g) {}
+
+ virtual void animationFinished(QAbstractAnimationJob *)
+ {
+ group->clear();
+ }
+
+ QSequentialAnimationGroupJob *group;
+};
+
+class RefillFinishedListener: public QAnimation2ChangeListener
+{
+public:
+ RefillFinishedListener(QSequentialAnimationGroupJob *g) : group(g) {}
+
+ virtual void animationFinished(QAbstractAnimationJob *)
+ {
+ group->stop();
+ group->clear();
+ group->appendAnimation(new TestAnimation);
+ group->start();
+ }
+
+ QSequentialAnimationGroupJob *group;
+};
+
+void tst_QSequentialAnimationGroupJob::clear()
+{
+ QSKIP("deleting an animation when finished is not currently supported");
+ QSequentialAnimationGroupJob group;
+ TestAnimation *anim1 = new TestAnimation;
+ group.appendAnimation(anim1);
+ ClearFinishedListener clearListener(&group);
+ anim1->addAnimationChangeListener(&clearListener, QAbstractAnimationJob::Completion);
+
+ TestAnimation *anim2 = new TestAnimation;
+ group.appendAnimation(anim2);
+ QCOMPARE(group.firstChild(), anim1);
+ QCOMPARE(group.lastChild(), anim2);
+
+ group.start();
+ QTest::qWait(anim1->duration() + 100);
+ QTRY_VERIFY(!group.firstChild());
+ QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
+ QCOMPARE(group.currentLoopTime(), 0);
+
+ anim1 = new TestAnimation;
+ group.appendAnimation(anim1);
+ RefillFinishedListener refillListener(&group);
+ anim1->addAnimationChangeListener(&refillListener, QAbstractAnimationJob::Completion);
+ group.start();
+ QTest::qWait(anim1->duration() + 100);
+ QTRY_COMPARE(group.state(), QAbstractAnimationJob::Running);
+}
+
+void tst_QSequentialAnimationGroupJob::pauseResume()
+{
+ QParallelAnimationGroupJob group;
+ TestAnimation *anim = new TestAnimation;
+ group.appendAnimation(anim);
+ StateChangeListener spy;
+ anim->addAnimationChangeListener(&spy, QAbstractAnimationJob::StateChange);
+ QCOMPARE(group.duration(), 250);
+ group.start();
+ QTest::qWait(100);
+ QTRY_COMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim->state(), QAnimationGroupJob::Running);
+ QCOMPARE(spy.count(), 1);
+ spy.clear();
+ const int currentTime = group.currentLoopTime();
+ QCOMPARE(anim->currentLoopTime(), currentTime);
+
+ group.pause();
+ QCOMPARE(group.state(), QAnimationGroupJob::Paused);
+ QCOMPARE(group.currentLoopTime(), currentTime);
+ QCOMPARE(anim->state(), QAnimationGroupJob::Paused);
+ QCOMPARE(anim->currentLoopTime(), currentTime);
+ QCOMPARE(spy.count(), 1);
+ spy.clear();
+
+ group.resume();
+ QCOMPARE(group.state(), QAnimationGroupJob::Running);
+ QCOMPARE(group.currentLoopTime(), currentTime);
+ QCOMPARE(anim->state(), QAnimationGroupJob::Running);
+ QCOMPARE(anim->currentLoopTime(), currentTime);
+ QCOMPARE(spy.count(), 1);
+
+ anim->removeAnimationChangeListener(&spy, QAbstractAnimationJob::StateChange);
+}
+
+QTEST_MAIN(tst_QSequentialAnimationGroupJob)
+#include "tst_qsequentialanimationgroupjob.moc"
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index 6780a87f55..7288da27ba 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -27,6 +27,7 @@ PUBLICTESTS += \
qmlplugindump
PRIVATETESTS += \
+ animation \
qdeclarativebinding \
qdeclarativechangeset \
qdeclarativeconnection \