summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2013-12-28 19:20:58 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-08 15:59:28 +0100
commit66c0d916131c1e9e896705971f20385c75e753a2 (patch)
tree59b25cd7b9bc1ff688ff46c2b4f4c21fa60019cf /src
parent318576f0cc0ebef78c5b27106b1a8429eb54fac8 (diff)
downloadqtwebchannel-66c0d916131c1e9e896705971f20385c75e753a2.tar.gz
Simplify usage of QWebChannel on the server side.
This is achieved by hiding the MetaObjectPublisher completely as private API. The QWebChannel is the only publisher API and now handles both the socket as well as the publisher internally. This now allows us to create a proper QML api in the new QmlWebChannel. Change-Id: I3096364af8485353ca9bc19df4a81a8e4552c3d7 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/imports/webchannel/plugin.cpp6
-rw-r--r--src/imports/webchannel/qmlwebchannel.cpp75
-rw-r--r--src/imports/webchannel/qmlwebchannel.h63
-rw-r--r--src/imports/webchannel/webchannel.pro11
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp344
-rw-r--r--src/webchannel/qmetaobjectpublisher.h121
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h62
-rw-r--r--src/webchannel/qwebchannel.cpp149
-rw-r--r--src/webchannel/qwebchannel.h35
-rw-r--r--src/webchannel/qwebchannel_p.h60
-rw-r--r--src/webchannel/qwebchannelsocket.cpp99
-rw-r--r--src/webchannel/qwebchannelsocket_p.h74
-rw-r--r--src/webchannel/signalhandler_p.h2
-rw-r--r--src/webchannel/webchannel.pro9
14 files changed, 671 insertions, 439 deletions
diff --git a/src/imports/webchannel/plugin.cpp b/src/imports/webchannel/plugin.cpp
index a5e9895..0835c2b 100644
--- a/src/imports/webchannel/plugin.cpp
+++ b/src/imports/webchannel/plugin.cpp
@@ -43,8 +43,7 @@
#include <qqml.h>
#include <QtQml/QQmlExtensionPlugin>
-#include "qwebchannel.h"
-#include "qmetaobjectpublisher.h"
+#include "qmlwebchannel.h"
QT_USE_NAMESPACE
@@ -61,8 +60,7 @@ void QWebChannelPlugin::registerTypes(const char *uri)
{
int major = 1;
int minor = 0;
- qmlRegisterType<QWebChannel>(uri, major, minor, "WebChannel");
- qmlRegisterType<QMetaObjectPublisher>(uri, major, minor, "MetaObjectPublisher");
+ qmlRegisterType<QmlWebChannel>(uri, major, minor, "WebChannel");
}
diff --git a/src/imports/webchannel/qmlwebchannel.cpp b/src/imports/webchannel/qmlwebchannel.cpp
new file mode 100644
index 0000000..a7a6db0
--- /dev/null
+++ b/src/imports/webchannel/qmlwebchannel.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 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:LGPL$
+** 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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlwebchannel.h"
+
+#include "qwebchannel_p.h"
+#include "qmetaobjectpublisher_p.h"
+
+QmlWebChannel::QmlWebChannel(QObject *parent)
+ : QWebChannel(parent)
+{
+
+}
+
+QmlWebChannel::~QmlWebChannel()
+{
+
+}
+
+void QmlWebChannel::registerObjects(const QVariantMap &objects)
+{
+ QMap<QString, QVariant>::const_iterator it = objects.constBegin();
+ for (; it != objects.constEnd(); ++it) {
+ QObject *object = it.value().value<QObject*>();
+ if (!object) {
+ qWarning("Invalid QObject given to register under name %s", qPrintable(it.key()));
+ continue;
+ }
+ d->publisher->registerObject(it.key(), object);
+ }
+}
+
+bool QmlWebChannel::test_clientIsIdle() const
+{
+ return d->publisher->clientIsIdle;
+}
diff --git a/src/imports/webchannel/qmlwebchannel.h b/src/imports/webchannel/qmlwebchannel.h
new file mode 100644
index 0000000..b52bc8b
--- /dev/null
+++ b/src/imports/webchannel/qmlwebchannel.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 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:LGPL$
+** 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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLWEBCHANNEL_H
+#define QMLWEBCHANNEL_H
+
+#include <qwebchannel.h>
+
+class QmlWebChannel : public QWebChannel
+{
+ Q_OBJECT
+
+public:
+ QmlWebChannel(QObject *parent = 0);
+ virtual ~QmlWebChannel();
+
+ // TODO: replace by list property
+ Q_INVOKABLE void registerObjects(const QVariantMap &objects);
+
+ // TODO: remove this by replacing QML with C++ tests
+ Q_INVOKABLE bool test_clientIsIdle() const;
+};
+
+#endif // QMLWEBCHANNEL_H
diff --git a/src/imports/webchannel/webchannel.pro b/src/imports/webchannel/webchannel.pro
index 1753cee..3051077 100644
--- a/src/imports/webchannel/webchannel.pro
+++ b/src/imports/webchannel/webchannel.pro
@@ -1,6 +1,13 @@
-QT = core quick webchannel
+QT = core quick webchannel-private
+
+INCLUDEPATH += ../../webchannel
+VPATH += ../../webchannel
SOURCES += \
- plugin.cpp
+ plugin.cpp \
+ qmlwebchannel.cpp
+
+HEADERS += \
+ qmlwebchannel.h
load(qml_plugin)
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index 27c7d70..d3659bd 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -40,7 +40,6 @@
**
****************************************************************************/
-#include "qmetaobjectpublisher.h"
#include "qmetaobjectpublisher_p.h"
#include "qwebchannel.h"
@@ -87,8 +86,9 @@ QString objectId(const QObject *object)
const int PROPERTY_UPDATE_INTERVAL = 50;
}
-QMetaObjectPublisherPrivate::QMetaObjectPublisherPrivate(QMetaObjectPublisher *q)
- : q(q)
+QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel)
+ : QObject(webChannel)
+ , webChannel(webChannel)
, signalHandler(this)
, clientIsIdle(false)
, blockUpdates(false)
@@ -97,7 +97,112 @@ QMetaObjectPublisherPrivate::QMetaObjectPublisherPrivate(QMetaObjectPublisher *q
{
}
-void QMetaObjectPublisherPrivate::setClientIsIdle(bool isIdle)
+QMetaObjectPublisher::~QMetaObjectPublisher()
+{
+
+}
+
+void QMetaObjectPublisher::registerObject(const QString &id, QObject *object)
+{
+ if (propertyUpdatesInitialized) {
+ qWarning("Registered new object after initialization. This does not work!");
+ return;
+ }
+ registeredObjects[id] = object;
+ registeredObjectIds[object] = id;
+}
+
+QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) const
+{
+ QJsonObject data;
+ if (!object) {
+ qWarning("null object given to MetaObjectPublisher - bad API usage?");
+ return data;
+ }
+
+ QJsonArray qtSignals;
+ QJsonArray qtMethods;
+ QJsonArray qtProperties;
+ QJsonObject qtEnums;
+
+ const QMetaObject *metaObject = object->metaObject();
+ QSet<int> notifySignals;
+ QSet<QString> identifiers;
+ for (int i = 0; i < metaObject->propertyCount(); ++i) {
+ const QMetaProperty &prop = metaObject->property(i);
+ QJsonArray propertyInfo;
+ const QString &propertyName = QString::fromLatin1(prop.name());
+ propertyInfo.append(i);
+ propertyInfo.append(propertyName);
+ identifiers << propertyName;
+ QJsonArray signalInfo;
+ if (prop.hasNotifySignal()) {
+ notifySignals << prop.notifySignalIndex();
+ const int numParams = prop.notifySignal().parameterCount();
+ if (numParams > 1) {
+ qWarning("Notify signal for property '%s' has %d parameters, expected zero or one.",
+ prop.name(), numParams);
+ }
+ // optimize: compress the common propertyChanged notification names, just send a 1
+ const QByteArray &notifySignal = prop.notifySignal().name();
+ static const QByteArray changedSuffix = QByteArrayLiteral("Changed");
+ if (notifySignal.length() == changedSuffix.length() + propertyName.length() &&
+ notifySignal.endsWith(changedSuffix) && notifySignal.startsWith(prop.name()))
+ {
+ signalInfo.append(1);
+ } else {
+ signalInfo.append(QString::fromLatin1(notifySignal));
+ }
+ signalInfo.append(prop.notifySignalIndex());
+ } else if (!prop.isConstant()) {
+ qWarning("Property '%s'' of object '%s' has no notify signal and is not constant, "
+ "value updates in HTML will be broken!",
+ prop.name(), object->metaObject()->className());
+ }
+ propertyInfo.append(signalInfo);
+ propertyInfo.append(QJsonValue::fromVariant(prop.read(object)));
+ qtProperties.append(propertyInfo);
+ }
+ for (int i = 0; i < metaObject->methodCount(); ++i) {
+ if (notifySignals.contains(i)) {
+ continue;
+ }
+ const QMetaMethod &method = metaObject->method(i);
+ //NOTE: this must be a string, otherwise it will be converted to '{}' in QML
+ const QString &name = QString::fromLatin1(method.name());
+ // optimize: skip overloaded methods/signals or property getters, on the JS side we can only
+ // call one of them anyways
+ // TODO: basic support for overloaded signals, methods
+ if (identifiers.contains(name)) {
+ continue;
+ }
+ identifiers << name;
+ // send data as array to client with format: [name, index]
+ QJsonArray data;
+ data.append(name);
+ data.append(i);
+ if (method.methodType() == QMetaMethod::Signal) {
+ qtSignals.append(data);
+ } else if (method.access() == QMetaMethod::Public) {
+ qtMethods.append(data);
+ }
+ }
+ for (int i = 0; i < metaObject->enumeratorCount(); ++i) {
+ QMetaEnum enumerator = metaObject->enumerator(i);
+ QJsonObject values;
+ for (int k = 0; k < enumerator.keyCount(); ++k) {
+ values[QString::fromLatin1(enumerator.key(k))] = enumerator.value(k);
+ }
+ qtEnums[QString::fromLatin1(enumerator.name())] = values;
+ }
+ data[KEY_SIGNALS] = qtSignals;
+ data[KEY_METHODS] = qtMethods;
+ data[KEY_PROPERTIES] = qtProperties;
+ data[KEY_ENUMS] = qtEnums;
+ return data;
+}
+
+void QMetaObjectPublisher::setClientIsIdle(bool isIdle)
{
if (clientIsIdle == isIdle) {
return;
@@ -106,11 +211,11 @@ void QMetaObjectPublisherPrivate::setClientIsIdle(bool isIdle)
if (!isIdle && timer.isActive()) {
timer.stop();
} else if (isIdle && !timer.isActive()) {
- timer.start(PROPERTY_UPDATE_INTERVAL, q);
+ timer.start(PROPERTY_UPDATE_INTERVAL, this);
}
}
-void QMetaObjectPublisherPrivate::initializeClients()
+void QMetaObjectPublisher::initializeClients()
{
if (!webChannel) {
return;
@@ -120,7 +225,7 @@ void QMetaObjectPublisherPrivate::initializeClients()
{
const QHash<QString, QObject *>::const_iterator end = registeredObjects.constEnd();
for (QHash<QString, QObject *>::const_iterator it = registeredObjects.constBegin(); it != end; ++it) {
- const QJsonObject &info = q->classInfoForObject(it.value());
+ const QJsonObject &info = classInfoForObject(it.value());
if (!propertyUpdatesInitialized) {
initializePropertyUpdates(it.value(), info);
}
@@ -132,7 +237,7 @@ void QMetaObjectPublisherPrivate::initializeClients()
pendingInit = false;
}
-void QMetaObjectPublisherPrivate::initializePropertyUpdates(const QObject *const object, const QJsonObject &objectInfo)
+void QMetaObjectPublisher::initializePropertyUpdates(const QObject *const object, const QJsonObject &objectInfo)
{
foreach (const QJsonValue &propertyInfoVar, objectInfo[KEY_PROPERTIES].toArray()) {
const QJsonArray &propertyInfo = propertyInfoVar.toArray();
@@ -164,7 +269,7 @@ void QMetaObjectPublisherPrivate::initializePropertyUpdates(const QObject *const
signalHandler.connectTo(object, s_destroyedSignalIndex);
}
-void QMetaObjectPublisherPrivate::sendPendingPropertyUpdates()
+void QMetaObjectPublisher::sendPendingPropertyUpdates()
{
if (blockUpdates || !clientIsIdle || pendingPropertyUpdates.isEmpty()) {
return;
@@ -204,7 +309,7 @@ void QMetaObjectPublisherPrivate::sendPendingPropertyUpdates()
setClientIsIdle(false);
}
-bool QMetaObjectPublisherPrivate::invokeMethod(QObject *const object, const int methodIndex,
+bool QMetaObjectPublisher::invokeMethod(QObject *const object, const int methodIndex,
const QJsonArray &args, const QJsonValue &id)
{
const QMetaMethod &method = object->metaObject()->method(methodIndex);
@@ -257,7 +362,7 @@ bool QMetaObjectPublisherPrivate::invokeMethod(QObject *const object, const int
return true;
}
-void QMetaObjectPublisherPrivate::signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments)
+void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments)
{
if (!webChannel) {
return;
@@ -280,12 +385,12 @@ void QMetaObjectPublisherPrivate::signalEmitted(const QObject *object, const int
} else {
pendingPropertyUpdates[object][signalIndex] = arguments;
if (clientIsIdle && !blockUpdates && !timer.isActive()) {
- timer.start(PROPERTY_UPDATE_INTERVAL, q);
+ timer.start(PROPERTY_UPDATE_INTERVAL, this);
}
}
}
-void QMetaObjectPublisherPrivate::objectDestroyed(const QObject *object)
+void QMetaObjectPublisher::objectDestroyed(const QObject *object)
{
const QString &id = registeredObjectIds.take(object);
Q_ASSERT(!id.isEmpty());
@@ -298,7 +403,7 @@ void QMetaObjectPublisherPrivate::objectDestroyed(const QObject *object)
wrappedObjects.remove(object);
}
-QJsonValue QMetaObjectPublisherPrivate::wrapResult(const QVariant &result)
+QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result)
{
if (QObject *object = result.value<QObject *>()) {
QJsonObject &objectInfo = wrappedObjects[object];
@@ -314,7 +419,7 @@ QJsonValue QMetaObjectPublisherPrivate::wrapResult(const QVariant &result)
objectInfo[KEY_QOBJECT] = true;
objectInfo[KEY_ID] = id;
- objectInfo[KEY_DATA] = q->classInfoForObject(object);
+ objectInfo[KEY_DATA] = classInfoForObject(object);
registeredObjectIds[object] = id;
registeredObjects[id] = object;
@@ -328,7 +433,7 @@ QJsonValue QMetaObjectPublisherPrivate::wrapResult(const QVariant &result)
return QJsonValue::fromVariant(result);
}
-void QMetaObjectPublisherPrivate::deleteWrappedObject(QObject *object) const
+void QMetaObjectPublisher::deleteWrappedObject(QObject *object) const
{
if (!wrappedObjects.contains(object)) {
qWarning() << "Not deleting non-wrapped object" << object;
@@ -337,142 +442,6 @@ void QMetaObjectPublisherPrivate::deleteWrappedObject(QObject *object) const
object->deleteLater();
}
-QMetaObjectPublisher::QMetaObjectPublisher(QObject *parent)
- : QObject(parent)
- , d(new QMetaObjectPublisherPrivate(this))
-{
-}
-
-QMetaObjectPublisher::~QMetaObjectPublisher()
-{
-
-}
-
-QJsonObject QMetaObjectPublisher::classInfoForObjects(const QVariantMap &objectMap) const
-{
- QJsonObject ret;
- QMap<QString, QVariant>::const_iterator it = objectMap.constBegin();
- while (it != objectMap.constEnd()) {
- QObject *object = it.value().value<QObject *>();
- if (object) {
- const QJsonObject &info = classInfoForObject(object);
- if (!info.isEmpty()) {
- ret[it.key()] = info;
- }
- }
- ++it;
- }
- return ret;
-}
-
-QJsonObject QMetaObjectPublisher::classInfoForObject(QObject *object) const
-{
- QJsonObject data;
- if (!object) {
- qWarning("null object given to MetaObjectPublisher - bad API usage?");
- return data;
- }
-
- QJsonArray qtSignals;
- QJsonArray qtMethods;
- QJsonArray qtProperties;
- QJsonObject qtEnums;
-
- const QMetaObject *metaObject = object->metaObject();
- QSet<int> notifySignals;
- QSet<QString> identifiers;
- for (int i = 0; i < metaObject->propertyCount(); ++i) {
- const QMetaProperty &prop = metaObject->property(i);
- QJsonArray propertyInfo;
- const QString &propertyName = QString::fromLatin1(prop.name());
- propertyInfo.append(i);
- propertyInfo.append(propertyName);
- identifiers << propertyName;
- QJsonArray signalInfo;
- if (prop.hasNotifySignal()) {
- notifySignals << prop.notifySignalIndex();
- const int numParams = prop.notifySignal().parameterCount();
- if (numParams > 1) {
- qWarning("Notify signal for property '%s' has %d parameters, expected zero or one.",
- prop.name(), numParams);
- }
- // optimize: compress the common propertyChanged notification names, just send a 1
- const QByteArray &notifySignal = prop.notifySignal().name();
- static const QByteArray changedSuffix = QByteArrayLiteral("Changed");
- if (notifySignal.length() == changedSuffix.length() + propertyName.length() &&
- notifySignal.endsWith(changedSuffix) && notifySignal.startsWith(prop.name()))
- {
- signalInfo.append(1);
- } else {
- signalInfo.append(QString::fromLatin1(notifySignal));
- }
- signalInfo.append(prop.notifySignalIndex());
- } else if (!prop.isConstant()) {
- qWarning("Property '%s'' of object '%s' has no notify signal and is not constant, "
- "value updates in HTML will be broken!",
- prop.name(), object->metaObject()->className());
- }
- propertyInfo.append(signalInfo);
- propertyInfo.append(QJsonValue::fromVariant(prop.read(object)));
- qtProperties.append(propertyInfo);
- }
- for (int i = 0; i < metaObject->methodCount(); ++i) {
- if (notifySignals.contains(i)) {
- continue;
- }
- const QMetaMethod &method = metaObject->method(i);
- //NOTE: this must be a string, otherwise it will be converted to '{}' in QML
- const QString &name = QString::fromLatin1(method.name());
- // optimize: skip overloaded methods/signals or property getters, on the JS side we can only
- // call one of them anyways
- // TODO: basic support for overloaded signals, methods
- if (identifiers.contains(name)) {
- continue;
- }
- identifiers << name;
- // send data as array to client with format: [name, index]
- QJsonArray data;
- data.append(name);
- data.append(i);
- if (method.methodType() == QMetaMethod::Signal) {
- qtSignals.append(data);
- } else if (method.access() == QMetaMethod::Public) {
- qtMethods.append(data);
- }
- }
- for (int i = 0; i < metaObject->enumeratorCount(); ++i) {
- QMetaEnum enumerator = metaObject->enumerator(i);
- QJsonObject values;
- for (int k = 0; k < enumerator.keyCount(); ++k) {
- values[QString::fromLatin1(enumerator.key(k))] = enumerator.value(k);
- }
- qtEnums[QString::fromLatin1(enumerator.name())] = values;
- }
- data[KEY_SIGNALS] = qtSignals;
- data[KEY_METHODS] = qtMethods;
- data[KEY_PROPERTIES] = qtProperties;
- data[KEY_ENUMS] = qtEnums;
- return data;
-}
-
-void QMetaObjectPublisher::registerObjects(const QVariantMap &objects)
-{
- if (d->propertyUpdatesInitialized) {
- qWarning("Registered new object after initialization. This does not work!");
- return;
- }
- const QMap<QString, QVariant>::const_iterator end = objects.end();
- for (QMap<QString, QVariant>::const_iterator it = objects.begin(); it != end; ++it) {
- QObject *object = it.value().value<QObject *>();
- if (!object) {
- qWarning("Invalid QObject given to register under name %s", qPrintable(it.key()));
- continue;
- }
- d->registeredObjects[it.key()] = object;
- d->registeredObjectIds[object] = it.key();
- }
-}
-
bool QMetaObjectPublisher::handleRequest(const QJsonObject &message)
{
if (!message.contains(KEY_DATA)) {
@@ -486,13 +455,13 @@ bool QMetaObjectPublisher::handleRequest(const QJsonObject &message)
const QString &type = payload.value(KEY_TYPE).toString();
if (type == TYPE_IDLE) {
- d->setClientIsIdle(true);
+ setClientIsIdle(true);
return true;
} else if (type == TYPE_INIT) {
- if (!d->blockUpdates) {
- d->initializeClients();
+ if (!blockUpdates) {
+ initializeClients();
} else {
- d->pendingInit = true;
+ pendingInit = true;
}
return true;
} else if (type == TYPE_DEBUG) {
@@ -501,19 +470,19 @@ bool QMetaObjectPublisher::handleRequest(const QJsonObject &message)
return true;
} else if (payload.contains(KEY_OBJECT)) {
const QString &objectName = payload.value(KEY_OBJECT).toString();
- QObject *object = d->registeredObjects.value(objectName);
+ QObject *object = registeredObjects.value(objectName);
if (!object) {
qWarning() << "Unknown object encountered" << objectName;
return false;
}
if (type == TYPE_INVOKE_METHOD) {
- return d->invokeMethod(object, payload.value(KEY_METHOD).toInt(-1), payload.value(KEY_ARGS).toArray(), message.value(KEY_ID));
+ return invokeMethod(object, payload.value(KEY_METHOD).toInt(-1), payload.value(KEY_ARGS).toArray(), message.value(KEY_ID));
} else if (type == TYPE_CONNECT_TO_SIGNAL) {
- d->signalHandler.connectTo(object, payload.value(KEY_SIGNAL).toInt(-1));
+ signalHandler.connectTo(object, payload.value(KEY_SIGNAL).toInt(-1));
return true;
} else if (type == TYPE_DISCONNECT_FROM_SIGNAL) {
- d->signalHandler.disconnectFrom(object, payload.value(KEY_SIGNAL).toInt(-1));
+ signalHandler.disconnectFrom(object, payload.value(KEY_SIGNAL).toInt(-1));
return true;
} else if (type == TYPE_SET_PROPERTY) {
const int propertyIdx = payload.value(KEY_PROPERTY).toInt(-1);
@@ -534,65 +503,36 @@ bool QMetaObjectPublisher::handleRequest(const QJsonObject &message)
void QMetaObjectPublisher::handleRawMessage(const QString &message)
{
- QJsonParseError error;
- const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8(), &error);
- if (error.error) {
- qWarning() << "Could not parse raw input message as JSON: " << error.errorString() << "Message was: " << message;
- } else if (doc.isObject() && !handleRequest(doc.object())) {
- qWarning() << "Could not handle raw message as meta object request: " << message;
- }
-}
-
-QWebChannel *QMetaObjectPublisher::webChannel() const
-{
- return d->webChannel;
-}
-
-void QMetaObjectPublisher::setWebChannel(QWebChannel *webChannel)
-{
- if (d->webChannel == webChannel) {
- return;
+ const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
+ if (doc.isObject()) {
+ handleRequest(doc.object());
}
-
- d->webChannel = webChannel;
-
- emit webChannelChanged(webChannel);
-}
-
-bool QMetaObjectPublisher::blockUpdates() const
-{
- return d->blockUpdates;
}
void QMetaObjectPublisher::setBlockUpdates(bool block)
{
- if (d->blockUpdates == block) {
+ if (blockUpdates == block) {
return;
}
- d->blockUpdates = block;
+ blockUpdates = block;
- if (!d->blockUpdates) {
- if (d->pendingInit) {
- d->initializeClients();
+ if (!blockUpdates) {
+ if (pendingInit) {
+ initializeClients();
} else {
- d->sendPendingPropertyUpdates();
+ sendPendingPropertyUpdates();
}
- } else if (d->timer.isActive()) {
- d->timer.stop();
+ } else if (timer.isActive()) {
+ timer.stop();
}
emit blockUpdatesChanged(block);
}
-bool QMetaObjectPublisher::test_clientIsIdle() const
-{
- return d->clientIsIdle;
-}
-
void QMetaObjectPublisher::timerEvent(QTimerEvent *event)
{
- if (event->timerId() == d->timer.timerId()) {
- d->sendPendingPropertyUpdates();
+ if (event->timerId() == timer.timerId()) {
+ sendPendingPropertyUpdates();
} else {
QObject::timerEvent(event);
}
diff --git a/src/webchannel/qmetaobjectpublisher.h b/src/webchannel/qmetaobjectpublisher.h
deleted file mode 100644
index 9d17aff..0000000
--- a/src/webchannel/qmetaobjectpublisher.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Copyright (C) 2013 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:LGPL$
-** 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 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: 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.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QTMETAOBJECTPUBLISHER_H
-#define QTMETAOBJECTPUBLISHER_H
-
-#include <QObject>
-#include <QVariant>
-#include <QJsonObject>
-
-#include "qwebchannelglobal.h"
-
-class QWebChannel;
-
-struct QMetaObjectPublisherPrivate;
-
-class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QWebChannel *webChannel READ webChannel WRITE setWebChannel NOTIFY webChannelChanged);
- Q_PROPERTY(bool blockUpdates READ blockUpdates WRITE setBlockUpdates NOTIFY blockUpdatesChanged);
-
-public:
- explicit QMetaObjectPublisher(QObject *parent = 0);
- virtual ~QMetaObjectPublisher();
-
- Q_INVOKABLE QJsonObject classInfoForObjects(const QVariantMap &objects) const;
- Q_INVOKABLE QJsonObject classInfoForObject(QObject *object) const;
-
- /**
- * Register a map of string ID to QObject* objects.
- *
- * The properties, signals and public methods of the QObject are
- * published to the remote client, where an object with the given identifier
- * is constructed.
- *
- * TODO: This must be called, before clients are initialized.
- */
- Q_INVOKABLE void registerObjects(const QVariantMap &objects);
-
- /**
- * Handle the given WebChannel client request and potentially give a response.
- *
- * @return true if the request was handled, false otherwise.
- */
- Q_INVOKABLE bool handleRequest(const QJsonObject &message);
-
- QWebChannel *webChannel() const;
- void setWebChannel(QWebChannel *webChannel);
-
- /**
- * When updates are blocked, no property updates are transmitted to remote clients.
- */
- bool blockUpdates() const;
- void setBlockUpdates(bool block);
-
- /// TODO: cleanup: rewrite tests in C++ and access PIMPL data from there
- Q_INVOKABLE bool test_clientIsIdle() const;
-
-signals:
- void webChannelChanged(QWebChannel *channel);
- void blockUpdatesChanged(bool block);
-
-public slots:
- /**
- * Helper slot which you can connect directly to WebChannel's rawMessageReceived signal.
- *
- * This slot then tries to parse the message as JSON and if it succeeds, calls handleRequest
- * with the obtained JSON object.
- */
- void handleRawMessage(const QString &message);
-
-protected:
- void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
-
-private:
- QScopedPointer<QMetaObjectPublisherPrivate> d;
- friend struct QMetaObjectPublisherPrivate;
- friend class TestWebChannel;
-};
-
-#endif // QMETAOBJECTPUBLISHER_H
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index 4df5b38..a7342d0 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -51,14 +51,40 @@
#include <QBasicTimer>
#include <QPointer>
-class QMetaObjectPublisher;
class QWebChannel;
#include "qwebchannelglobal.h"
-struct Q_WEBCHANNEL_EXPORT QMetaObjectPublisherPrivate
+class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject
{
- QMetaObjectPublisherPrivate(QMetaObjectPublisher *q);
+ Q_OBJECT
+
+public:
+ QMetaObjectPublisher(QWebChannel *webChannel);
+ virtual ~QMetaObjectPublisher();
+
+ /**
+ * Register @p object nuder the given @p id.
+ *
+ * The properties, signals and public methods of the QObject are
+ * published to the remote client, where an object with the given identifier
+ * is constructed.
+ *
+ * TODO: This must be called, before clients are initialized.
+ */
+ void registerObject(const QString &id, QObject *object);
+
+ /**
+ * Handle the given WebChannel client request and potentially give a response.
+ *
+ * @return true if the request was handled, false otherwise.
+ */
+ bool handleRequest(const QJsonObject &message);
+
+ /**
+ * Serialize the QMetaObject of @p object and return it in JSON form.
+ */
+ QJsonObject classInfoForObject(const QObject *object) const;
/**
* Set the client to idle or busy, based on the value of @p isIdle.
@@ -128,9 +154,33 @@ struct Q_WEBCHANNEL_EXPORT QMetaObjectPublisherPrivate
*/
void deleteWrappedObject(QObject *object) const;
- QMetaObjectPublisher *q;
- QPointer<QWebChannel> webChannel;
- SignalHandler<QMetaObjectPublisherPrivate> signalHandler;
+ /**
+ * When updates are blocked, no property updates are transmitted to remote clients.
+ */
+ void setBlockUpdates(bool block);
+
+public slots:
+ /**
+ * Helper slot which you can connect directly to WebChannel's rawMessageReceived signal.
+ *
+ * This slot then tries to parse the message as JSON and if it succeeds, calls handleRequest
+ * with the obtained JSON object.
+ */
+ void handleRawMessage(const QString &message);
+
+signals:
+ void blockUpdatesChanged(bool block);
+
+protected:
+ void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
+
+private:
+ friend class QmlWebChannel;
+ friend class QWebChannel;
+ friend class TestWebChannel;
+
+ QWebChannel *webChannel;
+ SignalHandler<QMetaObjectPublisher> signalHandler;
// true when the client is idle, false otherwise
bool clientIsIdle;
diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp
index 8dc7e5e..026b31e 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -41,93 +41,14 @@
****************************************************************************/
#include "qwebchannel.h"
+#include "qwebchannel_p.h"
+#include "qmetaobjectpublisher_p.h"
+#include "qwebchannelsocket_p.h"
-#include <QUuid>
-#include <QStringList>
-#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
-#include "qwebsocketserver_p.h"
-
-class QWebChannelPrivate : public QWebSocketServer
-{
- Q_OBJECT
-public:
- QByteArray m_secret;
- bool m_useSecret;
-
- QString m_baseUrl;
- bool m_starting;
-
- QWebChannelPrivate(QObject* parent)
- : QWebSocketServer(parent)
- , m_useSecret(true)
- , m_starting(false)
- {
- connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
- SLOT(socketError()));
- }
-
- void initLater()
- {
- if (m_starting)
- return;
- metaObject()->invokeMethod(this, "init", Qt::QueuedConnection);
- m_starting = true;
- }
-
- void sendJSONMessage(const QJsonValue& id, const QJsonValue& data, bool response) const;
-
-signals:
- void failed(const QString& reason);
- void initialized();
-
-protected:
- bool isValid(const HeaderData& connection) Q_DECL_OVERRIDE;
-
-private slots:
- void init();
- void socketError();
-};
-
-bool QWebChannelPrivate::isValid(const HeaderData& connection)
-{
- if (!QWebSocketServer::isValid(connection)) {
- return false;
- }
- return connection.protocol == QByteArrayLiteral("QWebChannel")
- && connection.path == m_secret;
-}
-
-void QWebChannelPrivate::init()
-{
- close();
-
- m_starting = false;
- if (m_useSecret) {
- m_secret = QUuid::createUuid().toByteArray();
- // replace { by /
- m_secret[0] = '/';
- // chop of trailing }
- m_secret.chop(1);
- }
-
- if (!listen(QHostAddress::LocalHost)) {
- emit failed(errorString());
- return;
- }
-
- m_baseUrl = QStringLiteral("127.0.0.1:%1%2").arg(port()).arg(QString::fromLatin1(m_secret));
- emit initialized();
-}
-
-void QWebChannelPrivate::socketError()
-{
- emit failed(errorString());
-}
-
-void QWebChannelPrivate::sendJSONMessage(const QJsonValue& id, const QJsonValue& data, bool response) const
+void QWebChannelPrivate::sendJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response) const
{
QJsonObject obj;
if (response) {
@@ -138,22 +59,31 @@ void QWebChannelPrivate::sendJSONMessage(const QJsonValue& id, const QJsonValue&
obj[QStringLiteral("data")] = data;
}
QJsonDocument doc(obj);
- sendMessage(doc.toJson(QJsonDocument::Compact));
+ socket->sendMessage(doc.toJson(QJsonDocument::Compact));
}
QWebChannel::QWebChannel(QObject *parent)
: QObject(parent)
-, d(new QWebChannelPrivate(this))
+, d(new QWebChannelPrivate)
{
- connect(d, SIGNAL(textDataReceived(QString)),
+ d->socket = new QWebChannelSocket(this);
+
+ connect(d->socket, SIGNAL(textDataReceived(QString)),
SIGNAL(rawMessageReceived(QString)));
- connect(d, SIGNAL(failed(QString)),
+ connect(d->socket, SIGNAL(failed(QString)),
SIGNAL(failed(QString)));
- connect(d, SIGNAL(initialized()),
+ connect(d->socket, SIGNAL(initialized()),
SLOT(onInitialized()));
- connect(d, SIGNAL(pongReceived()),
+ connect(d->socket, SIGNAL(pongReceived()),
SIGNAL(pongReceived()));
- d->initLater();
+
+ d->socket->initLater();
+
+ d->publisher = new QMetaObjectPublisher(this);
+ connect(d->publisher, SIGNAL(blockUpdatesChanged(bool)),
+ SIGNAL(blockUpdatesChanged(bool)));
+ connect(d->socket, SIGNAL(textDataReceived(QString)),
+ d->publisher, SLOT(handleRawMessage(QString)));
}
QWebChannel::~QWebChannel()
@@ -162,26 +92,49 @@ QWebChannel::~QWebChannel()
QString QWebChannel::baseUrl() const
{
- return d->m_baseUrl;
+ return d->socket->m_baseUrl;
}
void QWebChannel::setUseSecret(bool s)
{
- if (d->m_useSecret == s)
+ if (d->socket->m_useSecret == s)
return;
- d->m_useSecret = s;
- d->initLater();
+ d->socket->m_useSecret = s;
+ d->socket->initLater();
}
bool QWebChannel::useSecret() const
{
- return d->m_useSecret;
+ return d->socket->m_useSecret;
+}
+
+void QWebChannel::registerObjects(const QHash< QString, QObject * > &objects)
+{
+ const QHash<QString, QObject *>::const_iterator end = objects.constEnd();
+ for (QHash<QString, QObject *>::const_iterator it = objects.constBegin(); it != end; ++it) {
+ d->publisher->registerObject(it.key(), it.value());
+ }
+}
+
+void QWebChannel::registerObject(const QString &id, QObject *object)
+{
+ d->publisher->registerObject(id, object);
+}
+
+bool QWebChannel::blockUpdates() const
+{
+ return d->publisher->blockUpdates;
+}
+
+void QWebChannel::setBlockUpdates(bool block)
+{
+ d->publisher->setBlockUpdates(block);
}
void QWebChannel::onInitialized()
{
emit initialized();
- emit baseUrlChanged(d->m_baseUrl);
+ emit baseUrlChanged(d->socket->m_baseUrl);
}
void QWebChannel::respond(const QJsonValue& messageId, const QJsonValue& data) const
@@ -196,12 +149,12 @@ void QWebChannel::sendMessage(const QJsonValue& id, const QJsonValue& data) cons
void QWebChannel::sendRawMessage(const QString& message) const
{
- d->sendMessage(message.toUtf8());
+ d->socket->sendMessage(message.toUtf8());
}
void QWebChannel::ping() const
{
- d->ping();
+ d->socket->ping();
}
#include "qwebchannel.moc"
diff --git a/src/webchannel/qwebchannel.h b/src/webchannel/qwebchannel.h
index 321706e..ec62208 100644
--- a/src/webchannel/qwebchannel.h
+++ b/src/webchannel/qwebchannel.h
@@ -56,16 +56,43 @@ class Q_WEBCHANNEL_EXPORT QWebChannel : public QObject
Q_DISABLE_COPY(QWebChannel)
Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged)
Q_PROPERTY(bool useSecret READ useSecret WRITE setUseSecret)
+ Q_PROPERTY(bool blockUpdates READ blockUpdates WRITE setBlockUpdates NOTIFY blockUpdatesChanged);
public:
QWebChannel(QObject *parent = 0);
~QWebChannel();
- QString baseUrl() const;
+ QString baseUrl() const;
void setUseSecret(bool);
bool useSecret() const;
+ /**
+ * Register a map of string ID to QObject* objects.
+ *
+ * The properties, signals and public methods of the QObject are
+ * published to the remote client, where an object with the given identifier
+ * is constructed.
+ *
+ * TODO: This must be called, before clients are initialized.
+ */
+ void registerObjects(const QHash<QString, QObject*> &objects);
+ void registerObject(const QString &id, QObject *object);
+
+ /**
+ * @return true when property updates are blocked, false otherwise.
+ */
+ bool blockUpdates() const;
+
+ /**
+ * Set whether property updates should be blocked or not.
+ *
+ * When they are blocked, the remote clients will not be notified about
+ * property changes. The changes are recorded and sent to the clients once
+ * setBlockUpdates(false) is called.
+ */
+ void setBlockUpdates(bool block);
+
signals:
void baseUrlChanged(const QString& baseUrl);
void rawMessageReceived(const QString& rawMessage);
@@ -74,6 +101,8 @@ signals:
void failed(const QString& reason);
+ void blockUpdatesChanged(bool block);
+
public slots:
void sendMessage(const QJsonValue& id, const QJsonValue& data = QJsonValue()) const;
void respond(const QJsonValue& messageId, const QJsonValue& data = QJsonValue()) const;
@@ -84,7 +113,9 @@ private slots:
void onInitialized();
private:
- QWebChannelPrivate* d;
+ QScopedPointer<QWebChannelPrivate> d;
+ friend class QmlWebChannel;
+ friend class TestWebChannel;
};
#endif // QWEBCHANNEL_H
diff --git a/src/webchannel/qwebchannel_p.h b/src/webchannel/qwebchannel_p.h
new file mode 100644
index 0000000..3b8a34b
--- /dev/null
+++ b/src/webchannel/qwebchannel_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 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:LGPL$
+** 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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBCHANNEL_P_H
+#define QWEBCHANNEL_P_H
+
+#include "qwebchannelglobal.h"
+
+class QJsonValue;
+class QWebChannelSocket;
+class QMetaObjectPublisher;
+
+struct Q_WEBCHANNEL_EXPORT QWebChannelPrivate
+{
+ QWebChannelSocket *socket;
+ QMetaObjectPublisher *publisher;
+
+ void sendJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response) const;
+};
+
+#endif // QWEBCHANNEL_P_H
diff --git a/src/webchannel/qwebchannelsocket.cpp b/src/webchannel/qwebchannelsocket.cpp
new file mode 100644
index 0000000..c5275d0
--- /dev/null
+++ b/src/webchannel/qwebchannelsocket.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 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:LGPL$
+** 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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwebchannelsocket_p.h"
+
+#include <QUuid>
+#include <QDebug>
+
+QWebChannelSocket::QWebChannelSocket(QObject *parent)
+ : QWebSocketServer(parent)
+ , m_useSecret(true)
+ , m_starting(false)
+{
+ connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
+ SLOT(socketError()));
+}
+
+void QWebChannelSocket::initLater()
+{
+ if (m_starting)
+ return;
+ metaObject()->invokeMethod(this, "init", Qt::QueuedConnection);
+ m_starting = true;
+}
+
+bool QWebChannelSocket::isValid(const HeaderData &connection)
+{
+ if (!QWebSocketServer::isValid(connection)) {
+ return false;
+ }
+ return connection.protocol == QByteArrayLiteral("QWebChannel")
+ && connection.path == m_secret;
+}
+
+void QWebChannelSocket::init()
+{
+ close();
+
+ m_starting = false;
+ if (m_useSecret) {
+ m_secret = QUuid::createUuid().toByteArray();
+ // replace { by /
+ m_secret[0] = '/';
+ // chop of trailing }
+ m_secret.chop(1);
+ }
+
+ if (!listen(QHostAddress::LocalHost)) {
+ emit failed(errorString());
+ return;
+ }
+
+ m_baseUrl = QStringLiteral("127.0.0.1:%1%2").arg(port()).arg(QString::fromLatin1(m_secret));
+ emit initialized();
+}
+
+void QWebChannelSocket::socketError()
+{
+ emit failed(errorString());
+}
diff --git a/src/webchannel/qwebchannelsocket_p.h b/src/webchannel/qwebchannelsocket_p.h
new file mode 100644
index 0000000..234c200
--- /dev/null
+++ b/src/webchannel/qwebchannelsocket_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 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:LGPL$
+** 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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBCHANNELSOCKET_P_H
+#define QWEBCHANNELSOCKET_P_H
+
+#include "qwebsocketserver_p.h"
+
+class QWebChannelSocket : public QWebSocketServer
+{
+ Q_OBJECT
+public:
+ QByteArray m_secret;
+ QString m_baseUrl;
+
+ bool m_useSecret;
+ bool m_starting;
+
+ QWebChannelSocket(QObject *parent);
+
+ void initLater();
+
+signals:
+ void failed(const QString &reason);
+ void initialized();
+
+protected:
+ bool isValid(const HeaderData &connection) Q_DECL_OVERRIDE;
+
+private slots:
+ void init();
+ void socketError();
+};
+
+#endif // QWEBCHANNELSOCKET_P_H
diff --git a/src/webchannel/signalhandler_p.h b/src/webchannel/signalhandler_p.h
index 66bdb28..8c49346 100644
--- a/src/webchannel/signalhandler_p.h
+++ b/src/webchannel/signalhandler_p.h
@@ -141,7 +141,7 @@ SignalHandler<Receiver>::SignalHandler(Receiver *receiver, QObject *parent)
*
* The return value is also verified to ensure it is a signal.
*/
-QMetaMethod findSignal(const QMetaObject *metaObject, const int signalIndex)
+inline QMetaMethod findSignal(const QMetaObject *metaObject, const int signalIndex)
{
QMetaMethod signal = metaObject->method(signalIndex);
if (!signal.isValid()) {
diff --git a/src/webchannel/webchannel.pro b/src/webchannel/webchannel.pro
index 376711d..0678346 100644
--- a/src/webchannel/webchannel.pro
+++ b/src/webchannel/webchannel.pro
@@ -11,17 +11,20 @@ OTHER_FILES = \
qwebchannel.js
PUBLIC_HEADERS += \
- qwebchannel.h \
- qmetaobjectpublisher.h
+ qwebchannel.h
PRIVATE_HEADERS += \
+ qwebchannel_p.h \
+ qmetaobjectpublisher_p.h \
qwebsocketserver_p.h \
+ qwebchannelsocket_p.h \
variantargument_p.h \
signalhandler_p.h
SOURCES += \
qwebchannel.cpp \
qmetaobjectpublisher.cpp \
- qwebsocketserver.cpp
+ qwebsocketserver.cpp \
+ qwebchannelsocket.cpp
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS