diff options
author | Brett Stottlemyer <bstottle@ford.com> | 2017-12-06 11:21:49 -0600 |
---|---|---|
committer | Tony SarajΓ€rvi <tony.sarajarvi@qt.io> | 2017-12-13 08:33:46 +0000 |
commit | 833885e3f342ead957128413fd451cb1eb71a65b (patch) | |
tree | 3e92ad0cc9cc4c3ba78c214f299ee1b57081129f /src/remoteobjects/qremoteobjectsource.cpp | |
parent | 9ae28ac68af20b4d8b305fa78a478833cc833642 (diff) |
Add/extend Class/Model keywords for repc
The Class and Model extensions to QML are very similar in that they come
down to additional QObject derived types that need to be made available
to the QtRO bus. The original Model behavior only supported c++ templated
calls on the source and replica side.
This change adds support for nested classes, via an extension to the .rep
file format. Similar to how POD types work, if multiple classes are
described in a .rep file, a class can include other classes as children.
When the `parent` is acquired, all child classes will be acquired as
well, automatically.
The syntax is `CLASS <name>(<type>), where type needs to be a class
defined in the same rep file, and the name is the getter name used to
access the sub-QObject. See tests/auto/subclassreplica/class.rep for an
example of usage.
This change includes supporting the non-templated enableRemoting() call,
as well as using/constructing replica types from QML for both Class and
Model.
Future TODO - update docs
Change-Id: Ib1e75c1a6db44497f78026e7f89caab5da94375b
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Diffstat (limited to 'src/remoteobjects/qremoteobjectsource.cpp')
-rw-r--r-- | src/remoteobjects/qremoteobjectsource.cpp | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/src/remoteobjects/qremoteobjectsource.cpp b/src/remoteobjects/qremoteobjectsource.cpp index dcbc8ea..d28c59e 100644 --- a/src/remoteobjects/qremoteobjectsource.cpp +++ b/src/remoteobjects/qremoteobjectsource.cpp @@ -39,12 +39,14 @@ #include "qremoteobjectsource.h" #include "qremoteobjectsource_p.h" +#include "qremoteobjectnode.h" #include "qconnectionfactories_p.h" #include "qremoteobjectsourceio_p.h" #include <QMetaProperty> #include <QVarLengthArray> +#include <QAbstractItemModel> #include <algorithm> #include <iterator> @@ -241,7 +243,7 @@ int QRemoteObjectSource::qt_metacall(QMetaObject::Call call, int methodId, void return -1; } -DynamicApiMap::DynamicApiMap(const QMetaObject *metaObject, const QString &name, const QString &typeName) +DynamicApiMap::DynamicApiMap(QObject *object, const QMetaObject *metaObject, const QString &name, const QString &typeName) : m_name(name), m_typeName(typeName), m_metaObject(metaObject), @@ -255,6 +257,28 @@ DynamicApiMap::DynamicApiMap(const QMetaObject *metaObject, const QString &name, m_properties.reserve(propCount-propOffset); int i = 0; for (i = propOffset; i < propCount; ++i) { + const QMetaProperty property = metaObject->property(i); + if (QMetaType::typeFlags(property.userType()).testFlag(QMetaType::PointerToQObject)) { + auto propertyMeta = QMetaType::metaObjectForType(property.userType()); + QObject *child = property.read(object).value<QObject *>(); + if (propertyMeta->inherits(&QAbstractItemModel::staticMetaObject)) { + const QByteArray name = QByteArray::fromRawData(property.name(), + qstrlen(property.name())); + const QByteArray infoName = name.toUpper() + QByteArrayLiteral("_ROLES"); + const int infoIndex = metaObject->indexOfClassInfo(infoName.constData()); + QByteArray roleInfo; + if (infoIndex >= 0) { + auto ci = metaObject->classInfo(infoIndex); + roleInfo = QByteArray::fromRawData(ci.value(), qstrlen(ci.value())); + } + m_models << ModelInfo({qobject_cast<QAbstractItemModel *>(child), + QString::fromLatin1(property.name()), + roleInfo}); + } else { + m_subclasses << SubclassInfo({child, QString::fromLatin1(property.name())}); + } + continue; + } m_properties << i; const int notifyIndex = metaObject->property(i).notifySignalIndex(); if (notifyIndex != -1) { @@ -327,4 +351,43 @@ QList<QByteArray> DynamicApiMap::methodParameterNames(int index) const return m_cachedMetamethod.parameterNames(); } +void SourceApiMap::qobjectSetup(QRemoteObjectHostBase *node) const +{ + if (m_models.isEmpty() && m_subclasses.isEmpty()) + return; + + QVector<int> roles; + + qCDebug(QT_REMOTEOBJECT) << "In qobjectSetup, model count =" << m_models.count() << "subclass count =" << m_subclasses.count(); + for (int i = 0; i < m_models.count(); ++i) { + const auto model = m_models.at(i); + if (!model.ptr) + continue; // Pointer not initialized + roles.clear(); + const auto knownRoles = model.ptr->roleNames(); + for (auto role : model.roles.split('|')) { + const int roleIndex = knownRoles.key(role, -1); + if (roleIndex == -1) { + qCWarning(QT_REMOTEOBJECT) << "Invalid role" << role << "for model" << model.ptr->metaObject()->className(); + qCWarning(QT_REMOTEOBJECT) << " known roles:" << knownRoles; + } else + roles << roleIndex; + } + const auto reportedName = QString::fromLatin1("Model::%1").arg(model.name); + // TODO handle selection model + if (roles.isEmpty()) + node->enableRemoting(model.ptr, reportedName, knownRoles.keys().toVector(), nullptr); + else + node->enableRemoting(model.ptr, reportedName, roles, nullptr); + } + + for (int i = 0; i < m_subclasses.count(); ++i) { + const auto subclass = m_subclasses.at(i); + if (subclass.ptr) { + const auto reportedName = QString::fromLatin1("Class::%1").arg(subclass.name); + node->enableRemoting(subclass.ptr, reportedName); + } + } +} + QT_END_NAMESPACE |