diff options
15 files changed, 634 insertions, 8 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..77064f2 --- /dev/null +++ b/examples/webchannel/chatclient-html/chatclient.html @@ -0,0 +1,135 @@ +<!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.min.css" /> + <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> + <script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>--> + <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 src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.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"></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-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/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/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 de6b4b8..7bd0d35 100644 --- a/examples/webchannel/webchannel.pro +++ b/examples/webchannel/webchannel.pro @@ -1,7 +1,10 @@ TEMPLATE = subdirs qtHaveModule(widgets):qtHaveModule(websockets) { - SUBDIRS += standalone + SUBDIRS += standalone \ } -SUBDIRS += nodejs +SUBDIRS += nodejs \ + chatserver-cpp \ + chatclient-html \ + chatclient-qml |