When clearing an incubator also clear incubators it is waiting for.
authorMartin Jones <martin.jones@nokia.com>
Mon, 19 Mar 2012 07:37:02 +0000 (17:37 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 19 Mar 2012 09:49:39 +0000 (10:49 +0100)
If an incubator is cleared while waiting for other incubators
to complete also clear the incubators it is waiting for.

Change-Id: I83470920c0fd8a23d0098849192555f7478bb492
Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
src/qml/qml/qqmlincubator.cpp
tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp

index c8413f7..aa9777d 100644 (file)
@@ -542,6 +542,10 @@ void QQmlIncubator::clear()
 
     d->clear();
 
+    // if we're waiting on any incubators then they should be cleared too.
+    while (d->waitingFor.first())
+        static_cast<QQmlIncubatorPrivate*>(d->waitingFor.first())->q->clear();
+
     d->vme.reset();
     d->vmeGuard.clear();
 
index fc54f71..54a31ae 100644 (file)
@@ -76,6 +76,7 @@ private slots:
     void nestedComponent();
     void chainedAsynchronousIfNested();
     void chainedAsynchronousIfNestedOnCompleted();
+    void chainedAsynchronousClear();
     void selfDelete();
     void contextDelete();
 
@@ -934,6 +935,122 @@ void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted()
     QVERIFY(incubator3.isReady());
 }
 
+// Checks that new AsynchronousIfNested incubators can be correctly cleared if started in
+// componentCompleted().
+void tst_qqmlincubator::chainedAsynchronousClear()
+{
+    SelfRegisteringType::clearMe();
+
+    QQmlComponent component(&engine, testFileUrl("chainInCompletion.qml"));
+    QVERIFY(component.isReady());
+
+    QQmlComponent c1(&engine, testFileUrl("chainedAsynchronousIfNested.qml"));
+    QVERIFY(c1.isReady());
+
+    struct MyIncubator : public QQmlIncubator {
+        MyIncubator(MyIncubator *next, QQmlComponent *component, QQmlContext *ctxt)
+        : QQmlIncubator(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;
+        QQmlComponent *component;
+        QQmlContext *ctxt;
+    };
+
+    struct CallbackData {
+        CallbackData(QQmlComponent *c, MyIncubator *i, QQmlContext *ct)
+            : component(c), incubator(i), ctxt(ct) {}
+        QQmlComponent *component;
+        MyIncubator *incubator;
+        QQmlContext *ctxt;
+        static void callback(CompletionCallbackType *, void *data) {
+            CallbackData *d = (CallbackData *)data;
+            d->component->create(*d->incubator, 0, d->ctxt);
+        }
+    };
+
+    QQmlIncubator incubator(QQmlIncubator::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());
+
+    MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me()));
+    MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me()));
+    MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me()));
+
+    // start incubator1 in componentComplete
+    CallbackData cd(&c1, &incubator1, qmlContext(SelfRegisteringType::me()));
+    CompletionCallbackType::registerCallback(&CallbackData::callback, &cd);
+
+    while (!incubator1.isLoading()) {
+        QVERIFY(incubator.isLoading());
+        QVERIFY(incubator2.isNull());
+        QVERIFY(incubator3.isNull());
+
+        bool b = false;
+        controller.incubateWhile(&b);
+    }
+
+    QVERIFY(incubator.isLoading());
+    QVERIFY(incubator1.isLoading());
+    QVERIFY(incubator2.isNull());
+    QVERIFY(incubator3.isNull());
+
+    while (incubator1.isLoading()) {
+        QVERIFY(incubator.isLoading());
+        QVERIFY(incubator1.isLoading());
+        QVERIFY(incubator2.isNull());
+        QVERIFY(incubator3.isNull());
+
+        bool b = false;
+        controller.incubateWhile(&b);
+    }
+
+    QVERIFY(incubator.isLoading());
+    QVERIFY(incubator1.isReady());
+    QVERIFY(incubator2.isLoading());
+    QVERIFY(incubator3.isNull());
+
+    while (incubator2.isLoading()) {
+        QVERIFY(incubator.isLoading());
+        QVERIFY(incubator1.isReady());
+        QVERIFY(incubator2.isLoading());
+        QVERIFY(incubator3.isNull());
+
+        bool b = false;
+        controller.incubateWhile(&b);
+    }
+
+    QVERIFY(incubator.isLoading());
+    QVERIFY(incubator1.isReady());
+    QVERIFY(incubator2.isReady());
+    QVERIFY(incubator3.isLoading());
+
+    // Any in loading state will become null when cleared.
+    incubator.clear();
+
+    QVERIFY(incubator.isNull());
+    QVERIFY(incubator1.isReady());
+    QVERIFY(incubator2.isReady());
+    QVERIFY(incubator3.isNull());
+}
+
 void tst_qqmlincubator::selfDelete()
 {
     struct MyIncubator : public QQmlIncubator {