File indexing completed on 2026-08-13 09:22:40
0001
0002
0003
0004
0005 #ifndef QPROPERTY_H
0006 #define QPROPERTY_H
0007
0008 #include <QtCore/qglobal.h>
0009 #include <QtCore/qshareddata.h>
0010 #include <QtCore/qstring.h>
0011 #include <QtCore/qttypetraits.h>
0012 #include <QtCore/qbindingstorage.h>
0013
0014 #include <type_traits>
0015
0016 #include <QtCore/qpropertyprivate.h>
0017
0018 #if __has_include(<source_location>) && __cplusplus >= 202002L && !defined(Q_QDOC)
0019 #include <source_location>
0020 #if defined(__cpp_lib_source_location)
0021 #define QT_SOURCE_LOCATION_NAMESPACE std
0022 #define QT_PROPERTY_COLLECT_BINDING_LOCATION
0023 #if defined(Q_CC_MSVC)
0024
0025
0026 # define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation::fromStdSourceLocation(std::source_location::current())
0027 #else
0028
0029
0030
0031 # define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current())
0032 #endif
0033 #endif
0034 #endif
0035
0036 #if __has_include(<experimental/source_location>) && !defined(Q_QDOC)
0037 #include <experimental/source_location>
0038 #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)
0039 #if defined(__cpp_lib_experimental_source_location)
0040 #define QT_SOURCE_LOCATION_NAMESPACE std::experimental
0041 #define QT_PROPERTY_COLLECT_BINDING_LOCATION
0042 #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::experimental::source_location::current())
0043 #endif
0044 #endif
0045 #endif
0046
0047 #if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)
0048 #define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation()
0049 #endif
0050
0051 QT_BEGIN_NAMESPACE
0052
0053 namespace Qt {
0054 Q_CORE_EXPORT void beginPropertyUpdateGroup();
0055 Q_CORE_EXPORT void endPropertyUpdateGroup();
0056 }
0057
0058 class QScopedPropertyUpdateGroup
0059 {
0060 Q_DISABLE_COPY_MOVE(QScopedPropertyUpdateGroup)
0061 public:
0062 Q_NODISCARD_CTOR
0063 QScopedPropertyUpdateGroup()
0064 { Qt::beginPropertyUpdateGroup(); }
0065 ~QScopedPropertyUpdateGroup() noexcept(false)
0066 { Qt::endPropertyUpdateGroup(); }
0067 };
0068
0069 template <typename T>
0070 class QPropertyData : public QUntypedPropertyData
0071 {
0072 protected:
0073 mutable T val = T();
0074 private:
0075 class DisableRValueRefs {};
0076 protected:
0077 static constexpr bool UseReferences = !(std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_pointer_v<T>);
0078 public:
0079 using value_type = T;
0080 using parameter_type = std::conditional_t<UseReferences, const T &, T>;
0081 using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>;
0082 using arrow_operator_result = std::conditional_t<std::is_pointer_v<T>, const T &,
0083 std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, const T &, void>>;
0084
0085 QPropertyData() = default;
0086 QPropertyData(parameter_type t) : val(t) {}
0087 QPropertyData(rvalue_ref t) : val(std::move(t)) {}
0088 ~QPropertyData() = default;
0089
0090 parameter_type valueBypassingBindings() const { return val; }
0091 void setValueBypassingBindings(parameter_type v) { val = v; }
0092 void setValueBypassingBindings(rvalue_ref v) { val = std::move(v); }
0093 };
0094
0095
0096 struct Q_CORE_EXPORT QPropertyBindingSourceLocation
0097 {
0098 const char *fileName = nullptr;
0099 const char *functionName = nullptr;
0100 quint32 line = 0;
0101 quint32 column = 0;
0102 QPropertyBindingSourceLocation() = default;
0103 #ifdef __cpp_lib_source_location
0104 constexpr QPropertyBindingSourceLocation(const std::source_location &cppLocation)
0105 {
0106 fileName = cppLocation.file_name();
0107 functionName = cppLocation.function_name();
0108 line = cppLocation.line();
0109 column = cppLocation.column();
0110 }
0111 QT_POST_CXX17_API_IN_EXPORTED_CLASS
0112 static consteval QPropertyBindingSourceLocation
0113 fromStdSourceLocation(const std::source_location &cppLocation)
0114 {
0115 return cppLocation;
0116 }
0117 #endif
0118 #ifdef __cpp_lib_experimental_source_location
0119 constexpr QPropertyBindingSourceLocation(const std::experimental::source_location &cppLocation)
0120 {
0121 fileName = cppLocation.file_name();
0122 functionName = cppLocation.function_name();
0123 line = cppLocation.line();
0124 column = cppLocation.column();
0125 }
0126 #endif
0127 };
0128
0129 template <typename Functor> class QPropertyChangeHandler;
0130 class QPropertyBindingErrorPrivate;
0131
0132 class Q_CORE_EXPORT QPropertyBindingError
0133 {
0134 public:
0135 enum Type {
0136 NoError,
0137 BindingLoop,
0138 EvaluationError,
0139 UnknownError
0140 };
0141
0142 QPropertyBindingError();
0143 QPropertyBindingError(Type type, const QString &description = QString());
0144
0145 QPropertyBindingError(const QPropertyBindingError &other);
0146 QPropertyBindingError &operator=(const QPropertyBindingError &other);
0147 QPropertyBindingError(QPropertyBindingError &&other);
0148 QPropertyBindingError &operator=(QPropertyBindingError &&other);
0149 ~QPropertyBindingError();
0150
0151 bool hasError() const { return d.get() != nullptr; }
0152 Type type() const;
0153 QString description() const;
0154
0155 private:
0156 QSharedDataPointer<QPropertyBindingErrorPrivate> d;
0157 };
0158
0159 class Q_CORE_EXPORT QUntypedPropertyBinding
0160 {
0161 public:
0162
0163 using BindingFunctionVTable = QtPrivate::BindingFunctionVTable;
0164
0165 QUntypedPropertyBinding();
0166 QUntypedPropertyBinding(QMetaType metaType, const BindingFunctionVTable *vtable, void *function, const QPropertyBindingSourceLocation &location);
0167
0168 template<typename Functor>
0169 QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
0170 : QUntypedPropertyBinding(metaType, &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>>, &f, location)
0171 {}
0172
0173 QUntypedPropertyBinding(QUntypedPropertyBinding &&other);
0174 QUntypedPropertyBinding(const QUntypedPropertyBinding &other);
0175 QUntypedPropertyBinding &operator=(const QUntypedPropertyBinding &other);
0176 QUntypedPropertyBinding &operator=(QUntypedPropertyBinding &&other);
0177 ~QUntypedPropertyBinding();
0178
0179 bool isNull() const;
0180
0181 QPropertyBindingError error() const;
0182
0183 QMetaType valueMetaType() const;
0184
0185 explicit QUntypedPropertyBinding(QPropertyBindingPrivate *priv);
0186 private:
0187 friend class QtPrivate::QPropertyBindingData;
0188 friend class QPropertyBindingPrivate;
0189 template <typename> friend class QPropertyBinding;
0190 QPropertyBindingPrivatePtr d;
0191 };
0192
0193 template <typename PropertyType>
0194 class QPropertyBinding : public QUntypedPropertyBinding
0195 {
0196
0197 public:
0198 QPropertyBinding() = default;
0199
0200 template<typename Functor>
0201 QPropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location)
0202 : QUntypedPropertyBinding(QMetaType::fromType<PropertyType>(), &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>, PropertyType>, &f, location)
0203 {}
0204
0205
0206
0207 explicit QPropertyBinding(const QUntypedPropertyBinding &binding)
0208 : QUntypedPropertyBinding(binding)
0209 {}
0210 };
0211
0212 namespace Qt {
0213 template <typename Functor>
0214 auto makePropertyBinding(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0215 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0216 {
0217 return QPropertyBinding<std::invoke_result_t<Functor>>(std::forward<Functor>(f), location);
0218 }
0219 }
0220
0221 struct QPropertyObserverPrivate;
0222 struct QPropertyObserverPointer;
0223 class QPropertyObserver;
0224
0225 class QPropertyObserverBase
0226 {
0227 public:
0228
0229 enum ObserverTag {
0230 ObserverNotifiesBinding,
0231 ObserverNotifiesChangeHandler,
0232 ObserverIsPlaceholder,
0233 #if QT_DEPRECATED_SINCE(6, 6)
0234 ObserverIsAlias QT_DEPRECATED_VERSION_X_6_6("Use QProperty and add a binding to the target.")
0235 #endif
0236 };
0237 protected:
0238 using ChangeHandler = void (*)(QPropertyObserver*, QUntypedPropertyData *);
0239
0240 private:
0241 friend struct QPropertyDelayedNotifications;
0242 friend struct QPropertyObserverNodeProtector;
0243 friend class QPropertyObserver;
0244 friend struct QPropertyObserverPointer;
0245 friend struct QPropertyBindingDataPointer;
0246 friend class QPropertyBindingPrivate;
0247
0248 QTaggedPointer<QPropertyObserver, ObserverTag> next;
0249
0250
0251 QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTag> prev;
0252
0253 union {
0254 QPropertyBindingPrivate *binding = nullptr;
0255 ChangeHandler changeHandler;
0256 QUntypedPropertyData *aliasData;
0257 };
0258 };
0259
0260 class Q_CORE_EXPORT QPropertyObserver : public QPropertyObserverBase
0261 {
0262 public:
0263 constexpr QPropertyObserver() = default;
0264 QPropertyObserver(QPropertyObserver &&other) noexcept;
0265 QPropertyObserver &operator=(QPropertyObserver &&other) noexcept;
0266 ~QPropertyObserver();
0267
0268 template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0269 void setSource(const Property &property)
0270 { setSource(property.bindingData()); }
0271 void setSource(const QtPrivate::QPropertyBindingData &property);
0272
0273 protected:
0274 QPropertyObserver(ChangeHandler changeHandler);
0275 #if QT_DEPRECATED_SINCE(6, 6)
0276 QT_DEPRECATED_VERSION_X_6_6("This constructor was only meant for internal use. Use QProperty and add a binding to the target.")
0277 QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr);
0278 #endif
0279
0280 QUntypedPropertyData *aliasedProperty() const
0281 {
0282 return aliasData;
0283 }
0284
0285 private:
0286
0287 QPropertyObserver(const QPropertyObserver &) = delete;
0288 QPropertyObserver &operator=(const QPropertyObserver &) = delete;
0289
0290 };
0291
0292 template <typename Functor>
0293 class QPropertyChangeHandler : public QPropertyObserver
0294 {
0295 Functor m_handler;
0296 public:
0297 Q_NODISCARD_CTOR
0298 QPropertyChangeHandler(Functor handler)
0299 : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0300 auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
0301 This->m_handler();
0302 })
0303 , m_handler(std::move(handler))
0304 {
0305 }
0306
0307 template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0308 Q_NODISCARD_CTOR
0309 QPropertyChangeHandler(const Property &property, Functor handler)
0310 : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0311 auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
0312 This->m_handler();
0313 })
0314 , m_handler(std::move(handler))
0315 {
0316 setSource(property);
0317 }
0318 };
0319
0320 class QPropertyNotifier : public QPropertyObserver
0321 {
0322 std::function<void()> m_handler;
0323 public:
0324 Q_NODISCARD_CTOR
0325 QPropertyNotifier() = default;
0326 template<typename Functor>
0327 Q_NODISCARD_CTOR
0328 QPropertyNotifier(Functor handler)
0329 : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0330 auto This = static_cast<QPropertyNotifier *>(self);
0331 This->m_handler();
0332 })
0333 , m_handler(std::move(handler))
0334 {
0335 }
0336
0337 template <typename Functor, typename Property,
0338 QtPrivate::IsUntypedPropertyData<Property> = true>
0339 Q_NODISCARD_CTOR
0340 QPropertyNotifier(const Property &property, Functor handler)
0341 : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
0342 auto This = static_cast<QPropertyNotifier *>(self);
0343 This->m_handler();
0344 })
0345 , m_handler(std::move(handler))
0346 {
0347 setSource(property);
0348 }
0349 };
0350
0351 template <typename T>
0352 class QProperty : public QPropertyData<T>
0353 {
0354 QtPrivate::QPropertyBindingData d;
0355 bool is_equal(const T &v)
0356 {
0357 if constexpr (QTypeTraits::has_operator_equal_v<T>) {
0358 if (v == this->val)
0359 return true;
0360 }
0361 return false;
0362 }
0363
0364 template <typename U, typename = void>
0365 struct has_operator_equal_to : std::false_type{};
0366
0367 template <typename U>
0368 struct has_operator_equal_to<U, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const U&>()))>>
0369 : std::true_type{};
0370
0371 template <typename U>
0372 static constexpr bool has_operator_equal_to_v =
0373 !std::is_same_v<U, T> && has_operator_equal_to<U>::value;
0374
0375 public:
0376 using value_type = typename QPropertyData<T>::value_type;
0377 using parameter_type = typename QPropertyData<T>::parameter_type;
0378 using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
0379 using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
0380
0381 QProperty() = default;
0382 explicit QProperty(parameter_type initialValue) : QPropertyData<T>(initialValue) {}
0383 explicit QProperty(rvalue_ref initialValue) : QPropertyData<T>(std::move(initialValue)) {}
0384 explicit QProperty(const QPropertyBinding<T> &binding)
0385 : QProperty()
0386 { setBinding(binding); }
0387 #ifndef Q_QDOC
0388 template <typename Functor>
0389 explicit QProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0390 typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
0391 : QProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
0392 {}
0393 #else
0394 template <typename Functor>
0395 explicit QProperty(Functor &&f);
0396 #endif
0397 ~QProperty() = default;
0398
0399 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, QProperty, , noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
0400 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, T, , noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
0401 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QProperty, T, , noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
0402
0403 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QProperty, U, , noexcept(false), template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>)
0404 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QProperty, U, , noexcept(false), template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>)
0405
0406
0407
0408
0409
0410 #if !defined(Q_CC_GNU) || defined(Q_CC_CLANG)
0411 #define QPROPERTY_DECL_DELETED_EQ_OP \
0412 Q_DECL_EQ_DELETE_X("Call .value() on one of the properties explicitly.")
0413 template <typename U, std::enable_if_t<!std::is_same_v<T, U>>* = nullptr>
0414 friend void operator==(const QProperty &, const QProperty<U> &) QPROPERTY_DECL_DELETED_EQ_OP;
0415 template <typename U, std::enable_if_t<!std::is_same_v<T, U>>* = nullptr>
0416 friend void operator!=(const QProperty &, const QProperty<U> &) QPROPERTY_DECL_DELETED_EQ_OP;
0417 #undef QPROPERTY_DECL_DELETED_EQ_OP
0418 #endif
0419
0420 parameter_type value() const
0421 {
0422 d.registerWithCurrentlyEvaluatingBinding();
0423 return this->val;
0424 }
0425
0426 arrow_operator_result operator->() const
0427 {
0428 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
0429 return value();
0430 } else if constexpr (std::is_pointer_v<T>) {
0431 value();
0432 return this->val;
0433 } else {
0434 return;
0435 }
0436 }
0437
0438 parameter_type operator*() const
0439 {
0440 return value();
0441 }
0442
0443 operator parameter_type() const
0444 {
0445 return value();
0446 }
0447
0448 void setValue(rvalue_ref newValue)
0449 {
0450 d.removeBinding();
0451 if (is_equal(newValue))
0452 return;
0453 this->val = std::move(newValue);
0454 notify();
0455 }
0456
0457 void setValue(parameter_type newValue)
0458 {
0459 d.removeBinding();
0460 if (is_equal(newValue))
0461 return;
0462 this->val = newValue;
0463 notify();
0464 }
0465
0466 QProperty<T> &operator=(rvalue_ref newValue)
0467 {
0468 setValue(std::move(newValue));
0469 return *this;
0470 }
0471
0472 QProperty<T> &operator=(parameter_type newValue)
0473 {
0474 setValue(newValue);
0475 return *this;
0476 }
0477
0478 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
0479 {
0480 return QPropertyBinding<T>(d.setBinding(newBinding, this));
0481 }
0482
0483 bool setBinding(const QUntypedPropertyBinding &newBinding)
0484 {
0485 if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())
0486 return false;
0487 setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
0488 return true;
0489 }
0490
0491 #ifndef Q_QDOC
0492 template <typename Functor>
0493 QPropertyBinding<T> setBinding(Functor &&f,
0494 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0495 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0496 {
0497 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0498 }
0499 #else
0500 template <typename Functor>
0501 QPropertyBinding<T> setBinding(Functor f);
0502 #endif
0503
0504 bool hasBinding() const { return d.hasBinding(); }
0505
0506 QPropertyBinding<T> binding() const
0507 {
0508 return QPropertyBinding<T>(QUntypedPropertyBinding(d.binding()));
0509 }
0510
0511 QPropertyBinding<T> takeBinding()
0512 {
0513 return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(), this));
0514 }
0515
0516 template<typename Functor>
0517 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
0518 {
0519 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0520 return QPropertyChangeHandler<Functor>(*this, std::move(f));
0521 }
0522
0523 template<typename Functor>
0524 QPropertyChangeHandler<Functor> subscribe(Functor f)
0525 {
0526 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0527 f();
0528 return onValueChanged(std::move(f));
0529 }
0530
0531 template<typename Functor>
0532 QPropertyNotifier addNotifier(Functor f)
0533 {
0534 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0535 return QPropertyNotifier(*this, std::move(f));
0536 }
0537
0538 const QtPrivate::QPropertyBindingData &bindingData() const { return d; }
0539 private:
0540 template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
0541 friend bool comparesEqual(const QProperty &lhs, const QProperty &rhs)
0542 {
0543 return lhs.value() == rhs.value();
0544 }
0545
0546 template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
0547 friend bool comparesEqual(const QProperty &lhs, const T &rhs)
0548 {
0549 return lhs.value() == rhs;
0550 }
0551
0552 template <typename U, std::enable_if_t<has_operator_equal_to_v<U>>* = nullptr>
0553 friend bool comparesEqual(const QProperty &lhs, const U &rhs)
0554 {
0555 return lhs.value() == rhs;
0556 }
0557
0558 void notify()
0559 {
0560 d.notifyObservers(this);
0561 }
0562
0563 Q_DISABLE_COPY_MOVE(QProperty)
0564 };
0565
0566 namespace Qt {
0567 template <typename PropertyType>
0568 QPropertyBinding<PropertyType> makePropertyBinding(const QProperty<PropertyType> &otherProperty,
0569 const QPropertyBindingSourceLocation &location =
0570 QT_PROPERTY_DEFAULT_BINDING_LOCATION)
0571 {
0572 return Qt::makePropertyBinding([&otherProperty]() -> PropertyType { return otherProperty; }, location);
0573 }
0574 }
0575
0576
0577 namespace QtPrivate
0578 {
0579
0580 struct QBindableInterface
0581 {
0582 using Getter = void (*)(const QUntypedPropertyData *d, void *value);
0583 using Setter = void (*)(QUntypedPropertyData *d, const void *value);
0584 using BindingGetter = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d);
0585 using BindingSetter = QUntypedPropertyBinding (*)(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding);
0586 using MakeBinding = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location);
0587 using SetObserver = void (*)(const QUntypedPropertyData *d, QPropertyObserver *observer);
0588 using GetMetaType = QMetaType (*)();
0589 Getter getter;
0590 Setter setter;
0591 BindingGetter getBinding;
0592 BindingSetter setBinding;
0593 MakeBinding makeBinding;
0594 SetObserver setObserver;
0595 GetMetaType metaType;
0596
0597 static constexpr quintptr MetaTypeAccessorFlag = 0x1;
0598 };
0599
0600 template<typename Property, typename = void>
0601 class QBindableInterfaceForProperty
0602 {
0603 using T = typename Property::value_type;
0604 public:
0605
0606
0607 static constexpr QBindableInterface iface = {
0608 [](const QUntypedPropertyData *d, void *value) -> void
0609 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0610 nullptr,
0611 nullptr,
0612 nullptr,
0613 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0614 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0615 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0616 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0617 []() { return QMetaType::fromType<T>(); }
0618 };
0619 };
0620
0621 template<typename Property>
0622 class QBindableInterfaceForProperty<const Property, std::void_t<decltype(std::declval<Property>().binding())>>
0623 {
0624 using T = typename Property::value_type;
0625 public:
0626
0627 static constexpr QBindableInterface iface = {
0628
0629 [](const QUntypedPropertyData *d, void *value) -> void
0630 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0631 nullptr,
0632 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
0633 { return static_cast<const Property *>(d)->binding(); },
0634 nullptr,
0635 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0636 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0637 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0638 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0639 []() { return QMetaType::fromType<T>(); }
0640 };
0641 };
0642
0643 template<typename Property>
0644 class QBindableInterfaceForProperty<Property, std::void_t<decltype(std::declval<Property>().binding())>>
0645 {
0646 using T = typename Property::value_type;
0647 public:
0648 static constexpr QBindableInterface iface = {
0649 [](const QUntypedPropertyData *d, void *value) -> void
0650 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0651 [](QUntypedPropertyData *d, const void *value) -> void
0652 { static_cast<Property *>(d)->setValue(*static_cast<const T*>(value)); },
0653 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
0654 { return static_cast<const Property *>(d)->binding(); },
0655 [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding
0656 { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },
0657 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0658 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0659 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0660 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0661 []() { return QMetaType::fromType<T>(); }
0662 };
0663 };
0664
0665 }
0666
0667 namespace QtPrivate {
0668
0669 namespace BindableWarnings {
0670 enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface };
0671 Q_CORE_EXPORT void printUnsuitableBindableWarning(QAnyStringView prefix, Reason reason);
0672 Q_CORE_EXPORT void printMetaTypeMismatch(QMetaType actual, QMetaType expected);
0673 }
0674
0675 namespace PropertyAdaptorSlotObjectHelpers {
0676 Q_CORE_EXPORT void getter(const QUntypedPropertyData *d, void *value);
0677 Q_CORE_EXPORT void setter(QUntypedPropertyData *d, const void *value);
0678 Q_CORE_EXPORT QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d);
0679 Q_CORE_EXPORT bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
0680 QtPrivate::QPropertyBindingFunction binding,
0681 QUntypedPropertyData *temp, void *value);
0682 Q_CORE_EXPORT QUntypedPropertyBinding setBinding(QUntypedPropertyData *d,
0683 const QUntypedPropertyBinding &binding,
0684 QPropertyBindingWrapper wrapper);
0685 Q_CORE_EXPORT void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer);
0686
0687 template<typename T>
0688 bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
0689 QtPrivate::QPropertyBindingFunction binding)
0690 {
0691 struct Data : QPropertyData<T>
0692 {
0693 void *data() { return &this->val; }
0694 } temp;
0695 return bindingWrapper(type, d, binding, &temp, temp.data());
0696 }
0697
0698 template<typename T>
0699 QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding)
0700 {
0701 return setBinding(d, binding, &bindingWrapper<T>);
0702 }
0703
0704 template<typename T>
0705 QUntypedPropertyBinding makeBinding(const QUntypedPropertyData *d,
0706 const QPropertyBindingSourceLocation &location)
0707 {
0708 return Qt::makePropertyBinding(
0709 [d]() -> T {
0710 T r;
0711 getter(d, &r);
0712 return r;
0713 },
0714 location);
0715 }
0716
0717 template<class T>
0718 inline constexpr QBindableInterface iface = {
0719 #ifdef QT_NO_DATA_RELOCATION
0720
0721
0722 [](const QUntypedPropertyData *d, void *value) { getter(d, value); },
0723 [](QUntypedPropertyData *d, const void *value) { setter(d, value); },
0724 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding { return getBinding(d); },
0725 &setBinding<T>,
0726 &makeBinding<T>,
0727 [](const QUntypedPropertyData *d, QPropertyObserver *observer) { setObserver(d, observer); },
0728 &QMetaType::fromType<T>,
0729 #else
0730 &getter,
0731 &setter,
0732 &getBinding,
0733 &setBinding<T>,
0734 &makeBinding<T>,
0735 &setObserver,
0736 &QMetaType::fromType<T>,
0737 #endif
0738 };
0739 }
0740 }
0741
0742 class QUntypedBindable
0743 {
0744 friend struct QUntypedBindablePrivate;
0745 protected:
0746 QUntypedPropertyData *data = nullptr;
0747 const QtPrivate::QBindableInterface *iface = nullptr;
0748 constexpr QUntypedBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
0749 : data(d), iface(i)
0750 {}
0751
0752 Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const QMetaProperty &property, const QtPrivate::QBindableInterface *i);
0753 Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const char* property, const QtPrivate::QBindableInterface *i);
0754
0755 public:
0756 constexpr QUntypedBindable() = default;
0757 template<typename Property>
0758 QUntypedBindable(Property *p)
0759 : data(const_cast<std::remove_cv_t<Property> *>(p)),
0760 iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
0761 { Q_ASSERT(data && iface); }
0762
0763 bool isValid() const { return data != nullptr; }
0764 bool isBindable() const { return iface && iface->getBinding; }
0765 bool isReadOnly() const { return !(iface && iface->setBinding && iface->setObserver); }
0766
0767 QUntypedPropertyBinding makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
0768 {
0769 return iface ? iface->makeBinding(data, location) : QUntypedPropertyBinding();
0770 }
0771
0772 QUntypedPropertyBinding takeBinding()
0773 {
0774 if (!iface)
0775 return QUntypedPropertyBinding {};
0776
0777
0778
0779
0780 if (!(iface->getBinding && iface->setBinding))
0781 return QUntypedPropertyBinding {};
0782 return [&] {
0783 QUntypedPropertyBinding binding = iface->getBinding(data);
0784 iface->setBinding(data, QUntypedPropertyBinding{});
0785 return binding;
0786 }();
0787 }
0788
0789 void observe(QPropertyObserver *observer) const
0790 {
0791 if (iface)
0792 iface->setObserver(data, observer);
0793 #ifndef QT_NO_DEBUG
0794 else
0795 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:",
0796 QtPrivate::BindableWarnings::InvalidInterface);
0797 #endif
0798 }
0799
0800 template<typename Functor>
0801 QPropertyChangeHandler<Functor> onValueChanged(Functor f) const
0802 {
0803 QPropertyChangeHandler<Functor> handler(std::move(f));
0804 observe(&handler);
0805 return handler;
0806 }
0807
0808 template<typename Functor>
0809 QPropertyChangeHandler<Functor> subscribe(Functor f) const
0810 {
0811 f();
0812 return onValueChanged(std::move(f));
0813 }
0814
0815 template<typename Functor>
0816 QPropertyNotifier addNotifier(Functor f)
0817 {
0818 QPropertyNotifier handler(std::move(f));
0819 observe(&handler);
0820 return handler;
0821 }
0822
0823 QUntypedPropertyBinding binding() const
0824 {
0825 if (!isBindable()) {
0826 #ifndef QT_NO_DEBUG
0827 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ",
0828 QtPrivate::BindableWarnings::NonBindableInterface);
0829 #endif
0830 return QUntypedPropertyBinding();
0831 }
0832 return iface->getBinding(data);
0833 }
0834 bool setBinding(const QUntypedPropertyBinding &binding)
0835 {
0836 if (isReadOnly()) {
0837 #ifndef QT_NO_DEBUG
0838 const auto errorType = iface ? QtPrivate::BindableWarnings::ReadOnlyInterface :
0839 QtPrivate::BindableWarnings::InvalidInterface;
0840 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType);
0841 #endif
0842 return false;
0843 }
0844 if (!binding.isNull() && binding.valueMetaType() != metaType()) {
0845 #ifndef QT_NO_DEBUG
0846 QtPrivate::BindableWarnings::printMetaTypeMismatch(metaType(), binding.valueMetaType());
0847 #endif
0848 return false;
0849 }
0850 iface->setBinding(data, binding);
0851 return true;
0852 }
0853 bool hasBinding() const
0854 {
0855 return !binding().isNull();
0856 }
0857
0858 QMetaType metaType() const
0859 {
0860 if (!(iface && data))
0861 return QMetaType();
0862 if (iface->metaType)
0863 return iface->metaType();
0864
0865
0866
0867 Q_ASSERT(iface->getter);
0868 QMetaType result;
0869 iface->getter(data, reinterpret_cast<void *>(quintptr(&result) | QtPrivate::QBindableInterface::MetaTypeAccessorFlag));
0870 return result;
0871 }
0872
0873 };
0874
0875 template<typename T>
0876 class QBindable : public QUntypedBindable
0877 {
0878 template<typename U>
0879 friend class QPropertyAlias;
0880 constexpr QBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
0881 : QUntypedBindable(d, i)
0882 {}
0883 public:
0884 using QUntypedBindable::QUntypedBindable;
0885 explicit QBindable(const QUntypedBindable &b) : QUntypedBindable(b)
0886 {
0887 if (iface && metaType() != QMetaType::fromType<T>()) {
0888 data = nullptr;
0889 iface = nullptr;
0890 }
0891 }
0892
0893 explicit QBindable(QObject *obj, const QMetaProperty &property)
0894 : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
0895
0896 explicit QBindable(QObject *obj, const char *property)
0897 : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
0898
0899 QPropertyBinding<T> makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
0900 {
0901 return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::makeBinding(location));
0902 }
0903 QPropertyBinding<T> binding() const
0904 {
0905 return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::binding());
0906 }
0907
0908 QPropertyBinding<T> takeBinding()
0909 {
0910 return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::takeBinding());
0911 }
0912
0913 using QUntypedBindable::setBinding;
0914 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &binding)
0915 {
0916 Q_ASSERT(!iface || binding.isNull() || binding.valueMetaType() == metaType());
0917
0918 if (iface && iface->setBinding)
0919 return static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding));
0920 #ifndef QT_NO_DEBUG
0921 if (!iface)
0922 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding", QtPrivate::BindableWarnings::InvalidInterface);
0923 else
0924 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", QtPrivate::BindableWarnings::ReadOnlyInterface);
0925 #endif
0926 return QPropertyBinding<T>();
0927 }
0928 #ifndef Q_QDOC
0929 template <typename Functor>
0930 QPropertyBinding<T> setBinding(Functor &&f,
0931 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0932 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0933 {
0934 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0935 }
0936 #else
0937 template <typename Functor>
0938 QPropertyBinding<T> setBinding(Functor f);
0939 #endif
0940
0941 T value() const
0942 {
0943 if (iface) {
0944 T result;
0945 iface->getter(data, &result);
0946 return result;
0947 }
0948 return T{};
0949 }
0950
0951 void setValue(const T &value)
0952 {
0953 if (iface && iface->setter)
0954 iface->setter(data, &value);
0955 }
0956 };
0957
0958 #if QT_DEPRECATED_SINCE(6, 6)
0959 template<typename T>
0960 class QT_DEPRECATED_VERSION_X_6_6("Class was only meant for internal use, use a QProperty and add a binding to the target")
0961 QPropertyAlias : public QPropertyObserver
0962 {
0963 Q_DISABLE_COPY_MOVE(QPropertyAlias)
0964 const QtPrivate::QBindableInterface *iface = nullptr;
0965
0966 public:
0967 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
0968 QPropertyAlias(QProperty<T> *property)
0969 : QPropertyObserver(property),
0970 iface(&QtPrivate::QBindableInterfaceForProperty<QProperty<T>>::iface)
0971 {
0972 if (iface)
0973 iface->setObserver(aliasedProperty(), this);
0974 }
0975
0976 template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0977 QPropertyAlias(Property *property)
0978 : QPropertyObserver(property),
0979 iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
0980 {
0981 if (iface)
0982 iface->setObserver(aliasedProperty(), this);
0983 }
0984
0985 QPropertyAlias(QPropertyAlias<T> *alias)
0986 : QPropertyObserver(alias->aliasedProperty()),
0987 iface(alias->iface)
0988 {
0989 if (iface)
0990 iface->setObserver(aliasedProperty(), this);
0991 }
0992
0993 QPropertyAlias(const QBindable<T> &property)
0994 : QPropertyObserver(property.data),
0995 iface(property.iface)
0996 {
0997 if (iface)
0998 iface->setObserver(aliasedProperty(), this);
0999 }
1000
1001 T value() const
1002 {
1003 T t = T();
1004 if (auto *p = aliasedProperty())
1005 iface->getter(p, &t);
1006 return t;
1007 }
1008
1009 operator T() const { return value(); }
1010
1011 void setValue(const T &newValue)
1012 {
1013 if (auto *p = aliasedProperty())
1014 iface->setter(p, &newValue);
1015 }
1016
1017 QPropertyAlias<T> &operator=(const T &newValue)
1018 {
1019 setValue(newValue);
1020 return *this;
1021 }
1022
1023 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
1024 {
1025 return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
1026 }
1027
1028 bool setBinding(const QUntypedPropertyBinding &newBinding)
1029 {
1030 return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
1031 }
1032
1033 #ifndef Q_QDOC
1034 template <typename Functor>
1035 QPropertyBinding<T> setBinding(Functor &&f,
1036 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1037 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
1038 {
1039 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
1040 }
1041 #else
1042 template <typename Functor>
1043 QPropertyBinding<T> setBinding(Functor f);
1044 #endif
1045
1046 bool hasBinding() const
1047 {
1048 return QBindable<T>(aliasedProperty(), iface).hasBinding();
1049 }
1050
1051 QPropertyBinding<T> binding() const
1052 {
1053 return QBindable<T>(aliasedProperty(), iface).binding();
1054 }
1055
1056 QPropertyBinding<T> takeBinding()
1057 {
1058 return QBindable<T>(aliasedProperty(), iface).takeBinding();
1059 }
1060
1061 template<typename Functor>
1062 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1063 {
1064 return QBindable<T>(aliasedProperty(), iface).onValueChanged(std::move(f));
1065 }
1066
1067 template<typename Functor>
1068 QPropertyChangeHandler<Functor> subscribe(Functor f)
1069 {
1070 return QBindable<T>(aliasedProperty(), iface).subscribe(std::move(f));
1071 }
1072
1073 template<typename Functor>
1074 QPropertyNotifier addNotifier(Functor f)
1075 {
1076 return QBindable<T>(aliasedProperty(), iface).addNotifier(std::move(f));
1077 }
1078
1079 bool isValid() const
1080 {
1081 return aliasedProperty() != nullptr;
1082 }
1083 QT_WARNING_POP
1084 };
1085 #endif
1086
1087 template<typename Class, typename T, auto Offset, auto Signal = nullptr>
1088 class QObjectBindableProperty : public QPropertyData<T>
1089 {
1090 using ThisType = QObjectBindableProperty<Class, T, Offset, Signal>;
1091 static bool constexpr HasSignal = !std::is_same_v<decltype(Signal), std::nullptr_t>;
1092 using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
1093 Class *owner()
1094 {
1095 char *that = reinterpret_cast<char *>(this);
1096 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1097 }
1098 const Class *owner() const
1099 {
1100 char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
1101 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1102 }
1103 static void signalCallBack(QUntypedPropertyData *o)
1104 {
1105 QObjectBindableProperty *that = static_cast<QObjectBindableProperty *>(o);
1106 if constexpr (HasSignal) {
1107 if constexpr (SignalTakesValue::value)
1108 (that->owner()->*Signal)(that->valueBypassingBindings());
1109 else
1110 (that->owner()->*Signal)();
1111 }
1112 }
1113 public:
1114 using value_type = typename QPropertyData<T>::value_type;
1115 using parameter_type = typename QPropertyData<T>::parameter_type;
1116 using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
1117 using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
1118
1119 QObjectBindableProperty() = default;
1120 explicit QObjectBindableProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}
1121 explicit QObjectBindableProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}
1122 explicit QObjectBindableProperty(const QPropertyBinding<T> &binding)
1123 : QObjectBindableProperty()
1124 { setBinding(binding); }
1125 #ifndef Q_QDOC
1126 template <typename Functor>
1127 explicit QObjectBindableProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1128 typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
1129 : QObjectBindableProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
1130 {}
1131 #else
1132 template <typename Functor>
1133 explicit QObjectBindableProperty(Functor &&f);
1134 #endif
1135
1136 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QObjectBindableProperty, QObjectBindableProperty, , noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
1137 QT_DECLARE_EQUALITY_OPERATORS_HELPER(QObjectBindableProperty, T, , noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
1138 QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(QObjectBindableProperty, T, , noexcept(false), template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>)
1139
1140 parameter_type value() const
1141 {
1142 qGetBindingStorage(owner())->registerDependency(this);
1143 return this->val;
1144 }
1145
1146 arrow_operator_result operator->() const
1147 {
1148 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
1149 return value();
1150 } else if constexpr (std::is_pointer_v<T>) {
1151 value();
1152 return this->val;
1153 } else {
1154 return;
1155 }
1156 }
1157
1158 parameter_type operator*() const
1159 {
1160 return value();
1161 }
1162
1163 operator parameter_type() const
1164 {
1165 return value();
1166 }
1167
1168 void setValue(parameter_type t)
1169 {
1170 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1171 if (bd)
1172 bd->removeBinding();
1173 if (this->val == t)
1174 return;
1175 this->val = t;
1176 notify(bd);
1177 }
1178
1179 void notify() {
1180 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1181 notify(bd);
1182 }
1183
1184 void setValue(rvalue_ref t)
1185 {
1186 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1187 if (bd)
1188 bd->removeBinding();
1189 if (this->val == t)
1190 return;
1191 this->val = std::move(t);
1192 notify(bd);
1193 }
1194
1195 QObjectBindableProperty &operator=(rvalue_ref newValue)
1196 {
1197 setValue(std::move(newValue));
1198 return *this;
1199 }
1200
1201 QObjectBindableProperty &operator=(parameter_type newValue)
1202 {
1203 setValue(newValue);
1204 return *this;
1205 }
1206
1207 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
1208 {
1209 QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true);
1210 QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, HasSignal ? &signalCallBack : nullptr));
1211 return static_cast<QPropertyBinding<T> &>(oldBinding);
1212 }
1213
1214 bool setBinding(const QUntypedPropertyBinding &newBinding)
1215 {
1216 if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())
1217 return false;
1218 setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
1219 return true;
1220 }
1221
1222 #ifndef Q_QDOC
1223 template <typename Functor>
1224 QPropertyBinding<T> setBinding(Functor &&f,
1225 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1226 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
1227 {
1228 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
1229 }
1230 #else
1231 template <typename Functor>
1232 QPropertyBinding<T> setBinding(Functor f);
1233 #endif
1234
1235 bool hasBinding() const
1236 {
1237 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1238 return bd && bd->binding() != nullptr;
1239 }
1240
1241 QPropertyBinding<T> binding() const
1242 {
1243 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1244 return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() : nullptr));
1245 }
1246
1247 QPropertyBinding<T> takeBinding()
1248 {
1249 return setBinding(QPropertyBinding<T>());
1250 }
1251
1252 template<typename Functor>
1253 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1254 {
1255 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1256 return QPropertyChangeHandler<Functor>(*this, std::move(f));
1257 }
1258
1259 template<typename Functor>
1260 QPropertyChangeHandler<Functor> subscribe(Functor f)
1261 {
1262 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1263 f();
1264 return onValueChanged(std::move(f));
1265 }
1266
1267 template<typename Functor>
1268 QPropertyNotifier addNotifier(Functor f)
1269 {
1270 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1271 return QPropertyNotifier(*this, std::move(f));
1272 }
1273
1274 const QtPrivate::QPropertyBindingData &bindingData() const
1275 {
1276 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1277 return *storage->bindingData(const_cast<ThisType *>(this), true);
1278 }
1279 private:
1280 template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
1281 friend bool comparesEqual(const QObjectBindableProperty &lhs, const QObjectBindableProperty &rhs)
1282 {
1283 return lhs.value() == rhs.value();
1284 }
1285
1286 template <typename Ty = T, std::enable_if_t<QTypeTraits::has_operator_equal_v<Ty>>* = nullptr>
1287 friend bool comparesEqual(const QObjectBindableProperty &lhs, const T &rhs)
1288 {
1289 return lhs.value() == rhs;
1290 }
1291
1292 void notify(const QtPrivate::QPropertyBindingData *binding)
1293 {
1294 if (binding)
1295 binding->notifyObservers(this, qGetBindingStorage(owner()));
1296 if constexpr (HasSignal) {
1297 if constexpr (SignalTakesValue::value)
1298 (owner()->*Signal)(this->valueBypassingBindings());
1299 else
1300 (owner()->*Signal)();
1301 }
1302 }
1303 };
1304
1305 #define QT_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \
1306 static constexpr size_t _qt_property_##name##_offset() { \
1307 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1308 return offsetof(Class, name); \
1309 QT_WARNING_POP \
1310 } \
1311 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name;
1312
1313 #define QT_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, Signal) \
1314 static constexpr size_t _qt_property_##name##_offset() { \
1315 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1316 return offsetof(Class, name); \
1317 QT_WARNING_POP \
1318 } \
1319 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name;
1320
1321 #define Q_OBJECT_BINDABLE_PROPERTY(...) \
1322 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1323 QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \
1324 QT_WARNING_POP
1325
1326 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(Class, Type, name, value) \
1327 static constexpr size_t _qt_property_##name##_offset() \
1328 { \
1329 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1330 return offsetof(Class, name); \
1331 QT_WARNING_POP \
1332 } \
1333 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name = \
1334 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr>( \
1335 value);
1336
1337 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(Class, Type, name, value, Signal) \
1338 static constexpr size_t _qt_property_##name##_offset() \
1339 { \
1340 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1341 return offsetof(Class, name); \
1342 QT_WARNING_POP \
1343 } \
1344 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name = \
1345 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal>( \
1346 value);
1347
1348 #define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...) \
1349 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1350 QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \
1351 QT_WARNING_POP
1352
1353 template<typename Class, typename T, auto Offset, auto Getter>
1354 class QObjectComputedProperty : public QUntypedPropertyData
1355 {
1356 Class *owner()
1357 {
1358 char *that = reinterpret_cast<char *>(this);
1359 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1360 }
1361 const Class *owner() const
1362 {
1363 char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
1364 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1365 }
1366
1367 public:
1368 using value_type = T;
1369 using parameter_type = T;
1370
1371 QObjectComputedProperty() = default;
1372
1373 parameter_type value() const
1374 {
1375 qGetBindingStorage(owner())->registerDependency(this);
1376 return (owner()->*Getter)();
1377 }
1378
1379 std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type, void>
1380 operator->() const
1381 {
1382 if constexpr (QTypeTraits::is_dereferenceable_v<T>)
1383 return value();
1384 else
1385 return;
1386 }
1387
1388 parameter_type operator*() const
1389 {
1390 return value();
1391 }
1392
1393 operator parameter_type() const
1394 {
1395 return value();
1396 }
1397
1398 constexpr bool hasBinding() const { return false; }
1399
1400 template<typename Functor>
1401 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1402 {
1403 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1404 return QPropertyChangeHandler<Functor>(*this, std::move(f));
1405 }
1406
1407 template<typename Functor>
1408 QPropertyChangeHandler<Functor> subscribe(Functor f)
1409 {
1410 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1411 f();
1412 return onValueChanged(std::move(f));
1413 }
1414
1415 template<typename Functor>
1416 QPropertyNotifier addNotifier(Functor f)
1417 {
1418 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1419 return QPropertyNotifier(*this, std::move(f));
1420 }
1421
1422 QtPrivate::QPropertyBindingData &bindingData() const
1423 {
1424 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1425 return *storage->bindingData(const_cast<QObjectComputedProperty *>(this), true);
1426 }
1427
1428 void notify() {
1429
1430 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1431 auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this), false);
1432 if (bd)
1433 bd->notifyObservers(this, qGetBindingStorage(owner()));
1434 }
1435 };
1436
1437 #define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \
1438 static constexpr size_t _qt_property_##name##_offset() { \
1439 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1440 return offsetof(Class, name); \
1441 QT_WARNING_POP \
1442 } \
1443 QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;
1444
1445 #undef QT_SOURCE_LOCATION_NAMESPACE
1446
1447 QT_END_NAMESPACE
1448
1449 #endif