summaryrefslogtreecommitdiffstats
path: root/src/remoteobjects/qremoteobjectsource.cpp
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2017-12-06 11:21:49 -0600
committerTony SarajΓ€rvi <tony.sarajarvi@qt.io>2017-12-13 08:33:46 +0000
commit833885e3f342ead957128413fd451cb1eb71a65b (patch)
tree3e92ad0cc9cc4c3ba78c214f299ee1b57081129f /src/remoteobjects/qremoteobjectsource.cpp
parent9ae28ac68af20b4d8b305fa78a478833cc833642 (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.cpp65
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