diff options
author | BogDan Vatra <bogdan@kdab.com> | 2018-08-21 17:32:13 +0300 |
---|---|---|
committer | Brett Stottlemyer <bstottle@ford.com> | 2018-09-06 00:32:25 +0000 |
commit | e43c9fe03e6ff6849f43117c384c083c4bf8ff1d (patch) | |
tree | 38ead2adba1f15b477b2563df21220dee9af898f | |
parent | 854217d60da9ab54795fb39896a053f301222848 (diff) |
Implement dynamic gadgetsv5.12.0-alpha1
Change-Id: Icff4455ad58bd28dd1db1d5502725101f1b5d7b6
Reviewed-by: Brett Stottlemyer <bstottle@ford.com>
-rw-r--r-- | src/remoteobjects/qconnectionfactories_p.h | 4 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectnode.cpp | 118 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectpacket.cpp | 74 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectpacket_p.h | 7 |
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 { |