summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qproperty.h25
-rw-r--r--tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp8
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);