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