aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Jones <martin.jones@nokia.com>2011-11-01 10:05:47 +1000
committerQt by Nokia <qt-info@nokia.com>2011-11-01 13:09:31 +0100
commitf75bd7eb78759a2b708771517b5fc64fd7a75e8a (patch)
tree3e71ed39482f9272afbc6feea2d6cf94b5555e48
parentc29b3c0974383dfe5e2b4890b5d6377d5aa4264e (diff)
Ensure that chained incubation works from componentCompleted.
Make chained AsynchronousIfNested initiated from componentComplete work correctly, i.e. asynchronous incubator is not Ready until all chained creation is Ready. Change-Id: I286cc10e2f09e36dcc6034f3f23681e833d7e6e8 Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp4
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h5
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp3
-rw-r--r--src/declarative/qml/qdeclarativeincubator.cpp17
-rw-r--r--src/declarative/qml/qdeclarativeincubator_p.h2
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp25
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h2
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml5
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/testtypes.cpp28
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/testtypes.h18
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp129
11 files changed, 216 insertions, 22 deletions
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index c9ae825ae2..c4fc764e7d 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -511,7 +511,7 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject
QDeclarativeContextData::QDeclarativeContextData()
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
- isPragmaLibraryContext(false), publicContext(0), activeVME(0), propertyNames(0), contextObject(0),
+ isPragmaLibraryContext(false), publicContext(0), activeVMEData(0), propertyNames(0), contextObject(0),
imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0),
v4bindings(0), v8bindings(0)
@@ -520,7 +520,7 @@ QDeclarativeContextData::QDeclarativeContextData()
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
- isPragmaLibraryContext(false), publicContext(ctxt), activeVME(0), propertyNames(0),
+ isPragmaLibraryContext(false), publicContext(ctxt), activeVMEData(0), propertyNames(0),
contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0),
contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
componentAttached(0), v4bindings(0), v8bindings(0)
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index ba4edb8e15..a6e83a0692 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -146,9 +146,8 @@ public:
quint32 dummy:28;
QDeclarativeContext *publicContext;
- // VME that is constructing this context if any
- // XXX remove if possible
- QDeclarativeVME *activeVME;
+ // VME data that is constructing this context if any
+ void *activeVMEData;
// Property name cache
QDeclarativeIntegerCache *propertyNames;
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 1f539ee082..50b5db897c 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -542,6 +542,9 @@ QDeclarativeEngine::~QDeclarativeEngine()
// ensure we clean up QObjects with JS ownership
d->v8engine()->gc();
+
+ if (d->incubationController)
+ d->incubationController->d = 0;
}
/*! \fn void QDeclarativeEngine::quit()
diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp
index 05c73da3a2..80bdfac24a 100644
--- a/src/declarative/qml/qdeclarativeincubator.cpp
+++ b/src/declarative/qml/qdeclarativeincubator.cpp
@@ -65,8 +65,8 @@ void QDeclarativeEnginePrivate::incubate(QDeclarativeIncubator &i, QDeclarativeC
QDeclarativeIncubatorPrivate *parentIncubator = 0;
QDeclarativeContextData *cctxt = forContext;
while (cctxt) {
- if (cctxt->activeVME) {
- parentIncubator = (QDeclarativeIncubatorPrivate *)cctxt->activeVME->data;
+ if (cctxt->activeVMEData) {
+ parentIncubator = (QDeclarativeIncubatorPrivate *)cctxt->activeVMEData;
break;
}
cctxt = cctxt->parent;
@@ -113,6 +113,8 @@ and it does not take ownership of it.
void QDeclarativeEngine::setIncubationController(QDeclarativeIncubationController *controller)
{
Q_D(QDeclarativeEngine);
+ if (d->incubationController)
+ d->incubationController->d = 0;
d->incubationController = controller;
if (controller) controller->d = d;
}
@@ -155,6 +157,10 @@ void QDeclarativeIncubatorPrivate::clear()
component->release();
component = 0;
}
+ if (!rootContext.isNull()) {
+ rootContext->activeVMEData = 0;
+ rootContext = 0;
+ }
if (nextWaitingFor.isInList()) {
Q_ASSERT(waitingOnMe);
@@ -250,6 +256,8 @@ void QDeclarativeIncubationController::incubatingObjectCountChanged(int incubati
void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i)
{
+ if (!component)
+ return;
typedef QDeclarativeIncubatorPrivate IP;
QRecursionWatcher<IP, &IP::recursion> watcher(this);
@@ -311,7 +319,9 @@ void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i)
if (watcher.hasRecursed())
return;
- if (vme.complete(i)) {
+ QDeclarativeContextData *ctxt = vme.complete(i);
+ if (ctxt) {
+ rootContext = ctxt;
progress = QDeclarativeIncubatorPrivate::Completed;
goto finishIncubate;
}
@@ -570,7 +580,6 @@ void QDeclarativeIncubator::forceCompletion()
if (Loading == status())
d->incubate(i);
}
-
}
/*!
diff --git a/src/declarative/qml/qdeclarativeincubator_p.h b/src/declarative/qml/qdeclarativeincubator_p.h
index eaa4ce5ecb..ebabbae1d2 100644
--- a/src/declarative/qml/qdeclarativeincubator_p.h
+++ b/src/declarative/qml/qdeclarativeincubator_p.h
@@ -46,6 +46,7 @@
#include <private/qdeclarativevme_p.h>
#include <private/qrecursionwatcher_p.h>
#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecontext_p.h>
//
// W A R N I N G
@@ -83,6 +84,7 @@ public:
Progress progress;
QObject *result;
+ QDeclarativeGuardedContextData rootContext;
QDeclarativeCompiledData *component;
QDeclarativeVME vme;
QDeclarativeVMEGuard vmeGuard;
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index b7abef4aef..ad8d80c51a 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -310,7 +310,7 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
}
if (states.count() == 1) {
rootContext = CTXT;
- rootContext->activeVME = this;
+ rootContext->activeVMEData = data;
}
if (states.count() == 1 && !creationContext.isNull()) {
// A component that is logically created within another component instance shares the
@@ -1207,7 +1207,7 @@ void QDeclarativeVME::reset()
delete objects.at(0);
if (!rootContext.isNull())
- rootContext->activeVME = 0;
+ rootContext->activeVMEData = 0;
// Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers
blank(parserStatus);
@@ -1342,7 +1342,7 @@ void **QDeclarativeVME::instructionJumpTable()
}
#endif
-bool QDeclarativeVME::complete(const Interrupt &interrupt)
+QDeclarativeContextData *QDeclarativeVME::complete(const Interrupt &interrupt)
{
Q_ASSERT(engine ||
(bindValues.isEmpty() &&
@@ -1352,7 +1352,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
finalizeCallbacks.isEmpty()));
if (!engine)
- return true;
+ return 0;
ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine));
QRecursionWatcher<QDeclarativeVME, &QDeclarativeVME::recursion> watcher(this);
@@ -1367,7 +1367,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return false;
+ return 0;
}
bindValues.deallocate();
@@ -1380,7 +1380,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return false;
+ return 0;
}
parserStatus.deallocate();
@@ -1394,12 +1394,9 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
emit a->completed();
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return false;
+ return 0;
}
- if (!rootContext.isNull())
- rootContext->activeVME = 0;
-
for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
QDeclarativeEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii);
QObject *obj = callback.first;
@@ -1408,13 +1405,17 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
}
if (watcher.hasRecursed())
- return false;
+ return 0;
}
finalizeCallbacks.clear();
+ QDeclarativeContextData *rv = rootContext;
+
reset();
- return true;
+ if (rv) rv->activeVMEData = data;
+
+ return rv;
}
void QDeclarativeVME::blank(QFiniteStack<QDeclarativeAbstractBinding *> &bs)
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index b74bc547bf..4edceb283a 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -125,7 +125,7 @@ public:
void reset();
QObject *execute(QList<QDeclarativeError> *errors, const Interrupt & = Interrupt());
- bool complete(const Interrupt & = Interrupt());
+ QDeclarativeContextData *complete(const Interrupt & = Interrupt());
private:
friend class QDeclarativeVMEGuard;
diff --git a/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml b/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml
new file mode 100644
index 0000000000..e79fed356a
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+SelfRegistering {
+ property variant a: CompletionCallback {}
+}
diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp
index 99d2cb1005..6d6fb38daf 100644
--- a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp
+++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp
@@ -101,9 +101,37 @@ void CallbackRegisteringType::registerCallback(callback c, void *d)
m_data = d;
}
+CompletionCallbackType::callback CompletionCallbackType::m_callback = 0;
+void *CompletionCallbackType::m_data = 0;
+CompletionCallbackType::CompletionCallbackType()
+{
+}
+
+void CompletionCallbackType::classBegin()
+{
+}
+
+void CompletionCallbackType::componentComplete()
+{
+ if (m_callback) m_callback(this, m_data);
+}
+
+void CompletionCallbackType::clearCallback()
+{
+ m_callback = 0;
+ m_data = 0;
+}
+
+void CompletionCallbackType::registerCallback(callback c, void *d)
+{
+ m_callback = c;
+ m_data = d;
+}
+
void registerTypes()
{
qmlRegisterType<SelfRegisteringType>("Qt.test", 1,0, "SelfRegistering");
qmlRegisterType<CompletionRegisteringType>("Qt.test", 1,0, "CompletionRegistering");
qmlRegisterType<CallbackRegisteringType>("Qt.test", 1,0, "CallbackRegistering");
+ qmlRegisterType<CompletionCallbackType>("Qt.test", 1,0, "CompletionCallback");
}
diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.h b/tests/auto/declarative/qdeclarativeincubator/testtypes.h
index 6e732548b2..8d9968de3c 100644
--- a/tests/auto/declarative/qdeclarativeincubator/testtypes.h
+++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.h
@@ -100,6 +100,24 @@ private:
static CompletionRegisteringType *m_me;
};
+class CompletionCallbackType : public QObject, public QDeclarativeParserStatus
+{
+Q_OBJECT
+public:
+ CompletionCallbackType();
+
+ virtual void classBegin();
+ virtual void componentComplete();
+
+ typedef void (*callback)(CompletionCallbackType *, void *);
+ static void clearCallback();
+ static void registerCallback(callback, void *);
+
+private:
+ static callback m_callback;
+ static void *m_data;
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp
index 684cd35613..54ca622753 100644
--- a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp
+++ b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp
@@ -83,6 +83,7 @@ private slots:
void asynchronousIfNested();
void nestedComponent();
void chainedAsynchronousIfNested();
+ void chainedAsynchronousIfNestedOnCompleted();
void selfDelete();
private:
@@ -773,6 +774,134 @@ void tst_qdeclarativeincubator::chainedAsynchronousIfNested()
QVERIFY(incubator2.isReady());
}
+// Checks that new AsynchronousIfNested incubators can be correctly chained if started in
+// componentCompleted().
+void tst_qdeclarativeincubator::chainedAsynchronousIfNestedOnCompleted()
+{
+ SelfRegisteringType::clearMe();
+
+ QDeclarativeComponent component(&engine, TEST_FILE("chainInCompletion.qml"));
+ QVERIFY(component.isReady());
+
+ QDeclarativeComponent c1(&engine, TEST_FILE("chainedAsynchronousIfNested.qml"));
+ QVERIFY(c1.isReady());
+
+ 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;
+ };
+
+ struct CallbackData {
+ CallbackData(QDeclarativeComponent *c, MyIncubator *i, QDeclarativeContext *ct)
+ : component(c), incubator(i), ctxt(ct) {}
+ QDeclarativeComponent *component;
+ MyIncubator *incubator;
+ QDeclarativeContext *ctxt;
+ static void callback(CompletionCallbackType *o, void *data) {
+ CallbackData *d = (CallbackData *)data;
+ d->component->create(*d->incubator, 0, d->ctxt);
+ }
+ };
+
+ 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());
+
+ 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());
+
+ while (incubator3.isLoading()) {
+ QVERIFY(incubator.isLoading());
+ QVERIFY(incubator1.isReady());
+ QVERIFY(incubator2.isReady());
+ QVERIFY(incubator3.isLoading());
+
+ bool b = false;
+ controller.incubateWhile(&b);
+ }
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ QVERIFY(incubator.isReady());
+ QVERIFY(incubator1.isReady());
+ QVERIFY(incubator2.isReady());
+ QVERIFY(incubator3.isReady());
+}
+
void tst_qdeclarativeincubator::selfDelete()
{
struct MyIncubator : public QDeclarativeIncubator {