Allow one incubator to start in the statusChanged() of another
authorAaron Kennedy <aaron.kennedy@nokia.com>
Tue, 18 Oct 2011 04:10:36 +0000 (14:10 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 20 Oct 2011 11:25:45 +0000 (13:25 +0200)
Change-Id: I91cb7e2a8ecc67f34cdcadc0b71f819c2881e2da
Reviewed-by: Martin Jones <martin.jones@nokia.com>

src/declarative/qml/qdeclarativeincubator.cpp
tests/auto/declarative/qdeclarativeincubator/data/chainedAsynchronousIfNested.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp

index abd759d..d1afac2 100644 (file)
@@ -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<IP, &IP::recursion> 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 (file)
index 0000000..1300426
--- /dev/null
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+SelfRegistering {
+    property int dummy: 10
+}
index 3582548..e3648f7 100644 (file)
@@ -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"