summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2018-04-03 13:44:01 -0400
committerBrett Stottlemyer <bstottle@ford.com>2018-04-04 01:39:37 +0000
commit35dd08098f8a4b422d523792261aefe039358f6a (patch)
tree3c626bca824b869d2008e00978496c731fc5e4d6
parent6e5e4df3c65e01bae143887fb4eff409c846023a (diff)
Rework REPC QObject* handlingv5.11.0-beta3
The MODEL and CLASS types were originally tacked on top of repc's property handling mechanism. That is, separate lists for models and subclasses were created instead of including the types in repc's list of property metadata. This was convenient for proving out the functionality, but led to a bunch of one-off code (generating Q_PROPERTY code manually, needing separate replica getter functions, etc). This change incorporates the pointer types back into the property list in repc, simplifying the code. This does require extensions because pointer types are not symmetric (i.e., for MODEL, the type is QAbstractItemModel* on the source side, QAbstractItemModelReplica* on the replica side). The generated SourceApi code is enhanced to compile-time check subclass types as well as take an optional name parameter (which allows a class to have multiple subclass pointers). SimpleSource handling of CONSTANT properties is also extended, providing constructor parameters to set the initial values. Change-Id: I91f542ef936abe4459962ae759ba3b0571464d5f Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r--src/remoteobjects/qremoteobjectnode.cpp36
-rw-r--r--src/remoteobjects/qremoteobjectreplica.cpp12
-rw-r--r--src/remoteobjects/qremoteobjectreplica.h1
-rw-r--r--src/remoteobjects/qremoteobjectsource.cpp7
-rw-r--r--src/remoteobjects/qremoteobjectsource.h7
-rw-r--r--src/remoteobjects/qtremoteobjectglobal.h2
-rw-r--r--src/repparser/parser.g60
-rw-r--r--tests/auto/integration/engine.cpp4
-rw-r--r--tests/auto/integration/engine.h2
-rw-r--r--tests/auto/repparser/tst_parser.cpp11
-rw-r--r--tools/repc/repcodegenerator.cpp318
-rw-r--r--tools/repc/repcodegenerator.h1
12 files changed, 211 insertions, 250 deletions
diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp
index c035e37..97abf89 100644
--- a/src/remoteobjects/qremoteobjectnode.cpp
+++ b/src/remoteobjects/qremoteobjectnode.cpp
@@ -62,6 +62,23 @@ static QString name(const QMetaObject * const mobj)
return ind >= 0 ? QString::fromLatin1(mobj->classInfo(ind).value()) : QString();
}
+QString QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(const QMetaObject *& meta) {
+ QString typeName;
+ const int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ if (ind != -1) { //We have an object created from repc or at least with QCLASSINFO defined
+ typeName = QString::fromLatin1(meta->classInfo(ind).value());
+ while (true) {
+ Q_ASSERT(meta->superClass());//This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
+ //At the point superclass doesn't have the same QCLASSINFO_REMOTEOBJECT_TYPE,
+ //we have the metaobject we should work from
+ if (ind != meta->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE))
+ break;
+ meta = meta->superClass();
+ }
+ }
+ return typeName;
+}
+
template <typename K, typename V, typename Query>
bool map_contains(const QMap<K,V> &map, const Query &key, typename QMap<K,V>::const_iterator &result)
{
@@ -1329,20 +1346,8 @@ bool QRemoteObjectHostBase::enableRemoting(QObject *object, const QString &name)
const QMetaObject *meta = object->metaObject();
QString _name = name;
- QString typeName;
- const int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
- if (ind != -1) { //We have an object created from repc or at least with QCLASSINFO defined
- typeName = QString::fromLatin1(meta->classInfo(ind).value());
- if (_name.isEmpty())
- _name = typeName;
- while (true) {
- Q_ASSERT(meta->superClass()); //This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
- if (ind != meta->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE)) //At the point we don't find the same QCLASSINFO_REMOTEOBJECT_TYPE,
- //we have the metaobject we should work from
- break;
- meta = meta->superClass();
- }
- } else { //This is a passed in QObject, use its API
+ QString typeName = getTypeNameAndMetaobjectFromClassInfo(meta);
+ if (typeName.isEmpty()) { //This is a passed in QObject, use its API
if (_name.isEmpty()) {
_name = object->objectName();
if (_name.isEmpty()) {
@@ -1351,7 +1356,8 @@ bool QRemoteObjectHostBase::enableRemoting(QObject *object, const QString &name)
return false;
}
}
- }
+ } else if (_name.isEmpty())
+ _name = typeName;
return d->remoteObjectIo->enableRemoting(object, meta, _name, typeName, this);
}
diff --git a/src/remoteobjects/qremoteobjectreplica.cpp b/src/remoteobjects/qremoteobjectreplica.cpp
index 292e6db..3d15502 100644
--- a/src/remoteobjects/qremoteobjectreplica.cpp
+++ b/src/remoteobjects/qremoteobjectreplica.cpp
@@ -129,6 +129,10 @@ QConnectedReplicaImplementation::~QConnectedReplicaImplementation()
serializeRemoveObjectPacket(m_packet, m_objectName);
sendCommand();
}
+ for (auto prop : m_propertyStorage) {
+ if (prop.canConvert<QObject*>())
+ prop.value<QObject *>()->deleteLater();
+ }
}
bool QRemoteObjectReplicaImplementation::needsDynamicInitialization() const
@@ -640,6 +644,14 @@ void QRemoteObjectReplica::setProperties(const QVariantList &properties)
}
/*!
+ \internal
+*/
+void QRemoteObjectReplica::setChild(int i, const QVariant &value)
+{
+ d_impl->setProperty(i, value);
+}
+
+/*!
Returns \c true if this replica has been initialized with data from the \l {Source} object. Returns \c false otherwise.
\sa state()
diff --git a/src/remoteobjects/qremoteobjectreplica.h b/src/remoteobjects/qremoteobjectreplica.h
index a6b7d56..04c5db6 100644
--- a/src/remoteobjects/qremoteobjectreplica.h
+++ b/src/remoteobjects/qremoteobjectreplica.h
@@ -92,6 +92,7 @@ protected:
protected:
void setProperties(const QVariantList &);
+ void setChild(int i, const QVariant &);
const QVariant propAsVariant(int i) const;
void persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props) const;
QVariantList retrieveProperties(const QString &repName, const QByteArray &repSig) const;
diff --git a/src/remoteobjects/qremoteobjectsource.cpp b/src/remoteobjects/qremoteobjectsource.cpp
index d28c59e..3a91922 100644
--- a/src/remoteobjects/qremoteobjectsource.cpp
+++ b/src/remoteobjects/qremoteobjectsource.cpp
@@ -275,7 +275,12 @@ DynamicApiMap::DynamicApiMap(QObject *object, const QMetaObject *metaObject, con
QString::fromLatin1(property.name()),
roleInfo});
} else {
- m_subclasses << SubclassInfo({child, QString::fromLatin1(property.name())});
+ const QMetaObject *meta = child->metaObject();
+ QString typeName = QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(meta);
+ if (typeName.isNull())
+ typeName = QString::fromLatin1(propertyMeta->className());
+
+ m_subclasses << SubclassInfo{child, QString::fromLatin1(property.name()), new DynamicApiMap(child, meta, QString::fromLatin1(property.name()), typeName)};
}
continue;
}
diff --git a/src/remoteobjects/qremoteobjectsource.h b/src/remoteobjects/qremoteobjectsource.h
index a5b738b..bd57dad 100644
--- a/src/remoteobjects/qremoteobjectsource.h
+++ b/src/remoteobjects/qremoteobjectsource.h
@@ -131,18 +131,19 @@ struct ModelInfo
QByteArray roles;
};
+class SourceApiMap;
struct SubclassInfo
{
+ SubclassInfo(QObject *_ptr = nullptr, QString _name = QString(), SourceApiMap *_api = nullptr) : ptr(_ptr), name(_name), api(_api) {}
QObject *ptr;
QString name;
+ SourceApiMap *api;
};
class SourceApiMap
{
protected:
SourceApiMap() {}
- QVector<ModelInfo> m_models;
- QVector<SubclassInfo> m_subclasses;
public:
virtual ~SourceApiMap() {}
virtual QString name() const = 0;
@@ -173,6 +174,8 @@ public:
virtual bool isAdapterMethod(int) const { return false; }
virtual bool isAdapterProperty(int) const { return false; }
void qobjectSetup(QRemoteObjectHostBase *node) const;
+ QVector<ModelInfo> m_models;
+ QVector<SubclassInfo> m_subclasses;
};
QT_END_NAMESPACE
diff --git a/src/remoteobjects/qtremoteobjectglobal.h b/src/remoteobjects/qtremoteobjectglobal.h
index 69ba108..4a9ca81 100644
--- a/src/remoteobjects/qtremoteobjectglobal.h
+++ b/src/remoteobjects/qtremoteobjectglobal.h
@@ -136,6 +136,8 @@ Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, const vo
Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &dst);
Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst);
+QString getTypeNameAndMetaobjectFromClassInfo(const QMetaObject *& meta);
+
template <typename T>
void copyStoredProperties(const T *src, T *dst)
{
diff --git a/src/repparser/parser.g b/src/repparser/parser.g
index 6736b67..0343576 100644
--- a/src/repparser/parser.g
+++ b/src/repparser/parser.g
@@ -87,13 +87,15 @@ struct ASTProperty
};
ASTProperty();
- ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted);
+ ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted,
+ bool isPointer=false);
QString type;
QString name;
QString defaultValue;
Modifier modifier;
bool persisted;
+ bool isPointer;
};
Q_DECLARE_TYPEINFO(ASTProperty, Q_MOVABLE_TYPE);
@@ -178,29 +180,20 @@ Q_DECLARE_TYPEINFO(ASTModelRole, Q_MOVABLE_TYPE);
struct ASTModel
{
- explicit ASTModel(const QString &name = QString());
+ ASTModel(int index = -1) : propertyIndex(index) {}
QVector<ASTModelRole> roles;
- QString name;
+ int propertyIndex;
};
Q_DECLARE_TYPEINFO(ASTModel, Q_MOVABLE_TYPE);
-struct ASTChildRep
-{
- explicit ASTChildRep(const QString &name = QString(),
- const QString &type = QString());
-
- QString name;
- QString type;
-};
-Q_DECLARE_TYPEINFO(ASTChildRep, Q_MOVABLE_TYPE);
-
/// A Class declaration
struct ASTClass
{
explicit ASTClass(const QString& name = QString());
bool isValid() const;
+ bool hasPointerObjects() const;
QString name;
QVector<ASTProperty> properties;
@@ -208,8 +201,8 @@ struct ASTClass
QVector<ASTFunction> slotsList;
QVector<ASTEnum> enums;
bool hasPersisted;
- QVector<ASTModel> models;
- QVector<ASTChildRep> children;
+ QVector<ASTModel> modelMetadata;
+ QVector<int> subClassPropertyIndices;
};
Q_DECLARE_TYPEINFO(ASTClass, Q_MOVABLE_TYPE);
@@ -328,12 +321,12 @@ static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false)
}
ASTProperty::ASTProperty()
- : modifier(ReadPush), persisted(false)
+ : modifier(ReadPush), persisted(false), isPointer(false)
{
}
-ASTProperty::ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted)
- : type(type), name(name), defaultValue(defaultValue), modifier(modifier), persisted(persisted)
+ASTProperty::ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted, bool isPointer)
+ : type(type), name(name), defaultValue(defaultValue), modifier(modifier), persisted(persisted), isPointer(isPointer)
{
}
@@ -387,16 +380,6 @@ ASTEnum::ASTEnum(const QString &name)
{
}
-ASTModel::ASTModel(const QString &name)
- : name(name)
-{
-}
-
-ASTChildRep::ASTChildRep(const QString &name, const QString &type)
- : name(name), type(type)
-{
-}
-
ASTClass::ASTClass(const QString &name)
: name(name), hasPersisted(false)
{
@@ -407,6 +390,12 @@ bool ASTClass::isValid() const
return !name.isEmpty();
}
+bool ASTClass::hasPointerObjects() const
+{
+ int count = modelMetadata.size() + subClassPropertyIndices.size();
+ return count > 0;
+}
+
RepParser::RepParser(QIODevice &outputDevice)
: QRegexParser(), m_astEnumValue(-1)
{
@@ -841,14 +830,15 @@ Model: model;
/.
case $rule_number:
{
- ASTModel model;
- model.name = captured().value(QLatin1String("name")).trimmed();
+ ASTModel model(m_astClass.properties.size());
+ const QString name = captured().value(QLatin1String("name")).trimmed();
const QString argString = captured().value(QLatin1String("args")).trimmed();
if (!parseRoles(model, argString))
return false;
- m_astClass.models << model;
+ m_astClass.modelMetadata << model;
+ m_astClass.properties << ASTProperty(QStringLiteral("QAbstractItemModel"), name, QStringLiteral("nullptr"), ASTProperty::Constant, false, true);
}
break;
./
@@ -857,11 +847,11 @@ ChildRep: childrep;
/.
case $rule_number:
{
- ASTChildRep child;
- child.name = captured().value(QLatin1String("name")).trimmed();
- child.type = captured().value(QLatin1String("type")).trimmed();
+ const QString name = captured().value(QLatin1String("name")).trimmed();
+ const QString type = captured().value(QLatin1String("type")).trimmed();
- m_astClass.children << child;
+ m_astClass.subClassPropertyIndices << m_astClass.properties.size();
+ m_astClass.properties << ASTProperty(type, name, QStringLiteral("nullptr"), ASTProperty::Constant, false, true);
}
break;
./
diff --git a/tests/auto/integration/engine.cpp b/tests/auto/integration/engine.cpp
index d59b2d5..9f1c103 100644
--- a/tests/auto/integration/engine.cpp
+++ b/tests/auto/integration/engine.cpp
@@ -28,8 +28,8 @@
#include "engine.h"
-Engine::Engine(QObject *parent) :
- EngineSimpleSource(parent)
+Engine::Engine(int cylinders, QObject *parent) :
+ EngineSimpleSource(cylinders, parent)
{
setRpm(0);
setpurchasedPart(false);
diff --git a/tests/auto/integration/engine.h b/tests/auto/integration/engine.h
index 7252f38..12ef36a 100644
--- a/tests/auto/integration/engine.h
+++ b/tests/auto/integration/engine.h
@@ -37,7 +37,7 @@ class Engine : public EngineSimpleSource
Q_PROPERTY(bool purchasedPart READ purchasedPart WRITE setpurchasedPart)
public:
- Engine(QObject *parent = nullptr);
+ Engine(int cylinders = 4, QObject *parent = nullptr);
~Engine() override;
bool start() override;
diff --git a/tests/auto/repparser/tst_parser.cpp b/tests/auto/repparser/tst_parser.cpp
index 58162ce..46211a2 100644
--- a/tests/auto/repparser/tst_parser.cpp
+++ b/tests/auto/repparser/tst_parser.cpp
@@ -386,8 +386,9 @@ void tst_Parser::testModels()
QCOMPARE(ast.classes.count(), 1);
const ASTClass astClass = ast.classes.first();
- ASTModel model = astClass.models.first();
- QCOMPARE(model.name, expectedModel);
+ ASTModel model = astClass.modelMetadata.first();
+ ASTProperty property = astClass.properties.at(model.propertyIndex);
+ QCOMPARE(property.name, expectedModel);
int i = 0;
for (auto role : model.roles) {
QCOMPARE(role.name, expectedRoles.at(i).name);
@@ -430,9 +431,9 @@ void tst_Parser::testClasses()
const ASTClass astSub = ast.classes.value(0);
const ASTClass astObj = ast.classes.value(1);
- const ASTChildRep child = astObj.children.first();
- QCOMPARE(child.name, expectedName);
- QCOMPARE(child.type, expectedType);
+ const ASTProperty property = astObj.properties.at(astObj.subClassPropertyIndices.at(0));
+ QCOMPARE(property.name, expectedName);
+ QCOMPARE(property.type, expectedType);
}
void tst_Parser::testInvalid_data()
diff --git a/tools/repc/repcodegenerator.cpp b/tools/repc/repcodegenerator.cpp
index 00cc481..8f8cfb3 100644
--- a/tools/repc/repcodegenerator.cpp
+++ b/tools/repc/repcodegenerator.cpp
@@ -201,8 +201,11 @@ void RepCodeGenerator::generate(const AST &ast, Mode mode, QString fileName)
metaTypes << attribute.type;
}
Q_FOREACH (const ASTClass &astClass, ast.classes) {
- Q_FOREACH (const ASTProperty &property, astClass.properties)
+ Q_FOREACH (const ASTProperty &property, astClass.properties) {
+ if (property.isPointer)
+ continue;
metaTypes << property.type;
+ }
Q_FOREACH (const ASTFunction &function, astClass.signalsList + astClass.slotsList) {
metaTypes << function.returnType;
Q_FOREACH (const ASTDeclaration &decl, function.params) {
@@ -248,7 +251,7 @@ void RepCodeGenerator::generateHeader(Mode mode, QTextStream &out, const AST &as
bool hasModel = false;
for (auto c : ast.classes)
{
- if (c.models.count() > 0)
+ if (c.modelMetadata.count() > 0)
{
hasModel = true;
break;
@@ -362,6 +365,25 @@ QString RepCodeGenerator::formatMarshallingOperators(const POD &pod)
;
}
+QString RepCodeGenerator::typeForMode(const ASTProperty &property, RepCodeGenerator::Mode mode)
+{
+ if (!property.isPointer)
+ return property.type;
+
+ if (property.type.startsWith(QStringLiteral("QAbstractItemModel")))
+ return mode == REPLICA ? property.type + QStringLiteral("Replica*") : property.type + QStringLiteral("*");
+
+ switch (mode) {
+ case REPLICA: return property.type + QStringLiteral("Replica*");
+ case SIMPLE_SOURCE:
+ Q_FALLTHROUGH();
+ case SOURCE: return property.type + QStringLiteral("Source*");
+ default: qCritical("Invalid mode");
+ }
+
+ return QStringLiteral("InvalidPropertyName");
+}
+
void RepCodeGenerator::generateSimpleSetter(QTextStream &out, const ASTProperty &property, bool generateOverride)
{
out << " virtual void set" << cap(property.name) << "(" << property.type << " " << property.name << ")";
@@ -594,20 +616,21 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
if (mode != SIMPLE_SOURCE) {
out << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, \"" << astClass.name << "\")" << endl;
out << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, \"" << QLatin1String(classSignature(astClass)) << "\")" << endl;
- for (int i = 0; i < astClass.models.count(); i++) {
- const auto model = astClass.models.at(i);
+ for (int i = 0; i < astClass.modelMetadata.count(); i++) {
+ const auto model = astClass.modelMetadata.at(i);
+ const auto modelName = astClass.properties.at(model.propertyIndex).name;
if (!model.roles.isEmpty()) {
QStringList list;
for (auto role : model.roles)
list << role.name;
- out << QString::fromLatin1(" Q_CLASSINFO(\"%1_ROLES\", \"%2\")").arg(model.name.toUpper(), list.join(QChar::fromLatin1('|'))) << endl;
+ out << QString::fromLatin1(" Q_CLASSINFO(\"%1_ROLES\", \"%2\")").arg(modelName.toUpper(), list.join(QChar::fromLatin1('|'))) << endl;
}
}
//First output properties
Q_FOREACH (const ASTProperty &property, astClass.properties) {
- out << " Q_PROPERTY(" << property.type << " " << property.name << " READ " << property.name;
+ out << " Q_PROPERTY(" << typeForMode(property, mode) << " " << property.name << " READ " << property.name;
if (property.modifier == ASTProperty::Constant)
out << " CONSTANT";
else if (property.modifier == ASTProperty::ReadOnly)
@@ -622,18 +645,6 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
}
out << ")" << endl;
}
- for (auto model : astClass.models) {
- if (mode == REPLICA)
- out << QString::fromLatin1(" Q_PROPERTY(QAbstractItemModelReplica *%1 READ %1 NOTIFY %1Changed)").arg(model.name) << endl;
- else
- out << QString::fromLatin1(" Q_PROPERTY(QAbstractItemModel *%1 READ %1 CONSTANT)").arg(model.name) << endl;
- }
- for (auto child : astClass.children) {
- if (mode == REPLICA)
- out << QString::fromLatin1(" Q_PROPERTY(%1Replica *%2 READ %2 NOTIFY %2Changed)").arg(child.type, child.name) << endl;
- else
- out << QString::fromLatin1(" Q_PROPERTY(%1Source *%2 READ %2 CONSTANT)").arg(child.type, child.name) << endl;
- }
if (!astClass.enums.isEmpty()) {
out << "" << endl;
@@ -659,47 +670,42 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << " }" << endl;
- if (!astClass.models.isEmpty() || !astClass.children.isEmpty())
+ if (astClass.hasPointerObjects())
{
out << " void setNode(QRemoteObjectNode *node) override" << endl;
out << " {" << endl;
- for (auto model : astClass.models) {
- out << QString::fromLatin1(" m_%1.reset(node->acquireModel(\"Model::%1\"));")
- .arg(model.name) << endl;
- out << " emit " << model.name << "Changed();" << endl;
- }
- for (auto child : astClass.children) {
- out << QString::fromLatin1(" m_%1.reset(node->acquire<%2Replica>(\"Class::%1\"));")
- .arg(child.name, child.type) << endl;
- out << " emit " << child.name << "Changed();" << endl;
- }
- if (!astClass.children.isEmpty()) {
- out << " // This relies on finalize being called before any other slots connected to initialized to ensure" << endl;
- out << " // any child replicas that don't have sources are null instead of the replica defaults." << endl;
- out << " connect(this, &" << className << "::initialized, [this]() { finalize(); });" << endl;
- }
out << " QRemoteObjectReplica::setNode(node);" << endl;
+ for (int index = 0; index < astClass.properties.count(); ++index) {
+ const ASTProperty &property = astClass.properties.at(index);
+ if (!property.isPointer)
+ continue;
+ if (astClass.subClassPropertyIndices.contains(index))
+ out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquire<%2Replica>(\"Class::%3\")));")
+ .arg(QString::number(index), property.type, property.name) << endl;
+ else
+ out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquireModel(\"Model::%2\")));")
+ .arg(QString::number(index), property.name) << endl;
+ }
out << " }" << endl;
}
out << "" << endl;
out << "private:" << endl;
out << " " << className << "(QRemoteObjectNode *node, const QString &name = QString())" << endl;
out << " : QRemoteObjectReplica(ConstructWithNode)" << endl;
- for (auto model : astClass.models)
- out << QString::fromLatin1(" , m_%1(node->acquireModel(\"Model::%1\"))")
- .arg(model.name) << endl;
- for (auto child : astClass.children)
- out << QString::fromLatin1(" , m_%1(node->acquire<%2Replica>(\"Class::%1\"))")
- .arg(child.name, child.type) << endl;
- if (astClass.children.count()) {
- out << " {" << endl;
- out << " // This relies on finalize being called before any other slots connected to initialized to ensure" << endl;
- out << " // any child replicas that don't have sources are null instead of the replica defaults." << endl;
- out << " connect(this, &" << className << "::initialized, [this]() { finalize(); });" << endl;
- out << " initializeNode(node, name);" << endl;
- out << " }" << endl;
- } else
- out << " { initializeNode(node, name); }" << endl;
+ out << " {" << endl;
+ out << " initializeNode(node, name);" << endl;
+ for (int index = 0; index < astClass.properties.count(); ++index) {
+ const ASTProperty &property = astClass.properties.at(index);
+ if (!property.isPointer)
+ continue;
+ if (astClass.subClassPropertyIndices.contains(index))
+ out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquire<%2Replica>(\"Class::%3\")));")
+ .arg(QString::number(index), property.type, property.name) << endl;
+ else
+ out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquireModel(\"Model::%2\")));")
+ .arg(QString::number(index), property.name) << endl;
+ }
+ out << " }" << endl;
out << "" << endl;
@@ -709,7 +715,10 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << " QVariantList properties;" << endl;
out << " properties.reserve(" << astClass.properties.size() << ");" << endl;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
- out << " properties << QVariant::fromValue(" << property.type << "(" << property.defaultValue << "));" << endl;
+ if (property.isPointer)
+ out << " properties << QVariant::fromValue((" << typeForMode(property, mode) << ")" << property.defaultValue << ");" << endl;
+ else
+ out << " properties << QVariant::fromValue(" << typeForMode(property, mode) << "(" << property.defaultValue << "));" << endl;
}
int nPersisted = 0;
if (astClass.hasPersisted) {
@@ -725,46 +734,37 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
}
out << " setProperties(properties);" << endl;
out << " }" << endl;
+ } else if (mode == SOURCE) {
+ out << " explicit " << className << "(QObject *parent = nullptr) : QObject(parent)" << endl;
+ out << " {" << endl;
+ if (!metaTypeRegistrationCode.isEmpty())
+ out << metaTypeRegistrationCode << endl;
+ out << " }" << endl;
} else {
- if ( (astClass.models.isEmpty() && astClass.children.isEmpty()) || mode == SOURCE) {
- if (mode == SOURCE)
- out << " explicit " << className << "(QObject *parent = nullptr) : QObject(parent)" << endl;
- else
- out << " explicit " << className << "(QObject *parent = nullptr) : " << astClass.name << "Source(parent)" << endl;
+ QVector<int> constIndices;
+ for (int index = 0; index < astClass.properties.count(); ++index) {
+ const ASTProperty &property = astClass.properties.at(index);
+ if (property.modifier == ASTProperty::Constant)
+ constIndices.append(index);
+ }
+ if (constIndices.isEmpty()) {
+ out << " explicit " << className << "(QObject *parent = nullptr) : " << astClass.name << "Source(parent)" << endl;
} else {
- int childIndex = 0;
- if (astClass.models.count())
- out << " explicit " << className << "(QAbstractItemModel *model0";
- else {
- out << " explicit " << className << "(" << astClass.children.at(0).type << "Source *sub0";
- childIndex = 1;
- }
- for (int i = 1; i < astClass.models.count(); i++)
- out << QString::fromLatin1(", QAbstractItemModel *model%1").arg(QString::number(i));
- for (int i = childIndex; i < astClass.children.count(); i++)
- out << QString::fromLatin1(", %1Source *sub%2").arg(astClass.children.at(childIndex).type, QString::number(i));
- out << ", QObject *parent = nullptr) : " << astClass.name << "Source(parent)" << endl;
- for (int i = 0; i < astClass.models.count(); i++)
- {
- out << " , m_" << astClass.models[i].name
- << QString::fromLatin1("(model%1)").arg(QString::number(i)) << endl;
- }
- for (int i = 0; i < astClass.children.count(); i++)
- {
- out << " , m_" << astClass.children[i].name
- << QString::fromLatin1("(sub%1)").arg(QString::number(i)) << endl;
+ QStringList parameters;
+ for (int index : constIndices) {
+ const ASTProperty &property = astClass.properties.at(index);
+ parameters.append(QString::fromLatin1("%1 %2 = %3").arg(typeForMode(property, SOURCE), property.name, property.defaultValue));
}
+ parameters.append(QStringLiteral("QObject *parent = nullptr"));
+ out << " explicit " << className << "(" << parameters.join(QStringLiteral(", ")) << ") : " << astClass.name << "Source(parent)" << endl;
}
-
- if (mode == SIMPLE_SOURCE) {
- Q_FOREACH (const ASTProperty &property, astClass.properties) {
+ Q_FOREACH (const ASTProperty &property, astClass.properties) {
+ if (property.modifier == ASTProperty::Constant)
+ out << " , m_" << property.name << "(" << property.name << ")" << endl;
+ else
out << " , m_" << property.name << "(" << property.defaultValue << ")" << endl;
- }
}
-
out << " {" << endl;
- if (mode != SIMPLE_SOURCE && !metaTypeRegistrationCode.isEmpty())
- out << metaTypeRegistrationCode << endl;
out << " }" << endl;
}
@@ -793,13 +793,14 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
if (mode == REPLICA) {
int i = 0;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
- out << " " << property.type << " " << property.name << "() const" << endl;
+ auto type = typeForMode(property, mode);
+ out << " " << type << " " << property.name << "() const" << endl;
out << " {" << endl;
out << " const QVariant variant = propAsVariant(" << i << ");" << endl;
- out << " if (!variant.canConvert<" << property.type << ">()) {" << endl;
- out << " qWarning() << \"QtRO cannot convert the property " << property.name << " to type " << property.type << "\";" << endl;
+ out << " if (!variant.canConvert<" << type << ">()) {" << endl;
+ out << " qWarning() << \"QtRO cannot convert the property " << property.name << " to type " << type << "\";" << endl;
out << " }" << endl;
- out << " return variant.value<" << property.type << " >();" << endl;
+ out << " return variant.value<" << type << " >();" << endl;
out << " }" << endl;
i++;
if (property.modifier == ASTProperty::ReadWrite) {
@@ -816,16 +817,16 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
}
} else if (mode == SOURCE) {
Q_FOREACH (const ASTProperty &property, astClass.properties)
- out << " virtual " << property.type << " " << property.name << "() const = 0;" << endl;
+ out << " virtual " << typeForMode(property, mode) << " " << property.name << "() const = 0;" << endl;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
if (property.modifier == ASTProperty::ReadWrite ||
property.modifier == ASTProperty::ReadPush)
out << " virtual void set" << cap(property.name) << "(" << property.type << " " << property.name << ") = 0;" << endl;
}
} else {
- Q_FOREACH (const ASTProperty &property, astClass.properties) {
- out << " virtual " << property.type << " " << property.name << "() const override { return m_" << property.name << "; }" << endl;
- }
+ Q_FOREACH (const ASTProperty &property, astClass.properties)
+ out << " " << typeForMode(property, mode) << " " << property.name << "() const override { return m_"
+ << property.name << "; }" << endl;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
if (property.modifier == ASTProperty::ReadWrite ||
property.modifier == ASTProperty::ReadPush) {
@@ -834,42 +835,6 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
}
}
- if (!astClass.models.isEmpty()) {
- Q_FOREACH (const ASTModel &model, astClass.models) {
- if (mode != SOURCE) {
- if (mode == REPLICA)
- out << " QAbstractItemModelReplica *" << model.name << "()" << endl;
- else
- out << " QAbstractItemModel *" << model.name << "() override" << endl;
- out << " {" << endl;
- out << " return m_" << model.name << ".data();" << endl;
- out << " }" << endl;
- } else {
- out << " virtual QAbstractItemModel *" << model.name << "() = 0;" << endl;
- }
- }
- }
-
- if (!astClass.children.isEmpty()) {
- Q_FOREACH (const ASTChildRep &child, astClass.children) {
- if (mode != SOURCE) {
- if (mode == REPLICA) {
- out << " " << child.type << "Replica *" << child.name << "()" << endl;
- out << " {" << endl;
- out << " return m_" << child.name << ".data();" << endl;
- out << " }" << endl;
- } else {
- out << " " << child.type << "Source *" << child.name << "() override" << endl;
- out << " {" << endl;
- out << " return m_" << child.name << ";" << endl;
- out << " }" << endl;
- }
- } else {
- out << " virtual " << child.type << "Source *" << child.name << "() = 0;" << endl;
- }
- }
- }
-
if (mode != SIMPLE_SOURCE) {
//Next output property signals
if (!astClass.properties.isEmpty() || !astClass.signalsList.isEmpty()) {
@@ -877,23 +842,12 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << "Q_SIGNALS:" << endl;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
if (property.modifier != ASTProperty::Constant)
- out << " void " << property.name << "Changed(" << fullyQualifiedTypeName(astClass, className, property.type) << " " << property.name << ");" << endl;
+ out << " void " << property.name << "Changed(" << fullyQualifiedTypeName(astClass, className, typeForMode(property, mode)) << " " << property.name << ");" << endl;
}
QVector<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList, className);
Q_FOREACH (const ASTFunction &signal, signalsList)
out << " void " << signal.name << "(" << signal.paramsAsString() << ");" << endl;
- for (auto model : astClass.models)
- out << " void " << model.name << "Changed();" << endl;
- for (auto child : astClass.children)
- out << " void " << child.name << "Changed();" << endl;
- } else if (!astClass.models.isEmpty() || !astClass.children.isEmpty()) {
- out << "" << endl;
- out << "Q_SIGNALS:" << endl;
- for (auto model : astClass.models)
- out << " void " << model.name << "Changed();" << endl;
- for (auto child : astClass.children)
- out << " void " << child.name << "Changed();" << endl;
}
bool hasWriteSlots = false;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
@@ -972,32 +926,8 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
//Next output data members
if (mode == SIMPLE_SOURCE) {
- Q_FOREACH (const ASTModel &model, astClass.models)
- out << " QScopedPointer<QAbstractItemModel> m_" << model.name << ";" << endl;
- Q_FOREACH (const ASTChildRep &child, astClass.children)
- out << " " << child.type << "Source *m_" << child.name << ";" << endl;
-
- if (!astClass.properties.isEmpty()) {
- Q_FOREACH (const ASTProperty &property, astClass.properties) {
- out << " " << property.type << " " << "m_" << property.name << ";" << endl;
- }
- }
- } else if (mode == REPLICA) {
- if (astClass.children.count()) {
- out << " void finalize()" << endl;
- out << " {" << endl;
- Q_FOREACH (const ASTChildRep &child, astClass.children) {
- out << " if (!m_" << child.name << "->isInitialized()) {" << endl;
- out << " m_" << child.name << ".reset(nullptr);" << endl;
- out << " emit " << child.name << "Changed();" << endl;
- out << " }" << endl;
- }
- out << " }" << endl << endl;
- }
- Q_FOREACH (const ASTModel &model, astClass.models)
- out << " QScopedPointer<QAbstractItemModelReplica> m_" << model.name << ";" << endl;
- Q_FOREACH (const ASTChildRep &child, astClass.children)
- out << " QScopedPointer<" << child.type << "Replica> m_" << child.name << ";" << endl;
+ Q_FOREACH (const ASTProperty &property, astClass.properties)
+ out << " " << typeForMode(property, SOURCE) << " " << "m_" << property.name << ";" << endl;
}
if (mode != SIMPLE_SOURCE)
@@ -1029,13 +959,18 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
// Include enum definition in SourceAPI
generateDeclarationsForEnums(out, astClass.enums, false);
}
- out << QString::fromLatin1(" %1(ObjectType *object)").arg(className) << endl;
- out << QStringLiteral(" : SourceApiMap()") << endl;
+ out << QString::fromLatin1(" %1(ObjectType *object, const QString &name = QStringLiteral(\"%2\"))").arg(className, astClass.name) << endl;
+ out << QStringLiteral(" : SourceApiMap(), m_name(name)") << endl;
out << QStringLiteral(" {") << endl;
- if (astClass.models.isEmpty() && astClass.children.isEmpty())
+ if (!astClass.hasPointerObjects())
out << QStringLiteral(" Q_UNUSED(object);") << endl;
const int enumCount = astClass.enums.count();
+ for (int i : astClass.subClassPropertyIndices) {
+ const ASTProperty &child = astClass.properties.at(i);
+ out << QString::fromLatin1(" using %1_type_t = typename std::remove_pointer<decltype(object->%1())>::type;")
+ .arg(child.name) << endl;
+ }
out << QString::fromLatin1(" m_enums[0] = %1;").arg(enumCount) << endl;
for (int i = 0; i < enumCount; ++i) {
const auto enumerator = astClass.enums.at(i);
@@ -1044,11 +979,11 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
}
const int propCount = astClass.properties.count();
out << QString::fromLatin1(" m_properties[0] = %1;").arg(propCount) << endl;
- QStringList changeSignals;
+ QList<ASTProperty> onChangeProperties;
QList<int> propertyChangeIndex;
for (int i = 0; i < propCount; ++i) {
const ASTProperty &prop = astClass.properties.at(i);
- const QString propTypeName = fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), prop.type);
+ const QString propTypeName = fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), typeForMode(prop, SOURCE));
out << QString::fromLatin1(" m_properties[%1] = QtPrivate::qtro_property_index<ObjectType>(&ObjectType::%2, "
"static_cast<%3 (QObject::*)()>(0),\"%2\");")
.arg(QString::number(i+1), prop.name, propTypeName) << endl;
@@ -1058,17 +993,19 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
if (prop.modifier != prop.Constant) { //Make sure we have an onChange signal
out << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>(&ObjectType::%1Changed, static_cast<void (QObject::*)()>(0));")
.arg(prop.name) << endl;
- changeSignals << QString::fromLatin1("%1Changed").arg(prop.name);
+ onChangeProperties << prop;
propertyChangeIndex << i + 1; //m_properties[0] is the count, so index is one higher
}
}
const int signalCount = astClass.signalsList.count();
- const int changedCount = changeSignals.size();
- out << QString::fromLatin1(" m_signals[0] = %1;").arg(signalCount+changeSignals.size()) << endl;
+ const int changedCount = onChangeProperties.size();
+ out << QString::fromLatin1(" m_signals[0] = %1;").arg(signalCount+onChangeProperties.size()) << endl;
for (int i = 0; i < changedCount; ++i)
- out << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::%2, "
- "static_cast<void (QObject::*)()>(0),m_signalArgCount+%4,&m_signalArgTypes[%4]);")
- .arg(i+1).arg(changeSignals.at(i)).arg(i) << endl;
+ out << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::%2Changed, "
+ "static_cast<void (QObject::*)(%3)>(0),m_signalArgCount+%4,&m_signalArgTypes[%4]);")
+ .arg(QString::number(i+1), onChangeProperties.at(i).name,
+ fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), onChangeProperties.at(i).type),
+ QString::number(i)) << endl;
QVector<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList, QStringLiteral("typename ObjectType"));
for (int i = 0; i < signalCount; ++i) {
@@ -1090,8 +1027,10 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
const ASTProperty &prop = pushProps.at(i);
const QString propTypeName = fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), prop.type);
out << QString::fromLatin1(" m_methods[%1] = QtPrivate::qtro_method_index<ObjectType>(&ObjectType::push%2, "
- "static_cast<void (QObject::*)(%3)>(0),\"push%2(%3)\",m_methodArgCount+%4,&m_methodArgTypes[%4]);")
- .arg(QString::number(i+1), cap(prop.name), propTypeName, QString::number(i)) << endl;
+ "static_cast<void (QObject::*)(%3)>(0),\"push%2(%4)\",m_methodArgCount+%5,&m_methodArgTypes[%5]);")
+ .arg(QString::number(i+1), cap(prop.name), propTypeName,
+ QString(propTypeName).remove(QStringLiteral("typename ObjectType::")), // we don't want this in the string signature
+ QString::number(i)) << endl;
}
QVector<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList, QStringLiteral("typename ObjectType"));
@@ -1104,11 +1043,10 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
QString(params).remove(QStringLiteral("typename ObjectType::")), // we don't want this in the string signature
QString::number(i+pushCount)) << endl;
}
- const int modelCount = astClass.models.count();
- for (int i = 0; i < modelCount; ++i) {
- const ASTModel &model = astClass.models.at(i);
- out << QString::fromLatin1(" m_models << ModelInfo({object->%1(),").arg(model.name) << endl;
- out << QString::fromLatin1(" QStringLiteral(\"%1\"),").arg(model.name) << endl;
+ for (const auto &model : astClass.modelMetadata) {
+ const ASTProperty &property = astClass.properties.at(model.propertyIndex);
+ out << QString::fromLatin1(" m_models << ModelInfo({object->%1(),").arg(property.name) << endl;
+ out << QString::fromLatin1(" QStringLiteral(\"%1\"),").arg(property.name) << endl;
QStringList list;
if (!model.roles.isEmpty()) {
for (auto role : model.roles)
@@ -1116,14 +1054,14 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
}
out << QString::fromLatin1(" QByteArrayLiteral(\"%1\")});").arg(list.join(QChar::fromLatin1('|'))) << endl;
}
- const int subclassCount = astClass.children.count();
- for (int i = 0; i < subclassCount; ++i) {
- const ASTChildRep &child = astClass.children.at(i);
- out << QString::fromLatin1(" m_subclasses << SubclassInfo({object->%1(), QStringLiteral(\"%1\")});").arg(child.name) << endl;
+ for (int i : astClass.subClassPropertyIndices) {
+ const ASTProperty &child = astClass.properties.at(i);
+ out << QString::fromLatin1(" m_subclasses << SubclassInfo{object->%1(), QStringLiteral(\"%1\"), new %2SourceAPI<%1_type_t>(object->%1(), QStringLiteral(\"%1\"))};")
+ .arg(child.name, child.type) << endl;
}
out << QStringLiteral(" }") << endl;
out << QStringLiteral("") << endl;
- out << QString::fromLatin1(" QString name() const override { return QStringLiteral(\"%1\"); }").arg(astClass.name) << endl;
+ out << QString::fromLatin1(" QString name() const override { return m_name; }") << endl;
out << QString::fromLatin1(" QString typeName() const override { return QStringLiteral(\"%1\"); }").arg(astClass.name) << endl;
out << QStringLiteral(" int enumCount() const override { return m_enums[0]; }") << endl;
out << QStringLiteral(" int propertyCount() const override { return m_properties[0]; }") << endl;
@@ -1220,7 +1158,8 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
if (signalCount+changedCount > 0) {
out << QStringLiteral(" switch (index) {") << endl;
for (int i = 0; i < changedCount; ++i)
- out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2()\");").arg(i).arg(changeSignals.at(i)) << endl;
+ out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2Changed(%3)\");")
+ .arg(QString::number(i), onChangeProperties.at(i).name, onChangeProperties.at(i).type) << endl;
for (int i = 0; i < signalCount; ++i)
{
const ASTFunction &sig = astClass.signalsList.at(i);
@@ -1310,6 +1249,7 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
out << QString::fromLatin1(" int m_properties[%1];").arg(propCount+1) << endl;
out << QString::fromLatin1(" int m_signals[%1];").arg(signalCount+changedCount+1) << endl;
out << QString::fromLatin1(" int m_methods[%1];").arg(methodCount+1) << endl;
+ out << QString::fromLatin1(" const QString m_name;") << endl;
if (signalCount+changedCount > 0) {
out << QString::fromLatin1(" int m_signalArgCount[%1];").arg(signalCount+changedCount) << endl;
out << QString::fromLatin1(" const int* m_signalArgTypes[%1];").arg(signalCount+changedCount) << endl;
diff --git a/tools/repc/repcodegenerator.h b/tools/repc/repcodegenerator.h
index 18af23c..d7ec4c8 100644
--- a/tools/repc/repcodegenerator.h
+++ b/tools/repc/repcodegenerator.h
@@ -79,6 +79,7 @@ private:
QString formatSignals(const POD &pod);
QString formatDataMembers(const POD &pod);
QString formatMarshallingOperators(const POD &pod);
+ QString typeForMode(const ASTProperty &property, Mode mode);
void generateClass(Mode mode, QTextStream &out, const ASTClass &astClasses, const QString &metaTypeRegistrationCode);
void generateSourceAPI(QTextStream &out, const ASTClass &astClass);