Bindable property with initialization

Implement Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS and
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS macros.
They allow to directly initialize the property member.

Task-number: QTBUG-85520
Change-Id: I76541d6785bbbf27976b9f0b865fb45be1e9beee
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ivan Solovev 2020-12-11 11:56:48 +01:00
parent f8de5e5402
commit f0668433c4
5 changed files with 151 additions and 2 deletions

View File

@ -68,3 +68,42 @@ private:
Q_OBJECT_BINDABLE_PROPERTY(MyClass, int, xProp, &MyClass::xChanged)
};
//! [0]
//! [1]
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged BINDABLE bindableX)
public:
int x() const { return xProp; }
void setX(int x) { xProp = x; }
QBindable<int> bindableX() { return QBindable<int>(&xProp); }
signals:
void xChanged();
private:
// Declare the instance of int bindable property data and
// initialize it with the value 5.
// This is similar to declaring
// int xProp = 5;
// without using the new QObjectBindableProperty class.
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MyClass, int, xProp, 5, &MyClass::xChanged)
};
//! [1]
//! [2]
class CustomType
{
public:
CustomType(int val, int otherVal) : value(val), anotherValue(otherVal) { }
private:
int value = 0;
int anotherValue = 0;
};
// later when using CustomType as a property
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MyClass, CustomType xProp, CustomType(5, 10),
&MyClass::xChanged)
//! [2]

View File

@ -947,8 +947,22 @@ QString QPropertyBindingError::description() const
\snippet code/src_corelib_kernel_qproperty.cpp 0
If the property does not need a changed notification, you can leave out the "NOFITY xChanged" in the Q_PROPERTY macro as well as the last argument
of the Q_OBJECT_BINDABLE_PROPERTY macro.
If you need to directly initialize the property with some non-default value,
you can use the Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS macro. It accepts a
value for the initialization as one of its parameters.
\snippet code/src_corelib_kernel_qproperty.cpp 1
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS does not support multiple arguments
directly. If your property requires multiple arguments for initialization,
please explicitly call the specific constructor.
\snippet code/src_corelib_kernel_qproperty.cpp 2
If the property does not need a changed notification, you can leave out the
"NOFITY xChanged" in the Q_PROPERTY macro as well as the last argument
of the Q_OBJECT_BINDABLE_PROPERTY and Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS
macros.
*/
/*!

View File

@ -1031,6 +1031,29 @@ private:
#define Q_OBJECT_BINDABLE_PROPERTY(...) QT_OVERLOADED_MACRO(Q_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__)
#define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS4(Class, Type, name, value) \
static constexpr size_t _qt_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF return offsetof(Class, name); \
QT_WARNING_POP \
} \
QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name = \
QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr>( \
value);
#define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS5(Class, Type, name, value, Signal) \
static constexpr size_t _qt_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF return offsetof(Class, name); \
QT_WARNING_POP \
} \
QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name = \
QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal>( \
value);
#define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...) \
QT_OVERLOADED_MACRO(Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__)
template<typename Class, typename T, auto Offset, auto Getter>
class QObjectComputedProperty : public QUntypedPropertyData
{

View File

@ -545,6 +545,15 @@ private:
} \
QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name;
#define Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(Class, Type, name, setter, value) \
static constexpr size_t _qt_property_##name##_offset() \
{ \
QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF return offsetof(Class, name); \
QT_WARNING_POP \
} \
QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter> name = \
QObjectCompatProperty<Class, Type, Class::_qt_property_##name##_offset, setter>( \
value);
QT_END_NAMESPACE

View File

@ -89,6 +89,8 @@ private slots:
void compatPropertyNoDobuleNotification();
void noFakeDependencies();
void bindablePropertyWithInitialization();
};
void tst_QProperty::functorBinding()
@ -1416,6 +1418,68 @@ void tst_QProperty::noFakeDependencies()
QCOMPARE(old, bindingFunctionCalled);
}
struct CustomType
{
CustomType() = default;
CustomType(int val) : value(val) { }
CustomType(int val, int otherVal) : value(val), anotherValue(otherVal) { }
CustomType(const CustomType &) = default;
CustomType(CustomType &&) = default;
~CustomType() = default;
CustomType &operator=(const CustomType &) = default;
CustomType &operator=(CustomType &&) = default;
bool operator==(const CustomType &other) const
{
return (value == other.value) && (anotherValue == other.anotherValue);
}
int value = 0;
int anotherValue = 0;
};
class PropertyWithInitializationTester : public QObject
{
Q_OBJECT
Q_PROPERTY(int prop1 READ prop1 WRITE setProp1 NOTIFY prop1Changed BINDABLE bindableProp1)
Q_PROPERTY(CustomType prop2 READ prop2 WRITE setProp2 BINDABLE bindableProp2)
Q_PROPERTY(CustomType prop3 READ prop3 WRITE setProp3 BINDABLE bindableProp3)
signals:
void prop1Changed();
public:
PropertyWithInitializationTester(QObject *parent = nullptr) : QObject(parent) { }
int prop1() { return prop1Data.value(); }
void setProp1(int i) { prop1Data = i; }
QBindable<int> bindableProp1() { return QBindable<int>(&prop1Data); }
CustomType prop2() { return prop2Data.value(); }
void setProp2(CustomType val) { prop2Data = val; }
QBindable<CustomType> bindableProp2() { return QBindable<CustomType>(&prop2Data); }
CustomType prop3() { return prop3Data.value(); }
void setProp3(CustomType val) { prop3Data = val; }
QBindable<CustomType> bindableProp3() { return QBindable<CustomType>(&prop3Data); }
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(PropertyWithInitializationTester, int, prop1Data, 5,
&PropertyWithInitializationTester::prop1Changed)
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(PropertyWithInitializationTester, CustomType, prop2Data,
CustomType(5))
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(PropertyWithInitializationTester, CustomType, prop3Data,
&PropertyWithInitializationTester::setProp3,
CustomType(10, 20))
};
void tst_QProperty::bindablePropertyWithInitialization()
{
PropertyWithInitializationTester tester;
QCOMPARE(tester.prop1(), 5);
QCOMPARE(tester.prop2().value, 5);
QCOMPARE(tester.prop3().value, 10);
QCOMPARE(tester.prop3().anotherValue, 20);
}
QTEST_MAIN(tst_QProperty);
#include "tst_qproperty.moc"