diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2021-06-17 12:33:54 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2021-06-17 19:32:56 +0200 |
commit | 6b36e783521993df8de6477c789aa26c38803656 (patch) | |
tree | 72a0e60c5e65742271c564d1cb4d11d54910daca /src | |
parent | 8aee7c6b29be5a0ee7d5e7cfcb5f2db762b2e28b (diff) |
QBindable: Use setter in setValue for QObjectCompatProperty
Directly writing to the underlying property storage has the potential of
breaking all kinds of internal invariants. As we return QBindable in
the public interface, we should not grant callers access to the
internals of the object.
Pick-to: 6.2 6.1
Change-Id: I737ff293b9d921b7de861da5ae23356c17690b78
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index e92c8f878a..2883308299 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -396,6 +396,9 @@ namespace QtPrivate { template<typename Class, typename T, auto Offset, auto Setter, auto Signal=nullptr> class QObjectCompatProperty : public QPropertyData<T> { + template<typename Property, typename> + friend class QtPrivate::QBindableInterfaceForProperty; + using ThisType = QObjectCompatProperty<Class, T, Offset, Setter, Signal>; using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>; Class *owner() @@ -408,6 +411,7 @@ class QObjectCompatProperty : public QPropertyData<T> char *that = const_cast<char *>(reinterpret_cast<const char *>(this)); return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset)); } + static bool bindingWrapper(QMetaType type, QUntypedPropertyData *dataPtr, QtPrivate::QPropertyBindingFunction binding) { auto *thisData = static_cast<ThisType *>(dataPtr); @@ -591,6 +595,33 @@ private: } }; +namespace QtPrivate { +template<typename Class, typename Ty, auto Offset, auto Setter, auto Signal> +class QBindableInterfaceForProperty<QObjectCompatProperty<Class, Ty, Offset, Setter, Signal>, std::void_t<Class>> +{ + using Property = QObjectCompatProperty<Class, Ty, Offset, Setter, Signal>; + using T = typename Property::value_type; +public: + static constexpr QBindableInterface iface = { + [](const QUntypedPropertyData *d, void *value) -> void + { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); }, + [](QUntypedPropertyData *d, const void *value) -> void + { + (static_cast<Property *>(d)->owner()->*Setter)(*static_cast<const T*>(value)); + }, + [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding + { return static_cast<const Property *>(d)->binding(); }, + [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding + { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); }, + [](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>(); } + }; +}; +} + #define QT_OBJECT_COMPAT_PROPERTY_4(Class, Type, name, setter) \ static constexpr size_t _qt_property_##name##_offset() { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ |