diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | dependencies.yaml | 10 | ||||
-rw-r--r-- | examples/webchannel/shared/qwebchannel.js | 14 | ||||
-rw-r--r-- | src/imports/webchannel/plugin.cpp | 5 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher.cpp | 43 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher_p.h | 3 | ||||
-rw-r--r-- | src/webchannel/variantargument_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/testobject.cpp | 13 | ||||
-rw-r--r-- | tests/auto/qml/testobject.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannel.qml | 64 |
10 files changed, 149 insertions, 11 deletions
diff --git a/.qmake.conf b/.qmake.conf index 748ca99..05001fb 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.15.0 +MODULE_VERSION = 6.0.0 diff --git a/dependencies.yaml b/dependencies.yaml new file mode 100644 index 0000000..b235d87 --- /dev/null +++ b/dependencies.yaml @@ -0,0 +1,10 @@ +dependencies: + ../qtbase: + ref: 8b91c6831546f884437122ce243b8a08c328a13c + required: true + ../qtdeclarative: + ref: 7b2e90258c2e4719d41c5306c3d55a604ef1520b + required: false + ../qtwebsockets: + ref: e804be843128e4afa5353a0beeab3deefe5bbde5 + required: false diff --git a/examples/webchannel/shared/qwebchannel.js b/examples/webchannel/shared/qwebchannel.js index fca45d9..37ac9eb 100644 --- a/examples/webchannel/shared/qwebchannel.js +++ b/examples/webchannel/shared/qwebchannel.js @@ -351,10 +351,6 @@ function QObject(name, data, webChannel) var argument = arguments[i]; if (typeof argument === "function") callback = argument; - else if (argument instanceof QObject && webChannel.objects[argument.__id__] !== undefined) - args.push({ - "id": argument.__id__ - }); else args.push(argument); } @@ -426,8 +422,6 @@ function QObject(name, data, webChannel) } object.__propertyCache__[propertyIndex] = value; var valueToSend = value; - if (valueToSend instanceof QObject && webChannel.objects[valueToSend.__id__] !== undefined) - valueToSend = { "id": valueToSend.__id__ }; webChannel.exec({ "type": QWebChannelMessageTypes.setProperty, "object": object.__id__, @@ -452,6 +446,14 @@ function QObject(name, data, webChannel) } } +QObject.prototype.toJSON = function() { + if (this.__id__ === undefined) return {}; + return { + id: this.__id__, + "__QObject*__": true + }; +}; + //required for use with nodejs if (typeof module === 'object') { module.exports = { diff --git a/src/imports/webchannel/plugin.cpp b/src/imports/webchannel/plugin.cpp index b6d4018..45d83b1 100644 --- a/src/imports/webchannel/plugin.cpp +++ b/src/imports/webchannel/plugin.cpp @@ -61,8 +61,9 @@ void QWebChannelPlugin::registerTypes(const char *uri) int minor = 0; qmlRegisterType<QQmlWebChannel>(uri, major, minor, "WebChannel"); - // Auto-increment the import to stay in sync with ALL future QtQuick minor versions - qmlRegisterModule(uri, major, QT_VERSION_MINOR); + // The minor version used to be the current Qt 5 minor. For compatibility it is the last + // Qt 5 release. + qmlRegisterModule(uri, major, 15); } QT_END_NAMESPACE diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index e23921d..c0a12dc 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -457,6 +457,7 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const QMetaMe VariantArgument arguments[10]; for (int i = 0; i < qMin(args.size(), method.parameterCount()); ++i) { arguments[i].value = toVariant(args.at(i), method.parameterType(i)); + arguments[i].type = method.parameterType(i); } // construct QGenericReturnArgument QVariant returnValue; @@ -611,6 +612,44 @@ QObject *QMetaObjectPublisher::unwrapObject(const QString &objectId) const return Q_NULLPTR; } +QVariant QMetaObjectPublisher::unwrapMap(QVariantMap map) const +{ + const auto qobj = map.value(KEY_QOBJECT).toBool(); + const auto id = qobj ? map.value(KEY_ID).toString() : QString(); + + if (!id.isEmpty()) // it's probably a QObject + return QVariant::fromValue(unwrapObject(id)); + + // it's probably just a normal JS object, continue searching for objects + // that look like QObject* + for (auto &value : map) + value = unwrapVariant(value); + + return map; +} + +QVariant QMetaObjectPublisher::unwrapList(QVariantList list) const +{ + for (auto &value : list) + value = unwrapVariant(value); + + return list; +} + +QVariant QMetaObjectPublisher::unwrapVariant(const QVariant &value) const +{ + switch (value.type()) + { + case QMetaType::QVariantList: + return unwrapList(value.toList()); + case QMetaType::QVariantMap: + return unwrapMap(value.toMap()); + default: + break; + } + return value; +} + QVariant QMetaObjectPublisher::toVariant(const QJsonValue &value, int targetType) const { if (targetType == QMetaType::QJsonValue) { @@ -635,7 +674,7 @@ QVariant QMetaObjectPublisher::toVariant(const QJsonValue &value, int targetType // this converts QJsonObjects to QVariantMaps, which is not desired when // we want to get a QJsonObject or QJsonValue (see above) - QVariant variant = value.toVariant(); + QVariant variant = unwrapVariant(value.toVariant()); if (targetType != QMetaType::QVariant && !variant.convert(targetType)) { qWarning() << "Could not convert argument" << value << "to target type" << QVariant::typeToName(targetType) << '.'; } @@ -860,7 +899,7 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel transport->sendMessage(createResponse(message.value(KEY_ID), initializeClient(transport))); } else if (type == TypeDebug) { static QTextStream out(stdout); - out << "DEBUG: " << message.value(KEY_DATA).toString() << endl; + out << "DEBUG: " << message.value(KEY_DATA).toString() << Qt::endl; } else if (message.contains(KEY_OBJECT)) { const QString &objectName = message.value(KEY_OBJECT).toString(); QObject *object = registeredObjects.value(objectName); diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index 6030de2..2ffeca3 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -191,6 +191,9 @@ public: void objectDestroyed(const QObject *object); QObject *unwrapObject(const QString &objectId) const; + QVariant unwrapMap(QVariantMap map) const; + QVariant unwrapList(QVariantList list) const; + QVariant unwrapVariant(const QVariant &value) const; QVariant toVariant(const QJsonValue &value, int targetType) const; diff --git a/src/webchannel/variantargument_p.h b/src/webchannel/variantargument_p.h index 263a742..afac507 100644 --- a/src/webchannel/variantargument_p.h +++ b/src/webchannel/variantargument_p.h @@ -62,6 +62,9 @@ struct VariantArgument { operator QGenericArgument() const { + if (type == QMetaType::QVariant) { + return Q_ARG(QVariant, value); + } if (!value.isValid()) { return QGenericArgument(); } @@ -69,6 +72,7 @@ struct VariantArgument } QVariant value; + int type; }; QT_END_NAMESPACE diff --git a/tests/auto/qml/testobject.cpp b/tests/auto/qml/testobject.cpp index ad302e7..bd9db04 100644 --- a/tests/auto/qml/testobject.cpp +++ b/tests/auto/qml/testobject.cpp @@ -77,4 +77,17 @@ QString TestObject::testOverload(const QString &str, int i) return str.toUpper() + QString::number(i + 1); } +int TestObject::testVariantType(const QVariant &val) +{ + return val.type(); +} + +bool TestObject::testEmbeddedObjects(const QVariantList &list) +{ + return list.size() == 2 && + QMetaType::Type(list[0].type()) == QMetaType::QObjectStar && + QMetaType::Type(list[1].type()) == QMetaType::QVariantMap && + QMetaType::Type(list[1].toMap()["obj"].type()) == QMetaType::QObjectStar; +} + QT_END_NAMESPACE diff --git a/tests/auto/qml/testobject.h b/tests/auto/qml/testobject.h index b9c5ecc..9889523 100644 --- a/tests/auto/qml/testobject.h +++ b/tests/auto/qml/testobject.h @@ -51,6 +51,8 @@ public slots: int testOverload(int i); QString testOverload(const QString &str); QString testOverload(const QString &str, int i); + int testVariantType(const QVariant &val); + bool testEmbeddedObjects(const QVariantList &list); signals: void testSignalBool(bool testBool); diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml index ed1c4a1..9c9b6d0 100644 --- a/tests/auto/qml/tst_webchannel.qml +++ b/tests/auto/qml/tst_webchannel.qml @@ -556,4 +556,68 @@ TestCase { compare(signalArgs_explicit3, [["the answer is ", 41]]); compare(returnValues, [100, 42, "HELLO WORLD", "THE ANSWER IS 42"]); } + + function test_variantType() + { + var returnValues = []; + function logReturnValue(value) { + returnValues.push(value); + } + var channel = client.createChannel(function(channel) { + var testObject = channel.objects.testObject; + testObject.testVariantType(0, logReturnValue); + testObject.testVariantType("0", logReturnValue); + testObject.testVariantType(null, logReturnValue); + testObject.testVariantType(testObject, logReturnValue); + }); + client.awaitInit(); + + function awaitMessage(type) + { + var msg = client.awaitMessage(); + compare(msg.type, type); + compare(msg.object, "testObject"); + } + + console.log("double arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + console.log("string arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + console.log("null arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + console.log("QObject arg"); + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + + client.awaitIdle(); + + // QMetaType::Double: 6, QMetaType::QString: 10, QMetaType::Nullptr: 51, + // QMetaType::QObjectStar: 39 + compare(returnValues, [6, 10, 51, 39]); + } + + function test_embeddedQObject() + { + var success = false; + function logReturnValue(value) { + success = value; + } + var channel = client.createChannel(function(channel) { + var testObject = channel.objects.testObject; + testObject.testEmbeddedObjects([testObject, { obj: testObject }], logReturnValue); + }); + client.awaitInit(); + + function awaitMessage(type) + { + var msg = client.awaitMessage(); + compare(msg.type, type); + compare(msg.object, "testObject"); + } + + awaitMessage(JSClient.QWebChannelMessageTypes.invokeMethod); + + client.awaitIdle(); + + compare(success, true); + } } |