diff options
author | Andrew Webster <awebster@arcx.com> | 2018-09-13 16:59:44 -0400 |
---|---|---|
committer | Andrew Webster <awebster@arcx.com> | 2019-02-06 18:56:35 +0000 |
commit | e283b0852c25dba2ef73556062b5605af3632b05 (patch) | |
tree | f14e5452047291e8e4dd1656f33d654db9fe8c9c | |
parent | 93db9349c3f40fad6e4a7d94a719dcbeb1195590 (diff) | |
download | qtwebchannel-e283b0852c25dba2ef73556062b5605af3632b05.tar.gz |
Convert QObjects in QVariantMaps
QObjects that are present in an array are already converted to
an object identifier. This does the same for variant maps, which
end up as ECMAScript objects.
This allows QObjects put into a QVariantMap to be properly
deserialized. For example, if a property is declared as such:
Q_PROPERTY(QVariantMap propName READ propName CONSTANT)
And propName is:
QVariantMap propName() const {
QVariantMap map;
map.insert("theProperty", QVariant::fromValue(someQObject));
return map;
}
The "theProperty" property will now properly refer to the object.
Change-Id: I3c6e71b860f6825a31eb337aeffa55302287c8ff
Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
-rw-r--r-- | examples/webchannel/shared/qwebchannel.js | 12 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher.cpp | 12 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher_p.h | 8 | ||||
-rw-r--r-- | tests/auto/qml/testobject.cpp | 9 | ||||
-rw-r--r-- | tests/auto/qml/testobject.h | 7 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannel.qml | 3 |
6 files changed, 48 insertions, 3 deletions
diff --git a/examples/webchannel/shared/qwebchannel.js b/examples/webchannel/shared/qwebchannel.js index 5b047c2..d75e148 100644 --- a/examples/webchannel/shared/qwebchannel.js +++ b/examples/webchannel/shared/qwebchannel.js @@ -197,10 +197,16 @@ function QObject(name, data, webChannel) } return ret; } - if (!response - || !response["__QObject*__"] - || response.id === undefined) { + if (!(response instanceof Object)) return response; + + if (!response["__QObject*__"] + || response.id === undefined) { + var jObj = {}; + for (var propName in response) { + jObj[propName] = object.unwrapQObject(response[propName]); + } + return jObj; } var objectId = response.id; diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index cd2d940..f1ccbe9 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -617,6 +617,9 @@ QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelA } else if (result.canConvert<QVariantList>()) { // recurse and potentially wrap contents of the array return wrapList(result.toList(), transport); + } else if (result.canConvert<QVariantMap>()) { + // recurse and potentially wrap contents of the map + return wrapMap(result.toMap(), transport); } return QJsonValue::fromVariant(result); @@ -631,6 +634,15 @@ QJsonArray QMetaObjectPublisher::wrapList(const QVariantList &list, QWebChannelA return array; } +QJsonObject QMetaObjectPublisher::wrapMap(const QVariantMap &map, QWebChannelAbstractTransport *transport, const QString &parentObjectId) +{ + QJsonObject obj; + for (QVariantMap::const_iterator i = map.begin(); i != map.end(); i++) { + obj.insert(i.key(), wrapResult(i.value(), transport, parentObjectId)); + } + return obj; +} + void QMetaObjectPublisher::deleteWrappedObject(QObject *object) const { if (!wrappedObjects.contains(registeredObjectIds.value(object))) { diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index d02a933..1535a70 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -199,6 +199,14 @@ public: const QString &parentObjectId = QString()); /** + * Convert a variant map for consumption by the client. + * + * This properly handles QML values and also wraps the result if required. + */ + QJsonObject wrapMap(const QVariantMap &map, QWebChannelAbstractTransport *transport, + const QString &parentObjectId = QString()); + + /** * Invoke delete later on @p object. */ void deleteWrappedObject(QObject *object) const; diff --git a/tests/auto/qml/testobject.cpp b/tests/auto/qml/testobject.cpp index 2be7773..4968bf4 100644 --- a/tests/auto/qml/testobject.cpp +++ b/tests/auto/qml/testobject.cpp @@ -33,13 +33,22 @@ QT_BEGIN_NAMESPACE TestObject::TestObject(QObject* parent) : QObject(parent) + , embeddedObject(new QObject(this)) { + embeddedObject->setObjectName("embedded"); } TestObject::~TestObject() { } +QVariantMap TestObject::objectMap() const +{ + QVariantMap map; + map.insert("subObject", QVariant::fromValue(embeddedObject)); + return map; +} + void TestObject::triggerSignals() { emit testSignalBool(true); diff --git a/tests/auto/qml/testobject.h b/tests/auto/qml/testobject.h index e025ea6..5813dae 100644 --- a/tests/auto/qml/testobject.h +++ b/tests/auto/qml/testobject.h @@ -31,22 +31,29 @@ #define TESTOBJECT_H #include <QObject> +#include <QVariantMap> QT_BEGIN_NAMESPACE class TestObject : public QObject { Q_OBJECT + Q_PROPERTY(QVariantMap objectMap READ objectMap CONSTANT) public: explicit TestObject(QObject *parent = Q_NULLPTR); ~TestObject(); + QVariantMap objectMap() const; + public slots: void triggerSignals(); signals: void testSignalBool(bool testBool); void testSignalInt(int testInt); + +private: + QObject *embeddedObject; }; QT_END_NAMESPACE diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml index 6da6c4b..298376f 100644 --- a/tests/auto/qml/tst_webchannel.qml +++ b/tests/auto/qml/tst_webchannel.qml @@ -297,6 +297,9 @@ TestCase { compare(channel.objects.myFactory.objects.length, 2); compare(channel.objects.myFactory.objects[0].objectName, "bar"); compare(channel.objects.myFactory.objects[1].objectName, "baz"); + // map property as well + compare(channel.objects.testObject.objectMap.subObject.objectName, + "embedded"); // also works with properties that reference other registered objects compare(channel.objects.myFactory.otherObject, channel.objects.myObj); |