summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2016-07-20 16:27:47 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2016-07-21 16:44:49 +0200
commit91ebebdbf26907c126dcc367832ed524d64b94cf (patch)
treed9d4fee39a1fa88a2eb8ff90bcde6ec248550311
parentfa2374d7c4dedea907e2df26fdad28bdee73b122 (diff)
parent3836fd7d12777fc53836a72d6542d2fbf2f20ac9 (diff)
downloadqtwebchannel-91ebebdbf26907c126dcc367832ed524d64b94cf.tar.gz
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts: src/webchannel/doc/src/index.qdoc src/webchannel/qwebchannelabstracttransport.cpp Overlapping changes to documentation; constructed hybrid. src/webchannel/qmetaobjectpublisher.cpp tests/auto/webchannel/tst_webchannel.cpp tests/auto/webchannel/tst_webchannel.h Both sides made additions; in the same place. Change-Id: Iff12970978b70946dc3e1290841aca2d35c9c1d0
-rw-r--r--.qmake.conf2
-rw-r--r--LICENSE.GPLv22
-rw-r--r--LICENSE.GPLv32
-rw-r--r--LICENSE.LGPLv212
-rw-r--r--LICENSE.LGPLv32
-rw-r--r--dist/changes-5.7.020
-rw-r--r--examples/webchannel/chatclient-html/doc/images/chatclient-html.pngbin0 -> 7284 bytes
-rw-r--r--examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc31
-rw-r--r--examples/webchannel/chatclient-qml/doc/images/chatclient-qml.pngbin0 -> 5018 bytes
-rw-r--r--examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc32
-rw-r--r--examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.pngbin0 -> 6829 bytes
-rw-r--r--examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc32
-rw-r--r--examples/webchannel/standalone/doc/src/standalone.qdoc18
-rw-r--r--src/webchannel/doc/qtwebchannel.qdocconf3
-rw-r--r--src/webchannel/doc/src/examples.qdoc3
-rw-r--r--src/webchannel/doc/src/external-resources.qdoc57
-rw-r--r--src/webchannel/doc/src/index.qdoc42
-rw-r--r--src/webchannel/doc/src/javascript.qdoc17
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp66
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h9
-rw-r--r--src/webchannel/qqmlwebchannel.cpp21
-rw-r--r--src/webchannel/qwebchannel.cpp10
-rw-r--r--src/webchannel/qwebchannel.js18
-rw-r--r--src/webchannel/qwebchannelabstracttransport.cpp7
-rw-r--r--tests/auto/qml/tst_webchannel.qml19
-rw-r--r--tests/auto/webchannel/tst_webchannel.cpp205
-rw-r--r--tests/auto/webchannel/tst_webchannel.h51
27 files changed, 556 insertions, 115 deletions
diff --git a/.qmake.conf b/.qmake.conf
index a1a840c..556f554 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.8.0
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.
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
@@ -16,6 +17,21 @@ 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 *
****************************************************************************
- This release contains only minor improvements.
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
--- /dev/null
+++ b/examples/webchannel/chatclient-html/doc/images/chatclient-html.png
Binary files 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
--- /dev/null
+++ b/examples/webchannel/chatclient-qml/doc/images/chatclient-qml.png
Binary files 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
--- /dev/null
+++ b/examples/webchannel/chatserver-cpp/doc/images/chatserver-cpp.png
Binary files 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
+*/
diff --git a/src/webchannel/doc/src/index.qdoc b/src/webchannel/doc/src/index.qdoc
index a4eaad0..5529093 100644
--- a/src/webchannel/doc/src/index.qdoc
+++ b/src/webchannel/doc/src/index.qdoc
@@ -31,25 +31,49 @@
\title Qt WebChannel
\brief Bridges the gap between Qt applications and HTML/JavaScript.
- Qt WebChannel enables peer-to-peer communication between a host
- (QML/C++ application) and a client (HTML/JavaScript application).
- It is supported out of the box by Qt WebKit 2 and Qt WebEngine.
- In addition it can work on all
- browsers that support WebSockets, enabling Qt WebChannel clients
- to run in any JavaScript environment (including QML). This requires
+ Qt WebChannel enables peer-to-peer communication between a server (QML/C++
+ application) and a client (HTML/JavaScript or QML application). It is
+ supported out of the box by \l{Qt WebEngine}. In addition it can work on all
+ browsers that support \l{Qt WebSockets}{WebSockets}, enabling Qt WebChannel
+ clients to run in any JavaScript environment (including QML). This requires
the implementation of a custom transport based on Qt WebSockets.
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 <QtWebChannel/QtWebChannel>
+ \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
*/
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/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index 8fd8e4f..66676f0 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -372,11 +372,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
@@ -397,6 +393,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()) {
@@ -449,6 +455,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;
+}
+
void QMetaObjectPublisher::transportRemoved(QWebChannelAbstractTransport *transport)
{
auto it = transportedWrappedObjects.find(transport);
@@ -618,14 +664,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 fe75656..830e510 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -156,6 +156,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.
*/
void signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments);
@@ -167,6 +172,10 @@ public:
*/
void objectDestroyed(const QObject *object);
+ QObject *unwrapObject(const QString &objectId) const;
+
+ QVariant toVariant(const QJsonValue &value, int targetType) const;
+
/**
* Remove wrapped objects which last transport relation is with the passed transport object.
*/
diff --git a/src/webchannel/qqmlwebchannel.cpp b/src/webchannel/qqmlwebchannel.cpp
index 264bc54..d23ebef 100644
--- a/src/webchannel/qqmlwebchannel.cpp
+++ b/src/webchannel/qqmlwebchannel.cpp
@@ -69,7 +69,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()
*/
/*!
@@ -77,7 +77,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.
@@ -86,7 +86,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
@@ -134,8 +134,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.
@@ -143,7 +143,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)
{
@@ -167,11 +167,12 @@ 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.
- \sa WebChannel::transports, WebChannel::disconnectFrom()
+ \sa transports, disconnectFrom()
*/
void QQmlWebChannel::connectTo(QObject *transport)
{
@@ -185,12 +186,12 @@ 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.
- \sa WebChannel::connectTo()
+ \sa connectTo()
*/
void QQmlWebChannel::disconnectFrom(QObject *transport)
{
diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp
index 7a63af9..0e9a4c5 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -52,7 +52,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
@@ -69,7 +69,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}
*/
@@ -138,7 +138,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.
@@ -168,7 +168,7 @@ QHash<QString, QObject *> 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.
@@ -184,7 +184,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/qwebchannel.js b/src/webchannel/qwebchannel.js
index d39e301..5b047c2 100644
--- a/src/webchannel/qwebchannel.js
+++ b/src/webchannel/qwebchannel.js
@@ -319,7 +319,7 @@ function QObject(name, data, webChannel)
this.signalEmitted = function(signalName, signalArgs)
{
- invokeSignalCallbacks(signalName, signalArgs);
+ invokeSignalCallbacks(signalName, this.unwrapQObject(signalArgs));
}
function addMethod(methodData)
@@ -330,10 +330,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({
@@ -387,11 +392,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/src/webchannel/qwebchannelabstracttransport.cpp b/src/webchannel/qwebchannelabstracttransport.cpp
index d1b7199..86a9c18 100644
--- a/src/webchannel/qwebchannelabstracttransport.cpp
+++ b/src/webchannel/qwebchannelabstracttransport.cpp
@@ -50,9 +50,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 \l {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.
@@ -69,7 +68,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.
*/
diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml
index 403cc4b..5e28db3 100644
--- a/tests/auto/qml/tst_webchannel.qml
+++ b/tests/auto/qml/tst_webchannel.qml
@@ -46,7 +46,7 @@ TestCase {
id: myObj
property int myProperty: 1
- signal mySignal(var arg)
+ signal mySignal(var arg, QtObject object)
function myMethod(arg)
{
@@ -169,9 +169,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();
@@ -182,9 +184,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()
@@ -388,14 +397,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);
}
}
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index 9531c6f..0fe742f 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -187,6 +187,7 @@ TestWebChannel::TestWebChannel(QObject *parent)
: QObject(parent)
, m_dummyTransport(new DummyTransport(this))
, m_lastInt(0)
+ , m_lastBool(false)
, m_lastDouble(0)
{
}
@@ -196,19 +197,81 @@ TestWebChannel::~TestWebChannel()
}
+int TestWebChannel::readInt() const
+{
+ return m_lastInt;
+}
+
void TestWebChannel::setInt(int i)
{
m_lastInt = 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;
}
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_lastJsonObject = v;
+ emit lastJsonObjectChanged();
+}
+
+QJsonArray TestWebChannel::readJsonArray() const
+{
+ return m_lastJsonArray;
+}
+
+void TestWebChannel::setJsonArray(const QJsonArray& v)
+{
+ m_lastJsonArray = v;
+ emit lastJsonArrayChanged();
}
void TestWebChannel::testRegisterObjects()
@@ -290,6 +353,12 @@ void TestWebChannel::testInfoForObject()
}
{
QJsonArray method;
+ method.append(QStringLiteral("setReturnedObject"));
+ method.append(obj.metaObject()->indexOfMethod("setReturnedObject(TestObject*)"));
+ expected.append(method);
+ }
+ {
+ QJsonArray method;
method.append(QStringLiteral("setObjectProperty"));
method.append(obj.metaObject()->indexOfMethod("setObjectProperty(QObject*)"));
expected.append(method);
@@ -391,6 +460,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);
}
}
@@ -410,6 +492,14 @@ void TestWebChannel::testInvokeMethodConversion()
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);
channel.d_func()->publisher->invokeMethod(this, method, args);
@@ -421,6 +511,90 @@ 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_lastJsonObject, 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_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("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);
+ 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);
+ }
}
void TestWebChannel::testDisconnect()
@@ -455,6 +629,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(), &registeredObj);
+ 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(&registeredObj, registeredObj.metaObject()->indexOfSlot("setReturnedObject(TestObject*)"), argsMethod);
+ QCOMPARE(registeredObj.mReturnedObject, &returnedObjMethod);
+ pub->setProperty(&registeredObj, registeredObj.metaObject()->indexOfProperty("returnedObject"), argProperty);
+ QCOMPARE(registeredObj.mReturnedObject, &returnedObjProperty);
+}
+
void TestWebChannel::testRemoveUnusedTransports()
{
QWebChannel channel;
@@ -660,6 +864,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 0d2fe55..a587499 100644
--- a/tests/auto/webchannel/tst_webchannel.h
+++ b/tests/auto/webchannel/tst_webchannel.h
@@ -31,6 +31,9 @@
#include <QObject>
#include <QVariant>
+#include <QJsonValue>
+#include <QJsonObject>
+#include <QJsonArray>
#include <QtWebChannel/QWebChannelAbstractTransport>
@@ -65,11 +68,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 {
@@ -86,6 +91,11 @@ public:
return mObjectProperty;
}
+ TestObject *returnedObject() const
+ {
+ return mReturnedObject;
+ }
+
Q_INVOKABLE void method1() {}
protected:
@@ -100,11 +110,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;
@@ -119,6 +136,7 @@ private slots:
public:
QObject *mObjectProperty;
+ TestObject *mReturnedObject;
};
class BenchObject : public QObject
@@ -217,21 +235,50 @@ 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);
+ 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);
+ bool readBool() const;
+ Q_INVOKABLE void setBool(bool b);
+ 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 lastBoolChanged();
+ 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 testPassWrappedObjectBack();
void testRemoveUnusedTransports();
void testInfiniteRecursion();
@@ -247,8 +294,12 @@ private:
DummyTransport *m_dummyTransport;
int m_lastInt;
+ bool m_lastBool;
double m_lastDouble;
QVariant m_lastVariant;
+ QJsonValue m_lastJsonValue;
+ QJsonObject m_lastJsonObject;
+ QJsonArray m_lastJsonArray;
};
QT_END_NAMESPACE