diff options
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 36 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 27 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml | 19 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/deferredProperties.qml | 19 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 15 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 48 |
11 files changed, 162 insertions, 31 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index ce35846c88..7f1121c1e1 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -878,19 +878,33 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) } void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv, - QObject *object, ConstructionState *state) + QObject *object, DeferredState *deferredState) { - enginePriv->inProgressCreations++; - state->errors.clear(); - state->completePending = true; - QQmlData *ddata = QQmlData::get(object); - Q_ASSERT(ddata->deferredData); - QQmlData::DeferredData *deferredData = ddata->deferredData; - QQmlContextData *creationContext = 0; - state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext)); - if (!state->creator->populateDeferredProperties(object)) - state->errors << state->creator->errors; + Q_ASSERT(!ddata->deferredData.isEmpty()); + + deferredState->constructionStates.reserve(ddata->deferredData.size()); + + for (QQmlData::DeferredData *deferredData : qAsConst(ddata->deferredData)) { + enginePriv->inProgressCreations++; + + ConstructionState *state = new ConstructionState; + state->completePending = true; + + QQmlContextData *creationContext = nullptr; + state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext)); + + if (!state->creator->populateDeferredProperties(object, deferredData)) + state->errors << state->creator->errors; + + deferredState->constructionStates += state; + } +} + +void QQmlComponentPrivate::completeDeferred(QQmlEnginePrivate *enginePriv, QQmlComponentPrivate::DeferredState *deferredState) +{ + for (ConstructionState *state : qAsConst(deferredState->constructionStates)) + complete(enginePriv, state); } void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state) diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index d01a987acc..2a57f7b247 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -114,8 +114,17 @@ public: }; ConstructionState state; - static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object, - ConstructionState *state); + struct DeferredState { + ~DeferredState() { + qDeleteAll(constructionStates); + constructionStates.clear(); + } + QVector<ConstructionState *> constructionStates; + }; + + static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object, DeferredState* deferredState); + static void completeDeferred(QQmlEnginePrivate *enginePriv, DeferredState *deferredState); + static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state); QQmlEngine *engine; diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 75ea720358..d692feb975 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -57,6 +57,7 @@ #include <private/qv4value_p.h> #include <private/qv4persistent_p.h> #include <qjsengine.h> +#include <qvector.h> QT_BEGIN_NAMESPACE @@ -219,7 +220,9 @@ public: QQmlContextData *context;//Could be either context or outerContext }; QV4::CompiledData::CompilationUnit *compilationUnit; - DeferredData *deferredData; + QVector<DeferredData *> deferredData; + + void releaseDeferredData(); QV4::WeakValue jsWrapper; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 13b17e6946..5a52224208 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -739,7 +739,7 @@ QQmlData::QQmlData() hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0), bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), deferredData(0), + lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), propertyCache(0), guards(0), extendedData(0) { init(); @@ -1469,18 +1469,16 @@ void qmlExecuteDeferred(QObject *object) { QQmlData *data = QQmlData::get(object); - if (data && data->deferredData && !data->wasDeleted(object)) { + if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine); - QQmlComponentPrivate::ConstructionState state; + QQmlComponentPrivate::DeferredState state; QQmlComponentPrivate::beginDeferred(ep, object, &state); // Release the reference for the deferral action (we still have one from construction) - data->deferredData->compilationUnit->release(); - delete data->deferredData; - data->deferredData = 0; + data->releaseDeferredData(); - QQmlComponentPrivate::complete(ep, &state); + QQmlComponentPrivate::completeDeferred(ep, &state); } } @@ -1638,6 +1636,15 @@ void QQmlData::NotifyList::layout() todo = 0; } +void QQmlData::releaseDeferredData() +{ + for (DeferredData *deferData : qAsConst(deferredData)) { + deferData->compilationUnit->release(); + delete deferData; + } + deferredData.clear(); +} + void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint) { if (!notifyList) { @@ -1712,11 +1719,7 @@ void QQmlData::destroyed(QObject *object) compilationUnit = 0; } - if (deferredData) { - deferredData->compilationUnit->release(); - delete deferredData; - deferredData = 0; - } + releaseDeferredData(); QQmlBoundSignal *signalHandler = signalHandlers; while (signalHandler) { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 07a90d4d63..b2f1421bcb 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -233,10 +233,10 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI return instance; } -bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) +bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData) { QQmlData *declarativeData = QQmlData::get(instance); - context = declarativeData->deferredData->context; + context = deferredData->context; sharedState->rootContext = context; QObject *bindingTarget = instance; @@ -260,7 +260,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_propertyCache, cache); qSwap(_qobject, instance); - int objectIndex = declarativeData->deferredData->deferredIdx; + int objectIndex = deferredData->deferredIdx; qSwap(_compiledObjectIndex, objectIndex); const QV4::CompiledData::Object *obj = qmlUnit->objectAt(_compiledObjectIndex); @@ -1347,7 +1347,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * deferData->compilationUnit = compilationUnit; deferData->compilationUnit->addref(); deferData->context = context; - _ddata->deferredData = deferData; + _ddata->deferredData.append(deferData); } if (_compiledObject->nFunctions > 0) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index a62825e19e..0c2d427c58 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -89,7 +89,7 @@ public: ~QQmlObjectCreator(); QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0); - bool populateDeferredProperties(QObject *instance); + bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData); QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); void cancel(QObject *object); void clear(); diff --git a/tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml b/tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml new file mode 100644 index 0000000000..67e92e5a05 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/MyDeferredProperties.qml @@ -0,0 +1,19 @@ +import QtQml 2.0 +import Test 1.0 +DeferredProperties { + groupProperty: QtObject { + objectName: "innerobj" + property bool wasCompleted: false + Component.onCompleted: wasCompleted = true + } + QtObject { + objectName: "innerlist1" + property bool wasCompleted: false + Component.onCompleted: wasCompleted = true + } + QtObject { + objectName: "innerlist2" + property bool wasCompleted: false + Component.onCompleted: wasCompleted = true + } +} diff --git a/tests/auto/qml/qqmllanguage/data/deferredProperties.qml b/tests/auto/qml/qqmllanguage/data/deferredProperties.qml new file mode 100644 index 0000000000..07b146967c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/deferredProperties.qml @@ -0,0 +1,19 @@ +import QtQml 2.0 +import Test 1.0 +MyDeferredProperties { + groupProperty: QtObject { + objectName: "outerobj" + property bool wasCompleted: false + Component.onCompleted: wasCompleted = true + } + QtObject { + objectName: "outerlist1" + property bool wasCompleted: false + Component.onCompleted: wasCompleted = true + } + QtObject { + objectName: "outerlist2" + property bool wasCompleted: false + Component.onCompleted: wasCompleted = true + } +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 72e06d26aa..d2240d25a9 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -105,6 +105,7 @@ void registerTypes() qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass"); qmlRegisterType<LazyDeferredSubObject>("Test", 1, 0, "LazyDeferredSubObject"); + qmlRegisterType<DeferredProperties>("Test", 1, 0, "DeferredProperties"); } QVariant myCustomVariantTypeConverter(const QString &data) diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index b0e677feb8..d9ddff20a7 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1351,6 +1351,21 @@ private: QObject *obj; }; +class DeferredProperties : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *groupProperty MEMBER m_group) + Q_PROPERTY(QQmlListProperty<QObject> listProperty READ listProperty) + Q_CLASSINFO("DeferredPropertyNames", "groupProperty,listProperty") + Q_CLASSINFO("DefaultProperty", "listProperty") +public: + QQmlListProperty<QObject> listProperty() { return QQmlListProperty<QObject>(this, m_list); } + +private: + QObject *m_group = 0; + QObjectList m_list; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 30c34426af..f4d31d9e60 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -248,6 +248,7 @@ private slots: void rootObjectInCreationNotForSubObjects(); void lazyDeferredSubObject(); + void deferredProperties(); void noChildEvents(); @@ -4258,6 +4259,53 @@ void tst_qqmllanguage::lazyDeferredSubObject() QCOMPARE(subObject->objectName(), QStringLiteral("custom")); } +// QTBUG-63200 +void tst_qqmllanguage::deferredProperties() +{ + QQmlComponent component(&engine, testFile("deferredProperties.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QObject *innerObj = object->findChild<QObject *>(QStringLiteral("innerobj")); + QVERIFY(!innerObj); + + QObject *outerObj = object->findChild<QObject *>(QStringLiteral("outerobj")); + QVERIFY(!outerObj); + + QObject *groupProperty = object->property("groupProperty").value<QObject *>(); + QVERIFY(!groupProperty); + + QQmlListProperty<QObject> listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>(); + QCOMPARE(listProperty.count(&listProperty), 0); + + qmlExecuteDeferred(object.data()); + + innerObj = object->findChild<QObject *>(QStringLiteral("innerobj")); // MyDeferredListProperty.qml + QVERIFY(innerObj); + QCOMPARE(innerObj->property("wasCompleted"), QVariant(true)); + + outerObj = object->findChild<QObject *>(QStringLiteral("outerobj")); // deferredListProperty.qml + QVERIFY(outerObj); + QCOMPARE(outerObj->property("wasCompleted"), QVariant(true)); + + groupProperty = object->property("groupProperty").value<QObject *>(); + QCOMPARE(groupProperty, outerObj); + + listProperty = object->property("listProperty").value<QQmlListProperty<QObject>>(); + QCOMPARE(listProperty.count(&listProperty), 4); + + QCOMPARE(listProperty.at(&listProperty, 0)->objectName(), QStringLiteral("innerlist1")); // MyDeferredListProperty.qml + QCOMPARE(listProperty.at(&listProperty, 0)->property("wasCompleted"), QVariant(true)); + QCOMPARE(listProperty.at(&listProperty, 1)->objectName(), QStringLiteral("innerlist2")); // MyDeferredListProperty.qml + QCOMPARE(listProperty.at(&listProperty, 1)->property("wasCompleted"), QVariant(true)); + + QCOMPARE(listProperty.at(&listProperty, 2)->objectName(), QStringLiteral("outerlist1")); // deferredListProperty.qml + QCOMPARE(listProperty.at(&listProperty, 2)->property("wasCompleted"), QVariant(true)); + QCOMPARE(listProperty.at(&listProperty, 3)->objectName(), QStringLiteral("outerlist2")); // deferredListProperty.qml + QCOMPARE(listProperty.at(&listProperty, 3)->property("wasCompleted"), QVariant(true)); +} + void tst_qqmllanguage::noChildEvents() { QQmlComponent component(&engine); |