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)
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)
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;
// ensure we clean up QObjects with JS ownership
d->v8engine()->gc();
+
+ if (d->incubationController)
+ d->incubationController->d = 0;
}
/*! \fn void QDeclarativeEngine::quit()
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;
void QDeclarativeEngine::setIncubationController(QDeclarativeIncubationController *controller)
{
Q_D(QDeclarativeEngine);
+ if (d->incubationController)
+ d->incubationController->d = 0;
d->incubationController = controller;
if (controller) controller->d = d;
}
component->release();
component = 0;
}
+ if (!rootContext.isNull()) {
+ rootContext->activeVMEData = 0;
+ rootContext = 0;
+ }
if (nextWaitingFor.isInList()) {
Q_ASSERT(waitingOnMe);
void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i)
{
+ if (!component)
+ return;
typedef QDeclarativeIncubatorPrivate IP;
QRecursionWatcher<IP, &IP::recursion> watcher(this);
if (watcher.hasRecursed())
return;
- if (vme.complete(i)) {
+ QDeclarativeContextData *ctxt = vme.complete(i);
+ if (ctxt) {
+ rootContext = ctxt;
progress = QDeclarativeIncubatorPrivate::Completed;
goto finishIncubate;
}
if (Loading == status())
d->incubate(i);
}
-
}
/*!
#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
Progress progress;
QObject *result;
+ QDeclarativeGuardedContextData rootContext;
QDeclarativeCompiledData *component;
QDeclarativeVME vme;
QDeclarativeVMEGuard vmeGuard;
}
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
delete objects.at(0);
if (!rootContext.isNull())
- rootContext->activeVME = 0;
+ rootContext->activeVMEData = 0;
// Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers
blank(parserStatus);
}
#endif
-bool QDeclarativeVME::complete(const Interrupt &interrupt)
+QDeclarativeContextData *QDeclarativeVME::complete(const Interrupt &interrupt)
{
Q_ASSERT(engine ||
(bindValues.isEmpty() &&
finalizeCallbacks.isEmpty()));
if (!engine)
- return true;
+ return 0;
ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine));
QRecursionWatcher<QDeclarativeVME, &QDeclarativeVME::recursion> watcher(this);
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return false;
+ return 0;
}
bindValues.deallocate();
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return false;
+ return 0;
}
parserStatus.deallocate();
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;
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)
void reset();
QObject *execute(QList<QDeclarativeError> *errors, const Interrupt & = Interrupt());
- bool complete(const Interrupt & = Interrupt());
+ QDeclarativeContextData *complete(const Interrupt & = Interrupt());
private:
friend class QDeclarativeVMEGuard;
--- /dev/null
+import Qt.test 1.0
+
+SelfRegistering {
+ property variant a: CompletionCallback {}
+}
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");
}
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
void asynchronousIfNested();
void nestedComponent();
void chainedAsynchronousIfNested();
+ void chainedAsynchronousIfNestedOnCompleted();
void selfDelete();
private:
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 {