summaryrefslogtreecommitdiffstats
ModeNameSize
-rw-r--r--.gitattributes151logstatsplain
-rw-r--r--.gitignore7873logstatsplain
-rw-r--r--.qmake.conf129logstatsplain
-rw-r--r--.tag12logstatsplain
-rw-r--r--INSTALL521logstatsplain
-rw-r--r--LGPL_EXCEPTION.txt1196logstatsplain
-rw-r--r--LICENSE.FDL22961logstatsplain
-rw-r--r--LICENSE.GPL218092logstatsplain
-rw-r--r--LICENSE.GPL335147logstatsplain
-rw-r--r--LICENSE.GPL3-EXCEPT36363logstatsplain
-rw-r--r--LICENSE.LGPL37651logstatsplain
-rw-r--r--LICENSE.LGPLv38173logstatsplain
-rw-r--r--LICENSE.QT-LICENSE-AGREEMENT-4.046903logstatsplain
d---------bin81logstatsplain
d---------config.tests626logstatsplain
-rw-r--r--config_help.txt16741logstatsplain
-rwxr-xr-xconfigure26968logstatsplain
-rw-r--r--configure.bat7923logstatsplain
-rw-r--r--configure.json49495logstatsplain
-rw-r--r--configure.pri46584logstatsplain
d---------dist6250logstatsplain
d---------doc132logstatsplain
d---------examples602logstatsplain
-rw-r--r--header.BSD2457logstatsplain
-rw-r--r--header.COMM805logstatsplain
-rw-r--r--header.FDL1256logstatsplain
-rw-r--r--header.GPL1341logstatsplain
-rw-r--r--header.GPL-EXCEPT1272logstatsplain
-rw-r--r--header.LGPL1918logstatsplain
-rw-r--r--header.LGPL-NOGPL21810logstatsplain
-rw-r--r--header.LGPL-ONLY937logstatsplain
-rw-r--r--header.LGPL31722logstatsplain
-rw-r--r--header.LGPL3-COMM1278logstatsplain
d---------lib34logstatsplain
d---------mkspecs2622logstatsplain
d---------qmake861logstatsplain
-rw-r--r--qtbase.pro2624logstatsplain
d---------src729logstatsplain
-rw-r--r--sync.profile4456logstatsplain
d---------tests279logstatsplain
d---------util469logstatsplain
********************************************* ** ** 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.io/licensing/ ** ** 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 The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/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. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmetaobjectpublisher_p.h" #include "qwebchannel.h" #include "qwebchannel_p.h" #include "qwebchannelabstracttransport.h" #include <QEvent> #include <QJsonDocument> #include <QDebug> #include <QJsonObject> #include <QJsonArray> #include <QJSValue> #include <QUuid> QT_BEGIN_NAMESPACE namespace { MessageType toType(const QJsonValue &value) { int i = value.toInt(-1); if (i >= TYPES_FIRST_VALUE && i <= TYPES_LAST_VALUE) { return static_cast<MessageType>(i); } else { return TypeInvalid; } } const QString KEY_SIGNALS = QStringLiteral("signals"); const QString KEY_METHODS = QStringLiteral("methods"); const QString KEY_PROPERTIES = QStringLiteral("properties"); const QString KEY_ENUMS = QStringLiteral("enums"); const QString KEY_QOBJECT = QStringLiteral("__QObject*__"); const QString KEY_ID = QStringLiteral("id"); const QString KEY_DATA = QStringLiteral("data"); const QString KEY_OBJECT = QStringLiteral("object"); const QString KEY_DESTROYED = QStringLiteral("destroyed"); const QString KEY_SIGNAL = QStringLiteral("signal"); const QString KEY_TYPE = QStringLiteral("type"); const QString KEY_METHOD = QStringLiteral("method"); const QString KEY_ARGS = QStringLiteral("args"); const QString KEY_PROPERTY = QStringLiteral("property"); const QString KEY_VALUE = QStringLiteral("value"); QJsonObject createResponse(const QJsonValue &id, const QJsonValue &data) { QJsonObject response; response[KEY_TYPE] = TypeResponse; response[KEY_ID] = id; response[KEY_DATA] = data; return response; } /// TODO: what is the proper value here? const int PROPERTY_UPDATE_INTERVAL = 50; } QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel) : QObject(webChannel) , webChannel(webChannel) , signalHandler(this) , clientIsIdle(false) , blockUpdates(false) , propertyUpdatesInitialized(false) { } QMetaObjectPublisher::~QMetaObjectPublisher() { } void QMetaObjectPublisher::registerObject(const QString &id, QObject *object) { registeredObjects[id] = object; registeredObjectIds[object] = id; if (propertyUpdatesInitialized) { if (!webChannel->d_func()->transports.isEmpty()) { qWarning("Registered new object after initialization, existing clients won't be notified!"); // TODO: send a message to clients that an object was added } initializePropertyUpdates(object, classInfoForObject(object, Q_NULLPTR)); } } QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport) { 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(wrapResult(prop.read(object), transport)); 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; if (!qtEnums.isEmpty()) { data[KEY_ENUMS] = qtEnums; } return data; } void QMetaObjectPublisher::setClientIsIdle(bool isIdle) { if (clientIsIdle == isIdle) { return; } clientIsIdle = isIdle; if (!isIdle && timer.isActive()) { timer.stop(); } else if (isIdle && !timer.isActive()) { timer.start(PROPERTY_UPDATE_INTERVAL, this); } } QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport *transport) { QJsonObject objectInfos; { const QHash<QString, QObject *>::const_iterator end = registeredObjects.constEnd(); for (QHash<QString, QObject *>::const_iterator it = registeredObjects.constBegin(); it != end; ++it) { const QJsonObject &info = classInfoForObject(it.value(), transport); if (!propertyUpdatesInitialized) {