summaryrefslogtreecommitdiff
path: root/src/webchannel/qmetaobjectpublisher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/webchannel/qmetaobjectpublisher.cpp')
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp112
1 files changed, 69 insertions, 43 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index c476011..0c22798 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -104,15 +104,18 @@ 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;
+ 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) const
+QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport)
{
QJsonObject data;
if (!object) {
@@ -160,7 +163,7 @@ QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) cons
prop.name(), object->metaObject()->className());
}
propertyInfo.append(signalInfo);
- propertyInfo.append(QJsonValue::fromVariant(prop.read(object)));
+ propertyInfo.append(wrapResult(prop.read(object), transport));
qtProperties.append(propertyInfo);
}
for (int i = 0; i < metaObject->methodCount(); ++i) {
@@ -217,13 +220,13 @@ void QMetaObjectPublisher::setClientIsIdle(bool isIdle)
}
}
-QJsonObject QMetaObjectPublisher::initializeClient()
+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());
+ const QJsonObject &info = classInfoForObject(it.value(), transport);
if (!propertyUpdatesInitialized) {
initializePropertyUpdates(it.value(), info);
}
@@ -280,6 +283,7 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates()
for (PendingPropertyUpdates::const_iterator it = pendingPropertyUpdates.constBegin(); it != end; ++it) {
const QObject *object = it.key();
const QMetaObject *const metaObject = object->metaObject();
+ const QString objectId = registeredObjectIds.value(object);
const SignalToPropertyNameMap &objectsSignalToPropertyMap = signalToPropertyMap.value(object);
// maps property name to current property value
QJsonObject properties;
@@ -291,12 +295,11 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates()
foreach (const int propertyIndex, objectsSignalToPropertyMap.value(sigIt.key())) {
const QMetaProperty &property = metaObject->property(propertyIndex);
Q_ASSERT(property.isValid());
- properties[QString::number(propertyIndex)] = QJsonValue::fromVariant(property.read(object));
+ properties[QString::number(propertyIndex)] = wrapResult(property.read(object), Q_NULLPTR, objectId);
}
sigs[QString::number(sigIt.key())] = QJsonArray::fromVariantList(sigIt.value());
}
QJsonObject obj;
- const QString objectId = registeredObjectIds.value(object);
obj[KEY_OBJECT] = objectId;
obj[KEY_SIGNALS] = sigs;
obj[KEY_PROPERTIES] = properties;
@@ -400,9 +403,7 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal
message[KEY_OBJECT] = objectName;
message[KEY_SIGNAL] = signalIndex;
if (!arguments.isEmpty()) {
- // TODO: wrap (new) objects on the fly
- QJsonArray args = QJsonArray::fromVariantList(arguments);
- message[KEY_ARGS] = args;
+ message[KEY_ARGS] = wrapList(arguments, Q_NULLPTR, objectName);
}
message[KEY_TYPE] = TypeSignal;
@@ -435,52 +436,77 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object)
Q_ASSERT(removed);
Q_UNUSED(removed);
+ signalHandler.remove(object);
signalToPropertyMap.remove(object);
pendingPropertyUpdates.remove(object);
}
-QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport)
+// NOTE: transport can be a nullptr
+// in such a case, we need to ensure that the property is registered to
+// the target transports of the parentObjectId
+QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport,
+ const QString &parentObjectId)
{
if (QObject *object = result.value<QObject *>()) {
QString id = registeredObjectIds.value(object);
-
- QJsonObject objectInfo;
-
- if (!id.isEmpty() && wrappedObjects.contains(id)) {
- Q_ASSERT(object == wrappedObjects.value(id).object);
- // check if this transport is already assigned to the object
- if (!wrappedObjects.value(id).transports.contains(transport))
- wrappedObjects[id].transports.append(transport);
- return wrappedObjects.value(id).classinfo;
- } else {
+ QJsonObject classInfo;
+ if (id.isEmpty()) {
+ // neither registered, nor wrapped, do so now
id = QUuid::createUuid().toString();
+ Q_ASSERT(!registeredObjects.contains(id));
- QJsonObject info = classInfoForObject(object);
- objectInfo[KEY_QOBJECT] = true;
- objectInfo[KEY_ID] = id;
- objectInfo[KEY_DATA] = info;
+ classInfo = classInfoForObject(object, transport);
- if (!registeredObjects.contains(id)) {
- registeredObjectIds[object] = id;
- ObjectInfo oi(object, objectInfo);
- oi.transports.append(transport);
- wrappedObjects.insert(id, oi);
+ registeredObjectIds[object] = id;
- initializePropertyUpdates(object, info);
+ ObjectInfo oi(object, classInfo);
+ if (transport) {
+ oi.transports.append(transport);
+ } else {
+ // use the transports from the parent object
+ oi.transports = wrappedObjects.value(parentObjectId).transports;
+ // or fallback to all transports if the parent is not wrapped
+ if (oi.transports.isEmpty())
+ oi.transports = webChannel->d_func()->transports;
}
+ wrappedObjects.insert(id, oi);
+
+ initializePropertyUpdates(object, classInfo);
+ } else if (wrappedObjects.contains(id)) {
+ Q_ASSERT(object == wrappedObjects.value(id).object);
+ // check if this transport is already assigned to the object
+ if (transport && !wrappedObjects.value(id).transports.contains(transport))
+ wrappedObjects[id].transports.append(transport);
+ classInfo = wrappedObjects.value(id).classinfo;
}
+
+ QJsonObject objectInfo;
+ objectInfo[KEY_QOBJECT] = true;
+ objectInfo[KEY_ID] = id;
+ if (!classInfo.isEmpty())
+ objectInfo[KEY_DATA] = classInfo;
return objectInfo;
+ } else if (result.canConvert<QJSValue>()) {
+ // Workaround for keeping QJSValues from QVariant.
+ // Calling QJSValue::toVariant() converts JS-objects/arrays to QVariantMap/List
+ // instead of stashing a QJSValue itself into a variant.
+ // TODO: Improve QJSValue-QJsonValue conversion in Qt.
+ return wrapResult(result.value<QJSValue>().toVariant(), transport, parentObjectId);
+ } else if (result.canConvert<QVariantList>()) {
+ // recurse and potentially wrap contents of the array
+ return wrapList(result.toList(), transport);
}
- // Workaround for keeping QJSValues from QVariant.
- // Calling QJSValue::toVariant() converts JS-objects/arrays to QVariantMap/List
- // instead of stashing a QJSValue itself into a variant.
- // TODO: Improve QJSValue-QJsonValue conversion in Qt.
- QVariant jsvVariant = result;
- if (result.canConvert<QJSValue>())
- jsvVariant = result.value<QJSValue>().toVariant();
+ return QJsonValue::fromVariant(result);
+}
- return QJsonValue::fromVariant(jsvVariant);
+QJsonArray QMetaObjectPublisher::wrapList(const QVariantList &list, QWebChannelAbstractTransport *transport, const QString &parentObjectId)
+{
+ QJsonArray array;
+ foreach (const QVariant &arg, list) {
+ array.append(wrapResult(arg, transport, parentObjectId));
+ }
+ return array;
}
void QMetaObjectPublisher::deleteWrappedObject(QObject *object) const
@@ -525,7 +551,7 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel
QJsonDocument(message).toJson().constData());
return;
}
- transport->sendMessage(createResponse(message.value(KEY_ID), initializeClient()));
+ transport->sendMessage(createResponse(message.value(KEY_ID), initializeClient(transport)));
} else if (type == TypeDebug) {
static QTextStream out(stdout);
out << "DEBUG: " << message.value(KEY_DATA).toString() << endl;