Allow declaring QProperty<> based Q_PROPERTYies with a notify signal
This requires mostly making moc a bit more permissive, which has the advantage that it also simplifies the code a little bit. The newly added test case demonstrates how to connect such a property with a change signal. One test case needed to be changed regarding the callback as the publicProperty member now has a (permanent) observer and therefore re-assigning the binding will re-evaluate it as the value might have changed. Change-Id: Ia7edcec432de830bdd4e07d943c5d4550c175ca4 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
parent
0bfbe10ff2
commit
5422fb7948
@ -1266,16 +1266,6 @@ 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") {
|
||||
@ -1806,31 +1796,32 @@ void Moc::checkProperties(ClassDef *cdef)
|
||||
QSet<QByteArray> definedProperties;
|
||||
for (int i = 0; i < cdef->propertyList.count(); ++i) {
|
||||
PropertyDef &p = cdef->propertyList[i];
|
||||
if (p.read.isEmpty() && p.member.isEmpty())
|
||||
continue;
|
||||
if (definedProperties.contains(p.name)) {
|
||||
QByteArray msg = "The property '" + p.name + "' is defined multiple times in class " + cdef->classname + ".";
|
||||
warning(msg.constData());
|
||||
}
|
||||
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 (p.read.isEmpty() && p.member.isEmpty()) {
|
||||
if (!cdef->qPropertyMembers.contains(p.name)) {
|
||||
const int rewind = index;
|
||||
if (p.location >= 0)
|
||||
index = p.location;
|
||||
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;
|
||||
", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
|
||||
warning(msg.constData());
|
||||
index = rewind;
|
||||
if (p.write.isEmpty()) {
|
||||
cdef->propertyList.removeAt(i);
|
||||
--i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
p.read = p.name + ".value";
|
||||
p.write = p.name + ".setValue";
|
||||
p.isQProperty = true;
|
||||
p.designable = p.scriptable = p.stored = "true";
|
||||
p.user = "false";
|
||||
}
|
||||
|
||||
for (int j = 0; j < cdef->publicList.count(); ++j) {
|
||||
|
@ -4106,19 +4106,23 @@ void tst_Moc::requiredProperties()
|
||||
class ClassWithQPropertyMembers : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int publicProperty)
|
||||
Q_PROPERTY(int publicProperty NOTIFY publicPropertyChanged)
|
||||
Q_PROPERTY(int privateExposedProperty)
|
||||
public:
|
||||
|
||||
QProperty<int> publicProperty;
|
||||
QProperty<int> notExposed;
|
||||
|
||||
signals:
|
||||
void publicPropertyChanged();
|
||||
|
||||
protected:
|
||||
QProperty<int> protectedProperty;
|
||||
|
||||
private:
|
||||
QProperty<int> privateProperty;
|
||||
QProperty<int> privateExposedProperty;
|
||||
QPropertyMemberChangeHandler<&ClassWithQPropertyMembers::publicProperty, &ClassWithQPropertyMembers::publicPropertyChanged> connector{this};
|
||||
};
|
||||
|
||||
void tst_Moc::qpropertyMembers()
|
||||
@ -4139,12 +4143,15 @@ void tst_Moc::qpropertyMembers()
|
||||
prop.write(&instance, 42);
|
||||
QCOMPARE(instance.publicProperty.value(), 42);
|
||||
|
||||
QSignalSpy publicPropertySpy(&instance, SIGNAL(publicPropertyChanged()));
|
||||
|
||||
instance.publicProperty.setValue(100);
|
||||
QCOMPARE(prop.read(&instance).toInt(), 100);
|
||||
QCOMPARE(publicPropertySpy.count(), 1);
|
||||
|
||||
QCOMPARE(prop.metaType(), QMetaType(QMetaType::Int));
|
||||
|
||||
QVERIFY(!prop.notifySignal().isValid());
|
||||
QVERIFY(prop.notifySignal().isValid());
|
||||
}
|
||||
|
||||
|
||||
@ -4195,7 +4202,6 @@ void tst_Moc::setQPRopertyBinding()
|
||||
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 :)
|
||||
|
Loading…
Reference in New Issue
Block a user