summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@theqtcompany.com>2014-10-20 19:17:32 +0200
committerFrederik Gladhorn <frederik.gladhorn@theqtcompany.com>2014-10-20 19:17:32 +0200
commite50edc952ce15f3c11f4cdfad74ec984043cb080 (patch)
tree060893ceb61fa700053b61db8f0d8ebed462e1c3
parenta7c39b36c157e08fdbca6edc97950cd08d682024 (diff)
parent86d77a900852691267f556fbde98406a12ee4310 (diff)
downloadqtwebchannel-e50edc952ce15f3c11f4cdfad74ec984043cb080.tar.gz
Merge remote-tracking branch 'origin/5.4' into dev
Conflicts: examples/webchannel/webchannel.pro Change-Id: Ia768202d177a24ae90358b5d88621a5fa88f9002
-rw-r--r--examples/webchannel/chatclient-html/chatclient-html.pro7
-rw-r--r--examples/webchannel/chatclient-html/chatclient.html131
-rw-r--r--examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc63
-rw-r--r--examples/webchannel/chatclient-qml/chatclient-qml.pro7
-rw-r--r--examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc64
-rw-r--r--examples/webchannel/chatclient-qml/qmlchatclient.qml173
-rw-r--r--examples/webchannel/chatserver-cpp/chatserver-cpp.pro18
-rw-r--r--examples/webchannel/chatserver-cpp/chatserver.cpp124
-rw-r--r--examples/webchannel/chatserver-cpp/chatserver.h88
-rw-r--r--examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc63
-rw-r--r--examples/webchannel/chatserver-cpp/main.cpp71
-rw-r--r--examples/webchannel/shared/websocketclientwrapper.cpp (renamed from examples/webchannel/standalone/websocketclientwrapper.cpp)0
-rw-r--r--examples/webchannel/shared/websocketclientwrapper.h (renamed from examples/webchannel/standalone/websocketclientwrapper.h)0
-rw-r--r--examples/webchannel/shared/websockettransport.cpp (renamed from examples/webchannel/standalone/websockettransport.cpp)0
-rw-r--r--examples/webchannel/shared/websockettransport.h (renamed from examples/webchannel/standalone/websockettransport.h)0
-rw-r--r--examples/webchannel/standalone/main.cpp4
-rw-r--r--examples/webchannel/standalone/standalone.pro8
-rw-r--r--examples/webchannel/webchannel.pro13
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp23
-rw-r--r--src/webchannel/qwebchannel.js3
-rw-r--r--src/webchannel/webchannel.pro1
-rw-r--r--tests/auto/qml/tst_webchannel.qml32
22 files changed, 840 insertions, 53 deletions
diff --git a/examples/webchannel/chatclient-html/chatclient-html.pro b/examples/webchannel/chatclient-html/chatclient-html.pro
new file mode 100644
index 0000000..f5f0bf4
--- /dev/null
+++ b/examples/webchannel/chatclient-html/chatclient-html.pro
@@ -0,0 +1,7 @@
+TEMPLATE = aux
+
+exampleassets.files += \
+ chatclient.html
+
+exampleassets.path = $$[QT_INSTALL_EXAMPLES]/qwebchannel/chatclient-html
+include(../exampleassets.pri)
diff --git a/examples/webchannel/chatclient-html/chatclient.html b/examples/webchannel/chatclient-html/chatclient.html
new file mode 100644
index 0000000..b392282
--- /dev/null
+++ b/examples/webchannel/chatclient-html/chatclient.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>ChatClient</title>
+
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+
+ <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.css" />
+ <link rel="stylesheet" type="text/css" href="http://www.jeasyui.com/easyui/themes/default/easyui.css" />
+ <link rel="stylesheet" type="text/css" href="http://www.jeasyui.com/easyui/themes/icon.css" />
+ <link rel="stylesheet" type="text/css" href="http://www.jeasyui.com/easyui/demo/demo.css" />
+ <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
+ <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
+ <script type="text/javascript" src="qwebchannel.js"></script>
+
+ <script>
+ 'use strict';
+ var wsUri = "ws://localhost:12345";
+ window.loggedin = false;
+
+ window.onload = function() {
+ var socket = new WebSocket(wsUri);
+
+ socket.onclose = function()
+ {
+ console.error("web channel closed");
+ };
+ socket.onerror = function(error)
+ {
+ console.error("web channel error: " + error);
+ };
+ socket.onopen = function()
+ {
+ window.channel = new QWebChannel(socket, function(channel) {
+ //connect to the changed signal of a property
+ channel.objects.chatserver.userListChanged.connect(function() {
+ $('#userlist').empty();
+ //access the property
+ channel.objects.chatserver.userList.forEach(function(user) {
+ $('#userlist').append(user + '<br>');
+ });
+ });
+ //connect to a signal
+ channel.objects.chatserver.newMessage.connect(function(time, user, message) {
+ $('#chat').append("[" + time + "] " + user + ": " + message + '<br>');
+ });
+ //connect to a signal
+ channel.objects.chatserver.keepAlive.connect(function(args) {
+ if(window.loggedin) {
+ //call a method
+ channel.objects.chatserver.keepAliveResponse($('#loginname').val())
+ console.log("sent alive");
+ }
+ });
+
+ });
+ }
+ }
+ </script>
+</head>
+<body>
+
+<div id="loginDialog" class="easyui-dialog" title="Chat Login" data-options="iconCls:'icon-save'" style="width:400px;height:200px;padding:10px">
+ <form id="loginForm" method="post">
+ <table cellpadding="5">
+ <tr><td>Name:</td><td><input class="easyui-validatebox" type="text" id="loginname" name="name" data-options="required:true"></input></td></tr>
+ </table>
+ </form>
+ <div style="text-align:center;padding:5px">
+ <a href="javascript:void(0)" class="easyui-linkbutton" onclick="submitForm()">Login</a>
+ </div>
+ <div style="text-align:center;padding:5px" id="loginError">
+ Username already in use.
+ </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) {
+ $('#loginError').hide();
+ $('#loginDialog').dialog('close');
+ window.loggedin = true;
+ } else {
+ $('#loginError').show();
+ }
+ });
+ console.log($('#loginname').val());
+ if(event !== undefined)
+ event.preventDefault();
+ return false;
+
+ }
+ </script>
+</div>
+
+
+<div class="easyui-layout" style="width:500px;height:300px;">
+ <div data-options="region:'east',split:true" title="Users" id="userlist" style="width:100px;">
+
+ </div>
+ <div data-options="region:'south',split:true" style="height:50px;">
+ <form id="messageForm">
+ <input class="easyui-validatebox" type="text" id="message" name="name" style="width: 97%"></input>
+ </form>
+ </div>
+ <div data-options="region:'center'" id="chat">
+
+ </div>
+ <script>
+ $('#messageForm').submit(submitMessage);
+ function submitMessage(event) {
+ channel.objects.chatserver.sendMessage($('#loginname').val(), $('#message').val());
+ $('#message').val('');
+ if(event !== undefined)
+ event.preventDefault();
+ return false;
+ }
+ </script>
+</div>
+
+
+<script type="text/javascript">
+$(document).ready(function(){
+ $('#loginError').hide();
+});
+</script>
+
+</body>
+</html>
diff --git a/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc b/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc
new file mode 100644
index 0000000..3d4b672
--- /dev/null
+++ b/examples/webchannel/chatclient-html/doc/src/chatclient-html.qdoc
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example chatclient-html
+ \title Qt WebChannel Chatclient HTML Example
+ \ingroup qtwebchannel-examples
+ \brief A HTML/JavaScript client that communicates over a WebSocket with a QWebChannel server.
+
+ The chatclient-html example provides a simple QWebChannel client implemented using JavaScript and HTML.
+
+ \section1 Overview
+
+ The client initializes a WebSocket connection to the chat server and receives an object
+ containing all neccessarry signals, slots and properties for implementing a chat client.
+
+ After login the client can invoke the method \c sendMessage and receive the signal \c newMessage
+ to send and receive messages. Furthermore there is a \c userList property which provides the
+ names of all other connected clients. It is automatically updated when its contents change.
+ Also, the client responds to the servers keep alive signal which is needed to detect disconnected
+ clients and remove them from the \c userlist property.
+
+ The example shows how basic elements can be used with the client JavaScript implementation of
+ QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage) and handle
+ property changes (\c userList).
+
+ The client is able to work with the chatserver-cpp example.
+
+ To run the example, open the \c chatclient.html in a browser.
+
+ \sa {chatserver-cpp}, {chatclient-qml}
+
+*/
diff --git a/examples/webchannel/chatclient-qml/chatclient-qml.pro b/examples/webchannel/chatclient-qml/chatclient-qml.pro
new file mode 100644
index 0000000..74b274d
--- /dev/null
+++ b/examples/webchannel/chatclient-qml/chatclient-qml.pro
@@ -0,0 +1,7 @@
+TEMPLATE = aux
+
+exampleassets.files += \
+ qmlchatclient.qml
+
+exampleassets.path = $$[QT_INSTALL_EXAMPLES]/qwebchannel/chatclient-qml
+include(../exampleassets.pri)
diff --git a/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc b/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc
new file mode 100644
index 0000000..da80526
--- /dev/null
+++ b/examples/webchannel/chatclient-qml/doc/src/chatclient-qml.qdoc
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example chatclient-qml
+ \title Qt WebChannel Chatclient QML Example
+ \ingroup qtwebchannel-examples
+ \brief A QML client that communicates over a WebSocket with a QWebChannel server.
+
+ The chatclient-html example provides a simple QWebChannel client implemented using JavaScript and QML.
+
+ \section1 Overview
+
+ The client initializes a WebSocket connection to the chat server and receives an object
+ containing all neccessarry signals, slots and properties for implementing a chat client.
+
+ After login, the client can invoke the method \c sendMessage and receive the signal \c newMessage
+ to send and receive messages. Furthermore, there is a \c userList property which provides the
+ names of all other connected clients. It is automatically updated when its contents change.
+ Also, the client responds to the servers keep alive signal which is needed to detect disconnected
+ clients and remove them from the \c userList property.
+
+ The example shows how basic elements can be used with the client JavaScript implementation of
+ QWebChannel, like connecting to signals (\c newMessage), calling slots (\c sendMessage) and handle
+ property changes (\c userList).
+
+ The client is able to work with the chatserver-cpp as server application
+
+
+ The example can be run by invoking \c {path/to/qmlscene qmlchatclient.qml}.
+
+ \sa {chatserver-cpp}, {chatclient-html}
+
+*/
diff --git a/examples/webchannel/chatclient-qml/qmlchatclient.qml b/examples/webchannel/chatclient-qml/qmlchatclient.qml
new file mode 100644
index 0000000..7ecd15c
--- /dev/null
+++ b/examples/webchannel/chatclient-qml/qmlchatclient.qml
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtQuick.Controls 1.1
+import QtQuick.Window 2.0
+import QtQuick.Layouts 1.1
+import Qt.WebSockets 1.0
+import "qwebchannel.js" as WebChannel
+
+ApplicationWindow {
+ id: root
+ title: qsTr("Hello World")
+ width: 640
+ height: 480
+
+ property var channel;
+
+ 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) {
+ 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
+ }
+
+ Text {
+ id: userlist
+ text: ""
+ width: 150
+ Layout.fillHeight: true
+ }
+ TextField {
+ id: message
+ height: 50
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+
+ onEditingFinished: {
+ if (message.text.length)
+ //call the sendMessage method to send the message
+ root.channel.objects.chatserver.sendMessage(loginName.text, message.text);
+ 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;
+ }
+ }
+
+ Component.onCompleted: {
+ loginWindow.show();
+ socket.active = true; //connect
+ }
+}
diff --git a/examples/webchannel/chatserver-cpp/chatserver-cpp.pro b/examples/webchannel/chatserver-cpp/chatserver-cpp.pro
new file mode 100644
index 0000000..ce6a3f7
--- /dev/null
+++ b/examples/webchannel/chatserver-cpp/chatserver-cpp.pro
@@ -0,0 +1,18 @@
+TARGET = chatserver
+
+TEMPLATE = app
+
+QT += core websockets webchannel
+QT -= gui
+
+CONFIG += console
+
+SOURCES += main.cpp \
+ chatserver.cpp \
+ ../shared/websocketclientwrapper.cpp \
+ ../shared/websockettransport.cpp
+
+HEADERS += \
+ chatserver.h \
+ ../shared/websocketclientwrapper.h \
+ ../shared/websockettransport.h
diff --git a/examples/webchannel/chatserver-cpp/chatserver.cpp b/examples/webchannel/chatserver-cpp/chatserver.cpp
new file mode 100644
index 0000000..4663549
--- /dev/null
+++ b/examples/webchannel/chatserver-cpp/chatserver.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "chatserver.h"
+
+#include <QtCore/QDebug>
+#include <QTimer>
+#include <QTime>
+
+QT_BEGIN_NAMESPACE
+
+ChatServer::ChatServer(QObject *parent)
+ : QObject(parent)
+{
+ QTimer* t = new QTimer(this);
+ connect(t, SIGNAL(timeout()), this, SLOT(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()));
+}
+
+ChatServer::~ChatServer()
+{}
+
+
+bool ChatServer::login(const QString& userName)
+{
+ //stop keepAliveCheck, when a new user logged in
+ if (m_keepAliveCheckTimer->isActive()) {
+ m_keepAliveCheckTimer->stop();
+ m_stillAliveUsers.clear();
+ }
+
+ if (m_userList.contains(userName)) {
+ return false;
+ }
+
+ qDebug() << "User logged in:" << userName;
+ m_userList.append(userName);
+ m_userList.sort();
+ emit userListChanged();
+ emit userCountChanged();
+ return true;
+}
+
+bool ChatServer::logout(const QString& userName)
+{
+ if (!m_userList.contains(userName)) {
+ return false;
+ } else {
+ m_userList.removeAt(m_userList.indexOf(userName));
+ emit userListChanged();
+ emit userCountChanged();
+ return true;
+ }
+}
+
+bool ChatServer::sendMessage(const QString& user, const QString& msg)
+{
+ if (m_userList.contains(user)) {
+ emit newMessage(QTime::currentTime().toString("HH:mm:ss"), user, msg);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void ChatServer::sendKeepAlive() {
+ emit keepAlive();
+ m_keepAliveCheckTimer->start();
+}
+
+void ChatServer::checkKeepAliveResponses() {
+ qDebug() << "Keep Alive Check" << m_stillAliveUsers;
+ m_userList = m_stillAliveUsers;
+ m_stillAliveUsers.clear();
+ m_userList.sort();
+ emit userListChanged();
+}
+
+void ChatServer::keepAliveResponse(const QString& user) {
+ m_stillAliveUsers.append(user);
+}
+
+
+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
new file mode 100644
index 0000000..eba219a
--- /dev/null
+++ b/examples/webchannel/chatserver-cpp/chatserver.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ChatServer_H
+#define ChatServer_H
+
+#include <QObject>
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+
+class ChatServer : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QStringList userList READ userList NOTIFY userListChanged)
+
+public:
+ explicit ChatServer(QObject *parent = 0);
+ virtual ~ChatServer();
+
+public:
+ //a user logs in with the given 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);
+
+ //a user sends a message to all other users
+ 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);
+
+ QStringList userList() const;
+
+protected slots:
+ void sendKeepAlive();
+ void checkKeepAliveResponses();
+
+signals:
+ void newMessage(QString time, QString user, QString msg);
+ void keepAlive();
+ void userListChanged();
+ void userCountChanged();
+
+private:
+ QStringList m_userList;
+ QStringList m_stillAliveUsers;
+ QTimer* m_keepAliveCheckTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // ChatServer_H
diff --git a/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc b/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc
new file mode 100644
index 0000000..ceae6ab
--- /dev/null
+++ b/examples/webchannel/chatserver-cpp/doc/src/chatserver-cpp.qdoc
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 basysKom GmbH, author Bernd Lamecker <bernd.lamecker@basyskom.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example chatserver-cpp
+ \title Qt WebChannel Chatserver Example
+ \ingroup qtwebchannel-examples
+ \brief Shows how to use the QWebChannel C++ API to implement a simple chat server
+
+ The chatserver examples provides a chat service that client examples can connect to.
+
+ \section1 Overview
+
+ The C++ application implements a QObject which provides all mechanisms required for
+ a chat service.
+ This object is published through a QWebChannel which uses a WebSocket as transport.
+
+ The server provides a basic \c login method (username only, no passwords), which must be
+ successfully invoked before a client is able to chat.
+ After login a client can invoke the method \c sendMessage and receive the signal \c newMessage
+ to write and receive messages. Furthermore there is a \c userList property which provides
+ the names of all other connected clients.
+ Additionally the server sends a keepAlive signal periodically to all clients. The clients
+ have to respond to this signal, otherwise the client will be removed from the \c userList property.
+
+ The example shows how basic QObject elements can be used with QWebChannel, i.e. signals
+ (\c newMessage), slots (\c sendMessage) and properties (\c userList).
+
+ Because this is a plain server application, there are separated clients needed to interact
+ with the server. Both examples chatclient-qml and chatclient-html show a client implementation
+ compatible with this server.
+
+*/
diff --git a/examples/webchannel/chatserver-cpp/main.cpp b/examples/webchannel/chatserver-cpp/main.cpp
new file mode 100644
index 0000000..d971bee
--- /dev/null
+++ b/examples/webchannel/chatserver-cpp/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwebchannel.h"
+
+#include <QCoreApplication>
+#include <QUrl>
+#include <QDebug>
+
+#include <QtWebSockets/QWebSocketServer>
+
+#include "../shared/websocketclientwrapper.h"
+#include "../shared/websockettransport.h"
+#include "chatserver.h"
+
+
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QWebSocketServer server(QStringLiteral("QWebChannel Standalone Example Server"),
+ QWebSocketServer::NonSecureMode);
+ if (!server.listen(QHostAddress::LocalHost, 12345)) {
+ qFatal("Failed to open web socket server.");
+ return 1;
+ }
+
+ // wrap WebSocket clients in QWebChannelAbstractTransport objects
+ WebSocketClientWrapper clientWrapper(&server);
+
+ // setup the channel
+ QWebChannel channel;
+ QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected,
+ &channel, &QWebChannel::connectTo);
+
+ // setup the dialog and publish it to the QWebChannel
+ ChatServer* chatserver = new ChatServer(&app);
+ channel.registerObject("chatserver", chatserver);
+
+ return app.exec();
+}
diff --git a/examples/webchannel/standalone/websocketclientwrapper.cpp b/examples/webchannel/shared/websocketclientwrapper.cpp
index 68ff1c0..68ff1c0 100644
--- a/examples/webchannel/standalone/websocketclientwrapper.cpp
+++ b/examples/webchannel/shared/websocketclientwrapper.cpp
diff --git a/examples/webchannel/standalone/websocketclientwrapper.h b/examples/webchannel/shared/websocketclientwrapper.h
index f49b8b9..f49b8b9 100644
--- a/examples/webchannel/standalone/websocketclientwrapper.h
+++ b/examples/webchannel/shared/websocketclientwrapper.h
diff --git a/examples/webchannel/standalone/websockettransport.cpp b/examples/webchannel/shared/websockettransport.cpp
index 266563a..266563a 100644
--- a/examples/webchannel/standalone/websockettransport.cpp
+++ b/examples/webchannel/shared/websockettransport.cpp
diff --git a/examples/webchannel/standalone/websockettransport.h b/examples/webchannel/shared/websockettransport.h
index 4d4a6cd..4d4a6cd 100644
--- a/examples/webchannel/standalone/websockettransport.h
+++ b/examples/webchannel/shared/websockettransport.h
diff --git a/examples/webchannel/standalone/main.cpp b/examples/webchannel/standalone/main.cpp
index 6f0db3a..201c4cd 100644
--- a/examples/webchannel/standalone/main.cpp
+++ b/examples/webchannel/standalone/main.cpp
@@ -42,8 +42,8 @@
#include <QtWebSockets/QWebSocketServer>
-#include "websocketclientwrapper.h"
-#include "websockettransport.h"
+#include "../shared/websocketclientwrapper.h"
+#include "../shared/websockettransport.h"
#include "ui_dialog.h"
diff --git a/examples/webchannel/standalone/standalone.pro b/examples/webchannel/standalone/standalone.pro
index fdeb87a..19aa264 100644
--- a/examples/webchannel/standalone/standalone.pro
+++ b/examples/webchannel/standalone/standalone.pro
@@ -4,12 +4,12 @@ CONFIG += warn_on
SOURCES += \
main.cpp \
- websockettransport.cpp \
- websocketclientwrapper.cpp
+ ../shared/websockettransport.cpp \
+ ../shared/websocketclientwrapper.cpp
HEADERS += \
- websockettransport.h \
- websocketclientwrapper.h
+ ../shared/websockettransport.h \
+ ../shared/websocketclientwrapper.h
FORMS += \
dialog.ui
diff --git a/examples/webchannel/webchannel.pro b/examples/webchannel/webchannel.pro
index ed1e21b..7d3db8d 100644
--- a/examples/webchannel/webchannel.pro
+++ b/examples/webchannel/webchannel.pro
@@ -1,7 +1,12 @@
TEMPLATE = subdirs
-
-qtHaveModule(widgets):qtHaveModule(websockets) {
- SUBDIRS += standalone
+qtHaveModule(websockets) {
+ SUBDIRS += chatserver-cpp \
+ chatclient-qml
+ qtHaveModule(widgets) {
+ SUBDIRS += standalone
+ }
}
-SUBDIRS += nodejs qwclient
+SUBDIRS += nodejs \
+ qwclient \
+ chatclient-html
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index 1271fda..eeab014 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -43,11 +43,6 @@
#include <QJsonArray>
#include <QUuid>
-#if HAVE_QML
-#include <QtQml/QJSValue>
-#include <QtQml/QJSEngine>
-#endif
-
QT_BEGIN_NAMESPACE
namespace {
@@ -194,7 +189,9 @@ QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) cons
data[KEY_SIGNALS] = qtSignals;
data[KEY_METHODS] = qtMethods;
data[KEY_PROPERTIES] = qtProperties;
- data[KEY_ENUMS] = qtEnums;
+ if (!qtEnums.isEmpty()) {
+ data[KEY_ENUMS] = qtEnums;
+ }
return data;
}
@@ -380,19 +377,7 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal
message[KEY_SIGNAL] = signalIndex;
if (!arguments.isEmpty()) {
// TODO: wrap (new) objects on the fly
- QJsonArray args;
-#if HAVE_QML
- foreach (const QVariant &arg, arguments) {
- if (arg.canConvert<QJSValue>()) {
- const QJSValue &jsValue = arg.value<QJSValue>();
- args.append(qjsvalue_cast<QJsonValue>(jsValue));
- } else {
- args.append(QJsonValue::fromVariant(arg));
- }
- }
-#else
- args = QJsonArray::fromVariantList(arguments);
-#endif
+ QJsonArray args = QJsonArray::fromVariantList(arguments);
message[KEY_ARGS] = args;
}
message[KEY_TYPE] = TypeSignal;
diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js
index 3feb829..d2c6525 100644
--- a/src/webchannel/qwebchannel.js
+++ b/src/webchannel/qwebchannel.js
@@ -236,8 +236,9 @@ function QObject(name, data, webChannel)
object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];
object.__objectSignals__[signalIndex].push(callback);
- if (!isPropertyNotifySignal) {
+ if (!isPropertyNotifySignal && signalName !== "destroyed") {
// only required for "pure" signals, handled separately for properties in propertyUpdate
+ // also note that we always get notified about the destroyed signal
webChannel.exec({
type: QWebChannelMessageTypes.connectToSignal,
object: object.__id__,
diff --git a/src/webchannel/webchannel.pro b/src/webchannel/webchannel.pro
index 024956e..eba8123 100644
--- a/src/webchannel/webchannel.pro
+++ b/src/webchannel/webchannel.pro
@@ -29,7 +29,6 @@ SOURCES += \
qtHaveModule(qml) {
QT += qml
- DEFINES += HAVE_QML=1
SOURCES += \
qqmlwebchannel.cpp \
diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml
index 3e76d12..f304197 100644
--- a/tests/auto/qml/tst_webchannel.qml
+++ b/tests/auto/qml/tst_webchannel.qml
@@ -244,11 +244,6 @@ TestCase {
compare(myFactory.lastObj.objectName, "testObj");
compare(channel.objects[testObjId].objectName, "testObj");
- // deleteLater signal connection
- msg = client.awaitMessage();
- compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
- compare(msg.object, testObjId);
-
// mySignal connection
msg = client.awaitMessage();
compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
@@ -287,26 +282,23 @@ TestCase {
// objects even if no callback function is set
function test_wrapper_wrapEveryQObject()
{
+ var testObj;
var channel = client.createChannel(function(channel) {
- channel.objects.myFactory.create("testObj");
+ channel.objects.myFactory.create("testObj", function(obj) {
+ testObj = obj;
+ });
});
client.awaitInit();
// ignore first message (call to myFactory.create())
client.awaitMessage();
-
- // second message connects to destroyed signal and contains the new objects ID
- var msg = client.awaitMessage();
- verify(msg.object);
-
- var testObjId = msg.object;
- compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
- compare(typeof channel.objects[testObjId], "object");
-
client.awaitIdle();
- channel.objects[testObjId].deleteLater();
- msg = client.awaitMessage();
+ verify(testObj);
+ var testObjId = testObj.__id__;
+
+ testObj.deleteLater();
+ var msg = client.awaitMessage();
compare(msg.type, JSClient.QWebChannelMessageTypes.invokeMethod);
compare(msg.object, testObjId);
@@ -329,14 +321,10 @@ TestCase {
});
client.awaitInit();
- // first message (call to myFactory.create())
+ // call to myFactory.create()
var msg = client.awaitMessage();
compare(msg.type, JSClient.QWebChannelMessageTypes.invokeMethod);
- // second message connects to destroyed signal
- msg = client.awaitMessage();
- compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
-
client.awaitIdle();
testObj.myProperty = 42;