diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2013-01-18 16:27:42 +0100 |
---|---|---|
committer | Pierre Rossi <pierre.rossi@gmail.com> | 2013-11-01 13:57:42 +0100 |
commit | 62c243c979b172ae554f372a0d883c0273cafc53 (patch) | |
tree | 432211b3d834cf3702012afffc510c349e436e3b /src | |
parent | b23f72024c14153d233563f600a359456649aaaf (diff) | |
download | qtwebchannel-62c243c979b172ae554f372a0d883c0273cafc53.tar.gz |
Refactor the QObject QWebChannel and make the API reusable.
It might becme a very common use case of the QWebChannel QML plugin.
Thus it should be as simple as possible for third party consumers to
setup a QWebChannel for QObject publishing.
The new API basically moves the QtMetaObjectPublisher along with
the JavaScript marshalling to the qwebchannl/src folder.
The updated qtobject example shows how this new API can be used.
Furthermore note how it is now trivially possible to register
multiple objects, which was not easily possible before.
Some notes on the applied refactoring:
- qobject.js contains the JavaScript QObject binding and was
refactored to support multiple objects.
- the MetaObjectPublisher contains a new handleRequest function
which handles the QML-side of the QObject binding. This is
implemented in QML, while the other book keeping and esp. the
classInfoForObject is still handled in C++ via the
QtMetaObjectPublisher class (which is registered as
MetaObjectPublisherPrivate and used by MetaObjectPublisher)
Change-Id: Id45121bb654447e095bf8a8062d0c8edf9dcb018
Reviewed-by: Pierre Rossi <pierre.rossi@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/MetaObjectPublisher.qml | 74 | ||||
-rw-r--r-- | src/qmldir | 3 | ||||
-rw-r--r-- | src/qobject.js | 119 | ||||
-rw-r--r-- | src/qtmetaobjectpublisher.cpp | 73 | ||||
-rw-r--r-- | src/qtmetaobjectpublisher.h | 74 | ||||
-rw-r--r-- | src/qwebchannel.cpp | 9 | ||||
-rw-r--r-- | src/qwebchannel_plugin.cpp | 3 | ||||
-rw-r--r-- | src/resources.qrc | 1 | ||||
-rw-r--r-- | src/src.pri | 4 | ||||
-rw-r--r-- | src/src.pro | 7 | ||||
-rw-r--r-- | src/webchannel-iframe.html | 1 |
11 files changed, 361 insertions, 7 deletions
diff --git a/src/MetaObjectPublisher.qml b/src/MetaObjectPublisher.qml new file mode 100644 index 0000000..e938a83 --- /dev/null +++ b/src/MetaObjectPublisher.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QWebChannel module on Qt labs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +import Qt.labs.WebChannel 1.0 + +MetaObjectPublisherPrivate { + function handleRequest(payload, webChannel) { + var object = publisher.namedObject(payload.object); + var ret = false; + if (payload.type == "Qt.invokeMethod") { + ret = (object[payload.method])(payload.args); + } else if (payload.type == "Qt.connectToSignal") { + object[payload.signal].connect( + function(a,b,c,d,e,f,g,h,i,j) { + webChannel.broadcast("Qt.signal", JSON.stringify({object: payload.object, signal: payload.signal, args: [a,b,c,d,e,f,g,h,i,j]})); + }); + } else if (payload.type == "Qt.getProperty") { + ret = object[payload.property]; + } else if (payload.type == "Qt.setProperty") { + object[payload.property] = payload.value; + } else if (payload.type == "Qt.getObjects") { + var objects = {}; + var objectNames = publisher.objectNames; + for (var i = 0; i < objectNames.length; ++i) { + var name = objectNames[i]; + var object = publisher.namedObject(name); + objects[name] = publisher.classInfoForObject(object); + } + ret = objects; + } + + return ret; + } +}
\ No newline at end of file @@ -1,2 +1,3 @@ +module Qt.labs.WebChannel plugin qwebchannel - +MetaObjectPublisher 1.0 MetaObjectPublisher.qml
\ No newline at end of file diff --git a/src/qobject.js b/src/qobject.js new file mode 100644 index 0000000..d5d7f42 --- /dev/null +++ b/src/qobject.js @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QWebChannel module on Qt labs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +function QObject(name, data, webChannel) { + this.__id__ = name; + this.__objectSignals__ = {}; + + var methodsAndSignals = []; + for (var i in data.methods) + methodsAndSignals.push(data.methods[i]); + for (i in data.signals) + methodsAndSignals.push(data.signals[i]); + + var object = this; + + methodsAndSignals.forEach(function(method) { + object[method] = function() { + var args = []; + var callback; + for (var i = 0; i < arguments.length; ++i) { + if (typeof arguments[i] == "function") + callback = arguments[i]; + else + args.push(arguments[i]); + } + + webChannel.exec(JSON.stringify({"type": "Qt.invokeMethod", "object": object.__id__, "method": method, "args": args}), function(response) { + if (response.length) + (callback)(JSON.parse(response)); + }); + }; + }); + + for (i in data.signals) { + var signal = data.signals[i]; + object[signal].connect = function(callback) { + object.__objectSignals__[signal] = object.__objectSignals__[signal] || []; + webChannel.exec(JSON.stringify({"type": "Qt.connectToSignal", "object": object.__id__, "signal": signal})); + object.__objectSignals__[signal].push(callback); + }; + } + + for (i in data.properties) { + var prop = data.properties[i]; + object.__defineSetter__(prop, function(value) { + webChannel.exec(JSON.stringify({"type": "Qt.setProperty", "object": object.__id__, "property": prop, "value": value })); + }); + object.__defineGetter__(prop, function() { + return (function(callback) { + webChannel.exec(JSON.stringify({"type": "Qt.getProperty", "object": object.__id__, "property": prop}), function(response) { + callback(JSON.parse(response)); + }); + }); + }); + } +} + +window.setupQObjectWebChannel = function(webChannel) { + webChannel.subscribe( + "Qt.signal", + function(payload) { + var signalData = JSON.parse(payload); + var object = window[signalData.object]; + var conns = (object ? object.__objectSignals__[signalData.signal] : []) || []; + var a = payload.args; + conns.forEach(function(callback) { + callback.call(a); + }); + } + ); + webChannel.exec(JSON.stringify({type:"Qt.getObjects"}), function(response) { + if (response.length) { + var objects = JSON.parse(response); + for (var objectName in objects) { + var data = objects[objectName]; + var object = new QObject(objectName, data, webChannel); + window[objectName] = object; + } + } + }); +}; diff --git a/src/qtmetaobjectpublisher.cpp b/src/qtmetaobjectpublisher.cpp new file mode 100644 index 0000000..d136ce7 --- /dev/null +++ b/src/qtmetaobjectpublisher.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QWebChannel module on Qt labs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtmetaobjectpublisher.h" +#include <QVariantMap> +#include <QStringList> +#include <QMetaObject> +#include <QMetaProperty> + +QtMetaObjectPublisher::QtMetaObjectPublisher(QObject *parent) : + QObject(parent) +{ +} + +QVariantMap QtMetaObjectPublisher::classInfoForObject(QObject *object) +{ + QVariantMap data; + QStringList qtSignals, qtMethods, qtProperties; + const QMetaObject* metaObject = object->metaObject(); + for (int i = 0; i < metaObject->propertyCount(); ++i) + qtProperties.append(metaObject->property(i).name()); + for (int i = 0; i < metaObject->methodCount(); ++i) { + QMetaMethod method = metaObject->method(i); + QString signature = method.methodSignature(); + QString name = signature.left(signature.indexOf("(")); + if (method.access() == QMetaMethod::Public) + qtMethods << signature << name; + if (method.methodType() == QMetaMethod::Signal) + qtSignals << signature << name; + } + data["signals"] = qtSignals; + data["methods"] = qtMethods; + data["properties"] = qtProperties; + return data; +} diff --git a/src/qtmetaobjectpublisher.h b/src/qtmetaobjectpublisher.h new file mode 100644 index 0000000..816338a --- /dev/null +++ b/src/qtmetaobjectpublisher.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QWebChannel module on Qt labs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMETAOBJECTPUBLISHER_H +#define QTMETAOBJECTPUBLISHER_H + +#include <QObject> +#include <QVariantMap> +#include <QPointer> +#include <QStringList> + +class QtMetaObjectPublisher : public QObject +{ + Q_OBJECT + Q_PROPERTY(QStringList objectNames READ objectNames) +public: + explicit QtMetaObjectPublisher(QObject *parent = 0); + Q_INVOKABLE QVariantMap classInfoForObject(QObject*); + QStringList objectNames() { return objects.keys(); } + Q_INVOKABLE QObject* namedObject(const QString& name) { + if (!objects.contains(name)) + return 0; + return objects[name]; + } +public slots: + void addObject(const QString& name, QObject* object) + { + objects[name] = object; + } + +private: + QMap<QString, QPointer<QObject> > objects; + +}; + +#endif // QTMETAOBJECTPUBLISHER_H diff --git a/src/qwebchannel.cpp b/src/qwebchannel.cpp index 6d7d62f..ee03cf8 100644 --- a/src/qwebchannel.cpp +++ b/src/qwebchannel.cpp @@ -311,6 +311,15 @@ void QWebChannelPrivate::handleHttpRequest(QTcpSocket *socket, const HttpRequest socket->write("\n})();"); socket->close(); file.close(); + } else if (type == "qobject.js") { + QFile file(":/qobject.js"); + file.open(QIODevice::ReadOnly); + socket->write("HTTP/1.1 200 OK\r\n" + "Content-Type: text/javascript\r\n" + "\r\n"); + socket->write(file.readAll()); + socket->close(); + file.close(); } else if (type == "iframe.html") { QFile file(":/webchannel-iframe.html"); file.open(QIODevice::ReadOnly); diff --git a/src/qwebchannel_plugin.cpp b/src/qwebchannel_plugin.cpp index a0675d6..1c71463 100644 --- a/src/qwebchannel_plugin.cpp +++ b/src/qwebchannel_plugin.cpp @@ -42,12 +42,13 @@ #include <qqml.h> #include "qwebchannel.h" +#include "qtmetaobjectpublisher.h" #include "qwebchannel_plugin.h" void QWebChannelPlugin::registerTypes(const char *uri) { - Q_ASSERT(uri == QLatin1String("Qt.labs.WebChannel")); qmlRegisterType<QWebChannel>(uri, 1, 0, "WebChannel"); + qmlRegisterType<QtMetaObjectPublisher>(uri, 1, 0, "MetaObjectPublisherPrivate"); } diff --git a/src/resources.qrc b/src/resources.qrc index 6f81393..431c12b 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -1,6 +1,7 @@ <RCC> <qresource prefix="/"> <file>webchannel.js</file> + <file>qobject.js</file> <file>webchannel-iframe.html</file> </qresource> </RCC> diff --git a/src/src.pri b/src/src.pri index c64cc76..55ed7e3 100644 --- a/src/src.pri +++ b/src/src.pri @@ -1,3 +1,3 @@ QT += network -SOURCES += $$PWD/qwebchannel.cpp -HEADERS += $$PWD/qwebchannel.h +SOURCES += $$PWD/qwebchannel.cpp $$PWD/qtmetaobjectpublisher.cpp +HEADERS += $$PWD/qwebchannel.h $$PWD/qtmetaobjectpublisher.h diff --git a/src/src.pro b/src/src.pro index 1f940c6..1f5a62e 100644 --- a/src/src.pro +++ b/src/src.pro @@ -13,7 +13,6 @@ SOURCES += qwebchannel_plugin.cpp HEADERS += qwebchannel_plugin.h OTHER_FILES = qmldir \ - qwebchannel.js \ qtc_packaging/debian_harmattan/rules \ qtc_packaging/debian_harmattan/README \ qtc_packaging/debian_harmattan/copyright \ @@ -21,7 +20,9 @@ OTHER_FILES = qmldir \ qtc_packaging/debian_harmattan/compat \ qtc_packaging/debian_harmattan/changelog \ webchannel.js \ - webchannel-iframe.html + qobject.js \ + webchannel-iframe.html \ + MetaObjectPublisher.qml !equals(_PRO_FILE_PWD_, $$OUT_PWD) { copy_qmldir.target = $$OUT_PWD/qmldir @@ -33,7 +34,7 @@ OTHER_FILES = qmldir \ target.path = $$[QT_INSTALL_QML]/$$TARGETPATH -qmldir.files += $$PWD/qmldir +qmldir.files += $$PWD/qmldir $$PWD/MetaObjectPublisher.qml qmldir.path += $$[QT_INSTALL_QML]/$$TARGETPATH INSTALLS += target qmldir diff --git a/src/webchannel-iframe.html b/src/webchannel-iframe.html index 1f93eac..bbaf7cd 100644 --- a/src/webchannel-iframe.html +++ b/src/webchannel-iframe.html @@ -24,6 +24,7 @@ window.addEventListener("message", function(event) { var data = JSON.parse(event.data); + console.log("MESSAGE:", data); function callback(r) { window.parent.postMessage(JSON.stringify({ type: "callback", id: data.id, payload: r }), "*"); } if (data.type == "EXEC") exec(data.payload, callback); |