From 3fe0716f608da26332625b98e724aad73f687993 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 18 Oct 2011 14:10:36 +1000 Subject: [PATCH] Allow one incubator to start in the statusChanged() of another Change-Id: I91cb7e2a8ecc67f34cdcadc0b71f819c2881e2da Reviewed-by: Martin Jones --- src/declarative/qml/qdeclarativeincubator.cpp | 14 +++- .../data/chainedAsynchronousIfNested.qml | 5 ++ .../tst_qdeclarativeincubator.cpp | 85 ++++++++++++++++++++++ 3 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeincubator/data/chainedAsynchronousIfNested.qml diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp index abd759d..d1afac2 100644 --- a/src/declarative/qml/qdeclarativeincubator.cpp +++ b/src/declarative/qml/qdeclarativeincubator.cpp @@ -313,13 +313,21 @@ void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i) finishIncubate: if (progress == QDeclarativeIncubatorPrivate::Completed && waitingFor.isEmpty()) { + typedef QDeclarativeIncubatorPrivate IP; + QDeclarativeIncubatorPrivate *isWaiting = waitingOnMe; clear(); - if (isWaiting) isWaiting->incubate(i); - enginePriv->inProgressCreations--; + if (isWaiting) { + QRecursionWatcher watcher(isWaiting); + changeStatus(calculateStatus()); + if (!watcher.hasRecursed()) + isWaiting->incubate(i); + } else { + changeStatus(calculateStatus()); + } - changeStatus(calculateStatus()); + enginePriv->inProgressCreations--; if (0 == enginePriv->inProgressCreations) { while (enginePriv->erroredBindings) { diff --git a/tests/auto/declarative/qdeclarativeincubator/data/chainedAsynchronousIfNested.qml b/tests/auto/declarative/qdeclarativeincubator/data/chainedAsynchronousIfNested.qml new file mode 100644 index 0000000..1300426 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/data/chainedAsynchronousIfNested.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +SelfRegistering { + property int dummy: 10 +} diff --git a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp index 3582548..e3648f7 100644 --- a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp +++ b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp @@ -82,6 +82,7 @@ private slots: void statusChanged(); void asynchronousIfNested(); void nestedComponent(); + void chainedAsynchronousIfNested(); private: QDeclarativeIncubationController controller; @@ -687,6 +688,90 @@ void tst_qdeclarativeincubator::nestedComponent() delete object; } +// Checks that a new AsynchronousIfNested incubator can be correctly started in the +// statusChanged() callback of another. +void tst_qdeclarativeincubator::chainedAsynchronousIfNested() +{ + SelfRegisteringType::clearMe(); + + QDeclarativeComponent component(&engine, TEST_FILE("chainedAsynchronousIfNested.qml")); + QVERIFY(component.isReady()); + + QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous); + component.create(incubator); + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + struct MyIncubator : public QDeclarativeIncubator { + MyIncubator(MyIncubator *next, QDeclarativeComponent *component, QDeclarativeContext *ctxt) + : QDeclarativeIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {} + + protected: + virtual void statusChanged(Status s) { + if (s == Ready && next) + component->create(*next, 0, ctxt); + } + + private: + MyIncubator *next; + QDeclarativeComponent *component; + QDeclarativeContext *ctxt; + }; + + MyIncubator incubator2(0, &component, 0); + MyIncubator incubator1(&incubator2, &component, qmlContext(SelfRegisteringType::me())); + + component.create(incubator1, 0, qmlContext(SelfRegisteringType::me())); + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + + while (incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + + while (incubator2.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); +} + QTEST_MAIN(tst_qdeclarativeincubator) #include "tst_qdeclarativeincubator.moc" -- 2.7.4