Add support for exposing public QProperty members in the meta-object system
At the moment this makes the type as well as the setter/getter available through the meta-call as well as the ability to register observers and bindings. Only QProperty members that are annotated with Q_PROPERTY(type name) are made public through the meta-object. Change-Id: I16b98fd318122c722b85ce61e39975284e0c2404 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>bb10
parent
b5f6a85d27
commit
d4f0445331
|
|
@ -3505,6 +3505,21 @@ bool QMetaProperty::isRequired() const
|
|||
return flags & Required;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.0
|
||||
Returns \c true if the property is implemented using a QProperty member; otherwise returns \c false.
|
||||
|
||||
This can be used to detect the availability of QProperty related meta-call types ahead of
|
||||
performing the call itself.
|
||||
*/
|
||||
bool QMetaProperty::isQProperty() const
|
||||
{
|
||||
if (!mobj)
|
||||
return false;
|
||||
int flags = mobj->d.data[handle + 2];
|
||||
return flags & IsQProperty;
|
||||
}
|
||||
|
||||
/*!
|
||||
\obsolete
|
||||
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ public:
|
|||
bool isConstant() const;
|
||||
bool isFinal() const;
|
||||
bool isRequired() const;
|
||||
bool isQProperty() const;
|
||||
|
||||
bool isFlagType() const;
|
||||
bool isEnumType() const;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ enum PropertyFlags {
|
|||
Notify = 0x00400000,
|
||||
Revisioned = 0x00800000,
|
||||
Required = 0x01000000,
|
||||
IsQProperty = 0x02000000
|
||||
};
|
||||
|
||||
enum MethodFlags {
|
||||
|
|
|
|||
|
|
@ -390,7 +390,9 @@ struct Q_CORE_EXPORT QMetaObject
|
|||
CreateInstance,
|
||||
IndexOfMethod,
|
||||
RegisterPropertyMetaType,
|
||||
RegisterMethodArgumentMetaType
|
||||
RegisterMethodArgumentMetaType,
|
||||
RegisterQPropertyObserver,
|
||||
SetQPropertyBinding
|
||||
};
|
||||
|
||||
int static_metacall(Call, int, void **) const;
|
||||
|
|
|
|||
|
|
@ -869,6 +869,9 @@ void Generator::generateProperties()
|
|||
if (p.required)
|
||||
flags |= Required;
|
||||
|
||||
if (p.isQProperty)
|
||||
flags |= IsQProperty;
|
||||
|
||||
fprintf(out, " %4d, ", stridx(p.name));
|
||||
generateTypeInfo(p.type);
|
||||
fprintf(out, ", 0x%.8x,\n", flags);
|
||||
|
|
@ -1017,7 +1020,9 @@ void Generator::generateMetacall()
|
|||
fprintf(out, "else ");
|
||||
fprintf(out,
|
||||
"if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n"
|
||||
" || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {\n"
|
||||
" || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType\n"
|
||||
" || _c == QMetaObject::RegisterQPropertyObserver\n"
|
||||
" || _c == QMetaObject::SetQPropertyBinding) {\n"
|
||||
" qt_static_metacall(this, _c, _id, _a);\n"
|
||||
" _id -= %d;\n }", cdef->propertyList.count());
|
||||
|
||||
|
|
@ -1354,6 +1359,7 @@ void Generator::generateStaticMetacall()
|
|||
bool needTempVarForGet = false;
|
||||
bool needSet = false;
|
||||
bool needReset = false;
|
||||
bool haveQProperties = false;
|
||||
for (int i = 0; i < cdef->propertyList.size(); ++i) {
|
||||
const PropertyDef &p = cdef->propertyList.at(i);
|
||||
needGet |= !p.read.isEmpty() || !p.member.isEmpty();
|
||||
|
|
@ -1363,13 +1369,15 @@ void Generator::generateStaticMetacall()
|
|||
|
||||
needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant);
|
||||
needReset |= !p.reset.isEmpty();
|
||||
haveQProperties |= p.isQProperty;
|
||||
}
|
||||
fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
|
||||
|
||||
if (needElse)
|
||||
fprintf(out, "else ");
|
||||
fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n");
|
||||
if (needGet) {
|
||||
|
||||
auto setupMemberAccess = [this]() {
|
||||
if (cdef->hasQObject) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
|
||||
|
|
@ -1379,6 +1387,10 @@ void Generator::generateStaticMetacall()
|
|||
fprintf(out, " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData());
|
||||
}
|
||||
fprintf(out, " Q_UNUSED(_t)\n");
|
||||
};
|
||||
|
||||
if (needGet) {
|
||||
setupMemberAccess();
|
||||
if (needTempVarForGet)
|
||||
fprintf(out, " void *_v = _a[0];\n");
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
|
|
@ -1416,15 +1428,7 @@ void Generator::generateStaticMetacall()
|
|||
fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n");
|
||||
|
||||
if (needSet) {
|
||||
if (cdef->hasQObject) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
|
||||
#endif
|
||||
fprintf(out, " auto *_t = static_cast<%s *>(_o);\n", cdef->classname.constData());
|
||||
} else {
|
||||
fprintf(out, " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData());
|
||||
}
|
||||
fprintf(out, " Q_UNUSED(_t)\n");
|
||||
setupMemberAccess();
|
||||
fprintf(out, " void *_v = _a[0];\n");
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
||||
|
|
@ -1472,15 +1476,7 @@ void Generator::generateStaticMetacall()
|
|||
fprintf(out, " else ");
|
||||
fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n");
|
||||
if (needReset) {
|
||||
if (cdef->hasQObject) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
|
||||
#endif
|
||||
fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
|
||||
} else {
|
||||
fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
|
||||
}
|
||||
fprintf(out, " Q_UNUSED(_t)\n");
|
||||
setupMemberAccess();
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
||||
const PropertyDef &p = cdef->propertyList.at(propindex);
|
||||
|
|
@ -1497,6 +1493,42 @@ void Generator::generateStaticMetacall()
|
|||
fprintf(out, " }\n");
|
||||
}
|
||||
fprintf(out, " }");
|
||||
|
||||
fprintf(out, " else ");
|
||||
fprintf(out, "if (_c == QMetaObject::RegisterQPropertyObserver) {\n");
|
||||
if (haveQProperties) {
|
||||
setupMemberAccess();
|
||||
fprintf(out, " QPropertyObserver *observer = reinterpret_cast<QPropertyObserver *>(_a[0]);\n");
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
||||
const PropertyDef &p = cdef->propertyList.at(propindex);
|
||||
if (!p.isQProperty)
|
||||
continue;
|
||||
fprintf(out, " case %d: observer->setSource(_t->%s); break;\n",
|
||||
propindex, p.name.constData());
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
}
|
||||
fprintf(out, " }");
|
||||
|
||||
fprintf(out, " else ");
|
||||
fprintf(out, "if (_c == QMetaObject::SetQPropertyBinding) {\n");
|
||||
if (haveQProperties) {
|
||||
setupMemberAccess();
|
||||
fprintf(out, " switch (_id) {\n");
|
||||
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
|
||||
const PropertyDef &p = cdef->propertyList.at(propindex);
|
||||
if (!p.isQProperty)
|
||||
continue;
|
||||
fprintf(out, " case %d: _t->%s.setBinding(*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
|
||||
propindex, p.name.constData(), p.type.constData());
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
}
|
||||
fprintf(out, " }");
|
||||
|
||||
fprintf(out, "\n#endif // QT_NO_PROPERTIES");
|
||||
needElse = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,6 +564,32 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Try to parse QProperty<MyType> propertName; members
|
||||
bool Moc::parseMaybeQProperty(ClassDef *def)
|
||||
{
|
||||
if (!test(IDENTIFIER))
|
||||
return false;
|
||||
|
||||
if (lexem() != "QProperty")
|
||||
return false;
|
||||
|
||||
if (!test(LANGLE))
|
||||
return false;
|
||||
|
||||
until(RANGLE);
|
||||
|
||||
next();
|
||||
const auto propName = lexem();
|
||||
|
||||
if (!test(SEMIC))
|
||||
return false;
|
||||
|
||||
def->qPropertyMembers.insert(propName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Moc::parse()
|
||||
{
|
||||
QVector<NamespaceDef> namespaceList;
|
||||
|
|
@ -909,7 +935,9 @@ void Moc::parse()
|
|||
}
|
||||
}
|
||||
} else {
|
||||
index = rewind;
|
||||
index = rewind - 1;
|
||||
if (!parseMaybeQProperty(&def))
|
||||
index = rewind;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1198,11 +1226,14 @@ void Moc::parseSignals(ClassDef *def)
|
|||
|
||||
void Moc::createPropertyDef(PropertyDef &propDef)
|
||||
{
|
||||
propDef.location = index;
|
||||
|
||||
QByteArray type = parseType().name;
|
||||
if (type.isEmpty())
|
||||
error();
|
||||
propDef.designable = propDef.scriptable = propDef.stored = "true";
|
||||
propDef.user = "false";
|
||||
|
||||
/*
|
||||
The Q_PROPERTY construct cannot contain any commas, since
|
||||
commas separate macro arguments. We therefore expect users
|
||||
|
|
@ -1234,6 +1265,17 @@ void Moc::createPropertyDef(PropertyDef &propDef)
|
|||
|
||||
next();
|
||||
propDef.name = lexem();
|
||||
|
||||
// Could be Q_PROPERTY(type field) and later QProperty<int> field; -- to be resolved later.
|
||||
if (lookup() == RPAREN) {
|
||||
propDef.isQProperty = true;
|
||||
propDef.designable = propDef.scriptable = propDef.stored = "true";
|
||||
propDef.user = "false";
|
||||
propDef.read = propDef.name + ".value";
|
||||
propDef.write = propDef.name + ".setValue";
|
||||
return;
|
||||
}
|
||||
|
||||
while (test(IDENTIFIER)) {
|
||||
const QByteArray l = lexem();
|
||||
if (l[0] == 'C' && l == "CONSTANT") {
|
||||
|
|
@ -1320,11 +1362,6 @@ void Moc::createPropertyDef(PropertyDef &propDef)
|
|||
error(2);
|
||||
}
|
||||
}
|
||||
if (propDef.read.isNull() && propDef.member.isNull()) {
|
||||
const QByteArray msg = "Property declaration " + propDef.name
|
||||
+ " has no READ accessor function or associated MEMBER variable. The property will be invalid.";
|
||||
warning(msg.constData());
|
||||
}
|
||||
if (propDef.constant && !propDef.write.isNull()) {
|
||||
const QByteArray msg = "Property declaration " + propDef.name
|
||||
+ " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
|
||||
|
|
@ -1777,6 +1814,25 @@ void Moc::checkProperties(ClassDef *cdef)
|
|||
}
|
||||
definedProperties.insert(p.name);
|
||||
|
||||
const auto skipProperty = [&](const QByteArray &msg) {
|
||||
const int rewind = index;
|
||||
if (p.location >= 0)
|
||||
index = p.location;
|
||||
warning(msg.constData());
|
||||
index = rewind;
|
||||
cdef->propertyList.removeAt(i);
|
||||
--i;
|
||||
};
|
||||
|
||||
if (p.isQProperty) {
|
||||
if (!cdef->qPropertyMembers.contains(p.name)) {
|
||||
QByteArray msg = "Property declaration " + p.name + " has neither an associated QProperty<> member"
|
||||
", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
|
||||
skipProperty(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < cdef->publicList.count(); ++j) {
|
||||
const FunctionDef &f = cdef->publicList.at(j);
|
||||
if (f.name != p.read)
|
||||
|
|
@ -1989,6 +2045,7 @@ QJsonObject PropertyDef::toJson() const
|
|||
prop[QLatin1String("constant")] = constant;
|
||||
prop[QLatin1String("final")] = final;
|
||||
prop[QLatin1String("required")] = required;
|
||||
prop[QLatin1String("isQProperty")] = isQProperty;
|
||||
|
||||
if (revision > 0)
|
||||
prop[QLatin1String("revision")] = revision;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,9 @@ struct PropertyDef
|
|||
bool constant = false;
|
||||
bool final = false;
|
||||
bool required = false;
|
||||
bool isQProperty = false;
|
||||
|
||||
int location = -1; // token index, used for error reporting
|
||||
|
||||
QJsonObject toJson() const;
|
||||
};
|
||||
|
|
@ -188,6 +191,7 @@ struct ClassDef : BaseDef {
|
|||
QVector<FunctionDef> signalList, slotList, methodList, publicList;
|
||||
QVector<QByteArray> nonClassSignalList;
|
||||
QVector<PropertyDef> propertyList;
|
||||
QSet<QByteArray> qPropertyMembers;
|
||||
int notifyableProperties = 0;
|
||||
int revisionedMethods = 0;
|
||||
int revisionedProperties = 0;
|
||||
|
|
@ -247,6 +251,7 @@ public:
|
|||
|
||||
bool parseFunction(FunctionDef *def, bool inMacro = false);
|
||||
bool parseMaybeFunction(const ClassDef *cdef, FunctionDef *def);
|
||||
bool parseMaybeQProperty(ClassDef *def);
|
||||
|
||||
void parseSlots(ClassDef *def, FunctionDef::Access access);
|
||||
void parseSignals(ClassDef *def);
|
||||
|
|
|
|||
|
|
@ -1046,6 +1046,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "prop1",
|
||||
"read": "getProp1",
|
||||
"required": false,
|
||||
|
|
@ -1059,6 +1060,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "prop2",
|
||||
"read": "getProp2",
|
||||
"required": false,
|
||||
|
|
@ -1072,6 +1074,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "prop3",
|
||||
"read": "getProp3",
|
||||
"required": false,
|
||||
|
|
@ -1184,6 +1187,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "flags",
|
||||
"read": "flags",
|
||||
"required": false,
|
||||
|
|
@ -1210,6 +1214,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "flags",
|
||||
"read": "flags",
|
||||
"required": false,
|
||||
|
|
@ -1223,6 +1228,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "flagsList",
|
||||
"read": "flagsList",
|
||||
"required": false,
|
||||
|
|
@ -1747,6 +1753,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "blah",
|
||||
"read": "blah",
|
||||
"required": false,
|
||||
|
|
@ -1799,6 +1806,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "blah",
|
||||
"read": "blah",
|
||||
"required": false,
|
||||
|
|
@ -1974,6 +1982,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "gadgetPoperty",
|
||||
"read": "gadgetPoperty",
|
||||
"required": false,
|
||||
|
|
@ -1986,6 +1995,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "objectPoperty",
|
||||
"read": "objectPoperty",
|
||||
"required": false,
|
||||
|
|
@ -2011,6 +2021,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "nestedGadgetPoperty",
|
||||
"read": "nestedGadgetPoperty",
|
||||
"required": false,
|
||||
|
|
@ -2036,6 +2047,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "nestedObjectPoperty",
|
||||
"read": "nestedObjectPoperty",
|
||||
"required": false,
|
||||
|
|
@ -2169,6 +2181,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "gadgetPoperty",
|
||||
"read": "gadgetPoperty",
|
||||
"required": false,
|
||||
|
|
@ -2181,6 +2194,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "objectPoperty",
|
||||
"read": "objectPoperty",
|
||||
"required": false,
|
||||
|
|
@ -2206,6 +2220,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "nestedGadgetPoperty",
|
||||
"read": "nestedGadgetPoperty",
|
||||
"required": false,
|
||||
|
|
@ -2231,6 +2246,7 @@
|
|||
"constant": false,
|
||||
"designable": true,
|
||||
"final": false,
|
||||
"isQProperty": false,
|
||||
"name": "nestedObjectPoperty",
|
||||
"read": "nestedObjectPoperty",
|
||||
"required": false,
|
||||
|
|
|
|||
|
|
@ -723,6 +723,9 @@ private slots:
|
|||
void mocJsonOutput();
|
||||
void mocInclude();
|
||||
void requiredProperties();
|
||||
void qpropertyMembers();
|
||||
void observerMetaCall();
|
||||
void setQPRopertyBinding();
|
||||
|
||||
signals:
|
||||
void sigWithUnsignedArg(unsigned foo);
|
||||
|
|
@ -1603,7 +1606,7 @@ void tst_Moc::warnOnPropertyWithoutREAD()
|
|||
QVERIFY(!mocOut.isEmpty());
|
||||
QString mocWarning = QString::fromLocal8Bit(proc.readAllStandardError());
|
||||
QCOMPARE(mocWarning, header +
|
||||
QString(":36: Warning: Property declaration foo has no READ accessor function or associated MEMBER variable. The property will be invalid.\n"));
|
||||
QString(":36: Warning: Property declaration foo has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.\n"));
|
||||
#else
|
||||
QSKIP("Only tested on linux/gcc");
|
||||
#endif
|
||||
|
|
@ -2087,7 +2090,7 @@ void tst_Moc::warnings_data()
|
|||
<< QStringList()
|
||||
<< 0
|
||||
<< QString("IGNORE_ALL_STDOUT")
|
||||
<< QString("standard input:1: Warning: Property declaration x has no READ accessor function or associated MEMBER variable. The property will be invalid.");
|
||||
<< QString("standard input:1: Warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.");
|
||||
|
||||
// This should output a warning
|
||||
QTest::newRow("Duplicate property warning")
|
||||
|
|
@ -2103,7 +2106,7 @@ void tst_Moc::warnings_data()
|
|||
<< (QStringList() << "-nn")
|
||||
<< 0
|
||||
<< QString("IGNORE_ALL_STDOUT")
|
||||
<< QString("standard input:1: Warning: Property declaration x has no READ accessor function or associated MEMBER variable. The property will be invalid.");
|
||||
<< QString("standard input:1: Warning: Property declaration x has neither an associated QProperty<> member, nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.");
|
||||
|
||||
// Passing "-nw" should suppress the warning
|
||||
QTest::newRow("Invalid property warning with -nw")
|
||||
|
|
@ -4100,6 +4103,104 @@ void tst_Moc::requiredProperties()
|
|||
QVERIFY(!notRequired.isRequired());
|
||||
}
|
||||
|
||||
class ClassWithQPropertyMembers : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int publicProperty)
|
||||
Q_PROPERTY(int privateExposedProperty)
|
||||
public:
|
||||
|
||||
QProperty<int> publicProperty;
|
||||
QProperty<int> notExposed;
|
||||
|
||||
protected:
|
||||
QProperty<int> protectedProperty;
|
||||
|
||||
private:
|
||||
QProperty<int> privateProperty;
|
||||
QProperty<int> privateExposedProperty;
|
||||
};
|
||||
|
||||
void tst_Moc::qpropertyMembers()
|
||||
{
|
||||
const auto metaObject = &ClassWithQPropertyMembers::staticMetaObject;
|
||||
|
||||
QCOMPARE(metaObject->propertyCount() - metaObject->superClass()->propertyCount(), 2);
|
||||
|
||||
QCOMPARE(metaObject->indexOfProperty("notExposed"), -1);
|
||||
|
||||
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("publicProperty"));
|
||||
QVERIFY(prop.isValid());
|
||||
|
||||
QVERIFY(metaObject->property(metaObject->indexOfProperty("privateExposedProperty")).isValid());
|
||||
|
||||
ClassWithQPropertyMembers instance;
|
||||
|
||||
prop.write(&instance, 42);
|
||||
QCOMPARE(instance.publicProperty.value(), 42);
|
||||
|
||||
instance.publicProperty.setValue(100);
|
||||
QCOMPARE(prop.read(&instance).toInt(), 100);
|
||||
|
||||
QCOMPARE(prop.metaType(), QMetaType(QMetaType::Int));
|
||||
|
||||
QVERIFY(!prop.notifySignal().isValid());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tst_Moc::observerMetaCall()
|
||||
{
|
||||
const auto metaObject = &ClassWithQPropertyMembers::staticMetaObject;
|
||||
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("publicProperty"));
|
||||
QVERIFY(prop.isValid());
|
||||
|
||||
ClassWithQPropertyMembers instance;
|
||||
|
||||
int observerCallCount = 0;
|
||||
|
||||
QProperty<int> dummy;
|
||||
auto handler = dummy.onValueChanged([&observerCallCount]() {
|
||||
++observerCallCount;
|
||||
});
|
||||
|
||||
{
|
||||
void *argv[] = { &handler };
|
||||
instance.qt_metacall(QMetaObject::RegisterQPropertyObserver, prop.propertyIndex(), argv);
|
||||
}
|
||||
|
||||
instance.publicProperty.setValue(100);
|
||||
QCOMPARE(observerCallCount, 1);
|
||||
instance.publicProperty.setValue(101);
|
||||
QCOMPARE(observerCallCount, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tst_Moc::setQPRopertyBinding()
|
||||
{
|
||||
const auto metaObject = &ClassWithQPropertyMembers::staticMetaObject;
|
||||
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("publicProperty"));
|
||||
QVERIFY(prop.isValid());
|
||||
|
||||
ClassWithQPropertyMembers instance;
|
||||
|
||||
bool bindingCalled = false;
|
||||
auto binding = Qt::makePropertyBinding([&bindingCalled]() {
|
||||
bindingCalled = true;
|
||||
return 42;
|
||||
});
|
||||
|
||||
{
|
||||
void *argv[] = { &binding };
|
||||
instance.qt_metacall(QMetaObject::SetQPropertyBinding, prop.propertyIndex(), argv);
|
||||
}
|
||||
QVERIFY(!bindingCalled); // not yet!
|
||||
|
||||
QCOMPARE(instance.publicProperty.value(), 42);
|
||||
QVERIFY(bindingCalled); // but now it should've been called :)
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_Moc)
|
||||
|
||||
// the generated code must compile with QT_NO_KEYWORDS
|
||||
|
|
|
|||
Loading…
Reference in New Issue