diff options
-rw-r--r-- | src/imports/webchannel/plugins.qmltypes | 62 | ||||
-rw-r--r-- | src/imports/webchannel/webchannel.pro | 2 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher.cpp | 112 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher_p.h | 15 | ||||
-rw-r--r-- | src/webchannel/qwebchannel.js | 36 | ||||
-rw-r--r-- | src/webchannel/signalhandler_p.h | 25 | ||||
-rw-r--r-- | tests/auto/qml/tst_multiclient.qml | 21 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannel.qml | 17 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannelseparation.qml | 26 | ||||
-rw-r--r-- | tests/auto/webchannel/tst_webchannel.cpp | 32 | ||||
-rw-r--r-- | tests/auto/webchannel/tst_webchannel.h | 1 |
11 files changed, 230 insertions, 119 deletions
diff --git a/src/imports/webchannel/plugins.qmltypes b/src/imports/webchannel/plugins.qmltypes index 789f2b4..4d0155d 100644 --- a/src/imports/webchannel/plugins.qmltypes +++ b/src/imports/webchannel/plugins.qmltypes @@ -4,49 +4,21 @@ import QtQuick.tooling 1.1 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -notrelocatable QtWebChannel 1.0' +// 'qmlplugindump -nonrelocatable QtWebChannel 1.0' Module { Component { - name: "QWebChannel" - prototype: "QObject" - Property { name: "blockUpdates"; type: "bool" } - Signal { - name: "blockUpdatesChanged" - Parameter { name: "block"; type: "bool" } - } - Method { - name: "sendMessage" - Parameter { name: "id"; type: "QJsonValue" } - Parameter { name: "data"; type: "QJsonValue" } - } - Method { - name: "sendMessage" - Parameter { name: "id"; type: "QJsonValue" } - } - Method { - name: "registerObject" - Parameter { name: "id"; type: "string" } - Parameter { name: "object"; type: "QObject"; isPointer: true } - } - Method { - name: "deregisterObject" - Parameter { name: "object"; type: "QObject"; isPointer: true } - } - } - Component { - name: "QmlWebChannel" + name: "QQmlWebChannel" prototype: "QWebChannel" exports: ["QtWebChannel/WebChannel 1.0"] exportMetaObjectRevisions: [0] - attachedType: "QmlWebChannelAttached" + attachedType: "QQmlWebChannelAttached" Property { name: "transports"; type: "QObject"; isList: true; isReadonly: true } Property { name: "registeredObjects"; type: "QObject"; isList: true; isReadonly: true } Method { name: "registerObjects" Parameter { name: "objects"; type: "QVariantMap" } } - Method { name: "test_clientIsIdle"; type: "bool" } Method { name: "connectTo" Parameter { name: "transport"; type: "QObject"; isPointer: true } @@ -57,7 +29,7 @@ Module { } } Component { - name: "QmlWebChannelAttached" + name: "QQmlWebChannelAttached" prototype: "QObject" Property { name: "id"; type: "string" } Signal { @@ -65,4 +37,30 @@ Module { Parameter { name: "id"; type: "string" } } } + Component { + name: "QWebChannel" + prototype: "QObject" + Property { name: "blockUpdates"; type: "bool" } + Signal { + name: "blockUpdatesChanged" + Parameter { name: "block"; type: "bool" } + } + Method { + name: "connectTo" + Parameter { name: "transport"; type: "QWebChannelAbstractTransport"; isPointer: true } + } + Method { + name: "disconnectFrom" + Parameter { name: "transport"; type: "QWebChannelAbstractTransport"; isPointer: true } + } + Method { + name: "registerObject" + Parameter { name: "id"; type: "string" } + Parameter { name: "object"; type: "QObject"; isPointer: true } + } + Method { + name: "deregisterObject" + Parameter { name: "object"; type: "QObject"; isPointer: true } + } + } } diff --git a/src/imports/webchannel/webchannel.pro b/src/imports/webchannel/webchannel.pro index 8ae6ef5..4c8d322 100644 --- a/src/imports/webchannel/webchannel.pro +++ b/src/imports/webchannel/webchannel.pro @@ -3,6 +3,8 @@ QT = core quick webchannel-private INCLUDEPATH += ../../webchannel VPATH += ../../webchannel +IMPORT_VERSION = 1.0 + SOURCES += \ plugin.cpp diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index c476011..0c22798 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -104,15 +104,18 @@ QMetaObjectPublisher::~QMetaObjectPublisher() void QMetaObjectPublisher::registerObject(const QString &id, QObject *object) { - if (propertyUpdatesInitialized) { - qWarning("Registered new object after initialization. This does not work!"); - return; - } registeredObjects[id] = object; registeredObjectIds[object] = id; + if (propertyUpdatesInitialized) { + if (!webChannel->d_func()->transports.isEmpty()) { + qWarning("Registered new object after initialization, existing clients won't be notified!"); + // TODO: send a message to clients that an object was added + } + initializePropertyUpdates(object, classInfoForObject(object, Q_NULLPTR)); + } } -QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) const +QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport) { QJsonObject data; if (!object) { @@ -160,7 +163,7 @@ QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) cons prop.name(), object->metaObject()->className()); } propertyInfo.append(signalInfo); - propertyInfo.append(QJsonValue::fromVariant(prop.read(object))); + propertyInfo.append(wrapResult(prop.read(object), transport)); qtProperties.append(propertyInfo); } for (int i = 0; i < metaObject->methodCount(); ++i) { @@ -217,13 +220,13 @@ void QMetaObjectPublisher::setClientIsIdle(bool isIdle) } } -QJsonObject QMetaObjectPublisher::initializeClient() +QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport *transport) { QJsonObject objectInfos; { const QHash<QString, QObject *>::const_iterator end = registeredObjects.constEnd(); for (QHash<QString, QObject *>::const_iterator it = registeredObjects.constBegin(); it != end; ++it) { - const QJsonObject &info = classInfoForObject(it.value()); + const QJsonObject &info = classInfoForObject(it.value(), transport); if (!propertyUpdatesInitialized) { initializePropertyUpdates(it.value(), info); } @@ -280,6 +283,7 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates() for (PendingPropertyUpdates::const_iterator it = pendingPropertyUpdates.constBegin(); it != end; ++it) { const QObject *object = it.key(); const QMetaObject *const metaObject = object->metaObject(); + const QString objectId = registeredObjectIds.value(object); const SignalToPropertyNameMap &objectsSignalToPropertyMap = signalToPropertyMap.value(object); // maps property name to current property value QJsonObject properties; @@ -291,12 +295,11 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates() foreach (const int propertyIndex, objectsSignalToPropertyMap.value(sigIt.key())) { const QMetaProperty &property = metaObject->property(propertyIndex); Q_ASSERT(property.isValid()); - properties[QString::number(propertyIndex)] = QJsonValue::fromVariant(property.read(object)); + properties[QString::number(propertyIndex)] = wrapResult(property.read(object), Q_NULLPTR, objectId); } sigs[QString::number(sigIt.key())] = QJsonArray::fromVariantList(sigIt.value()); } QJsonObject obj; - const QString objectId = registeredObjectIds.value(object); obj[KEY_OBJECT] = objectId; obj[KEY_SIGNALS] = sigs; obj[KEY_PROPERTIES] = properties; @@ -400,9 +403,7 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal message[KEY_OBJECT] = objectName; message[KEY_SIGNAL] = signalIndex; if (!arguments.isEmpty()) { - // TODO: wrap (new) objects on the fly - QJsonArray args = QJsonArray::fromVariantList(arguments); - message[KEY_ARGS] = args; + message[KEY_ARGS] = wrapList(arguments, Q_NULLPTR, objectName); } message[KEY_TYPE] = TypeSignal; @@ -435,52 +436,77 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object) Q_ASSERT(removed); Q_UNUSED(removed); + signalHandler.remove(object); signalToPropertyMap.remove(object); pendingPropertyUpdates.remove(object); } -QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport) +// NOTE: transport can be a nullptr +// in such a case, we need to ensure that the property is registered to +// the target transports of the parentObjectId +QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport, + const QString &parentObjectId) { if (QObject *object = result.value<QObject *>()) { QString id = registeredObjectIds.value(object); - - QJsonObject objectInfo; - - if (!id.isEmpty() && wrappedObjects.contains(id)) { - Q_ASSERT(object == wrappedObjects.value(id).object); - // check if this transport is already assigned to the object - if (!wrappedObjects.value(id).transports.contains(transport)) - wrappedObjects[id].transports.append(transport); - return wrappedObjects.value(id).classinfo; - } else { + QJsonObject classInfo; + if (id.isEmpty()) { + // neither registered, nor wrapped, do so now id = QUuid::createUuid().toString(); + Q_ASSERT(!registeredObjects.contains(id)); - QJsonObject info = classInfoForObject(object); - objectInfo[KEY_QOBJECT] = true; - objectInfo[KEY_ID] = id; - objectInfo[KEY_DATA] = info; + classInfo = classInfoForObject(object, transport); - if (!registeredObjects.contains(id)) { - registeredObjectIds[object] = id; - ObjectInfo oi(object, objectInfo); - oi.transports.append(transport); - wrappedObjects.insert(id, oi); + registeredObjectIds[object] = id; - initializePropertyUpdates(object, info); + ObjectInfo oi(object, classInfo); + if (transport) { + oi.transports.append(transport); + } else { + // use the transports from the parent object + oi.transports = wrappedObjects.value(parentObjectId).transports; + // or fallback to all transports if the parent is not wrapped + if (oi.transports.isEmpty()) + oi.transports = webChannel->d_func()->transports; } + wrappedObjects.insert(id, oi); + + initializePropertyUpdates(object, classInfo); + } else if (wrappedObjects.contains(id)) { + Q_ASSERT(object == wrappedObjects.value(id).object); + // check if this transport is already assigned to the object + if (transport && !wrappedObjects.value(id).transports.contains(transport)) + wrappedObjects[id].transports.append(transport); + classInfo = wrappedObjects.value(id).classinfo; } + + QJsonObject objectInfo; + objectInfo[KEY_QOBJECT] = true; + objectInfo[KEY_ID] = id; + if (!classInfo.isEmpty()) + objectInfo[KEY_DATA] = classInfo; return objectInfo; + } else if (result.canConvert<QJSValue>()) { + // Workaround for keeping QJSValues from QVariant. + // Calling QJSValue::toVariant() converts JS-objects/arrays to QVariantMap/List + // instead of stashing a QJSValue itself into a variant. + // TODO: Improve QJSValue-QJsonValue conversion in Qt. + return wrapResult(result.value<QJSValue>().toVariant(), transport, parentObjectId); + } else if (result.canConvert<QVariantList>()) { + // recurse and potentially wrap contents of the array + return wrapList(result.toList(), transport); } - // Workaround for keeping QJSValues from QVariant. - // Calling QJSValue::toVariant() converts JS-objects/arrays to QVariantMap/List - // instead of stashing a QJSValue itself into a variant. - // TODO: Improve QJSValue-QJsonValue conversion in Qt. - QVariant jsvVariant = result; - if (result.canConvert<QJSValue>()) - jsvVariant = result.value<QJSValue>().toVariant(); + return QJsonValue::fromVariant(result); +} - return QJsonValue::fromVariant(jsvVariant); +QJsonArray QMetaObjectPublisher::wrapList(const QVariantList &list, QWebChannelAbstractTransport *transport, const QString &parentObjectId) +{ + QJsonArray array; + foreach (const QVariant &arg, list) { + array.append(wrapResult(arg, transport, parentObjectId)); + } + return array; } void QMetaObjectPublisher::deleteWrappedObject(QObject *object) const @@ -525,7 +551,7 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel QJsonDocument(message).toJson().constData()); return; } - transport->sendMessage(createResponse(message.value(KEY_ID), initializeClient())); + 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; diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index 1d269f1..359135c 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -95,7 +95,7 @@ public: /** * Serialize the QMetaObject of @p object and return it in JSON form. */ - QJsonObject classInfoForObject(const QObject *object) const; + QJsonObject classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport); /** * Set the client to idle or busy, based on the value of @p isIdle. @@ -109,7 +109,7 @@ public: * * Furthermore, if that was not done already, connect to their property notify signals. */ - QJsonObject initializeClient(); + QJsonObject initializeClient(QWebChannelAbstractTransport *transport); /** * Go through all properties of the given object and connect to their notify signal. @@ -155,10 +155,17 @@ public: * return the objects class information. * * All other input types are returned as-is. + */ + QJsonValue wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport, + const QString &parentObjectId = QString()); + + /** + * Convert a list of variant values for consumption by the client. * - * TODO: support wrapping of initially-registered objects + * This properly handles QML values and also wraps the result if required. */ - QJsonValue wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport); + QJsonArray wrapList(const QVariantList &list, QWebChannelAbstractTransport *transport, + const QString &parentObjectId = QString()); /** * Invoke delete later on @p object. diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js index 13e9da5..4a1c784 100644 --- a/src/webchannel/qwebchannel.js +++ b/src/webchannel/qwebchannel.js @@ -155,6 +155,10 @@ var QWebChannel = function(transport, initCallback) for (var objectName in data) { var object = new QObject(objectName, data[objectName], channel); } + // now unwrap properties, which might reference other registered objects + for (var objectName in channel.objects) { + channel.objects[objectName].unwrapProperties(); + } if (initCallback) { initCallback(channel); } @@ -177,18 +181,31 @@ function QObject(name, data, webChannel) // ---------------------------------------------------------------------- - function unwrapQObject( response ) + this.unwrapQObject = function(response) { + if (response instanceof Array) { + // support list of objects + var ret = new Array(response.length); + for (var i = 0; i < response.length; ++i) { + ret[i] = object.unwrapQObject(response[i]); + } + return ret; + } if (!response || !response["__QObject*__"] - || response["id"] === undefined - || response["data"] === undefined) { + || response["id"] === undefined) { return response; } + var objectId = response.id; if (webChannel.objects[objectId]) return webChannel.objects[objectId]; + if (!response.data) { + console.error("Cannot unwrap unknown QObject " + objectId + " without data."); + return; + } + var qObject = new QObject( objectId, response.data, webChannel ); qObject.destroyed.connect(function() { if (webChannel.objects[objectId] === qObject) { @@ -206,9 +223,18 @@ function QObject(name, data, webChannel) } } }); + // here we are already initialized, and thus must directly unwrap the properties + qObject.unwrapProperties(); return qObject; } + this.unwrapProperties = function() + { + for (var propertyIdx in object.__propertyCache__) { + object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]); + } + } + function addSignal(signalData, isPropertyNotifySignal) { var signalName = signalData[0]; @@ -311,7 +337,7 @@ function QObject(name, data, webChannel) "args": args }, function(response) { if (response !== undefined) { - var result = unwrapQObject(response); + var result = object.unwrapQObject(response); if (callback) { (callback)(result); } @@ -326,6 +352,8 @@ function QObject(name, data, webChannel) var propertyName = propertyInfo[1]; var notifySignalData = propertyInfo[2]; // initialize property cache with current value + // NOTE: if this is an object, it is not directly unwrapped as it might + // reference other QObject that we do not know yet object.__propertyCache__[propertyIndex] = propertyInfo[3]; if (notifySignalData) { diff --git a/src/webchannel/signalhandler_p.h b/src/webchannel/signalhandler_p.h index 2560cdb..03fbca9 100644 --- a/src/webchannel/signalhandler_p.h +++ b/src/webchannel/signalhandler_p.h @@ -84,6 +84,11 @@ public: */ void clear(); + /** + * Fully remove and disconnect an object from handler + */ + void remove(const QObject *object); + private: /** * Exctract the arguments of a signal call and pass them to the receiver. @@ -252,15 +257,6 @@ int SignalHandler<Receiver>::qt_metacall(QMetaObject::Call call, int methodId, v dispatch(object, methodId, args); - if (methodId == s_destroyedSignalIndex) { - // disconnect on QObject::destroyed - ConnectionHash::iterator it = m_connectionsCounter.find(object); - Q_ASSERT(it != m_connectionsCounter.end()); - foreach (const ConnectionPair &connection, *it) { - QObject::disconnect(connection.first); - } - m_connectionsCounter.erase(it); - } return -1; } return methodId; @@ -280,6 +276,17 @@ void SignalHandler<Receiver>::clear() m_signalArgumentTypes[&QObject::staticMetaObject] = keep; } +template<class Receiver> +void SignalHandler<Receiver>::remove(const QObject *object) +{ + Q_ASSERT(m_connectionsCounter.contains(object)); + const SignalConnectionHash &connections = m_connectionsCounter.value(object); + foreach (const ConnectionPair &connection, connections) { + QObject::disconnect(connection.first); + } + m_connectionsCounter.remove(object); +} + QT_END_NAMESPACE #endif // SIGNALHANDLER_H diff --git a/tests/auto/qml/tst_multiclient.qml b/tests/auto/qml/tst_multiclient.qml index 115857d..4977e50 100644 --- a/tests/auto/qml/tst_multiclient.qml +++ b/tests/auto/qml/tst_multiclient.qml @@ -87,14 +87,14 @@ TestCase { WebChannel.id: "myOtherObj" } + property var lastFactoryObj + property var createdFactoryObjects: [] QtObject { id: myFactory - property var lastObj - property var createdObjects: [] function cleanup() { - while (createdObjects.length) { - var obj = createdObjects.shift(); + while (createdFactoryObjects.length) { + var obj = createdFactoryObjects.shift(); if (obj) { obj.destroy(); } @@ -103,9 +103,9 @@ TestCase { function create(id) { - lastObj = component.createObject(myFactory, {objectName: id}); - createdObjects.push(lastObj); - return lastObj; + lastFactoryObj = component.createObject(myFactory, {objectName: id}); + createdFactoryObjects.push(lastFactoryObj); + return lastFactoryObj; } WebChannel.id: "myFactory" } @@ -139,7 +139,8 @@ TestCase { client2.debug = false; // delete all created objects myFactory.cleanup(); - myFactory.lastObj = undefined; + lastFactoryObj = undefined; + createdFactoryObjects = []; // reschedule current task to end of event loop wait(1); } @@ -180,7 +181,7 @@ TestCase { var channel1 = client1.createChannel(function (channel1) { channel1.objects.myFactory.create("testObj1", function (obj1) { - testObj1 = myFactory.lastObj; + testObj1 = lastFactoryObj; testObj1Id = obj1.__id__; // create second channel after factory has created first @@ -227,7 +228,7 @@ TestCase { channel2 = client2.createChannel(function (channel2) { channel2.objects.myFactory.create("testObj2", function (obj2) { - testObj2 = myFactory.lastObj; + testObj2 = lastFactoryObj; testObj2Id = obj2.__id__; }); }); diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml index f41c4fa..3bfbfc9 100644 --- a/tests/auto/qml/tst_webchannel.qml +++ b/tests/auto/qml/tst_webchannel.qml @@ -67,6 +67,8 @@ TestCase { WebChannel.id: "myOtherObj" } property var lastFactoryObj + QtObject{ id: bar; objectName: "bar" } + QtObject{ id: baz; objectName: "baz" } QtObject { id: myFactory function create(id) @@ -74,9 +76,13 @@ TestCase { lastFactoryObj = component.createObject(myFactory, {objectName: id}); return lastFactoryObj; } + property var objectInProperty: QtObject { + objectName: "foo" + } + property var otherObject: myObj + property var objects: [ bar, baz ]; WebChannel.id: "myFactory" } - Component { id: component QtObject { @@ -276,6 +282,15 @@ TestCase { lastFactoryObj.mySignal("foobar", 42); client.awaitSignal(); + // property should be wrapped + compare(channel.objects.myFactory.objectInProperty.objectName, "foo"); + // list property as well + compare(channel.objects.myFactory.objects.length, 2); + compare(channel.objects.myFactory.objects[0].objectName, "bar"); + compare(channel.objects.myFactory.objects[1].objectName, "baz"); + // also works with properties that reference other registered objects + compare(channel.objects.myFactory.otherObject, channel.objects.myObj); + // deleteLater call msg = client.awaitMessage(); compare(msg.type, JSClient.QWebChannelMessageTypes.invokeMethod); diff --git a/tests/auto/qml/tst_webchannelseparation.qml b/tests/auto/qml/tst_webchannelseparation.qml index 289f8b2..8a74243 100644 --- a/tests/auto/qml/tst_webchannelseparation.qml +++ b/tests/auto/qml/tst_webchannelseparation.qml @@ -91,15 +91,16 @@ TestCase { } WebChannel.id: "myObj3" } + + property var lastFactoryObj + property var createdFactoryObjects: [] QtObject { id: myFactory - property var lastObj - property var createdObjects: [] function cleanup() { - while (createdObjects.length) { - var obj = createdObjects.shift(); + while (createdFactoryObjects.length) { + var obj = createdFactoryObjects.shift(); if (obj) { obj.destroy(); } @@ -108,9 +109,9 @@ TestCase { function create(id) { - lastObj = component.createObject(myFactory, {objectName: id}); - createdObjects.push(lastObj); - return lastObj; + lastFactoryObj = component.createObject(myFactory, {objectName: id}); + createdFactoryObjects.push(lastFactoryObj); + return lastFactoryObj; } WebChannel.id: "myFactory" } @@ -146,7 +147,8 @@ TestCase { client2.debug = false; // delete all created objects myFactory.cleanup(); - myFactory.lastObj = undefined; + lastFactoryObj = undefined; + createdFactoryObjects = []; // reschedule current task to end of event loop wait(1); } @@ -160,7 +162,7 @@ TestCase { var channel1 = client1.createChannel(function (channel1) { channel1.objects.myFactory.create("testObj1", function (obj1) { - testObj1 = myFactory.lastObj; + testObj1 = lastFactoryObj; testObj1Id = obj1.__id__; obj1.mySignal.connect(function (arg1_1, arg1_2) { @@ -182,7 +184,7 @@ TestCase { channel2 = client2.createChannel(function (channel2) { channel2.objects.myFactory.create("testObj2", function (obj2) { - testObj2 = myFactory.lastObj; + testObj2 = lastFactoryObj; testObj2Id = obj2.__id__; obj2.mySignal.connect(function (arg2_1, arg2_2) { console.debug("client 2 received signal 'mySignal'"); @@ -278,7 +280,7 @@ TestCase { var channel1 = client1.createChannel(function (channel1) { channel1.objects.myFactory.create("testObj1", function (obj1) { - testObj1 = myFactory.lastObj; + testObj1 = lastFactoryObj; testObj1Id = obj1.__id__; obj1.myPropertyChanged.connect(function (arg1_1) { @@ -300,7 +302,7 @@ TestCase { channel2 = client2.createChannel(function (channel2) { channel2.objects.myFactory.create("testObj2", function (obj2) { - testObj2 = myFactory.lastObj; + testObj2 = lastFactoryObj; testObj2Id = obj2.__id__; obj2.myPropertyChanged.connect(function (arg1_1) { console.debug("client 2 received property update 'myProperty' " + obj2.myProperty); diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 5060028..3d77b42 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -83,13 +83,37 @@ void TestWebChannel::testRegisterObjects() channel.registerObjects(objects); } +void TestWebChannel::testDeregisterObjects() +{ + QWebChannel channel; + TestObject testObject; + testObject.setObjectName("myTestObject"); + + + channel.registerObject(testObject.objectName(), &testObject); + + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QJsonObject connectMessage = + QJsonDocument::fromJson(("{\"type\": 7," + "\"object\": \"myTestObject\"," + "\"signal\": " + QString::number(testObject.metaObject()->indexOfSignal("sig1()")) + + "}").toLatin1()).object(); + channel.d_func()->publisher->handleMessage(connectMessage, m_dummyTransport); + + emit testObject.sig1(); + channel.deregisterObject(&testObject); + emit testObject.sig1(); +} + void TestWebChannel::testInfoForObject() { TestObject obj; obj.setObjectName("myTestObject"); QWebChannel channel; - const QJsonObject info = channel.d_func()->publisher->classInfoForObject(&obj); + const QJsonObject info = channel.d_func()->publisher->classInfoForObject(&obj, m_dummyTransport); QCOMPARE(info.keys(), QStringList() << "enums" << "methods" << "properties" << "signals"); @@ -267,7 +291,7 @@ void TestWebChannel::benchClassInfo() QBENCHMARK { foreach (const QObject *object, objects) { - channel.d_func()->publisher->classInfoForObject(object); + channel.d_func()->publisher->classInfoForObject(object, m_dummyTransport); } } } @@ -282,7 +306,7 @@ void TestWebChannel::benchInitializeClients() QMetaObjectPublisher *publisher = channel.d_func()->publisher; QBENCHMARK { - publisher->initializeClient(); + publisher->initializeClient(m_dummyTransport); publisher->propertyUpdatesInitialized = false; publisher->signalToPropertyMap.clear(); @@ -304,7 +328,7 @@ void TestWebChannel::benchPropertyUpdates() } channel.registerObjects(objects); - channel.d_func()->publisher->initializeClient(); + channel.d_func()->publisher->initializeClient(m_dummyTransport); QBENCHMARK { foreach (BenchObject *obj, objectList) { diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index ad8c6a4..6564944 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -214,6 +214,7 @@ public: private slots: void testRegisterObjects(); + void testDeregisterObjects(); void testInfoForObject(); void testInvokeMethodConversion(); void testDisconnect(); |