120 |
121 |
122 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/licenseRule.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "comment": ["file_pattern_ending: strings matched against the end of a file name.",
4 | "location keys: regular expression matched against the beginning of",
5 | "the file path (relative to the git submodule root).",
6 | "spdx: list of SPDX-License-Expression's allowed in the matching files.",
7 | "-------------------------------------------------------",
8 | "Files with the following endings are Build System licensed,",
9 | "unless they are examples",
10 | "Files with other endings can also be build system files"
11 | ],
12 | "file_pattern_ending": ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf",
13 | "configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in",
14 | ".cmake.conf", ".tag", "ci_config_linux.json",
15 | ".yaml", "BLACKLIST", ".cfg"],
16 | "location": {
17 | "": {
18 | "comment": "Default",
19 | "file type": "build system",
20 | "spdx": ["BSD-3-Clause"]
21 | },
22 | "(.*)(examples/|snippets/)": {
23 | "comment": "Example takes precedence",
24 | "file type": "examples and snippets",
25 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
26 | }
27 | }
28 | },
29 | {
30 | "comments": ["Files with the following endings are infrastructure licensed"],
31 | "file_pattern_ending": [".gitattributes", ".gitignore", ".gitmodules", ".gitreview",
32 | "clang-format", "licenseRule.json", "REUSE.toml"],
33 | "location":{
34 | "": {
35 | "comment": "Default",
36 | "file type": "infrastructure",
37 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
38 | }
39 | }
40 | },
41 | {
42 | "comments": ["Files with the following endings are Tool licensed,",
43 | "unless they are examples.",
44 | "Files with other endings can also be tool files."],
45 | "file_pattern_ending": [".sh", ".py", ".pl", ".bat", ".ps1"],
46 | "location":{
47 | "": {
48 | "comment": "Default",
49 | "file type": "tools and utils",
50 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"]
51 | },
52 | "(.*)(examples/|snippets/)": {
53 | "comment": "Example takes precedence",
54 | "file type": "examples and snippets",
55 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
56 | }
57 | }
58 | },
59 | {
60 | "comment": "Files with the following endings are Documentation licensed.",
61 | "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", "qt_attribution.json",
62 | "README.md"],
63 | "location":{
64 | "": {
65 | "comment": "",
66 | "file type": "documentation",
67 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
68 | }
69 | }
70 | },
71 | {
72 | "comment": ["All other files",
73 | "The licensing is defined only by the file location in the Qt module repository.",
74 | "NO key for this case!",
75 | "This needs to be the last entry of the file."],
76 | "location": {
77 | "": {
78 | "comment": "Default",
79 | "file type": "module and plugin",
80 | "spdx": ["LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only"]
81 | },
82 | "dist/": {
83 | "comment": "Default",
84 | "file type": "documentation",
85 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
86 | },
87 | "src/": {
88 | "comment": "Default",
89 | "file type": "module and plugin",
90 | "spdx": ["LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only"]
91 | },
92 | "tests/": {
93 | "comment": "Default",
94 | "file type": "test",
95 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
96 | },
97 | "(.*)(examples/|snippets/)": {
98 | "comment": "Default",
99 | "file type": "examples and snippets",
100 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
101 | },
102 | "(.*|examples).*/doc/images": {
103 | "comment": "Default",
104 | "file type": "documentation",
105 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
106 | },
107 | "examples/webchannel/shared/qwebchannel\\.js": {
108 | "comment": "Exception, copyright not only Qt (to be confirmed)",
109 | "file type": "examples and snippets",
110 | "spdx": ["LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only"]
111 | }
112 | }
113 | }
114 | ]
115 |
--------------------------------------------------------------------------------
/examples/webchannel/chatclient-qml/qmlchatclient.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2017 The Qt Company Ltd.
2 | // Copyright (C) 2016 basysKom GmbH, author Bernd Lamecker
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
4 |
5 | import QtQuick
6 | import QtQuick.Dialogs
7 | import QtQuick.Controls
8 | import QtQuick.Layouts
9 | import QtWebSockets
10 | import "qrc:/qwebchannel.js" as WebChannel
11 |
12 | ApplicationWindow {
13 | id: root
14 |
15 | property var channel
16 | property string loginName: loginUi.userName.text
17 | property bool loggedIn: false
18 |
19 | title: "Chat client"
20 | width: 640
21 | height: 480
22 | visible: true
23 |
24 | WebSocket {
25 | id: socket
26 |
27 | // the following three properties/functions are required to align the QML WebSocket API
28 | // with the HTML5 WebSocket API.
29 | property var send: function(arg) {
30 | sendTextMessage(arg);
31 | }
32 |
33 | onTextMessageReceived: function(message) {
34 | onmessage({data: message});
35 | }
36 |
37 | property var onmessage
38 |
39 | active: true
40 | url: "ws://localhost:12345"
41 |
42 | onStatusChanged: {
43 | switch (socket.status) {
44 | case WebSocket.Error:
45 | errorDialog.text = "Error: " + socket.errorString;
46 | errorDialog.visible = true;
47 | break;
48 | case WebSocket.Closed:
49 | errorDialog.text = "Error: Socket at " + url + " closed.";
50 | errorDialog.visible = true;
51 | break;
52 | case WebSocket.Open:
53 | //open the webchannel with the socket as transport
54 | new WebChannel.QWebChannel(socket, function(ch) {
55 | root.channel = ch;
56 |
57 | //connect to the changed signal of the userList property
58 | ch.objects.chatserver.userListChanged.connect(function(args) {
59 | mainUi.userlist.text = '';
60 | ch.objects.chatserver.userList.forEach(function(user) {
61 | mainUi.userlist.text += user + '\n';
62 | });
63 | });
64 |
65 | //connect to the newMessage signal
66 | ch.objects.chatserver.newMessage.connect(function(time, user, message) {
67 | var line = "[" + time + "] " + user + ": " + message + '\n';
68 | mainUi.chat.text = mainUi.chat.text + line;
69 | });
70 |
71 | //connect to the keep alive signal
72 | ch.objects.chatserver.keepAlive.connect(function(args) {
73 | if (loginName !== '' && root.loggedIn)
74 | //and call the keep alive response method as an answer
75 | ch.objects.chatserver.keepAliveResponse(loginName);
76 | });
77 | });
78 |
79 | loginWindow.show();
80 | break;
81 | }
82 | }
83 | }
84 |
85 | MainForm {
86 | id: mainUi
87 | anchors.fill: parent
88 |
89 | Connections {
90 | target: mainUi.message
91 | function onEditingFinished() {
92 | if (mainUi.message.text.length) {
93 | //call the sendMessage method to send the message
94 | root.channel.objects.chatserver.sendMessage(loginName,
95 | mainUi.message.text);
96 | }
97 | mainUi.message.text = '';
98 | }
99 | }
100 | }
101 |
102 | ApplicationWindow {
103 | id: loginWindow
104 |
105 | title: "Login"
106 | modality: Qt.ApplicationModal
107 | flags: Qt.CustomizeWindowHint | Qt.WindowTitleHint
108 | width: 300
109 | height: 200
110 |
111 | LoginForm {
112 | id: loginUi
113 | anchors.fill: parent
114 |
115 | nameInUseError.visible: false
116 |
117 | Connections {
118 | target: loginUi.loginButton
119 |
120 | function onClicked() {
121 | if (loginName === '')
122 | return;
123 | //call the login method
124 | root.channel.objects.chatserver.login(loginName, function(arg) {
125 | //check the return value for success
126 | if (arg === true) {
127 | loginUi.nameInUseError.visible = false;
128 | loginWindow.close();
129 | root.loggedIn = true;
130 | } else {
131 | loginUi.nameInUseError.visible = true;
132 | }
133 | });
134 | }
135 | }
136 | }
137 | }
138 |
139 | Dialog {
140 | id: errorDialog
141 | property alias text: message.text
142 |
143 | anchors.centerIn: parent
144 | standardButtons: Dialog.Close
145 | title: "Chat client"
146 | width: parent.width / 2
147 |
148 | Label {
149 | id: message
150 | }
151 |
152 | onAccepted: {
153 | Qt.quit();
154 | }
155 | onRejected: {
156 | Qt.quit();
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/tests/auto/qml/data/tst_multiclient.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff
2 | // Copyright (C) 2016 basysKom GmbH, info@basyskom.com, author Lutz Schönemann
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4 |
5 | import QtQuick
6 | import QtTest
7 |
8 | import QtWebChannel
9 | import QtWebChannel.Tests
10 |
11 | import "qrc:///qtwebchannel/qwebchannel.js" as JSClient
12 |
13 | TestCase {
14 | name: "MultiClient"
15 |
16 | Client {
17 | id: client1
18 | }
19 |
20 | Client {
21 | id: client2
22 | }
23 |
24 | property int bar: 0
25 | QtObject {
26 | id: foo
27 |
28 | signal ping()
29 |
30 | function pong()
31 | {
32 | return ++bar;
33 | }
34 |
35 | WebChannel.id: "foo"
36 | }
37 |
38 | property var lastMethodArg
39 | QtObject {
40 | id: myObj
41 | property int myProperty: 1
42 |
43 | signal mySignal(var arg)
44 |
45 | function myMethod(arg)
46 | {
47 | lastMethodArg = arg;
48 | }
49 |
50 | WebChannel.id: "myObj"
51 | }
52 |
53 | QtObject {
54 | id: myOtherObj
55 | property var foo: 1
56 | property var bar: 1
57 | WebChannel.id: "myOtherObj"
58 | }
59 |
60 | property var lastFactoryObj
61 | property var createdFactoryObjects: []
62 | QtObject {
63 | id: myFactory
64 |
65 | function cleanup() {
66 | while (createdFactoryObjects.length) {
67 | var obj = createdFactoryObjects.shift();
68 | if (obj) {
69 | obj.destroy();
70 | }
71 | }
72 | }
73 |
74 | function create(id)
75 | {
76 | lastFactoryObj = component.createObject(myFactory, {objectName: id});
77 | createdFactoryObjects.push(lastFactoryObj);
78 | return lastFactoryObj;
79 | }
80 | WebChannel.id: "myFactory"
81 | }
82 |
83 | Component {
84 | id: component
85 | QtObject {
86 | property var myProperty : 0
87 | function myMethod(arg) {
88 | lastMethodArg = arg;
89 | }
90 | signal mySignal(var arg1, var arg2)
91 | }
92 | }
93 |
94 | TestWebChannel {
95 | id: webChannel
96 | transports: [client1.serverTransport, client2.serverTransport]
97 | registeredObjects: [foo, myObj, myOtherObj, myFactory]
98 | }
99 |
100 | function init()
101 | {
102 | myObj.myProperty = 1
103 | client1.cleanup();
104 | client2.cleanup();
105 | }
106 |
107 | function cleanup() {
108 | client1.debug = false;
109 | client2.debug = false;
110 | // delete all created objects
111 | myFactory.cleanup();
112 | lastFactoryObj = undefined;
113 | createdFactoryObjects = [];
114 | // reschedule current task to end of event loop
115 | wait(1);
116 | }
117 |
118 | function clientInitCallback(channel)
119 | {
120 | channel.objects.foo.ping.connect(function() {
121 | channel.objects.foo.pong(function(value) {
122 | channel.pongAnswer = value;
123 | });
124 | });
125 | }
126 |
127 | function test_multiclient()
128 | {
129 | var c1 = client1.createChannel(clientInitCallback);
130 | var c2 = client2.createChannel(clientInitCallback);
131 |
132 | // init, connect & idle messages for two clients
133 | for (var i = 0; i < 3; ++i) {
134 | client1.awaitMessage();
135 | client2.awaitMessage();
136 | }
137 |
138 | foo.ping();
139 |
140 | // invoke of pong method
141 | client1.awaitMessage();
142 | client2.awaitMessage();
143 |
144 | compare(c1.pongAnswer, 1);
145 | compare(c2.pongAnswer, 2);
146 | }
147 |
148 | function test_autowrappedObjectsNotInInit() {
149 | var testObj1;
150 | var testObj1Id;
151 |
152 | var channel1 = client1.createChannel(function (channel1) {
153 | channel1.objects.myFactory.create("testObj1", function (obj1) {
154 | testObj1 = lastFactoryObj;
155 | testObj1Id = obj1.__id__;
156 |
157 | // create second channel after factory has created first
158 | // object to make sure that a dynamically created object
159 | // exists but does not get exposed to new channels
160 | createSecondChannel();
161 | });
162 | });
163 | var channel2;
164 | function createSecondChannel() {
165 | // dismiss all messges received before channel creation
166 | client2.cleanup();
167 |
168 | channel2 = client2.createChannel(function (channel2) {
169 | });
170 | }
171 |
172 | client1.awaitInit();
173 | var msg1 = client1.awaitMessage();
174 | compare(msg1.type, JSClient.QWebChannelMessageTypes.invokeMethod); // create
175 |
176 | client1.awaitIdle();
177 |
178 | client2.awaitInit();
179 | client2.awaitIdle();
180 |
181 | compare(typeof channel2.objects[testObj1Id], "undefined")
182 | }
183 |
184 | function test_autowrappedObjectsNotBroadcasted() {
185 | var testObj2;
186 | var testObj2Id;
187 |
188 | var channel1 = client1.createChannel(function (channel1) {
189 | // create second channel after first channel to make sure
190 | // that a dynamically created object do not get exposed to
191 | // existing channels
192 | createSecondChannel();
193 | });
194 | var channel2;
195 | function createSecondChannel() {
196 | // dismiss all messges received before channel creation
197 | client2.cleanup();
198 |
199 | channel2 = client2.createChannel(function (channel2) {
200 | channel2.objects.myFactory.create("testObj2", function (obj2) {
201 | testObj2 = lastFactoryObj;
202 | testObj2Id = obj2.__id__;
203 | });
204 | });
205 | }
206 |
207 | client1.awaitInit();
208 | client1.awaitIdle();
209 |
210 | client2.awaitInit();
211 | var msg2 = client2.awaitMessage();
212 | compare(msg2.type, JSClient.QWebChannelMessageTypes.invokeMethod); // create
213 |
214 | client2.awaitIdle();
215 |
216 | compare(typeof channel1.objects[testObj2Id], "undefined")
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/src/webchannel/doc/src/javascript.qdoc:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3 |
4 | /*!
5 | \title Qt WebChannel JavaScript API
6 | \page qtwebchannel-javascript.html
7 |
8 | \brief This page explains how to use the JavaScript QWebChannel API in HTML clients.
9 |
10 | \section1 Setting up the JavaScript API
11 |
12 | To communicate with a QWebChannel or \l [QML] WebChannel, a client must use and set up the
13 | JavaScript API provided by \c qwebchannel.js. For clients run inside \l{Qt WebEngine}, you
14 | can load the file via \c qrc:///qtwebchannel/qwebchannel.js. For external clients, you
15 | need to copy the file to your web server. Then instantiate a QWebChannel object and pass
16 | it a transport object and a callback function, which will be invoked once the
17 | initialization of the channel finishes and the published objects become available. An optional
18 | third argument contains an array of converter wrapper functions or a single one.
19 |
20 | The transport object implements a minimal message passing interface. It should be an object
21 | with a \c send() function, which takes a stringified JSON message and transmits it to the
22 | server-side QWebChannelAbstractTransport object. Furthermore, its \c onmessage property should
23 | be called when a message from the server was received. Alternatively, you can use a
24 | \l{Qt WebSockets}{WebSocket} to implement the interface.
25 |
26 | Note that the JavaScript QWebChannel object should be constructed once the transport object is
27 | fully operational. In case of a WebSocket, that means you should create the QWebChannel in the
28 | socket's \c onopen handler. Take a look at the \l{Qt WebChannel Standalone Example} to see how
29 | this is done.
30 |
31 | \note Only a single \c QWebChannel object per transport can be created in the same page.
32 |
33 | A converter wrapper function is either a string with the name of a built-in converter or a
34 | user supplied function that takes the object to process as an argument and returns the
35 | resultant type or undefined if the function does not apply. If undefined is returned the next
36 | converter is processed. If there are no converters that returns a value other than undefined,
37 | processing proceeds as normal. "Date" is the only currently built-in converter function. It
38 | takes a string with an ISO 8601 date and returns a new Date object if the syntax is right and
39 | the date is valid.
40 |
41 | \section1 Interacting with QObjects
42 |
43 | Once the callback passed to the QWebChannel object is invoked, the channel has finished
44 | initialization and all published objects are accessible to the HTML client via the \c channel.objects
45 | property. Thus, assuming an object was published with the identifier "foo", then we can interact with it
46 | as shown in the example below. Note that all communication between the HTML client and
47 | the QML/C++ server is asynchronous. Properties are cached on the HTML side. Furthermore
48 | keep in mind that only QML/C++ data types which can be converted to JSON will be (de-)serialized
49 | properly and thus accessible to HTML clients.
50 |
51 | \code
52 | new QWebChannel(yourTransport, function(channel) {
53 |
54 | // Connect to a signal:
55 | channel.objects.foo.mySignal.connect(function() {
56 | // This callback will be invoked whenever the signal is emitted on the C++/QML side.
57 | console.log(arguments);
58 | });
59 |
60 | // To make the object known globally, assign it to the window object, i.e.:
61 | window.foo = channel.objects.foo;
62 |
63 | // Invoke a method:
64 | foo.myMethod(arg1, arg2, function(returnValue) {
65 | // This callback will be invoked when myMethod has a return value. Keep in mind that
66 | // the communication is asynchronous, hence the need for this callback.
67 | console.log(returnValue);
68 | });
69 |
70 | // Read a property value, which is cached on the client side:
71 | console.log(foo.myProperty);
72 |
73 | // Writing a property will instantly update the client side cache.
74 | // The remote end will be notified about the change asynchronously
75 | foo.myProperty = "Hello World!";
76 |
77 | // To get notified about remote property changes,
78 | // simply connect to the corresponding notify signal:
79 | foo.myPropertyChanged.connect(function() {
80 | console.log(foo.myProperty);
81 | });
82 |
83 | // One can also access enums that are marked with Q_ENUM:
84 | console.log(foo.MyEnum.MyEnumerator);
85 | });
86 | \endcode
87 |
88 | \section2 Overloaded methods and signals
89 |
90 | When you publish a \c QObject that has overloaded methods, QWebChannel will resolve
91 | method invocations to the best match. Note that due to JavaScript's type system, there is only
92 | a single 'number' type which maps best to a C++ 'double'. When overloads differ only in the type
93 | of a number-like parameter, QWebChannel will always choose that overload which best matches the
94 | JavaScript 'number' type.
95 | When you connect to an overloaded signal, the QWebChannel client will by default only connect to
96 | the first signal overload of that name.
97 | Additionally, overloads of methods and signals can explicitly be requested by their complete
98 | \c QMetaMethod signature.
99 | Assume we have the following \c QObject subclass on the C++ side:
100 |
101 | \code
102 | class Foo : public QObject
103 | {
104 | Q_OBJECT
105 | slots:
106 | void foo(int i);
107 | void foo(double d);
108 | void foo(const QString &str);
109 | void foo(const QString &str, int i);
110 |
111 | signals:
112 | void bar(int i);
113 | void bar(const QString &str);
114 | void bar(const QString &str, int i);
115 | };
116 | \endcode
117 |
118 | Then you can interact with this class on the JavaScript side like this:
119 |
120 | \code
121 | // methods
122 | foo.foo(42); // will call the method named foo which best matches the JavaScript number parameter, i.e. foo(double d)
123 | foo.foo("asdf"); // will call foo(const QString &str)
124 | foo.foo("asdf", 42); // will call foo(const QString &str, int i)
125 | foo["foo(int)"](42); // explicitly call foo(int i), *not* foo(double d)
126 | foo["foo(QString)"]("asdf"); // explicitly call foo(const QString &str)
127 | foo["foo(QString,int)"]("asdf", 42); // explicitly call foo(const QString &str, int i)
128 |
129 | // signals
130 | foo.bar.connect(...); // connect to first signal named bar, i.e. bar(int i)
131 | foo["bar(int)"].connect(...); // connect explicitly to bar(int i)
132 | foo["bar(QString)"].connect(...); // connect explicitly to bar(const QString &str)
133 | foo["bar(QString,int)"].connect(...); // connect explicitly to bar(const QString &str, int i)
134 | \endcode
135 | */
136 |
--------------------------------------------------------------------------------
/LICENSES/LGPL-3.0-only.txt:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/tests/auto/webchannel/tst_webchannel.h:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff
2 | // Copyright (C) 2019 Menlo Systems GmbH, author Arno Rehn
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4 |
5 | #ifndef TST_WEBCHANNEL_H
6 | #define TST_WEBCHANNEL_H
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #if QT_CONFIG(future)
16 | #include
17 | #endif
18 | #include
19 |
20 | #include
21 |
22 | struct TestStruct
23 | {
24 | TestStruct(int foo = 0, int bar = 0)
25 | : foo(foo)
26 | , bar(bar)
27 | {}
28 | int foo;
29 | int bar;
30 |
31 | operator QString() const {
32 | return QStringLiteral("TestStruct(foo=%1, bar=%2)").arg(foo).arg(bar);
33 | }
34 | };
35 | inline bool operator==(const TestStruct &a, const TestStruct &b)
36 | {
37 | return a.foo == b.foo && a.bar == b.bar;
38 | }
39 | inline QDebug operator<<(QDebug &dbg, const TestStruct &ts)
40 | {
41 | QDebugStateSaver dbgState(dbg);
42 | dbg.noquote() << static_cast(ts);
43 | return dbg;
44 | }
45 | Q_DECLARE_METATYPE(TestStruct)
46 | using TestStructVector = std::vector;
47 | Q_DECLARE_METATYPE(TestStructVector)
48 |
49 | QT_BEGIN_NAMESPACE
50 |
51 | class DummyTransport : public QWebChannelAbstractTransport
52 | {
53 | Q_OBJECT
54 | public:
55 | explicit DummyTransport(QObject *parent = nullptr)
56 | : QWebChannelAbstractTransport(parent)
57 | {}
58 | ~DummyTransport() {};
59 |
60 | void emitMessageReceived(const QJsonObject &message)
61 | {
62 | emit messageReceived(message, this);
63 | }
64 |
65 | QList messagesSent() const { return mMessagesSent; }
66 |
67 | public slots:
68 | void sendMessage(const QJsonObject &message) override
69 | {
70 | mMessagesSent.push_back(message);
71 | }
72 | private:
73 | QList mMessagesSent;
74 | };
75 |
76 | class TestObject : public QObject
77 | {
78 | Q_OBJECT
79 |
80 | Q_PROPERTY(Foo foo READ foo CONSTANT)
81 | Q_PROPERTY(int asdf READ asdf NOTIFY asdfChanged)
82 | Q_PROPERTY(QString bar READ bar NOTIFY theBarHasChanged)
83 | Q_PROPERTY(QObject * objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectPropertyChanged)
84 | Q_PROPERTY(TestObject * returnedObject READ returnedObject WRITE setReturnedObject NOTIFY returnedObjectChanged)
85 | Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged)
86 | Q_PROPERTY(QString stringProperty READ readStringProperty WRITE setStringProperty BINDABLE bindableStringProperty)
87 |
88 | public:
89 | explicit TestObject(QObject *parent = nullptr)
90 | : QObject(parent)
91 | , mObjectProperty(nullptr)
92 | , mReturnedObject(nullptr)
93 | { }
94 |
95 | enum Foo {
96 | Bar,
97 | Asdf
98 | };
99 | Q_ENUM(Foo)
100 |
101 | enum TestFlag : quint16 {
102 | FirstFlag = 0x1,
103 | SecondFlag = 0x2
104 | };
105 | Q_DECLARE_FLAGS(TestFlags, TestFlag)
106 | Q_FLAG(TestFlags)
107 |
108 | Foo foo() const {return Bar;}
109 | int asdf() const {return 42;}
110 | QString bar() const {return QString();}
111 |
112 | QObject *objectProperty() const
113 | {
114 | return mObjectProperty;
115 | }
116 |
117 | TestObject *returnedObject() const
118 | {
119 | return mReturnedObject;
120 | }
121 |
122 | QString prop() const
123 | {
124 | return mProp;
125 | }
126 |
127 | QString readStringProperty() const { return mStringProperty; }
128 |
129 | Q_INVOKABLE void method1() {}
130 |
131 | #if QT_CONFIG(future)
132 | Q_INVOKABLE QFuture futureIntResult() const;
133 | Q_INVOKABLE QFuture futureDelayedIntResult() const;
134 | #ifdef WEBCHANNEL_TESTS_CAN_USE_CONCURRENT
135 | Q_INVOKABLE QFuture futureIntResultFromThread() const;
136 | #endif
137 | Q_INVOKABLE QFuture futureVoidResult() const;
138 | Q_INVOKABLE QFuture futureStringResult() const;
139 | Q_INVOKABLE QFuture cancelledFuture() const;
140 | Q_INVOKABLE QFuture failedFuture() const;
141 | #endif
142 |
143 | protected:
144 | Q_INVOKABLE void method2() {}
145 |
146 | private:
147 | Q_INVOKABLE void method3() {}
148 |
149 | signals:
150 | void sig1();
151 | void sig2(const QString&);
152 | void asdfChanged();
153 | void theBarHasChanged();
154 | void objectPropertyChanged();
155 | void returnedObjectChanged();
156 | void propChanged(const QString&);
157 | void replay();
158 | void overloadSignal(int);
159 | void overloadSignal(float);
160 |
161 | public slots:
162 | void slot1() {}
163 | void slot2(const QString&) {}
164 |
165 | void setReturnedObject(TestObject *obj)
166 | {
167 | mReturnedObject = obj;
168 | emit returnedObjectChanged();
169 | }
170 |
171 | void setObjectProperty(QObject *object)
172 | {
173 | mObjectProperty = object;
174 | emit objectPropertyChanged();
175 | }
176 |
177 | void setProp(const QString&prop) {emit propChanged(mProp=prop);}
178 | void fire() {emit replay();}
179 |
180 | double overload(double d) { return d + 1; }
181 | int overload(int i) { return i * 2; }
182 | QObject *overload(QObject *object) { return object; }
183 | QString overload(const QString &str) { return str.toUpper(); }
184 | QString overload(const QString &str, int i) { return str.toUpper() + QString::number(i + 1); }
185 | QString overload(const QJsonArray &v) { return QString::number(v[1].toInt()) + v[0].toString(); }
186 |
187 | void setStringProperty(const QString &v) { mStringProperty = v; }
188 | QBindable bindableStringProperty() { return &mStringProperty; }
189 | QString getStringProperty() const { return mStringProperty; }
190 | void bindStringPropertyToStringProperty2() { bindableStringProperty().setBinding(Qt::makePropertyBinding(mStringProperty2)); }
191 | void setStringProperty2(const QString &string) { mStringProperty2 = string; }
192 |
193 | protected slots:
194 | void slot3() {}
195 |
196 | private slots:
197 | void slot4() {}
198 |
199 | public:
200 | QObject *mObjectProperty;
201 | TestObject *mReturnedObject;
202 | QString mProp;
203 | Q_OBJECT_BINDABLE_PROPERTY(TestObject, QString, mStringProperty);
204 | QProperty mStringProperty2;
205 | };
206 |
207 | Q_DECLARE_OPERATORS_FOR_FLAGS(TestObject::TestFlags)
208 |
209 | class TestWebChannel : public QObject
210 | {
211 | Q_OBJECT
212 |
213 | Q_PROPERTY(int lastInt READ readInt WRITE setInt NOTIFY lastIntChanged);
214 | Q_PROPERTY(bool lastBool READ readBool WRITE setBool NOTIFY lastBoolChanged);
215 | Q_PROPERTY(double lastDouble READ readDouble WRITE setDouble NOTIFY lastDoubleChanged);
216 | Q_PROPERTY(QVariant lastVariant READ readVariant WRITE setVariant NOTIFY lastVariantChanged);
217 | Q_PROPERTY(QJsonValue lastJsonValue READ readJsonValue WRITE setJsonValue NOTIFY lastJsonValueChanged);
218 | Q_PROPERTY(QJsonObject lastJsonObject READ readJsonObject WRITE setJsonObject NOTIFY lastJsonObjectChanged);
219 | Q_PROPERTY(QJsonArray lastJsonArray READ readJsonArray WRITE setJsonArray NOTIFY lastJsonArrayChanged);
220 | public:
221 | explicit TestWebChannel(QObject *parent = 0);
222 | virtual ~TestWebChannel();
223 |
224 | public slots:
225 | int readInt() const;
226 | void setInt(int i);
227 | bool readBool() const;
228 | void setBool(bool b);
229 | double readDouble() const;
230 | void setDouble(double d);
231 | QVariant readVariant() const;
232 | void setVariant(const QVariant &v);
233 | QJsonValue readJsonValue() const;
234 | void setJsonValue(const QJsonValue &v);
235 | QJsonObject readJsonObject() const;
236 | void setJsonObject(const QJsonObject &v);
237 | QJsonArray readJsonArray() const;
238 | void setJsonArray(const QJsonArray &v);
239 |
240 | QUrl readUrl() const;
241 | void setUrl(const QUrl &u);
242 |
243 | int readOverload(int i);
244 | QString readOverload(const QString &arg);
245 | QString readOverload(const QString &arg, int i);
246 |
247 | signals:
248 | void lastIntChanged();
249 | void lastBoolChanged();
250 | void lastDoubleChanged();
251 | void lastVariantChanged();
252 | void lastJsonValueChanged();
253 | void lastJsonObjectChanged();
254 | void lastJsonArrayChanged();
255 |
256 | private slots:
257 | void testRegisterObjects();
258 | void testDeregisterObjects();
259 | void testDeregisterObjectAtStart();
260 | void testInfoForObject();
261 | void testInvokeMethodConversion();
262 | void testFunctionOverloading();
263 | void testSetPropertyConversion();
264 | void testInvokeMethodOverloadResolution();
265 | void testDisconnect();
266 | void testWrapRegisteredObject();
267 | void testUnwrapObject();
268 | void testTransportWrapObjectProperties();
269 | void testRemoveUnusedTransports();
270 | void testPassWrappedObjectBack();
271 | void testWrapValues_data();
272 | void testWrapValues();
273 | void testWrapObjectWithMultipleTransports();
274 | void testJsonToVariant_data();
275 | void testJsonToVariant();
276 | void testInfiniteRecursion();
277 | void testAsyncObject();
278 | void testQProperty();
279 | void testPropertyUpdateInterval_data();
280 | void testPropertyUpdateInterval();
281 | void testPropertyMultipleTransports();
282 | void testQPropertyBlockUpdates();
283 | void testBindings();
284 | void testDeletionDuringMethodInvocation_data();
285 | void testDeletionDuringMethodInvocation();
286 |
287 | #if QT_CONFIG(future)
288 | void testAsyncMethodReturningFuture_data();
289 | void testAsyncMethodReturningFuture();
290 | #endif
291 |
292 | void qtbug46548_overriddenProperties();
293 | void qtbug62388_wrapObjectMultipleTransports();
294 |
295 | private:
296 | DummyTransport *m_dummyTransport;
297 |
298 | int m_lastInt;
299 | bool m_lastBool;
300 | double m_lastDouble;
301 | QVariant m_lastVariant;
302 | QJsonValue m_lastJsonValue;
303 | QJsonObject m_lastJsonObject;
304 | QJsonArray m_lastJsonArray;
305 | QUrl m_lastUrl;
306 | };
307 |
308 | QT_END_NAMESPACE
309 |
310 | Q_DECLARE_METATYPE(TestObject::Foo)
311 |
312 | #endif // TST_WEBCHANNEL_H
313 |
--------------------------------------------------------------------------------
/src/webchannelquick/qqmlwebchannel.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author
2 | // Milian Wolff
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4 | // Qt-Security score:significant reason:default
5 |
6 | #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
7 |
8 | #include "qqmlwebchannel.h"
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "qqmlwebchannelattached_p.h"
15 |
16 | QT_BEGIN_NAMESPACE
17 |
18 | /*!
19 | \qmltype WebChannel
20 | \nativetype QQmlWebChannel
21 |
22 | \inqmlmodule QtWebChannel
23 | \ingroup webchannel-qml
24 | \brief QML interface to QWebChannel.
25 | \since 5.4
26 |
27 | The WebChannel provides a mechanism to transparently access QObject or QML objects from HTML
28 | clients. All properties, signals and public slots can be used from the HTML clients.
29 |
30 | \sa QWebChannel, {Qt WebChannel JavaScript API}{JavaScript API}
31 | */
32 |
33 | /*!
34 | \qmlproperty list WebChannel::transports
35 | A list of transport objects, which implement QWebChannelAbstractTransport. The transports
36 | are used to talk to the remote clients.
37 |
38 | \sa connectTo(), disconnectFrom()
39 | */
40 |
41 | /*!
42 | \qmlproperty list WebChannel::registeredObjects
43 |
44 | \brief A list of objects which should be accessible to remote clients.
45 |
46 | The objects must have the attached \l id property set to an identifier, under which the
47 | object is then known on the HTML side.
48 |
49 | Once registered, all signals and property changes are automatically propagated to the clients.
50 | Public invokable methods, including slots, are also accessible to the clients.
51 |
52 | If one needs to register objects which are not available when the component is created, use the
53 | imperative registerObjects method.
54 |
55 | \sa registerObjects(), id
56 | */
57 |
58 | class QQmlWebChannelPrivate : public QWebChannelPrivate
59 | {
60 | Q_DECLARE_PUBLIC(QQmlWebChannel)
61 | public:
62 | QList registeredObjects;
63 |
64 | void _q_objectIdChanged(const QString &newId);
65 | };
66 |
67 | /*!
68 | \internal
69 |
70 | Update the name of the sender object, when its attached WebChannel.id property changed.
71 | This is required, since during startup the property is empty and only gets set later on.
72 | */
73 | void QQmlWebChannelPrivate::_q_objectIdChanged(const QString &newId)
74 | {
75 | Q_Q(QQmlWebChannel);
76 | const QQmlWebChannelAttached *const attached =
77 | qobject_cast(q->sender());
78 | Q_ASSERT(attached);
79 | Q_ASSERT(attached->parent());
80 | Q_ASSERT(registeredObjects.contains(attached->parent()));
81 |
82 | QObject *const object = attached->parent();
83 | const QString &oldId = publisher->registeredObjectIds.value(object);
84 |
85 | if (!oldId.isEmpty()) {
86 | q->deregisterObject(object);
87 | }
88 |
89 | q->registerObject(newId, object);
90 | }
91 |
92 | QQmlWebChannel::QQmlWebChannel(QObject *parent) : QWebChannel(*(new QQmlWebChannelPrivate), parent)
93 | {
94 | }
95 |
96 | QQmlWebChannel::~QQmlWebChannel() { }
97 |
98 | /*!
99 | \qmlmethod void WebChannel::registerObjects(object objects)
100 | Registers the specified \a objects to make them accessible to HTML clients.
101 | \a objects should be a JavaScript Map object.
102 | The key of the map is used as an identifier for the object on the client side.
103 |
104 | Once registered, all signals and property changes are automatically propagated to the clients.
105 | Public invokable methods, including slots, are also accessible to the clients.
106 |
107 | This imperative API can be used to register objects on the fly. For static objects, the
108 | declarative registeredObjects property should be preferred.
109 |
110 | \sa registeredObjects
111 | */
112 | void QQmlWebChannel::registerObjects(const QVariantMap &objects)
113 | {
114 | Q_D(QQmlWebChannel);
115 | QMap::const_iterator it = objects.constBegin();
116 | for (; it != objects.constEnd(); ++it) {
117 | QObject *object = it.value().value();
118 | if (!object) {
119 | qWarning("Invalid QObject given to register under name %s", qPrintable(it.key()));
120 | continue;
121 | }
122 | d->publisher->registerObject(it.key(), object);
123 | }
124 | }
125 |
126 | QQmlWebChannelAttached *QQmlWebChannel::qmlAttachedProperties(QObject *obj)
127 | {
128 | return new QQmlWebChannelAttached(obj);
129 | }
130 |
131 | /*!
132 | \qmlmethod void WebChannel::connectTo(QtObject transport)
133 |
134 | \brief Connects to the \a transport, which represents a communication
135 | channel to a single client.
136 |
137 | The transport object must be an implementation of \l QWebChannelAbstractTransport.
138 |
139 | \sa transports, disconnectFrom()
140 | */
141 | void QQmlWebChannel::connectTo(QObject *transport)
142 | {
143 | if (QWebChannelAbstractTransport *realTransport =
144 | qobject_cast(transport)) {
145 | QWebChannel::connectTo(realTransport);
146 | } else {
147 | qWarning() << "Cannot connect to transport" << transport
148 | << " - it is not a QWebChannelAbstractTransport.";
149 | }
150 | }
151 |
152 | /*!
153 | \qmlmethod void WebChannel::disconnectFrom(QtObject transport)
154 |
155 | \brief Disconnects the \a transport from this WebChannel.
156 |
157 | The client will not be able to communicate with the WebChannel anymore, nor will it receive any
158 | signals or property updates.
159 |
160 | \sa connectTo()
161 | */
162 | void QQmlWebChannel::disconnectFrom(QObject *transport)
163 | {
164 | if (QWebChannelAbstractTransport *realTransport =
165 | qobject_cast(transport)) {
166 | QWebChannel::disconnectFrom(realTransport);
167 | } else {
168 | qWarning() << "Cannot disconnect from transport" << transport
169 | << " - it is not a QWebChannelAbstractTransport.";
170 | }
171 | }
172 |
173 | /*!
174 | \property QQmlWebChannel::registeredObjects
175 |
176 | This property holds the list of objects which should be accessible to remote clients.
177 |
178 | The objects must have the attached id property set to an identifier, under which the
179 | object is then known on the HTML side.
180 |
181 | Once registered, all signals and property changes are automatically propagated to the clients.
182 | Public invokable methods, including slots, are also accessible to the clients.
183 |
184 | If one needs to register objects which are not available when the component is created, use the
185 | imperative registerObjects method.
186 |
187 | \sa registerObjects(), id
188 | */
189 | QQmlListProperty QQmlWebChannel::registeredObjects()
190 | {
191 | return QQmlListProperty(this, nullptr, registeredObjects_append,
192 | registeredObjects_count, registeredObjects_at,
193 | registeredObjects_clear);
194 | }
195 |
196 | void QQmlWebChannel::registeredObjects_append(QQmlListProperty *prop, QObject *object)
197 | {
198 | if (!object) {
199 | qWarning() << "Cannot register null object to WebChannel";
200 | return;
201 | }
202 | const QQmlWebChannelAttached *const attached = qobject_cast(
203 | qmlAttachedPropertiesObject(object, false /* don't create */));
204 | if (!attached) {
205 | const QQmlContext *const context = qmlContext(object);
206 | if (context) {
207 | qWarning() << "Cannot register object" << context->nameForObject(object) << '(' << object
208 | << ") without attached WebChannel.id property. Did you forget to set it?";
209 | } else {
210 | qWarning() << "Cannot register an object without WebChannel attached property.";
211 | }
212 | return;
213 | }
214 | QQmlWebChannel *channel = static_cast(prop->object);
215 | if (!attached->id().isEmpty()) {
216 | // TODO: warning in such cases?
217 | channel->registerObject(attached->id(), object);
218 | }
219 | channel->d_func()->registeredObjects.append(object);
220 | connect(attached, SIGNAL(idChanged(QString)), channel, SLOT(_q_objectIdChanged(QString)));
221 | }
222 |
223 | qsizetype QQmlWebChannel::registeredObjects_count(QQmlListProperty *prop)
224 | {
225 | return static_cast(prop->object)->d_func()->registeredObjects.size();
226 | }
227 |
228 | QObject *QQmlWebChannel::registeredObjects_at(QQmlListProperty *prop, qsizetype index)
229 | {
230 | return static_cast(prop->object)->d_func()->registeredObjects.at(index);
231 | }
232 |
233 | void QQmlWebChannel::registeredObjects_clear(QQmlListProperty *prop)
234 | {
235 | QQmlWebChannel *channel = static_cast(prop->object);
236 | foreach (QObject *object, channel->d_func()->registeredObjects) {
237 | channel->deregisterObject(object);
238 | }
239 | return channel->d_func()->registeredObjects.clear();
240 | }
241 |
242 | /*!
243 | \property QQmlWebChannel::transports
244 |
245 | This property holds a list of transport objects, which implement QWebChannelAbstractTransport.
246 | The transports are used to talk to the remote clients.
247 |
248 | \sa connectTo(), disconnectFrom()
249 | */
250 | QQmlListProperty QQmlWebChannel::transports()
251 | {
252 | return QQmlListProperty(this, nullptr, transports_append, transports_count,
253 | transports_at, transports_clear);
254 | }
255 |
256 | void QQmlWebChannel::transports_append(QQmlListProperty *prop, QObject *transport)
257 | {
258 | QQmlWebChannel *channel = static_cast(prop->object);
259 | channel->connectTo(transport);
260 | }
261 |
262 | qsizetype QQmlWebChannel::transports_count(QQmlListProperty *prop)
263 | {
264 | return static_cast(prop->object)->d_func()->transports.size();
265 | }
266 |
267 | QObject *QQmlWebChannel::transports_at(QQmlListProperty *prop, qsizetype index)
268 | {
269 | QQmlWebChannel *channel = static_cast(prop->object);
270 | return channel->d_func()->transports.at(index);
271 | }
272 |
273 | void QQmlWebChannel::transports_clear(QQmlListProperty *prop)
274 | {
275 | QWebChannel *channel = static_cast(prop->object);
276 | foreach (QWebChannelAbstractTransport *transport, channel->d_func()->transports) {
277 | channel->disconnectFrom(transport);
278 | }
279 | Q_ASSERT(channel->d_func()->transports.isEmpty());
280 | }
281 |
282 | QT_END_NAMESPACE
283 |
284 | #include "moc_qqmlwebchannel.cpp"
285 |
--------------------------------------------------------------------------------