diff options
-rw-r--r-- | src/corelib/kernel/qproperty.h | 25 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp | 8 |
2 files changed, 32 insertions, 1 deletions
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index 8fda7715c2..f853eb8634 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -494,7 +494,7 @@ class QBindableInterfaceForProperty { using T = typename Property::value_type; public: - // interface for read-only properties. Those do not have a binding()/setBinding() method, but one can + // interface for computed properties. Those do not have a binding()/setBinding() method, but one can // install observers on them. static constexpr QBindableInterface iface = { [](const QUntypedPropertyData *d, void *value) -> void @@ -511,6 +511,28 @@ public: }; template<typename Property> +class QBindableInterfaceForProperty<const Property, std::void_t<decltype(std::declval<Property>().binding())>> +{ + using T = typename Property::value_type; +public: + // A bindable created from a const property results in a read-only interface, too. + static constexpr QBindableInterface iface = { + + [](const QUntypedPropertyData *d, void *value) -> void + { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); }, + /*setter=*/nullptr, + [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding + { return static_cast<const Property *>(d)->binding(); }, + /*setBinding=*/nullptr, + [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding + { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); }, + [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void + { observer->setSource(static_cast<const Property *>(d)->bindingData()); }, + []() { return QMetaType::fromType<T>(); } + }; +}; + +template<typename Property> class QBindableInterfaceForProperty<Property, std::void_t<decltype(std::declval<Property>().binding())>> { using T = typename Property::value_type; @@ -553,6 +575,7 @@ public: bool isValid() const { return data != nullptr; } bool isBindable() const { return iface && iface->getBinding; } + bool isReadOnly() const { return !(iface && iface->setBinding && iface->setObserver); } QUntypedPropertyBinding makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) { diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index 4559587afd..7de6458406 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -1048,6 +1048,7 @@ public: } QBindable<int> bindableFoo() { return QBindable<int>(&fooData); } + const QBindable<int> bindableFoo() const { return QBindable<int>(&fooData); } QBindable<int> bindableBar() { return QBindable<int>(&barData); } QBindable<int> bindableRead() { return QBindable<int>(&readData); } QBindable<int> bindableComputed() { return QBindable<int>(&computedData); } @@ -1068,7 +1069,14 @@ public: void tst_QProperty::testNewStuff() { + MyQObject testReadOnly; + testReadOnly.bindableFoo().setBinding([](){return 42;}); + auto bindable = const_cast<const MyQObject&>(testReadOnly).bindableFoo(); + QVERIFY(bindable.hasBinding()); + QVERIFY(bindable.isReadOnly()); + MyQObject object; + QVERIFY(!object.bindableFoo().isReadOnly()); QObject::connect(&object, &MyQObject::fooChanged, &object, &MyQObject::fooHasChanged); QObject::connect(&object, &MyQObject::barChanged, &object, &MyQObject::barHasChanged); |