qt5base-lts/tests/auto/qsequentialanimationgroup/tst_qsequentialanimationgroup.cpp
Qt by Nokia 38be0d1383 Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:

http://qt.gitorious.org/qt/pages/GitIntroductionWithQt

If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.

Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
2011-04-27 12:05:43 +02:00

1673 lines
60 KiB
C++

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