From cc0ed84fa6eac8119313543d2dc33658a78e50c7 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 21 Apr 2016 10:52:20 +0200 Subject: do not enable example installs explicitly any more it's done centrally now. Change-Id: I0922b2083b594cdf61f4606fe17c9c61c0d4683a Reviewed-by: Milian Wolff --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index b7605bf..c945d77 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) -CONFIG += qt_example_installs warning_clean +CONFIG += warning_clean MODULE_VERSION = 5.6.2 -- cgit v1.2.1 From 97c876a1353f29ed0129360f013f2529bed69d98 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 25 May 2016 16:42:01 +0200 Subject: Enable calling C++ functions taking QJson arguments via webchannel. We used to convert the QJsonValue arguments to QVariants, which then failed to call a C++ function which expected on of the three QJson data types, i.e. QJsonValue, QJsonObject or QJsonArray. Instead, we now detect these three cases and manually convert the QJsonValue as needed. [ChangeLog] C++ functions taking arguments of type QJsonValue, QJsonArray or QJsonObject can now be called via the Qt WebChannel. Change-Id: I94e0c8937ca35e2ecd3554f7ddf2d4e5a3328570 Task-number: QTBUG-48198 Reviewed-by: Simon Hausmann --- src/webchannel/qmetaobjectpublisher.cpp | 29 ++++++++++++++++++---- tests/auto/webchannel/tst_webchannel.cpp | 41 ++++++++++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 5 ++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index 324191e..e85bc76 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -87,6 +87,29 @@ QJsonObject createResponse(const QJsonValue &id, const QJsonValue &data) /// TODO: what is the proper value here? const int PROPERTY_UPDATE_INTERVAL = 50; + +QVariant toVariant(const QJsonValue &value, int targetType) +{ + if (targetType == QMetaType::QJsonValue) { + return QVariant::fromValue(value); + } else if (targetType == QMetaType::QJsonArray) { + if (!value.isArray()) + qWarning() << "Cannot not convert non-array argument" << value << "to QJsonArray."; + return QVariant::fromValue(value.toArray()); + } else if (targetType == QMetaType::QJsonObject) { + if (!value.isObject()) + qWarning() << "Cannot not convert non-object argument" << value << "to QJsonObject."; + return QVariant::fromValue(value.toObject()); + } + + // this converts QJsonObjects to QVariantMaps, which is not desired when + // we want to get a QJsonObject or QJsonValue (see above) + QVariant variant = value.toVariant(); + if (targetType != QMetaType::QVariant && !variant.convert(targetType)) { + qWarning() << "Could not convert argument" << value << "to target type" << QVariant::typeToName(targetType) << '.'; + } + return variant; +} } QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel) @@ -366,11 +389,7 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const int met // construct converter objects of QVariant to QGenericArgument VariantArgument arguments[10]; for (int i = 0; i < qMin(args.size(), method.parameterCount()); ++i) { - QVariant arg = args.at(i).toVariant(); - if (method.parameterType(i) != QMetaType::QVariant && !arg.convert(method.parameterType(i))) { - qWarning() << "Could not convert argument" << args.at(i) << "to target type" << method.parameterTypes().at(i) << '.'; - } - arguments[i].value = arg; + arguments[i].value = toVariant(args.at(i), method.parameterType(i)); } // construct QGenericReturnArgument diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index f1911e5..4db8bae 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -216,6 +216,21 @@ void TestWebChannel::setVariant(const QVariant &v) m_lastVariant = v; } +void TestWebChannel::setJsonValue(const QJsonValue& v) +{ + m_lastJsonValue = v; +} + +void TestWebChannel::setJsonObject(const QJsonObject& v) +{ + m_lastJsonValue = v; +} + +void TestWebChannel::setJsonArray(const QJsonArray& v) +{ + m_lastJsonValue = v; +} + void TestWebChannel::testRegisterObjects() { QWebChannel channel; @@ -426,6 +441,32 @@ void TestWebChannel::testInvokeMethodConversion() channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastVariant, args.at(0).toVariant()); } + { + int method = metaObject()->indexOfMethod("setJsonValue(QJsonValue)"); + QVERIFY(method != -1); + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastJsonValue, args.at(0)); + } + { + int method = metaObject()->indexOfMethod("setJsonObject(QJsonObject)"); + QVERIFY(method != -1); + QJsonObject object; + object["foo"] = QJsonValue(123); + object["bar"] = QJsonValue(4.2); + args[0] = object; + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastJsonValue.toObject(), object); + } + { + int method = metaObject()->indexOfMethod("setJsonArray(QJsonArray)"); + QVERIFY(method != -1); + QJsonArray array; + array << QJsonValue(123); + array << QJsonValue(4.2); + args[0] = array; + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastJsonValue.toArray(), array); + } } void TestWebChannel::testDisconnect() diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index b2a1040..e551458 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -36,6 +36,7 @@ #include #include +#include #include @@ -229,6 +230,9 @@ public: Q_INVOKABLE void setInt(int i); Q_INVOKABLE void setDouble(double d); Q_INVOKABLE void setVariant(const QVariant &v); + Q_INVOKABLE void setJsonValue(const QJsonValue &v); + Q_INVOKABLE void setJsonObject(const QJsonObject &v); + Q_INVOKABLE void setJsonArray(const QJsonArray &v); private slots: void testRegisterObjects(); @@ -252,6 +256,7 @@ private: int m_lastInt; double m_lastDouble; QVariant m_lastVariant; + QJsonValue m_lastJsonValue; }; QT_END_NAMESPACE -- cgit v1.2.1 From bec50124b893c4632829d9806f49f64c4debf936 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 25 May 2016 18:20:30 +0200 Subject: Fix setting properties of QJson{Value,Array,Object} type. Similar to the previous issue, where these types were not properly converted to QVariant when invoking a method, we manually do the conversion now to get the desired behavior. The culprit is again that QJsonValue::toVariant converts an object e.g. to a QVariantMap, and not to a QVariant containing a QJsonObject. [ChangeLog] QObject properties of type QJsonValue, QJsonArray or QJsonObject can now be set via the Qt WebChannel. Task-number: QTBUG-48198 Change-Id: I5d574b1a5cffd6d6ad9b555f2a3e872b9c3425a7 Reviewed-by: Simon Hausmann --- src/webchannel/qmetaobjectpublisher.cpp | 20 ++++--- src/webchannel/qmetaobjectpublisher_p.h | 5 ++ tests/auto/webchannel/tst_webchannel.cpp | 94 ++++++++++++++++++++++++++++++-- tests/auto/webchannel/tst_webchannel.h | 25 +++++++++ 4 files changed, 132 insertions(+), 12 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index e85bc76..0fa4ae2 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -410,6 +410,16 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const int met return returnValue; } +void QMetaObjectPublisher::setProperty(QObject *object, const int propertyIndex, const QJsonValue &value) +{ + QMetaProperty property = object->metaObject()->property(propertyIndex); + if (!property.isValid()) { + qWarning() << "Cannot set unknown property" << propertyIndex << "of object" << object; + } else if (!property.write(object, toVariant(value, property.userType()))) { + qWarning() << "Could not write value " << value << "to property" << property.name() << "of object" << object; + } +} + void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments) { if (!webChannel || webChannel->d_func()->transports.isEmpty()) { @@ -607,14 +617,8 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel } else if (type == TypeDisconnectFromSignal) { signalHandler.disconnectFrom(object, message.value(KEY_SIGNAL).toInt(-1)); } else if (type == TypeSetProperty) { - const int propertyIdx = message.value(KEY_PROPERTY).toInt(-1); - QMetaProperty property = object->metaObject()->property(propertyIdx); - if (!property.isValid()) { - qWarning() << "Cannot set unknown property" << message.value(KEY_PROPERTY) << "of object" << objectName; - } else if (!object->metaObject()->property(propertyIdx).write(object, message.value(KEY_VALUE).toVariant())) { - qWarning() << "Could not write value " << message.value(KEY_VALUE) - << "to property" << property.name() << "of object" << objectName; - } + setProperty(object, message.value(KEY_PROPERTY).toInt(-1), + message.value(KEY_VALUE)); } } } diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index cb3350e..b0ebd84 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -149,6 +149,11 @@ public: */ QVariant invokeMethod(QObject *const object, const int methodIndex, const QJsonArray &args); + /** + * Set the value of property @p propertyIndex on @p object to @p value. + */ + void setProperty(QObject *object, const int propertyIndex, const QJsonValue &value); + /** * Callback of the signalHandler which forwards the signal invocation to the webchannel clients. */ diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 4db8bae..93c7aa8 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -200,35 +200,70 @@ TestWebChannel::~TestWebChannel() { } +int TestWebChannel::readInt() const +{ + return m_lastInt; +} void TestWebChannel::setInt(int i) { m_lastInt = i; + emit lastIntChanged(); +} + +double TestWebChannel::readDouble() const +{ + return m_lastDouble; } void TestWebChannel::setDouble(double d) { m_lastDouble = d; + emit lastDoubleChanged(); +} + +QVariant TestWebChannel::readVariant() const +{ + return m_lastVariant; } void TestWebChannel::setVariant(const QVariant &v) { m_lastVariant = v; + emit lastVariantChanged(); +} + +QJsonValue TestWebChannel::readJsonValue() const +{ + return m_lastJsonValue; } void TestWebChannel::setJsonValue(const QJsonValue& v) { m_lastJsonValue = v; + emit lastJsonValueChanged(); +} + +QJsonObject TestWebChannel::readJsonObject() const +{ + return m_lastJsonObject; } void TestWebChannel::setJsonObject(const QJsonObject& v) { - m_lastJsonValue = v; + m_lastJsonObject = v; + emit lastJsonObjectChanged(); +} + +QJsonArray TestWebChannel::readJsonArray() const +{ + return m_lastJsonArray; } void TestWebChannel::setJsonArray(const QJsonArray& v) { - m_lastJsonValue = v; + m_lastJsonArray = v; + emit lastJsonArrayChanged(); } void TestWebChannel::testRegisterObjects() @@ -455,7 +490,7 @@ void TestWebChannel::testInvokeMethodConversion() object["bar"] = QJsonValue(4.2); args[0] = object; channel.d_func()->publisher->invokeMethod(this, method, args); - QCOMPARE(m_lastJsonValue.toObject(), object); + QCOMPARE(m_lastJsonObject, object); } { int method = metaObject()->indexOfMethod("setJsonArray(QJsonArray)"); @@ -465,7 +500,58 @@ void TestWebChannel::testInvokeMethodConversion() array << QJsonValue(4.2); args[0] = array; channel.d_func()->publisher->invokeMethod(this, method, args); - QCOMPARE(m_lastJsonValue.toArray(), array); + QCOMPARE(m_lastJsonArray, array); + } +} + +void TestWebChannel::testSetPropertyConversion() +{ + QWebChannel channel; + channel.connectTo(m_dummyTransport); + + { + int property = metaObject()->indexOfProperty("lastInt"); + QVERIFY(property != -1); + channel.d_func()->publisher->setProperty(this, property, QJsonValue(42)); + QCOMPARE(m_lastInt, 42); + } + { + int property = metaObject()->indexOfProperty("lastDouble"); + QVERIFY(property != -1); + channel.d_func()->publisher->setProperty(this, property, QJsonValue(-4.2)); + QCOMPARE(m_lastDouble, -4.2); + } + { + int property = metaObject()->indexOfProperty("lastVariant"); + QVERIFY(property != -1); + QVariant variant("foo bar asdf"); + channel.d_func()->publisher->setProperty(this, property, QJsonValue::fromVariant(variant)); + QCOMPARE(m_lastVariant, variant); + } + { + int property = metaObject()->indexOfProperty("lastJsonValue"); + QVERIFY(property != -1); + QJsonValue value("asdf asdf"); + channel.d_func()->publisher->setProperty(this, property, value); + QCOMPARE(m_lastJsonValue, value); + } + { + int property = metaObject()->indexOfProperty("lastJsonArray"); + QVERIFY(property != -1); + QJsonArray array; + array << QJsonValue(-123); + array << QJsonValue(-42); + channel.d_func()->publisher->setProperty(this, property, array); + QCOMPARE(m_lastJsonArray, array); + } + { + int property = metaObject()->indexOfProperty("lastJsonObject"); + QVERIFY(property != -1); + QJsonObject object; + object["foo"] = QJsonValue(-123); + object["bar"] = QJsonValue(-4.2); + channel.d_func()->publisher->setProperty(this, property, object); + QCOMPARE(m_lastJsonObject, object); } } diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index e551458..13294c2 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include @@ -223,22 +225,43 @@ class TestWebChannel : public QObject { Q_OBJECT + Q_PROPERTY(int lastInt READ readInt WRITE setInt NOTIFY lastIntChanged); + Q_PROPERTY(double lastDouble READ readDouble WRITE setDouble NOTIFY lastDoubleChanged); + Q_PROPERTY(QVariant lastVariant READ readVariant WRITE setVariant NOTIFY lastVariantChanged); + Q_PROPERTY(QJsonValue lastJsonValue READ readJsonValue WRITE setJsonValue NOTIFY lastJsonValueChanged); + Q_PROPERTY(QJsonObject lastJsonObject READ readJsonObject WRITE setJsonObject NOTIFY lastJsonObjectChanged); + Q_PROPERTY(QJsonArray lastJsonArray READ readJsonArray WRITE setJsonArray NOTIFY lastJsonArrayChanged); public: explicit TestWebChannel(QObject *parent = 0); virtual ~TestWebChannel(); + int readInt() const; Q_INVOKABLE void setInt(int i); + double readDouble() const; Q_INVOKABLE void setDouble(double d); + QVariant readVariant() const; Q_INVOKABLE void setVariant(const QVariant &v); + QJsonValue readJsonValue() const; Q_INVOKABLE void setJsonValue(const QJsonValue &v); + QJsonObject readJsonObject() const; Q_INVOKABLE void setJsonObject(const QJsonObject &v); + QJsonArray readJsonArray() const; Q_INVOKABLE void setJsonArray(const QJsonArray &v); +signals: + void lastIntChanged(); + void lastDoubleChanged(); + void lastVariantChanged(); + void lastJsonValueChanged(); + void lastJsonObjectChanged(); + void lastJsonArrayChanged(); + private slots: void testRegisterObjects(); void testDeregisterObjects(); void testInfoForObject(); void testInvokeMethodConversion(); + void testSetPropertyConversion(); void testDisconnect(); void testWrapRegisteredObject(); void testInfiniteRecursion(); @@ -257,6 +280,8 @@ private: double m_lastDouble; QVariant m_lastVariant; QJsonValue m_lastJsonValue; + QJsonObject m_lastJsonObject; + QJsonArray m_lastJsonArray; }; QT_END_NAMESPACE -- cgit v1.2.1 From 01ea92c7c8d77d3d3c10ab1cc4bf4f214aa07126 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 15:34:32 +0200 Subject: Doc: Edit example documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add images to the examples. - Add instructions for running the examples - Edit for grammar and style - Add dependencies to Qt WebEngine and Qt WebSockets modules - Add a workaround for preventing autolinking of WebChannel, WebEngine and WebSockets to the wrong targets - Use explicit linking where necessary Change-Id: Ia4025284063fa09c9e2a0b2c347ee682bba8a615 Reviewed-by: Topi Reiniö --- .../chatclient-html/doc/images/chatclient-html.png | Bin 0 -> 7284 bytes .../chatclient-html/doc/src/chatclient-html.qdoc | 31 ++++++----- .../chatclient-qml/doc/images/chatclient-qml.png | Bin 0 -> 5018 bytes .../chatclient-qml/doc/src/chatclient-qml.qdoc | 32 +++++++----- .../chatserver-cpp/doc/images/chatserver-cpp.png | Bin 0 -> 6829 bytes .../chatserver-cpp/doc/src/chatserver-cpp.qdoc | 32 +++++++----- .../webchannel/standalone/doc/src/standalone.qdoc | 18 ++++--- src/webchannel/doc/qtwebchannel.qdocconf | 3 +- src/webchannel/doc/src/examples.qdoc | 3 +- src/webchannel/doc/src/external-resources.qdoc | 57 +++++++++++++++++++++ 10 files changed, 128 insertions(+), 48 deletions(-) create mode 100644 examples/webchannel/chatclient-html/doc/images/chatclient-html.png create mode 100644 examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png create mode 100644 examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png create mode 100644 src/webchannel/doc/src/external-resources.qdoc diff --git a/examples/webchannel/chatclient-html/doc/images/chatclient-html.png b/examples/webchannel/chatclient-html/doc/images/chatclient-html.png new file mode 100644 index 0000000..f61c9ec Binary files /dev/null and b/examples/webchannel/chatclient-html/doc/images/chatclient-html.png differ diff --git a/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc b/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc index 3bf5745..66f2773 100644 --- a/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc +++ b/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc @@ -33,31 +33,36 @@ /*! \example chatclient-html - \title Qt WebChannel Chatclient HTML Example + \title Qt WebChannel ChatClient HTML Example \ingroup qtwebchannel-examples \brief A HTML/JavaScript client that communicates over a WebSocket with a QWebChannel server. - The chatclient-html example provides a simple QWebChannel client implemented using JavaScript and HTML. + \image chatclient-html.png - \section1 Overview + \e{ChatClient HTML} provides a simple QWebChannel client implemented using JavaScript and HTML. + + \section1 Running the Example + + To run the example, open the \c chatclient.html file in a browser. + + \section1 Implementing a Web Channel Client The client initializes a WebSocket connection to the chat server and receives an object - containing all neccessarry signals, slots and properties for implementing a chat client. + containing all the necessary signals, slots, and properties for implementing a chat client. - After login the client can invoke the method \c sendMessage and receive the signal \c newMessage - to send and receive messages. Furthermore there is a \c userList property which provides the - names of all other connected clients. It is automatically updated when its contents change. - Also, the client responds to the servers keep alive signal which is needed to detect disconnected - clients and remove them from the \c userlist property. + After login, the client can invoke the method \c sendMessage and receive the signal \c newMessage + to send and receive messages. Furthermore, a \c userList property provides the names of + all other connected clients. The list is automatically updated when its contents change. + Also, the client responds to the server's keep alive signal which is needed to detect disconnected + clients and remove them from the \c userList property. The example shows how basic elements can be used with the client JavaScript implementation of - QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage) and handle + QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage), and handling property changes (\c userList). - The client is able to work with the chatserver-cpp example. + The client is able to work with \l{Qt WebChannel ChatServer Example}. - To run the example, open the \c chatclient.html in a browser. - \sa {chatserver-cpp}, {chatclient-qml} + \sa {Qt WebChannel ChatServer Example}, {Qt WebChannel ChatClient QML Example} */ diff --git a/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png b/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png new file mode 100644 index 0000000..7f96e26 Binary files /dev/null and b/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png differ diff --git a/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc b/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc index c3bb3d3..4664141 100644 --- a/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc +++ b/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc @@ -33,32 +33,38 @@ /*! \example chatclient-qml - \title Qt WebChannel Chatclient QML Example + \title Qt WebChannel ChatClient QML Example \ingroup qtwebchannel-examples \brief A QML client that communicates over a WebSocket with a QWebChannel server. - The chatclient-html example provides a simple QWebChannel client implemented using JavaScript and QML. + \image chatclient-qml.png - \section1 Overview + \e{ChatClient QML} provides a simple QWebChannel client implemented using JavaScript and QML. - The client initializes a WebSocket connection to the chat server and receives an object - containing all neccessarry signals, slots and properties for implementing a chat client. + \section1 Running the Example + + To run the example, enter the following command in the client source + directory: + + \c {path/to/qmlscene qmlchatclient.qml} + + \section1 Implementing a Web Channel Client + + The client initializes a \l [QML] WebSocket connection to the chat server and receives an object + containing all the necessary signals, slots, and properties for implementing a chat client. After login, the client can invoke the method \c sendMessage and receive the signal \c newMessage - to send and receive messages. Furthermore, there is a \c userList property which provides the + to send and receive messages. Furthermore, a \c userList property provides the names of all other connected clients. It is automatically updated when its contents change. - Also, the client responds to the servers keep alive signal which is needed to detect disconnected + Also, the client responds to the server's keep alive signal which is needed to detect disconnected clients and remove them from the \c userList property. The example shows how basic elements can be used with the client JavaScript implementation of - QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage) and handle + QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage), and handling property changes (\c userList). - The client is able to work with the chatserver-cpp as server application - - - The example can be run by invoking \c {path/to/qmlscene qmlchatclient.qml}. + The client is able to work with the \l{Qt WebChannel ChatServer Example}. - \sa {chatserver-cpp}, {chatclient-html} + \sa {Qt WebChannel ChatServer Example}, {Qt WebChannel ChatClient HTML Example} */ diff --git a/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png b/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png new file mode 100644 index 0000000..b0f484a Binary files /dev/null and b/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png differ diff --git a/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc b/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc index e286476..0622fcf 100644 --- a/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc +++ b/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc @@ -33,31 +33,39 @@ /*! \example chatserver-cpp - \title Qt WebChannel Chatserver Example + \title Qt WebChannel ChatServer Example \ingroup qtwebchannel-examples - \brief Shows how to use the QWebChannel C++ API to implement a simple chat server + \brief A simple chat server implemented using the QWebChannel C++ API. - The chatserver examples provides a chat service that client examples can connect to. + \image chatserver-cpp.png - \section1 Overview + \e{ChatServer} provides a chat service that the + \l{Qt WebChannel ChatClient QML Example} and + \l{Qt WebChannel ChatClient HTML Example} can connect to. + + \include examples-run.qdocinc + + \section1 Implementing a Chat Server The C++ application implements a QObject which provides all mechanisms required for a chat service. - This object is published through a QWebChannel which uses a WebSocket as transport. + This object is published through a QWebChannel which uses a \l{Qt WebSockets} + {WebSocket} as transport. The server provides a basic \c login method (username only, no passwords), which must be successfully invoked before a client is able to chat. - After login a client can invoke the method \c sendMessage and receive the signal \c newMessage - to write and receive messages. Furthermore there is a \c userList property which provides + After login, a client can invoke the method \c sendMessage and receive the signal \c newMessage + to write and receive messages. Furthermore, there is a \c userList property which provides the names of all other connected clients. - Additionally the server sends a keepAlive signal periodically to all clients. The clients + Additionally the server sends a \c keepAlive signal periodically to all clients. The clients have to respond to this signal, otherwise the client will be removed from the \c userList property. - The example shows how basic QObject elements can be used with QWebChannel, i.e. signals - (\c newMessage), slots (\c sendMessage) and properties (\c userList). + The example shows how basic QObject elements can be used with QWebChannel, that is signals + (\c newMessage), slots (\c sendMessage), and properties (\c userList). - Because this is a plain server application, there are separated clients needed to interact - with the server. Both examples chatclient-qml and chatclient-html show a client implementation + Because this is a plain server application, separate clients are needed to + interact with it. \l{Qt WebChannel ChatClient QML Example} and + \l{Qt WebChannel ChatClient HTML Example} are client implementations compatible with this server. */ diff --git a/examples/webchannel/standalone/doc/src/standalone.qdoc b/examples/webchannel/standalone/doc/src/standalone.qdoc index bf62181..e8e2a57 100644 --- a/examples/webchannel/standalone/doc/src/standalone.qdoc +++ b/examples/webchannel/standalone/doc/src/standalone.qdoc @@ -36,26 +36,28 @@ \title Qt WebChannel Standalone Example \ingroup qtwebchannel-examples \image standalone-screenshot.png - \brief Shows how to use the QWebChannel C++ API to communicate with an external client. + \brief A simple chat between a server and a remote client running in a + browser. - The standalone example is a simple chat between a C++ application and a remote HTML - client running in your default browser. + \e{Standalone} demonstrates how to use the QWebChannel C++ API to + communicate with an external client. It is a simple chat between a C++ + application and a remote HTML client running in your default browser. \include examples-run.qdocinc - \section1 Overview + \section1 Communicating with a Remote Client - The C++ application sets up a QWebChannel instance and publishes a Dialog object over it. + The C++ application sets up a QWebChannel instance and publishes a \c Dialog object over it. For the remote client side, \l {standalone/index.html}{index.html} is opened. Both show a dialog with the list of received messages and an input box to send messages to the other end. - The Dialog emits the Dialog::sendText() signal when the user sends a message. The signal + The \c Dialog emits the \c Dialog::sendText() signal when the user sends a message. The signal automatically gets propagated to the HTML client. When the user enters a message on the HTML - side, Dialog::receiveText() is called. + side, \c Dialog::receiveText() is called. All communication between the HTML client and the C++ server is done over a WebSocket. The C++ side instantiates a QWebSocketServer and wraps incoming QWebSocket connections - in WebSocketTransport objects, which implement QWebChannelAbstractTransport. These objects are + in QWebChannelAbstractTransport objects. These objects are then connected to the QWebChannel instance. \sa {Qt WebChannel JavaScript API} diff --git a/src/webchannel/doc/qtwebchannel.qdocconf b/src/webchannel/doc/qtwebchannel.qdocconf index cfb47e4..4026379 100644 --- a/src/webchannel/doc/qtwebchannel.qdocconf +++ b/src/webchannel/doc/qtwebchannel.qdocconf @@ -40,7 +40,7 @@ qhp.QtWebChannel.subprojects.javascript.indexTitle = Qt WebChannel JavaScript tagfile = ../../../doc/qtwebchannel/qtwebchannel.tags -depends += qtcore qtquick qtqml qmake qtdoc +depends += qtcore qtquick qtqml qmake qtdoc qtwebengine qtwebsockets headerdirs += .. \ ../../imports @@ -48,6 +48,7 @@ headerdirs += .. \ sourcedirs += .. \ ../../imports +imagedirs += images exampledirs += ../../../examples/webchannel examples.fileextensions += "*.html *.json" diff --git a/src/webchannel/doc/src/examples.qdoc b/src/webchannel/doc/src/examples.qdoc index c47b687..34875f8 100644 --- a/src/webchannel/doc/src/examples.qdoc +++ b/src/webchannel/doc/src/examples.qdoc @@ -36,6 +36,7 @@ \group qtwebchannel-examples \brief List of Qt WebChannel examples. - The examples show how to use the QWebChannel C++ and WebChannel QML API. + The examples show how to use the QWebChannel C++ and \l [QML] WebChannel QML + API. */ diff --git a/src/webchannel/doc/src/external-resources.qdoc b/src/webchannel/doc/src/external-resources.qdoc new file mode 100644 index 0000000..0002ec1 --- /dev/null +++ b/src/webchannel/doc/src/external-resources.qdoc @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + The nolink entries prevent autolinking of each occurrence of 'WebChannel' + 'WebEngine' or 'WebSocket' to the QML type. + To link to the QML type, use explicit linking. For example: + \l [QML] WebChannel + \sa {QtWebChannel::}{WebChannel} +*/ +/*! + \externalpage nolink + \title WebChannel + \internal +*/ + +/*! + \externalpage nolink + \title WebEngine + \internal +*/ + +/*! + \externalpage nolink + \title WebSockets + \internal +*/ + +/*! + \externalpage nolink + \title WebSocket + \internal +*/ -- cgit v1.2.1 From 432ff4bf15e2bbafaf1d36814ef0231baaf9f4ee Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 15:37:55 +0200 Subject: Doc: Edit the index page - Remove reference to Qt WebKit - Add Getting Started section - Use standard section titles for API Reference and Examples Change-Id: Ie5e3ac792a109f680132a79e86d5e1065f4c3829 Reviewed-by: Milian Wolff --- src/webchannel/doc/src/index.qdoc | 40 +++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/webchannel/doc/src/index.qdoc b/src/webchannel/doc/src/index.qdoc index 5f354bd..43f4e6f 100644 --- a/src/webchannel/doc/src/index.qdoc +++ b/src/webchannel/doc/src/index.qdoc @@ -31,26 +31,50 @@ \title Qt WebChannel \brief Bridges the gap between Qt applications and HTML/JavaScript. - Qt WebChannel enables peer-to-peer communication between the host - (QML/C++ application) and the client (HTML/JavaScript application). The - transport mechanism is supported out of the box by the two popular web - engines, Qt WebKit 2 and Qt WebEngine (experimental). It works on all - browsers that support Qt WebSockets, enabling Qt WebChannel applications + Qt WebChannel enables peer-to-peer communication between the server + (QML/C++ application) and the client (HTML/JavaScript or QML application). The + transport mechanism is supported out of the box by \l{Qt WebEngine}. It works on all + browsers that support \l{Qt WebSockets}, enabling Qt WebChannel applications to run in any JavaScript runtime. Additionally, a custom transport mechanism can also be implemented using Qt WebSockets to support Qt WebChannel-based communication. The module provides a JavaScript library for seamless integration of C++ - and QML applications with HTML/JavaScript clients. The client must use the + and QML applications with HTML/JavaScript and QML clients. The clients must use the JavaScript library to access the serialized QObjects published by the host applications. - \section1 Related Information + \section1 Getting Started + + To use these classes in your application, use the following include + statement: + + \code + #include + \endcode + + To link against the module, add this line to your \l qmake \c .pro file: + + \code + QT += webchannel + \endcode + + The QML types are accessed by using: + \badcode + import QtWebChannel 1.0 + \endcode + + \section1 API Reference \list \li \l{Qt WebChannel JavaScript API}{JavaScript API} \li \l{Qt WebChannel C++ Classes}{C++ API} \li \l{Qt WebChannel QML Types}{QML API} - \li \l{Qt WebChannel Examples}{Examples} - show how use the API in practice + \endlist + + \section1 Examples + + \list + \li \l{Qt WebChannel Examples}{Examples} \endlist */ -- cgit v1.2.1 From 9ebaffbd531f0db4b3f528ebb7812b281520117d Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 15:56:35 +0200 Subject: Doc: Fix links to other modules -Remove references to Qt WebKit Change-Id: I0bd184021b1a87828e93f5783c38b9ba97f37763 Reviewed-by: Milian Wolff --- src/webchannel/doc/src/javascript.qdoc | 17 ++++++++--------- src/webchannel/qwebchannel.cpp | 2 +- src/webchannel/qwebchannelabstracttransport.cpp | 5 ++--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/webchannel/doc/src/javascript.qdoc b/src/webchannel/doc/src/javascript.qdoc index cfb5b21..a508ff9 100644 --- a/src/webchannel/doc/src/javascript.qdoc +++ b/src/webchannel/doc/src/javascript.qdoc @@ -31,21 +31,20 @@ \brief This page explains how to use the JavaScript QWebChannel API in HTML clients. - \section1 Setup + \section1 Setting up the JavaScript API - To communicate with a QWebChannel or WebChannel, any HTML client must use and setup the - JavaScript API provided by \c qwebchannel.js. For HTML clients run inside Qt WebKit, you - can load the file via \c qrc:///qtwebchannel/qwebchannel.js. For external clients you will - need to copy the file to your webserver. Then instantiate a QWebChannel object and pass + To communicate with a QWebChannel or \l [QML] WebChannel, a client must use and set up the + JavaScript API provided by \c qwebchannel.js. For clients run inside \l{Qt WebEngine}, you + can load the file via \c qrc:///qtwebchannel/qwebchannel.js. For external clients, you + need to copy the file to your web server. Then instantiate a QWebChannel object and pass it a transport object and a callback function, which will be invoked once the - initialization of the channel finished and published objects become available. + initialization of the channel finishes and the published objects become available. The transport object implements a minimal message passing interface. It should be an object with a \c send() function, which takes a stringified JSON message and transmits it to the server-side QWebChannelAbstractTransport object. Furthermore, its \c onmessage property should - be called when a message from the server was received. This interface is implemented internally - by the Qt WebKit navigator.qtWebChannelTransport object. Alternatively, you can also use a - WebSocket, which also implements this interface. + be called when a message from the server was received. Alternatively, you can use a + \l{Qt WebSockets}{WebSocket} to implement the interface. Note that the JavaScript QWebChannel object should be constructed once the transport object is fully operational. In case of a WebSocket, that means you should create the QWebChannel in the diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp index d440556..24f99a2 100644 --- a/src/webchannel/qwebchannel.cpp +++ b/src/webchannel/qwebchannel.cpp @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE features used by \c{qwebchannel.js}. As such, one can interact with basically any modern HTML browser or standalone JavaScript runtime, such as node.js. - There also exists a declarative WebChannel API. + There also exists a declarative \l{Qt WebChannel QML Types}{WebChannel API}. \sa {Qt WebChannel Standalone Example}, {Qt WebChannel JavaScript API}{JavaScript API} */ diff --git a/src/webchannel/qwebchannelabstracttransport.cpp b/src/webchannel/qwebchannelabstracttransport.cpp index 8d91dd1..771325a 100644 --- a/src/webchannel/qwebchannelabstracttransport.cpp +++ b/src/webchannel/qwebchannelabstracttransport.cpp @@ -44,9 +44,8 @@ QT_BEGIN_NAMESPACE Users of the QWebChannel must implement this interface and connect instances of it to the QWebChannel server for every client that should be connected to the QWebChannel. - The {Qt WebChannel Standalone Example}{Standalone Example} shows how this can be done - using Qt WebSockets. Qt WebKit implements this interface internally and uses the native - WebKit IPC mechanism to transmit messages to HTML clients. + The \l{Qt WebChannel Standalone Example} shows how this can be done + using \l{Qt WebSockets}. \note The JSON message protocol is considered internal and might change over time. -- cgit v1.2.1 From d2e2afcea59ec4e9d5edc30bad0866a8c18647b8 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 16:37:14 +0200 Subject: Doc: Use standard verb form to start function docs For consistency, the first verb should be in 3rd person singular form. Change-Id: I5e24ecbbac1b1ab85e737f127b021f24a55c8dd4 Reviewed-by: Milian Wolff --- src/webchannel/qwebchannel.cpp | 8 ++++---- src/webchannel/qwebchannelabstracttransport.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp index 24f99a2..1e8ed8f 100644 --- a/src/webchannel/qwebchannel.cpp +++ b/src/webchannel/qwebchannel.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE \class QWebChannel \inmodule QtWebChannel - \brief Expose QObjects to remote HTML clients. + \brief Exposes QObjects to remote HTML clients. \since 5.4 The QWebChannel fills the gap between C++ applications and HTML/JavaScript @@ -130,7 +130,7 @@ QWebChannel::~QWebChannel() } /*! - Register a group of objects to the QWebChannel. + Registers a group of objects to the QWebChannel. The properties, signals and public invokable methods of the objects are published to the remote clients. There, an object with the identifier used as key in the \a objects map is then constructed. @@ -160,7 +160,7 @@ QHash QWebChannel::registeredObjects() const } /*! - Register a single object to the QWebChannel. + Registers a single object to the QWebChannel. The properties, signals and public methods of the \a object are published to the remote clients. There, an object with the identifier \a id is then constructed. @@ -176,7 +176,7 @@ void QWebChannel::registerObject(const QString &id, QObject *object) } /*! - Deregister the given \a object from the QWebChannel. + Deregisters the given \a object from the QWebChannel. Remote clients will receive a \c destroyed signal for the given object. diff --git a/src/webchannel/qwebchannelabstracttransport.cpp b/src/webchannel/qwebchannelabstracttransport.cpp index 771325a..584342b 100644 --- a/src/webchannel/qwebchannelabstracttransport.cpp +++ b/src/webchannel/qwebchannelabstracttransport.cpp @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE /*! \fn QWebChannelAbstractTransport::sendMessage(const QJsonObject &message) - Send a JSON \a message to the remote client. An implementation would serialize the message and + Sends a JSON \a message to the remote client. An implementation would serialize the message and transmit it to the remote JavaScript client. */ -- cgit v1.2.1 From 7774f94b5d5cf8cea863ba22258bbd4543fab5ac Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 16:55:01 +0200 Subject: Doc: Use 3rd person singular verb form to begin method docs And fix a typo "connectect". Change-Id: I14c4b249af3cad142a5f6042b2059f653a9c3eae Reviewed-by: Milian Wolff --- src/webchannel/qqmlwebchannel.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/webchannel/qqmlwebchannel.cpp b/src/webchannel/qqmlwebchannel.cpp index 277cd62..c9567a3 100644 --- a/src/webchannel/qqmlwebchannel.cpp +++ b/src/webchannel/qqmlwebchannel.cpp @@ -128,8 +128,8 @@ QQmlWebChannel::~QQmlWebChannel() /*! \qmlmethod void WebChannel::registerObjects(QVariantMap objects) - Register objects to make them accessible to HTML clients. The key of the map is used as an identifier - for the object on the client side. + Registers objects to make them accessible to HTML clients. The key of the + map is used as an identifier for the object on the client side. Once registered, all signals and property changes are automatically propagated to the clients. Public invokable methods, including slots, are also accessible to the clients. @@ -161,7 +161,8 @@ QQmlWebChannelAttached *QQmlWebChannel::qmlAttachedProperties(QObject *obj) /*! \qmlmethod void WebChannel::connectTo(QWebChannelAbstractTransport transport) - \brief Connectect to the \a transport, which represents a communication channel to a single client. + \brief Connects to the \a transport, which represents a communication + channel to a single client. The transport object must be an implementation of QWebChannelAbstractTransport. @@ -179,7 +180,7 @@ void QQmlWebChannel::connectTo(QObject *transport) /*! \qmlmethod void WebChannel::disconnectFrom(QWebChannelAbstractTransport transport) - \brief Disconnect the \a transport from this WebChannel. + \brief Disconnects the \a transport from this WebChannel. The client will not be able to communicate with the WebChannel anymore, nor will it receive any signals or property updates. -- cgit v1.2.1 From 224742f0e2e882bce21047622d4c351803b9d486 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 16:33:29 +0200 Subject: Doc: Fix linking to methods and properties within the type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You don't need the type name for linking within the type docs. Also, the convention in QML and Qt Quick is to use a period and not a double colon. Change-Id: Ic93bae51e766ef782f089ce69dc4e54a712445c6 Reviewed-by: Topi Reiniö --- src/webchannel/qqmlwebchannel.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/webchannel/qqmlwebchannel.cpp b/src/webchannel/qqmlwebchannel.cpp index c9567a3..4bd4413 100644 --- a/src/webchannel/qqmlwebchannel.cpp +++ b/src/webchannel/qqmlwebchannel.cpp @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE A list of transport objects, which implement QWebChannelAbstractTransport. The transports are used to talk to the remote clients. - \sa WebChannel::connectTo(), WebChannel::disconnectFrom() + \sa connectTo(), disconnectFrom() */ /*! @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE \brief A list of objects which should be accessible to remote clients. - The objects must have the attached WebChannel::id property set to an identifier, under which the + The objects must have the attached \l id property set to an identifier, under which the object is then known on the HTML side. Once registered, all signals and property changes are automatically propagated to the clients. @@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE If one needs to register objects which are not available when the component is created, use the imperative registerObjects method. - \sa WebChannel::registerObjects(), WebChannel::id + \sa registerObjects(), id */ class QQmlWebChannelPrivate : public QWebChannelPrivate @@ -137,7 +137,7 @@ QQmlWebChannel::~QQmlWebChannel() This imperative API can be used to register objects on the fly. For static objects, the declarative registeredObjects property should be preferred. - \sa WebChannel::registeredObjects + \sa registeredObjects */ void QQmlWebChannel::registerObjects(const QVariantMap &objects) { @@ -166,7 +166,7 @@ QQmlWebChannelAttached *QQmlWebChannel::qmlAttachedProperties(QObject *obj) The transport object must be an implementation of QWebChannelAbstractTransport. - \sa WebChannel::transports, WebChannel::disconnectFrom() + \sa transports, disconnectFrom() */ void QQmlWebChannel::connectTo(QObject *transport) { @@ -185,7 +185,7 @@ void QQmlWebChannel::connectTo(QObject *transport) The client will not be able to communicate with the WebChannel anymore, nor will it receive any signals or property updates. - \sa WebChannel::connectTo() + \sa connectTo() */ void QQmlWebChannel::disconnectFrom(QObject *transport) { -- cgit v1.2.1 From 18d8ca185819d6d81a9f21858ff2d60bf6fd05f8 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 31 May 2016 15:34:32 +0200 Subject: Doc: Edit example documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add images to the examples. - Add instructions for running the examples - Edit for grammar and style - Add dependencies to Qt WebEngine and Qt WebSockets modules - Add a workaround for preventing autolinking of WebChannel, WebEngine and WebSockets to the wrong targets - Use explicit linking where necessary Change-Id: Ia4025284063fa09c9e2a0b2c347ee682bba8a615 Reviewed-by: Topi Reiniö (cherry picked from commit 01ea92c7c8d77d3d3c10ab1cc4bf4f214aa07126) --- .../chatclient-html/doc/images/chatclient-html.png | Bin 0 -> 7284 bytes .../chatclient-html/doc/src/chatclient-html.qdoc | 31 ++++++----- .../chatclient-qml/doc/images/chatclient-qml.png | Bin 0 -> 5018 bytes .../chatclient-qml/doc/src/chatclient-qml.qdoc | 32 +++++++----- .../chatserver-cpp/doc/images/chatserver-cpp.png | Bin 0 -> 6829 bytes .../chatserver-cpp/doc/src/chatserver-cpp.qdoc | 32 +++++++----- .../webchannel/standalone/doc/src/standalone.qdoc | 18 ++++--- src/webchannel/doc/qtwebchannel.qdocconf | 3 +- src/webchannel/doc/src/examples.qdoc | 3 +- src/webchannel/doc/src/external-resources.qdoc | 57 +++++++++++++++++++++ 10 files changed, 128 insertions(+), 48 deletions(-) create mode 100644 examples/webchannel/chatclient-html/doc/images/chatclient-html.png create mode 100644 examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png create mode 100644 examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png create mode 100644 src/webchannel/doc/src/external-resources.qdoc diff --git a/examples/webchannel/chatclient-html/doc/images/chatclient-html.png b/examples/webchannel/chatclient-html/doc/images/chatclient-html.png new file mode 100644 index 0000000..f61c9ec Binary files /dev/null and b/examples/webchannel/chatclient-html/doc/images/chatclient-html.png differ diff --git a/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc b/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc index 497c63f..0a3efb6 100644 --- a/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc +++ b/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc @@ -50,31 +50,36 @@ /*! \example chatclient-html - \title Qt WebChannel Chatclient HTML Example + \title Qt WebChannel ChatClient HTML Example \ingroup qtwebchannel-examples \brief A HTML/JavaScript client that communicates over a WebSocket with a QWebChannel server. - The chatclient-html example provides a simple QWebChannel client implemented using JavaScript and HTML. + \image chatclient-html.png - \section1 Overview + \e{ChatClient HTML} provides a simple QWebChannel client implemented using JavaScript and HTML. + + \section1 Running the Example + + To run the example, open the \c chatclient.html file in a browser. + + \section1 Implementing a Web Channel Client The client initializes a WebSocket connection to the chat server and receives an object - containing all neccessarry signals, slots and properties for implementing a chat client. + containing all the necessary signals, slots, and properties for implementing a chat client. - After login the client can invoke the method \c sendMessage and receive the signal \c newMessage - to send and receive messages. Furthermore there is a \c userList property which provides the - names of all other connected clients. It is automatically updated when its contents change. - Also, the client responds to the servers keep alive signal which is needed to detect disconnected - clients and remove them from the \c userlist property. + After login, the client can invoke the method \c sendMessage and receive the signal \c newMessage + to send and receive messages. Furthermore, a \c userList property provides the names of + all other connected clients. The list is automatically updated when its contents change. + Also, the client responds to the server's keep alive signal which is needed to detect disconnected + clients and remove them from the \c userList property. The example shows how basic elements can be used with the client JavaScript implementation of - QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage) and handle + QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage), and handling property changes (\c userList). - The client is able to work with the chatserver-cpp example. + The client is able to work with \l{Qt WebChannel ChatServer Example}. - To run the example, open the \c chatclient.html in a browser. - \sa {chatserver-cpp}, {chatclient-qml} + \sa {Qt WebChannel ChatServer Example}, {Qt WebChannel ChatClient QML Example} */ diff --git a/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png b/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png new file mode 100644 index 0000000..7f96e26 Binary files /dev/null and b/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png differ diff --git a/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc b/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc index cd029e0..c6e0f32 100644 --- a/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc +++ b/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc @@ -50,32 +50,38 @@ /*! \example chatclient-qml - \title Qt WebChannel Chatclient QML Example + \title Qt WebChannel ChatClient QML Example \ingroup qtwebchannel-examples \brief A QML client that communicates over a WebSocket with a QWebChannel server. - The chatclient-html example provides a simple QWebChannel client implemented using JavaScript and QML. + \image chatclient-qml.png - \section1 Overview + \e{ChatClient QML} provides a simple QWebChannel client implemented using JavaScript and QML. - The client initializes a WebSocket connection to the chat server and receives an object - containing all neccessarry signals, slots and properties for implementing a chat client. + \section1 Running the Example + + To run the example, enter the following command in the client source + directory: + + \c {path/to/qmlscene qmlchatclient.qml} + + \section1 Implementing a Web Channel Client + + The client initializes a \l [QML] WebSocket connection to the chat server and receives an object + containing all the necessary signals, slots, and properties for implementing a chat client. After login, the client can invoke the method \c sendMessage and receive the signal \c newMessage - to send and receive messages. Furthermore, there is a \c userList property which provides the + to send and receive messages. Furthermore, a \c userList property provides the names of all other connected clients. It is automatically updated when its contents change. - Also, the client responds to the servers keep alive signal which is needed to detect disconnected + Also, the client responds to the server's keep alive signal which is needed to detect disconnected clients and remove them from the \c userList property. The example shows how basic elements can be used with the client JavaScript implementation of - QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage) and handle + QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage), and handling property changes (\c userList). - The client is able to work with the chatserver-cpp as server application - - - The example can be run by invoking \c {path/to/qmlscene qmlchatclient.qml}. + The client is able to work with the \l{Qt WebChannel ChatServer Example}. - \sa {chatserver-cpp}, {chatclient-html} + \sa {Qt WebChannel ChatServer Example}, {Qt WebChannel ChatClient HTML Example} */ diff --git a/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png b/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png new file mode 100644 index 0000000..b0f484a Binary files /dev/null and b/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png differ diff --git a/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc b/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc index 06d5b2e..0b198d2 100644 --- a/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc +++ b/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc @@ -50,31 +50,39 @@ /*! \example chatserver-cpp - \title Qt WebChannel Chatserver Example + \title Qt WebChannel ChatServer Example \ingroup qtwebchannel-examples - \brief Shows how to use the QWebChannel C++ API to implement a simple chat server + \brief A simple chat server implemented using the QWebChannel C++ API. - The chatserver examples provides a chat service that client examples can connect to. + \image chatserver-cpp.png - \section1 Overview + \e{ChatServer} provides a chat service that the + \l{Qt WebChannel ChatClient QML Example} and + \l{Qt WebChannel ChatClient HTML Example} can connect to. + + \include examples-run.qdocinc + + \section1 Implementing a Chat Server The C++ application implements a QObject which provides all mechanisms required for a chat service. - This object is published through a QWebChannel which uses a WebSocket as transport. + This object is published through a QWebChannel which uses a \l{Qt WebSockets} + {WebSocket} as transport. The server provides a basic \c login method (username only, no passwords), which must be successfully invoked before a client is able to chat. - After login a client can invoke the method \c sendMessage and receive the signal \c newMessage - to write and receive messages. Furthermore there is a \c userList property which provides + After login, a client can invoke the method \c sendMessage and receive the signal \c newMessage + to write and receive messages. Furthermore, there is a \c userList property which provides the names of all other connected clients. - Additionally the server sends a keepAlive signal periodically to all clients. The clients + Additionally the server sends a \c keepAlive signal periodically to all clients. The clients have to respond to this signal, otherwise the client will be removed from the \c userList property. - The example shows how basic QObject elements can be used with QWebChannel, i.e. signals - (\c newMessage), slots (\c sendMessage) and properties (\c userList). + The example shows how basic QObject elements can be used with QWebChannel, that is signals + (\c newMessage), slots (\c sendMessage), and properties (\c userList). - Because this is a plain server application, there are separated clients needed to interact - with the server. Both examples chatclient-qml and chatclient-html show a client implementation + Because this is a plain server application, separate clients are needed to + interact with it. \l{Qt WebChannel ChatClient QML Example} and + \l{Qt WebChannel ChatClient HTML Example} are client implementations compatible with this server. */ diff --git a/examples/webchannel/standalone/doc/src/standalone.qdoc b/examples/webchannel/standalone/doc/src/standalone.qdoc index 28c67a2..0d030bf 100644 --- a/examples/webchannel/standalone/doc/src/standalone.qdoc +++ b/examples/webchannel/standalone/doc/src/standalone.qdoc @@ -53,26 +53,28 @@ \title Qt WebChannel Standalone Example \ingroup qtwebchannel-examples \image standalone-screenshot.png - \brief Shows how to use the QWebChannel C++ API to communicate with an external client. + \brief A simple chat between a server and a remote client running in a + browser. - The standalone example is a simple chat between a C++ application and a remote HTML - client running in your default browser. + \e{Standalone} demonstrates how to use the QWebChannel C++ API to + communicate with an external client. It is a simple chat between a C++ + application and a remote HTML client running in your default browser. \include examples-run.qdocinc - \section1 Overview + \section1 Communicating with a Remote Client - The C++ application sets up a QWebChannel instance and publishes a Dialog object over it. + The C++ application sets up a QWebChannel instance and publishes a \c Dialog object over it. For the remote client side, \l {standalone/index.html}{index.html} is opened. Both show a dialog with the list of received messages and an input box to send messages to the other end. - The Dialog emits the Dialog::sendText() signal when the user sends a message. The signal + The \c Dialog emits the \c Dialog::sendText() signal when the user sends a message. The signal automatically gets propagated to the HTML client. When the user enters a message on the HTML - side, Dialog::receiveText() is called. + side, \c Dialog::receiveText() is called. All communication between the HTML client and the C++ server is done over a WebSocket. The C++ side instantiates a QWebSocketServer and wraps incoming QWebSocket connections - in WebSocketTransport objects, which implement QWebChannelAbstractTransport. These objects are + in QWebChannelAbstractTransport objects. These objects are then connected to the QWebChannel instance. \sa {Qt WebChannel JavaScript API} diff --git a/src/webchannel/doc/qtwebchannel.qdocconf b/src/webchannel/doc/qtwebchannel.qdocconf index cfb47e4..4026379 100644 --- a/src/webchannel/doc/qtwebchannel.qdocconf +++ b/src/webchannel/doc/qtwebchannel.qdocconf @@ -40,7 +40,7 @@ qhp.QtWebChannel.subprojects.javascript.indexTitle = Qt WebChannel JavaScript tagfile = ../../../doc/qtwebchannel/qtwebchannel.tags -depends += qtcore qtquick qtqml qmake qtdoc +depends += qtcore qtquick qtqml qmake qtdoc qtwebengine qtwebsockets headerdirs += .. \ ../../imports @@ -48,6 +48,7 @@ headerdirs += .. \ sourcedirs += .. \ ../../imports +imagedirs += images exampledirs += ../../../examples/webchannel examples.fileextensions += "*.html *.json" diff --git a/src/webchannel/doc/src/examples.qdoc b/src/webchannel/doc/src/examples.qdoc index b304ac6..83e614e 100644 --- a/src/webchannel/doc/src/examples.qdoc +++ b/src/webchannel/doc/src/examples.qdoc @@ -42,6 +42,7 @@ \group qtwebchannel-examples \brief List of Qt WebChannel examples. - The examples show how to use the QWebChannel C++ and WebChannel QML API. + The examples show how to use the QWebChannel C++ and \l [QML] WebChannel QML + API. */ diff --git a/src/webchannel/doc/src/external-resources.qdoc b/src/webchannel/doc/src/external-resources.qdoc new file mode 100644 index 0000000..0002ec1 --- /dev/null +++ b/src/webchannel/doc/src/external-resources.qdoc @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + The nolink entries prevent autolinking of each occurrence of 'WebChannel' + 'WebEngine' or 'WebSocket' to the QML type. + To link to the QML type, use explicit linking. For example: + \l [QML] WebChannel + \sa {QtWebChannel::}{WebChannel} +*/ +/*! + \externalpage nolink + \title WebChannel + \internal +*/ + +/*! + \externalpage nolink + \title WebEngine + \internal +*/ + +/*! + \externalpage nolink + \title WebSockets + \internal +*/ + +/*! + \externalpage nolink + \title WebSocket + \internal +*/ -- cgit v1.2.1 From 23cd16ad672a3d07da00d14276a63901d8d9f118 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 8 Jun 2016 13:40:01 +0200 Subject: Mention license change in 5.7.0 changelog. Change-Id: I9120c4d9c6cf08cdaaec468a514e2ab060abde35 Task-number: QTBUG-53913 Reviewed-by: Sami Makkonen Reviewed-by: Jani Heikkinen --- dist/changes-5.7.0 | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/dist/changes-5.7.0 b/dist/changes-5.7.0 index 40ce280..b85aa40 100644 --- a/dist/changes-5.7.0 +++ b/dist/changes-5.7.0 @@ -1,6 +1,7 @@ Qt 5.7 introduces many new features and improvements as well as bugfixes -over the 5.6.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: +over the 5.6.x series. Also, there is a change in the licensing terms. +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: http://doc.qt.io/qt-5.7 @@ -15,6 +16,21 @@ corresponding to tasks in the Qt Bug Tracker: Each of these identifiers can be entered in the bug tracker to obtain more information about a particular change. +**************************************************************************** +* Important License Changes * +**************************************************************************** + + This module is no longer available under LGPLv2.1. The libraries are + now available under the following licenses: + * Commercial License + * GNU General Public License v2.0 (LICENSE.GPL2) and later + * GNU Lesser General Public License v3.0 (LICENSE.LGPL3) + + The tools are now available under the following licenses: + * Commercial License + * GNU General Public License 3.0 (LICENSE.GPL3) with exceptions + described in The Qt Company GPL Exception 1.0 (LICENSE.GPL3-EXCEPT) + **************************************************************************** * General * **************************************************************************** -- cgit v1.2.1 From 3be67a7799aa1960d459548a43ddf54044f80ec1 Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Wed, 15 Jun 2016 08:39:01 +0800 Subject: Expand license scope from "Qt GUI Toolkit" to "Qt Toolkit" See http://comments.gmane.org/gmane.comp.lib.qt.devel/25771 Change-Id: I84346b304041f23abe6f1b99d8681199b03e57f4 Reviewed-by: Milian Wolff --- LICENSE.GPLv2 | 2 +- LICENSE.GPLv3 | 2 +- LICENSE.LGPLv21 | 2 +- LICENSE.LGPLv3 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE.GPLv2 b/LICENSE.GPLv2 index 6dbb032..a424477 100644 --- a/LICENSE.GPLv2 +++ b/LICENSE.GPLv2 @@ -3,7 +3,7 @@ The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. Contact: http://www.qt.io/licensing/ - You may use, distribute and copy the Qt GUI Toolkit under the terms of + You may use, distribute and copy the Qt Toolkit under the terms of GNU General Public License version 2, which is displayed below. ------------------------------------------------------------------------- diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3 index 4e49b12..71c4ad4 100644 --- a/LICENSE.GPLv3 +++ b/LICENSE.GPLv3 @@ -3,7 +3,7 @@ The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. Contact: http://www.qt.io/licensing/ - You may use, distribute and copy the Qt GUI Toolkit under the terms of + You may use, distribute and copy the Qt Toolkit under the terms of GNU Lesser General Public License version 3. That license references the General Public License version 3, that is displayed below. Other portions of the Qt Toolkit may be licensed directly under this license. diff --git a/LICENSE.LGPLv21 b/LICENSE.LGPLv21 index 6e18461..dfcab5e 100644 --- a/LICENSE.LGPLv21 +++ b/LICENSE.LGPLv21 @@ -3,7 +3,7 @@ The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. Contact: http://www.qt.io/licensing/ - You may use, distribute and copy the Qt GUI Toolkit under the terms of + You may use, distribute and copy the Qt Toolkit under the terms of GNU Lesser General Public License version 2.1, which is displayed below. ------------------------------------------------------------------------- diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3 index 4d67bac..6bf924c 100644 --- a/LICENSE.LGPLv3 +++ b/LICENSE.LGPLv3 @@ -3,7 +3,7 @@ The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. Contact: http://www.qt.io/licensing/ - You may use, distribute and copy the Qt GUI Toolkit under the terms of + You may use, distribute and copy the Qt Toolkit under the terms of GNU Lesser General Public License version 3, which is displayed below. This license makes reference to the version 3 of the GNU General Public License, which you can find in the LICENSE.GPLv3 file. -- cgit v1.2.1 From f48e8c9711fbeb350ccf70f852ce3732844d4287 Mon Sep 17 00:00:00 2001 From: Kai Dohmen Date: Mon, 11 Apr 2016 19:38:50 +0200 Subject: Make passing objects from website to server possible If you get an object from the server and want to pass it back to the server via a function the id of the object is passed instead of the whole json object. On the server side QMetaObjectPublisher::invokeMethod now looks up the object in QMetaObjectPublisher::wrappedObjects by the passed object-id. Task-number: QTBUG-50075 Change-Id: Id0df2dfaa79bcba12ca48391ae7537ac1a086898 Reviewed-by: Milian Wolff --- src/webchannel/qmetaobjectpublisher.cpp | 63 ++++++++++++++++++++------------ src/webchannel/qmetaobjectpublisher_p.h | 4 ++ src/webchannel/qwebchannel.js | 16 ++++++-- tests/auto/webchannel/tst_webchannel.cpp | 50 +++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 16 ++++++++ 5 files changed, 122 insertions(+), 27 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index 0fa4ae2..b3fc53d 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -87,29 +87,6 @@ QJsonObject createResponse(const QJsonValue &id, const QJsonValue &data) /// TODO: what is the proper value here? const int PROPERTY_UPDATE_INTERVAL = 50; - -QVariant toVariant(const QJsonValue &value, int targetType) -{ - if (targetType == QMetaType::QJsonValue) { - return QVariant::fromValue(value); - } else if (targetType == QMetaType::QJsonArray) { - if (!value.isArray()) - qWarning() << "Cannot not convert non-array argument" << value << "to QJsonArray."; - return QVariant::fromValue(value.toArray()); - } else if (targetType == QMetaType::QJsonObject) { - if (!value.isObject()) - qWarning() << "Cannot not convert non-object argument" << value << "to QJsonObject."; - return QVariant::fromValue(value.toObject()); - } - - // this converts QJsonObjects to QVariantMaps, which is not desired when - // we want to get a QJsonObject or QJsonValue (see above) - QVariant variant = value.toVariant(); - if (targetType != QMetaType::QVariant && !variant.convert(targetType)) { - qWarning() << "Could not convert argument" << value << "to target type" << QVariant::typeToName(targetType) << '.'; - } - return variant; -} } QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel) @@ -472,6 +449,46 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object) pendingPropertyUpdates.remove(object); } +QObject *QMetaObjectPublisher::unwrapObject(const QString &objectId) const +{ + if (!objectId.isEmpty()) { + ObjectInfo objectInfo = wrappedObjects.value(objectId); + if (objectInfo.object && !objectInfo.classinfo.isEmpty()) + return objectInfo.object; + } + + qWarning() << "No wrapped object" << objectId; + return Q_NULLPTR; +} + +QVariant QMetaObjectPublisher::toVariant(const QJsonValue &value, int targetType) const +{ + if (targetType == QMetaType::QJsonValue) { + return QVariant::fromValue(value); + } else if (targetType == QMetaType::QJsonArray) { + if (!value.isArray()) + qWarning() << "Cannot not convert non-array argument" << value << "to QJsonArray."; + return QVariant::fromValue(value.toArray()); + } else if (targetType == QMetaType::QJsonObject) { + if (!value.isObject()) + qWarning() << "Cannot not convert non-object argument" << value << "to QJsonObject."; + return QVariant::fromValue(value.toObject()); + } else if (QMetaType::typeFlags(targetType) & QMetaType::PointerToQObject) { + QObject *unwrappedObject = unwrapObject(value.toObject()[KEY_ID].toString()); + if (unwrappedObject == Q_NULLPTR) + qWarning() << "Cannot not convert non-object argument" << value << "to QObject*."; + return QVariant::fromValue(unwrappedObject); + } + + // this converts QJsonObjects to QVariantMaps, which is not desired when + // we want to get a QJsonObject or QJsonValue (see above) + QVariant variant = value.toVariant(); + if (targetType != QMetaType::QVariant && !variant.convert(targetType)) { + qWarning() << "Could not convert argument" << value << "to target type" << QVariant::typeToName(targetType) << '.'; + } + return variant; +} + // 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 diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index b0ebd84..048a33c 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -166,6 +166,10 @@ public: */ void objectDestroyed(const QObject *object); + QObject *unwrapObject(const QString &objectId) const; + + QVariant toVariant(const QJsonValue &value, int targetType) const; + /** * Given a QVariant containing a QObject*, wrap the object and register for property updates * return the objects class information. diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js index d8c28bc..148e70d 100644 --- a/src/webchannel/qwebchannel.js +++ b/src/webchannel/qwebchannel.js @@ -324,10 +324,15 @@ function QObject(name, data, webChannel) var args = []; var callback; for (var i = 0; i < arguments.length; ++i) { - if (typeof arguments[i] === "function") - callback = arguments[i]; + 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(arguments[i]); + args.push(argument); } webChannel.exec({ @@ -381,11 +386,14 @@ function QObject(name, data, webChannel) return; } 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__, "property": propertyIndex, - "value": value + "value": valueToSend }); } }); diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 93c7aa8..7ae6f78 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -343,6 +343,12 @@ void TestWebChannel::testInfoForObject() method.append(obj.metaObject()->indexOfMethod("slot2(QString)")); expected.append(method); } + { + QJsonArray method; + method.append(QStringLiteral("setReturnedObject")); + method.append(obj.metaObject()->indexOfMethod("setReturnedObject(TestObject*)")); + expected.append(method); + } { QJsonArray method; method.append(QStringLiteral("setObjectProperty")); @@ -446,6 +452,19 @@ void TestWebChannel::testInfoForObject() property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.objectProperty()))); expected.append(property); } + { + QJsonArray property; + property.append(obj.metaObject()->indexOfProperty("returnedObject")); + property.append(QStringLiteral("returnedObject")); + { + QJsonArray signal; + signal.append(1); + signal.append(obj.metaObject()->indexOfMethod("returnedObjectChanged()")); + property.append(signal); + } + property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.returnedObject()))); + expected.append(property); + } QCOMPARE(info["properties"].toArray(), expected); } } @@ -587,6 +606,36 @@ void TestWebChannel::testWrapRegisteredObject() QCOMPARE(obj.objectName(), returnedId); } +void TestWebChannel::testPassWrappedObjectBack() +{ + QWebChannel channel; + TestObject registeredObj; + TestObject returnedObjMethod; + TestObject returnedObjProperty; + + registeredObj.setObjectName("registeredObject"); + + channel.registerObject(registeredObj.objectName(), ®isteredObj); + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QMetaObjectPublisher *pub = channel.d_func()->publisher; + QJsonObject returnedObjMethodInfo = pub->wrapResult(QVariant::fromValue(&returnedObjMethod), m_dummyTransport).toObject(); + QJsonObject returnedObjPropertyInfo = pub->wrapResult(QVariant::fromValue(&returnedObjProperty), m_dummyTransport).toObject(); + + QJsonArray argsMethod; + QJsonObject argMethod0; + argMethod0["id"] = returnedObjMethodInfo["id"]; + argsMethod << argMethod0; + QJsonObject argProperty; + argProperty["id"] = returnedObjPropertyInfo["id"]; + + pub->invokeMethod(®isteredObj, registeredObj.metaObject()->indexOfSlot("setReturnedObject(TestObject*)"), argsMethod); + QCOMPARE(registeredObj.mReturnedObject, &returnedObjMethod); + pub->setProperty(®isteredObj, registeredObj.metaObject()->indexOfProperty("returnedObject"), argProperty); + QCOMPARE(registeredObj.mReturnedObject, &returnedObjProperty); +} + void TestWebChannel::testInfiniteRecursion() { QWebChannel channel; @@ -739,6 +788,7 @@ void TestWebChannel::qtbug46548_overriddenProperties() #endif // WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE } + QTEST_MAIN(TestWebChannel) #include "tst_webchannel.moc" diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index 13294c2..5a9fa11 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -73,11 +73,13 @@ class TestObject : public QObject Q_PROPERTY(int asdf READ asdf NOTIFY asdfChanged) Q_PROPERTY(QString bar READ bar NOTIFY theBarHasChanged) Q_PROPERTY(QObject * objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectPropertyChanged) + Q_PROPERTY(TestObject * returnedObject READ returnedObject WRITE setReturnedObject NOTIFY returnedObjectChanged) public: explicit TestObject(QObject *parent = 0) : QObject(parent) , mObjectProperty(0) + , mReturnedObject(Q_NULLPTR) { } enum Foo { @@ -94,6 +96,11 @@ public: return mObjectProperty; } + TestObject *returnedObject() const + { + return mReturnedObject; + } + Q_INVOKABLE void method1() {} protected: @@ -108,11 +115,18 @@ signals: void asdfChanged(); void theBarHasChanged(); void objectPropertyChanged(); + void returnedObjectChanged(); public slots: void slot1() {} void slot2(const QString&) {} + void setReturnedObject(TestObject *obj) + { + mReturnedObject = obj; + emit returnedObjectChanged(); + } + void setObjectProperty(QObject *object) { mObjectProperty = object; @@ -127,6 +141,7 @@ private slots: public: QObject *mObjectProperty; + TestObject *mReturnedObject; }; class BenchObject : public QObject @@ -264,6 +279,7 @@ private slots: void testSetPropertyConversion(); void testDisconnect(); void testWrapRegisteredObject(); + void testPassWrappedObjectBack(); void testInfiniteRecursion(); void benchClassInfo(); -- cgit v1.2.1 From d3c594c382761241742cd6713f249abeb538ffaa Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 21 Jun 2016 11:30:03 +0200 Subject: Properly unwrap QObject signal parameters on the JavaScript side. This enables you to pass `QObject*` parameters via signals to the JavaScript side. The object will be serialized and then unwrapped as needed now. Task-number: QTBUG-54243 Change-Id: Ie8a6d14eb1351f14f1855d242ceb3b3f8262152d Reviewed-by: Andreas Holzammer --- src/webchannel/qwebchannel.js | 2 +- tests/auto/qml/tst_webchannel.qml | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js index 148e70d..b1722df 100644 --- a/src/webchannel/qwebchannel.js +++ b/src/webchannel/qwebchannel.js @@ -313,7 +313,7 @@ function QObject(name, data, webChannel) this.signalEmitted = function(signalName, signalArgs) { - invokeSignalCallbacks(signalName, signalArgs); + invokeSignalCallbacks(signalName, this.unwrapQObject(signalArgs)); } function addMethod(methodData) diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml index f1042ca..6cb24b0 100644 --- a/tests/auto/qml/tst_webchannel.qml +++ b/tests/auto/qml/tst_webchannel.qml @@ -51,7 +51,7 @@ TestCase { id: myObj property int myProperty: 1 - signal mySignal(var arg) + signal mySignal(var arg, QtObject object) function myMethod(arg) { @@ -174,9 +174,11 @@ TestCase { function test_signal() { var signalReceivedArg; + var signalReceivedObject; var channel = client.createChannel(function(channel) { - channel.objects.myObj.mySignal.connect(function(arg) { + channel.objects.myObj.mySignal.connect(function(arg, object) { signalReceivedArg = arg; + signalReceivedObject = object; }); }); client.awaitInit(); @@ -187,9 +189,16 @@ TestCase { client.awaitIdle(); // initialization - myObj.mySignal("test"); + myObj.mySignal("test", myObj); compare(signalReceivedArg, "test"); + compare(signalReceivedObject.__id__, "myObj"); + + var newObj = myFactory.create("newObj"); + myObj.mySignal(newObj, newObj); + + compare(signalReceivedArg.objectName, newObj.objectName); + compare(signalReceivedObject.objectName, newObj.objectName); } function test_grouping() @@ -393,14 +402,14 @@ TestCase { client.awaitIdle(); - myObj.mySignal(42); + myObj.mySignal(42, myObj); compare(signalArg, 42); msg = client.awaitMessage(); compare(msg.type, JSClient.QWebChannelMessageTypes.disconnectFromSignal); compare(msg.object, "myObj"); - myObj.mySignal(0); + myObj.mySignal(0, myObj); compare(signalArg, 42); } } -- cgit v1.2.1 From e35346cf70598c47a456946327927643910aa277 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Thu, 16 Jun 2016 12:46:42 +0200 Subject: Add test to verify that bools get properly converted. This test passes and seems to indicate that the signal-delivery has an issue, or that the issue lies on the JavaScript side. Change-Id: Ic2436147b3af49d35dc556da57aed3e54408f1f9 Task-number: QTBUG-54074 Reviewed-by: Frederik Gladhorn --- tests/auto/webchannel/tst_webchannel.cpp | 28 ++++++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 5 +++++ 2 files changed, 33 insertions(+) diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 7ae6f78..71779b9 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -192,6 +192,7 @@ TestWebChannel::TestWebChannel(QObject *parent) : QObject(parent) , m_dummyTransport(new DummyTransport(this)) , m_lastInt(0) + , m_lastBool(false) , m_lastDouble(0) { } @@ -200,6 +201,7 @@ TestWebChannel::~TestWebChannel() { } + int TestWebChannel::readInt() const { return m_lastInt; @@ -211,6 +213,17 @@ void TestWebChannel::setInt(int i) emit lastIntChanged(); } +bool TestWebChannel::readBool() const +{ + return m_lastBool; +} + +void TestWebChannel::setBool(bool b) +{ + m_lastBool = b; + emit lastBoolChanged(); +} + double TestWebChannel::readDouble() const { return m_lastDouble; @@ -483,6 +496,14 @@ void TestWebChannel::testInvokeMethodConversion() channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastInt, args.at(0).toInt()); } + { + int method = metaObject()->indexOfMethod("setBool(bool)"); + QVERIFY(method != -1); + QJsonArray args; + args.append(QJsonValue(!m_lastBool)); + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastBool, args.at(0).toBool()); + } { int method = metaObject()->indexOfMethod("setDouble(double)"); QVERIFY(method != -1); @@ -534,6 +555,13 @@ void TestWebChannel::testSetPropertyConversion() channel.d_func()->publisher->setProperty(this, property, QJsonValue(42)); QCOMPARE(m_lastInt, 42); } + { + int property = metaObject()->indexOfProperty("lastBool"); + QVERIFY(property != -1); + bool newValue = !m_lastBool; + channel.d_func()->publisher->setProperty(this, property, QJsonValue(newValue)); + QCOMPARE(m_lastBool, newValue); + } { int property = metaObject()->indexOfProperty("lastDouble"); QVERIFY(property != -1); diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index 5a9fa11..3469d41 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -241,6 +241,7 @@ class TestWebChannel : public QObject Q_OBJECT Q_PROPERTY(int lastInt READ readInt WRITE setInt NOTIFY lastIntChanged); + Q_PROPERTY(bool lastBool READ readBool WRITE setBool NOTIFY lastBoolChanged); Q_PROPERTY(double lastDouble READ readDouble WRITE setDouble NOTIFY lastDoubleChanged); Q_PROPERTY(QVariant lastVariant READ readVariant WRITE setVariant NOTIFY lastVariantChanged); Q_PROPERTY(QJsonValue lastJsonValue READ readJsonValue WRITE setJsonValue NOTIFY lastJsonValueChanged); @@ -252,6 +253,8 @@ public: int readInt() const; Q_INVOKABLE void setInt(int i); + bool readBool() const; + Q_INVOKABLE void setBool(bool b); double readDouble() const; Q_INVOKABLE void setDouble(double d); QVariant readVariant() const; @@ -265,6 +268,7 @@ public: signals: void lastIntChanged(); + void lastBoolChanged(); void lastDoubleChanged(); void lastVariantChanged(); void lastJsonValueChanged(); @@ -293,6 +297,7 @@ private: DummyTransport *m_dummyTransport; int m_lastInt; + bool m_lastBool; double m_lastDouble; QVariant m_lastVariant; QJsonValue m_lastJsonValue; -- cgit v1.2.1