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#include <QtQml/private/qsequentialanimationgroupjob_p.h>
31#include <QtQml/private/qparallelanimationgroupjob_p.h>
32#include <QtQml/private/qpauseanimationjob_p.h>
33
34Q_DECLARE_METATYPE(QAbstractAnimationJob::State)
35Q_DECLARE_METATYPE(QAbstractAnimationJob*)
36
37class tst_QSequentialAnimationGroupJob : public QObject
38{
39 Q_OBJECT
40public Q_SLOTS:
41 void initTestCase();
42
43private slots:
44 void construction();
45 void setCurrentTime();
46 void setCurrentTimeWithUncontrolledAnimation();
47 void seekingForwards();
48 void seekingBackwards();
49 void pauseAndResume();
50 void restart();
51 void looping();
52 void startDelay();
53 void clearGroup();
54 void groupWithZeroDurationAnimations();
55 void propagateGroupUpdateToChildren();
56 void updateChildrenWithRunningGroup();
57 void deleteChildrenWithRunningGroup();
58 void startChildrenWithStoppedGroup();
59 void stopGroupWithRunningChild();
60 void startGroupWithRunningChild();
61 void zeroDurationAnimation();
62 void stopUncontrolledAnimations();
63 void uncontrolledWithLoops();
64 void finishWithUncontrolledAnimation();
65 void addRemoveAnimation();
66 void currentAnimation();
67 void currentAnimationWithZeroDuration();
68 void insertAnimation();
69 void clear();
70 void pauseResume();
71 void deleteFromListener();
72};
73
74void tst_QSequentialAnimationGroupJob::initTestCase()
75{
76 qRegisterMetaType<QAbstractAnimationJob::State>(typeName: "QAbstractAnimationJob::State");
77 qRegisterMetaType<QAbstractAnimationJob*>(typeName: "QAbstractAnimationJob*");
78}
79
80void tst_QSequentialAnimationGroupJob::construction()
81{
82 QSequentialAnimationGroupJob animationgroup;
83}
84
85class TestAnimation : public QAbstractAnimationJob
86{
87public:
88 TestAnimation(int duration = 250) : m_duration(duration) {}
89 int duration() const { return m_duration; }
90
91private:
92 int m_duration;
93};
94
95class TestValueAnimation : public TestAnimation
96{
97public:
98 TestValueAnimation(int duration = 250)
99 : TestAnimation(duration) {}
100
101 void updateCurrentTime(int msecs)
102 {
103 if (msecs >= duration())
104 value = end;
105 else
106 value = start + (end - start) * (qreal(msecs) / duration());
107 }
108
109 qreal start = 0, end = 0;
110 qreal value = 0;
111};
112
113class UncontrolledAnimation : public QObject, public QAbstractAnimationJob
114{
115 Q_OBJECT
116public:
117 int duration() const { return -1; /* not time driven */ }
118
119protected:
120 void updateCurrentTime(int currentTime)
121 {
122 if (currentTime >= 250)
123 stop();
124 }
125};
126
127class StateChangeListener: public QAnimationJobChangeListener
128{
129public:
130 virtual void animationStateChanged(
131 QAbstractAnimationJob *job, QAbstractAnimationJob::State newState,
132 QAbstractAnimationJob::State)
133 {
134 states << newState;
135 if (beEvil) {
136 delete job->group();
137 groupDeleted = true;
138 }
139 }
140
141 void clear() { states.clear(); }
142 int count() const { return states.count(); }
143
144 QList<QAbstractAnimationJob::State> states;
145 bool beEvil = false;
146 bool groupDeleted = false;
147};
148
149class FinishedListener: public QAnimationJobChangeListener
150{
151public:
152 FinishedListener() {}
153
154 virtual void animationFinished(QAbstractAnimationJob *) { ++m_count; }
155 void clear() { m_count = 0; }
156 int count() { return m_count; }
157
158private:
159 int m_count = 0;
160};
161
162void tst_QSequentialAnimationGroupJob::setCurrentTime()
163{
164 // sequence operating on same object/property
165 QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
166 TestAnimation *a1_s_o1 = new TestAnimation;
167 TestAnimation *a2_s_o1 = new TestAnimation;
168 TestAnimation *a3_s_o1 = new TestAnimation;
169 a2_s_o1->setLoopCount(3);
170 sequence->appendAnimation(animation: a1_s_o1);
171 sequence->appendAnimation(animation: a2_s_o1);
172 sequence->appendAnimation(animation: a3_s_o1);
173
174 // sequence operating on different object/properties
175 QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob();
176 TestAnimation *a1_s_o2 = new TestAnimation;
177 TestAnimation *a1_s_o3 = new TestAnimation;
178 sequence2->appendAnimation(animation: a1_s_o2);
179 sequence2->appendAnimation(animation: a1_s_o3);
180
181 QSequentialAnimationGroupJob group;
182 group.appendAnimation(animation: sequence);
183 group.appendAnimation(animation: sequence2);
184
185 // Current time = 1
186 group.setCurrentTime(1);
187 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
188 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
189 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
190 QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
191 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
192
193 QCOMPARE(group.currentLoopTime(), 1);
194 QCOMPARE(sequence->currentLoopTime(), 1);
195 QCOMPARE(a1_s_o1->currentLoopTime(), 1);
196 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
197 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
198 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
199 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
200
201 // Current time = 250
202 group.setCurrentTime(250);
203 QCOMPARE(group.currentLoopTime(), 250);
204 QCOMPARE(sequence->currentLoopTime(), 250);
205 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
206 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
207 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
208 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
209 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
210
211 // Current time = 251
212 group.setCurrentTime(251);
213 QCOMPARE(group.currentLoopTime(), 251);
214 QCOMPARE(sequence->currentLoopTime(), 251);
215 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
216 QCOMPARE(a2_s_o1->currentLoopTime(), 1);
217 QCOMPARE(a2_s_o1->currentLoop(), 0);
218 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
219 QCOMPARE(sequence2->currentLoopTime(), 0);
220 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
221 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
222
223 // Current time = 750
224 group.setCurrentTime(750);
225 QCOMPARE(group.currentLoopTime(), 750);
226 QCOMPARE(sequence->currentLoopTime(), 750);
227 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
228 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
229 QCOMPARE(a2_s_o1->currentLoop(), 2);
230 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
231 QCOMPARE(sequence2->currentLoopTime(), 0);
232 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
233 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
234
235 // Current time = 1000
236 group.setCurrentTime(1000);
237 QCOMPARE(group.currentLoopTime(), 1000);
238 QCOMPARE(sequence->currentLoopTime(), 1000);
239 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
240 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
241 QCOMPARE(a2_s_o1->currentLoop(), 2);
242 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
243 QCOMPARE(sequence2->currentLoopTime(), 0);
244 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
245 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
246
247 // Current time = 1010
248 group.setCurrentTime(1010);
249 QCOMPARE(group.currentLoopTime(), 1010);
250 QCOMPARE(sequence->currentLoopTime(), 1010);
251 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
252 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
253 QCOMPARE(a2_s_o1->currentLoop(), 2);
254 QCOMPARE(a3_s_o1->currentLoopTime(), 10);
255 QCOMPARE(sequence2->currentLoopTime(), 0);
256 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
257 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
258
259 // Current time = 1250
260 group.setCurrentTime(1250);
261 QCOMPARE(group.currentLoopTime(), 1250);
262 QCOMPARE(sequence->currentLoopTime(), 1250);
263 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
264 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
265 QCOMPARE(a2_s_o1->currentLoop(), 2);
266 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
267 QCOMPARE(sequence2->currentLoopTime(), 0);
268 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
269 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
270
271 // Current time = 1500
272 group.setCurrentTime(1500);
273 QCOMPARE(group.currentLoopTime(), 1500);
274 QCOMPARE(sequence->currentLoopTime(), 1250);
275 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
276 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
277 QCOMPARE(a2_s_o1->currentLoop(), 2);
278 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
279 QCOMPARE(sequence2->currentLoopTime(), 250);
280 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
281 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
282
283 // Current time = 1750
284 group.setCurrentTime(1750);
285 QCOMPARE(group.currentLoopTime(), 1750);
286 QCOMPARE(sequence->currentLoopTime(), 1250);
287 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
288 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
289 QCOMPARE(a2_s_o1->currentLoop(), 2);
290 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
291 QCOMPARE(sequence2->currentLoopTime(), 500);
292 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
293 QCOMPARE(a1_s_o3->currentLoopTime(), 250);
294
295 // Current time = 2000
296 group.setCurrentTime(2000);
297 QCOMPARE(group.currentLoopTime(), 1750);
298 QCOMPARE(sequence->currentLoopTime(), 1250);
299 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
300 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
301 QCOMPARE(a2_s_o1->currentLoop(), 2);
302 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
303 QCOMPARE(sequence2->currentLoopTime(), 500);
304 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
305 QCOMPARE(a1_s_o3->currentLoopTime(), 250);
306}
307
308void tst_QSequentialAnimationGroupJob::setCurrentTimeWithUncontrolledAnimation()
309{
310 // sequence operating on different object/properties
311 QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
312 TestAnimation *a1_s_o1 = new TestAnimation;
313 TestAnimation *a1_s_o2 = new TestAnimation;
314 sequence->appendAnimation(animation: a1_s_o1);
315 sequence->appendAnimation(animation: a1_s_o2);
316
317 UncontrolledAnimation *notTimeDriven = new UncontrolledAnimation;
318 QCOMPARE(notTimeDriven->totalDuration(), -1);
319
320 TestAnimation *loopsForever = new TestAnimation;
321 loopsForever->setLoopCount(-1);
322 QCOMPARE(loopsForever->totalDuration(), -1);
323
324 QSequentialAnimationGroupJob group;
325 group.appendAnimation(animation: sequence);
326 group.appendAnimation(animation: notTimeDriven);
327 group.appendAnimation(animation: loopsForever);
328 group.start();
329 group.pause(); // this allows the group to listen for the finish signal of its children
330
331 // Current time = 1
332 group.setCurrentTime(1);
333 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
334 QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
335 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused);
336 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
337 QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
338 QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
339
340 QCOMPARE(group.currentLoopTime(), 1);
341 QCOMPARE(sequence->currentLoopTime(), 1);
342 QCOMPARE(a1_s_o1->currentLoopTime(), 1);
343 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
344 QCOMPARE(notTimeDriven->currentLoopTime(), 0);
345 QCOMPARE(loopsForever->currentLoopTime(), 0);
346
347 // Current time = 250
348 group.setCurrentTime(250);
349 QCOMPARE(group.currentLoopTime(), 250);
350 QCOMPARE(sequence->currentLoopTime(), 250);
351 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
352 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
353 QCOMPARE(notTimeDriven->currentLoopTime(), 0);
354 QCOMPARE(loopsForever->currentLoopTime(), 0);
355
356 // Current time = 500
357 group.setCurrentTime(500);
358 QCOMPARE(group.currentLoopTime(), 500);
359 QCOMPARE(sequence->currentLoopTime(), 500);
360 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
361 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
362 QCOMPARE(notTimeDriven->currentLoopTime(), 0);
363 QCOMPARE(loopsForever->currentLoopTime(), 0);
364 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob *>(notTimeDriven));
365
366 // Current time = 505
367 group.setCurrentTime(505);
368 QCOMPARE(group.currentLoopTime(), 505);
369 QCOMPARE(sequence->currentLoopTime(), 500);
370 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
371 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
372 QCOMPARE(notTimeDriven->currentLoopTime(), 5);
373 QCOMPARE(loopsForever->currentLoopTime(), 0);
374 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob *>(notTimeDriven));
375 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
376 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
377 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
378 QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Paused);
379 QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
380
381 // Current time = 750 (end of notTimeDriven animation)
382 group.setCurrentTime(750);
383 QCOMPARE(group.currentLoopTime(), 750);
384 QCOMPARE(sequence->currentLoopTime(), 500);
385 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
386 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
387 QCOMPARE(notTimeDriven->currentLoopTime(), 250);
388 QCOMPARE(loopsForever->currentLoopTime(), 0);
389 QCOMPARE(group.currentAnimation(), loopsForever);
390 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
391 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
392 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
393 QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
394 QCOMPARE(loopsForever->state(), QAnimationGroupJob::Paused);
395
396 // Current time = 800 (as notTimeDriven was finished at 750, loopsforever should still run)
397 group.setCurrentTime(800);
398 QCOMPARE(group.currentLoopTime(), 800);
399 QCOMPARE(group.currentAnimation(), loopsForever);
400 QCOMPARE(sequence->currentLoopTime(), 500);
401 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
402 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
403 QCOMPARE(notTimeDriven->currentLoopTime(), 250);
404 QCOMPARE(loopsForever->currentLoopTime(), 50);
405
406 loopsForever->stop(); // this should stop the group
407
408 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
409 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
410 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
411 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
412 QCOMPARE(notTimeDriven->state(), QAnimationGroupJob::Stopped);
413 QCOMPARE(loopsForever->state(), QAnimationGroupJob::Stopped);
414}
415
416void tst_QSequentialAnimationGroupJob::seekingForwards()
417{
418
419 // sequence operating on same object/property
420 QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob;
421 TestAnimation *a1_s_o1 = new TestAnimation;
422 TestAnimation *a2_s_o1 = new TestAnimation;
423 TestAnimation *a3_s_o1 = new TestAnimation;
424 a2_s_o1->setLoopCount(3);
425 sequence->appendAnimation(animation: a1_s_o1);
426 sequence->appendAnimation(animation: a2_s_o1);
427 sequence->appendAnimation(animation: a3_s_o1);
428
429 // sequence operating on different object/properties
430 QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob;
431 TestAnimation *a1_s_o2 = new TestAnimation;
432 TestAnimation *a1_s_o3 = new TestAnimation;
433 sequence2->appendAnimation(animation: a1_s_o2);
434 sequence2->appendAnimation(animation: a1_s_o3);
435
436 QSequentialAnimationGroupJob group;
437 group.appendAnimation(animation: sequence);
438 group.appendAnimation(animation: sequence2);
439
440 // Current time = 1
441 group.setCurrentTime(1);
442 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
443 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
444 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
445 QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
446 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
447 QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
448
449 QCOMPARE(group.currentLoopTime(), 1);
450 QCOMPARE(sequence->currentLoopTime(), 1);
451 QCOMPARE(a1_s_o1->currentLoopTime(), 1);
452 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
453 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
454 QCOMPARE(sequence2->currentLoopTime(), 0);
455 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
456 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
457
458 // Current time = 1500
459 group.setCurrentTime(1500);
460 QCOMPARE(group.currentLoopTime(), 1500);
461 QCOMPARE(sequence->currentLoopTime(), 1250);
462 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
463 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
464 QCOMPARE(a2_s_o1->currentLoop(), 2);
465 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
466 QCOMPARE(sequence2->currentLoopTime(), 250);
467 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
468 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
469
470 // this will restart the group
471 group.start();
472 group.pause();
473 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
474 QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
475 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused);
476 QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
477 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
478 QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
479
480 // Current time = 1750
481 group.setCurrentTime(1750);
482 QCOMPARE(group.currentLoopTime(), 1750);
483 QCOMPARE(sequence->currentLoopTime(), 1250);
484 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
485 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
486 QCOMPARE(a2_s_o1->currentLoop(), 2);
487 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
488 QCOMPARE(sequence2->currentLoopTime(), 500);
489 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
490 QCOMPARE(a1_s_o3->currentLoopTime(), 250);
491}
492
493void tst_QSequentialAnimationGroupJob::seekingBackwards()
494{
495 // sequence operating on same object/property
496 QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
497 TestAnimation *a1_s_o1 = new TestAnimation;
498 TestAnimation *a2_s_o1 = new TestAnimation;
499 TestAnimation *a3_s_o1 = new TestAnimation;
500 a2_s_o1->setLoopCount(3);
501 sequence->appendAnimation(animation: a1_s_o1);
502 sequence->appendAnimation(animation: a2_s_o1);
503 sequence->appendAnimation(animation: a3_s_o1);
504
505 // sequence operating on different object/properties
506 QAnimationGroupJob *sequence2 = new QSequentialAnimationGroupJob();
507 TestAnimation *a1_s_o2 = new TestAnimation;
508 TestAnimation *a1_s_o3 = new TestAnimation;
509 sequence2->appendAnimation(animation: a1_s_o2);
510 sequence2->appendAnimation(animation: a1_s_o3);
511
512 QSequentialAnimationGroupJob group;
513 group.appendAnimation(animation: sequence);
514 group.appendAnimation(animation: sequence2);
515
516 group.start();
517
518 // Current time = 1600
519 group.setCurrentTime(1600);
520 QCOMPARE(group.currentLoopTime(), 1600);
521 QCOMPARE(sequence->currentLoopTime(), 1250);
522 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
523 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
524 QCOMPARE(a2_s_o1->currentLoop(), 2);
525 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
526 QCOMPARE(sequence2->currentLoopTime(), 350);
527 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
528 QCOMPARE(a1_s_o3->currentLoopTime(), 100);
529
530 QCOMPARE(group.state(), QAnimationGroupJob::Running);
531 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
532 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
533 QCOMPARE(sequence2->state(), QAnimationGroupJob::Running);
534 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
535 QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Running);
536
537 // Seeking backwards, current time = 1
538 group.setCurrentTime(1);
539 QCOMPARE(group.currentLoopTime(), 1);
540 QCOMPARE(sequence->currentLoopTime(), 1);
541 QCOMPARE(a1_s_o1->currentLoopTime(), 1);
542
543 QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children,"
544 "hence they don't reset from their current animation", Continue);
545 QCOMPARE(a2_s_o1->currentLoopTime(), 0);
546 QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children,"
547 "hence they don't reset from their current animation", Continue);
548 QCOMPARE(a2_s_o1->currentLoop(), 0);
549 QEXPECT_FAIL("", "rewinding in nested groups is considered as a restart from the children,"
550 "hence they don't reset from their current animation", Continue);
551 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
552 QCOMPARE(sequence2->currentLoopTime(), 0);
553 QCOMPARE(a1_s_o2->currentLoopTime(), 0);
554 QCOMPARE(a1_s_o3->currentLoopTime(), 0);
555
556 QCOMPARE(group.state(), QAnimationGroupJob::Running);
557 QCOMPARE(sequence->state(), QAnimationGroupJob::Running);
558 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Running);
559 QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
560 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
561 QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
562
563 // Current time = 2000
564 group.setCurrentTime(2000);
565 QCOMPARE(group.currentLoopTime(), 1750);
566 QCOMPARE(sequence->currentLoopTime(), 1250);
567 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
568 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
569 QCOMPARE(a2_s_o1->currentLoop(), 2);
570 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
571 QCOMPARE(sequence2->currentLoopTime(), 500);
572 QCOMPARE(a1_s_o2->currentLoopTime(), 250);
573 QCOMPARE(a1_s_o3->currentLoopTime(), 250);
574
575 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
576 QCOMPARE(sequence->state(), QAnimationGroupJob::Stopped);
577 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
578 QCOMPARE(sequence2->state(), QAnimationGroupJob::Stopped);
579 QCOMPARE(a1_s_o2->state(), QAnimationGroupJob::Stopped);
580 QCOMPARE(a1_s_o3->state(), QAnimationGroupJob::Stopped);
581}
582
583typedef QList<QAbstractAnimationJob::State> StateList;
584
585static bool compareStates(const StateChangeListener& spy, const StateList &expectedStates)
586{
587 bool equals = true;
588 for (int i = 0; i < qMax(a: expectedStates.count(), b: spy.count()); ++i) {
589 if (i >= spy.count() || i >= expectedStates.count()) {
590 equals = false;
591 break;
592 }
593 QAbstractAnimationJob::State st = expectedStates.at(i);
594 QAbstractAnimationJob::State actual = spy.states.at(i);
595 if (equals && actual != st) {
596 equals = false;
597 break;
598 }
599 }
600 if (!equals) {
601 const char *stateStrings[] = {"Stopped", "Paused", "Running"};
602 QString e,a;
603 for (int i = 0; i < qMax(a: expectedStates.count(), b: spy.count()); ++i) {
604 if (i < expectedStates.count()) {
605 int exp = int(expectedStates.at(i));
606 if (!e.isEmpty())
607 e += QLatin1String(", ");
608 e += QLatin1String(stateStrings[exp]);
609 }
610 if (i < spy.count()) {
611 QAbstractAnimationJob::State actual = spy.states.at(i);
612 if (!a.isEmpty())
613 a += QLatin1String(", ");
614 if (int(actual) >= 0 && int(actual) <= 2) {
615 a += QLatin1String(stateStrings[int(actual)]);
616 } else {
617 a += QLatin1String("NaN");
618 }
619 }
620
621 }
622 qDebug(msg: "\n"
623 "expected (count == %d): %s\n"
624 "actual (count == %d): %s\n", expectedStates.count(), qPrintable(e), spy.count(), qPrintable(a));
625 }
626 return equals;
627}
628
629void tst_QSequentialAnimationGroupJob::pauseAndResume()
630{
631 // sequence operating on same object/property
632 QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
633 TestAnimation *a1_s_o1 = new TestAnimation;
634 TestAnimation *a2_s_o1 = new TestAnimation;
635 TestAnimation *a3_s_o1 = new TestAnimation;
636 a2_s_o1->setLoopCount(2);
637 sequence->appendAnimation(animation: a1_s_o1);
638 sequence->appendAnimation(animation: a2_s_o1);
639 sequence->appendAnimation(animation: a3_s_o1);
640 sequence->setLoopCount(2);
641
642 StateChangeListener a1StateChangedSpy;
643 a1_s_o1->addAnimationChangeListener(listener: &a1StateChangedSpy, QAbstractAnimationJob::StateChange);
644 StateChangeListener seqStateChangedSpy;
645 sequence->addAnimationChangeListener(listener: &seqStateChangedSpy, QAbstractAnimationJob::StateChange);
646
647 QSequentialAnimationGroupJob group;
648 group.appendAnimation(animation: sequence);
649
650 group.start();
651 group.pause();
652
653 // Current time = 1751
654 group.setCurrentTime(1751);
655 QCOMPARE(group.currentLoopTime(), 1751);
656 QCOMPARE(sequence->currentLoopTime(), 751);
657 QCOMPARE(sequence->currentLoop(), 1);
658 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
659 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
660 QCOMPARE(a2_s_o1->currentLoop(), 1);
661 QCOMPARE(a3_s_o1->currentLoop(), 0);
662 QCOMPARE(a3_s_o1->currentLoopTime(), 1);
663
664 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
665 QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
666 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
667 QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
668 QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused);
669
670 QCOMPARE(a1StateChangedSpy.count(), 5); // Running,Paused,Stopped,Running,Stopped
671 QCOMPARE(seqStateChangedSpy.count(), 2); // Running,Paused
672
673 QVERIFY(compareStates(a1StateChangedSpy, (StateList() << QAbstractAnimationJob::Running
674 << QAbstractAnimationJob::Paused
675 << QAbstractAnimationJob::Stopped
676 << QAbstractAnimationJob::Running
677 << QAbstractAnimationJob::Stopped)));
678
679 //### is this the same test as compareStates test above?
680 QCOMPARE(a1StateChangedSpy.states.at(0), QAnimationGroupJob::Running);
681 QCOMPARE(a1StateChangedSpy.states.at(1), QAnimationGroupJob::Paused);
682 QCOMPARE(a1StateChangedSpy.states.at(2), QAnimationGroupJob::Stopped);
683 QCOMPARE(a1StateChangedSpy.states.at(3), QAnimationGroupJob::Running);
684 QCOMPARE(a1StateChangedSpy.states.at(4), QAnimationGroupJob::Stopped);
685
686 QCOMPARE(seqStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
687 QCOMPARE(seqStateChangedSpy.states.at(1), QAnimationGroupJob::Paused);
688
689 group.resume();
690
691 QCOMPARE(group.state(), QAnimationGroupJob::Running);
692 QCOMPARE(sequence->state(), QAnimationGroupJob::Running);
693 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
694 QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
695 QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Running);
696
697 QVERIFY(group.currentLoopTime() >= 1751);
698 QVERIFY(sequence->currentLoopTime() >= 751);
699 QCOMPARE(sequence->currentLoop(), 1);
700 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
701 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
702 QCOMPARE(a2_s_o1->currentLoop(), 1);
703 QCOMPARE(a3_s_o1->currentLoop(), 0);
704 QVERIFY(a3_s_o1->currentLoopTime() >= 1);
705
706 QCOMPARE(seqStateChangedSpy.count(), 3); // Running,Paused,Running
707 QCOMPARE(seqStateChangedSpy.states.at(2), QAnimationGroupJob::Running);
708
709 group.pause();
710
711 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
712 QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
713 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
714 QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
715 QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused);
716
717 QVERIFY(group.currentLoopTime() >= 1751);
718 QVERIFY(sequence->currentLoopTime() >= 751);
719 QCOMPARE(sequence->currentLoop(), 1);
720 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
721 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
722 QCOMPARE(a2_s_o1->currentLoop(), 1);
723 QCOMPARE(a3_s_o1->currentLoop(), 0);
724 QVERIFY(a3_s_o1->currentLoopTime() >= 1);
725
726 QCOMPARE(seqStateChangedSpy.count(), 4); // Running,Paused,Running,Paused
727 QCOMPARE(seqStateChangedSpy.states.at(3), QAnimationGroupJob::Paused);
728
729 group.stop();
730
731 QCOMPARE(seqStateChangedSpy.count(), 5); // Running,Paused,Running,Paused,Stopped
732 QCOMPARE(seqStateChangedSpy.states.at(4), QAnimationGroupJob::Stopped);
733}
734
735void tst_QSequentialAnimationGroupJob::restart()
736{
737 // originally was sequence operating on same object/property
738 QAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
739 //### no equivilant signal
740 //QSignalSpy seqCurrentAnimChangedSpy(sequence, SIGNAL(currentAnimationChanged(QAbstractAnimationJob*)));
741
742 StateChangeListener seqStateChangedSpy;
743 sequence->addAnimationChangeListener(listener: &seqStateChangedSpy, QAbstractAnimationJob::StateChange);
744
745 TestAnimation *anims[3];
746 StateChangeListener *animsStateChanged[3];
747
748 for (int i = 0; i < 3; i++) {
749 anims[i] = new TestAnimation(100);
750 animsStateChanged[i] = new StateChangeListener;
751 anims[i]->addAnimationChangeListener(listener: animsStateChanged[i], QAbstractAnimationJob::StateChange);
752 }
753
754 anims[1]->setLoopCount(2);
755 sequence->appendAnimation(animation: anims[0]);
756 sequence->appendAnimation(animation: anims[1]);
757 sequence->appendAnimation(animation: anims[2]);
758 sequence->setLoopCount(2);
759
760 QSequentialAnimationGroupJob group;
761 group.appendAnimation(animation: sequence);
762
763 group.start();
764
765 QTest::qWait(ms: 500);
766
767 QCOMPARE(group.state(), QAnimationGroupJob::Running);
768
769 QTest::qWait(ms: 300);
770 QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped);
771
772 for (int i = 0; i < 3; i++) {
773 QCOMPARE(animsStateChanged[i]->count(), 4);
774 QCOMPARE(animsStateChanged[i]->states.at(0), QAnimationGroupJob::Running);
775 QCOMPARE(animsStateChanged[i]->states.at(1), QAnimationGroupJob::Stopped);
776 QCOMPARE(animsStateChanged[i]->states.at(2), QAnimationGroupJob::Running);
777 QCOMPARE(animsStateChanged[i]->states.at(3), QAnimationGroupJob::Stopped);
778 }
779
780 QCOMPARE(seqStateChangedSpy.count(), 2);
781 QCOMPARE(seqStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
782 QCOMPARE(seqStateChangedSpy.states.at(1), QAnimationGroupJob::Stopped);
783
784 //QCOMPARE(seqCurrentAnimChangedSpy.count(), 6);
785 //for(int i=0; i<seqCurrentAnimChangedSpy.count(); i++)
786 // QCOMPARE(static_cast<QAbstractAnimationJob*>(anims[i%3]), qVariantValue<QAbstractAnimationJob*>(seqCurrentAnimChangedSpy.at(i).at(0)));
787
788 group.start();
789
790 QCOMPARE(animsStateChanged[0]->count(), 5);
791 QCOMPARE(animsStateChanged[1]->count(), 4);
792 QCOMPARE(animsStateChanged[2]->count(), 4);
793 QCOMPARE(seqStateChangedSpy.count(), 3);
794}
795
796void tst_QSequentialAnimationGroupJob::looping()
797{
798 // originally was sequence operating on same object/property
799 QSequentialAnimationGroupJob *sequence = new QSequentialAnimationGroupJob();
800 QAbstractAnimationJob *a1_s_o1 = new TestAnimation;
801 QAbstractAnimationJob *a2_s_o1 = new TestAnimation;
802 QAbstractAnimationJob *a3_s_o1 = new TestAnimation;
803
804 StateChangeListener a1Spy;
805 a1_s_o1->addAnimationChangeListener(listener: &a1Spy, QAbstractAnimationJob::StateChange);
806 StateChangeListener a2Spy;
807 a2_s_o1->addAnimationChangeListener(listener: &a2Spy, QAbstractAnimationJob::StateChange);
808 StateChangeListener a3Spy;
809 a3_s_o1->addAnimationChangeListener(listener: &a3Spy, QAbstractAnimationJob::StateChange);
810 StateChangeListener seqSpy;
811 sequence->addAnimationChangeListener(listener: &seqSpy, QAbstractAnimationJob::StateChange);
812
813 a2_s_o1->setLoopCount(2);
814 sequence->appendAnimation(animation: a1_s_o1);
815 sequence->appendAnimation(animation: a2_s_o1);
816 sequence->appendAnimation(animation: a3_s_o1);
817 sequence->setLoopCount(2);
818
819 QSequentialAnimationGroupJob group;
820 StateChangeListener groupSpy;
821 group.addAnimationChangeListener(listener: &groupSpy, QAbstractAnimationJob::StateChange);
822
823 group.appendAnimation(animation: sequence);
824 group.setLoopCount(2);
825
826 group.start();
827 group.pause();
828
829 // Current time = 1750
830 group.setCurrentTime(1750);
831 QCOMPARE(group.currentLoopTime(), 1750);
832 QCOMPARE(sequence->currentLoopTime(), 750);
833 QCOMPARE(sequence->currentLoop(), 1);
834 QCOMPARE(a1_s_o1->currentLoopTime(), 250);
835 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
836 QCOMPARE(a2_s_o1->currentLoop(), 1);
837 // this animation is at the beginning because it is the current one inside sequence
838 QCOMPARE(a3_s_o1->currentLoop(), 0);
839 QCOMPARE(a3_s_o1->currentLoopTime(), 0);
840 QCOMPARE(sequence->currentAnimation(), a3_s_o1);
841
842 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
843 QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
844 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Stopped);
845 QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
846 QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Paused);
847
848 QCOMPARE(a1Spy.count(), 5); // Running,Paused,Stopped,Running,Stopped
849 QVERIFY(compareStates(a1Spy, (StateList() << QAbstractAnimationJob::Running
850 << QAbstractAnimationJob::Paused
851 << QAbstractAnimationJob::Stopped
852 << QAbstractAnimationJob::Running
853 << QAbstractAnimationJob::Stopped)));
854
855 QCOMPARE(a2Spy.count(), 4); // Running,Stopped,Running,Stopped
856 QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimationJob::Running
857 << QAbstractAnimationJob::Stopped
858 << QAbstractAnimationJob::Running
859 << QAbstractAnimationJob::Paused)));
860
861 QCOMPARE(seqSpy.count(), 2); // Running,Paused
862 QCOMPARE(groupSpy.count(), 2); // Running,Paused
863
864 // Looping, current time = duration + 1
865 group.setCurrentTime(group.duration() + 1);
866 QCOMPARE(group.currentLoopTime(), 1);
867 QCOMPARE(group.currentLoop(), 1);
868 QCOMPARE(sequence->currentLoopTime(), 1);
869 QCOMPARE(sequence->currentLoop(), 0);
870 QCOMPARE(a1_s_o1->currentLoopTime(), 1);
871 QCOMPARE(a2_s_o1->currentLoopTime(), 250);
872 QCOMPARE(a2_s_o1->currentLoop(), 1);
873 // this animation is at the end because it was run on the previous loop
874 QCOMPARE(a3_s_o1->currentLoop(), 0);
875 QCOMPARE(a3_s_o1->currentLoopTime(), 250);
876
877 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
878 QCOMPARE(sequence->state(), QAnimationGroupJob::Paused);
879 QCOMPARE(a1_s_o1->state(), QAnimationGroupJob::Paused);
880 QCOMPARE(a2_s_o1->state(), QAnimationGroupJob::Stopped);
881 QCOMPARE(a3_s_o1->state(), QAnimationGroupJob::Stopped);
882
883 QCOMPARE(a1Spy.count(), 7); // Running,Paused,Stopped,Running,Stopped,Running,Stopped
884 QCOMPARE(a2Spy.count(), 4); // Running, Stopped, Running, Stopped
885 QVERIFY(compareStates(a3Spy, (StateList() << QAbstractAnimationJob::Running
886 << QAbstractAnimationJob::Stopped
887 << QAbstractAnimationJob::Running
888 << QAbstractAnimationJob::Paused
889 << QAbstractAnimationJob::Stopped)));
890 QVERIFY(compareStates(seqSpy, (StateList() << QAbstractAnimationJob::Running
891 << QAbstractAnimationJob::Paused
892 << QAbstractAnimationJob::Stopped
893 << QAbstractAnimationJob::Running
894 << QAbstractAnimationJob::Paused)));
895 QCOMPARE(groupSpy.count(), 2);
896
897 //cleanup
898 a1_s_o1->removeAnimationChangeListener(listener: &a1Spy, QAbstractAnimationJob::StateChange);
899 a2_s_o1->removeAnimationChangeListener(listener: &a2Spy, QAbstractAnimationJob::StateChange);
900 a3_s_o1->removeAnimationChangeListener(listener: &a3Spy, QAbstractAnimationJob::StateChange);
901 sequence->removeAnimationChangeListener(listener: &seqSpy, QAbstractAnimationJob::StateChange);
902 group.removeAnimationChangeListener(listener: &groupSpy, QAbstractAnimationJob::StateChange);
903}
904
905void tst_QSequentialAnimationGroupJob::startDelay()
906{
907 QSequentialAnimationGroupJob group;
908 group.appendAnimation(animation: new QPauseAnimationJob(250));
909 group.appendAnimation(animation: new QPauseAnimationJob(125));
910 QCOMPARE(group.totalDuration(), 375);
911
912 group.start();
913 QCOMPARE(group.state(), QAnimationGroupJob::Running);
914
915 QTest::qWait(ms: 500);
916
917 QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped);
918 QCOMPARE(group.currentLoopTime(), 375);
919}
920
921void tst_QSequentialAnimationGroupJob::clearGroup()
922{
923 QSequentialAnimationGroupJob group;
924
925 static const int animationCount = 20;
926
927 for (int i = 0; i < animationCount/2; ++i) {
928 QSequentialAnimationGroupJob *subGroup = new QSequentialAnimationGroupJob;
929 group.appendAnimation(animation: subGroup);
930 group.appendAnimation(animation: new QPauseAnimationJob(100));
931 subGroup->appendAnimation(animation: new QPauseAnimationJob(10));
932 }
933
934 int count = 0;
935 for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling())
936 ++count;
937 QCOMPARE(count, animationCount);
938
939 group.clear();
940
941 QVERIFY(!group.firstChild() && !group.lastChild());
942 QCOMPARE(group.currentLoopTime(), 0);
943}
944
945void tst_QSequentialAnimationGroupJob::groupWithZeroDurationAnimations()
946{
947 QSequentialAnimationGroupJob group;
948
949 TestValueAnimation *a1 = new TestValueAnimation(0);
950 a1->start = 42;
951 a1->end = 43;
952 group.appendAnimation(animation: a1);
953
954 //this should just run fine and change nothing
955 group.setCurrentTime(0);
956 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(a1));
957
958 TestValueAnimation *a2 = new TestValueAnimation(500);
959 a2->start = 13;
960 a2->end = 31;
961 group.appendAnimation(animation: a2);
962
963 TestValueAnimation *a3 = new TestValueAnimation(0);
964 a3->start = 43;
965 a3->end = 44;
966 group.appendAnimation(animation: a3);
967
968 TestValueAnimation *a4 = new TestValueAnimation(250);
969 a4->start = 13;
970 a4->end = 75;
971 group.appendAnimation(animation: a4);
972
973 TestValueAnimation *a5 = new TestValueAnimation(0);
974 a5->start = 42;
975 a5->end = 12;
976 group.appendAnimation(animation: a5);
977
978 QCOMPARE((int)a1->value, 43); //### is this actually the behavior we want?
979 QCOMPARE((int)a2->value, 0);
980 QCOMPARE((int)a3->value, 0);
981 QCOMPARE((int)a4->value, 0);
982 QCOMPARE((int)a5->value, 0);
983
984 group.start();
985
986 QCOMPARE((int)a1->value, 43); //### is this actually the behavior we want?
987 QCOMPARE((int)a2->value, 13);
988 QCOMPARE((int)a3->value, 0);
989 QCOMPARE((int)a4->value, 0);
990 QCOMPARE((int)a5->value, 0);
991
992 QTest::qWait(ms: 100);
993
994 QCOMPARE((int)a1->value, 43);
995 QVERIFY(a2->value > 13 && a2->value < 31);
996 QCOMPARE((int)a3->value, 0);
997 QCOMPARE((int)a4->value, 0);
998 QCOMPARE((int)a5->value, 0);
999
1000 QTest::qWait(ms: 500);
1001
1002 QTRY_COMPARE((int)a3->value, 44);
1003 QCOMPARE((int)a1->value, 43);
1004 QCOMPARE((int)a2->value, 31);
1005 //QCOMPARE((int)a4->value, 36);
1006 QCOMPARE((int)a5->value, 0);
1007 QCOMPARE(a1->state(), QAnimationGroupJob::Stopped);
1008 QCOMPARE(a2->state(), QAnimationGroupJob::Stopped);
1009 QCOMPARE(a3->state(), QAnimationGroupJob::Stopped);
1010 QCOMPARE(a4->state(), QAnimationGroupJob::Running);
1011 QCOMPARE(a5->state(), QAnimationGroupJob::Stopped);
1012 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1013 QTest::qWait(ms: 500);
1014
1015 QTRY_COMPARE(group.state(), QAnimationGroupJob::Stopped);
1016 QCOMPARE((int)a1->value, 43);
1017 QCOMPARE((int)a2->value, 31);
1018 QCOMPARE((int)a3->value, 44);
1019 QCOMPARE((int)a4->value, 75);
1020 QCOMPARE((int)a5->value, 12);
1021 QCOMPARE(a1->state(), QAnimationGroupJob::Stopped);
1022 QCOMPARE(a2->state(), QAnimationGroupJob::Stopped);
1023 QCOMPARE(a3->state(), QAnimationGroupJob::Stopped);
1024 QCOMPARE(a4->state(), QAnimationGroupJob::Stopped);
1025 QCOMPARE(a5->state(), QAnimationGroupJob::Stopped);
1026}
1027
1028void tst_QSequentialAnimationGroupJob::propagateGroupUpdateToChildren()
1029{
1030 // this test verifies if group state changes are updating its children correctly
1031 QSequentialAnimationGroupJob group;
1032
1033 TestAnimation anim1(100);
1034 TestAnimation anim2(200);
1035
1036 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1037 QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
1038 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1039
1040 group.appendAnimation(animation: &anim1);
1041 group.appendAnimation(animation: &anim2);
1042
1043 group.start();
1044
1045 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1046 QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
1047 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1048
1049 group.pause();
1050
1051 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
1052 QCOMPARE(anim1.state(), QAnimationGroupJob::Paused);
1053 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1054
1055 group.stop();
1056
1057 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1058 QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
1059 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1060}
1061
1062void tst_QSequentialAnimationGroupJob::updateChildrenWithRunningGroup()
1063{
1064 // assert that its possible to modify a child's state directly while their group is running
1065 QSequentialAnimationGroupJob group;
1066
1067 TestAnimation anim(200);
1068
1069 StateChangeListener groupStateChangedSpy;
1070 group.addAnimationChangeListener(listener: &groupStateChangedSpy, QAbstractAnimationJob::StateChange);
1071 StateChangeListener childStateChangedSpy;
1072 anim.addAnimationChangeListener(listener: &childStateChangedSpy, QAbstractAnimationJob::StateChange);
1073
1074 QCOMPARE(groupStateChangedSpy.count(), 0);
1075 QCOMPARE(childStateChangedSpy.count(), 0);
1076 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1077 QCOMPARE(anim.state(), QAnimationGroupJob::Stopped);
1078
1079 group.appendAnimation(animation: &anim);
1080
1081 group.start();
1082
1083 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1084 QCOMPARE(anim.state(), QAnimationGroupJob::Running);
1085
1086 QCOMPARE(groupStateChangedSpy.count(), 1);
1087 QCOMPARE(childStateChangedSpy.count(), 1);
1088
1089 QCOMPARE(groupStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
1090 QCOMPARE(childStateChangedSpy.states.at(0), QAnimationGroupJob::Running);
1091
1092 // starting directly a running child will not have any effect
1093 anim.start();
1094
1095 QCOMPARE(groupStateChangedSpy.count(), 1);
1096 QCOMPARE(childStateChangedSpy.count(), 1);
1097
1098 anim.pause();
1099
1100 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1101 QCOMPARE(anim.state(), QAnimationGroupJob::Paused);
1102
1103 // in the animation stops directly, the group will still be running
1104 anim.stop();
1105
1106 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1107 QCOMPARE(anim.state(), QAnimationGroupJob::Stopped);
1108
1109 //cleanup
1110 group.removeAnimationChangeListener(listener: &groupStateChangedSpy, QAbstractAnimationJob::StateChange);
1111 anim.removeAnimationChangeListener(listener: &childStateChangedSpy, QAbstractAnimationJob::StateChange);
1112}
1113
1114void tst_QSequentialAnimationGroupJob::deleteChildrenWithRunningGroup()
1115{
1116 // test if children can be activated when their group is stopped
1117 QSequentialAnimationGroupJob group;
1118
1119 TestAnimation *anim1 = new TestAnimation(200);
1120 group.appendAnimation(animation: anim1);
1121
1122 QCOMPARE(group.duration(), anim1->duration());
1123
1124 group.start();
1125 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1126 QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
1127
1128 QTest::qWait(ms: 100);
1129 QTRY_VERIFY(group.currentLoopTime() > 0);
1130
1131 delete anim1;
1132 QVERIFY(!group.firstChild());
1133 QCOMPARE(group.duration(), 0);
1134 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1135 QCOMPARE(group.currentLoopTime(), 0); //that's the invariant
1136}
1137
1138void tst_QSequentialAnimationGroupJob::startChildrenWithStoppedGroup()
1139{
1140 // test if children can be activated when their group is stopped
1141 QSequentialAnimationGroupJob group;
1142
1143 TestAnimation anim1(200);
1144 TestAnimation anim2(200);
1145
1146 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1147 QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
1148 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1149
1150 group.appendAnimation(animation: &anim1);
1151 group.appendAnimation(animation: &anim2);
1152
1153 group.stop();
1154
1155 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1156 QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
1157 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1158
1159 anim1.start();
1160 anim2.start();
1161 anim2.pause();
1162
1163 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1164 QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
1165 QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
1166}
1167
1168void tst_QSequentialAnimationGroupJob::stopGroupWithRunningChild()
1169{
1170 // children that started independently will not be affected by a group stop
1171 QSequentialAnimationGroupJob group;
1172
1173 TestAnimation anim1(200);
1174 TestAnimation anim2(200);
1175
1176 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1177 QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
1178 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1179
1180 group.appendAnimation(animation: &anim1);
1181 group.appendAnimation(animation: &anim2);
1182
1183 anim1.start();
1184 anim2.start();
1185 anim2.pause();
1186
1187 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1188 QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
1189 QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
1190
1191 group.stop();
1192
1193 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1194 QCOMPARE(anim1.state(), QAnimationGroupJob::Running);
1195 QCOMPARE(anim2.state(), QAnimationGroupJob::Paused);
1196
1197 anim1.stop();
1198 anim2.stop();
1199
1200 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1201 QCOMPARE(anim1.state(), QAnimationGroupJob::Stopped);
1202 QCOMPARE(anim2.state(), QAnimationGroupJob::Stopped);
1203}
1204
1205void tst_QSequentialAnimationGroupJob::startGroupWithRunningChild()
1206{
1207 // as the group has precedence over its children, starting a group will restart all the children
1208 QSequentialAnimationGroupJob group;
1209
1210 TestAnimation *anim1 = new TestAnimation(200);
1211 TestAnimation *anim2 = new TestAnimation(200);
1212
1213 StateChangeListener stateChangedSpy1;
1214 anim1->addAnimationChangeListener(listener: &stateChangedSpy1, QAbstractAnimationJob::StateChange);
1215 StateChangeListener stateChangedSpy2;
1216 anim2->addAnimationChangeListener(listener: &stateChangedSpy2, QAbstractAnimationJob::StateChange);
1217
1218 QCOMPARE(stateChangedSpy1.count(), 0);
1219 QCOMPARE(stateChangedSpy2.count(), 0);
1220 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1221 QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
1222 QCOMPARE(anim2->state(), QAnimationGroupJob::Stopped);
1223
1224 group.appendAnimation(animation: anim1);
1225 group.appendAnimation(animation: anim2);
1226
1227 anim1->start();
1228 anim2->start();
1229 anim2->pause();
1230
1231 QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimationJob::Running)));
1232
1233 QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimationJob::Running
1234 << QAbstractAnimationJob::Paused)));
1235
1236 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1237 QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
1238 QCOMPARE(anim2->state(), QAnimationGroupJob::Paused);
1239
1240 group.start();
1241
1242 QVERIFY(compareStates(stateChangedSpy1, (StateList() << QAbstractAnimationJob::Running
1243 << QAbstractAnimationJob::Stopped
1244 << QAbstractAnimationJob::Running)));
1245 QVERIFY(compareStates(stateChangedSpy2, (StateList() << QAbstractAnimationJob::Running
1246 << QAbstractAnimationJob::Paused)));
1247
1248 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1249 QCOMPARE(anim1->state(), QAnimationGroupJob::Running);
1250 QCOMPARE(anim2->state(), QAnimationGroupJob::Paused);
1251
1252 QTest::qWait(ms: 300);
1253
1254 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1255 QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
1256 QCOMPARE(anim2->state(), QAnimationGroupJob::Running);
1257
1258 QCOMPARE(stateChangedSpy2.count(), 4);
1259 QCOMPARE(stateChangedSpy2.states.at(2), QAnimationGroupJob::Stopped);
1260 QCOMPARE(stateChangedSpy2.states.at(3), QAnimationGroupJob::Running);
1261
1262 group.stop();
1263
1264 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1265 QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
1266 QCOMPARE(anim2->state(), QAnimationGroupJob::Stopped);
1267
1268 anim1->removeAnimationChangeListener(listener: &stateChangedSpy1, QAbstractAnimationJob::StateChange);
1269 anim2->removeAnimationChangeListener(listener: &stateChangedSpy2, QAbstractAnimationJob::StateChange);
1270}
1271
1272void tst_QSequentialAnimationGroupJob::zeroDurationAnimation()
1273{
1274 QSequentialAnimationGroupJob group;
1275
1276 TestAnimation *anim1 = new TestAnimation(0);
1277 TestAnimation *anim2 = new TestAnimation(100);
1278 TestValueAnimation *anim3 = new TestValueAnimation(0);
1279 anim3->end = 100;
1280
1281 StateChangeListener stateChangedSpy;
1282 anim1->addAnimationChangeListener(listener: &stateChangedSpy, QAbstractAnimationJob::StateChange);
1283
1284 group.appendAnimation(animation: anim1);
1285 group.appendAnimation(animation: anim2);
1286 group.appendAnimation(animation: anim3);
1287 group.setLoopCount(2);
1288 group.start();
1289
1290 QCOMPARE(stateChangedSpy.count(), 2);
1291 QCOMPARE(stateChangedSpy.states.at(0), QAnimationGroupJob::Running);
1292 QCOMPARE(stateChangedSpy.states.at(1), QAnimationGroupJob::Stopped);
1293
1294 QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
1295 QCOMPARE(anim2->state(), QAnimationGroupJob::Running);
1296 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1297
1298 //now let's try to seek to the next loop
1299 group.setCurrentTime(group.duration() + 1);
1300 QCOMPARE(anim1->state(), QAnimationGroupJob::Stopped);
1301 QCOMPARE(anim2->state(), QAnimationGroupJob::Running);
1302 QCOMPARE(anim3->state(), QAnimationGroupJob::Stopped);
1303 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1304 //TODO: test that anim3 was run
1305 QCOMPARE(anim3->value, qreal(100)); //anim3 should have been run
1306
1307 anim1->removeAnimationChangeListener(listener: &stateChangedSpy, QAbstractAnimationJob::StateChange);
1308}
1309
1310void tst_QSequentialAnimationGroupJob::stopUncontrolledAnimations()
1311{
1312 QSequentialAnimationGroupJob group;
1313
1314 UncontrolledAnimation notTimeDriven;
1315 QCOMPARE(notTimeDriven.totalDuration(), -1);
1316
1317 TestAnimation loopsForever(100);
1318 loopsForever.setLoopCount(-1);
1319
1320 group.appendAnimation(animation: &notTimeDriven);
1321 group.appendAnimation(animation: &loopsForever);
1322
1323 group.start();
1324
1325 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1326 QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
1327 QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped);
1328
1329 notTimeDriven.stop();
1330
1331 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1332 QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
1333 QCOMPARE(loopsForever.state(), QAnimationGroupJob::Running);
1334
1335 loopsForever.stop();
1336
1337 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1338 QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
1339 QCOMPARE(loopsForever.state(), QAnimationGroupJob::Stopped);
1340}
1341
1342void tst_QSequentialAnimationGroupJob::finishWithUncontrolledAnimation()
1343{
1344 //1st case:
1345 //first we test a group with one uncontrolled animation
1346 QSequentialAnimationGroupJob group;
1347 UncontrolledAnimation notTimeDriven;
1348 group.appendAnimation(animation: &notTimeDriven);
1349 FinishedListener spy;
1350 group.addAnimationChangeListener(listener: &spy, QAbstractAnimationJob::Completion);
1351
1352 group.start();
1353 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1354 QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
1355 QCOMPARE(group.currentLoopTime(), 0);
1356 QCOMPARE(notTimeDriven.currentLoopTime(), 0);
1357
1358 QTest::qWait(ms: 300); //wait for the end of notTimeDriven
1359 QTRY_COMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
1360 const int actualDuration = notTimeDriven.currentLoopTime();
1361 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1362 QCOMPARE(group.currentLoopTime(), actualDuration);
1363 QCOMPARE(spy.count(), 1);
1364
1365 //2nd case:
1366 // lets make sure the seeking will work again
1367 spy.clear();
1368 TestAnimation anim;
1369 group.appendAnimation(animation: &anim);
1370 StateChangeListener animStateChangedSpy;
1371 anim.addAnimationChangeListener(listener: &animStateChangedSpy, QAbstractAnimationJob::StateChange);
1372
1373 group.setCurrentTime(300);
1374 QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
1375 QCOMPARE(notTimeDriven.currentLoopTime(), actualDuration);
1376 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
1377
1378 //3rd case:
1379 //now let's add a perfectly defined animation at the end
1380 QCOMPARE(animStateChangedSpy.count(), 0);
1381 group.start();
1382 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1383 QCOMPARE(notTimeDriven.state(), QAnimationGroupJob::Running);
1384 QCOMPARE(group.currentLoopTime(), 0);
1385 QCOMPARE(notTimeDriven.currentLoopTime(), 0);
1386
1387 QCOMPARE(animStateChangedSpy.count(), 0);
1388
1389 QTest::qWait(ms: 300); //wait for the end of notTimeDriven
1390 QTRY_COMPARE(notTimeDriven.state(), QAnimationGroupJob::Stopped);
1391 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1392 QCOMPARE(anim.state(), QAnimationGroupJob::Running);
1393 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
1394 QCOMPARE(animStateChangedSpy.count(), 1);
1395 QTest::qWait(ms: 300); //wait for the end of anim
1396
1397 QTRY_COMPARE(anim.state(), QAnimationGroupJob::Stopped);
1398 QCOMPARE(anim.currentLoopTime(), anim.duration());
1399
1400 //we should simply be at the end
1401 QCOMPARE(spy.count(), 1);
1402 QCOMPARE(animStateChangedSpy.count(), 2);
1403 QCOMPARE(group.currentLoopTime(), notTimeDriven.currentLoopTime() + anim.currentLoopTime());
1404
1405 //cleanup
1406 group.removeAnimationChangeListener(listener: &spy, QAbstractAnimationJob::Completion);
1407 anim.removeAnimationChangeListener(listener: &animStateChangedSpy, QAbstractAnimationJob::StateChange);
1408}
1409
1410void tst_QSequentialAnimationGroupJob::addRemoveAnimation()
1411{
1412 //this test is specific to the sequential animation group
1413 QSequentialAnimationGroupJob group;
1414
1415 QCOMPARE(group.duration(), 0);
1416 QCOMPARE(group.currentLoopTime(), 0);
1417 QAbstractAnimationJob *anim1 = new TestAnimation;
1418 group.appendAnimation(animation: anim1);
1419 QCOMPARE(group.duration(), 250);
1420 QCOMPARE(group.currentLoopTime(), 0);
1421 QCOMPARE(group.currentAnimation(), anim1);
1422
1423 //let's append an animation
1424 QAbstractAnimationJob *anim2 = new TestAnimation;
1425 group.appendAnimation(animation: anim2);
1426 QCOMPARE(group.duration(), 500);
1427 QCOMPARE(group.currentLoopTime(), 0);
1428 QCOMPARE(group.currentAnimation(), anim1);
1429
1430 //let's prepend an animation
1431 QAbstractAnimationJob *anim0 = new TestAnimation;
1432 group.prependAnimation(animation: anim0);
1433 QCOMPARE(group.duration(), 750);
1434 QCOMPARE(group.currentLoopTime(), 0);
1435 QCOMPARE(group.currentAnimation(), anim0); //anim0 has become the new currentAnimation
1436
1437 group.setCurrentTime(300); //anim0 | anim1 | anim2
1438 QCOMPARE(group.currentLoopTime(), 300);
1439 QCOMPARE(group.currentAnimation(), anim1);
1440 QCOMPARE(anim1->currentLoopTime(), 50);
1441
1442 group.removeAnimation(animation: anim0); //anim1 | anim2
1443 QCOMPARE(group.currentLoopTime(), 50);
1444 QCOMPARE(group.currentAnimation(), anim1);
1445 QCOMPARE(anim1->currentLoopTime(), 50);
1446
1447 group.setCurrentTime(0);
1448 group.prependAnimation(animation: anim0); //anim0 | anim1 | anim2
1449 group.setCurrentTime(300);
1450 QCOMPARE(group.currentLoopTime(), 300);
1451 QCOMPARE(group.currentAnimation(), anim1);
1452 QCOMPARE(anim1->currentLoopTime(), 50);
1453
1454 group.removeAnimation(animation: anim1); //anim0 | anim2
1455 QCOMPARE(group.currentLoopTime(), 250);
1456 QCOMPARE(group.currentAnimation(), anim2);
1457 QCOMPARE(anim0->currentLoopTime(), 250);
1458}
1459
1460void tst_QSequentialAnimationGroupJob::currentAnimation()
1461{
1462 QSequentialAnimationGroupJob group;
1463 QVERIFY(!group.currentAnimation());
1464
1465 TestAnimation anim(0);
1466 group.appendAnimation(animation: &anim);
1467 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
1468}
1469
1470void tst_QSequentialAnimationGroupJob::currentAnimationWithZeroDuration()
1471{
1472 QSequentialAnimationGroupJob group;
1473 QVERIFY(!group.currentAnimation());
1474
1475 TestAnimation zero1(0);
1476 TestAnimation zero2(0);
1477
1478 TestAnimation anim;
1479
1480 TestAnimation zero3(0);
1481 TestAnimation zero4(0);
1482
1483 group.appendAnimation(animation: &zero1);
1484 group.appendAnimation(animation: &zero2);
1485 group.appendAnimation(animation: &anim);
1486 group.appendAnimation(animation: &zero3);
1487 group.appendAnimation(animation: &zero4);
1488
1489 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero1));
1490
1491 group.setCurrentTime(0);
1492 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
1493
1494 group.setCurrentTime(group.duration());
1495 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero4));
1496
1497 group.setDirection(QAbstractAnimationJob::Backward);
1498
1499 group.setCurrentTime(0);
1500 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&zero1));
1501
1502 group.setCurrentTime(group.duration());
1503 QCOMPARE(group.currentAnimation(), static_cast<QAbstractAnimationJob*>(&anim));
1504}
1505
1506void tst_QSequentialAnimationGroupJob::insertAnimation()
1507{
1508 QSequentialAnimationGroupJob group;
1509 group.setLoopCount(2);
1510 TestAnimation *anim = new TestAnimation;
1511 group.appendAnimation(animation: anim);
1512 QCOMPARE(group.duration(), anim->duration());
1513 group.setCurrentTime(300);
1514 QCOMPARE(group.currentLoop(), 1);
1515
1516 //this will crash if the sequential group calls duration on the created animation
1517 group.appendAnimation(animation: new TestAnimation);
1518}
1519
1520class ClearFinishedListener: public QAnimationJobChangeListener
1521{
1522public:
1523 ClearFinishedListener(QSequentialAnimationGroupJob *g) : group(g) {}
1524
1525 virtual void animationFinished(QAbstractAnimationJob *)
1526 {
1527 group->clear();
1528 }
1529
1530 QSequentialAnimationGroupJob *group;
1531};
1532
1533class RefillFinishedListener: public QAnimationJobChangeListener
1534{
1535public:
1536 RefillFinishedListener(QSequentialAnimationGroupJob *g) : group(g) {}
1537
1538 virtual void animationFinished(QAbstractAnimationJob *)
1539 {
1540 group->stop();
1541 group->clear();
1542 group->appendAnimation(animation: new TestAnimation);
1543 group->start();
1544 }
1545
1546 QSequentialAnimationGroupJob *group;
1547};
1548
1549void tst_QSequentialAnimationGroupJob::clear()
1550{
1551 QSKIP("deleting an animation when finished is not currently supported");
1552 QSequentialAnimationGroupJob group;
1553 TestAnimation *anim1 = new TestAnimation;
1554 group.appendAnimation(animation: anim1);
1555 ClearFinishedListener clearListener(&group);
1556 anim1->addAnimationChangeListener(listener: &clearListener, QAbstractAnimationJob::Completion);
1557
1558 TestAnimation *anim2 = new TestAnimation;
1559 group.appendAnimation(animation: anim2);
1560 QCOMPARE(group.firstChild(), anim1);
1561 QCOMPARE(group.lastChild(), anim2);
1562
1563 group.start();
1564 QTest::qWait(ms: anim1->duration() + 100);
1565 QTRY_VERIFY(!group.firstChild());
1566 QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
1567 QCOMPARE(group.currentLoopTime(), 0);
1568
1569 anim1 = new TestAnimation;
1570 group.appendAnimation(animation: anim1);
1571 RefillFinishedListener refillListener(&group);
1572 anim1->addAnimationChangeListener(listener: &refillListener, QAbstractAnimationJob::Completion);
1573 group.start();
1574 QTest::qWait(ms: anim1->duration() + 100);
1575 QTRY_COMPARE(group.state(), QAbstractAnimationJob::Running);
1576}
1577
1578void tst_QSequentialAnimationGroupJob::pauseResume()
1579{
1580 QParallelAnimationGroupJob group;
1581 TestAnimation *anim = new TestAnimation;
1582 group.appendAnimation(animation: anim);
1583 StateChangeListener spy;
1584 anim->addAnimationChangeListener(listener: &spy, QAbstractAnimationJob::StateChange);
1585 QCOMPARE(group.duration(), 250);
1586 group.start();
1587 QTest::qWait(ms: 100);
1588 QTRY_COMPARE(group.state(), QAnimationGroupJob::Running);
1589 QCOMPARE(anim->state(), QAnimationGroupJob::Running);
1590 QCOMPARE(spy.count(), 1);
1591 spy.clear();
1592 const int currentTime = group.currentLoopTime();
1593 QCOMPARE(anim->currentLoopTime(), currentTime);
1594
1595 group.pause();
1596 QCOMPARE(group.state(), QAnimationGroupJob::Paused);
1597 QCOMPARE(group.currentLoopTime(), currentTime);
1598 QCOMPARE(anim->state(), QAnimationGroupJob::Paused);
1599 QCOMPARE(anim->currentLoopTime(), currentTime);
1600 QCOMPARE(spy.count(), 1);
1601 spy.clear();
1602
1603 group.resume();
1604 QCOMPARE(group.state(), QAnimationGroupJob::Running);
1605 QCOMPARE(group.currentLoopTime(), currentTime);
1606 QCOMPARE(anim->state(), QAnimationGroupJob::Running);
1607 QCOMPARE(anim->currentLoopTime(), currentTime);
1608 QCOMPARE(spy.count(), 1);
1609
1610 anim->removeAnimationChangeListener(listener: &spy, QAbstractAnimationJob::StateChange);
1611}
1612
1613
1614void tst_QSequentialAnimationGroupJob::uncontrolledWithLoops()
1615{
1616 QSequentialAnimationGroupJob group;
1617
1618 TestAnimation *plain = new TestAnimation(100);
1619 TestAnimation *loopsForever = new TestAnimation();
1620 UncontrolledAnimation *notTimeBased = new UncontrolledAnimation();
1621
1622 loopsForever->setLoopCount(-1);
1623
1624 group.appendAnimation(animation: plain);
1625 group.appendAnimation(animation: loopsForever);
1626 group.appendAnimation(animation: notTimeBased);
1627
1628 StateChangeListener listener;
1629 group.addAnimationChangeListener(listener: &listener, QAbstractAnimationJob::CurrentLoop);
1630 group.setLoopCount(2);
1631
1632 group.start();
1633
1634 QCOMPARE(group.currentLoop(), 0);
1635 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
1636 QTRY_COMPARE(plain->state(), QAbstractAnimationJob::Running);
1637
1638 QTRY_COMPARE(loopsForever->state(), QAbstractAnimationJob::Running);
1639 loopsForever->stop();
1640 QTRY_COMPARE(notTimeBased->state(), QAbstractAnimationJob::Running);
1641 QTRY_COMPARE(notTimeBased->state(), QAbstractAnimationJob::Stopped); // Stops on its own after 250ms
1642
1643 QTRY_COMPARE(group.currentLoop(), 1);
1644
1645 QCOMPARE(group.state(), QAbstractAnimationJob::Running);
1646 QTRY_COMPARE(plain->state(), QAbstractAnimationJob::Running);
1647 QTRY_COMPARE(plain->state(), QAbstractAnimationJob::Stopped);
1648 QTRY_COMPARE(loopsForever->state(), QAbstractAnimationJob::Running);
1649 loopsForever->stop();
1650 QTRY_COMPARE(notTimeBased->state(), QAbstractAnimationJob::Running);
1651 QTRY_COMPARE(notTimeBased->state(), QAbstractAnimationJob::Stopped);
1652
1653 QTRY_COMPARE(group.state(), QAbstractAnimationJob::Stopped);
1654}
1655
1656void tst_QSequentialAnimationGroupJob::deleteFromListener()
1657{
1658 QSequentialAnimationGroupJob *group = new QSequentialAnimationGroupJob;
1659
1660 UncontrolledAnimation *uncontrolled = new UncontrolledAnimation();
1661 TestAnimation *shortLoop = new TestAnimation(100);
1662 UncontrolledAnimation *more = new UncontrolledAnimation();
1663
1664 shortLoop->setLoopCount(-1);
1665
1666 group->appendAnimation(animation: uncontrolled);
1667 group->appendAnimation(animation: shortLoop);
1668 group->appendAnimation(animation: more);
1669
1670 StateChangeListener listener;
1671 listener.beEvil = true;
1672 shortLoop->addAnimationChangeListener(listener: &listener, QAbstractAnimationJob::StateChange);
1673 group->setLoopCount(2);
1674
1675 group->start();
1676
1677 QCOMPARE(group->currentLoop(), 0);
1678 QCOMPARE(group->state(), QAbstractAnimationJob::Running);
1679 QTRY_COMPARE(uncontrolled->state(), QAbstractAnimationJob::Running);
1680
1681 QVERIFY(!listener.groupDeleted);
1682 uncontrolled->stop();
1683
1684 QTRY_VERIFY(listener.groupDeleted);
1685 // It's dead, Jim.
1686}
1687
1688QTEST_MAIN(tst_QSequentialAnimationGroupJob)
1689#include "tst_qsequentialanimationgroupjob.moc"
1690

source code of qtdeclarative/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp