summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--dependencies.yaml4
-rw-r--r--examples/webchannel/shared/qwebchannel.js26
-rw-r--r--src/imports/webchannel/plugin.cpp5
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp41
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h3
-rw-r--r--src/webchannel/qwebchannelabstracttransport.h4
-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.qml125
11 files changed, 210 insertions, 19 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..df75d3f
--- /dev/null
+++ b/dependencies.yaml
@@ -0,0 +1,4 @@
+dependencies:
+ ../qtwebsockets:
+ ref: 0c488149eafadc550ee4034a49c1bacdc1e955ec
+ required: false
diff --git a/examples/webchannel/shared/qwebchannel.js b/examples/webchannel/shared/qwebchannel.js
index 32ad51e..3cfcd62 100644
--- a/examples/webchannel/shared/qwebchannel.js
+++ b/examples/webchannel/shared/qwebchannel.js
@@ -273,13 +273,11 @@ function QObject(name, data, webChannel)
console.error("Bad callback given to disconnect from signal " + signalName);
return;
}
- object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];
- var idx = object.__objectSignals__[signalIndex].indexOf(callback);
- if (idx === -1) {
- console.error("Cannot find connection of signal " + signalName + " to " + callback.name);
- return;
- }
- object.__objectSignals__[signalIndex].splice(idx, 1);
+ // This makes a new list. This is important because it won't interfere with
+ // signal processing if a disconnection happens while emittig a signal
+ object.__objectSignals__[signalIndex] = (object.__objectSignals__[signalIndex] || []).filter(function(c) {
+ return c != callback;
+ });
if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) {
// only required for "pure" signals, handled separately for properties in propertyUpdate
webChannel.exec({
@@ -341,10 +339,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);
}
@@ -416,8 +410,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__,
@@ -440,6 +432,14 @@ function QObject(name, data, webChannel)
Object.assign(object, data.enums);
}
+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 677f79c..f6110ed 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/qwebchannelabstracttransport.h b/src/webchannel/qwebchannelabstracttransport.h
index ecac588..e3747c7 100644
--- a/src/webchannel/qwebchannelabstracttransport.h
+++ b/src/webchannel/qwebchannelabstracttransport.h
@@ -50,8 +50,8 @@ class Q_WEBCHANNEL_EXPORT QWebChannelAbstractTransport : public QObject
{
Q_OBJECT
public:
- explicit QWebChannelAbstractTransport(QObject *parent = Q_NULLPTR);
- virtual ~QWebChannelAbstractTransport();
+ explicit QWebChannelAbstractTransport(QObject *parent = nullptr);
+ ~QWebChannelAbstractTransport() override;
public Q_SLOTS:
virtual void sendMessage(const QJsonObject &message) = 0;
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..0255d43 100644
--- a/tests/auto/qml/tst_webchannel.qml
+++ b/tests/auto/qml/tst_webchannel.qml
@@ -497,6 +497,67 @@ TestCase {
compare(signalArgs, [42, 42, 1, 1, 0, 0]);
}
+ function test_connectDuringEmit()
+ {
+ var cb1 = 0;
+ var cb2 = 0;
+ var channel = client.createChannel(function(channel) {
+ var myObj = channel.objects.myObj;
+ myObj.mySignal.connect(function() {
+ cb1++;
+ myObj.mySignal.connect(function() {
+ cb2++;
+ });
+ });
+ });
+ client.awaitInit();
+
+ var msg = client.awaitMessage();
+ compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
+ compare(msg.object, "myObj");
+
+ client.awaitIdle();
+
+ myObj.mySignal(42, myObj);
+
+ compare(cb1, 1);
+ compare(cb2, 0);
+ }
+
+ function test_disconnectDuringEmit()
+ {
+ var cb1 = 0;
+ var cb2 = 0;
+ var cb3 = 0;
+ var channel = client.createChannel(function(channel) {
+ var myObj = channel.objects.myObj;
+ var cb1impl = function() {
+ cb1++;
+ };
+ myObj.mySignal.connect(cb1impl);
+ myObj.mySignal.connect(function() {
+ cb2++;
+ myObj.mySignal.disconnect(cb1impl);
+ });
+ myObj.mySignal.connect(function() {
+ cb3++;
+ });
+ });
+ client.awaitInit();
+
+ var msg = client.awaitMessage();
+ compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
+ compare(msg.object, "myObj");
+
+ client.awaitIdle();
+
+ myObj.mySignal(42, myObj);
+
+ compare(cb1, 1);
+ compare(cb2, 1);
+ compare(cb3, 1);
+ }
+
function test_overloading()
{
var signalArgs_implicit = [];
@@ -556,4 +617,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.25, 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);
+ }
}