summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBogDan Vatra <bogdan@kdab.com>2018-08-21 17:32:13 +0300
committerBrett Stottlemyer <bstottle@ford.com>2018-09-06 00:32:25 +0000
commite43c9fe03e6ff6849f43117c384c083c4bf8ff1d (patch)
tree38ead2adba1f15b477b2563df21220dee9af898f
parent854217d60da9ab54795fb39896a053f301222848 (diff)
Implement dynamic gadgetsv5.12.0-alpha1
Change-Id: Icff4455ad58bd28dd1db1d5502725101f1b5d7b6 Reviewed-by: Brett Stottlemyer <bstottle@ford.com>
-rw-r--r--src/remoteobjects/qconnectionfactories_p.h4
-rw-r--r--src/remoteobjects/qremoteobjectnode.cpp118
-rw-r--r--src/remoteobjects/qremoteobjectpacket.cpp74
-rw-r--r--src/remoteobjects/qremoteobjectpacket_p.h7
4 files changed, 199 insertions, 4 deletions
diff --git a/src/remoteobjects/qconnectionfactories_p.h b/src/remoteobjects/qconnectionfactories_p.h
index 84bc917..3d71895 100644
--- a/src/remoteobjects/qconnectionfactories_p.h
+++ b/src/remoteobjects/qconnectionfactories_p.h
@@ -62,8 +62,8 @@ QT_BEGIN_NAMESPACE
namespace QtRemoteObjects {
-static const int dataStreamVersion = QDataStream::Qt_5_6;
-static const QLatin1String protocolVersion("QtRO 1.1");
+static const int dataStreamVersion = QDataStream::Qt_5_12;
+static const QLatin1String protocolVersion("QtRO 1.2");
}
diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp
index 19b9d14..f28d764 100644
--- a/src/remoteobjects/qremoteobjectnode.cpp
+++ b/src/remoteobjects/qremoteobjectnode.cpp
@@ -51,12 +51,72 @@
#include "qremoteobjectabstractitemmodelreplica_p.h"
#include "qremoteobjectabstractitemmodeladapter_p.h"
#include <QAbstractItemModel>
+#include <memory>
QT_BEGIN_NAMESPACE
using namespace QtRemoteObjects;
using namespace QRemoteObjectStringLiterals;
+using GadgetType = QVector<QVariant>;
+using RegisteredType = QPair<GadgetType, std::shared_ptr<QMetaObject>>;
+static QMutex s_managedTypesMutex;
+static QHash<int, RegisteredType> s_managedTypes;
+
+static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::ReadProperty) {
+ GadgetType *_t = reinterpret_cast<GadgetType *>(_o);
+ if (_id < _t->size()) {
+ const auto &prop = _t->at(_id);
+ QMetaType::destruct(int(prop.userType()), _a[0]);
+ QMetaType::construct(int(prop.userType()), _a[0], prop.constData());
+ }
+ } else if (_c == QMetaObject::WriteProperty) {
+ GadgetType *_t = reinterpret_cast<GadgetType *>(_o);
+ if (_id < _t->size()) {
+ auto & prop = (*_t)[_id];
+ prop = QVariant(prop.userType(), _a[0]);
+ }
+ }
+}
+
+static void GadgetTypedDestructor(int, void *ptr)
+{
+ reinterpret_cast<GadgetType*>(ptr)->~GadgetType();
+}
+
+static void *GadgetTypedConstructor(int type, void *where, const void *copy)
+{
+ GadgetType *ret = where ? new(where) GadgetType : new GadgetType;
+ if (copy) {
+ *ret = *reinterpret_cast<const GadgetType*>(copy);
+ } else {
+ QMutexLocker lock(&s_managedTypesMutex);
+ auto it = s_managedTypes.find(type);
+ if (it == s_managedTypes.end()) {
+ delete ret;
+ return nullptr;
+ }
+ *ret = it->first;
+ }
+ return ret;
+}
+
+static void GadgetSaveOperator(QDataStream & out, const void *data)
+{
+ const GadgetType *gadgetProperties = reinterpret_cast<const GadgetType *>(data);
+ for (const auto &prop : *gadgetProperties)
+ out << prop;
+}
+
+static void GadgetLoadOperator(QDataStream &in, void *data)
+{
+ GadgetType *gadgetProperties = reinterpret_cast<GadgetType *>(data);
+ for (auto &prop : *gadgetProperties)
+ in >> prop;
+}
+
static QString name(const QMetaObject * const mobj)
{
const int ind = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
@@ -568,6 +628,47 @@ const QMetaObject *QRemoteObjectMetaObjectManager::metaObjectForType(const QStri
return dynamicTypes.value(type);
}
+static int registerGadget(QRemoteObjectPackets::GadgetsData &gadgets, QByteArray typeName)
+{
+ const auto &properties = gadgets.take(typeName);
+ int typeId = QMetaType::type(typeName);
+ if (typeId != QMetaType::UnknownType)
+ return typeId;
+
+ QMetaObjectBuilder gadgetBuilder;
+ gadgetBuilder.setClassName(typeName);
+ gadgetBuilder.setFlags(QMetaObjectBuilder::DynamicMetaObject | QMetaObjectBuilder::PropertyAccessInStaticMetaCall);
+ GadgetType gadgetType;
+ for (const auto &prop : properties) {
+ int propertyType = QMetaType::type(prop.type);
+ if (!propertyType && gadgets.contains(prop.type))
+ propertyType = registerGadget(gadgets, prop.type);
+ gadgetType.push_back(QVariant(QVariant::Type(propertyType)));
+ auto dynamicProperty = gadgetBuilder.addProperty(prop.name, prop.type);
+ dynamicProperty.setWritable(true);
+ dynamicProperty.setReadable(true);
+ }
+ auto meta = gadgetBuilder.toMetaObject();
+ meta->d.static_metacall = &GadgetsStaticMetacallFunction;
+ meta->d.superdata = nullptr;
+ const auto flags = QMetaType::WasDeclaredAsMetaType | QMetaType::IsGadget | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ int gadgetTypeId = QMetaType::registerType(typeName.constData(),
+ &GadgetTypedDestructor,
+ &GadgetTypedConstructor,
+ sizeof(GadgetType),
+ flags, meta);
+ QMetaType::registerStreamOperators(gadgetTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
+ QMutexLocker lock(&s_managedTypesMutex);
+ s_managedTypes[gadgetTypeId] = qMakePair(gadgetType, std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr); }});
+ return gadgetTypeId;
+}
+
+static void registerAllGadgets(QRemoteObjectPackets::GadgetsData &gadgets)
+{
+ while (!gadgets.isEmpty())
+ registerGadget(gadgets, gadgets.constBegin().key());
+}
+
QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(QDataStream &in)
{
QMetaObjectBuilder builder;
@@ -577,6 +678,7 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(QDataStream &in)
QString type;
quint32 numEnums = 0;
+ quint32 numGadgets = 0;
quint32 numSignals = 0;
quint32 numMethods = 0;
quint32 numProperties = 0;
@@ -607,6 +709,22 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(QDataStream &in)
enumBuilder.addKey(key, value);
}
}
+ in >> numGadgets;
+ QRemoteObjectPackets::GadgetsData gadgets;
+ for (quint32 i = 0; i < numGadgets; ++i) {
+ QByteArray type;
+ in >> type;
+ quint32 numProperties;
+ in >> numProperties;
+ auto &properties = gadgets[type];
+ for (quint32 p = 0; p < numProperties; ++p) {
+ QRemoteObjectPackets::GadgetProperty prop;
+ in >> prop.name;
+ in >> prop.type;
+ properties.push_back(prop);
+ }
+ }
+ registerAllGadgets(gadgets);
int curIndex = 0;
diff --git a/src/remoteobjects/qremoteobjectpacket.cpp b/src/remoteobjects/qremoteobjectpacket.cpp
index 066b977..ecf593c 100644
--- a/src/remoteobjects/qremoteobjectpacket.cpp
+++ b/src/remoteobjects/qremoteobjectpacket.cpp
@@ -165,6 +165,31 @@ void serializeInitDynamicPacket(DataStreamPacket &ds, const QRemoteObjectRootSou
ds.finishPacket();
}
+static void mergeData(GadgetsData &a, const GadgetsData &b)
+{
+ for (auto it = b.constBegin(); it != b.constEnd(); ++it)
+ a[it.key()] = it.value();
+}
+
+static GadgetsData gadgetData(const QMetaObject *mo)
+{
+ if (!mo)
+ return {};
+ GadgetsData res;
+ auto & properties = res[mo->className()];
+ const int numProperties = mo->propertyCount();
+ for (int i = 0; i < numProperties; ++i) {
+ const auto property = mo->property(i);
+ GadgetProperty data;
+ data.name = property.name();
+ data.type = property.typeName();
+ if (QMetaType::typeFlags(property.userType()).testFlag(QMetaType::IsGadget))
+ mergeData(res, gadgetData(QMetaType::metaObjectForType(property.userType())));
+ properties.push_back(data);
+ }
+ return res;
+}
+
void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
{
const SourceApiMap *api = source->m_api;
@@ -190,6 +215,53 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
}
const int numSignals = api->signalCount();
+ const int numMethods = api->methodCount();
+ const int numProperties = api->propertyCount();
+
+ GadgetsData gadgets;
+ QSet<int> processedTypes;
+ for (int si = 0; si < numSignals; ++si) {
+ const int params = api->signalParameterCount(si);
+ for (int pi = 0; pi < params; ++pi) {
+ const int type = api->signalParameterType(si, pi);
+ if (processedTypes.contains(type) || !QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget))
+ continue;
+ mergeData(gadgets, gadgetData(QMetaType::metaObjectForType(type)));
+ processedTypes.insert(type);
+ }
+ }
+
+ for (int mi = 0; mi < numMethods; ++mi) {
+ const int params = api->methodParameterCount(mi);
+ for (int pi = 0; pi < params; ++pi) {
+ const int type = api->methodParameterType(mi, pi);
+ if (processedTypes.contains(type) || !QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget))
+ continue;
+ mergeData(gadgets, gadgetData(QMetaType::metaObjectForType(type)));
+ processedTypes.insert(type);
+ }
+ }
+ for (int pi = 0; pi < numProperties; ++pi) {
+ const int index = api->sourcePropertyIndex(pi);
+ Q_ASSERT(index >= 0);
+ const auto target = api->isAdapterProperty(pi) ? source->m_adapter : source->m_object;
+ const auto metaProperty = target->metaObject()->property(index);
+ const int type = metaProperty.userType();
+ if (processedTypes.contains(type) || !QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget))
+ continue;
+ mergeData(gadgets, gadgetData(QMetaType::metaObjectForType(type)));
+ processedTypes.insert(type);
+ }
+ ds << quint32(gadgets.size());
+ for (auto it = gadgets.constBegin(); it != gadgets.constEnd(); ++it) {
+ ds << it.key();
+ ds << quint32(it.value().size());
+ for (const auto &prop : qAsConst(it.value())) {
+ ds << prop.name;
+ ds << prop.type;
+ }
+ }
+
ds << quint32(numSignals); //Number of signals
for (int i = 0; i < numSignals; ++i) {
const int index = api->sourceSignalIndex(i);
@@ -198,7 +270,6 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
ds << api->signalParameterNames(i);
}
- const int numMethods = api->methodCount();
ds << quint32(numMethods); //Number of methods
for (int i = 0; i < numMethods; ++i) {
const int index = api->sourceMethodIndex(i);
@@ -208,7 +279,6 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
ds << api->methodParameterNames(i);
}
- const int numProperties = api->propertyCount();
ds << quint32(numProperties); //Number of properties
for (int i = 0; i < numProperties; ++i) {
const int index = api->sourcePropertyIndex(i);
diff --git a/src/remoteobjects/qremoteobjectpacket_p.h b/src/remoteobjects/qremoteobjectpacket_p.h
index 4aae866..4a73cb8 100644
--- a/src/remoteobjects/qremoteobjectpacket_p.h
+++ b/src/remoteobjects/qremoteobjectpacket_p.h
@@ -130,6 +130,13 @@ QDataStream& operator>>(QDataStream &stream, QRO_ &info);
void serializeObjectListPacket(DataStreamPacket&, const ObjectInfoList&);
void deserializeObjectListPacket(QDataStream&, ObjectInfoList&);
+struct GadgetProperty {
+ QByteArray name;
+ QByteArray type;
+};
+
+using GadgetsData = QHash<QByteArray, QVector<GadgetProperty>>;
+
//Helper class for creating a QByteArray from a QRemoteObjectPacket
class DataStreamPacket : public QDataStream
{