aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/CMakeLists.txt1
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp2
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h7
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp58
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h19
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob.cpp18
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp24
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp73
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h6
-rw-r--r--src/qml/qml/ftw/qdoubleendedlist_p.h292
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp9
-rw-r--r--src/quick/util/qquickanimatorjob.cpp2
-rw-r--r--tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp17
-rw-r--r--tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp9
-rw-r--r--tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp15
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp2
16 files changed, 408 insertions, 146 deletions
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index f59f1d8f23..39c50e5050 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -205,6 +205,7 @@ qt_internal_add_module(Qml
parser/qqmljskeywords_p.h
parser/qqmljslexer.cpp parser/qqmljslexer_p.h
qml/ftw/qbitfield_p.h
+ qml/ftw/qdoubleendedlist_p.h
qml/ftw/qfieldlist_p.h
qml/ftw/qfinitestack_p.h
qml/ftw/qflagpointer_p.h
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index a04b8b6e9b..9e82b63771 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -259,8 +259,6 @@ QAbstractAnimationJob::QAbstractAnimationJob()
, m_currentLoop(0)
, m_uncontrolledFinishTime(-1)
, m_currentLoopStartTime(0)
- , m_nextSibling(nullptr)
- , m_previousSibling(nullptr)
, m_hasRegisteredTimer(false)
, m_isPause(false)
, m_isGroup(false)
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 9490070246..c7514f4583 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -53,6 +53,7 @@
#include <private/qtqmlglobal_p.h>
#include <private/qanimationjobutil_p.h>
+#include <private/qdoubleendedlist_p.h>
#include <QtCore/QObject>
#include <QtCore/private/qabstractanimation_p.h>
#include <vector>
@@ -65,7 +66,7 @@ class QAnimationGroupJob;
class QAnimationJobChangeListener;
class QQmlAnimationTimer;
-class Q_QML_PRIVATE_EXPORT QAbstractAnimationJob
+class Q_QML_PRIVATE_EXPORT QAbstractAnimationJob : public QInheritedListNode
{
Q_DISABLE_COPY(QAbstractAnimationJob)
public:
@@ -124,8 +125,6 @@ public:
void addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
void removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
- QAbstractAnimationJob *nextSibling() const { return m_nextSibling; }
- QAbstractAnimationJob *previousSibling() const { return m_previousSibling; }
bool isGroup() const { return m_isGroup; }
bool isRenderThreadJob() const { return m_isRenderThreadJob; }
@@ -173,8 +172,6 @@ protected:
};
std::vector<ChangeListener> changeListeners;
- QAbstractAnimationJob *m_nextSibling;
- QAbstractAnimationJob *m_previousSibling;
QQmlAnimationTimer *m_timer = nullptr;
bool m_hasRegisteredTimer:1;
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index 60b3003d0a..3b6c9123bf 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -42,7 +42,6 @@
QT_BEGIN_NAMESPACE
QAnimationGroupJob::QAnimationGroupJob()
- : QAbstractAnimationJob(), m_firstChild(nullptr), m_lastChild(nullptr)
{
m_isGroup = true;
}
@@ -51,29 +50,14 @@ void QAnimationGroupJob::ungroupChild(QAbstractAnimationJob *animation)
{
Q_ASSERT(animation);
Q_ASSERT(animation->m_group == this);
- QAbstractAnimationJob *prev = animation->previousSibling();
- QAbstractAnimationJob *next = animation->nextSibling();
-
- if (prev)
- prev->m_nextSibling = next;
- else
- m_firstChild = next;
-
- if (next)
- next->m_previousSibling = prev;
- else
- m_lastChild = prev;
-
- animation->m_previousSibling = nullptr;
- animation->m_nextSibling = nullptr;
-
+ m_children.remove(animation);
animation->m_group = nullptr;
}
void QAnimationGroupJob::handleAnimationRemoved(QAbstractAnimationJob *animation)
{
resetUncontrolledAnimationFinishTime(animation);
- if (!firstChild()) {
+ if (m_children.isEmpty()) {
m_currentTime = 0;
stop();
}
@@ -81,7 +65,7 @@ void QAnimationGroupJob::handleAnimationRemoved(QAbstractAnimationJob *animation
QAnimationGroupJob::~QAnimationGroupJob()
{
- while (QAbstractAnimationJob *animation = firstChild()) {
+ while (QAbstractAnimationJob *animation = m_children.first()) {
ungroupChild(animation);
handleAnimationRemoved(animation);
delete animation;
@@ -90,7 +74,7 @@ QAnimationGroupJob::~QAnimationGroupJob()
void QAnimationGroupJob::topLevelAnimationLoopChanged()
{
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
animation->fireTopLevelAnimationLoopChanged();
}
@@ -99,15 +83,9 @@ void QAnimationGroupJob::appendAnimation(QAbstractAnimationJob *animation)
if (QAnimationGroupJob *oldGroup = animation->m_group)
oldGroup->removeAnimation(animation);
- Q_ASSERT(!animation->previousSibling() && !animation->nextSibling());
-
- if (m_lastChild)
- m_lastChild->m_nextSibling = animation;
- else
- m_firstChild = animation;
- animation->m_previousSibling = m_lastChild;
- m_lastChild = animation;
+ Q_ASSERT(!animation->isInList());
+ m_children.append(animation);
animation->m_group = this;
animationInserted(animation);
}
@@ -117,40 +95,34 @@ void QAnimationGroupJob::prependAnimation(QAbstractAnimationJob *animation)
if (QAnimationGroupJob *oldGroup = animation->m_group)
oldGroup->removeAnimation(animation);
- Q_ASSERT(!previousSibling() && !nextSibling());
-
- if (m_firstChild)
- m_firstChild->m_previousSibling = animation;
- else
- m_lastChild = animation;
- animation->m_nextSibling = m_firstChild;
- m_firstChild = animation;
+ Q_ASSERT(!animation->isInList());
+ m_children.prepend(animation);
animation->m_group = this;
animationInserted(animation);
}
void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
{
- QAbstractAnimationJob *prev = animation->previousSibling();
- QAbstractAnimationJob *next = animation->nextSibling();
+ QAbstractAnimationJob *prev = m_children.prev(animation);
+ QAbstractAnimationJob *next = m_children.next(animation);
ungroupChild(animation);
animationRemoved(animation, prev, next);
}
void QAnimationGroupJob::clear()
{
- while (QAbstractAnimationJob *child = firstChild()) {
+ while (QAbstractAnimationJob *child = m_children.first()) {
removeAnimation(child);
delete child;
}
- m_firstChild = nullptr;
- m_lastChild = nullptr;
+
+ Q_ASSERT(m_children.isEmpty());
}
void QAnimationGroupJob::resetUncontrolledAnimationsFinishTime()
{
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
if (animation->duration() == -1 || animation->loopCount() < 0) {
resetUncontrolledAnimationFinishTime(animation);
}
@@ -185,7 +157,7 @@ void QAnimationGroupJob::debugChildren(QDebug d) const
++indentLevel;
QByteArray ind(indentLevel, ' ');
- for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling())
+ for (const QAbstractAnimationJob *child : m_children)
d << "\n" << ind.constData() << child;
}
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index 6a0941db65..3733fc6b8a 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include "private/qabstractanimationjob_p.h"
+#include <QtQml/private/qabstractanimationjob_p.h>
+#include <QtQml/private/qdoubleendedlist_p.h>
#include <QtCore/qdebug.h>
QT_REQUIRE_CONFIG(qml_animation);
@@ -62,6 +63,8 @@ class Q_QML_PRIVATE_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
{
Q_DISABLE_COPY(QAnimationGroupJob)
public:
+ using Children = QDoubleEndedList<QAbstractAnimationJob>;
+
QAnimationGroupJob();
~QAnimationGroupJob() override;
@@ -69,8 +72,8 @@ public:
void prependAnimation(QAbstractAnimationJob *animation);
void removeAnimation(QAbstractAnimationJob *animation);
- QAbstractAnimationJob *firstChild() const { return m_firstChild; }
- QAbstractAnimationJob *lastChild() const { return m_lastChild; }
+ Children *children() { return &m_children; }
+ const Children *children() const { return &m_children; }
virtual void clear();
@@ -85,18 +88,18 @@ protected:
//TODO: confirm location of these (should any be moved into QAbstractAnimationJob?)
void resetUncontrolledAnimationsFinishTime();
void resetUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim);
- int uncontrolledAnimationFinishTime(QAbstractAnimationJob *anim) const { return anim->m_uncontrolledFinishTime; }
+ int uncontrolledAnimationFinishTime(const QAbstractAnimationJob *anim) const
+ {
+ return anim->m_uncontrolledFinishTime;
+ }
void setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time);
void debugChildren(QDebug d) const;
-private:
void ungroupChild(QAbstractAnimationJob *animation);
void handleAnimationRemoved(QAbstractAnimationJob *animation);
- //definition
- QAbstractAnimationJob *m_firstChild = nullptr;
- QAbstractAnimationJob *m_lastChild = nullptr;
+ Children m_children;
};
QT_END_NAMESPACE
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
index 88c0e9e60e..7d24d8ce55 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
@@ -52,9 +52,8 @@ QContinuingAnimationGroupJob::~QContinuingAnimationGroupJob()
void QContinuingAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
- Q_ASSERT(firstChild());
-
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ Q_ASSERT(!m_children.isEmpty());
+ for (QAbstractAnimationJob *animation : m_children) {
if (animation->state() == state()) {
RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
}
@@ -68,20 +67,20 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
switch (newState) {
case Stopped:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
animation->stop();
break;
case Paused:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
if (animation->isRunning())
animation->pause();
break;
case Running:
- if (!firstChild()) {
+ if (m_children.isEmpty()) {
stop();
return;
}
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
resetUncontrolledAnimationFinishTime(animation);
animation->setDirection(m_direction);
animation->start();
@@ -93,9 +92,8 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
void QContinuingAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
{
if (!isStopped()) {
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children)
animation->setDirection(direction);
- }
}
}
@@ -104,7 +102,7 @@ void QContinuingAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
Q_ASSERT(animation && (animation->duration() == -1));
int uncontrolledRunningCount = 0;
- for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
+ for (QAbstractAnimationJob *child : m_children) {
if (child == animation)
setUncontrolledAnimationFinishTime(animation, animation->currentTime());
else if (uncontrolledAnimationFinishTime(child) == -1)
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 420a934ba2..4da4a06af2 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -57,7 +57,7 @@ int QParallelAnimationGroupJob::duration() const
{
int ret = 0;
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (const QAbstractAnimationJob *animation : m_children) {
int currentDuration = animation->totalDuration();
if (currentDuration == -1)
return -1; // Undetermined length
@@ -69,7 +69,7 @@ int QParallelAnimationGroupJob::duration() const
void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
- if (!firstChild())
+ if (m_children.isEmpty())
return;
if (m_currentLoop > m_previousLoop) {
@@ -79,21 +79,21 @@ void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
// For an uncontrolled parallel group, we need to simulate the end of running animations.
// As uncontrolled animation finish time is already reset for this next loop, we pick the
// longest of the known stop times.
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
int currentDuration = animation->totalDuration();
if (currentDuration >= 0)
dura = qMax(dura, currentDuration);
}
}
if (dura > 0) {
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
if (!animation->isStopped())
RETURN_IF_DELETED(animation->setCurrentTime(dura)); // will stop
}
}
} else if (m_currentLoop < m_previousLoop) {
// simulate completion of the loop seeking backwards
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
//we need to make sure the animation is in the right state
//and then rewind it
applyGroupState(animation);
@@ -103,7 +103,7 @@ void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
}
// finally move into the actual time of the current loop
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
const int dura = animation->totalDuration();
//if the loopcount is bigger we should always start all animations
if (m_currentLoop > m_previousLoop
@@ -130,16 +130,16 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
switch (newState) {
case Stopped:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
animation->stop();
break;
case Paused:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
if (animation->isRunning())
animation->pause();
break;
case Running:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
if (oldState == Stopped) {
animation->stop();
m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
@@ -188,7 +188,7 @@ void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Directio
{
//we need to update the direction of the current animation
if (!isStopped()) {
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
animation->setDirection(direction);
}
} else {
@@ -208,7 +208,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
int uncontrolledRunningCount = 0;
- for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
+ for (QAbstractAnimationJob *child : m_children) {
if (child == animation) {
setUncontrolledAnimationFinishTime(animation, animation->currentTime());
} else if (child->duration() == -1 || child->loopCount() < 0) {
@@ -222,7 +222,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
int maxDuration = 0;
bool running = false;
- for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling()) {
+ for (QAbstractAnimationJob *job : m_children) {
if (job->state() == Running)
running = true;
maxDuration = qMax(maxDuration, job->totalDuration());
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index 1d19bbf79d..2da6c79e29 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -66,11 +66,12 @@ bool QSequentialAnimationGroupJob::atEnd() const
const int animTotalCurrentTime = m_currentAnimation->currentTime();
return (m_currentLoop == m_loopCount - 1
&& m_direction == Forward
- && !m_currentAnimation->nextSibling()
+ && !m_children.next(m_currentAnimation)
&& animTotalCurrentTime == animationActualTotalDuration(m_currentAnimation));
}
-int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimationJob *anim) const
+int QSequentialAnimationGroupJob::animationActualTotalDuration(
+ const QAbstractAnimationJob *anim) const
{
int ret = anim->totalDuration();
if (ret == -1) {
@@ -84,13 +85,12 @@ int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimatio
QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::indexForCurrentTime() const
{
- Q_ASSERT(firstChild());
+ Q_ASSERT(!m_children.isEmpty());
AnimationIndex ret;
- QAbstractAnimationJob *anim = nullptr;
int duration = 0;
- for (anim = firstChild(); anim; anim = anim->nextSibling()) {
+ for (const QAbstractAnimationJob *anim : m_children) {
duration = animationActualTotalDuration(anim);
// 'animation' is the current animation if one of these reasons is true:
@@ -116,7 +116,7 @@ QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::index
// 1. the duration of the group is undefined and we passed its actual duration
// 2. there are only 0-duration animations in the group
ret.timeOffset -= duration;
- ret.animation = lastChild();
+ ret.animation = m_children.last();
return ret;
}
@@ -125,17 +125,17 @@ void QSequentialAnimationGroupJob::restart()
// restarting the group by making the first/last animation the current one
if (m_direction == Forward) {
m_previousLoop = 0;
- if (m_currentAnimation == firstChild())
+ if (m_currentAnimation == m_children.first())
activateCurrentAnimation();
else
- setCurrentAnimation(firstChild());
+ setCurrentAnimation(m_children.first());
}
else { // direction == Backward
m_previousLoop = m_loopCount - 1;
- if (m_currentAnimation == lastChild())
+ if (m_currentAnimation == m_children.last())
activateCurrentAnimation();
else
- setCurrentAnimation(lastChild());
+ setCurrentAnimation(m_children.last());
}
}
@@ -143,21 +143,22 @@ void QSequentialAnimationGroupJob::advanceForwards(const AnimationIndex &newAnim
{
if (m_previousLoop < m_currentLoop) {
// we need to fast forward to the end
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->nextSibling()) {
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = m_children.next(anim)) {
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
}
// this will make sure the current animation is reset to the beginning
- if (firstChild() && !firstChild()->nextSibling()) { //count == 1
+ if (m_children.count() == 1) {
// we need to force activation because setCurrentAnimation will have no effect
RETURN_IF_DELETED(activateCurrentAnimation());
} else {
- RETURN_IF_DELETED(setCurrentAnimation(firstChild(), true));
+ RETURN_IF_DELETED(setCurrentAnimation(m_children.first(), true));
}
}
// and now we need to fast forward from the current position to
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->nextSibling()) { //### WRONG,
+ for (QAbstractAnimationJob *anim = m_currentAnimation;
+ anim && anim != newAnimationIndex.animation; anim = m_children.next(anim)) { //### WRONG,
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
}
@@ -168,21 +169,23 @@ void QSequentialAnimationGroupJob::rewindForwards(const AnimationIndex &newAnima
{
if (m_previousLoop > m_currentLoop) {
// we need to fast rewind to the beginning
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->previousSibling()) {
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim;
+ anim = m_children.prev(anim)) {
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(0));
}
// this will make sure the current animation is reset to the end
- if (lastChild() && !lastChild()->previousSibling()) { //count == 1
+ if (m_children.count() == 1) { //count == 1
// we need to force activation because setCurrentAnimation will have no effect
RETURN_IF_DELETED(activateCurrentAnimation());
} else {
- RETURN_IF_DELETED(setCurrentAnimation(lastChild(), true));
+ RETURN_IF_DELETED(setCurrentAnimation(m_children.last(), true));
}
}
// and now we need to fast rewind from the current position to
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->previousSibling()) {
+ for (QAbstractAnimationJob *anim = m_currentAnimation;
+ anim && anim != newAnimationIndex.animation; anim = m_children.prev(anim)) {
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(0));
}
@@ -193,7 +196,7 @@ int QSequentialAnimationGroupJob::duration() const
{
int ret = 0;
- for (QAbstractAnimationJob *anim = firstChild(); anim; anim = anim->nextSibling()) {
+ for (const QAbstractAnimationJob *anim : m_children) {
const int currentDuration = anim->totalDuration();
if (currentDuration == -1)
return -1; // Undetermined length
@@ -246,7 +249,7 @@ void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
} else {
//the only case where currentAnimation could be null
//is when all animations have been removed
- Q_ASSERT(!firstChild());
+ Q_ASSERT(m_children.isEmpty());
m_currentTime = 0;
RETURN_IF_DELETED(stop());
}
@@ -288,10 +291,11 @@ void QSequentialAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direct
m_currentAnimation->setDirection(direction);
}
-void QSequentialAnimationGroupJob::setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate)
+void QSequentialAnimationGroupJob::setCurrentAnimation(
+ const QAbstractAnimationJob *anim, bool intermediate)
{
if (!anim) {
- Q_ASSERT(!firstChild());
+ Q_ASSERT(m_children.isEmpty());
m_currentAnimation = nullptr;
return;
}
@@ -303,7 +307,12 @@ void QSequentialAnimationGroupJob::setCurrentAnimation(QAbstractAnimationJob *an
if (m_currentAnimation)
m_currentAnimation->stop();
- m_currentAnimation = anim;
+ // Assert that the animation passed as argument is actually part of this group ...
+ Q_ASSERT(m_children.contains(anim));
+
+ // ... as then this const_cast is just a shortcut for looking up the non-const
+ // pointer in the linked list of jobs.
+ m_currentAnimation = const_cast<QAbstractAnimationJob *>(anim);
activateCurrentAnimation(intermediate);
}
@@ -337,10 +346,10 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
int totalTime = currentTime();
if (m_direction == Forward) {
// set the current animation to be the next one
- if (m_currentAnimation->nextSibling())
- RETURN_IF_DELETED(setCurrentAnimation(m_currentAnimation->nextSibling()));
+ if (auto *anim = m_children.next(m_currentAnimation))
+ RETURN_IF_DELETED(setCurrentAnimation(anim));
- for (QAbstractAnimationJob *a = animation->nextSibling(); a; a = a->nextSibling()) {
+ for (QAbstractAnimationJob *a = m_children.next(animation); a; a = m_children.next(a)) {
int dur = a->duration();
if (dur == -1) {
totalTime = -1;
@@ -352,10 +361,10 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
} else {
// set the current animation to be the previous one
- if (m_currentAnimation->previousSibling())
- RETURN_IF_DELETED(setCurrentAnimation(m_currentAnimation->previousSibling()));
+ if (auto *anim = m_children.prev(m_currentAnimation))
+ RETURN_IF_DELETED(setCurrentAnimation(anim));
- for (QAbstractAnimationJob *a = animation->previousSibling(); a; a = a->previousSibling()) {
+ for (QAbstractAnimationJob *a = m_children.prev(animation); a; a = m_children.prev(a)) {
int dur = a->duration();
if (dur == -1) {
totalTime = -1;
@@ -374,9 +383,9 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)
{
if (m_currentAnimation == nullptr)
- RETURN_IF_DELETED(setCurrentAnimation(firstChild())); // initialize the current animation
+ RETURN_IF_DELETED(setCurrentAnimation(m_children.first())); // initialize the current animation
- if (m_currentAnimation == anim->nextSibling()
+ if (m_currentAnimation == m_children.next(anim)
&& m_currentAnimation->currentTime() == 0 && m_currentAnimation->currentLoop() == 0) {
//in this case we simply insert the animation before the current one has actually started
RETURN_IF_DELETED(setCurrentAnimation(anim));
@@ -407,7 +416,7 @@ void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim,
// duration of the previous animations up to the current animation
m_currentTime = 0;
- for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling()) {
+ for (QAbstractAnimationJob *job : m_children) {
if (job == m_currentAnimation)
break;
m_currentTime += animationActualTotalDuration(job);
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
index 34e8fe1e08..8c58862a50 100644
--- a/src/qml/animations/qsequentialanimationgroupjob_p.h
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -85,13 +85,13 @@ private:
// Note that the index semantic is slightly different depending on the direction.
bool afterCurrent = false; //whether animation is before or after m_currentAnimation //TODO: make enum Before/After/Same
int timeOffset = 0; // time offset when the animation at index starts.
- QAbstractAnimationJob *animation = nullptr; //points to the animation at timeOffset
+ const QAbstractAnimationJob *animation = nullptr; //points to the animation at timeOffset
};
- int animationActualTotalDuration(QAbstractAnimationJob *anim) const;
+ int animationActualTotalDuration(const QAbstractAnimationJob *anim) const;
AnimationIndex indexForCurrentTime() const;
- void setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate = false);
+ void setCurrentAnimation(const QAbstractAnimationJob *anim, bool intermediate = false);
void activateCurrentAnimation(bool intermediate = false);
void animationInserted(QAbstractAnimationJob *anim) override;
diff --git a/src/qml/qml/ftw/qdoubleendedlist_p.h b/src/qml/qml/ftw/qdoubleendedlist_p.h
new file mode 100644
index 0000000000..33fe97502d
--- /dev/null
+++ b/src/qml/qml/ftw/qdoubleendedlist_p.h
@@ -0,0 +1,292 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDOUBLEENDEDLIST_P_H
+#define QDOUBLEENDEDLIST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QInheritedListNode
+{
+public:
+ ~QInheritedListNode() { remove(); }
+ bool isInList() const
+ {
+ Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next));
+ return m_prev != nullptr;
+ }
+
+private:
+ template<class N>
+ friend class QDoubleEndedList;
+
+ void remove()
+ {
+ Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next));
+ if (!m_prev)
+ return;
+
+ m_prev->m_next = m_next;
+ m_next->m_prev = m_prev;
+ m_prev = nullptr;
+ m_next = nullptr;
+ }
+
+ QInheritedListNode *m_next = nullptr;
+ QInheritedListNode *m_prev = nullptr;
+};
+
+template<class N>
+class QDoubleEndedList
+{
+public:
+ QDoubleEndedList()
+ {
+ m_head.m_next = &m_head;
+ m_head.m_prev = &m_head;
+ assertHeadConsistent();
+ }
+
+ ~QDoubleEndedList()
+ {
+ assertHeadConsistent();
+ while (!isEmpty())
+ m_head.m_next->remove();
+ assertHeadConsistent();
+ }
+
+ bool isEmpty() const
+ {
+ assertHeadConsistent();
+ return m_head.m_next == &m_head;
+ }
+
+ void prepend(N *n)
+ {
+ assertHeadConsistent();
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+
+ nnode->m_next = m_head.m_next ? m_head.m_next : &m_head;
+ nnode->m_next->m_prev = nnode;
+
+ m_head.m_next = nnode;
+ nnode->m_prev = &m_head;
+ assertHeadConsistent();
+ }
+
+ void append(N *n)
+ {
+ assertHeadConsistent();
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+
+ nnode->m_prev = m_head.m_prev ? m_head.m_prev : &m_head;
+ nnode->m_prev->m_next = nnode;
+
+ m_head.m_prev = nnode;
+ nnode->m_next = &m_head;
+ assertHeadConsistent();
+ }
+
+ void remove(N *n) {
+ Q_ASSERT(contains(n));
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+ assertHeadConsistent();
+ }
+
+ bool contains(const N *n) const
+ {
+ assertHeadConsistent();
+ for (const QInheritedListNode *nnode = m_head.m_next;
+ nnode != &m_head; nnode = nnode->m_next) {
+ if (nnode == n)
+ return true;
+ }
+
+ return false;
+ }
+
+ template<typename T, typename Node>
+ class base_iterator {
+ public:
+ T *operator*() const { return QDoubleEndedList<N>::nodeToN(m_node); }
+ T *operator->() const { return QDoubleEndedList<N>::nodeToN(m_node); }
+
+ bool operator==(const base_iterator &other) const { return other.m_node == m_node; }
+ bool operator!=(const base_iterator &other) const { return other.m_node != m_node; }
+
+ base_iterator &operator++()
+ {
+ m_node = m_node->m_next;
+ return *this;
+ }
+
+ base_iterator operator++(int)
+ {
+ const base_iterator self(m_node);
+ m_node = m_node->m_next;
+ return self;
+ }
+
+ private:
+ friend class QDoubleEndedList<N>;
+
+ base_iterator(Node *node) : m_node(node)
+ {
+ Q_ASSERT(m_node != nullptr);
+ }
+
+ Node *m_node = nullptr;
+ };
+
+ using iterator = base_iterator<N, QInheritedListNode>;
+ using const_iterator = base_iterator<const N, const QInheritedListNode>;
+
+ const N *first() const { return checkedNodeToN(m_head.m_next); }
+ N *first() { return checkedNodeToN(m_head.m_next); }
+
+ const N *last() const { return checkedNodeToN(m_head.m_prev); }
+ N *last() { return checkedNodeToN(m_head.m_prev); }
+
+ const N *next(const N *current) const
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_next);
+ }
+
+ N *next(N *current)
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_next);
+ }
+
+ const N *prev(const N *current) const
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_prev);
+ }
+
+ N *prev(N *current)
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_prev);
+ }
+
+ iterator begin()
+ {
+ assertHeadConsistent();
+ return iterator(m_head.m_next);
+ }
+
+ iterator end()
+ {
+ assertHeadConsistent();
+ return iterator(&m_head);
+ }
+
+ const_iterator begin() const
+ {
+ assertHeadConsistent();
+ return const_iterator(m_head.m_next);
+ }
+
+ const_iterator end() const
+ {
+ assertHeadConsistent();
+ return const_iterator(&m_head);
+ }
+
+ qsizetype count() const
+ {
+ assertHeadConsistent();
+ qsizetype result = 0;
+ for (const auto *node = m_head.m_next; node != &m_head; node = node->m_next)
+ ++result;
+ return result;
+ }
+
+private:
+ static N *nodeToN(QInheritedListNode *node)
+ {
+ return static_cast<N *>(node);
+ }
+
+ static const N *nodeToN(const QInheritedListNode *node)
+ {
+ return static_cast<const N *>(node);
+ }
+
+ N *checkedNodeToN(QInheritedListNode *node) const
+ {
+ assertHeadConsistent();
+ return (!node || node == &m_head) ? nullptr : nodeToN(node);
+ }
+
+ void assertHeadConsistent() const
+ {
+ Q_ASSERT(m_head.m_next != nullptr);
+ Q_ASSERT(m_head.m_prev != nullptr);
+ Q_ASSERT(m_head.m_next != &m_head || m_head.m_prev == &m_head);
+ }
+
+ QInheritedListNode m_head;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDOUBLEENDEDLIST_P_H
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 9b60fe7ae0..e0fd8537a7 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -65,8 +65,7 @@ static void qquickanimator_invalidate_jobs(QAbstractAnimationJob *job)
if (job->isRenderThreadJob()) {
static_cast<QQuickAnimatorJob *>(job)->invalidate();
} else if (job->isGroup()) {
- QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
- for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+ for (QAbstractAnimationJob *a : *static_cast<QAnimationGroupJob *>(job)->children())
qquickanimator_invalidate_jobs(a);
}
}
@@ -115,8 +114,7 @@ static void qquickanimator_sync_before_start(QAbstractAnimationJob *job)
if (job->isRenderThreadJob()) {
static_cast<QQuickAnimatorJob *>(job)->preSync();
} else if (job->isGroup()) {
- QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
- for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+ for (QAbstractAnimationJob *a : *static_cast<QAnimationGroupJob *>(job)->children())
qquickanimator_sync_before_start(a);
}
}
@@ -195,8 +193,7 @@ void QQuickAnimatorController::start_helper(QAbstractAnimationJob *job)
j->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
j->initialize(this);
} else if (job->isGroup()) {
- QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
- for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+ for (QAbstractAnimationJob *a : *static_cast<QAnimationGroupJob *>(job)->children())
start_helper(a);
}
}
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 93d4e9a8b5..e18e31c023 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -243,7 +243,7 @@ static void qquick_syncback_helper(QAbstractAnimationJob *job)
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
- for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+ for (QAbstractAnimationJob *a : *g->children())
qquick_syncback_helper(a);
}
diff --git a/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp b/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
index 6bd8c2a2e0..ceb8cc707f 100644
--- a/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qanimationgroupjob/tst_qanimationgroupjob.cpp
@@ -266,14 +266,15 @@ void tst_QAnimationGroupJob::addChildTwice()
subGroup = new QAbstractAnimationJob;
parent->appendAnimation(subGroup);
parent->appendAnimation(subGroup);
- QVERIFY(parent->firstChild());
- QVERIFY(!parent->firstChild()->nextSibling());
- QVERIFY(!parent->firstChild()->previousSibling());
+ QVERIFY(!parent->children()->isEmpty());
+ QCOMPARE(parent->children()->count(), 1);
+ QVERIFY(!parent->children()->next(parent->children()->first()));
+ QVERIFY(!parent->children()->prev(parent->children()->last()));
parent->clear();
QCOMPARE(parent->currentAnimation(), nullptr);
- QVERIFY(!parent->firstChild());
+ QVERIFY(parent->children()->isEmpty());
// adding the same item twice to a group will remove the item from its current position
// and append it to the end
@@ -282,13 +283,13 @@ void tst_QAnimationGroupJob::addChildTwice()
subGroup2 = new QAbstractAnimationJob;
parent->appendAnimation(subGroup2);
- QCOMPARE(parent->firstChild(), subGroup);
- QCOMPARE(parent->lastChild(), subGroup2);
+ QCOMPARE(parent->children()->first(), subGroup);
+ QCOMPARE(parent->children()->last(), subGroup2);
parent->appendAnimation(subGroup);
- QCOMPARE(parent->firstChild(), subGroup2);
- QCOMPARE(parent->lastChild(), subGroup);
+ QCOMPARE(parent->children()->first(), subGroup2);
+ QCOMPARE(parent->children()->last(), subGroup);
delete parent;
}
diff --git a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
index 8c4c461813..a22c94e4c4 100644
--- a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp
@@ -321,14 +321,11 @@ void tst_QParallelAnimationGroupJob::clearGroup()
group.appendAnimation(new QParallelAnimationGroupJob);
}
- int count = 0;
- for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling())
- ++count;
- QCOMPARE(count, animationCount);
+ QCOMPARE(group.children()->count(), animationCount);
group.clear();
- QVERIFY(!group.firstChild() && !group.lastChild());
+ QVERIFY(group.children()->isEmpty());
QCOMPARE(group.currentLoopTime(), 0);
}
@@ -435,7 +432,7 @@ void tst_QParallelAnimationGroupJob::deleteChildrenWithRunningGroup()
QTRY_VERIFY(group.currentLoopTime() > 0);
delete anim1;
- QVERIFY(!group.firstChild());
+ QVERIFY(group.children()->isEmpty());
QCOMPARE(group.duration(), 0);
QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
QCOMPARE(group.currentLoopTime(), 0); //that's the invariant
diff --git a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
index 2712ccde67..e8872ebc58 100644
--- a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
@@ -933,14 +933,11 @@ void tst_QSequentialAnimationGroupJob::clearGroup()
subGroup->appendAnimation(new QPauseAnimationJob(10));
}
- int count = 0;
- for (QAbstractAnimationJob *anim = group.firstChild(); anim; anim = anim->nextSibling())
- ++count;
- QCOMPARE(count, animationCount);
+ QCOMPARE(group.children()->count(), animationCount);
group.clear();
- QVERIFY(!group.firstChild() && !group.lastChild());
+ QVERIFY(group.children()->isEmpty());
QCOMPARE(group.currentLoopTime(), 0);
}
@@ -1131,7 +1128,7 @@ void tst_QSequentialAnimationGroupJob::deleteChildrenWithRunningGroup()
QTRY_VERIFY(group.currentLoopTime() > 0);
delete anim1;
- QVERIFY(!group.firstChild());
+ QVERIFY(group.children()->isEmpty());
QCOMPARE(group.duration(), 0);
QCOMPARE(group.state(), QAnimationGroupJob::Stopped);
QCOMPARE(group.currentLoopTime(), 0); //that's the invariant
@@ -1568,12 +1565,12 @@ void tst_QSequentialAnimationGroupJob::clear()
TestAnimation *anim2 = new TestAnimation;
group.appendAnimation(anim2);
- QCOMPARE(group.firstChild(), anim1);
- QCOMPARE(group.lastChild(), anim2);
+ QCOMPARE(group.children()->first(), anim1);
+ QCOMPARE(group.children()->last(), anim2);
group.start();
QTest::qWait(anim1->duration() + 100);
- QTRY_VERIFY(!group.firstChild());
+ QTRY_VERIFY(group.children()->isEmpty());
QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
QCOMPARE(group.currentLoopTime(), 0);
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index fe366d0f34..f903256d49 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -1543,7 +1543,7 @@ void tst_qquickanimations::loopingBug()
QVERIFY(anim != nullptr);
QCOMPARE(anim->qtAnimation()->totalDuration(), 300);
QCOMPARE(anim->isRunning(), true);
- QTRY_COMPARE(static_cast<QAnimationGroupJob*>(anim->qtAnimation())->firstChild()->currentLoop(), 2);
+ QTRY_COMPARE(static_cast<QAnimationGroupJob*>(anim->qtAnimation())->children()->first()->currentLoop(), 2);
QTRY_COMPARE(anim->isRunning(), false);
QQuickRectangle *rect = obj->findChild<QQuickRectangle*>();