diff options
26 files changed, 671 insertions, 291 deletions
diff --git a/dist/changes-5.6.3 b/dist/changes-5.6.3 new file mode 100644 index 0000000..fe30fea --- /dev/null +++ b/dist/changes-5.6.3 @@ -0,0 +1,28 @@ +Qt 5.6.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.6.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.6 series is binary compatible with the 5.5.x series. +Applications compiled for 5.5 will continue to run with 5.6. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + + - [QTBUG-47678][QTBUG-51366] Correctly forward objects via the webchannel + that live in a separate thread. + + - [QTBUG-60250] Do not assert when unregistering an object before the + webchannel was initialized. diff --git a/examples/webchannel/chatclient-html/chatclient.html b/examples/webchannel/chatclient-html/chatclient.html index b392282..d3b36d8 100644 --- a/examples/webchannel/chatclient-html/chatclient.html +++ b/examples/webchannel/chatclient-html/chatclient.html @@ -21,16 +21,13 @@ window.onload = function() { var socket = new WebSocket(wsUri); - socket.onclose = function() - { + socket.onclose = function() { console.error("web channel closed"); }; - socket.onerror = function(error) - { + socket.onerror = function(error) { console.error("web channel error: " + error); }; - socket.onopen = function() - { + socket.onopen = function() { window.channel = new QWebChannel(socket, function(channel) { //connect to the changed signal of a property channel.objects.chatserver.userListChanged.connect(function() { @@ -42,11 +39,11 @@ }); //connect to a signal channel.objects.chatserver.newMessage.connect(function(time, user, message) { - $('#chat').append("[" + time + "] " + user + ": " + message + '<br>'); + $('#chat').append("[" + time + "] " + user + ": " + message + '<br>'); }); //connect to a signal channel.objects.chatserver.keepAlive.connect(function(args) { - if(window.loggedin) { + if (window.loggedin) { //call a method channel.objects.chatserver.keepAliveResponse($('#loginname').val()) console.log("sent alive"); @@ -74,11 +71,12 @@ </div> <script> $('#loginForm').submit(submitForm); + function submitForm(event) { console.log("DEBUG login: " + channel); channel.objects.chatserver.login($('#loginname').val(), function(arg) { console.log("DEBUG login response: " + arg); - if(arg === true) { + if (arg === true) { $('#loginError').hide(); $('#loginDialog').dialog('close'); window.loggedin = true; @@ -87,10 +85,9 @@ } }); console.log($('#loginname').val()); - if(event !== undefined) + if (event !== undefined) event.preventDefault(); return false; - } </script> </div> @@ -110,10 +107,11 @@ </div> <script> $('#messageForm').submit(submitMessage); + function submitMessage(event) { channel.objects.chatserver.sendMessage($('#loginname').val(), $('#message').val()); $('#message').val(''); - if(event !== undefined) + if (event !== undefined) event.preventDefault(); return false; } @@ -122,7 +120,7 @@ <script type="text/javascript"> -$(document).ready(function(){ +$(document).ready(function() { $('#loginError').hide(); }); </script> diff --git a/examples/webchannel/chatclient-qml/LoginForm.ui.qml b/examples/webchannel/chatclient-qml/LoginForm.ui.qml new file mode 100644 index 0000000..c8045e5 --- /dev/null +++ b/examples/webchannel/chatclient-qml/LoginForm.ui.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2016 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.0 + +Item { + property alias userName: userName + property alias loginButton: loginButton + property alias nameInUseError: nameInUseError + + ColumnLayout { + anchors.right: parent.right + anchors.left: parent.left + anchors.top: parent.top + + TextField { + id: userName + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + } + + Button { + id: loginButton + text: "Login" + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + } + + Label { + id: nameInUseError + text: "Name already in use" + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + } + } +} diff --git a/examples/webchannel/chatclient-qml/MainForm.ui.qml b/examples/webchannel/chatclient-qml/MainForm.ui.qml new file mode 100644 index 0000000..ff881df --- /dev/null +++ b/examples/webchannel/chatclient-qml/MainForm.ui.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2016 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +Item { + property alias chat: chat + property alias userlist: userlist + property alias message: message + + GridLayout { + anchors.fill: parent + rows: 2 + columns: 2 + + Text { + id: chat + Layout.fillWidth: true + Layout.fillHeight: true + } + + Text { + id: userlist + width: 150 + Layout.fillHeight: true + } + + TextField { + id: message + height: 50 + Layout.fillWidth: true + Layout.columnSpan: 2 + } + } +} diff --git a/examples/webchannel/chatclient-qml/chatclient-qml.pro b/examples/webchannel/chatclient-qml/chatclient-qml.pro index 185ffde..34fc08a 100644 --- a/examples/webchannel/chatclient-qml/chatclient-qml.pro +++ b/examples/webchannel/chatclient-qml/chatclient-qml.pro @@ -1,6 +1,8 @@ TEMPLATE = aux exampleassets.files += \ + LoginForm.ui.qml \ + MainForm.ui.qml \ qmlchatclient.qml exampleassets.path = $$[QT_INSTALL_EXAMPLES]/webchannel/chatclient-qml diff --git a/examples/webchannel/chatclient-qml/qmlchatclient.qml b/examples/webchannel/chatclient-qml/qmlchatclient.qml index abb0ea9..e10b118 100644 --- a/examples/webchannel/chatclient-qml/qmlchatclient.qml +++ b/examples/webchannel/chatclient-qml/qmlchatclient.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2016 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com> ** Contact: https://www.qt.io/licensing/ ** @@ -50,7 +50,8 @@ ****************************************************************************/ import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick.Dialogs 1.2 +import QtQuick.Controls 2.0 import QtQuick.Window 2.0 import QtQuick.Layouts 1.1 import Qt.WebSockets 1.0 @@ -58,133 +59,138 @@ import "qwebchannel.js" as WebChannel ApplicationWindow { id: root - title: qsTr("Hello World") + + property var channel + property string loginName: loginUi.userName.text + + title: "Chat client" width: 640 height: 480 - - property var channel; + visible: true WebSocket { id: socket - url: "ws://localhost:12345"; - active: false - - // the following three properties/functions are required to align the QML WebSocket API with the HTML5 WebSocket API. - property var send: function (arg) { + // the following three properties/functions are required to align the QML WebSocket API + // with the HTML5 WebSocket API. + property var send: function(arg) { sendTextMessage(arg); } onTextMessageReceived: { onmessage({data: message}); } - property var onmessage; - - onStatusChanged: if (socket.status == WebSocket.Error) { - console.error("Error: " + socket.errorString) - } else if (socket.status == WebSocket.Closed) { - messageBox.text += "\nSocket closed" - } else if (socket.status == WebSocket.Open) { - //open the webchannel with the socket as transport - new WebChannel.QWebChannel(socket, function(ch) { - root.channel = ch; - - //connect to the changed signal of the userList property - ch.objects.chatserver.userListChanged.connect(function(args) { - userlist.text = ''; - ch.objects.chatserver.userList.forEach(function(user) { - userlist.text += user + '\n'; - }); - }); - //connect to the newMessage signal - ch.objects.chatserver.newMessage.connect(function(time, user, message) { - chat.text = chat.text + "[" + time + "] " + user + ": " + message + '\n'; - }); - //connect to the keep alive signal - ch.objects.chatserver.keepAlive.connect(function(args) { - if (loginName.text !== '') - //and call the keep alive response method as an answer - ch.objects.chatserver.keepAliveResponse(loginName.text) - }); - }); - } - } - GridLayout { - id: grid - columns: 2 - anchors.fill: parent - Text { - id: chat - text: "" - Layout.fillHeight: true - Layout.fillWidth: true + property var onmessage + + active: true + url: "ws://localhost:12345" + + onStatusChanged: { + switch (socket.status) { + case WebSocket.Error: + errorDialog.text = "Error: " + socket.errorString; + errorDialog.visible = true; + break; + case WebSocket.Closed: + errorDialog.text = "Error: Socket at " + url + " closed."; + errorDialog.visible = true; + break; + case WebSocket.Open: + //open the webchannel with the socket as transport + new WebChannel.QWebChannel(socket, function(ch) { + root.channel = ch; + + //connect to the changed signal of the userList property + ch.objects.chatserver.userListChanged.connect(function(args) { + mainUi.userlist.text = ''; + ch.objects.chatserver.userList.forEach(function(user) { + mainUi.userlist.text += user + '\n'; + }); + }); + + //connect to the newMessage signal + ch.objects.chatserver.newMessage.connect(function(time, user, message) { + var line = "[" + time + "] " + user + ": " + message + '\n'; + mainUi.chat.text = mainUi.chat.text + line; + }); + + //connect to the keep alive signal + ch.objects.chatserver.keepAlive.connect(function(args) { + if (loginName !== '') + //and call the keep alive response method as an answer + ch.objects.chatserver.keepAliveResponse(loginName); + }); + }); + + loginWindow.show(); + break; + } } + } - Text { - id: userlist - text: "" - width: 150 - Layout.fillHeight: true - } - TextField { - id: message - height: 50 - Layout.columnSpan: 2 - Layout.fillWidth: true + MainForm { + id: mainUi + anchors.fill: parent + Connections { + target: mainUi.message onEditingFinished: { - if (message.text.length) + if (mainUi.message.text.length) { //call the sendMessage method to send the message - root.channel.objects.chatserver.sendMessage(loginName.text, message.text); - message.text = ''; + root.channel.objects.chatserver.sendMessage(loginName, + mainUi.message.text); + } + mainUi.message.text = ''; } } } - Window { - id: loginWindow; - title: "Login"; - modality: Qt.ApplicationModal - - TextField { - id: loginName - - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - } - Button { - anchors.top: loginName.bottom - anchors.horizontalCenter: parent.horizontalCenter - id: loginButton - text: "Login" - - onClicked: { - //call the login method - root.channel.objects.chatserver.login(loginName.text, function(arg) { - //check the return value for success - if (arg === true) { - loginError.visible = false; - loginWindow.close(); - } else { - loginError.visible = true; - } - }); - - } - } - Text { - id: loginError - anchors.top: loginButton.bottom - anchors.horizontalCenter: parent.horizontalCenter - text: "Name already in use" - visible: false; - } + id: loginWindow + + title: "Login" + modality: Qt.ApplicationModal + width: 300 + height: 200 + + LoginForm { + id: loginUi + anchors.fill: parent + + nameInUseError.visible: false + + Connections { + target: loginUi.loginButton + + onClicked: { + //call the login method + root.channel.objects.chatserver.login(loginName, function(arg) { + //check the return value for success + if (arg === true) { + loginUi.nameInUseError.visible = false; + loginWindow.close(); + } else { + loginUi.nameInUseError.visible = true; + } + }); + } + } + } } - Component.onCompleted: { - loginWindow.show(); - socket.active = true; //connect + MessageDialog { + id: errorDialog + + icon: StandardIcon.Critical + standardButtons: StandardButton.Close + title: "Chat client" + + onAccepted: { + Qt.quit(); + } + onRejected: { + Qt.quit(); + } } } diff --git a/examples/webchannel/chatserver-cpp/chatserver.cpp b/examples/webchannel/chatserver-cpp/chatserver.cpp index 74da4c3..1025c80 100644 --- a/examples/webchannel/chatserver-cpp/chatserver.cpp +++ b/examples/webchannel/chatserver-cpp/chatserver.cpp @@ -50,30 +50,28 @@ #include "chatserver.h" -#include <QtCore/QDebug> -#include <QTimer> +#include <QDebug> #include <QTime> - -QT_BEGIN_NAMESPACE +#include <QTimer> ChatServer::ChatServer(QObject *parent) : QObject(parent) { - QTimer* t = new QTimer(this); - connect(t, SIGNAL(timeout()), this, SLOT(sendKeepAlive())); + QTimer *t = new QTimer(this); + connect(t, &QTimer::timeout, this, &ChatServer::sendKeepAlive); t->start(10000); m_keepAliveCheckTimer = new QTimer(this); m_keepAliveCheckTimer->setSingleShot(true); m_keepAliveCheckTimer->setInterval(2000); - connect(m_keepAliveCheckTimer, SIGNAL(timeout()), this, SLOT(checkKeepAliveResponses())); + connect(m_keepAliveCheckTimer, &QTimer::timeout, this, &ChatServer::checkKeepAliveResponses); } ChatServer::~ChatServer() {} -bool ChatServer::login(const QString& userName) +bool ChatServer::login(const QString &userName) { //stop keepAliveCheck, when a new user logged in if (m_keepAliveCheckTimer->isActive()) { @@ -93,7 +91,7 @@ bool ChatServer::login(const QString& userName) return true; } -bool ChatServer::logout(const QString& userName) +bool ChatServer::logout(const QString &userName) { if (!m_userList.contains(userName)) { return false; @@ -105,7 +103,7 @@ bool ChatServer::logout(const QString& userName) } } -bool ChatServer::sendMessage(const QString& user, const QString& msg) +bool ChatServer::sendMessage(const QString &user, const QString &msg) { if (m_userList.contains(user)) { emit newMessage(QTime::currentTime().toString("HH:mm:ss"), user, msg); @@ -130,7 +128,7 @@ void ChatServer::checkKeepAliveResponses() emit userListChanged(); } -void ChatServer::keepAliveResponse(const QString& user) +void ChatServer::keepAliveResponse(const QString &user) { m_stillAliveUsers.append(user); } @@ -140,5 +138,3 @@ QStringList ChatServer::userList() const { return m_userList; } - -QT_END_NAMESPACE diff --git a/examples/webchannel/chatserver-cpp/chatserver.h b/examples/webchannel/chatserver-cpp/chatserver.h index 20f0928..9bc8026 100644 --- a/examples/webchannel/chatserver-cpp/chatserver.h +++ b/examples/webchannel/chatserver-cpp/chatserver.h @@ -48,15 +48,15 @@ ** ****************************************************************************/ -#ifndef ChatServer_H -#define ChatServer_H +#ifndef CHATSERVER_H +#define CHATSERVER_H #include <QObject> #include <QStringList> QT_BEGIN_NAMESPACE - class QTimer; +QT_END_NAMESPACE class ChatServer : public QObject { @@ -65,22 +65,22 @@ class ChatServer : public QObject Q_PROPERTY(QStringList userList READ userList NOTIFY userListChanged) public: - explicit ChatServer(QObject *parent = 0); + explicit ChatServer(QObject *parent = nullptr); virtual ~ChatServer(); public: //a user logs in with the given username - Q_INVOKABLE bool login(const QString& userName); + Q_INVOKABLE bool login(const QString &userName); //the user logs out, will be removed from userlist immediately - Q_INVOKABLE bool logout(const QString& userName); + Q_INVOKABLE bool logout(const QString &userName); //a user sends a message to all other users - Q_INVOKABLE bool sendMessage(const QString& user, const QString& msg); + Q_INVOKABLE bool sendMessage(const QString &user, const QString &msg); //response of the keep alive signal from a client. // This is used to detect disconnects. - Q_INVOKABLE void keepAliveResponse(const QString& user); + Q_INVOKABLE void keepAliveResponse(const QString &user); QStringList userList() const; @@ -97,9 +97,7 @@ signals: private: QStringList m_userList; QStringList m_stillAliveUsers; - QTimer* m_keepAliveCheckTimer; + QTimer *m_keepAliveCheckTimer; }; -QT_END_NAMESPACE - -#endif // ChatServer_H +#endif // CHATSERVER_H diff --git a/examples/webchannel/chatserver-cpp/main.cpp b/examples/webchannel/chatserver-cpp/main.cpp index ea27e87..9e025ac 100644 --- a/examples/webchannel/chatserver-cpp/main.cpp +++ b/examples/webchannel/chatserver-cpp/main.cpp @@ -48,14 +48,14 @@ ** ****************************************************************************/ -#include "qwebchannel.h" #include "chatserver.h" #include "../shared/websocketclientwrapper.h" #include "../shared/websockettransport.h" -#include <QtWebSockets/QWebSocketServer> #include <QCoreApplication> +#include <QWebChannel> +#include <QWebSocketServer> int main(int argc, char** argv) { diff --git a/examples/webchannel/exampleassets.pri b/examples/webchannel/exampleassets.pri index bbdf656..094d4d8 100644 --- a/examples/webchannel/exampleassets.pri +++ b/examples/webchannel/exampleassets.pri @@ -1,12 +1,5 @@ # This adds the qwebchannel js library to an example, creating a self-contained bundle -QTDIR_build { - # Build from within Qt. Copy and install the reference lib. - jslib = $$dirname(_QMAKE_CONF_)/src/webchannel/qwebchannel.js - assetcopy.files = $$jslib -} else { - # This is what an actual 3rd party project would do. - jslib = qwebchannel.js -} +jslib = $$PWD/shared/qwebchannel.js # This installs all assets including qwebchannel.js, regardless of the source. exampleassets.files += $$jslib @@ -16,7 +9,10 @@ INSTALLS += exampleassets !equals(_PRO_FILE_PWD_, $$OUT_PWD) { # Shadow build, copy all example assets. - assetcopy.files = $$exampleassets.files + assetcopy.files += $$exampleassets.files +} else { + # Just copy jslib - other assets are already in place. + assetcopy.files = $$jslib } assetcopy.path = $$OUT_PWD diff --git a/examples/webchannel/nodejs/chatclient.js b/examples/webchannel/nodejs/chatclient.js index 5e458f2..76b620c 100644 --- a/examples/webchannel/nodejs/chatclient.js +++ b/examples/webchannel/nodejs/chatclient.js @@ -91,7 +91,10 @@ var createWebChannel = function(transport, rlif) { console.log(' << ' + message); rlif.prompt(); // Go to end of existing input if any - rlif.write(null, {ctrl: true, name: 'e'}) + rlif.write(null, { + ctrl: true, + name: 'e' + }) }); rlif.on('line', function(line) { @@ -118,7 +121,9 @@ socket.on('open', function(event) { var transport = { // We cant't do 'send: socket.send' here // because 'send' wouldn't be bound to 'socket' - send: function(data) {socket.send(data)} + send: function(data) { + socket.send(data) + } }; createWebChannel(transport, createReadlineInterface()); @@ -131,12 +136,12 @@ socket.on('open', function(event) { }); }); -socket.on('error', function (error) { +socket.on('error', function(error) { console.log('Connection error: ' + error.message); process.exit(1); }); -socket.on('close', function () { +socket.on('close', function() { console.log('Connection closed.'); process.exit(1); }); diff --git a/examples/webchannel/qwclient/qwclient.js b/examples/webchannel/qwclient/qwclient.js index 0e28328..0b0909f 100755 --- a/examples/webchannel/qwclient/qwclient.js +++ b/examples/webchannel/qwclient/qwclient.js @@ -49,6 +49,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + 'use strict'; var repl = require('repl'); var WebSocket = require('faye-websocket').Client; @@ -62,7 +63,7 @@ if (autoConnect === __filename) { autoConnect = false; } -var openChannel = function (address) { +var openChannel = function(address) { // this should be bound to the repl var self = this; address = address ? address : serverAddress; @@ -72,25 +73,27 @@ var openChannel = function (address) { var ws = new WebSocket(address); - ws.on('open', function (event) { + ws.on('open', function(event) { var transport = { - onmessage: function (data) {}, - send: function (data) { - ws.send(data, {binary: false}); - } + onmessage: function(data) {}, + send: function(data) { + ws.send(data, { + binary: false + }); + } }; - ws.on('message', function (event) { - transport.onmessage(event); + ws.on('message', function(event) { + transport.onmessage(event); }); // onmessage - var webChannel = new QWebChannel(transport, function (channel) { + var webChannel = new QWebChannel(transport, function(channel) { channels.push(channel); var channelIdx = (channels.length - 1); console.log('channel opened', channelIdx); // Create a nice alias to access this channels objects self.context['c' + channelIdx] = channel.objects; - ws.on('close', function () { + ws.on('close', function() { for (var i = 0; i < channels.length; ++i) { if (channels[i] === channel) { console.log('channel closed', i); @@ -102,7 +105,7 @@ var openChannel = function (address) { }); // new QWebChannel }); // onopen - ws.on('error', function (error) { + ws.on('error', function(error) { console.log('websocket error', error.message); }); }; // openChannel @@ -119,7 +122,7 @@ var setupRepl = function() { r.context.channels = channels; r.context.lsObjects = function() { - channels.forEach(function(channel){ + channels.forEach(function(channel) { console.log('Channel ' + channel); Object.keys(channel.objects); }); diff --git a/src/webchannel/qwebchannel.js b/examples/webchannel/shared/qwebchannel.js index 5b047c2..5b047c2 100644 --- a/src/webchannel/qwebchannel.js +++ b/examples/webchannel/shared/qwebchannel.js diff --git a/examples/webchannel/shared/websocketclientwrapper.cpp b/examples/webchannel/shared/websocketclientwrapper.cpp index 3743bdd..16be85e 100644 --- a/examples/webchannel/shared/websocketclientwrapper.cpp +++ b/examples/webchannel/shared/websocketclientwrapper.cpp @@ -51,7 +51,7 @@ #include "websocketclientwrapper.h" #include "websockettransport.h" -#include <QtWebSockets/QWebSocketServer> +#include <QWebSocketServer> /*! \brief Wraps connected QWebSockets clients in WebSocketTransport objects. @@ -61,8 +61,6 @@ published objects. */ -QT_BEGIN_NAMESPACE - /*! Construct the client wrapper with the given parent. @@ -84,5 +82,3 @@ void WebSocketClientWrapper::handleNewConnection() { emit clientConnected(new WebSocketTransport(m_server->nextPendingConnection())); } - -QT_END_NAMESPACE diff --git a/examples/webchannel/shared/websocketclientwrapper.h b/examples/webchannel/shared/websocketclientwrapper.h index f03b825..efb8b4b 100644 --- a/examples/webchannel/shared/websocketclientwrapper.h +++ b/examples/webchannel/shared/websocketclientwrapper.h @@ -48,33 +48,32 @@ ** ****************************************************************************/ -#ifndef WEBSOCKETTRANSPORTSERVER_H -#define WEBSOCKETTRANSPORTSERVER_H +#ifndef WEBSOCKETCLIENTWRAPPER_H +#define WEBSOCKETCLIENTWRAPPER_H #include <QObject> -QT_BEGIN_NAMESPACE +class WebSocketTransport; +QT_BEGIN_NAMESPACE class QWebSocketServer; -class WebSocketTransport; +QT_END_NAMESPACE class WebSocketClientWrapper : public QObject { Q_OBJECT public: - WebSocketClientWrapper(QWebSocketServer *server, QObject *parent = 0); + WebSocketClientWrapper(QWebSocketServer *server, QObject *parent = nullptr); -Q_SIGNALS: - void clientConnected(WebSocketTransport* client); +signals: + void clientConnected(WebSocketTransport *client); -private Q_SLOTS: +private slots: void handleNewConnection(); private: QWebSocketServer *m_server; }; -QT_END_NAMESPACE - -#endif // WEBSOCKETTRANSPORTSERVER_H +#endif // WEBSOCKETCLIENTWRAPPER_H diff --git a/examples/webchannel/shared/websockettransport.cpp b/examples/webchannel/shared/websockettransport.cpp index a65bc2d..e4ce50a 100644 --- a/examples/webchannel/shared/websockettransport.cpp +++ b/examples/webchannel/shared/websockettransport.cpp @@ -50,11 +50,10 @@ #include "websockettransport.h" +#include <QDebug> #include <QJsonDocument> #include <QJsonObject> -#include <QDebug> - -#include <QtWebSockets/QWebSocket> +#include <QWebSocket> /*! \brief QWebChannelAbstractSocket implementation that uses a QWebSocket internally. @@ -64,8 +63,6 @@ be send over the QWebSocket to the remote client. */ -QT_BEGIN_NAMESPACE - /*! Construct the transport object and wrap the given socket. @@ -115,5 +112,3 @@ void WebSocketTransport::textMessageReceived(const QString &messageData) } emit messageReceived(message.object(), this); } - -QT_END_NAMESPACE diff --git a/examples/webchannel/shared/websockettransport.h b/examples/webchannel/shared/websockettransport.h index 44cb92e..252eaeb 100644 --- a/examples/webchannel/shared/websockettransport.h +++ b/examples/webchannel/shared/websockettransport.h @@ -51,11 +51,12 @@ #ifndef WEBSOCKETTRANSPORT_H #define WEBSOCKETTRANSPORT_H -#include <QtWebChannel/QWebChannelAbstractTransport> +#include <QWebChannelAbstractTransport> QT_BEGIN_NAMESPACE - class QWebSocket; +QT_END_NAMESPACE + class WebSocketTransport : public QWebChannelAbstractTransport { Q_OBJECT @@ -63,15 +64,13 @@ public: explicit WebSocketTransport(QWebSocket *socket); virtual ~WebSocketTransport(); - void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE; + void sendMessage(const QJsonObject &message) override; -private Q_SLOTS: +private slots: void textMessageReceived(const QString &message); private: QWebSocket *m_socket; }; -QT_END_NAMESPACE - #endif // WEBSOCKETTRANSPORT_H diff --git a/examples/webchannel/standalone/core.h b/examples/webchannel/standalone/core.h new file mode 100644 index 0000000..0e91bb7 --- /dev/null +++ b/examples/webchannel/standalone/core.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CORE_H +#define CORE_H + +#include "dialog.h" +#include <QObject> + +/* + An instance of this class gets published over the WebChannel and is then accessible to HTML clients. +*/ +class Core : public QObject +{ + Q_OBJECT + +public: + Core(Dialog *dialog, QObject *parent = nullptr) + : QObject(parent), m_dialog(dialog) + { + connect(dialog, &Dialog::sendText, this, &Core::sendText); + } + +signals: + /* + This signal is emitted from the C++ side and the text displayed on the HTML client side. + */ + void sendText(const QString &text); + +public slots: + + /* + This slot is invoked from the HTML client side and the text displayed on the server side. + */ + void receiveText(const QString &text) + { + m_dialog->displayMessage(Dialog::tr("Received message: %1").arg(text)); + } + +private: + Dialog *m_dialog; +}; + +#endif // CORE_H diff --git a/examples/webchannel/standalone/dialog.cpp b/examples/webchannel/standalone/dialog.cpp new file mode 100644 index 0000000..c9fc164 --- /dev/null +++ b/examples/webchannel/standalone/dialog.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dialog.h" +#include "ui_dialog.h" + +Dialog::Dialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::Dialog) +{ + ui->setupUi(this); + connect(ui->send, &QPushButton::clicked, this, &Dialog::clicked); +} + +void Dialog::displayMessage(const QString &message) +{ + ui->output->appendPlainText(message); +} + +void Dialog::clicked() +{ + const QString text = ui->input->text(); + + if (text.isEmpty()) + return; + + emit sendText(text); + displayMessage(tr("Sent message: %1").arg(text)); + + ui->input->clear(); +} diff --git a/examples/webchannel/standalone/dialog.h b/examples/webchannel/standalone/dialog.h new file mode 100644 index 0000000..143f2d8 --- /dev/null +++ b/examples/webchannel/standalone/dialog.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIALOG_H +#define DIALOG_H + +#include <QDialog> + +QT_BEGIN_NAMESPACE +namespace Ui { +class Dialog; +} +QT_END_NAMESPACE + +class Dialog : public QDialog +{ + Q_OBJECT + +public: + explicit Dialog(QWidget *parent = nullptr); + + void displayMessage(const QString &message); + +signals: + void sendText(const QString &text); + +private slots: + void clicked(); + +private: + Ui::Dialog *ui; +}; + +#endif // DIALOG_H diff --git a/examples/webchannel/standalone/doc/src/standalone.qdoc b/examples/webchannel/standalone/doc/src/standalone.qdoc index 0d030bf..6777492 100644 --- a/examples/webchannel/standalone/doc/src/standalone.qdoc +++ b/examples/webchannel/standalone/doc/src/standalone.qdoc @@ -64,13 +64,13 @@ \section1 Communicating with a Remote Client - The C++ application sets up a QWebChannel instance and publishes a \c Dialog object over it. + The C++ application sets up a QWebChannel instance and publishes a \c Core 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 \c Dialog emits the \c Dialog::sendText() signal when the user sends a message. The signal + The \c Core emits the \c Core::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, \c Dialog::receiveText() is called. + side, \c Core::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 diff --git a/examples/webchannel/standalone/index.html b/examples/webchannel/standalone/index.html index b5a9a49..7c042cd 100644 --- a/examples/webchannel/standalone/index.html +++ b/examples/webchannel/standalone/index.html @@ -5,8 +5,7 @@ <script type="text/javascript" src="./qwebchannel.js"></script> <script type="text/javascript"> //BEGIN SETUP - function output(message) - { + function output(message) { var output = document.getElementById("output"); output.innerHTML = output.innerHTML + message + "\n"; } @@ -19,20 +18,17 @@ output("Connecting to WebSocket server at " + baseUrl + "."); var socket = new WebSocket(baseUrl); - socket.onclose = function() - { + socket.onclose = function() { console.error("web channel closed"); }; - socket.onerror = function(error) - { + socket.onerror = function(error) { console.error("web channel error: " + error); }; - socket.onopen = function() - { + socket.onopen = function() { output("WebSocket connected, setting up QWebChannel."); new QWebChannel(socket, function(channel) { - // make dialog object accessible globally - window.dialog = channel.objects.dialog; + // make core object accessible globally + window.core = channel.objects.core; document.getElementById("send").onclick = function() { var input = document.getElementById("input"); @@ -43,14 +39,14 @@ output("Sent message: " + text); input.value = ""; - dialog.receiveText(text); + core.receiveText(text); } - dialog.sendText.connect(function(message) { + core.sendText.connect(function(message) { output("Received message: " + message); }); - dialog.receiveText("Client connected, ready to send/receive messages!"); + core.receiveText("Client connected, ready to send/receive messages!"); output("Connected to WebChannel, ready to send/receive messages!"); }); } diff --git a/examples/webchannel/standalone/main.cpp b/examples/webchannel/standalone/main.cpp index b53e9a6..3ea66ad 100644 --- a/examples/webchannel/standalone/main.cpp +++ b/examples/webchannel/standalone/main.cpp @@ -48,81 +48,19 @@ ** ****************************************************************************/ -#include "qwebchannel.h" +#include "dialog.h" +#include "core.h" +#include "../shared/websocketclientwrapper.h" +#include "../shared/websockettransport.h" #include <QApplication> -#include <QDialog> -#include <QVariantMap> #include <QDesktopServices> -#include <QUrl> +#include <QDialog> #include <QDir> #include <QFileInfo> -#include <QtWebSockets/QWebSocketServer> - -#include "../shared/websocketclientwrapper.h" -#include "../shared/websockettransport.h" - -#include "ui_dialog.h" - -/*! - An instance of this class gets published over the WebChannel and is then accessible to HTML clients. -*/ -class Dialog : public QObject -{ - Q_OBJECT - -public: - explicit Dialog(QObject *parent = 0) - : QObject(parent) - { - ui.setupUi(&dialog); - dialog.show(); - - connect(ui.send, SIGNAL(clicked()), SLOT(clicked())); - } - - void displayMessage(const QString &message) - { - ui.output->appendPlainText(message); - } - -signals: - /*! - This signal is emitted from the C++ side and the text displayed on the HTML client side. - */ - void sendText(const QString &text); - -public slots: - /*! - This slot is invoked from the HTML client side and the text displayed on the server side. - */ - void receiveText(const QString &text) - { - displayMessage(tr("Received message: %1").arg(text)); - } - -private slots: - /*! - Note that this slot is private and thus not accessible to HTML clients. - */ - void clicked() - { - const QString text = ui.input->text(); - - if (text.isEmpty()) { - return; - } - - emit sendText(text); - displayMessage(tr("Sent message: %1").arg(text)); - - ui.input->clear(); - } - -private: - QDialog dialog; - Ui::Dialog ui; -}; +#include <QUrl> +#include <QWebChannel> +#include <QWebSocketServer> int main(int argc, char** argv) { @@ -148,17 +86,19 @@ int main(int argc, char** argv) QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected, &channel, &QWebChannel::connectTo); - // setup the dialog and publish it to the QWebChannel + // setup the UI Dialog dialog; - channel.registerObject(QStringLiteral("dialog"), &dialog); + + // setup the core and publish it to the QWebChannel + Core core(&dialog); + channel.registerObject(QStringLiteral("core"), &core); // open a browser window with the client HTML page QUrl url = QUrl::fromLocalFile(BUILD_DIR "/index.html"); QDesktopServices::openUrl(url); - dialog.displayMessage(QObject::tr("Initialization complete, opening browser at %1.").arg(url.toDisplayString())); + dialog.displayMessage(Dialog::tr("Initialization complete, opening browser at %1.").arg(url.toDisplayString())); + dialog.show(); return app.exec(); } - -#include "main.moc" diff --git a/examples/webchannel/standalone/standalone.pro b/examples/webchannel/standalone/standalone.pro index cfe4297..eea78ef 100644 --- a/examples/webchannel/standalone/standalone.pro +++ b/examples/webchannel/standalone/standalone.pro @@ -4,10 +4,13 @@ CONFIG += warn_on SOURCES += \ main.cpp \ + dialog.cpp \ ../shared/websockettransport.cpp \ ../shared/websocketclientwrapper.cpp HEADERS += \ + core.h \ + dialog.h \ ../shared/websockettransport.h \ ../shared/websocketclientwrapper.h diff --git a/src/webchannel/doc/qtwebchannel.qdocconf b/src/webchannel/doc/qtwebchannel.qdocconf index 4026379..716da64 100644 --- a/src/webchannel/doc/qtwebchannel.qdocconf +++ b/src/webchannel/doc/qtwebchannel.qdocconf @@ -56,3 +56,5 @@ examples.fileextensions += "*.html *.json" navigation.landingpage = "Qt WebChannel" navigation.cppclassespage = "Qt WebChannel C++ Classes" navigation.qmltypespage = "Qt WebChannel QML Types" + +manifestmeta.highlighted.names += "QtWebChannel/Qt WebChannel Standalone Example" diff --git a/src/webchannel/resources.qrc b/src/webchannel/resources.qrc index 319c07a..3e6476b 100644 --- a/src/webchannel/resources.qrc +++ b/src/webchannel/resources.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/qtwebchannel/"> - <file>qwebchannel.js</file> + <file alias="qwebchannel.js">../../examples/webchannel/shared/qwebchannel.js</file> </qresource> </RCC> |