From 6080375fed90c09bfabb96a0319817f14f693b05 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 22 Aug 2011 15:51:28 +1000 Subject: [PATCH] Allow conversion of QObject Module API to QVariant This commit adds a conversion codepath for QV8TypeResource to QVariant where the resource contains a QObject module API. This allows such a module API to be used as the "target" in a Connections element. Task-number: QTBUG-20937 Change-Id: I9214b531968f2e6981a86e643859a97297c6a02a Reviewed-on: http://codereview.qt.nokia.com/3286 Reviewed-by: Chris Adams Reviewed-by: Qt Sanity Bot --- src/declarative/qml/v8/qv8engine.cpp | 3 +- src/declarative/qml/v8/qv8typewrapper.cpp | 28 ++++++++++ src/declarative/qml/v8/qv8typewrapper_p.h | 1 + .../data/moduleapi-target.qml | 22 ++++++++ .../tst_qdeclarativeconnection.cpp | 64 ++++++++++++++++++++++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests/auto/declarative/qdeclarativeconnection/data/moduleapi-target.qml diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index 8eaf902..5b74f48 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -208,7 +208,6 @@ QVariant QV8Engine::toVariant(v8::Handle value, int typeHint) if (r) { switch (r->resourceType()) { case QV8ObjectResource::ContextType: - case QV8ObjectResource::TypeType: case QV8ObjectResource::XMLHttpRequestType: case QV8ObjectResource::DOMNodeType: case QV8ObjectResource::SQLDatabaseType: @@ -216,6 +215,8 @@ QVariant QV8Engine::toVariant(v8::Handle value, int typeHint) case QV8ObjectResource::Context2DType: case QV8ObjectResource::ParticleDataType: return QVariant(); + case QV8ObjectResource::TypeType: + return m_typeWrapper.toVariant(r); case QV8ObjectResource::QObjectType: return qVariantFromValue(m_qobjectWrapper.toQObject(r)); case QV8ObjectResource::ListType: diff --git a/src/declarative/qml/v8/qv8typewrapper.cpp b/src/declarative/qml/v8/qv8typewrapper.cpp index f46aaab..c89d5ab 100644 --- a/src/declarative/qml/v8/qv8typewrapper.cpp +++ b/src/declarative/qml/v8/qv8typewrapper.cpp @@ -128,6 +128,34 @@ v8::Local QV8TypeWrapper::newObject(QObject *o, QDeclarativeTypeName return rv; } +QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r) +{ + Q_ASSERT(r->resourceType() == QV8ObjectResource::TypeType); + QV8TypeResource *resource = static_cast(r); + QV8Engine *v8engine = resource->engine; + + if (resource->typeNamespace) { + if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) { + if (moduleApi->scriptCallback) { + moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine()); + moduleApi->scriptCallback = 0; + moduleApi->qobjectCallback = 0; + } else if (moduleApi->qobjectCallback) { + moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine()); + moduleApi->scriptCallback = 0; + moduleApi->qobjectCallback = 0; + } + + if (moduleApi->qobjectApi) { + return QVariant::fromValue(moduleApi->qobjectApi); + } + } + } + + // only QObject Module API can be converted to a variant. + return QVariant(); +} + v8::Handle QV8TypeWrapper::Getter(v8::Local property, const v8::AccessorInfo &info) { diff --git a/src/declarative/qml/v8/qv8typewrapper_p.h b/src/declarative/qml/v8/qv8typewrapper_p.h index 2e79946..f9309f8 100644 --- a/src/declarative/qml/v8/qv8typewrapper_p.h +++ b/src/declarative/qml/v8/qv8typewrapper_p.h @@ -75,6 +75,7 @@ public: v8::Local newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums); v8::Local newObject(QObject *, QDeclarativeTypeNameCache *, const void *, TypeNameMode = IncludeEnums); + QVariant toVariant(QV8ObjectResource *); private: static v8::Handle Getter(v8::Local property, diff --git a/tests/auto/declarative/qdeclarativeconnection/data/moduleapi-target.qml b/tests/auto/declarative/qdeclarativeconnection/data/moduleapi-target.qml new file mode 100644 index 0000000..8803f24 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeconnection/data/moduleapi-target.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 +import MyTestModuleApi 1.0 as MyTestModuleApi + +Item { + id: rootObject + objectName: "rootObject" + property int newIntPropValue: 12 + + property int moduleIntPropChangedCount: 0 + property int moduleOtherSignalCount: 0 + + function setModuleIntProp() { + MyTestModuleApi.intProp = newIntPropValue; + newIntPropValue = newIntPropValue + 1; + } + + Connections { + target: MyTestModuleApi + onIntPropChanged: moduleIntPropChangedCount = moduleIntPropChangedCount + 1; + onOtherSignal: moduleOtherSignalCount = moduleOtherSignalCount + 1; + } +} diff --git a/tests/auto/declarative/qdeclarativeconnection/tst_qdeclarativeconnection.cpp b/tests/auto/declarative/qdeclarativeconnection/tst_qdeclarativeconnection.cpp index 37cce5c..c726fde 100644 --- a/tests/auto/declarative/qdeclarativeconnection/tst_qdeclarativeconnection.cpp +++ b/tests/auto/declarative/qdeclarativeconnection/tst_qdeclarativeconnection.cpp @@ -68,6 +68,7 @@ private slots: void unknownSignals(); void errors_data(); void errors(); + void moduleApiTarget(); private: QDeclarativeEngine engine; @@ -229,6 +230,69 @@ void tst_qdeclarativeconnection::errors() QCOMPARE(errors.at(0).description(), error); } + +class MyTestModuleApi : public QObject +{ +Q_OBJECT +Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) + +public: + MyTestModuleApi(QObject *parent = 0) : QObject(parent), m_intProp(0), m_changeCount(0) {} + ~MyTestModuleApi() {} + + Q_INVOKABLE int otherMethod(int val) { return val + 4; } + + int intProp() const { return m_intProp; } + void setIntProp(int val) + { + if (++m_changeCount % 3 == 0) emit otherSignal(); + m_intProp = val; emit intPropChanged(); + } + +signals: + void intPropChanged(); + void otherSignal(); + +private: + int m_intProp; + int m_changeCount; +}; + +static QObject *module_api_factory(QDeclarativeEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + MyTestModuleApi *api = new MyTestModuleApi(); + return api; +} + +// QTBUG-20937 +void tst_qdeclarativeconnection::moduleApiTarget() +{ + qmlRegisterModuleApi("MyTestModuleApi", 1, 0, module_api_factory); + QDeclarativeComponent component(&engine, QUrl(SRCDIR "/data/moduleapi-target.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("moduleIntPropChangedCount").toInt(), 0); + QCOMPARE(object->property("moduleOtherSignalCount").toInt(), 0); + + QMetaObject::invokeMethod(object, "setModuleIntProp"); + QCOMPARE(object->property("moduleIntPropChangedCount").toInt(), 1); + QCOMPARE(object->property("moduleOtherSignalCount").toInt(), 0); + + QMetaObject::invokeMethod(object, "setModuleIntProp"); + QCOMPARE(object->property("moduleIntPropChangedCount").toInt(), 2); + QCOMPARE(object->property("moduleOtherSignalCount").toInt(), 0); + + // the module API emits otherSignal every 3 times the int property changes. + QMetaObject::invokeMethod(object, "setModuleIntProp"); + QCOMPARE(object->property("moduleIntPropChangedCount").toInt(), 3); + QCOMPARE(object->property("moduleOtherSignalCount").toInt(), 1); + + delete object; +} + QTEST_MAIN(tst_qdeclarativeconnection) #include "tst_qdeclarativeconnection.moc" -- 2.7.4