diff options
-rw-r--r-- | src/qml/jsruntime/qv4context_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 23 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquickloader.cpp | 4 | ||||
-rw-r--r-- | src/quick/items/qquickloader_p_p.h | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/data/callingQmlContext.qml | 13 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/data/callingQmlContextComponent.qml | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 59 |
9 files changed, 99 insertions, 10 deletions
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 6c360e7dda..c0c89a5c3d 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -241,7 +241,7 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; -struct QmlContext : public ExecutionContext +struct Q_QML_EXPORT QmlContext : public ExecutionContext { V4_MANAGED(QmlContext, ExecutionContext) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 49b6dce697..fefc5b6308 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -693,7 +693,7 @@ Heap::QmlContext *ExecutionEngine::qmlContext() const if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) ctx = parentContext(currentContext)->d(); - if (!ctx->outer) + if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) return 0; while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 9b52a951af..24abf52e38 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1071,6 +1071,7 @@ struct QmlIncubatorObject : Object { QPointer<QObject> parent; QV4::Value valuemap; QV4::Value statusChanged; + Pointer<Heap::QmlContext> qmlContext; }; } @@ -1185,7 +1186,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) */ -static void setInitialProperties(QV4::ExecutionEngine *engine, const QV4::Value &o, const QV4::Value &v) +static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v) { QV4::Scope scope(engine); QV4::ScopedObject object(scope); @@ -1196,6 +1197,9 @@ static void setInitialProperties(QV4::ExecutionEngine *engine, const QV4::Value if (engine->hasException) return; + QV4::ExecutionContextSaver saver(scope); + engine->pushContext(qmlContext); + while (1) { name = it.nextPropertyNameAsString(val); if (!name) @@ -1269,8 +1273,10 @@ void QQmlComponent::createObject(QQmlV4Function *args) QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4, rv)); Q_ASSERT(object->isObject()); - if (!valuemap->isUndefined()) - setInitialProperties(v4, object, valuemap); + if (!valuemap->isUndefined()) { + QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext()); + setInitialProperties(v4, qmlContext, object, valuemap); + } d->completeCreate(); @@ -1387,6 +1393,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) if (!valuemap->isUndefined()) r->d()->valuemap = valuemap; + r->d()->qmlContext = v4->qmlContext(); r->d()->parent = parent; QQmlIncubator *incubator = r->d()->incubator.data(); @@ -1400,7 +1407,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) } // XXX used by QSGLoader -void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &valuemap, QObject *toCreate) +void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); QV4::ExecutionEngine *v4engine = QV8Engine::getV4(ep->v8engine()); @@ -1410,7 +1417,7 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Valu Q_ASSERT(object->as<QV4::Object>()); if (!valuemap.isUndefined()) - setInitialProperties(v4engine, object, valuemap); + setInitialProperties(v4engine, qmlContext, object, valuemap); } QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4) @@ -1487,6 +1494,7 @@ QQmlComponentExtension::~QQmlComponentExtension() QV4::Heap::QmlIncubatorObject::QmlIncubatorObject(QQmlIncubator::IncubationMode m) : valuemap(QV4::Primitive::undefinedValue()) , statusChanged(QV4::Primitive::undefinedValue()) + , qmlContext(0) { incubator.reset(new QQmlComponentIncubator(this, m)); } @@ -1499,7 +1507,8 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) QV4::ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o)); - setInitialProperties(v4, obj, d()->valuemap); + QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext); + setInitialProperties(v4, qmlCtxt, obj, d()->valuemap); } } @@ -1508,6 +1517,8 @@ void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionE QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that); o->valuemap.mark(e); o->statusChanged.mark(e); + if (o->qmlContext) + o->qmlContext->mark(e); Object::markObjects(that, e); } diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 15ec88dd52..ff6969fcdc 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -82,7 +82,7 @@ public: QObject *beginCreate(QQmlContextData *); void completeCreate(); - void initializeObjectWithInitialProperties(const QV4::Value &valuemap, QObject *toCreate); + void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate); QQmlTypeData *typeData; virtual void typeDataReady(QQmlTypeData *); diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 456eedd0be..7cac79bd46 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -577,6 +577,7 @@ void QQuickLoader::setSource(QQmlV4Function *args) d->disposeInitialPropertyValues(); d->initialPropertyValues.set(args->v4engine(), ipv); } + d->qmlCallingContext.set(scope.engine, scope.engine->qmlContext()); setSource(sourceUrl, false); // already cleared and set ipv above. } @@ -645,7 +646,8 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj) Q_ASSERT(v4); QV4::Scope scope(v4); QV4::ScopedValue ipv(scope, initialPropertyValues.value()); - d->initializeObjectWithInitialProperties(ipv, obj); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value()); + d->initializeObjectWithInitialProperties(qmlContext, ipv, obj); } void QQuickLoaderIncubator::statusChanged(Status status) diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index 9677318b58..26a74be9d9 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -102,6 +102,7 @@ public: QQmlContext *itemContext; QQuickLoaderIncubator *incubator; QV4::PersistentValue initialPropertyValues; + QV4::PersistentValue qmlCallingContext; bool updatingSize: 1; bool active : 1; bool loadingFromSource : 1; diff --git a/tests/auto/qml/qqmlcomponent/data/callingQmlContext.qml b/tests/auto/qml/qqmlcomponent/data/callingQmlContext.qml new file mode 100644 index 0000000000..8193d0f36c --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/callingQmlContext.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 +import qqmlcomponenttest 1.0 +QtObject { + property Component factory + property QtObject incubatedObject + + Component.onCompleted: { + var incubatorState = factory.incubateObject(null, { value: 42 }) + incubatorState.onStatusChanged = function(status) { + incubatedObject = incubatorState.object + } + } +} diff --git a/tests/auto/qml/qqmlcomponent/data/callingQmlContextComponent.qml b/tests/auto/qml/qqmlcomponent/data/callingQmlContextComponent.qml new file mode 100644 index 0000000000..adf491c87e --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/callingQmlContextComponent.qml @@ -0,0 +1,3 @@ +import qqmlcomponenttest 1.0 +CallingContextCheckingClass { +} diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 85579a6019..680ea720a8 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -40,6 +40,7 @@ #include <QtQuick> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickmousearea_p.h> +#include <private/qv8engine_p.h> #include <qcolor.h> #include "../../shared/util.h" #include "testhttpserver.h" @@ -116,6 +117,7 @@ private slots: void onDestructionCount(); void recursion(); void recursionContinuation(); + void callingContextForInitialProperties(); private: QQmlEngine engine; @@ -523,6 +525,63 @@ void tst_qqmlcomponent::recursionContinuation() QVERIFY(object->property("success").toBool()); } +class CallingContextCheckingClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) +public: + CallingContextCheckingClass() + : m_value(0) + {} + + int value() const { return m_value; } + void setValue(int v) { + scopeObject.clear(); + callingContextData.setContextData(0); + + m_value = v; + QJSEngine *jsEngine = qjsEngine(this); + if (!jsEngine) + return; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(jsEngine); + if (!v4) + return; + QV4::Scope scope(v4); + QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext()); + if (!qmlContext) + return; + callingContextData = qmlContext->qmlContext(); + scopeObject = qmlContext->qmlScope(); + } + + int m_value; + QQmlGuardedContextData callingContextData; + QPointer<QObject> scopeObject; +}; + +void tst_qqmlcomponent::callingContextForInitialProperties() +{ + qmlRegisterType<CallingContextCheckingClass>("qqmlcomponenttest", 1, 0, "CallingContextCheckingClass"); + + QQmlComponent testFactory(&engine, testFileUrl("callingQmlContextComponent.qml")); + + QQmlComponent component(&engine, testFileUrl("callingQmlContext.qml")); + QScopedPointer<QObject> root(component.beginCreate(engine.rootContext())); + QVERIFY(!root.isNull()); + root->setProperty("factory", QVariant::fromValue(&testFactory)); + component.completeCreate(); + QTRY_VERIFY(qvariant_cast<QObject *>(root->property("incubatedObject"))); + QObject *o = qvariant_cast<QObject *>(root->property("incubatedObject")); + CallingContextCheckingClass *checker = qobject_cast<CallingContextCheckingClass*>(o); + QVERIFY(checker); + + QVERIFY(!checker->callingContextData.isNull()); + QVERIFY(checker->callingContextData->urlString().endsWith(QStringLiteral("callingQmlContext.qml"))); + + QVERIFY(!checker->scopeObject.isNull()); + QVERIFY(checker->scopeObject->metaObject()->indexOfProperty("incubatedObject") != -1); +} + QTEST_MAIN(tst_qqmlcomponent) #include "tst_qqmlcomponent.moc" |