diff options
author | Brett Stottlemyer <bstottle@ford.com> | 2019-05-15 04:50:44 -0400 |
---|---|---|
committer | Michael Brasser <michael.brasser@live.com> | 2019-05-18 01:19:12 +0000 |
commit | fa84f22bfd5500550f26f544f6905ac89e60716f (patch) | |
tree | 3b1ab26a41ab4aaf10f60a381b6445a0fdead662 | |
parent | 91f83125dd403878c989be4098cc3a35eb5ba06f (diff) |
Fix dynamic use_enum logic (Qt types only)
This is the first step in getting use_enum working. Since Qt types are
already declared, we just need to register them get support into QtRO.
Change-Id: I9b1b52f3012fa066acede921db338a755295d8d7
Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r-- | src/remoteobjects/qremoteobjectnode.cpp | 38 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectpacket.cpp | 130 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectpacket_p.h | 4 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectreplica.cpp | 4 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectreplica_p.h | 2 | ||||
-rw-r--r-- | src/remoteobjects/qremoteobjectsourceio.cpp | 12 | ||||
-rw-r--r-- | tests/auto/proxy_multiprocess/client/main.cpp | 3 | ||||
-rw-r--r-- | tests/auto/proxy_multiprocess/server/main.cpp | 2 | ||||
-rw-r--r-- | tests/auto/proxy_multiprocess/server/mytestserver.cpp | 6 | ||||
-rw-r--r-- | tests/auto/proxy_multiprocess/server/mytestserver.h | 1 | ||||
-rw-r--r-- | tests/auto/proxy_multiprocess/subclass.rep | 6 |
11 files changed, 156 insertions, 52 deletions
diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp index 2c88983..2cce1a7 100644 --- a/src/remoteobjects/qremoteobjectnode.cpp +++ b/src/remoteobjects/qremoteobjectnode.cpp @@ -758,6 +758,19 @@ static void parseGadgets(IoDeviceBase *connection, QDataStream &in, quint32 numG 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; @@ -801,6 +814,12 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connec enumBuilder.addKey(key, 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); @@ -857,19 +876,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()); - // 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(registeredName))) - continue; - const auto flags = QMetaType::IsEnumeration | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction; - int enumTypeId = -1; - int size = 4; // This could have different values once we support typed scoped enums - enumTypeId = QMetaType::registerType(registeredName.constData(), nullptr, nullptr, - &EnumDestructor<qint32>, &EnumConstructor<qint32>, size, flags, nullptr); - // Below line will register load/save if needed. - // QMetaType::registerStreamOperators(enumTypeId, &EnumSaveOperator<qint32>, &EnumLoadOperator<qint32>); - qCDebug(QT_REMOTEOBJECT) << "Registering new enum with id" << enumTypeId << enumMeta.enumName() << enumMeta.name() << enumMeta.scope(); + registerEnum(registeredName); } dynamicTypes.insert(typeString, meta); return meta; @@ -1256,7 +1263,7 @@ void QRemoteObjectNodePrivate::onClientRead(QObject *obj) QDataStream ds(typeInfo.parameters); ds >> rxValue; } - rep->setProperty(propertyIndex, deserializedProperty(rxValue, property)); + rep->setProperty(propertyIndex, decodeVariant(rxValue, property.userType())); } } else { //replica has been deleted, remove from list replicas.remove(rxName); @@ -1280,8 +1287,7 @@ void QRemoteObjectNodePrivate::onClientRead(QObject *obj) if (signal.parameterType(i) == QMetaType::QVariant) param[i + 1] = const_cast<void*>(reinterpret_cast<const void*>(&rxArgs.at(i))); else { - if (QMetaType::typeFlags(signal.parameterType(i)).testFlag(QMetaType::IsEnumeration)) - rxArgs[i].convert(signal.parameterType(i)); + decodeVariant(rxArgs[i], signal.parameterType(i)); param[i + 1] = const_cast<void *>(rxArgs.at(i).data()); } } diff --git a/src/remoteobjects/qremoteobjectpacket.cpp b/src/remoteobjects/qremoteobjectpacket.cpp index e5c6213..c2e9060 100644 --- a/src/remoteobjects/qremoteobjectpacket.cpp +++ b/src/remoteobjects/qremoteobjectpacket.cpp @@ -44,14 +44,67 @@ #include "qremoteobjectpendingcall.h" #include "qremoteobjectsource.h" #include "qremoteobjectsource_p.h" +#include <cstring> //#define QTRO_VERBOSE_PROTOCOL QT_BEGIN_NAMESPACE + +// Add methods so we can use QMetaEnum in a set +// Note for both functions we are skipping string comparisons/hashes. Since the +// metaObjects are the same, we can just use the address of the string. +inline bool operator==(const QMetaEnum e1, const QMetaEnum e2) +{ + return e1.enclosingMetaObject() == e2.enclosingMetaObject() + && e1.name() == e2.name() + && e1.enumName() == e2.enumName() + && e1.scope() == e2.scope(); +} + +inline uint qHash(const QMetaEnum &key, uint seed=0) Q_DECL_NOTHROW +{ + return qHash(key.enclosingMetaObject(), seed) ^ qHash(static_cast<const void *>(key.name()), seed) + ^ qHash(static_cast<const void *>(key.enumName()), seed) ^ qHash(static_cast<const void *>(key.scope()), seed); +} + using namespace QtRemoteObjects; namespace QRemoteObjectPackets { +// QDataStream sends QVariants of custom types by sending their typename, allowing decode +// on the receiving side. For QtRO and enums, this won't work, as the enums have different +// scopes. E.g., the examples have ParentClassSource::MyEnum and ParentClassReplica::MyEnum. +// Dynamic types will be created as ParentClass::MyEnum. So instead, we change the variants +// to integers (encodeVariant) when sending them. On the receive side, the we know the +// types of properties and the signatures for methods, so we can use that information to +// decode the integer variant into an enum variant (via decodeVariant). +const QVariant encodeVariant(const QVariant &value) +{ + if (QMetaType::typeFlags(value.userType()).testFlag(QMetaType::IsEnumeration)) { +#ifdef QTRO_VERBOSE_PROTOCOL + qDebug() << "Converting from enum to integer type" << value << value.value<qint32>(); +#endif + auto converted = QVariant(value); + converted.convert(2); // typeId for int from qmetatype.h + return converted; + } + return value; +} + +QVariant &decodeVariant(QVariant &value, int type) +{ + if (QMetaType::typeFlags(type).testFlag(QMetaType::IsEnumeration)) { +#ifdef QTRO_VERBOSE_PROTOCOL + int asInt = value.value<qint32>(); +#endif + value.convert(type); +#ifdef QTRO_VERBOSE_PROTOCOL + qDebug() << "Converting to enum from integer type" << value << asInt; +#endif + } + return value; +} + void serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, int internalIndex) { const int propertyIndex = source->m_api->sourcePropertyIndex(internalIndex); @@ -59,10 +112,6 @@ void serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, i const auto target = source->m_api->isAdapterProperty(internalIndex) ? source->m_adapter : source->m_object; const auto property = target->metaObject()->property(propertyIndex); const QVariant value = property.read(target); - if (property.isEnumType()) { - ds << QVariant::fromValue<qint32>(value.toInt()); - return; - } if (QMetaType::typeFlags(property.userType()).testFlag(QMetaType::PointerToQObject)) { auto const childSource = source->m_children.value(internalIndex); auto valueAsPointerToQObject = qvariant_cast<QObject *>(value); @@ -98,17 +147,7 @@ void serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, i return; } } - ds << value; // return original -} - -QVariant deserializedProperty(const QVariant &in, const QMetaProperty &property) -{ - if (property.isEnumType()) { - const qint32 enumValue = in.toInt(); - return QVariant(property.userType(), &enumValue); - } else { - return in; // return original - } + ds << encodeVariant(value); } void serializeHandshakePacket(DataStreamPacket &ds) @@ -224,7 +263,23 @@ static ObjectType objectType(const QString &typeName) return ObjectType::CLASS; } -void recurseForGadgets(GadgetsData &gadgets, const QRemoteObjectSourceBase *source) +// Same method as in QVariant.cpp, as it isn't publicly exposed... +static QMetaEnum metaEnumFromType(int type) +{ + QMetaType t(type); + if (t.flags() & QMetaType::IsEnumeration) { + if (const QMetaObject *metaObject = t.metaObject()) { + const char *enumName = QMetaType::typeName(type); + const char *lastColon = std::strrchr(enumName, ':'); + if (lastColon) + enumName = lastColon + 1; + return metaObject->enumerator(metaObject->indexOfEnumerator(enumName)); + } + } + return QMetaEnum(); +} + +void recurseForGadgets(GadgetsData &gadgets, QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source) { const SourceApiMap *api = source->m_api; @@ -236,6 +291,13 @@ void recurseForGadgets(GadgetsData &gadgets, const QRemoteObjectSourceBase *sour 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); + continue; + } if (!QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget)) continue; const auto mo = QMetaType::metaObjectForType(type); @@ -250,6 +312,13 @@ void recurseForGadgets(GadgetsData &gadgets, const QRemoteObjectSourceBase *sour 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); + continue; + } if (!QMetaType::typeFlags(type).testFlag(QMetaType::IsGadget)) continue; const auto mo = QMetaType::metaObjectForType(type); @@ -264,12 +333,19 @@ void recurseForGadgets(GadgetsData &gadgets, const QRemoteObjectSourceBase *sour 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); + continue; + } if (QMetaType::typeFlags(metaProperty.userType()).testFlag(QMetaType::PointerToQObject)) { auto const type = objectType(QString::fromLatin1(metaProperty.typeName())); if (type == ObjectType::CLASS) { auto const childSource = source->m_children.value(pi); if (childSource->m_object) - recurseForGadgets(gadgets, childSource); + recurseForGadgets(gadgets, enums, childSource); } } const int type = metaProperty.userType(); @@ -330,7 +406,17 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source) if (source->d->isDynamic) { GadgetsData gadgets; - recurseForGadgets(gadgets, source); + 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"; @@ -453,12 +539,8 @@ void serializeInvokePacket(DataStreamPacket &ds, const QString &name, int call, ds << index; ds << (quint32)args.size(); - foreach (const auto &arg, args) { - if (QMetaType::typeFlags(arg.userType()).testFlag(QMetaType::IsEnumeration)) - ds << QVariant::fromValue<qint32>(arg.toInt()); - else - ds << arg; - } + foreach (const auto &arg, args) + ds << encodeVariant(arg); ds << serialId; ds << propertyIndex; diff --git a/src/remoteobjects/qremoteobjectpacket_p.h b/src/remoteobjects/qremoteobjectpacket_p.h index d0292b4..b802f8e 100644 --- a/src/remoteobjects/qremoteobjectpacket_p.h +++ b/src/remoteobjects/qremoteobjectpacket_p.h @@ -175,8 +175,10 @@ private: Q_DISABLE_COPY(DataStreamPacket) }; +const QVariant encodeVariant(const QVariant &value); +QVariant &decodeVariant(QVariant &value, int type); + void serializeProperty(QDataStream &, const QRemoteObjectSourceBase *source, int internalIndex); -QVariant deserializedProperty(const QVariant &in, const QMetaProperty &property); void serializeHandshakePacket(DataStreamPacket &); void serializeInitPacket(DataStreamPacket &, const QRemoteObjectRootSource*); diff --git a/src/remoteobjects/qremoteobjectreplica.cpp b/src/remoteobjects/qremoteobjectreplica.cpp index c663efd..6536dc8 100644 --- a/src/remoteobjects/qremoteobjectreplica.cpp +++ b/src/remoteobjects/qremoteobjectreplica.cpp @@ -196,7 +196,7 @@ QVector<int> QConnectedReplicaImplementation::childIndices() const return m_childIndices; } -void QConnectedReplicaImplementation::initialize(const QVariantList &values) +void QConnectedReplicaImplementation::initialize(QVariantList &values) { qCDebug(QT_REMOTEOBJECT) << "initialize()" << m_propertyStorage.size(); const int nParam = values.size(); @@ -207,7 +207,7 @@ void QConnectedReplicaImplementation::initialize(const QVariantList &values) changedProperties[i] = -1; if (m_propertyStorage[i] != values.at(i)) { const QMetaProperty property = m_metaObject->property(i+offset); - m_propertyStorage[i] = QRemoteObjectPackets::deserializedProperty(values.at(i), property); + m_propertyStorage[i] = QRemoteObjectPackets::decodeVariant(values[i], property.userType()); changedProperties[i] = i; } qCDebug(QT_REMOTEOBJECT) << "SETPROPERTY" << i << m_metaObject->property(i+offset).name() << values.at(i).typeName() << values.at(i).toString(); diff --git a/src/remoteobjects/qremoteobjectreplica_p.h b/src/remoteobjects/qremoteobjectreplica_p.h index e724dae..79a07cf 100644 --- a/src/remoteobjects/qremoteobjectreplica_p.h +++ b/src/remoteobjects/qremoteobjectreplica_p.h @@ -158,7 +158,7 @@ public: bool isInitialized() const override; bool waitForSource(int timeout) override; QVector<int> childIndices() const; - void initialize(const QVariantList &values); + void initialize(QVariantList &values); void configurePrivate(QRemoteObjectReplica *) override; void requestRemoteObjectSource(); bool sendCommand(); diff --git a/src/remoteobjects/qremoteobjectsourceio.cpp b/src/remoteobjects/qremoteobjectsourceio.cpp index 35f3bfd..189e5f4 100644 --- a/src/remoteobjects/qremoteobjectsourceio.cpp +++ b/src/remoteobjects/qremoteobjectsourceio.cpp @@ -239,10 +239,8 @@ void QRemoteObjectSourceIo::onServerRead(QObject *conn) qRODebug(this) << "Source (method) Invoke-->" << m_rxName << source->m_object->metaObject()->method(resolvedIndex).methodSignature(); auto method = source->m_object->metaObject()->method(resolvedIndex); const int parameterCount = method.parameterCount(); - for (int i = 0; i < parameterCount; i++) { - if (QMetaType::typeFlags(method.parameterType(i)).testFlag(QMetaType::IsEnumeration)) - m_rxArgs[i].convert(method.parameterType(i)); - } + for (int i = 0; i < parameterCount; i++) + decodeVariant(m_rxArgs[i], method.parameterType(i)); } int typeId = QMetaType::type(source->m_api->typeName(index).constData()); if (!QMetaType(typeId).sizeOf()) @@ -261,15 +259,13 @@ void QRemoteObjectSourceIo::onServerRead(QObject *conn) QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(call, connection); QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, connection, [this, serialId, connection, watcher]() { if (watcher->error() == QRemoteObjectPendingCall::NoError) { - serializeInvokeReplyPacket(this->m_packet, this->m_rxName, serialId, watcher->returnValue()); + serializeInvokeReplyPacket(this->m_packet, this->m_rxName, serialId, encodeVariant(watcher->returnValue())); connection->write(m_packet.array, m_packet.size); } watcher->deleteLater(); }); } else { - if (QMetaType::typeFlags(returnValue.userType()).testFlag(QMetaType::IsEnumeration)) - returnValue = QVariant::fromValue<qint32>(returnValue.toInt()); - serializeInvokeReplyPacket(m_packet, m_rxName, serialId, returnValue); + serializeInvokeReplyPacket(m_packet, m_rxName, serialId, encodeVariant(returnValue)); connection->write(m_packet.array, m_packet.size); } } diff --git a/tests/auto/proxy_multiprocess/client/main.cpp b/tests/auto/proxy_multiprocess/client/main.cpp index 7657464..1c4f02b 100644 --- a/tests/auto/proxy_multiprocess/client/main.cpp +++ b/tests/auto/proxy_multiprocess/client/main.cpp @@ -61,11 +61,13 @@ private Q_SLOTS: QVERIFY(m_rep->tracks() != nullptr); QVERIFY(tracksSpy.count() || tracksSpy.wait()); QCOMPARE(m_rep->myEnum(), QVariant::fromValue(ParentClassReplica::bar)); + QCOMPARE(m_rep->date(), QVariant::fromValue(Qt::SystemLocaleShortDate)); 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->variant(), QVariant()); } @@ -94,6 +96,7 @@ private Q_SLOTS: QCOMPARE(m_rep->subClass()->i(), updatedI); QVERIFY(m_rep->tracks() != nullptr); QCOMPARE(m_rep->myEnum(), QVariant::fromValue(ParentClassReplica::foobar)); + QCOMPARE(m_rep->date(), QVariant::fromValue(Qt::SystemLocaleLongDate)); QCOMPARE(m_rep->variant(), QVariant::fromValue(podValue)); qDebug() << "Verified expected final states, cleaning up."; } diff --git a/tests/auto/proxy_multiprocess/server/main.cpp b/tests/auto/proxy_multiprocess/server/main.cpp index 27d4336..e8e188d 100644 --- a/tests/auto/proxy_multiprocess/server/main.cpp +++ b/tests/auto/proxy_multiprocess/server/main.cpp @@ -56,6 +56,7 @@ private Q_SLOTS: parent.setSubClass(&subclass); parent.setTracks(&model); parent.setMyEnum(ParentClassSource::bar); + parent.setDate(Qt::SystemLocaleShortDate); parent.setVariant(QVariant::fromValue(42.0f)); } @@ -82,6 +83,7 @@ private Q_SLOTS: if (objectMode == QLatin1Literal("NullPointer")) parent.setTracks(&model); parent.setMyEnum(ParentClassSource::foobar); + parent.setDate(Qt::SystemLocaleLongDate); parent.setVariant(QVariant::fromValue(podValue)); emit parent.enum2(ParentClassSource::foo, ParentClassSource::bar); diff --git a/tests/auto/proxy_multiprocess/server/mytestserver.cpp b/tests/auto/proxy_multiprocess/server/mytestserver.cpp index 8b15e4d..e55739d 100644 --- a/tests/auto/proxy_multiprocess/server/mytestserver.cpp +++ b/tests/auto/proxy_multiprocess/server/mytestserver.cpp @@ -59,3 +59,9 @@ ParentClassSource::MyEnum MyTestServer::enumSlot(QPoint p, MyEnum myEnum) Q_UNUSED(myEnum) return ParentClassSource::foobar; } + +Qt::DateFormat MyTestServer::dateSlot(Qt::DateFormat date) +{ + Q_UNUSED(date) + return Qt::SystemLocaleDate; +} diff --git a/tests/auto/proxy_multiprocess/server/mytestserver.h b/tests/auto/proxy_multiprocess/server/mytestserver.h index 22fce15..8a4d09b 100644 --- a/tests/auto/proxy_multiprocess/server/mytestserver.h +++ b/tests/auto/proxy_multiprocess/server/mytestserver.h @@ -48,6 +48,7 @@ public Q_SLOTS: bool start() override; bool quit() override; MyEnum enumSlot(QPoint p, MyEnum myEnum) override; + Qt::DateFormat dateSlot(Qt::DateFormat date) override; Q_SIGNALS: void quitApp(); diff --git a/tests/auto/proxy_multiprocess/subclass.rep b/tests/auto/proxy_multiprocess/subclass.rep index 41377d0..d48b690 100644 --- a/tests/auto/proxy_multiprocess/subclass.rep +++ b/tests/auto/proxy_multiprocess/subclass.rep @@ -1,5 +1,7 @@ #include <QPoint> +USE_ENUM(Qt::DateFormat) + POD MyPOD(int i, float f, QString s) POD VariantPOD(int i, int j) @@ -15,6 +17,7 @@ class ParentClass PROP(bool started = false) PROP(MyEnum myEnum=foo) PROP(QVariant variant) + PROP(Qt::DateFormat date = Qt::ISODate) SLOT(bool start()) SLOT(bool quit()) @@ -22,6 +25,9 @@ class ParentClass SIGNAL(enum2(MyEnum myEnum1, MyEnum myEnum2)) SLOT(MyEnum enumSlot(QPoint point, MyEnum myEnum)) + SIGNAL(updateDate(Qt::DateFormat date1, Qt::DateFormat date2)) + SLOT(Qt::DateFormat dateSlot(Qt::DateFormat date)) + CLASS subClass(SubClass) MODEL tracks(display) } |