1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30
31#include <QtCore/qanimationgroup.h>
32#include <QtCore/qsequentialanimationgroup.h>
33#include <QtCore/qparallelanimationgroup.h>
34
35Q_DECLARE_METATYPE(QAbstractAnimation::State)
36
37class tst_QAnimationGroup : public QObject
38{
39 Q_OBJECT
40public Q_SLOTS:
41 void initTestCase();
42
43private slots:
44 void construction();
45 void emptyGroup();
46 void setCurrentTime();
47 void setParentAutoAdd();
48 void beginNestedGroup();
49 void addChildTwice();
50 void loopWithoutStartValue();
51};
52
53void tst_QAnimationGroup::initTestCase()
54{
55 qRegisterMetaType<QAbstractAnimation::State>(typeName: "QAbstractAnimation::State");
56}
57
58void tst_QAnimationGroup::construction()
59{
60 QSequentialAnimationGroup animationgroup;
61}
62
63class AnimationObject : public QObject
64{
65 Q_OBJECT
66 Q_PROPERTY(int value READ value WRITE setValue)
67public:
68 AnimationObject(int startValue = 0)
69 : v(startValue)
70 { }
71
72 int value() const { return v; }
73 void setValue(int value) { v = value; }
74
75 int v;
76};
77
78class TestAnimation : public QVariantAnimation
79{
80 Q_OBJECT
81public:
82 virtual void updateCurrentValue(const QVariant &value) { Q_UNUSED(value)};
83 virtual void updateState(QAbstractAnimation::State oldState,
84 QAbstractAnimation::State newState)
85 {
86 Q_UNUSED(oldState)
87 Q_UNUSED(newState)
88 };
89};
90
91class UncontrolledAnimation : public QPropertyAnimation
92{
93 Q_OBJECT
94public:
95 UncontrolledAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0)
96 : QPropertyAnimation(target, propertyName, parent), id(0)
97 {
98 setDuration(250);
99 }
100
101 int duration() const { return -1; /* not time driven */ }
102
103protected:
104 void timerEvent(QTimerEvent *event)
105 {
106 if (event->timerId() == id)
107 stop();
108 }
109
110 void updateRunning(bool running)
111 {
112 if (running) {
113 id = startTimer(interval: 500);
114 } else {
115 killTimer(id);
116 id = 0;
117 }
118 }
119
120private:
121 int id;
122};
123
124void tst_QAnimationGroup::emptyGroup()
125{
126 QSequentialAnimationGroup group;
127 QSignalSpy groupStateChangedSpy(&group, &QSequentialAnimationGroup::stateChanged);
128 QVERIFY(groupStateChangedSpy.isValid());
129
130 QCOMPARE(group.state(), QAnimationGroup::Stopped);
131 group.start();
132
133 QCOMPARE(groupStateChangedSpy.count(), 2);
134
135 QCOMPARE(qvariant_cast<QAbstractAnimation::State>(groupStateChangedSpy.at(0).first()),
136 QAnimationGroup::Running);
137 QCOMPARE(qvariant_cast<QAbstractAnimation::State>(groupStateChangedSpy.at(1).first()),
138 QAnimationGroup::Stopped);
139
140 QCOMPARE(group.state(), QAnimationGroup::Stopped);
141
142 QTest::ignoreMessage(type: QtWarningMsg, message: "QAbstractAnimation::pause: Cannot pause a stopped animation");
143 group.pause();
144
145 QCOMPARE(groupStateChangedSpy.count(), 2);
146 QCOMPARE(group.state(), QAnimationGroup::Stopped);
147
148 group.start();
149
150 QCOMPARE(qvariant_cast<QAbstractAnimation::State>(groupStateChangedSpy.at(2).first()),
151 QAnimationGroup::Running);
152 QCOMPARE(qvariant_cast<QAbstractAnimation::State>(groupStateChangedSpy.at(3).first()),
153 QAnimationGroup::Stopped);
154
155 QCOMPARE(group.state(), QAnimationGroup::Stopped);
156
157 group.stop();
158
159 QCOMPARE(groupStateChangedSpy.count(), 4);
160 QCOMPARE(group.state(), QAnimationGroup::Stopped);
161}
162
163void tst_QAnimationGroup::setCurrentTime()
164{
165 AnimationObject s_o1;
166 AnimationObject s_o2;
167 AnimationObject s_o3;
168 AnimationObject p_o1;
169 AnimationObject p_o2;
170 AnimationObject p_o3;
171 AnimationObject t_o1;
172 AnimationObject t_o2;
173
174 // sequence operating on same object/property
175 QSequentialAnimationGroup *sequence = new QSequentialAnimationGroup();
176 QAbstractAnimation *a1_s_o1 = new QPropertyAnimation(&s_o1, "value");
177 QAbstractAnimation *a2_s_o1 = new QPropertyAnimation(&s_o1, "value");
178 QAbstractAnimation *a3_s_o1 = new QPropertyAnimation(&s_o1, "value");
179 a2_s_o1->setLoopCount(3);
180 sequence->addAnimation(animation: a1_s_o1);
181 sequence->addAnimation(animation: a2_s_o1);
182 sequence->addAnimation(animation: a3_s_o1);
183
184 // sequence operating on different object/properties
185 QAnimationGroup *sequence2 = new QSequentialAnimationGroup();
186 QAbstractAnimation *a1_s_o2 = new QPropertyAnimation(&s_o2, "value");
187 QAbstractAnimation *a1_s_o3 = new QPropertyAnimation(&s_o3, "value");
188 sequence2->addAnimation(animation: a1_s_o2);
189 sequence2->addAnimation(animation: a1_s_o3);
190
191 // parallel operating on different object/properties
192 QAnimationGroup *parallel = new QParallelAnimationGroup();
193 QAbstractAnimation *a1_p_o1 = new QPropertyAnimation(&p_o1, "value");
194 QAbstractAnimation *a1_p_o2 = new QPropertyAnimation(&p_o2, "value");
195 QAbstractAnimation *a1_p_o3 = new QPropertyAnimation(&p_o3, "value");
196 a1_p_o2->setLoopCount(3);
197 parallel->addAnimation(animation: a1_p_o1);
198 parallel->addAnimation(animation: a1_p_o2);
199 parallel->addAnimation(animation: a1_p_o3);
200
201 QAbstractAnimation *notTimeDriven = new UncontrolledAnimation(&t_o1, "value");
202 QCOMPARE(notTimeDriven->totalDuration(), -1);
203
204 QAbstractAnimation *loopsForever = new QPropertyAnimation(&t_o2, "value");
205 loopsForever->setLoopCount(-1);
206 QCOMPARE(loopsForever->totalDuration(), -1);
207
208 QParallelAnimationGroup group;
209 group.addAnimation(animation: sequence);
210 group.addAnimation(animation: sequence2);
211 group.addAnimation(animation: parallel);
212 group.addAnimation(animation: notTimeDriven);
213 group.addAnimation(animation: loopsForever);
214
215 // Current time = 1
216 group.setCurrentTime(1);
217 QCOMPARE(group.state(), QAnimationGroup::Stopped);
218 QCOMPARE(sequence->state(), QAnimationGroup::Stopped);
219 QCOMPARE(a1_s_o1->state(), QAnimationGroup::Stopped);
220 QCOMPARE(sequence2->state(), QAnimationGroup::Stopped);
221 QCOMPARE(a1_s_o2->state(), QAnimationGroup::Stopped);
222 QCOMPARE(parallel->state(), QAnimationGroup::Stopped);
223 QCOMPARE(a1_p_o1->state(), QAnimationGroup::Stopped);
224 QCOMPARE(a1_p_o2->state(), QAnimationGroup::Stopped);
225 QCOMPARE(a1_p_o3->state(), QAnimationGroup::Stopped);
226 QCOMPARE(notTimeDriven->state(), QAnimationGroup::Stopped);
227 QCOMPARE(loopsForever->state(), QAnimationGroup::Stopped);
228
229 QCOMPARE(group.currentLoopTime(), 1);
230 QCOMPARE(sequence->currentLoopTime(), 1);
231 QCOMPARE(a1_s_o1->currentLoopTime(), 1);
232 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
233 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
234 QCOMPARE(a1_s_o2->currentLoopTime(), 1);
235 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
236 QCOMPARE(a1_p_o1->currentLoopTime(), 1);
237 QCOMPARE(a1_p_o2->currentLoopTime(), 1);
238 QCOMPARE(a1_p_o3->currentLoopTime(), 1);
239 QCOMPARE(notTimeDriven->currentLoopTime(), 1);
240 QCOMPARE(loopsForever->currentLoopTime(), 1);
241
242 // Current time = 250
243 group.setCurrentTime(250);
244 QCOMPARE(group.currentLoopTime(), 250);
245 QCOMPARE(sequence->currentLoopTime(), 250);
246 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
247 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
248 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
249 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
250 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
251 QCOMPARE(a1_p_o1->currentLoopTime(), 250);
252 QCOMPARE(a1_p_o2->currentLoopTime(), 0);
253 QCOMPARE(a1_p_o2->currentLoop(), 1);
254 QCOMPARE(a1_p_o3->currentLoopTime(), 250);
255 QCOMPARE(notTimeDriven->currentLoopTime(), 250);
256 QCOMPARE(loopsForever->currentLoopTime(), 0);
257 QCOMPARE(loopsForever->currentLoop(), 1);
258 QCOMPARE(sequence->currentAnimation(), a2_s_o1);
259
260 // Current time = 251
261 group.setCurrentTime(251);
262 QCOMPARE(group.currentLoopTime(), 251);
263 QCOMPARE(sequence->currentLoopTime(), 251);
264 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
265 QCOMPARE(a2_s_o1->currentLoopTime(), 1);
266 QCOMPARE(a2_s_o1->currentLoop(), 0);
267 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
268 QCOMPARE(sequence2->currentLoopTime(), 251);
269 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
270 QCOMPARE(a1_s_o3->currentLoopTime(), 1);
271 QCOMPARE(a1_p_o1->currentLoopTime(), 250);
272 QCOMPARE(a1_p_o2->currentLoopTime(), 1);
273 QCOMPARE(a1_p_o2->currentLoop(), 1);
274 QCOMPARE(a1_p_o3->currentLoopTime(), 250);
275 QCOMPARE(notTimeDriven->currentLoopTime(), 251);
276 QCOMPARE(loopsForever->currentLoopTime(), 1);
277 QCOMPARE(sequence->currentAnimation(), a2_s_o1);
278}
279
280void tst_QAnimationGroup::setParentAutoAdd()
281{
282 QParallelAnimationGroup group;
283 QVariantAnimation *animation = new QPropertyAnimation(&group);
284 QCOMPARE(animation->group(), static_cast<QAnimationGroup*>(&group));
285}
286
287void tst_QAnimationGroup::beginNestedGroup()
288{
289 QParallelAnimationGroup group;
290 QAnimationGroup *parent = &group;
291
292 for (int i = 0; i < 10; ++i) {
293 if (i & 1) {
294 new QParallelAnimationGroup(parent);
295 } else {
296 new QSequentialAnimationGroup(parent);
297 }
298
299 QCOMPARE(parent->animationCount(), 1);
300 QAnimationGroup *child = static_cast<QAnimationGroup *>(parent->animationAt(index: 0));
301
302 QCOMPARE(child->parent(), static_cast<QObject *>(parent));
303 if (i & 1)
304 QVERIFY(qobject_cast<QParallelAnimationGroup *> (child));
305 else
306 QVERIFY(qobject_cast<QSequentialAnimationGroup *> (child));
307
308 parent = child;
309 }
310}
311
312void tst_QAnimationGroup::addChildTwice()
313{
314 QAbstractAnimation *subGroup;
315 QAbstractAnimation *subGroup2;
316 QAnimationGroup *parent = new QSequentialAnimationGroup();
317
318 subGroup = new QPropertyAnimation();
319 subGroup->setParent(parent);
320 parent->addAnimation(animation: subGroup);
321 QCOMPARE(parent->animationCount(), 1);
322
323 parent->clear();
324
325 QCOMPARE(parent->animationCount(), 0);
326
327 // adding the same item twice to a group will remove the item from its current position
328 // and append it to the end
329 subGroup = new QPropertyAnimation(parent);
330 subGroup2 = new QPropertyAnimation(parent);
331
332 QCOMPARE(parent->animationCount(), 2);
333 QCOMPARE(parent->animationAt(0), subGroup);
334 QCOMPARE(parent->animationAt(1), subGroup2);
335
336 parent->addAnimation(animation: subGroup);
337
338 QCOMPARE(parent->animationCount(), 2);
339 QCOMPARE(parent->animationAt(0), subGroup2);
340 QCOMPARE(parent->animationAt(1), subGroup);
341
342 delete parent;
343}
344
345void tst_QAnimationGroup::loopWithoutStartValue()
346{
347 QSequentialAnimationGroup group;
348 QAnimationGroup *parent = &group;
349 QObject o;
350 o.setProperty(name: "ole", value: 0);
351 QCOMPARE(o.property("ole").toInt(), 0);
352
353 QPropertyAnimation anim1(&o, "ole");
354 anim1.setEndValue(-50);
355 anim1.setDuration(100);
356
357 QPropertyAnimation anim2(&o, "ole");
358 anim2.setEndValue(50);
359 anim2.setDuration(100);
360
361 parent->addAnimation(animation: &anim1);
362 parent->addAnimation(animation: &anim2);
363
364 parent->setLoopCount(-1);
365 parent->start();
366
367 QVERIFY(anim1.startValue().isNull());
368 QCOMPARE(anim1.currentValue().toInt(), 0);
369 QCOMPARE(parent->currentLoop(), 0);
370
371 parent->setCurrentTime(200);
372 QCOMPARE(parent->currentLoop(), 1);
373 QCOMPARE(anim1.currentValue().toInt(), 50);
374 parent->stop();
375}
376
377QTEST_MAIN(tst_QAnimationGroup)
378#include "tst_qanimationgroup.moc"
379

source code of qtbase/tests/auto/corelib/animation/qanimationgroup/tst_qanimationgroup.cpp