summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2019-05-18 18:37:11 -0400
committerBrett Stottlemyer <bstottle@ford.com>2019-05-20 19:37:44 -0400
commit2d5105518ee21ea9ccb32effab76f4c5d1366cae (patch)
tree0bfa5a4913526f140626b560d6ba9220f3624268
parentfa84f22bfd5500550f26f544f6905ac89e60716f (diff)
Support Q_GADGETs with enums
The previous logic for sending/receiving the Q_GADGET definition used a custom GadgetsData type on both sides (a QByteArray for name and a QList of name/type pairs for each member). This isn't really needed on the send side, we just need the QMetaObject for the class. This simplifies the logic on the send side, as we no longer need to copy data around and merge duplicate types, and it allows extension to getting enums. On the receive side, we do need to copy the data. In particular, there can be nested types, where one POD includes another or an enum from another type. It is easier to extend the class if it doesn't need to support the send operation as well. On the send side, we now have serializeGadgets() which takes the pointers for gadget metaobjects as well as the list of needed QMetaEnum types. Using these, it constructs the list of necessary types to serialize and marshalls those. On the receive side, there is registerGadgets which uses the extended GadgetData struct (now including the data needed to create dynamic QMetaEnums) to create metaObjects and register the required types. Change-Id: I80ceff39131c7a2cdcfe592f338ea98f72e76874 Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r--src/remoteobjects/qremoteobjectnode.cpp180
-rw-r--r--src/remoteobjects/qremoteobjectpacket.cpp245
-rw-r--r--src/remoteobjects/qremoteobjectpacket_p.h7
-rw-r--r--src/remoteobjects/qremoteobjectsource.cpp2
-rw-r--r--src/remoteobjects/qremoteobjectsource_p.h3
-rw-r--r--tests/auto/proxy_multiprocess/client/client.pro3
-rw-r--r--tests/auto/proxy_multiprocess/client/main.cpp3
-rw-r--r--tests/auto/proxy_multiprocess/namespace.h9
-rw-r--r--tests/auto/proxy_multiprocess/proxy_multiprocess.pro3
-rw-r--r--tests/auto/proxy_multiprocess/server/main.cpp2
-rw-r--r--tests/auto/proxy_multiprocess/server/server.pro1
-rw-r--r--tests/auto/proxy_multiprocess/subclass.rep3
12 files changed, 288 insertions, 173 deletions
diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp
index 2cce1a7..3353de1 100644
--- a/src/remoteobjects/qremoteobjectnode.cpp
+++ b/src/remoteobjects/qremoteobjectnode.cpp
@@ -695,9 +695,46 @@ static void trackConnection(int typeId, IoDeviceBase *connection)
QObject::connect(connection, &IoDeviceBase::destroyed, unregisterIfNotUsed);
}
-static int registerGadget(IoDeviceBase *connection, QRemoteObjectPackets::GadgetsData &gadgets, QByteArray typeName)
+struct EnumPair {
+ QByteArray name;
+ int value;
+};
+
+struct EnumData {
+ QByteArray name;
+ bool isFlag, isScoped;
+ quint32 keyCount;
+ QVector<EnumPair> values;
+};
+
+struct GadgetProperty {
+ QByteArray name;
+ QByteArray type;
+};
+
+struct GadgetData {
+ QVector<GadgetProperty> properties;
+ QVector<EnumData> enums;
+};
+
+using Gadgets = QHash<QByteArray, GadgetData>;
+
+static void registerEnum(const QByteArray &name, const QMetaObject *meta, int size=4)
+{
+ // When we add support for enum classes, we will need to set this to something like
+ // QByteArray(enumClass).append("::").append(enumMeta.name()) when enumMeta.isScoped() is true.
+ // That is a new feature, though.
+ if (QMetaType::isRegistered(QMetaType::type(name)))
+ return;
+ static const auto flags = QMetaType::IsEnumeration | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ int id = QMetaType::registerType(name.constData(), nullptr, nullptr, &EnumDestructor<qint32>,
+ &EnumConstructor<qint32>, size, flags, meta);
+ qCDebug(QT_REMOTEOBJECT) << "Registering new enum with id" << id << name;
+}
+
+static int registerGadgets(IoDeviceBase *connection, Gadgets &gadgets, QByteArray typeName)
{
- const auto &properties = gadgets.take(typeName);
+ const auto &gadget = gadgets.take(typeName);
int typeId = QMetaType::type(typeName);
if (typeId != QMetaType::UnknownType) {
trackConnection(typeId, connection);
@@ -708,69 +745,113 @@ static int registerGadget(IoDeviceBase *connection, QRemoteObjectPackets::Gadget
gadgetBuilder.setClassName(typeName);
gadgetBuilder.setFlags(QMetaObjectBuilder::DynamicMetaObject | QMetaObjectBuilder::PropertyAccessInStaticMetaCall);
GadgetType gadgetType;
- for (const auto &prop : properties) {
+ for (const auto &prop : gadget.properties) {
int propertyType = QMetaType::type(prop.type);
if (!propertyType && gadgets.contains(prop.type))
- propertyType = registerGadget(connection, gadgets, prop.type);
+ propertyType = registerGadgets(connection, gadgets, prop.type);
gadgetType.push_back(QVariant(QVariant::Type(propertyType)));
auto dynamicProperty = gadgetBuilder.addProperty(prop.name, prop.type);
dynamicProperty.setWritable(true);
dynamicProperty.setReadable(true);
}
+ for (const auto &enumData: gadget.enums) {
+ auto enumBuilder = gadgetBuilder.addEnumerator(enumData.name);
+ enumBuilder.setIsFlag(enumData.isFlag);
+ enumBuilder.setIsScoped(enumData.isScoped);
+
+ for (quint32 k = 0; k < enumData.keyCount; ++k) {
+ const auto pair = enumData.values.at(k);
+ enumBuilder.addKey(pair.name, pair.value);
+ }
+ }
auto meta = gadgetBuilder.toMetaObject();
- meta->d.static_metacall = &GadgetsStaticMetacallFunction;
- meta->d.superdata = nullptr;
- const auto flags = QMetaType::IsGadget | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
- int gadgetTypeId = QMetaType::registerType(typeName.constData(),
+ const auto enumCount = meta->enumeratorCount();
+ for (int i = 0; i < enumCount; i++) {
+ const QByteArray registeredName = QByteArray(typeName).append("::").append(meta->enumerator(i).name());
+ registerEnum(registeredName, meta);
+ }
+ QMetaType::TypeFlags flags = QMetaType::IsGadget;
+ int gadgetTypeId;
+ if (meta->propertyCount()) {
+ meta->d.static_metacall = &GadgetsStaticMetacallFunction;
+ meta->d.superdata = nullptr;
+ flags |= QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ gadgetTypeId = QMetaType::registerType(typeName.constData(),
&GadgetTypedDestructor,
&GadgetTypedConstructor,
sizeof(GadgetType),
flags, meta);
- QMetaType::registerStreamOperators(gadgetTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
+ QMetaType::registerStreamOperators(gadgetTypeId, &GadgetSaveOperator, &GadgetLoadOperator);
+ } else {
+ gadgetTypeId = QMetaType::registerType(typeName.constData(),
+ nullptr,
+ nullptr,
+ sizeof(GadgetType),
+ flags, meta);
+ }
trackConnection(gadgetTypeId, connection);
QMutexLocker lock(&s_managedTypesMutex);
s_managedTypes[gadgetTypeId] = qMakePair(gadgetType, std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr); }});
return gadgetTypeId;
}
-static void registerAllGadgets(IoDeviceBase *connection, QRemoteObjectPackets::GadgetsData &gadgets)
+static void registerAllGadgets(IoDeviceBase *connection, Gadgets &gadgets)
{
while (!gadgets.isEmpty())
- registerGadget(connection, gadgets, gadgets.constBegin().key());
+ registerGadgets(connection, gadgets, gadgets.constBegin().key());
+}
+
+static void deserializeEnum(QDataStream &ds, EnumData &enumData)
+{
+ ds >> enumData.name;
+ ds >> enumData.isFlag;
+ ds >> enumData.isScoped;
+ ds >> enumData.keyCount;
+ for (quint32 i = 0; i < enumData.keyCount; i++) {
+ EnumPair pair;
+ ds >> pair.name;
+ ds >> pair.value;
+ enumData.values.push_back(pair);
+ }
}
-static void parseGadgets(IoDeviceBase *connection, QDataStream &in, quint32 numGadgets = 1)
+static void parseGadgets(IoDeviceBase *connection, QDataStream &in)
{
- QRemoteObjectPackets::GadgetsData gadgets;
+ quint32 qtEnums, numGadgets;
+ in >> qtEnums; // Qt enums - just need registration
+ for (quint32 i = 0; i < qtEnums; ++i) {
+ QByteArray enumName;
+ in >> enumName;
+ QMetaType t(QMetaType::type(enumName.constData()));
+ registerEnum(enumName, t.metaObject()); // All Qt enums have default type int
+ }
+ in >> numGadgets;
+ if (numGadgets == 0)
+ return;
+ Gadgets gadgets;
for (quint32 i = 0; i < numGadgets; ++i) {
QByteArray type;
in >> type;
- quint32 numProperties;
+ quint32 numProperties, numEnums;
in >> numProperties;
- auto &properties = gadgets[type];
+ auto &properties = gadgets[type].properties;
for (quint32 p = 0; p < numProperties; ++p) {
- QRemoteObjectPackets::GadgetProperty prop;
+ GadgetProperty prop;
in >> prop.name;
in >> prop.type;
properties.push_back(prop);
}
+ in >> numEnums;
+ auto &enums = gadgets[type].enums;
+ for (quint32 e = 0; e < numEnums; ++e) {
+ EnumData enumData;
+ deserializeEnum(in, enumData);
+ enums.push_back(enumData);
+ }
}
registerAllGadgets(connection, gadgets);
}
-static void registerEnum(const QByteArray &name, int size=4)
-{
- // When we add support for enum classes, we will need to set this to something like
- // QByteArray(enumClass).append("::").append(enumMeta.name()) when enumMeta.isScoped() is true.
- // That is a new feature, though.
- if (QMetaType::isRegistered(QMetaType::type(name)))
- return;
- static const auto flags = QMetaType::IsEnumeration | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
- int id = QMetaType::registerType(name.constData(), nullptr, nullptr, &EnumDestructor<qint32>,
- &EnumConstructor<qint32>, size, flags, nullptr);
- qCDebug(QT_REMOTEOBJECT) << "Registering new enum with id" << id << name;
-}
-
QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connection, QDataStream &in)
{
QMetaObjectBuilder builder;
@@ -780,7 +861,6 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connec
QString typeString;
QByteArray type;
quint32 numEnums = 0;
- quint32 numGadgets = 0;
quint32 numSignals = 0;
quint32 numMethods = 0;
quint32 numProperties = 0;
@@ -792,36 +872,18 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connec
in >> numEnums;
for (quint32 i = 0; i < numEnums; ++i) {
- QByteArray name;
- in >> name;
- auto enumBuilder = builder.addEnumerator(name);
- bool isFlag;
- in >> isFlag;
- enumBuilder.setIsFlag(isFlag);
-
- QByteArray scopeName;
- in >> scopeName; // scope
- // TODO uncomment this line after https://bugreports.qt.io/browse/QTBUG-64081 is implemented
- //enumBuilder.setScope(scopeName);
-
- int keyCount;
- in >> keyCount;
- for (int k = 0; k < keyCount; ++k) {
- QByteArray key;
- int value;
- in >> key;
- in >> value;
- enumBuilder.addKey(key, value);
+ EnumData enumData;
+ deserializeEnum(in, enumData);
+ auto enumBuilder = builder.addEnumerator(enumData.name);
+ enumBuilder.setIsFlag(enumData.isFlag);
+ enumBuilder.setIsScoped(enumData.isScoped);
+
+ for (quint32 k = 0; k < enumData.keyCount; ++k) {
+ const auto pair = enumData.values.at(k);
+ enumBuilder.addKey(pair.name, pair.value);
}
}
- in >> numEnums; // Qt enums
- for (quint32 i = 0; i < numEnums; ++i) {
- QByteArray enumName;
- in >> enumName;
- registerEnum(enumName); // All Qt enums have default type int
- }
- in >> numGadgets;
- parseGadgets(connection, in, numGadgets);
+ parseGadgets(connection, in);
int curIndex = 0;
@@ -876,7 +938,7 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connec
for (int i = numEnums; i > 0; i--) {
auto const enumMeta = meta->enumerator(totalEnumCount - i);
const QByteArray registeredName = QByteArray(type).append("::").append(enumMeta.name());
- registerEnum(registeredName);
+ registerEnum(registeredName, meta);
}
dynamicTypes.insert(typeString, meta);
return meta;
diff --git a/src/remoteobjects/qremoteobjectpacket.cpp b/src/remoteobjects/qremoteobjectpacket.cpp
index c2e9060..631c362 100644
--- a/src/remoteobjects/qremoteobjectpacket.cpp
+++ b/src/remoteobjects/qremoteobjectpacket.cpp
@@ -224,32 +224,7 @@ 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;
-}
-
-static ObjectType objectType(const QString &typeName)
+static ObjectType getObjectType(const QString &typeName)
{
if (typeName == QLatin1String("QAbstractItemModelAdapter"))
return ObjectType::MODEL;
@@ -279,7 +254,35 @@ static QMetaEnum metaEnumFromType(int type)
return QMetaEnum();
}
-void recurseForGadgets(GadgetsData &gadgets, QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source)
+static bool checkEnum(int type, QSet<QMetaEnum> &enums)
+{
+ if (QMetaType::typeFlags(type).testFlag(QMetaType::IsEnumeration)) {
+ QMetaEnum meta = metaEnumFromType(type);
+ enums.insert(meta);
+ return true;
+ }
+ return false;
+}
+
+static void recurseMetaobject(const QMetaObject *mo, QSet<const QMetaObject *> &gadgets, QSet<QMetaEnum> &enums)
+{
+ if (!mo || gadgets.contains(mo))
+ return;
+ gadgets.insert(mo);
+ const int numProperties = mo->propertyCount();
+ for (int i = 0; i < numProperties; ++i) {
+ const auto property = mo->property(i);
+ if (checkEnum(property.userType(), enums))
+ continue;
+ if (QMetaType::typeFlags(property.userType()).testFlag(QMetaType::IsGadget))
+ recurseMetaobject(QMetaType::metaObjectForType(property.userType()), gadgets, enums);
+ }
+}
+
+// A Source may only use a subset of the metaobjects properties/signals/slots, so we only search
+// the ones in the API. For nested pointer types, we will have another api to limit the search.
+// For nested PODs/enums, we search the entire qobject (using the recurseMetaobject call()).
+void recurseForGadgets(QSet<const QMetaObject *> &gadgets, QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source)
{
const SourceApiMap *api = source->m_api;
@@ -291,19 +294,14 @@ void recurseForGadgets(GadgetsData &gadgets, QSet<QMetaEnum> &enums, const QRemo
const int params = api->signalParameterCount(si);
for (int pi = 0; pi < params; ++pi) {
const int type = api->signalParameterType(si, pi);
- if (QMetaType::typeFlags(type).testFlag(QMetaType::IsEnumeration)) {
- QMetaEnum meta = metaEnumFromType(type);
- if (source->m_object->inherits(meta.enclosingMetaObject()->className()))
- continue; // Enum is part of this object, it will be found below
- enums.insert(meta);
+ if (checkEnum(type, enums))
continue;
- }
if (!QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget))
continue;
const auto mo = QMetaType::metaObjectForType(type);
if (source->d->sentTypes.contains(QLatin1String(mo->className())))
continue;
- mergeData(gadgets, gadgetData(mo));
+ recurseMetaobject(mo, gadgets, enums);
source->d->sentTypes.insert(QLatin1String(mo->className()));
}
}
@@ -312,19 +310,14 @@ void recurseForGadgets(GadgetsData &gadgets, QSet<QMetaEnum> &enums, const QRemo
const int params = api->methodParameterCount(mi);
for (int pi = 0; pi < params; ++pi) {
const int type = api->methodParameterType(mi, pi);
- if (QMetaType::typeFlags(type).testFlag(QMetaType::IsEnumeration)) {
- QMetaEnum meta = metaEnumFromType(type);
- if (source->m_object->inherits(meta.enclosingMetaObject()->className()))
- continue; // Enum is part of this object, it will be found below
- enums.insert(meta);
+ if (checkEnum(type, enums))
continue;
- }
if (!QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget))
continue;
const auto mo = QMetaType::metaObjectForType(type);
if (source->d->sentTypes.contains(QLatin1String(mo->className())))
continue;
- mergeData(gadgets, gadgetData(mo));
+ recurseMetaobject(mo, gadgets, enums);
source->d->sentTypes.insert(QLatin1String(mo->className()));
}
}
@@ -333,32 +326,116 @@ void recurseForGadgets(GadgetsData &gadgets, QSet<QMetaEnum> &enums, const QRemo
Q_ASSERT(index >= 0);
const auto target = api->isAdapterProperty(pi) ? source->m_adapter : source->m_object;
const auto metaProperty = target->metaObject()->property(index);
- if (QMetaType::typeFlags(metaProperty.userType()).testFlag(QMetaType::IsEnumeration)) {
- QMetaEnum meta = metaProperty.enumerator();
- if (source->m_object->inherits(meta.enclosingMetaObject()->className()))
- continue; // Enum is part of this object, it will be found below
- enums.insert(meta);
+ const int type = metaProperty.userType();
+ if (checkEnum(type, enums))
continue;
- }
- if (QMetaType::typeFlags(metaProperty.userType()).testFlag(QMetaType::PointerToQObject)) {
- auto const type = objectType(QString::fromLatin1(metaProperty.typeName()));
- if (type == ObjectType::CLASS) {
+ if (QMetaType::typeFlags(type).testFlag(QMetaType::PointerToQObject)) {
+ auto const objectType = getObjectType(QString::fromLatin1(metaProperty.typeName()));
+ if (objectType == ObjectType::CLASS) {
auto const childSource = source->m_children.value(pi);
if (childSource->m_object)
recurseForGadgets(gadgets, enums, childSource);
}
}
- const int type = metaProperty.userType();
if (!QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget))
continue;
const auto mo = QMetaType::metaObjectForType(type);
if (source->d->sentTypes.contains(QLatin1String(mo->className())))
continue;
- mergeData(gadgets, gadgetData(mo));
+ recurseMetaobject(mo, gadgets, enums);
source->d->sentTypes.insert(QLatin1String(mo->className()));
}
}
+static bool checkForEnumsInSource(const QMetaObject *meta, const QRemoteObjectSourceBase *source)
+{
+ if (source->m_object->inherits(meta->className()))
+ return true;
+ for (const auto child : source->m_children) {
+ if (child->m_object && checkForEnumsInSource(meta, child))
+ return true;
+ }
+ return false;
+}
+
+static void serializeEnum(QDataStream &ds, const QMetaEnum &enumerator)
+{
+ ds << QByteArray::fromRawData(enumerator.name(), qstrlen(enumerator.name()));
+ ds << enumerator.isFlag();
+ ds << enumerator.isScoped();
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Enum (name = %s, isFlag = %s, isScoped = %s):", enumerator.name(), enumerator.isFlag() ? "true" : "false", enumerator.isScoped() ? "true" : "false");
+#endif
+ const int keyCount = enumerator.keyCount();
+ ds << keyCount;
+ for (int k = 0; k < keyCount; ++k) {
+ ds << QByteArray::fromRawData(enumerator.key(k), qstrlen(enumerator.key(k)));
+ ds << enumerator.value(k);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Key %d (name = %s, value = %d):", k, enumerator.key(k), enumerator.value(k));
+#endif
+ }
+}
+
+static void serializeGadgets(QDataStream &ds, const QSet<const QMetaObject *> &gadgets, const QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source=nullptr)
+{
+ // Determine how to handle the enums found
+ QSet<QMetaEnum> qtEnums;
+ QSet<const QMetaObject *> dynamicEnumMetaObjects;
+ for (const auto metaEnum : enums) {
+ auto const metaObject = metaEnum.enclosingMetaObject();
+ if (gadgets.contains(metaObject)) // Part of a gadget will we serialize
+ continue;
+ // This checks if the enum is defined in our object heirarchy, in which case it will
+ // already have been serialized.
+ if (source && checkForEnumsInSource(metaObject, source->d->root))
+ continue;
+ // qtEnums are enumerations already known by Qt, so we only need register them.
+ // We don't need to send all of the key/value data.
+ if (metaObject == qt_getQtMetaObject()) // Are the other Qt metaclasses for enums?
+ qtEnums.insert(metaEnum);
+ else
+ dynamicEnumMetaObjects.insert(metaEnum.enclosingMetaObject());
+ }
+ ds << quint32(qtEnums.size());
+ for (const auto metaEnum : qtEnums) {
+ QByteArray enumName(metaEnum.scope());
+ enumName.append("::", 2).append(metaEnum.name());
+ ds << enumName;
+ }
+ const auto allMetaObjects = gadgets + dynamicEnumMetaObjects;
+ ds << quint32(allMetaObjects.size());
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Found" << gadgets.size() << "gadget/pod and" << (allMetaObjects.size() - gadgets.size()) << "enum types";
+ int i = 0;
+#endif
+ // There isn't an easy way to update a metaobject incrementally, so we
+ // send all of the metaobject's enums, but no properties, when an external
+ // enum is requested.
+ for (auto const meta : allMetaObjects) {
+ ds << QByteArray::fromRawData(meta->className(), qstrlen(meta->className()));
+ int propertyCount = gadgets.contains(meta) ? meta->propertyCount() : 0;
+ ds << quint32(propertyCount);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Gadget %d (name = %s, # properties = %d, # enums = %d):", i++, meta->className(), propertyCount, meta->enumeratorCount());
+#endif
+ for (int j = 0; j < propertyCount; j++) {
+ auto prop = meta->property(j);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Data member %d (name = %s, type = %s):", j, prop.name(), prop.typeName());
+#endif
+ ds << QByteArray::fromRawData(prop.name(), qstrlen(prop.name()));
+ ds << QByteArray::fromRawData(prop.typeName(), qstrlen(prop.typeName()));
+ }
+ int enumCount = meta->enumeratorCount();
+ ds << enumCount;
+ for (int j = 0; j < enumCount; j++) {
+ auto const enumMeta = meta->enumerator(j);
+ serializeEnum(ds, enumMeta);
+ }
+ }
+}
+
void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
{
const SourceApiMap *api = source->m_api;
@@ -387,57 +464,16 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
for (int i = 0; i < numEnums; ++i) {
auto enumerator = metaObject->enumerator(api->sourceEnumIndex(i));
Q_ASSERT(enumerator.isValid());
- ds << enumerator.name();
- ds << enumerator.isFlag();
- ds << enumerator.scope();
-#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug(" Enum %d (name = %s, isFlag = %s, scope = %s):", i, enumerator.name(), enumerator.isFlag() ? "true" : "false", enumerator.scope());
-#endif
- const int keyCount = enumerator.keyCount();
- ds << keyCount;
- for (int k = 0; k < keyCount; ++k) {
- ds << enumerator.key(k);
- ds << enumerator.value(k);
-#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug(" Key %d (name = %s, value = %d):", k, enumerator.key(k), enumerator.value(k));
-#endif
- }
+ serializeEnum(ds, enumerator);
}
if (source->d->isDynamic) {
- GadgetsData gadgets;
+ QSet<const QMetaObject *> gadgets;
QSet<QMetaEnum> enums;
recurseForGadgets(gadgets, enums, source);
- ds << quint32(enums.size());
- for (const auto metaEnum : enums) {
- bool qtEnum = metaEnum.enclosingMetaObject() == qt_getQtMetaObject(); // Are the other Qt metaclasses for enums?
- if (qtEnum) {
- QByteArray enumName(metaEnum.scope());
- enumName.append("::", 2).append(metaEnum.name());
- ds << enumName;
- }
- }
- ds << quint32(gadgets.size());
-#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug() << " Found" << gadgets.size() << "gadget/pod types";
- int i = 0, j = 0;
-#endif
- for (auto it = gadgets.constBegin(); it != gadgets.constEnd(); ++it) {
- ds << it.key();
- ds << quint32(it.value().size());
-#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug(" Gadget %d (name = %s):", i++, it.key().constData());
-#endif
- for (const auto &prop : qAsConst(it.value())) {
-#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug(" Data member %d (name = %s, type = %s):", j++, prop.name.constData(), prop.type.constData());
-#endif
- ds << prop.name;
- ds << prop.type;
- }
- }
+ serializeGadgets(ds, gadgets, enums, source);
} else
- ds << quint32(0);
+ ds << quint32(0) << quint32(0); // qtEnums, numGadgets
const int numSignals = api->signalCount();
ds << quint32(numSignals); //Number of signals
@@ -483,10 +519,10 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
qDebug() << " Property" << i << "name =" << metaProperty.name();
#endif
if (QMetaType::typeFlags(metaProperty.userType()).testFlag(QMetaType::PointerToQObject)) {
- auto type = objectType(QLatin1String(metaProperty.typeName()));
- ds << (type == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
+ auto objectType = getObjectType(QLatin1String(metaProperty.typeName()));
+ ds << (objectType == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug() << " Type:" << (type == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
+ qDebug() << " Type:" << (objectType == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
#endif
} else {
ds << metaProperty.typeName();
@@ -618,7 +654,7 @@ void serializePongPacket(DataStreamPacket &ds, const QString &name)
QRO_::QRO_(QRemoteObjectSourceBase *source)
: name(source->name())
, typeName(source->m_api->typeName())
- , type(source->m_adapter ? ObjectType::MODEL : objectType(typeName))
+ , type(source->m_adapter ? ObjectType::MODEL : getObjectType(typeName))
, isNull(source->m_object == nullptr)
, classDefinition()
, parameters()
@@ -631,7 +667,8 @@ QRO_::QRO_(const QVariant &value)
auto meta = QMetaType::metaObjectForType(value.userType());
QDataStream out(&classDefinition, QIODevice::WriteOnly);
const int numProperties = meta->propertyCount();
- const auto typeName = QByteArray(QMetaType::typeName(value.userType()));
+ const auto typeName = QByteArray::fromRawData(QMetaType::typeName(value.userType()), qstrlen(QMetaType::typeName(value.userType())));
+ out << quint32(0) << quint32(1);
out << typeName;
out << numProperties;
#ifdef QTRO_VERBOSE_PROTOCOL
@@ -642,8 +679,8 @@ QRO_::QRO_(const QVariant &value)
#ifdef QTRO_VERBOSE_PROTOCOL
qDebug(" Data member %d (name = %s, type = %s):", i, property.name(), property.typeName());
#endif
- out << property.name();
- out << property.typeName();
+ out << QByteArray::fromRawData(property.name(), qstrlen(property.name()));
+ out << QByteArray::fromRawData(property.typeName(), qstrlen(property.typeName()));
}
QDataStream ds(&parameters, QIODevice::WriteOnly);
ds << value;
diff --git a/src/remoteobjects/qremoteobjectpacket_p.h b/src/remoteobjects/qremoteobjectpacket_p.h
index b802f8e..612fabf 100644
--- a/src/remoteobjects/qremoteobjectpacket_p.h
+++ b/src/remoteobjects/qremoteobjectpacket_p.h
@@ -134,13 +134,6 @@ 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
{
diff --git a/src/remoteobjects/qremoteobjectsource.cpp b/src/remoteobjects/qremoteobjectsource.cpp
index 52bd089..3ddec27 100644
--- a/src/remoteobjects/qremoteobjectsource.cpp
+++ b/src/remoteobjects/qremoteobjectsource.cpp
@@ -146,7 +146,7 @@ QRemoteObjectSource::QRemoteObjectSource(QObject *obj, Private *d, const SourceA
QRemoteObjectRootSource::QRemoteObjectRootSource(QObject *obj, const SourceApiMap *api,
QObject *adapter, QRemoteObjectSourceIo *sourceIo)
- : QRemoteObjectSourceBase(obj, new Private(sourceIo), api, adapter)
+ : QRemoteObjectSourceBase(obj, new Private(sourceIo, this), api, adapter)
, m_name(api->name())
{
d->m_sourceIo->registerSource(this);
diff --git a/src/remoteobjects/qremoteobjectsource_p.h b/src/remoteobjects/qremoteobjectsource_p.h
index 4ed4c5d..602c89d 100644
--- a/src/remoteobjects/qremoteobjectsource_p.h
+++ b/src/remoteobjects/qremoteobjectsource_p.h
@@ -84,7 +84,7 @@ public:
QByteArray m_objectChecksum;
QMap<int, QPointer<QRemoteObjectSourceBase>> m_children;
struct Private {
- Private(QRemoteObjectSourceIo *io) : m_sourceIo(io), isDynamic(false) {}
+ Private(QRemoteObjectSourceIo *io, QRemoteObjectRootSource *root) : m_sourceIo(io), isDynamic(false), root(root) {}
QRemoteObjectSourceIo *m_sourceIo;
QVector<IoDeviceBase*> m_listeners;
QRemoteObjectPackets::DataStreamPacket m_packet;
@@ -92,6 +92,7 @@ public:
// Types needed during recursively sending a root to a new listener
QSet<QString> sentTypes;
bool isDynamic;
+ QRemoteObjectRootSource *root;
};
Private *d;
static const int qobjectPropertyOffset;
diff --git a/tests/auto/proxy_multiprocess/client/client.pro b/tests/auto/proxy_multiprocess/client/client.pro
index d6c31db..7a181a2 100644
--- a/tests/auto/proxy_multiprocess/client/client.pro
+++ b/tests/auto/proxy_multiprocess/client/client.pro
@@ -12,6 +12,7 @@ REPC_REPLICA = ../subclass.rep
SOURCES += main.cpp \
HEADERS += \
- ../shared.h
+ ../shared.h \
+ ../namespace.h
INCLUDEPATH += $$PWD
diff --git a/tests/auto/proxy_multiprocess/client/main.cpp b/tests/auto/proxy_multiprocess/client/main.cpp
index 1c4f02b..5f11402 100644
--- a/tests/auto/proxy_multiprocess/client/main.cpp
+++ b/tests/auto/proxy_multiprocess/client/main.cpp
@@ -62,12 +62,14 @@ private Q_SLOTS:
QVERIFY(tracksSpy.count() || tracksSpy.wait());
QCOMPARE(m_rep->myEnum(), QVariant::fromValue(ParentClassReplica::bar));
QCOMPARE(m_rep->date(), QVariant::fromValue(Qt::SystemLocaleShortDate));
+ QCOMPARE(m_rep->nsEnum(), QVariant::fromValue(NS::Bravo));
QCOMPARE(m_rep->variant(), QVariant::fromValue(42.0f));
} else {
QVERIFY(m_rep->subClass() == nullptr);
QVERIFY(m_rep->tracks() == nullptr);
QCOMPARE(m_rep->myEnum(), QVariant::fromValue(ParentClassReplica::foo));
QCOMPARE(m_rep->date(), QVariant::fromValue(Qt::ISODate));
+ QCOMPARE(m_rep->nsEnum(), QVariant::fromValue(NS::Alpha));
QCOMPARE(m_rep->variant(), QVariant());
}
@@ -97,6 +99,7 @@ private Q_SLOTS:
QVERIFY(m_rep->tracks() != nullptr);
QCOMPARE(m_rep->myEnum(), QVariant::fromValue(ParentClassReplica::foobar));
QCOMPARE(m_rep->date(), QVariant::fromValue(Qt::SystemLocaleLongDate));
+ QCOMPARE(m_rep->nsEnum(), QVariant::fromValue(NS::Charlie));
QCOMPARE(m_rep->variant(), QVariant::fromValue(podValue));
qDebug() << "Verified expected final states, cleaning up.";
}
diff --git a/tests/auto/proxy_multiprocess/namespace.h b/tests/auto/proxy_multiprocess/namespace.h
new file mode 100644
index 0000000..0b370ba
--- /dev/null
+++ b/tests/auto/proxy_multiprocess/namespace.h
@@ -0,0 +1,9 @@
+#include <QMetaType>
+
+namespace NS
+{
+ Q_NAMESPACE
+ enum NamespaceEnum { Alpha=1, Bravo, Charlie };
+ Q_ENUM_NS(NamespaceEnum)
+}
+
diff --git a/tests/auto/proxy_multiprocess/proxy_multiprocess.pro b/tests/auto/proxy_multiprocess/proxy_multiprocess.pro
index 075bc00..6bd7af7 100644
--- a/tests/auto/proxy_multiprocess/proxy_multiprocess.pro
+++ b/tests/auto/proxy_multiprocess/proxy_multiprocess.pro
@@ -1,2 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = client server proxy tst
+
+OTHER_FILES += shared.h \
+ namespace.h
diff --git a/tests/auto/proxy_multiprocess/server/main.cpp b/tests/auto/proxy_multiprocess/server/main.cpp
index e8e188d..9e806b9 100644
--- a/tests/auto/proxy_multiprocess/server/main.cpp
+++ b/tests/auto/proxy_multiprocess/server/main.cpp
@@ -57,6 +57,7 @@ private Q_SLOTS:
parent.setTracks(&model);
parent.setMyEnum(ParentClassSource::bar);
parent.setDate(Qt::SystemLocaleShortDate);
+ parent.setNsEnum(NS::Bravo);
parent.setVariant(QVariant::fromValue(42.0f));
}
@@ -84,6 +85,7 @@ private Q_SLOTS:
parent.setTracks(&model);
parent.setMyEnum(ParentClassSource::foobar);
parent.setDate(Qt::SystemLocaleLongDate);
+ parent.setNsEnum(NS::Charlie);
parent.setVariant(QVariant::fromValue(podValue));
emit parent.enum2(ParentClassSource::foo, ParentClassSource::bar);
diff --git a/tests/auto/proxy_multiprocess/server/server.pro b/tests/auto/proxy_multiprocess/server/server.pro
index 24c9a13..02ca498 100644
--- a/tests/auto/proxy_multiprocess/server/server.pro
+++ b/tests/auto/proxy_multiprocess/server/server.pro
@@ -14,6 +14,7 @@ SOURCES += main.cpp \
HEADERS += \
../shared.h \
+ ../namespace.h \
mytestserver.h \
$$OUT_PWD/rep_subclass_source.h
diff --git a/tests/auto/proxy_multiprocess/subclass.rep b/tests/auto/proxy_multiprocess/subclass.rep
index d48b690..b1fe352 100644
--- a/tests/auto/proxy_multiprocess/subclass.rep
+++ b/tests/auto/proxy_multiprocess/subclass.rep
@@ -1,6 +1,8 @@
#include <QPoint>
+#include "../namespace.h"
USE_ENUM(Qt::DateFormat)
+USE_ENUM(NS::NamespaceEnum)
POD MyPOD(int i, float f, QString s)
POD VariantPOD(int i, int j)
@@ -18,6 +20,7 @@ class ParentClass
PROP(MyEnum myEnum=foo)
PROP(QVariant variant)
PROP(Qt::DateFormat date = Qt::ISODate)
+ PROP(NS::NamespaceEnum nsEnum = NS::Alpha)
SLOT(bool start())
SLOT(bool quit())