Revision control
++ // Copyright (C) 2020 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #ifndef QPROPERTY_H
++ #define QPROPERTY_H
++
++ #include <QtCore/qglobal.h>
++ #include <QtCore/qshareddata.h>
++ #include <QtCore/qstring.h>
++ #include <QtCore/qttypetraits.h>
++ #include <QtCore/qbindingstorage.h>
++
++ #include <type_traits>
++
++ #include <QtCore/qpropertyprivate.h>
++
++ #if __has_include(<source_location>) && __cplusplus >= 202002L && !defined(Q_QDOC)
++ #include <source_location>
++ #if defined(__cpp_lib_source_location)
++ #define QT_SOURCE_LOCATION_NAMESPACE std
++ #define QT_PROPERTY_COLLECT_BINDING_LOCATION
++ #if defined(Q_CC_MSVC)
++ /* MSVC runs into an issue with constexpr with source location (error C7595)
++ so use the factory function as a workaround */
++ # define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation::fromStdSourceLocation(std::source_location::current())
++ #else
++ /* some versions of gcc in turn run into
++ expression ‘std::source_location::current()’ is not a constant expression
++ so don't use the workaround there */
++ # define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current())
++ #endif
++ #endif
++ #endif
++
++ #if __has_include(<experimental/source_location>) && !defined(Q_QDOC)
++ #include <experimental/source_location>
++ #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)
++ #if defined(__cpp_lib_experimental_source_location)
++ #define QT_SOURCE_LOCATION_NAMESPACE std::experimental
++ #define QT_PROPERTY_COLLECT_BINDING_LOCATION
++ #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::experimental::source_location::current())
++ #endif // defined(__cpp_lib_experimental_source_location)
++ #endif
++ #endif
++
++ #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)
++ #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation()
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++ namespace Qt {
++ Q_CORE_EXPORT void beginPropertyUpdateGroup();
++ Q_CORE_EXPORT void endPropertyUpdateGroup();
++ }
++
++ class QScopedPropertyUpdateGroup
++ {
++ Q_DISABLE_COPY_MOVE(QScopedPropertyUpdateGroup)
++ public:
++ Q_NODISCARD_CTOR
++ QScopedPropertyUpdateGroup()
++ { Qt::beginPropertyUpdateGroup(); }
++ ~QScopedPropertyUpdateGroup() noexcept(false)
++ { Qt::endPropertyUpdateGroup(); }
++ };
++
++ template <typename T>
++ class QPropertyData : public QUntypedPropertyData
++ {
++ protected:
++ mutable T val = T();
++ private:
++ class DisableRValueRefs {};
++ protected:
++ static constexpr bool UseReferences = !(std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>);
++ public:
++ using value_type = T;
++ using parameter_type = std::conditional_t<UseReferences, const T &, T>;
++ using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>;
++ using arrow_operator_result = std::conditional_t<std::is_pointer_v<T>, const T &,
++ std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, const T &, void>>;
++
++ QPropertyData() = default;
++ QPropertyData(parameter_type t) : val(t) {}
++ QPropertyData(rvalue_ref t) : val(std::move(t)) {}
++ ~QPropertyData() = default;
++
++ parameter_type valueBypassingBindings() const { return val; }
++ void setValueBypassingBindings(parameter_type v) { val = v; }
++ void setValueBypassingBindings(rvalue_ref v) { val = std::move(v); }
++ };
++
++ // ### Qt 7: un-export
++ struct Q_CORE_EXPORT QPropertyBindingSourceLocation
++ {
++ const char *fileName = nullptr;
++ const char *functionName = nullptr;
++ quint32 line = 0;
++ quint32 column = 0;
++ QPropertyBindingSourceLocation() = default;
++ #ifdef __cpp_lib_source_location
++ constexpr QPropertyBindingSourceLocation(const std::source_location &cppLocation)
++ {
++ fileName = cppLocation.file_name();
++ functionName = cppLocation.function_name();
++ line = cppLocation.line();
++ column = cppLocation.column();
++ }
++ QT_POST_CXX17_API_IN_EXPORTED_CLASS
++ static consteval QPropertyBindingSourceLocation
++ fromStdSourceLocation(const std::source_location &cppLocation)
++ {
++ return cppLocation;
++ }
++ #endif
++ #ifdef __cpp_lib_experimental_source_location
++ constexpr QPropertyBindingSourceLocation(const std::experimental::source_location &cppLocation)
++ {
++ fileName = cppLocation.file_name();
++ functionName = cppLocation.function_name();
++ line = cppLocation.line();
++ column = cppLocation.column();
++ }
++ #endif
++ };
++
++ template <typename Functor> class QPropertyChangeHandler;
++ class QPropertyBindingErrorPrivate;
++
++ class Q_CORE_EXPORT QPropertyBindingError
++ {
++ public:
++ enum Type {
++ NoError,
++ BindingLoop,
++ EvaluationError,
++ UnknownError
++ };
++
++ QPropertyBindingError();
++ QPropertyBindingError(Type type, const QString &description = QString());
++
++ QPropertyBindingError(const QPropertyBindingError &other);
++ QPropertyBindingError &operator=(const QPropertyBindingError &other);
++ QPropertyBindingError(QPropertyBindingError &&other);
++ QPropertyBindingError &operator=(QPropertyBindingError &&other);
++ ~QPropertyBindingError();
++
++ bool hasError() const { return d.get() != nullptr; }
++ Type type() const;
++ QString description() const;
++
++ private:
++ QSharedDataPointer<QPropertyBindingErrorPrivate> d;
++ };
++
++ class Q_CORE_EXPORT QUntypedPropertyBinding
++ {
++ public:
++ // writes binding result into dataPtr
++ using BindingFunctionVTable = QtPrivate::BindingFunctionVTable;
++
++ QUntypedPropertyBinding();
++ QUntypedPropertyBinding(QMetaType metaType, const BindingFunctionVTable *vtable, void *function, const QPropertyBindingSourceLocation &location);
++
++ template<typename Functor>
++ QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
++ : QUntypedPropertyBinding(metaType, &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>>, &f, location)
++ {}
++
++ QUntypedPropertyBinding(QUntypedPropertyBinding &&other);
++ QUntypedPropertyBinding(const QUntypedPropertyBinding &other);
++ QUntypedPropertyBinding &operator=(const QUntypedPropertyBinding &other);
++ QUntypedPropertyBinding &operator=(QUntypedPropertyBinding &&other);
++ ~QUntypedPropertyBinding();
++
++ bool isNull() const;
++
++ QPropertyBindingError error() const;
++
++ QMetaType valueMetaType() const;
++
++ #if QT_CORE_REMOVED_SINCE(6, 12)
++ explicit QUntypedPropertyBinding(QPropertyBindingPrivate *priv);
++ #endif
++ private:
++ // the following public classes access this constructor from inline code
++ template<typename Class, typename T, auto Offset, auto Signal> friend class QObjectBindableProperty;
++ template<typename T> friend class QBindable;
++ template<typename T> friend class QProperty;
++ explicit QUntypedPropertyBinding(void *priv);
++ private:
++ friend class QtPrivate::QPropertyBindingData;
++ friend class QPropertyBindingPrivate;
++ template <typename> friend class QPropertyBinding;
++ QPropertyBindingPrivatePtr d;
++ };
++
++ template <typename PropertyType>
++ class QPropertyBinding : public QUntypedPropertyBinding
++ {
++
++ public:
++ QPropertyBinding() = default;
++
++ template<typename Functor>
++ QPropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location)
++ : QUntypedPropertyBinding(QMetaType::fromType<PropertyType>(), &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>, PropertyType>, &f, location)
++ {}
++
++
++ // Internal
++ explicit QPropertyBinding(const QUntypedPropertyBinding &binding)
++ : QUntypedPropertyBinding(binding)
++ {}
++ };
++
++ namespace Qt {
++ template <typename Functor>
++ auto makePropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
++ {
++ return QPropertyBinding<std::invoke_result_t<Functor>>(std::forward<Functor>(f), location);
++ }
++ }
++
++ struct QPropertyObserverPrivate;
++ struct QPropertyObserverPointer;
++ class QPropertyObserver;
++
++ class QPropertyObserverBase
++ {
++ public:
++ // Internal
++ enum ObserverTag {
++ ObserverNotifiesBinding, // observer was installed to notify bindings that obsverved property changed
++ ObserverNotifiesChangeHandler, // observer is a change handler, which runs on every change
++ ObserverIsPlaceholder, // the observer before this one is currently evaluated in QPropertyObserver::notifyObservers.
++ #if QT_DEPRECATED_SINCE(6, 6)
++ ObserverIsAlias QT_DEPRECATED_VERSION_X_6_6("Use QProperty and add a binding to the target.")
++ #endif
++ };
++ protected:
++ using ChangeHandler = void (*)(QPropertyObserver*, QUntypedPropertyData *);
++
++ private:
++ friend struct QPropertyDelayedNotifications;
++ friend struct QPropertyObserverNodeProtector;
++ friend class QPropertyObserver;
++ friend struct QPropertyObserverPointer;
++ friend struct QPropertyBindingDataPointer;
++ friend class QPropertyBindingPrivate;
++
++ QTaggedPointer<QPropertyObserver, ObserverTag> next;
++ // prev is a pointer to the "next" element within the previous node, or to the "firstObserverPtr" if it is the
++ // first node.
++ QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTag> prev;
++
++ union {
++ QPropertyBindingPrivate *binding = nullptr;
++ ChangeHandler changeHandler;
++ QUntypedPropertyData *aliasData;
++ };
++ };
++
++ class Q_CORE_EXPORT QPropertyObserver : public QPropertyObserverBase
++ {
++ public:
++ constexpr QPropertyObserver() = default;
++ QPropertyObserver(QPropertyObserver &&other) noexcept;
++ QPropertyObserver &operator=(QPropertyObserver &&other) noexcept;
++ ~QPropertyObserver();
++
++ template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
++ void setSource(const Property &property)
++ { setSource(property.bindingData()); }
++ void setSource(const QtPrivate::QPropertyBindingData &property);
++
++ protected:
++ QPropertyObserver(ChangeHandler changeHandler);
++ #if QT_DEPRECATED_SINCE(6, 6)
++ QT_DEPRECATED_VERSION_X_6_6("This constructor was only meant for internal use. Use QProperty and add a binding to the target.")
++ QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr);
++ #endif
++
++ QUntypedPropertyData *aliasedProperty() const
++ {
++ return aliasData;
++ }
++
++ private:
++
++ QPropertyObserver(const QPropertyObserver &) = delete;
++ QPropertyObserver &operator=(const QPropertyObserver &) = delete;
++
++ };
++
++ template <typename Functor>
++ class QPropertyChangeHandler : public QPropertyObserver
++ {
++ Functor m_handler;
++ public:
++ Q_NODISCARD_CTOR
++ QPropertyChangeHandler(Functor handler)
++ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
++ auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
++ This->m_handler();
++ })
++ , m_handler(std::move(handler))
++ {
++ }
++
++ template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
++ Q_NODISCARD_CTOR
++ QPropertyChangeHandler(const Property &property, Functor handler)
++ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
++ auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
++ This->m_handler();
++ })
++ , m_handler(std::move(handler))
++ {
++ setSource(property);
++ }
++ };
++
++ class QPropertyNotifier : public QPropertyObserver
++ {
++ std::function<void()> m_handler;
++ public:
++ Q_NODISCARD_CTOR
++ QPropertyNotifier() = default;
++ template<typename Functor>
++ Q_NODISCARD_CTOR
++ QPropertyNotifier(Functor handler)
++ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
++ auto This = static_cast<QPropertyNotifier *>(self);
++ This->m_handler();
++ })
++ , m_handler(std::move(handler))
++ {
++ }
++
++ template <typename Functor, typename Property,
++ QtPrivate::IsUntypedPropertyData<Property> = true>
++ Q_NODISCARD_CTOR
++ QPropertyNotifier(const Property &property, Functor handler)
++ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
++ auto This = static_cast<QPropertyNotifier *>(self);
++ This->m_handler();
++ })
++ , m_handler(std::move(handler))
++ {
++ setSource(property);
++ }
++ };
++
++ template <typename T>
++ class QProperty : public QPropertyData<T>
++ {
++ QtPrivate::QPropertyBindingData d;
++ bool is_equal(const T &v)
++ {
++ if constexpr (QTypeTraits::has_operator_equal_v<T>) {
++ if (v == this->val)
++ return true;
++ }
++ return false;
++ }
++
++ template <typename U, typename = void>
++ struct has_operator_equal_to : std::false_type{};
++
++ template <typename U>
++ struct has_operator_equal_to<U, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const U&>()))>>
++ : std::true_type{};
++
++ template <typename U>
++ static constexpr bool has_operator_equal_to_v =
++ !std::is_same_v<U, T> && has_operator_equal_to<U>::value;
++
++ public:
++ using value_type = typename QPropertyData<T>::value_type;
++ using parameter_type = typename QPropertyData<T>::parameter_type;
++ using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
++ using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
++
++ QProperty() = default;
++ explicit QProperty(parameter_type initialValue) : QPropertyData<T>(initialValue) {}
++ explicit QProperty(rvalue_ref initialValue) : QPropertyData<T>(std::move(initialValue)) {}
++ explicit QProperty(const QPropertyBinding<T> &binding)
++ : QProperty()
++ { setBinding(binding); }
++ #ifndef Q_QDOC
++ template <typename Functor>
++ explicit QProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
++ : QProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
++ {}
++ #else
++ template <typename Functor>
++ explicit QProperty(Functor &&f);
++ #endif
++ ~QProperty() = default;
++
++ QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, QProperty, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
++ QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
++ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
++
++ QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, U, /* non-constexpr */, noexcept(false), template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>)
++ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QProperty, U, /* non-constexpr */, noexcept(false), template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>)
++
++ // Explicitly delete op==(QProperty<T>, QProperty<U>) for different T & U.
++ // We do not want implicit conversions here!
++ // However, GCC complains about using a default template argument in a
++ // friend declaration, while Clang and MSVC are fine. So, skip GCC here.
++ #if !defined(Q_CC_GNU) || defined(Q_CC_CLANG)
++ #define QPROPERTY_DECL_DELETED_EQ_OP \
++ Q_DECL_EQ_DELETE_X("Call .value() on one of the properties explicitly.")
++ template <typename U, std::enable_if_t<!std::is_same_v<T, U>>* = nullptr>
++ friend void operator==(const QProperty &, const QProperty<U> &) QPROPERTY_DECL_DELETED_EQ_OP;
++ template <typename U, std::enable_if_t<!std::is_same_v<T, U>>* = nullptr>
++ friend void operator!=(const QProperty &, const QProperty<U> &) QPROPERTY_DECL_DELETED_EQ_OP;
++ #undef QPROPERTY_DECL_DELETED_EQ_OP
++ #endif // !defined(Q_CC_GNU) || defined(Q_CC_CLANG)
++
++ parameter_type value() const
++ {
++ d.registerWithCurrentlyEvaluatingBinding();
++ return this->val;
++ }
++
++ arrow_operator_result operator->() const
++ {
++ if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
++ return value();
++ } else if constexpr (std::is_pointer_v<T>) {
++ value();
++ return this->val;
++ } else {
++ return;
++ }
++ }
++
++ parameter_type operator*() const
++ {
++ return value();
++ }
++
++ operator parameter_type() const
++ {
++ return value();
++ }
++
++ void setValue(rvalue_ref newValue)
++ {
++ d.removeBinding();
++ if (is_equal(newValue))
++ return;
++ this->val = std::move(newValue);
++ notify();
++ }
++
++ void setValue(parameter_type newValue)
++ {
++ d.removeBinding();
++ if (is_equal(newValue))
++ return;
++ this->val = newValue;
++ notify();
++ }
++
++ QProperty<T> &operator=(rvalue_ref newValue)
++ {
++ setValue(std::move(newValue));
++ return *this;
++ }
++
++ QProperty<T> &operator=(parameter_type newValue)
++ {
++ setValue(newValue);
++ return *this;
++ }
++
++ QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
++ {
++ return QPropertyBinding<T>(d.setBinding(newBinding, this));
++ }
++
++ bool setBinding(const QUntypedPropertyBinding &newBinding)
++ {
++ if (!newBinding.isNull() && !newBinding.valueMetaType().isSameType<T>())
++ return false;
++ setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
++ return true;
++ }
++
++ #ifndef Q_QDOC
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor &&f,
++ const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
++ {
++ return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
++ }
++ #else
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor f);
++ #endif
++
++ bool hasBinding() const { return d.hasBinding(); }
++
++ QPropertyBinding<T> binding() const
++ {
++ return QPropertyBinding<T>(QUntypedPropertyBinding(d.binding()));
++ }
++
++ QPropertyBinding<T> takeBinding()
++ {
++ return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(), this));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> onValueChanged(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ return QPropertyChangeHandler<Functor>(*this, std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> subscribe(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ f();
++ return onValueChanged(std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyNotifier addNotifier(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ return QPropertyNotifier(*this, std::move(f));
++ }
++
++ const QtPrivate::QPropertyBindingData &bindingData() const { return d; }
++ private:
++ template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
++ friend bool comparesEqual(const QProperty &lhs, const QProperty &rhs)
++ {
++ return lhs.value() == rhs.value();
++ }
++
++ template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
++ friend bool comparesEqual(const QProperty &lhs, const T &rhs)
++ {
++ return lhs.value() == rhs;
++ }
++
++ template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>
++ friend bool comparesEqual(const QProperty &lhs, const U &rhs)
++ {
++ return lhs.value() == rhs;
++ }
++
++ void notify()
++ {
++ d.notifyObservers(this);
++ }
++
++ Q_DISABLE_COPY_MOVE(QProperty)
++ };
++
++ namespace Qt {
++ template <typename PropertyType>
++ QPropertyBinding<PropertyType> makePropertyBinding(const QProperty<PropertyType> &otherProperty,
++ const QPropertyBindingSourceLocation &location =
++ QT_PROPERTY_DEFAULT_BINDING_LOCATION)
++ {
++ return Qt::makePropertyBinding([&otherProperty]() -> PropertyType { return otherProperty; }, location);
++ }
++ }
++
++
++ namespace QtPrivate
++ {
++
++ struct QBindableInterface
++ {
++ using Getter = void (*)(const QUntypedPropertyData *d, void *value);
++ using Setter = void (*)(QUntypedPropertyData *d, const void *value);
++ using BindingGetter = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d);
++ using BindingSetter = QUntypedPropertyBinding (*)(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding);
++ using MakeBinding = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location);
++ using SetObserver = void (*)(const QUntypedPropertyData *d, QPropertyObserver *observer);
++ using GetMetaType = QMetaType (*)();
++ Getter getter;
++ Setter setter;
++ BindingGetter getBinding;
++ BindingSetter setBinding;
++ MakeBinding makeBinding;
++ SetObserver setObserver;
++ GetMetaType metaType;
++
++ static constexpr quintptr MetaTypeAccessorFlag = 0x1;
++ };
++
++ template<typename Property, typename = void>
++ class QBindableInterfaceForProperty
++ {
++ using T = typename Property::value_type;
++ public:
++ // 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
++ { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
++ nullptr,
++ nullptr,
++ 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<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;
++ 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)->setValue(*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>(); }
++ };
++ };
++
++ }
++
++ namespace QtPrivate {
++ // used in Q(Untyped)Bindable to print warnings about various binding errors
++ namespace BindableWarnings {
++ enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface };
++ Q_CORE_EXPORT void printUnsuitableBindableWarning(QAnyStringView prefix, Reason reason);
++ Q_CORE_EXPORT void printMetaTypeMismatch(QMetaType actual, QMetaType expected);
++ }
++
++ namespace PropertyAdaptorSlotObjectHelpers {
++ Q_CORE_EXPORT void getter(const QUntypedPropertyData *d, void *value);
++ Q_CORE_EXPORT void setter(QUntypedPropertyData *d, const void *value);
++ Q_CORE_EXPORT QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d);
++ Q_CORE_EXPORT bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
++ QtPrivate::QPropertyBindingFunction binding,
++ QUntypedPropertyData *temp, void *value);
++ Q_CORE_EXPORT QUntypedPropertyBinding setBinding(QUntypedPropertyData *d,
++ const QUntypedPropertyBinding &binding,
++ QPropertyBindingWrapper wrapper);
++ Q_CORE_EXPORT void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer);
++
++ template<typename T>
++ bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
++ QtPrivate::QPropertyBindingFunction binding)
++ {
++ struct Data : QPropertyData<T>
++ {
++ void *data() { return &this->val; }
++ } temp;
++ return bindingWrapper(type, d, binding, &temp, temp.data());
++ }
++
++ template<typename T>
++ QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding)
++ {
++ return setBinding(d, binding, &bindingWrapper<T>);
++ }
++
++ template<typename T>
++ QUntypedPropertyBinding makeBinding(const QUntypedPropertyData *d,
++ const QPropertyBindingSourceLocation &location)
++ {
++ return Qt::makePropertyBinding(
++ [d]() -> T {
++ T r;
++ getter(d, &r);
++ return r;
++ },
++ location);
++ }
++
++ template<class T>
++ inline constexpr QBindableInterface iface = {
++ #ifdef QT_NO_DATA_RELOCATION
++ // On windows the address of a dllimported function can't be relocated here.
++ // MSVC automatically generates a trampoline, but clang won't, so do it explicitly.
++ [](const QUntypedPropertyData *d, void *value) { getter(d, value); },
++ [](QUntypedPropertyData *d, const void *value) { setter(d, value); },
++ [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding { return getBinding(d); },
++ &setBinding<T>,
++ &makeBinding<T>,
++ [](const QUntypedPropertyData *d, QPropertyObserver *observer) { setObserver(d, observer); },
++ &QMetaType::fromType<T>,
++ #else
++ &getter,
++ &setter,
++ &getBinding,
++ &setBinding<T>,
++ &makeBinding<T>,
++ &setObserver,
++ &QMetaType::fromType<T>,
++ #endif
++ };
++ }
++ }
++
++ class QUntypedBindable
++ {
++ friend struct QUntypedBindablePrivate; // allows access to internal data
++ protected:
++ QUntypedPropertyData *data = nullptr;
++ const QtPrivate::QBindableInterface *iface = nullptr;
++ constexpr QUntypedBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
++ : data(d), iface(i)
++ {}
++
++ Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const QMetaProperty &property, const QtPrivate::QBindableInterface *i);
++ Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const char* property, const QtPrivate::QBindableInterface *i);
++
++ public:
++ constexpr QUntypedBindable() = default;
++ template<typename Property>
++ QUntypedBindable(Property *p)
++ : data(const_cast<std::remove_cv_t<Property> *>(p)),
++ iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
++ { Q_ASSERT(data && iface); }
++
++ 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) const
++ {
++ return iface ? iface->makeBinding(data, location) : QUntypedPropertyBinding();
++ }
++
++ QUntypedPropertyBinding takeBinding()
++ {
++ if (!iface)
++ return QUntypedPropertyBinding {};
++ // We do not have a dedicated takeBinding function pointer in the interface
++ // therefore we synthesize takeBinding by retrieving the binding with binding
++ // and calling setBinding with a default constructed QUntypedPropertyBinding
++ // afterwards.
++ if (!(iface->getBinding && iface->setBinding))
++ return QUntypedPropertyBinding {};
++ return [&] {
++ QUntypedPropertyBinding binding = iface->getBinding(data);
++ iface->setBinding(data, QUntypedPropertyBinding{});
++ return binding;
++ }();
++ }
++
++ void observe(QPropertyObserver *observer) const
++ {
++ if (iface)
++ iface->setObserver(data, observer);
++ #ifndef QT_NO_DEBUG
++ else
++ QtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:",
++ QtPrivate::BindableWarnings::InvalidInterface);
++ #endif
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> onValueChanged(Functor f) const
++ {
++ QPropertyChangeHandler<Functor> handler(std::move(f));
++ observe(&handler);
++ return handler;
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> subscribe(Functor f) const
++ {
++ f();
++ return onValueChanged(std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyNotifier addNotifier(Functor f)
++ {
++ QPropertyNotifier handler(std::move(f));
++ observe(&handler);
++ return handler;
++ }
++
++ QUntypedPropertyBinding binding() const
++ {
++ if (!isBindable()) {
++ #ifndef QT_NO_DEBUG
++ QtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ",
++ QtPrivate::BindableWarnings::NonBindableInterface);
++ #endif
++ return QUntypedPropertyBinding();
++ }
++ return iface->getBinding(data);
++ }
++ bool setBinding(const QUntypedPropertyBinding &binding)
++ {
++ if (isReadOnly()) {
++ #ifndef QT_NO_DEBUG
++ const auto errorType = iface ? QtPrivate::BindableWarnings::ReadOnlyInterface :
++ QtPrivate::BindableWarnings::InvalidInterface;
++ QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType);
++ #endif
++ return false;
++ }
++ if (!binding.isNull() && binding.valueMetaType() != metaType()) {
++ #ifndef QT_NO_DEBUG
++ QtPrivate::BindableWarnings::printMetaTypeMismatch(metaType(), binding.valueMetaType());
++ #endif
++ return false;
++ }
++ iface->setBinding(data, binding);
++ return true;
++ }
++ bool hasBinding() const
++ {
++ return !binding().isNull();
++ }
++
++ QMetaType metaType() const
++ {
++ if (!(iface && data))
++ return QMetaType();
++ if (iface->metaType)
++ return iface->metaType();
++ // ### Qt 7: Change the metatype function to take data as its argument
++ // special casing for QML's proxy bindable: allow multiplexing in the getter
++ // function to retrieve the metatype from data
++ Q_ASSERT(iface->getter);
++ QMetaType result;
++ iface->getter(data, reinterpret_cast<void *>(quintptr(&result) | QtPrivate::QBindableInterface::MetaTypeAccessorFlag));
++ return result;
++ }
++
++ };
++
++ template<typename T>
++ class QBindable : public QUntypedBindable
++ {
++ template<typename U>
++ friend class QPropertyAlias;
++ constexpr QBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
++ : QUntypedBindable(d, i)
++ {}
++ public:
++ using QUntypedBindable::QUntypedBindable;
++ explicit QBindable(const QUntypedBindable &b) : QUntypedBindable(b)
++ {
++ if (iface && metaType() != QMetaType::fromType<T>()) {
++ data = nullptr;
++ iface = nullptr;
++ }
++ }
++
++ explicit QBindable(QObject *obj, const QMetaProperty &property)
++ : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
++
++ explicit QBindable(QObject *obj, const char *property)
++ : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
++
++ QPropertyBinding<T> makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
++ {
++ return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::makeBinding(location));
++ }
++ QPropertyBinding<T> binding() const
++ {
++ return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::binding());
++ }
++
++ QPropertyBinding<T> takeBinding()
++ {
++ return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::takeBinding());
++ }
++
++ using QUntypedBindable::setBinding;
++ QPropertyBinding<T> setBinding(const QPropertyBinding<T> &binding)
++ {
++ Q_ASSERT(!iface || binding.isNull() || binding.valueMetaType() == metaType());
++
++ if (iface && iface->setBinding)
++ return static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding));
++ #ifndef QT_NO_DEBUG
++ if (!iface)
++ QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding", QtPrivate::BindableWarnings::InvalidInterface);
++ else
++ QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", QtPrivate::BindableWarnings::ReadOnlyInterface);
++ #endif
++ return QPropertyBinding<T>();
++ }
++ #ifndef Q_QDOC
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor &&f,
++ const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
++ {
++ return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
++ }
++ #else
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor f);
++ #endif
++
++ T value() const
++ {
++ if (iface) {
++ T result;
++ iface->getter(data, &result);
++ return result;
++ }
++ return T{};
++ }
++
++ void setValue(const T &value)
++ {
++ if (iface && iface->setter)
++ iface->setter(data, &value);
++ }
++ };
++
++ #if QT_DEPRECATED_SINCE(6, 6)
++ template<typename T>
++ class QT_DEPRECATED_VERSION_X_6_6("Class was only meant for internal use, use a QProperty and add a binding to the target")
++ QPropertyAlias : public QPropertyObserver
++ {
++ Q_DISABLE_COPY_MOVE(QPropertyAlias)
++ const QtPrivate::QBindableInterface *iface = nullptr;
++
++ public:
++ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
++ QPropertyAlias(QProperty<T> *property)
++ : QPropertyObserver(property),
++ iface(&QtPrivate::QBindableInterfaceForProperty<QProperty<T>>::iface)
++ {
++ if (iface)
++ iface->setObserver(aliasedProperty(), this);
++ }
++
++ template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
++ QPropertyAlias(Property *property)
++ : QPropertyObserver(property),
++ iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
++ {
++ if (iface)
++ iface->setObserver(aliasedProperty(), this);
++ }
++
++ QPropertyAlias(QPropertyAlias<T> *alias)
++ : QPropertyObserver(alias->aliasedProperty()),
++ iface(alias->iface)
++ {
++ if (iface)
++ iface->setObserver(aliasedProperty(), this);
++ }
++
++ QPropertyAlias(const QBindable<T> &property)
++ : QPropertyObserver(property.data),
++ iface(property.iface)
++ {
++ if (iface)
++ iface->setObserver(aliasedProperty(), this);
++ }
++
++ T value() const
++ {
++ T t = T();
++ if (auto *p = aliasedProperty())
++ iface->getter(p, &t);
++ return t;
++ }
++
++ operator T() const { return value(); }
++
++ void setValue(const T &newValue)
++ {
++ if (auto *p = aliasedProperty())
++ iface->setter(p, &newValue);
++ }
++
++ QPropertyAlias<T> &operator=(const T &newValue)
++ {
++ setValue(newValue);
++ return *this;
++ }
++
++ QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
++ {
++ return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
++ }
++
++ bool setBinding(const QUntypedPropertyBinding &newBinding)
++ {
++ return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
++ }
++
++ #ifndef Q_QDOC
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor &&f,
++ const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
++ {
++ return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
++ }
++ #else
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor f);
++ #endif
++
++ bool hasBinding() const
++ {
++ return QBindable<T>(aliasedProperty(), iface).hasBinding();
++ }
++
++ QPropertyBinding<T> binding() const
++ {
++ return QBindable<T>(aliasedProperty(), iface).binding();
++ }
++
++ QPropertyBinding<T> takeBinding()
++ {
++ return QBindable<T>(aliasedProperty(), iface).takeBinding();
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> onValueChanged(Functor f)
++ {
++ return QBindable<T>(aliasedProperty(), iface).onValueChanged(std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> subscribe(Functor f)
++ {
++ return QBindable<T>(aliasedProperty(), iface).subscribe(std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyNotifier addNotifier(Functor f)
++ {
++ return QBindable<T>(aliasedProperty(), iface).addNotifier(std::move(f));
++ }
++
++ bool isValid() const
++ {
++ return aliasedProperty() != nullptr;
++ }
++ QT_WARNING_POP
++ };
++ #endif // QT_DEPRECATED_SINCE(6, 6)
++
++ template<typename Class, typename T, auto Offset, auto Signal = nullptr>
++ class QObjectBindableProperty : public QPropertyData<T>
++ {
++ using ThisType = QObjectBindableProperty<Class, T, Offset, Signal>;
++ static bool constexpr HasSignal = !std::is_same_v<decltype(Signal), std::nullptr_t>;
++ using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
++ Class *owner()
++ {
++ char *that = reinterpret_cast<char *>(this);
++ return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
++ }
++ const Class *owner() const
++ {
++ char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
++ return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
++ }
++ static void signalCallBack(QUntypedPropertyData *o)
++ {
++ QObjectBindableProperty *that = static_cast<QObjectBindableProperty *>(o);
++ if constexpr (HasSignal) {
++ if constexpr (SignalTakesValue::value)
++ (that->owner()->*Signal)(that->valueBypassingBindings());
++ else
++ (that->owner()->*Signal)();
++ }
++ }
++ public:
++ using value_type = typename QPropertyData<T>::value_type;
++ using parameter_type = typename QPropertyData<T>::parameter_type;
++ using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
++ using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
++
++ QObjectBindableProperty() = default;
++ explicit QObjectBindableProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}
++ explicit QObjectBindableProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}
++ explicit QObjectBindableProperty(const QPropertyBinding<T> &binding)
++ : QObjectBindableProperty()
++ { setBinding(binding); }
++ #ifndef Q_QDOC
++ template <typename Functor>
++ explicit QObjectBindableProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
++ : QObjectBindableProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
++ {}
++ #else
++ template <typename Functor>
++ explicit QObjectBindableProperty(Functor &&f);
++ #endif
++
++ QT_DECLARE_EQUALITY_OPERATORS_HELPER(QObjectBindableProperty, QObjectBindableProperty, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
++ QT_DECLARE_EQUALITY_OPERATORS_HELPER(QObjectBindableProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
++ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QObjectBindableProperty, T, /* non-constexpr */, noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
++
++ parameter_type value() const
++ {
++ qGetBindingStorage(owner())->registerDependency(this);
++ return this->val;
++ }
++
++ arrow_operator_result operator->() const
++ {
++ if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
++ return value();
++ } else if constexpr (std::is_pointer_v<T>) {
++ value();
++ return this->val;
++ } else {
++ return;
++ }
++ }
++
++ parameter_type operator*() const
++ {
++ return value();
++ }
++
++ operator parameter_type() const
++ {
++ return value();
++ }
++
++ void setValue(parameter_type t)
++ {
++ auto *bd = qGetBindingStorage(owner())->bindingData(this);
++ if (bd)
++ bd->removeBinding();
++ if (this->val == t)
++ return;
++ this->val = t;
++ notify(bd);
++ }
++
++ void notify() {
++ auto *bd = qGetBindingStorage(owner())->bindingData(this);
++ notify(bd);
++ }
++
++ void setValue(rvalue_ref t)
++ {
++ auto *bd = qGetBindingStorage(owner())->bindingData(this);
++ if (bd)
++ bd->removeBinding();
++ if (this->val == t)
++ return;
++ this->val = std::move(t);
++ notify(bd);
++ }
++
++ QObjectBindableProperty &operator=(rvalue_ref newValue)
++ {
++ setValue(std::move(newValue));
++ return *this;
++ }
++
++ QObjectBindableProperty &operator=(parameter_type newValue)
++ {
++ setValue(newValue);
++ return *this;
++ }
++
++ QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
++ {
++ QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true);
++ QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, HasSignal ? &signalCallBack : nullptr));
++ return static_cast<QPropertyBinding<T> &>(oldBinding);
++ }
++
++ bool setBinding(const QUntypedPropertyBinding &newBinding)
++ {
++ if (!newBinding.isNull() && !newBinding.valueMetaType().isSameType<T>())
++ return false;
++ setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
++ return true;
++ }
++
++ #ifndef Q_QDOC
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor &&f,
++ const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
++ std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
++ {
++ return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
++ }
++ #else
++ template <typename Functor>
++ QPropertyBinding<T> setBinding(Functor f);
++ #endif
++
++ bool hasBinding() const
++ {
++ auto *bd = qGetBindingStorage(owner())->bindingData(this);
++ return bd && bd->binding() != nullptr;
++ }
++
++ QPropertyBinding<T> binding() const
++ {
++ auto *bd = qGetBindingStorage(owner())->bindingData(this);
++ return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() : nullptr));
++ }
++
++ QPropertyBinding<T> takeBinding()
++ {
++ return setBinding(QPropertyBinding<T>());
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> onValueChanged(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ return QPropertyChangeHandler<Functor>(*this, std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> subscribe(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ f();
++ return onValueChanged(std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyNotifier addNotifier(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ return QPropertyNotifier(*this, std::move(f));
++ }
++
++ const QtPrivate::QPropertyBindingData &bindingData() const
++ {
++ auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
++ return *storage->bindingData(const_cast<ThisType *>(this), true);
++ }
++ private:
++ template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
++ friend bool comparesEqual(const QObjectBindableProperty &lhs, const QObjectBindableProperty &rhs)
++ {
++ return lhs.value() == rhs.value();
++ }
++
++ template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
++ friend bool comparesEqual(const QObjectBindableProperty &lhs, const T &rhs)
++ {
++ return lhs.value() == rhs;
++ }
++
++ void notify(const QtPrivate::QPropertyBindingData *binding)
++ {
++ if (binding)
++ binding->notifyObservers(this, qGetBindingStorage(owner()));
++ if constexpr (HasSignal) {
++ if constexpr (SignalTakesValue::value)
++ (owner()->*Signal)(this->valueBypassingBindings());
++ else
++ (owner()->*Signal)();
++ }
++ }
++ };
++
++ #define QT_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \
++ 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;
++
++ #define QT_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, 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;
++
++ #define Q_OBJECT_BINDABLE_PROPERTY(...) \
++ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
++ QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \
++ QT_WARNING_POP
++
++ #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(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 QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(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_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
++ QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \
++ QT_WARNING_POP
++
++ template<typename Class, typename T, auto Offset, auto Getter>
++ class QObjectComputedProperty : public QUntypedPropertyData
++ {
++ Class *owner()
++ {
++ char *that = reinterpret_cast<char *>(this);
++ return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
++ }
++ const Class *owner() const
++ {
++ char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
++ return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
++ }
++
++ public:
++ using value_type = T;
++ using parameter_type = T;
++
++ QObjectComputedProperty() = default;
++
++ parameter_type value() const
++ {
++ qGetBindingStorage(owner())->registerDependency(this);
++ return (owner()->*Getter)();
++ }
++
++ std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type, void>
++ operator->() const
++ {
++ if constexpr (QTypeTraits::is_dereferenceable_v<T>)
++ return value();
++ else
++ return;
++ }
++
++ parameter_type operator*() const
++ {
++ return value();
++ }
++
++ operator parameter_type() const
++ {
++ return value();
++ }
++
++ constexpr bool hasBinding() const { return false; }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> onValueChanged(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ return QPropertyChangeHandler<Functor>(*this, std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyChangeHandler<Functor> subscribe(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ f();
++ return onValueChanged(std::move(f));
++ }
++
++ template<typename Functor>
++ [[nodiscard]]
++ QPropertyNotifier addNotifier(Functor f)
++ {
++ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
++ return QPropertyNotifier(*this, std::move(f));
++ }
++
++ QtPrivate::QPropertyBindingData &bindingData() const
++ {
++ auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
++ return *storage->bindingData(const_cast<QObjectComputedProperty *>(this), true);
++ }
++
++ void notify() {
++ // computed property can't store a binding, so there's nothing to mark
++ auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
++ auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this), false);
++ if (bd)
++ bd->notifyObservers(this, qGetBindingStorage(owner()));
++ }
++ };
++
++ #define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \
++ static constexpr size_t _qt_property_##name##_offset() { \
++ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
++ return offsetof(Class, name); \
++ QT_WARNING_POP \
++ } \
++ QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;
++
++ #undef QT_SOURCE_LOCATION_NAMESPACE
++
++ QT_END_NAMESPACE
++
++ #endif // QPROPERTY_H