diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2020-12-11 11:56:48 +0100 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2020-12-17 12:41:13 +0100 |
commit | f0668433c4041a00399eeb29856273fce1389bf3 (patch) | |
tree | 9d45d68221c5b55a137887a166d7d3b00b5d8f84 | |
parent | f8de5e54022b8b7471131b7ad55c83b69b2684c0 (diff) |
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>
-rw-r--r-- | src/corelib/doc/snippets/code/src_corelib_kernel_qproperty.cpp | 39 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty.cpp | 18 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty.h | 23 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 9 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp | 64 |
5 files changed, 151 insertions, 2 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qproperty.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qproperty.cpp index ed5df6eb86..4cb7c1c0ce 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qproperty.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qproperty.cpp @@ -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] diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 1fd5951675..20efbaa1aa 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -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. */ /*! diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index b6653c0411..d7d4593c09 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -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 { diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index 13bd40fad7..f7792c1b5a 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -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 diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index ca2de478cf..2ff32d0d1a 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -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" |