1244 lines
39 KiB
C++
1244 lines
39 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/qpropertyanimation.h>
|
||
|
#include <QtCore/qvariantanimation.h>
|
||
|
#include <QtGui/qwidget.h>
|
||
|
#include "../../shared/util.h"
|
||
|
|
||
|
//TESTED_CLASS=QPropertyAnimation
|
||
|
//TESTED_FILES=
|
||
|
|
||
|
class UncontrolledAnimation : public QPropertyAnimation
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
int duration() const { return -1; /* not time driven */ }
|
||
|
|
||
|
protected:
|
||
|
void updateCurrentTime(int currentTime)
|
||
|
{
|
||
|
QPropertyAnimation::updateCurrentTime(currentTime);
|
||
|
if (currentTime >= QPropertyAnimation::duration() || currentLoop() >= 1)
|
||
|
stop();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class MyObject : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
Q_PROPERTY(qreal x READ x WRITE setX)
|
||
|
public:
|
||
|
MyObject() : m_x(0) { }
|
||
|
qreal x() const { return m_x; }
|
||
|
void setX(qreal x) { m_x = x; }
|
||
|
private:
|
||
|
qreal m_x;
|
||
|
};
|
||
|
|
||
|
class DummyPropertyAnimation : public QPropertyAnimation
|
||
|
{
|
||
|
public:
|
||
|
DummyPropertyAnimation(QObject *parent = 0) : QPropertyAnimation(parent)
|
||
|
{
|
||
|
setTargetObject(&o);
|
||
|
this->setPropertyName("x");
|
||
|
setEndValue(100);
|
||
|
}
|
||
|
|
||
|
MyObject o;
|
||
|
};
|
||
|
|
||
|
|
||
|
class tst_QPropertyAnimation : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
tst_QPropertyAnimation();
|
||
|
virtual ~tst_QPropertyAnimation();
|
||
|
|
||
|
public Q_SLOTS:
|
||
|
void init();
|
||
|
void cleanup();
|
||
|
|
||
|
private slots:
|
||
|
void construction();
|
||
|
void setCurrentTime_data();
|
||
|
void setCurrentTime();
|
||
|
void statesAndSignals_data();
|
||
|
void statesAndSignals();
|
||
|
void deletion1();
|
||
|
void deletion2();
|
||
|
void deletion3();
|
||
|
void duration0();
|
||
|
void noStartValue();
|
||
|
void noStartValueWithLoop();
|
||
|
void startWhenAnotherIsRunning();
|
||
|
void easingcurve_data();
|
||
|
void easingcurve();
|
||
|
void startWithoutStartValue();
|
||
|
void startBackwardWithoutEndValue();
|
||
|
void playForwardBackward();
|
||
|
void interpolated();
|
||
|
void setStartEndValues_data();
|
||
|
void setStartEndValues();
|
||
|
void zeroDurationStart();
|
||
|
void operationsInStates_data();
|
||
|
void operationsInStates();
|
||
|
void oneKeyValue();
|
||
|
void updateOnSetKeyValues();
|
||
|
void restart();
|
||
|
void valueChanged();
|
||
|
void twoAnimations();
|
||
|
void deletedInUpdateCurrentTime();
|
||
|
void totalDuration();
|
||
|
void zeroLoopCount();
|
||
|
};
|
||
|
|
||
|
tst_QPropertyAnimation::tst_QPropertyAnimation()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
tst_QPropertyAnimation::~tst_QPropertyAnimation()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::init()
|
||
|
{
|
||
|
qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
|
||
|
qRegisterMetaType<QAbstractAnimation::DeletionPolicy>("QAbstractAnimation::DeletionPolicy");
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::cleanup()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
class AnimationObject : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
Q_PROPERTY(int value READ value WRITE setValue)
|
||
|
Q_PROPERTY(qreal realValue READ realValue WRITE setRealValue)
|
||
|
public:
|
||
|
AnimationObject(int startValue = 0)
|
||
|
: v(startValue), rv(startValue)
|
||
|
{ }
|
||
|
|
||
|
int value() const { return v; }
|
||
|
void setValue(int value) { v = value; }
|
||
|
|
||
|
qreal realValue() const { return rv; }
|
||
|
void setRealValue(qreal value) { rv = value; }
|
||
|
|
||
|
int v;
|
||
|
qreal rv;
|
||
|
};
|
||
|
|
||
|
|
||
|
void tst_QPropertyAnimation::construction()
|
||
|
{
|
||
|
QPropertyAnimation panimation;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::setCurrentTime_data()
|
||
|
{
|
||
|
QTest::addColumn<int>("duration");
|
||
|
QTest::addColumn<int>("loopCount");
|
||
|
QTest::addColumn<int>("currentTime");
|
||
|
QTest::addColumn<int>("testCurrentTime");
|
||
|
QTest::addColumn<int>("testCurrentLoop");
|
||
|
|
||
|
QTest::newRow("-1") << -1 << 1 << 0 << 0 << 0;
|
||
|
QTest::newRow("0") << 0 << 1 << 0 << 0 << 0;
|
||
|
QTest::newRow("1") << 0 << 1 << 1 << 0 << 0;
|
||
|
QTest::newRow("2") << 0 << 2 << 1 << 0 << 0;
|
||
|
QTest::newRow("3") << 1 << 1 << 0 << 0 << 0;
|
||
|
QTest::newRow("4") << 1 << 1 << 1 << 1 << 0;
|
||
|
QTest::newRow("5") << 1 << 2 << 1 << 0 << 1;
|
||
|
QTest::newRow("6") << 1 << 2 << 2 << 1 << 1;
|
||
|
QTest::newRow("7") << 1 << 2 << 3 << 1 << 1;
|
||
|
QTest::newRow("8") << 1 << 3 << 2 << 0 << 2;
|
||
|
QTest::newRow("9") << 1 << 3 << 3 << 1 << 2;
|
||
|
QTest::newRow("a") << 10 << 1 << 0 << 0 << 0;
|
||
|
QTest::newRow("b") << 10 << 1 << 1 << 1 << 0;
|
||
|
QTest::newRow("c") << 10 << 1 << 10 << 10 << 0;
|
||
|
QTest::newRow("d") << 10 << 2 << 10 << 0 << 1;
|
||
|
QTest::newRow("e") << 10 << 2 << 11 << 1 << 1;
|
||
|
QTest::newRow("f") << 10 << 2 << 20 << 10 << 1;
|
||
|
QTest::newRow("g") << 10 << 2 << 21 << 10 << 1;
|
||
|
QTest::newRow("negloop 0") << 10 << -1 << 0 << 0 << 0;
|
||
|
QTest::newRow("negloop 1") << 10 << -1 << 10 << 0 << 1;
|
||
|
QTest::newRow("negloop 2") << 10 << -1 << 15 << 5 << 1;
|
||
|
QTest::newRow("negloop 3") << 10 << -1 << 20 << 0 << 2;
|
||
|
QTest::newRow("negloop 4") << 10 << -1 << 30 << 0 << 3;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::setCurrentTime()
|
||
|
{
|
||
|
QFETCH(int, duration);
|
||
|
QFETCH(int, loopCount);
|
||
|
QFETCH(int, currentTime);
|
||
|
QFETCH(int, testCurrentTime);
|
||
|
QFETCH(int, testCurrentLoop);
|
||
|
|
||
|
QPropertyAnimation animation;
|
||
|
if (duration < 0)
|
||
|
QTest::ignoreMessage(QtWarningMsg, "QVariantAnimation::setDuration: cannot set a negative duration");
|
||
|
animation.setDuration(duration);
|
||
|
animation.setLoopCount(loopCount);
|
||
|
animation.setCurrentTime(currentTime);
|
||
|
|
||
|
QCOMPARE(animation.currentLoopTime(), testCurrentTime);
|
||
|
QCOMPARE(animation.currentLoop(), testCurrentLoop);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::statesAndSignals_data()
|
||
|
{
|
||
|
QTest::addColumn<bool>("uncontrolled");
|
||
|
QTest::newRow("normal animation") << false;
|
||
|
QTest::newRow("animation with undefined duration") << true;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::statesAndSignals()
|
||
|
{
|
||
|
QFETCH(bool, uncontrolled);
|
||
|
QPropertyAnimation *anim;
|
||
|
if (uncontrolled)
|
||
|
anim = new UncontrolledAnimation;
|
||
|
else
|
||
|
anim = new DummyPropertyAnimation;
|
||
|
anim->setDuration(100);
|
||
|
|
||
|
QSignalSpy finishedSpy(anim, SIGNAL(finished()));
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
QSignalSpy currentLoopSpy(anim, SIGNAL(currentLoopChanged(int)));
|
||
|
|
||
|
anim->setCurrentTime(1);
|
||
|
anim->setCurrentTime(100);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
QCOMPARE(runningSpy.count(), 0);
|
||
|
QCOMPARE(currentLoopSpy.count(), 0);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
|
||
|
anim->setLoopCount(3);
|
||
|
anim->setCurrentTime(101);
|
||
|
|
||
|
if (uncontrolled)
|
||
|
QSKIP("Uncontrolled animations don't handle looping", SkipSingle);
|
||
|
|
||
|
QCOMPARE(currentLoopSpy.count(), 1);
|
||
|
QCOMPARE(anim->currentLoop(), 1);
|
||
|
|
||
|
anim->setCurrentTime(0);
|
||
|
QCOMPARE(currentLoopSpy.count(), 2);
|
||
|
QCOMPARE(anim->currentLoop(), 0);
|
||
|
|
||
|
anim->start();
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QCOMPARE(runningSpy.count(), 1); //anim must have started
|
||
|
QCOMPARE(anim->currentLoop(), 0);
|
||
|
runningSpy.clear();
|
||
|
|
||
|
anim->stop();
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(runningSpy.count(), 1); //anim must have stopped
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
QCOMPARE(anim->currentLoopTime(), 0);
|
||
|
QCOMPARE(anim->currentLoop(), 0);
|
||
|
QCOMPARE(currentLoopSpy.count(), 2);
|
||
|
runningSpy.clear();
|
||
|
|
||
|
anim->start();
|
||
|
QTest::qWait(1000);
|
||
|
QTRY_COMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(runningSpy.count(), 2); //started and stopped again
|
||
|
runningSpy.clear();
|
||
|
QCOMPARE(finishedSpy.count(), 1);
|
||
|
QCOMPARE(anim->currentLoopTime(), 100);
|
||
|
QCOMPARE(anim->currentLoop(), 2);
|
||
|
QCOMPARE(currentLoopSpy.count(), 4);
|
||
|
|
||
|
anim->start(); // auto-rewinds
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QCOMPARE(anim->currentTime(), 0);
|
||
|
QCOMPARE(anim->currentLoop(), 0);
|
||
|
QCOMPARE(currentLoopSpy.count(), 5);
|
||
|
QCOMPARE(runningSpy.count(), 1); // anim has started
|
||
|
QCOMPARE(finishedSpy.count(), 1);
|
||
|
QCOMPARE(anim->currentLoop(), 0);
|
||
|
runningSpy.clear();
|
||
|
|
||
|
QTest::qWait(1000);
|
||
|
|
||
|
QCOMPARE(currentLoopSpy.count(), 7);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(anim->currentLoop(), 2);
|
||
|
QCOMPARE(runningSpy.count(), 1); // anim has stopped
|
||
|
QCOMPARE(finishedSpy.count(), 2);
|
||
|
QCOMPARE(anim->currentLoopTime(), 100);
|
||
|
|
||
|
delete anim;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::deletion1()
|
||
|
{
|
||
|
QObject *object = new QWidget;
|
||
|
QPointer<QPropertyAnimation> anim = new QPropertyAnimation(object, "minimumWidth");
|
||
|
|
||
|
//test that the animation is deleted correctly depending of the deletion flag passed in start()
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
QSignalSpy finishedSpy(anim, SIGNAL(finished()));
|
||
|
anim->setStartValue(10);
|
||
|
anim->setEndValue(20);
|
||
|
anim->setDuration(200);
|
||
|
anim->start();
|
||
|
QCOMPARE(runningSpy.count(), 1);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
|
||
|
QVERIFY(anim);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QTest::qWait(100);
|
||
|
QVERIFY(anim);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QTest::qWait(150);
|
||
|
QVERIFY(anim); //The animation should not have been deleted
|
||
|
QTRY_COMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(runningSpy.count(), 2);
|
||
|
QCOMPARE(finishedSpy.count(), 1);
|
||
|
|
||
|
anim->start(QVariantAnimation::DeleteWhenStopped);
|
||
|
QVERIFY(anim);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QTest::qWait(100);
|
||
|
QVERIFY(anim);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QTest::qWait(150);
|
||
|
QTRY_COMPARE(runningSpy.count(), 4);
|
||
|
QCOMPARE(finishedSpy.count(), 2);
|
||
|
QVERIFY(!anim); //The animation must have been deleted
|
||
|
delete object;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::deletion2()
|
||
|
{
|
||
|
//test that the animation get deleted if the object is deleted
|
||
|
QObject *object = new QWidget;
|
||
|
QPointer<QPropertyAnimation> anim = new QPropertyAnimation(object,"minimumWidth");
|
||
|
anim->setStartValue(10);
|
||
|
anim->setEndValue(20);
|
||
|
anim->setDuration(200);
|
||
|
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
QSignalSpy finishedSpy(anim, SIGNAL(finished()));
|
||
|
|
||
|
anim->setStartValue(10);
|
||
|
anim->setEndValue(20);
|
||
|
anim->setDuration(200);
|
||
|
anim->start();
|
||
|
|
||
|
QTest::qWait(50);
|
||
|
QVERIFY(anim);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
|
||
|
QCOMPARE(runningSpy.count(), 1);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
|
||
|
//we can't call deletaLater directly because the delete would only happen in the next loop of _this_ event loop
|
||
|
QTimer::singleShot(0, object, SLOT(deleteLater()));
|
||
|
QTest::qWait(50);
|
||
|
|
||
|
QVERIFY(anim->targetObject() == 0);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::deletion3()
|
||
|
{
|
||
|
//test that the stopped signal is emit when the animation is destroyed
|
||
|
QObject *object = new QWidget;
|
||
|
QPropertyAnimation *anim = new QPropertyAnimation(object,"minimumWidth");
|
||
|
anim->setStartValue(10);
|
||
|
anim->setEndValue(20);
|
||
|
anim->setDuration(200);
|
||
|
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
QSignalSpy finishedSpy(anim, SIGNAL(finished()));
|
||
|
anim->start();
|
||
|
|
||
|
QTest::qWait(50);
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Running);
|
||
|
QCOMPARE(runningSpy.count(), 1);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
delete anim;
|
||
|
QCOMPARE(runningSpy.count(), 2);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::duration0()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 42);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
|
||
|
QPropertyAnimation animation(&o, "ole");
|
||
|
animation.setEndValue(43);
|
||
|
QVERIFY(!animation.currentValue().isValid());
|
||
|
QCOMPARE(animation.currentValue().toInt(), 0);
|
||
|
animation.setStartValue(42);
|
||
|
QVERIFY(animation.currentValue().isValid());
|
||
|
QCOMPARE(animation.currentValue().toInt(), 42);
|
||
|
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
animation.setDuration(0);
|
||
|
QCOMPARE(animation.currentValue().toInt(), 43); //it is at the end
|
||
|
animation.start();
|
||
|
QCOMPARE(animation.state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(animation.currentTime(), 0);
|
||
|
QCOMPARE(o.property("ole").toInt(), 43);
|
||
|
}
|
||
|
|
||
|
class StartValueTester : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
Q_PROPERTY(int ole READ ole WRITE setOle)
|
||
|
public:
|
||
|
StartValueTester() : o(0) { }
|
||
|
int ole() const { return o; }
|
||
|
void setOle(int v) { o = v; values << v; }
|
||
|
|
||
|
int o;
|
||
|
QList<int> values;
|
||
|
};
|
||
|
|
||
|
void tst_QPropertyAnimation::noStartValue()
|
||
|
{
|
||
|
StartValueTester o;
|
||
|
o.setProperty("ole", 42);
|
||
|
o.values.clear();
|
||
|
|
||
|
QPropertyAnimation a(&o, "ole");
|
||
|
a.setEndValue(420);
|
||
|
a.setDuration(250);
|
||
|
a.start();
|
||
|
|
||
|
QTest::qWait(300);
|
||
|
|
||
|
QTRY_COMPARE(o.values.first(), 42);
|
||
|
QCOMPARE(o.values.last(), 420);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::noStartValueWithLoop()
|
||
|
{
|
||
|
StartValueTester o;
|
||
|
o.setProperty("ole", 42);
|
||
|
o.values.clear();
|
||
|
|
||
|
QPropertyAnimation a(&o, "ole");
|
||
|
a.setEndValue(420);
|
||
|
a.setDuration(250);
|
||
|
a.setLoopCount(2);
|
||
|
a.start();
|
||
|
|
||
|
a.setCurrentTime(250);
|
||
|
QCOMPARE(o.values.first(), 42);
|
||
|
QCOMPARE(a.currentValue().toInt(), 42);
|
||
|
QCOMPARE(o.values.last(), 42);
|
||
|
|
||
|
a.setCurrentTime(500);
|
||
|
QCOMPARE(a.currentValue().toInt(), 420);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::startWhenAnotherIsRunning()
|
||
|
{
|
||
|
StartValueTester o;
|
||
|
o.setProperty("ole", 42);
|
||
|
o.values.clear();
|
||
|
|
||
|
{
|
||
|
//normal case: the animation finishes and is deleted
|
||
|
QPointer<QVariantAnimation> anim = new QPropertyAnimation(&o, "ole");
|
||
|
anim->setEndValue(100);
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
anim->start(QVariantAnimation::DeleteWhenStopped);
|
||
|
QTest::qWait(anim->duration() + 100);
|
||
|
QTRY_COMPARE(runningSpy.count(), 2); //started and then stopped
|
||
|
QVERIFY(!anim);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
QPointer<QVariantAnimation> anim = new QPropertyAnimation(&o, "ole");
|
||
|
anim->setEndValue(100);
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
anim->start(QVariantAnimation::DeleteWhenStopped);
|
||
|
QTest::qWait(anim->duration()/2);
|
||
|
QPointer<QVariantAnimation> anim2 = new QPropertyAnimation(&o, "ole");
|
||
|
anim2->setEndValue(100);
|
||
|
QCOMPARE(runningSpy.count(), 1);
|
||
|
QCOMPARE(anim->state(), QVariantAnimation::Running);
|
||
|
|
||
|
//anim2 will interrupt anim1
|
||
|
QMetaObject::invokeMethod(anim2, "start", Qt::QueuedConnection, Q_ARG(QAbstractAnimation::DeletionPolicy, QVariantAnimation::DeleteWhenStopped));
|
||
|
QTest::qWait(50);
|
||
|
QVERIFY(!anim); //anim should have been deleted
|
||
|
QVERIFY(anim2);
|
||
|
QTest::qWait(anim2->duration());
|
||
|
QTRY_VERIFY(!anim2); //anim2 is finished: it should have been deleted by now
|
||
|
QVERIFY(!anim);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// copy from easing.cpp in case that function changes definition
|
||
|
static qreal easeInOutBack(qreal t)
|
||
|
{
|
||
|
qreal s = 1.70158;
|
||
|
qreal t_adj = 2.0f * (qreal)t;
|
||
|
if (t_adj < 1) {
|
||
|
s *= 1.525f;
|
||
|
return 1.0/2*(t_adj*t_adj*((s+1)*t_adj - s));
|
||
|
} else {
|
||
|
t_adj -= 2;
|
||
|
s *= 1.525f;
|
||
|
return 1.0/2*(t_adj*t_adj*((s+1)*t_adj + s) + 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::easingcurve_data()
|
||
|
{
|
||
|
QTest::addColumn<int>("currentTime");
|
||
|
QTest::addColumn<int>("expectedvalue");
|
||
|
|
||
|
QTest::newRow("interpolation1") << 0 << 0;
|
||
|
QTest::newRow("interpolation2") << 1000 << 1000;
|
||
|
QTest::newRow("extrapolationbelow") << 250 << -99;
|
||
|
QTest::newRow("extrapolationabove") << 750 << 1099;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::easingcurve()
|
||
|
{
|
||
|
QFETCH(int, currentTime);
|
||
|
QFETCH(int, expectedvalue);
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 42);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
|
||
|
QPropertyAnimation pAnimation(&o, "ole");
|
||
|
pAnimation.setStartValue(0);
|
||
|
pAnimation.setEndValue(1000);
|
||
|
pAnimation.setDuration(1000);
|
||
|
|
||
|
// this easingcurve assumes that we extrapolate before startValue and after endValue
|
||
|
QEasingCurve easingCurve;
|
||
|
easingCurve.setCustomType(easeInOutBack);
|
||
|
pAnimation.setEasingCurve(easingCurve);
|
||
|
pAnimation.start();
|
||
|
pAnimation.pause();
|
||
|
pAnimation.setCurrentTime(currentTime);
|
||
|
QCOMPARE(o.property("ole").toInt(), expectedvalue);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::startWithoutStartValue()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 42);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
|
||
|
QPropertyAnimation anim(&o, "ole");
|
||
|
anim.setEndValue(100);
|
||
|
|
||
|
anim.start();
|
||
|
|
||
|
QTest::qWait(100);
|
||
|
int current = anim.currentValue().toInt();
|
||
|
//it is somewhere in the animation
|
||
|
QVERIFY(current > 42);
|
||
|
QVERIFY(current < 100);
|
||
|
|
||
|
QTest::qWait(200);
|
||
|
QTRY_COMPARE(anim.state(), QVariantAnimation::Stopped);
|
||
|
current = anim.currentValue().toInt();
|
||
|
QCOMPARE(current, 100);
|
||
|
QCOMPARE(o.property("ole").toInt(), current);
|
||
|
|
||
|
anim.setEndValue(110);
|
||
|
anim.start();
|
||
|
current = anim.currentValue().toInt();
|
||
|
// the default start value will reevaluate the current property
|
||
|
// and set it to the end value of the last iteration
|
||
|
QCOMPARE(current, 100);
|
||
|
QTest::qWait(100);
|
||
|
current = anim.currentValue().toInt();
|
||
|
//it is somewhere in the animation
|
||
|
QVERIFY(current >= 100);
|
||
|
QVERIFY(current <= 110);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::startBackwardWithoutEndValue()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 42);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
|
||
|
QPropertyAnimation anim(&o, "ole");
|
||
|
anim.setStartValue(100);
|
||
|
anim.setDirection(QAbstractAnimation::Backward);
|
||
|
|
||
|
//we start without an end value
|
||
|
anim.start();
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Running);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42); //the initial value
|
||
|
|
||
|
QTest::qWait(100);
|
||
|
int current = anim.currentValue().toInt();
|
||
|
//it is somewhere in the animation
|
||
|
QVERIFY(current > 42);
|
||
|
QVERIFY(current < 100);
|
||
|
|
||
|
QTest::qWait(200);
|
||
|
QTRY_COMPARE(anim.state(), QVariantAnimation::Stopped);
|
||
|
current = anim.currentValue().toInt();
|
||
|
QCOMPARE(current, 100);
|
||
|
QCOMPARE(o.property("ole").toInt(), current);
|
||
|
|
||
|
anim.setStartValue(110);
|
||
|
anim.start();
|
||
|
current = anim.currentValue().toInt();
|
||
|
// the default start value will reevaluate the current property
|
||
|
// and set it to the end value of the last iteration
|
||
|
QCOMPARE(current, 100);
|
||
|
QTest::qWait(100);
|
||
|
current = anim.currentValue().toInt();
|
||
|
//it is somewhere in the animation
|
||
|
QVERIFY(current >= 100);
|
||
|
QVERIFY(current <= 110);
|
||
|
}
|
||
|
|
||
|
|
||
|
void tst_QPropertyAnimation::playForwardBackward()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 0);
|
||
|
QCOMPARE(o.property("ole").toInt(), 0);
|
||
|
|
||
|
QPropertyAnimation anim(&o, "ole");
|
||
|
anim.setStartValue(0);
|
||
|
anim.setEndValue(100);
|
||
|
anim.start();
|
||
|
QTest::qWait(anim.duration() + 100);
|
||
|
QTRY_COMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(anim.currentTime(), anim.duration());
|
||
|
|
||
|
//the animation is at the end
|
||
|
anim.setDirection(QVariantAnimation::Backward);
|
||
|
anim.start();
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Running);
|
||
|
QTest::qWait(anim.duration() + 100);
|
||
|
QTRY_COMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(anim.currentTime(), 0);
|
||
|
|
||
|
//the direction is backward
|
||
|
//restarting should jump to the end
|
||
|
anim.start();
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Running);
|
||
|
QCOMPARE(anim.currentTime(), anim.duration());
|
||
|
QTest::qWait(anim.duration() + 100);
|
||
|
QTRY_COMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(anim.currentTime(), 0);
|
||
|
}
|
||
|
|
||
|
struct Number
|
||
|
{
|
||
|
Number() {}
|
||
|
Number(int n)
|
||
|
: n(n) {}
|
||
|
|
||
|
Number(const Number &other)
|
||
|
: n(other.n){}
|
||
|
|
||
|
Number &operator=(const Number &other) {
|
||
|
n = other.n;
|
||
|
return *this;
|
||
|
}
|
||
|
bool operator==(const Number &other) const {
|
||
|
return n == other.n;
|
||
|
}
|
||
|
|
||
|
int n;
|
||
|
};
|
||
|
|
||
|
Q_DECLARE_METATYPE(Number)
|
||
|
Q_DECLARE_METATYPE(QAbstractAnimation::State)
|
||
|
|
||
|
QVariant numberInterpolator(const Number &f, const Number &t, qreal progress)
|
||
|
{
|
||
|
return qVariantFromValue<Number>(Number(f.n + (t.n - f.n)*progress));
|
||
|
}
|
||
|
|
||
|
QVariant xaxisQPointInterpolator(const QPointF &f, const QPointF &t, qreal progress)
|
||
|
{
|
||
|
return QPointF(f.x() + (t.x() - f.x())*progress, f.y());
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::interpolated()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("point", QPointF()); //this will avoid warnings
|
||
|
o.setProperty("number", qVariantFromValue<Number>(Number(42)));
|
||
|
QCOMPARE(qVariantValue<Number>(o.property("number")), Number(42));
|
||
|
{
|
||
|
qRegisterAnimationInterpolator<Number>(numberInterpolator);
|
||
|
QPropertyAnimation anim(&o, "number");
|
||
|
anim.setStartValue(qVariantFromValue<Number>(Number(0)));
|
||
|
anim.setEndValue(qVariantFromValue<Number>(Number(100)));
|
||
|
anim.setDuration(1000);
|
||
|
anim.start();
|
||
|
anim.pause();
|
||
|
anim.setCurrentTime(100);
|
||
|
Number t(qVariantValue<Number>(o.property("number")));
|
||
|
QCOMPARE(t, Number(10));
|
||
|
anim.setCurrentTime(500);
|
||
|
QCOMPARE(qVariantValue<Number>(o.property("number")), Number(50));
|
||
|
}
|
||
|
{
|
||
|
qRegisterAnimationInterpolator<QPointF>(xaxisQPointInterpolator);
|
||
|
QPropertyAnimation anim(&o, "point");
|
||
|
anim.setStartValue(QPointF(0,0));
|
||
|
anim.setEndValue(QPointF(100, 100));
|
||
|
anim.setDuration(1000);
|
||
|
anim.start();
|
||
|
anim.pause();
|
||
|
anim.setCurrentTime(100);
|
||
|
QCOMPARE(o.property("point"), QVariant(QPointF(10, 0)));
|
||
|
anim.setCurrentTime(500);
|
||
|
QCOMPARE(o.property("point"), QVariant(QPointF(50, 0)));
|
||
|
}
|
||
|
{
|
||
|
// unregister it and see if we get back the default behaviour
|
||
|
qRegisterAnimationInterpolator<QPointF>(0);
|
||
|
QPropertyAnimation anim(&o, "point");
|
||
|
anim.setStartValue(QPointF(0,0));
|
||
|
anim.setEndValue(QPointF(100, 100));
|
||
|
anim.setDuration(1000);
|
||
|
anim.start();
|
||
|
anim.pause();
|
||
|
anim.setCurrentTime(100);
|
||
|
QCOMPARE(o.property("point").toPointF(), QPointF(10, 10));
|
||
|
anim.setCurrentTime(500);
|
||
|
QCOMPARE(o.property("point").toPointF(), QPointF(50, 50));
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// Interpolate a qreal property with a int interpolator
|
||
|
AnimationObject o1;
|
||
|
o1.setRealValue(42.42);
|
||
|
QPropertyAnimation anim(&o1, "realValue");
|
||
|
anim.setStartValue(0);
|
||
|
anim.setEndValue(100);
|
||
|
anim.start();
|
||
|
QCOMPARE(o1.realValue(), qreal(0));
|
||
|
anim.setCurrentTime(250);
|
||
|
QCOMPARE(o1.realValue(), qreal(100));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Q_DECLARE_METATYPE(QVariant)
|
||
|
|
||
|
void tst_QPropertyAnimation::setStartEndValues_data()
|
||
|
{
|
||
|
QTest::addColumn<QByteArray>("propertyName");
|
||
|
QTest::addColumn<QVariant>("initialValue");
|
||
|
QTest::addColumn<QVariant>("startValue");
|
||
|
QTest::addColumn<QVariant>("endValue");
|
||
|
|
||
|
QTest::newRow("dynamic property") << QByteArray("ole") << QVariant(42) << QVariant(0) << QVariant(10);
|
||
|
QTest::newRow("real property, with unmatching types") << QByteArray("x") << QVariant(42.) << QVariant(0) << QVariant(10.);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::setStartEndValues()
|
||
|
{
|
||
|
MyObject object;
|
||
|
QFETCH(QByteArray, propertyName);
|
||
|
QFETCH(QVariant, initialValue);
|
||
|
QFETCH(QVariant, startValue);
|
||
|
QFETCH(QVariant, endValue);
|
||
|
|
||
|
//this tests the start value, end value and default start value
|
||
|
object.setProperty(propertyName, initialValue);
|
||
|
QPropertyAnimation anim(&object, propertyName);
|
||
|
QVariantAnimation::KeyValues values;
|
||
|
QCOMPARE(anim.keyValues(), values);
|
||
|
|
||
|
//let's add a start value
|
||
|
anim.setStartValue(startValue);
|
||
|
values << QVariantAnimation::KeyValue(0, startValue);
|
||
|
QCOMPARE(anim.keyValues(), values);
|
||
|
|
||
|
anim.setEndValue(endValue);
|
||
|
values << QVariantAnimation::KeyValue(1, endValue);
|
||
|
QCOMPARE(anim.keyValues(), values);
|
||
|
|
||
|
//now we can play with objects
|
||
|
QCOMPARE(object.property(propertyName).toDouble(), initialValue.toDouble());
|
||
|
anim.start();
|
||
|
QVERIFY(anim.startValue().isValid());
|
||
|
QCOMPARE(object.property(propertyName), anim.startValue());
|
||
|
anim.setCurrentTime(anim.duration()/2);
|
||
|
QCOMPARE(object.property(propertyName).toDouble(), (startValue.toDouble() + endValue.toDouble())/2 ); //just in the middle of the animation
|
||
|
anim.setCurrentTime(anim.duration()); //we go to the end of the animation
|
||
|
QCOMPARE(anim.state(), QAnimationGroup::Stopped); //it should have stopped
|
||
|
QVERIFY(anim.endValue().isValid());
|
||
|
QCOMPARE(object.property(propertyName), anim.endValue()); //end of the animations
|
||
|
|
||
|
//now we remove the explicit start value and test the implicit one
|
||
|
anim.stop();
|
||
|
object.setProperty(propertyName, initialValue);
|
||
|
|
||
|
//let's reset the start value
|
||
|
values.remove(0);
|
||
|
anim.setStartValue(QVariant());
|
||
|
QCOMPARE(anim.keyValues(), values);
|
||
|
QVERIFY(!anim.startValue().isValid());
|
||
|
|
||
|
anim.start();
|
||
|
QCOMPARE(object.property(propertyName), initialValue);
|
||
|
anim.setCurrentTime(anim.duration()/2);
|
||
|
QCOMPARE(object.property(propertyName).toDouble(), (initialValue.toDouble() + endValue.toDouble())/2 ); //just in the middle of the animation
|
||
|
anim.setCurrentTime(anim.duration()); //we go to the end of the animation
|
||
|
QCOMPARE(anim.state(), QAnimationGroup::Stopped); //it should have stopped
|
||
|
QVERIFY(anim.endValue().isValid());
|
||
|
QCOMPARE(object.property(propertyName), anim.endValue()); //end of the animations
|
||
|
|
||
|
//now we set back the startValue
|
||
|
anim.setStartValue(startValue);
|
||
|
QVERIFY(anim.startValue().isValid());
|
||
|
anim.start();
|
||
|
QCOMPARE(object.property(propertyName), startValue);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::zeroDurationStart()
|
||
|
{
|
||
|
DummyPropertyAnimation anim;
|
||
|
QSignalSpy spy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
anim.setDuration(0);
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
anim.start();
|
||
|
//the animation stops immediately
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(spy.count(), 2);
|
||
|
|
||
|
//let's check the first state change
|
||
|
const QVariantList firstChange = spy.first();
|
||
|
//old state
|
||
|
QCOMPARE(qVariantValue<QAbstractAnimation::State>(firstChange.last()), QAbstractAnimation::Stopped);
|
||
|
//new state
|
||
|
QCOMPARE(qVariantValue<QAbstractAnimation::State>(firstChange.first()), QAbstractAnimation::Running);
|
||
|
|
||
|
//let's check the first state change
|
||
|
const QVariantList secondChange = spy.last();
|
||
|
//old state
|
||
|
QCOMPARE(qVariantValue<QAbstractAnimation::State>(secondChange.last()), QAbstractAnimation::Running);
|
||
|
//new state
|
||
|
QCOMPARE(qVariantValue<QAbstractAnimation::State>(secondChange.first()), QAbstractAnimation::Stopped);
|
||
|
}
|
||
|
|
||
|
#define Pause 1
|
||
|
#define Start 2
|
||
|
#define Resume 3
|
||
|
#define Stop 4
|
||
|
|
||
|
void tst_QPropertyAnimation::operationsInStates_data()
|
||
|
{
|
||
|
QTest::addColumn<QAbstractAnimation::State>("originState");
|
||
|
QTest::addColumn<int>("operation");
|
||
|
QTest::addColumn<QString>("expectedWarning");
|
||
|
QTest::addColumn<QAbstractAnimation::State>("expectedState");
|
||
|
|
||
|
QString pauseWarn(QLatin1String("QAbstractAnimation::pause: Cannot pause a stopped animation"));
|
||
|
QString resumeWarn(QLatin1String("QAbstractAnimation::resume: Cannot resume an animation that is not paused"));
|
||
|
|
||
|
QTest::newRow("S-pause") << QAbstractAnimation::Stopped << Pause << pauseWarn << QAbstractAnimation::Stopped;
|
||
|
QTest::newRow("S-start") << QAbstractAnimation::Stopped << Start << QString() << QAbstractAnimation::Running;
|
||
|
QTest::newRow("S-resume") << QAbstractAnimation::Stopped << Resume << resumeWarn << QAbstractAnimation::Stopped;
|
||
|
QTest::newRow("S-stop") << QAbstractAnimation::Stopped << Stop << QString() << QAbstractAnimation::Stopped;
|
||
|
|
||
|
QTest::newRow("P-pause") << QAbstractAnimation::Paused << Pause << QString() << QAbstractAnimation::Paused;
|
||
|
QTest::newRow("P-start") << QAbstractAnimation::Paused << Start << QString() << QAbstractAnimation::Running;
|
||
|
QTest::newRow("P-resume") << QAbstractAnimation::Paused << Resume << QString() << QAbstractAnimation::Running;
|
||
|
QTest::newRow("P-stop") << QAbstractAnimation::Paused << Stop << QString() << QAbstractAnimation::Stopped;
|
||
|
|
||
|
QTest::newRow("R-pause") << QAbstractAnimation::Running << Pause << QString() << QAbstractAnimation::Paused;
|
||
|
QTest::newRow("R-start") << QAbstractAnimation::Running << Start << QString() << QAbstractAnimation::Running;
|
||
|
QTest::newRow("R-resume") << QAbstractAnimation::Running << Resume << resumeWarn << QAbstractAnimation::Running;
|
||
|
QTest::newRow("R-stop") << QAbstractAnimation::Running << Stop << QString() << QAbstractAnimation::Stopped;
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::operationsInStates()
|
||
|
{
|
||
|
/**
|
||
|
* | pause() |start() |resume() |stop()
|
||
|
* ----------+------------+-----------+-----------+-------------------+
|
||
|
* Stopped | Stopped |Running |Stopped |Stopped |
|
||
|
* _| qWarning |restart |qWarning | |
|
||
|
* Paused | Paused |Running |Running |Stopped |
|
||
|
* _| | | | |
|
||
|
* Running | Paused |Running |Running |Stopped |
|
||
|
* | |restart |qWarning | |
|
||
|
* ----------+------------+-----------+-----------+-------------------+
|
||
|
**/
|
||
|
|
||
|
QFETCH(QAbstractAnimation::State, originState);
|
||
|
QFETCH(int, operation);
|
||
|
QFETCH(QString, expectedWarning);
|
||
|
QFETCH(QAbstractAnimation::State, expectedState);
|
||
|
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 42);
|
||
|
QPropertyAnimation anim(&o, "ole");
|
||
|
anim.setEndValue(100);
|
||
|
QSignalSpy spy(&anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
|
||
|
anim.stop();
|
||
|
switch (originState) {
|
||
|
case QAbstractAnimation::Stopped:
|
||
|
break;
|
||
|
case QAbstractAnimation::Paused:
|
||
|
anim.start();
|
||
|
anim.pause();
|
||
|
break;
|
||
|
case QAbstractAnimation::Running:
|
||
|
anim.start();
|
||
|
break;
|
||
|
}
|
||
|
if (!expectedWarning.isEmpty()) {
|
||
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning));
|
||
|
}
|
||
|
QCOMPARE(anim.state(), originState);
|
||
|
switch (operation) {
|
||
|
case Pause:
|
||
|
anim.pause();
|
||
|
break;
|
||
|
case Start:
|
||
|
anim.start();
|
||
|
break;
|
||
|
case Resume:
|
||
|
anim.resume();
|
||
|
break;
|
||
|
case Stop:
|
||
|
anim.stop();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
QCOMPARE(anim.state(), expectedState);
|
||
|
}
|
||
|
#undef Pause
|
||
|
#undef Start
|
||
|
#undef Resume
|
||
|
#undef Stop
|
||
|
|
||
|
void tst_QPropertyAnimation::oneKeyValue()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 42);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
|
||
|
QPropertyAnimation animation(&o, "ole");
|
||
|
animation.setStartValue(43);
|
||
|
animation.setEndValue(44);
|
||
|
animation.setDuration(100);
|
||
|
|
||
|
animation.setCurrentTime(0);
|
||
|
|
||
|
QVERIFY(animation.currentValue().isValid());
|
||
|
QCOMPARE(animation.currentValue().toInt(), 43);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
|
||
|
// remove the last key value
|
||
|
animation.setKeyValueAt(1.0, QVariant());
|
||
|
|
||
|
// we will neither interpolate, nor update the current value
|
||
|
// since there is only one 1 key value defined
|
||
|
animation.setCurrentTime(100);
|
||
|
|
||
|
// the animation should not have been modified
|
||
|
QVERIFY(animation.currentValue().isValid());
|
||
|
QCOMPARE(animation.currentValue().toInt(), 43);
|
||
|
QCOMPARE(o.property("ole").toInt(), 42);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::updateOnSetKeyValues()
|
||
|
{
|
||
|
QObject o;
|
||
|
o.setProperty("ole", 100);
|
||
|
QCOMPARE(o.property("ole").toInt(), 100);
|
||
|
|
||
|
QPropertyAnimation animation(&o, "ole");
|
||
|
animation.setStartValue(100);
|
||
|
animation.setEndValue(200);
|
||
|
animation.setDuration(100);
|
||
|
|
||
|
animation.setCurrentTime(50);
|
||
|
QCOMPARE(animation.currentValue().toInt(), 150);
|
||
|
animation.setKeyValueAt(0.0, 300);
|
||
|
QCOMPARE(animation.currentValue().toInt(), 250);
|
||
|
|
||
|
o.setProperty("ole", 100);
|
||
|
QPropertyAnimation animation2(&o, "ole");
|
||
|
QVariantAnimation::KeyValues kValues;
|
||
|
kValues << QVariantAnimation::KeyValue(0.0, 100) << QVariantAnimation::KeyValue(1.0, 200);
|
||
|
animation2.setKeyValues(kValues);
|
||
|
animation2.setDuration(100);
|
||
|
animation2.setCurrentTime(50);
|
||
|
QCOMPARE(animation2.currentValue().toInt(), 150);
|
||
|
|
||
|
kValues.clear();
|
||
|
kValues << QVariantAnimation::KeyValue(0.0, 300) << QVariantAnimation::KeyValue(1.0, 200);
|
||
|
animation2.setKeyValues(kValues);
|
||
|
|
||
|
QCOMPARE(animation2.currentValue().toInt(), animation.currentValue().toInt());
|
||
|
}
|
||
|
|
||
|
|
||
|
//this class will 'throw' an error in the test lib
|
||
|
// if the property ole is set to ErrorValue
|
||
|
class MyErrorObject : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
Q_PROPERTY(int ole READ ole WRITE setOle)
|
||
|
public:
|
||
|
|
||
|
static const int ErrorValue = 10000;
|
||
|
|
||
|
MyErrorObject() : m_ole(0) { }
|
||
|
int ole() const { return m_ole; }
|
||
|
void setOle(int o)
|
||
|
{
|
||
|
QVERIFY(o != ErrorValue);
|
||
|
m_ole = o;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
int m_ole;
|
||
|
|
||
|
|
||
|
};
|
||
|
|
||
|
void tst_QPropertyAnimation::restart()
|
||
|
{
|
||
|
//here we check that be restarting an animation
|
||
|
//it doesn't get an bogus intermediate value (end value)
|
||
|
//because the time is not yet reset to 0
|
||
|
MyErrorObject o;
|
||
|
o.setOle(100);
|
||
|
QCOMPARE(o.property("ole").toInt(), 100);
|
||
|
|
||
|
QPropertyAnimation anim(&o, "ole");
|
||
|
anim.setEndValue(200);
|
||
|
anim.start();
|
||
|
anim.setCurrentTime(anim.duration());
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(o.property("ole").toInt(), 200);
|
||
|
|
||
|
//we'll check that the animation never gets a wrong value when starting it
|
||
|
//after having changed the end value
|
||
|
anim.setEndValue(MyErrorObject::ErrorValue);
|
||
|
anim.start();
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::valueChanged()
|
||
|
{
|
||
|
qRegisterMetaType<QVariant>("QVariant");
|
||
|
|
||
|
//we check that we receive the valueChanged signal
|
||
|
MyErrorObject o;
|
||
|
o.setOle(0);
|
||
|
QCOMPARE(o.property("ole").toInt(), 0);
|
||
|
QPropertyAnimation anim(&o, "ole");
|
||
|
anim.setEndValue(5);
|
||
|
anim.setDuration(1000);
|
||
|
QSignalSpy spy(&anim, SIGNAL(valueChanged(QVariant)));
|
||
|
anim.start();
|
||
|
|
||
|
QTest::qWait(anim.duration() + 100);
|
||
|
|
||
|
QTRY_COMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(anim.currentTime(), anim.duration());
|
||
|
|
||
|
//let's check that the values go forward
|
||
|
QCOMPARE(spy.count(), 6); //we should have got everything from 0 to 5
|
||
|
for (int i = 0; i < spy.count(); ++i) {
|
||
|
QCOMPARE(qvariant_cast<QVariant>(spy.at(i).first()).toInt(), i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//this class will help us make sure that 2 animations started
|
||
|
//at the same time also end at the same time
|
||
|
class MySyncObject : public MyErrorObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
MySyncObject() : anim(this, "ole")
|
||
|
{
|
||
|
anim.setEndValue(1000);
|
||
|
}
|
||
|
public slots:
|
||
|
void checkAnimationFinished()
|
||
|
{
|
||
|
QCOMPARE(anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(ole(), 1000);
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
QPropertyAnimation anim;
|
||
|
};
|
||
|
|
||
|
void tst_QPropertyAnimation::twoAnimations()
|
||
|
{
|
||
|
MySyncObject o1, o2;
|
||
|
o1.setOle(0);
|
||
|
o2.setOle(0);
|
||
|
|
||
|
//when the animation in o1 is finished
|
||
|
//the animation in o2 should stop around the same time
|
||
|
//We use a queued connection to check just after the tick from the common timer
|
||
|
//the other way is true too
|
||
|
QObject::connect(&o1.anim, SIGNAL(finished()),
|
||
|
&o2, SLOT(checkAnimationFinished()), Qt::QueuedConnection);
|
||
|
QObject::connect(&o2.anim, SIGNAL(finished()),
|
||
|
&o1, SLOT(checkAnimationFinished()), Qt::QueuedConnection);
|
||
|
|
||
|
o1.anim.start();
|
||
|
o2.anim.start();
|
||
|
|
||
|
QTest::qWait(o1.anim.duration() + 100);
|
||
|
QTRY_COMPARE(o1.anim.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(o2.anim.state(), QAbstractAnimation::Stopped);
|
||
|
|
||
|
QCOMPARE(o1.ole(), 1000);
|
||
|
QCOMPARE(o2.ole(), 1000);
|
||
|
}
|
||
|
|
||
|
class MyComposedAnimation : public QPropertyAnimation
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
MyComposedAnimation(QObject *target, const QByteArray &propertyName, const QByteArray &innerPropertyName)
|
||
|
: QPropertyAnimation(target, propertyName)
|
||
|
{
|
||
|
innerAnim = new QPropertyAnimation(target, innerPropertyName);
|
||
|
this->setEndValue(1000);
|
||
|
innerAnim->setEndValue(1000);
|
||
|
innerAnim->setDuration(duration() + 100);
|
||
|
}
|
||
|
|
||
|
void start()
|
||
|
{
|
||
|
QPropertyAnimation::start();
|
||
|
innerAnim->start();
|
||
|
}
|
||
|
|
||
|
void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
|
||
|
{
|
||
|
QPropertyAnimation::updateState(newState, oldState);
|
||
|
if (newState == QAbstractAnimation::Stopped)
|
||
|
delete innerAnim;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
QPropertyAnimation *innerAnim;
|
||
|
};
|
||
|
|
||
|
void tst_QPropertyAnimation::deletedInUpdateCurrentTime()
|
||
|
{
|
||
|
// this test case reproduces an animation being deleted in the updateCurrentTime of
|
||
|
// another animation(was causing segfault).
|
||
|
// the deleted animation must have been started after the animation that is deleting.
|
||
|
AnimationObject o;
|
||
|
o.setValue(0);
|
||
|
o.setRealValue(0.0);
|
||
|
|
||
|
MyComposedAnimation composedAnimation(&o, "value", "realValue");
|
||
|
composedAnimation.start();
|
||
|
QCOMPARE(composedAnimation.state(), QAbstractAnimation::Running);
|
||
|
QTest::qWait(composedAnimation.duration() + 100);
|
||
|
|
||
|
QTRY_COMPARE(composedAnimation.state(), QAbstractAnimation::Stopped);
|
||
|
QCOMPARE(o.value(), 1000);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::totalDuration()
|
||
|
{
|
||
|
QPropertyAnimation anim;
|
||
|
QCOMPARE(anim.totalDuration(), 250);
|
||
|
anim.setLoopCount(2);
|
||
|
QCOMPARE(anim.totalDuration(), 2*250);
|
||
|
anim.setLoopCount(-1);
|
||
|
QCOMPARE(anim.totalDuration(), -1);
|
||
|
anim.setDuration(0);
|
||
|
QCOMPARE(anim.totalDuration(), 0);
|
||
|
}
|
||
|
|
||
|
void tst_QPropertyAnimation::zeroLoopCount()
|
||
|
{
|
||
|
DummyPropertyAnimation* anim;
|
||
|
anim = new DummyPropertyAnimation;
|
||
|
anim->setStartValue(0);
|
||
|
anim->setDuration(20);
|
||
|
anim->setLoopCount(0);
|
||
|
|
||
|
QSignalSpy runningSpy(anim, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)));
|
||
|
QSignalSpy finishedSpy(anim, SIGNAL(finished()));
|
||
|
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(anim->currentValue().toInt(), 0);
|
||
|
QCOMPARE(runningSpy.count(), 0);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
|
||
|
anim->start();
|
||
|
|
||
|
QCOMPARE(anim->state(), QAnimationGroup::Stopped);
|
||
|
QCOMPARE(anim->currentValue().toInt(), 0);
|
||
|
QCOMPARE(runningSpy.count(), 0);
|
||
|
QCOMPARE(finishedSpy.count(), 0);
|
||
|
}
|
||
|
|
||
|
QTEST_MAIN(tst_QPropertyAnimation)
|
||
|
#include "tst_qpropertyanimation.moc"
|