Commit 3a5f473a16b3bc64e6793a9a5002d961a2a0762a
- Diff rendering mode:
- inline
- side by side
|   | |||
| 244 | 244 | // in ChildRemoved event | |
| 245 | 245 | d->animations.removeAt(index); | |
| 246 | 246 | animation->setParent(0); | |
| 247 | d->animationRemovedAt(index); | ||
| 247 | d->animationRemoved(index, animation); | ||
| 248 | 248 | return animation; | |
| 249 | 249 | } | |
| 250 | 250 | ||
| … | … | ||
| 285 | 285 | } | |
| 286 | 286 | ||
| 287 | 287 | ||
| 288 | void QAnimationGroupPrivate::animationRemovedAt(int index) | ||
| 288 | void QAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *) | ||
| 289 | 289 | { | |
| 290 | 290 | Q_Q(QAnimationGroup); | |
| 291 | 291 | Q_UNUSED(index); |
|   | |||
| 72 | 72 | isGroup = true; | |
| 73 | 73 | } | |
| 74 | 74 | ||
| 75 | virtual void animationInsertedAt(int index) { Q_UNUSED(index) }; | ||
| 76 | virtual void animationRemovedAt(int index); | ||
| 75 | virtual void animationInsertedAt(int) { } | ||
| 76 | virtual void animationRemoved(int, QAbstractAnimation *); | ||
| 77 | |||
| 78 | void disconnectUncontrolledAnimation(QAbstractAnimation *anim) | ||
| 79 | { | ||
| 80 | //0 for the signal here because we might be called from the animation destructor | ||
| 81 | QObject::disconnect(anim, 0, q_func(), SLOT(_q_uncontrolledAnimationFinished())); | ||
| 82 | } | ||
| 83 | |||
| 84 | void connectUncontrolledAnimation(QAbstractAnimation *anim) | ||
| 85 | { | ||
| 86 | QObject::connect(anim, SIGNAL(finished()), q_func(), SLOT(_q_uncontrolledAnimationFinished())); | ||
| 87 | } | ||
| 77 | 88 | ||
| 78 | 89 | QList<QAbstractAnimation *> animations; | |
| 79 | 90 | }; |
|   | |||
| 246 | 246 | ||
| 247 | 247 | void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations() | |
| 248 | 248 | { | |
| 249 | Q_Q(QParallelAnimationGroup); | ||
| 250 | |||
| 251 | 249 | QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin(); | |
| 252 | 250 | while (it != uncontrolledFinishTime.end()) { | |
| 253 | QObject::disconnect(it.key(), SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); | ||
| 251 | disconnectUncontrolledAnimation(it.key()); | ||
| 254 | 252 | ++it; | |
| 255 | 253 | } | |
| 256 | 254 | ||
| … | … | ||
| 257 | 257 | ||
| 258 | 258 | void QParallelAnimationGroupPrivate::connectUncontrolledAnimations() | |
| 259 | 259 | { | |
| 260 | Q_Q(QParallelAnimationGroup); | ||
| 261 | |||
| 262 | 260 | for (int i = 0; i < animations.size(); ++i) { | |
| 263 | 261 | QAbstractAnimation *animation = animations.at(i); | |
| 264 | 262 | if (animation->duration() == -1 || animation->loopCount() < 0) { | |
| 265 | 263 | uncontrolledFinishTime[animation] = -1; | |
| 266 | QObject::connect(animation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); | ||
| 264 | connectUncontrolledAnimation(animation); | ||
| 267 | 265 | } | |
| 268 | 266 | } | |
| 269 | 267 | } | |
| … | … | ||
| 299 | 299 | bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const | |
| 300 | 300 | { | |
| 301 | 301 | return uncontrolledFinishTime.value(anim, -1) >= 0; | |
| 302 | } | ||
| 303 | |||
| 304 | void QParallelAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *anim) | ||
| 305 | { | ||
| 306 | QAnimationGroupPrivate::animationRemoved(index, anim); | ||
| 307 | disconnectUncontrolledAnimation(anim); | ||
| 308 | uncontrolledFinishTime.remove(anim); | ||
| 302 | 309 | } | |
| 303 | 310 | ||
| 304 | 311 | /*! |
|   | |||
| 80 | 80 | void connectUncontrolledAnimations(); | |
| 81 | 81 | void disconnectUncontrolledAnimations(); | |
| 82 | 82 | ||
| 83 | void animationRemoved(int index, QAbstractAnimation *); | ||
| 84 | |||
| 83 | 85 | // private slot | |
| 84 | 86 | void _q_uncontrolledAnimationFinished(); | |
| 85 | 87 | }; |
|   | |||
| 479 | 479 | ||
| 480 | 480 | // connects to the finish signal of uncontrolled animations | |
| 481 | 481 | if (currentAnimation->totalDuration() == -1) | |
| 482 | QObject::connect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); | ||
| 482 | connectUncontrolledAnimation(currentAnimation); | ||
| 483 | 483 | ||
| 484 | 484 | currentAnimation->start(); | |
| 485 | 485 | if (!intermediate && state == QSequentialAnimationGroup::Paused) | |
| … | … | ||
| 496 | 496 | actualDuration.append(-1); | |
| 497 | 497 | actualDuration[currentAnimationIndex] = currentAnimation->currentTime(); | |
| 498 | 498 | ||
| 499 | QObject::disconnect(currentAnimation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished())); | ||
| 499 | disconnectUncontrolledAnimation(currentAnimation); | ||
| 500 | 500 | ||
| 501 | 501 | if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last()) | |
| 502 | 502 | || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) { | |
| … | … | ||
| 543 | 543 | the group at index \a index. The animation is no more listed when this | |
| 544 | 544 | method is called. | |
| 545 | 545 | */ | |
| 546 | void QSequentialAnimationGroupPrivate::animationRemovedAt(int index) | ||
| 546 | void QSequentialAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *anim) | ||
| 547 | 547 | { | |
| 548 | 548 | Q_Q(QSequentialAnimationGroup); | |
| 549 | QAnimationGroupPrivate::animationRemovedAt(index); | ||
| 549 | QAnimationGroupPrivate::animationRemoved(index, anim); | ||
| 550 | 550 | ||
| 551 | 551 | Q_ASSERT(currentAnimation); // currentAnimation should always be set | |
| 552 | 552 | ||
| … | … | ||
| 555 | 555 | ||
| 556 | 556 | const int currentIndex = animations.indexOf(currentAnimation); | |
| 557 | 557 | if (currentIndex == -1) { | |
| 558 | //we're removing the current animation, let's update it to another one | ||
| 558 | //we're removing the current animation | ||
| 559 | |||
| 560 | disconnectUncontrolledAnimation(currentAnimation); | ||
| 561 | |||
| 559 | 562 | if (index < animations.count()) | |
| 560 | 563 | setCurrentAnimation(index); //let's try to take the next one | |
| 561 | 564 | else if (index > 0) |
|   | |||
| 85 | 85 | void activateCurrentAnimation(bool intermediate = false); | |
| 86 | 86 | ||
| 87 | 87 | void animationInsertedAt(int index); | |
| 88 | void animationRemovedAt(int index); | ||
| 88 | void animationRemoved(int index, QAbstractAnimation *anim); | ||
| 89 | 89 | ||
| 90 | 90 | bool atEnd() const; | |
| 91 | 91 |
|   | |||
| 75 | 75 | void loopCount(); | |
| 76 | 76 | void autoAdd(); | |
| 77 | 77 | void pauseResume(); | |
| 78 | |||
| 79 | void QTBUG8910_crashWhenRemovingUncontrolledAnimation(); | ||
| 78 | 80 | }; | |
| 79 | 81 | ||
| 80 | 82 | tst_QParallelAnimationGroup::tst_QParallelAnimationGroup() | |
| … | … | ||
| 1001 | 1001 | QCOMPARE(spy.count(), 2); //this shouldn't have changed | |
| 1002 | 1002 | group.resume(); | |
| 1003 | 1003 | QCOMPARE(spy.count(), 2); //this shouldn't have changed | |
| 1004 | } | ||
| 1004 | 1005 | ||
| 1005 | 1006 | ||
| 1006 | |||
| 1007 | void tst_QParallelAnimationGroup::QTBUG8910_crashWhenRemovingUncontrolledAnimation() | ||
| 1008 | { | ||
| 1009 | QParallelAnimationGroup group; | ||
| 1010 | TestAnimation *anim = new TestAnimation; | ||
| 1011 | anim->setLoopCount(-1); | ||
| 1012 | TestAnimation *anim2 = new TestAnimation; | ||
| 1013 | anim2->setLoopCount(-1); | ||
| 1014 | group.addAnimation(anim); | ||
| 1015 | group.addAnimation(anim2); | ||
| 1016 | group.start(); | ||
| 1017 | delete anim; | ||
| 1018 | // it would crash here because the internals of the group would still have a reference to anim | ||
| 1019 | delete anim2; | ||
| 1007 | 1020 | } | |
| 1008 | 1021 | ||
| 1009 | 1022 |

