QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
enginePriv->referenceScarceResources();
- state.vme.init(context, cc, start);
+ state.vme.init(context, cc, start, creationContext);
QObject *rv = state.vme.execute(&state.errors);
enginePriv->dereferenceScarceResources();
- if (rv && creationContext && start != -1) {
- // A component that is logically created within another component instance shares the same
- // instances of script imports. For example:
- //
- // import QtQuick 1.0
- // import "test.js" as Test
- // ListView {
- // model: Test.getModel()
- // delegate: Component {
- // Text { text: Test.getValue(index); }
- // }
- // }
- //
- // Has the same "Test" instance. To implement this, we simply copy the v8 handles into
- // the inner context. We have to create a fresh persistent handle for each to prevent
- // double dispose. It is possible we could do this more efficiently using some form of
- // referencing instead.
- QDeclarativeContextData *objectContext = QDeclarativeData::get(rv, false)->outerContext;
- objectContext->importedScripts = creationContext->importedScripts;
- for (int ii = 0; ii < objectContext->importedScripts.count(); ++ii)
- objectContext->importedScripts[ii] = qPersistentNew<v8::Object>(objectContext->importedScripts[ii]);
- }
-
if (rv) {
QDeclarativeData *ddata = QDeclarativeData::get(rv);
Q_ASSERT(ddata);
QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(d->engine);
p->component = d->cc; p->component->addref();
- p->vme.init(contextData, d->cc, d->start);
+ p->vme.init(contextData, d->cc, d->start, d->creationContext);
enginePriv->incubate(i, forContextData);
}
inProgressCreations++;
+ Q_ASSERT(i.isLoading());
+ i.statusChanged(i.status());
+
if (mode == QDeclarativeIncubator::Synchronous) {
QDeclarativeVME::Interrupt i;
p->incubate(i);
bool guardOk = vmeGuard.isOK();
vmeGuard.clear();
+ QDeclarativeIncubator::Status oldStatus = q->status();
+
if (!guardOk) {
QDeclarativeError error;
error.setUrl(component->url);
else
progress = QDeclarativeIncubatorPrivate::Completed;
- q->statusChanged(q->status());
+ QDeclarativeIncubator::Status newStatus = q->status();
+
+ if (oldStatus != newStatus) {
+ q->statusChanged(newStatus);
+ oldStatus = newStatus;
+ }
if (watcher.hasRecursed())
return;
enginePriv->inProgressCreations--;
- q->statusChanged(q->status());
+ QDeclarativeIncubator::Status newStatus = q->status();
+ if (newStatus != oldStatus) {
+ q->statusChanged(newStatus);
+ oldStatus = newStatus;
+ }
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
goto exceptionExit; \
}
-void QDeclarativeVME::init(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, int start)
+void QDeclarativeVME::init(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, int start,
+ QDeclarativeContextData *creation)
{
Q_ASSERT(ctxt);
Q_ASSERT(comp);
- if (start == -1) start = 0;
+ if (start == -1) {
+ start = 0;
+ } else {
+ creationContext = creation;
+ }
State initState;
initState.context = ctxt;
rootContext = CTXT;
rootContext->activeVME = this;
}
+ if (states.count() == 1 && !creationContext.isNull()) {
+ // A component that is logically created within another component instance shares the
+ // same instances of script imports. For example:
+ //
+ // import QtQuick 1.0
+ // import "test.js" as Test
+ // ListView {
+ // model: Test.getModel()
+ // delegate: Component {
+ // Text { text: Test.getValue(index); }
+ // }
+ // }
+ //
+ // Has the same "Test" instance. To implement this, we simply copy the v8 handles into
+ // the inner context. We have to create a fresh persistent handle for each to prevent
+ // double dispose. It is possible we could do this more efficiently using some form of
+ // referencing instead.
+ CTXT->importedScripts = creationContext->importedScripts;
+ for (int ii = 0; ii < CTXT->importedScripts.count(); ++ii)
+ CTXT->importedScripts[ii] = qPersistentNew<v8::Object>(CTXT->importedScripts[ii]);
+ }
QML_END_INSTR(Init)
QML_BEGIN_INSTR(DeferInit)
finalizeCallbacks.clear();
states.clear();
rootContext = 0;
+ creationContext = 0;
}
// Must be called with a handle scope and context
void setInitialState();
void clearDuringCompletion();
void recursiveClear();
+ void statusChanged();
+ void asynchronousIfNested();
+ void nestedComponent();
private:
QDeclarativeIncubationController controller;
delete obj;
QVERIFY(obj.isNull());
}
-
- // XXX Clear in error state
}
void tst_qdeclarativeincubator::noIncubationController()
switcher.start();
}
+void tst_qdeclarativeincubator::statusChanged()
+{
+ class MyIncubator : public QDeclarativeIncubator
+ {
+ public:
+ MyIncubator(QDeclarativeIncubator::IncubationMode mode = QDeclarativeIncubator::Asynchronous)
+ : QDeclarativeIncubator(mode) {}
+
+ QList<int> statuses;
+ protected:
+ virtual void statusChanged(Status s) { statuses << s; }
+ virtual void setInitialState(QObject *) { statuses << -1; }
+ };
+
+ QDeclarativeComponent component(&engine, TEST_FILE("statusChanged.qml"));
+ QVERIFY(component.isReady());
+
+ {
+ MyIncubator incubator(QDeclarativeIncubator::Synchronous);
+ component.create(incubator);
+ QVERIFY(incubator.isReady());
+ QCOMPARE(incubator.statuses.count(), 3);
+ QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
+ QCOMPARE(incubator.statuses.at(1), -1);
+ QCOMPARE(incubator.statuses.at(2), int(QDeclarativeIncubator::Ready));
+ delete incubator.object();
+ }
+
+ {
+ MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
+ component.create(incubator);
+ QVERIFY(incubator.isLoading());
+ QCOMPARE(incubator.statuses.count(), 1);
+ QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ QCOMPARE(incubator.statuses.count(), 3);
+ QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
+ QCOMPARE(incubator.statuses.at(1), -1);
+ QCOMPARE(incubator.statuses.at(2), int(QDeclarativeIncubator::Ready));
+ delete incubator.object();
+ }
+}
+
+void tst_qdeclarativeincubator::asynchronousIfNested()
+{
+ // Asynchronous if nested within a finalized context behaves synchronously
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("asynchronousIfNested.1.qml"));
+ QVERIFY(component.isReady());
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("a").toInt(), 10);
+
+ QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
+ component.create(incubator, 0, qmlContext(object));
+
+ QVERIFY(incubator.isReady());
+ QVERIFY(incubator.object());
+ QCOMPARE(incubator.object()->property("a").toInt(), 10);
+ delete incubator.object();
+ delete object;
+ }
+
+ // Asynchronous if nested within an executing context behaves asynchronously, but prevents
+ // the parent from finishing
+ {
+ SelfRegisteringType::clearMe();
+
+ QDeclarativeComponent component(&engine, TEST_FILE("asynchronousIfNested.2.qml"));
+ QVERIFY(component.isReady());
+
+ QDeclarativeIncubator incubator;
+ 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());
+
+ QDeclarativeIncubator nested(QDeclarativeIncubator::AsynchronousIfNested);
+ component.create(nested, 0, qmlContext(SelfRegisteringType::me()));
+ QVERIFY(nested.isLoading());
+
+ while (nested.isLoading()) {
+ QVERIFY(incubator.isLoading());
+ bool b = false;
+ controller.incubateWhile(&b);
+ }
+
+ QVERIFY(nested.isReady());
+ QVERIFY(incubator.isLoading());
+
+ {
+ bool b = true;
+ controller.incubateWhile(&b);
+ }
+
+ QVERIFY(nested.isReady());
+ QVERIFY(incubator.isReady());
+
+ delete nested.object();
+ delete incubator.object();
+ }
+}
+
+void tst_qdeclarativeincubator::nestedComponent()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("nestedComponent.qml"));
+ QVERIFY(component.isReady());
+
+ QObject *object = component.create();
+
+ QDeclarativeComponent *nested = object->property("c").value<QDeclarativeComponent*>();
+ QVERIFY(nested);
+ QVERIFY(nested->isReady());
+
+ // Test without incubator
+ {
+ QObject *nestedObject = nested->create();
+ QCOMPARE(nestedObject->property("value").toInt(), 19988);
+ delete nestedObject;
+ }
+
+ // Test with incubator
+ {
+ QDeclarativeIncubator incubator(QDeclarativeIncubator::Synchronous);
+ nested->create(incubator);
+ QVERIFY(incubator.isReady());
+ QVERIFY(incubator.object());
+ QCOMPARE(incubator.object()->property("value").toInt(), 19988);
+ delete incubator.object();
+ }
+
+ delete object;
+}
+
QTEST_MAIN(tst_qdeclarativeincubator)
#include "tst_qdeclarativeincubator.moc"