aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/webchannel/shared/qwebchannel.js14
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp41
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h3
-rw-r--r--src/webchannel/variantargument_p.h4
-rw-r--r--tests/auto/qml/testobject.cpp13
-rw-r--r--tests/auto/qml/testobject.h2
-rw-r--r--tests/auto/qml/tst_webchannel.qml64
7 files changed, 134 insertions, 7 deletions
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/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index e23921d..124b5c6 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) << '.';
}
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);
+ }
}