QBindable: Improve read-only support
If we create a QBindable from a const property, we should obtain a read-only interface. Besides implementing this feature, this patch adds a isReadOnly method to Q(Untyped)Bindable which can be used to check whether one can modify the property via the bindable interface. Task-number: QTBUG-89505 Task-number: QTBUG-89469 Change-Id: Ic36949a5b84c5119e0060ed0a1cf4ac94a66f341 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
9f894788dd
commit
240505457b
@ -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
|
||||
@ -510,6 +510,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())>>
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user