File indexing completed on 2025-09-18 09:26:42
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(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(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(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(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 public:
0364 using value_type = typename QPropertyData<T>::value_type;
0365 using parameter_type = typename QPropertyData<T>::parameter_type;
0366 using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
0367 using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
0368
0369 QProperty() = default;
0370 explicit QProperty(parameter_type initialValue) : QPropertyData<T>(initialValue) {}
0371 explicit QProperty(rvalue_ref initialValue) : QPropertyData<T>(std::move(initialValue)) {}
0372 explicit QProperty(const QPropertyBinding<T> &binding)
0373 : QProperty()
0374 { setBinding(binding); }
0375 #ifndef Q_QDOC
0376 template <typename Functor>
0377 explicit QProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0378 typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
0379 : QProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
0380 {}
0381 #else
0382 template <typename Functor>
0383 explicit QProperty(Functor &&f);
0384 #endif
0385 ~QProperty() = default;
0386
0387 parameter_type value() const
0388 {
0389 d.registerWithCurrentlyEvaluatingBinding();
0390 return this->val;
0391 }
0392
0393 arrow_operator_result operator->() const
0394 {
0395 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
0396 return value();
0397 } else if constexpr (std::is_pointer_v<T>) {
0398 value();
0399 return this->val;
0400 } else {
0401 return;
0402 }
0403 }
0404
0405 parameter_type operator*() const
0406 {
0407 return value();
0408 }
0409
0410 operator parameter_type() const
0411 {
0412 return value();
0413 }
0414
0415 void setValue(rvalue_ref newValue)
0416 {
0417 d.removeBinding();
0418 if (is_equal(newValue))
0419 return;
0420 this->val = std::move(newValue);
0421 notify();
0422 }
0423
0424 void setValue(parameter_type newValue)
0425 {
0426 d.removeBinding();
0427 if (is_equal(newValue))
0428 return;
0429 this->val = newValue;
0430 notify();
0431 }
0432
0433 QProperty<T> &operator=(rvalue_ref newValue)
0434 {
0435 setValue(std::move(newValue));
0436 return *this;
0437 }
0438
0439 QProperty<T> &operator=(parameter_type newValue)
0440 {
0441 setValue(newValue);
0442 return *this;
0443 }
0444
0445 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
0446 {
0447 return QPropertyBinding<T>(d.setBinding(newBinding, this));
0448 }
0449
0450 bool setBinding(const QUntypedPropertyBinding &newBinding)
0451 {
0452 if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())
0453 return false;
0454 setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
0455 return true;
0456 }
0457
0458 #ifndef Q_QDOC
0459 template <typename Functor>
0460 QPropertyBinding<T> setBinding(Functor &&f,
0461 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0462 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0463 {
0464 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0465 }
0466 #else
0467 template <typename Functor>
0468 QPropertyBinding<T> setBinding(Functor f);
0469 #endif
0470
0471 bool hasBinding() const { return d.hasBinding(); }
0472
0473 QPropertyBinding<T> binding() const
0474 {
0475 return QPropertyBinding<T>(QUntypedPropertyBinding(d.binding()));
0476 }
0477
0478 QPropertyBinding<T> takeBinding()
0479 {
0480 return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(), this));
0481 }
0482
0483 template<typename Functor>
0484 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
0485 {
0486 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0487 return QPropertyChangeHandler<Functor>(*this, f);
0488 }
0489
0490 template<typename Functor>
0491 QPropertyChangeHandler<Functor> subscribe(Functor f)
0492 {
0493 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0494 f();
0495 return onValueChanged(f);
0496 }
0497
0498 template<typename Functor>
0499 QPropertyNotifier addNotifier(Functor f)
0500 {
0501 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
0502 return QPropertyNotifier(*this, f);
0503 }
0504
0505 const QtPrivate::QPropertyBindingData &bindingData() const { return d; }
0506 private:
0507 void notify()
0508 {
0509 d.notifyObservers(this);
0510 }
0511
0512 Q_DISABLE_COPY_MOVE(QProperty)
0513 };
0514
0515 namespace Qt {
0516 template <typename PropertyType>
0517 QPropertyBinding<PropertyType> makePropertyBinding(const QProperty<PropertyType> &otherProperty,
0518 const QPropertyBindingSourceLocation &location =
0519 QT_PROPERTY_DEFAULT_BINDING_LOCATION)
0520 {
0521 return Qt::makePropertyBinding([&otherProperty]() -> PropertyType { return otherProperty; }, location);
0522 }
0523 }
0524
0525
0526 namespace QtPrivate
0527 {
0528
0529 struct QBindableInterface
0530 {
0531 using Getter = void (*)(const QUntypedPropertyData *d, void *value);
0532 using Setter = void (*)(QUntypedPropertyData *d, const void *value);
0533 using BindingGetter = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d);
0534 using BindingSetter = QUntypedPropertyBinding (*)(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding);
0535 using MakeBinding = QUntypedPropertyBinding (*)(const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location);
0536 using SetObserver = void (*)(const QUntypedPropertyData *d, QPropertyObserver *observer);
0537 using GetMetaType = QMetaType (*)();
0538 Getter getter;
0539 Setter setter;
0540 BindingGetter getBinding;
0541 BindingSetter setBinding;
0542 MakeBinding makeBinding;
0543 SetObserver setObserver;
0544 GetMetaType metaType;
0545
0546 static constexpr quintptr MetaTypeAccessorFlag = 0x1;
0547 };
0548
0549 template<typename Property, typename = void>
0550 class QBindableInterfaceForProperty
0551 {
0552 using T = typename Property::value_type;
0553 public:
0554
0555
0556 static constexpr QBindableInterface iface = {
0557 [](const QUntypedPropertyData *d, void *value) -> void
0558 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0559 nullptr,
0560 nullptr,
0561 nullptr,
0562 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0563 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0564 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0565 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0566 []() { return QMetaType::fromType<T>(); }
0567 };
0568 };
0569
0570 template<typename Property>
0571 class QBindableInterfaceForProperty<const Property, std::void_t<decltype(std::declval<Property>().binding())>>
0572 {
0573 using T = typename Property::value_type;
0574 public:
0575
0576 static constexpr QBindableInterface iface = {
0577
0578 [](const QUntypedPropertyData *d, void *value) -> void
0579 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0580 nullptr,
0581 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
0582 { return static_cast<const Property *>(d)->binding(); },
0583 nullptr,
0584 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0585 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0586 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0587 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0588 []() { return QMetaType::fromType<T>(); }
0589 };
0590 };
0591
0592 template<typename Property>
0593 class QBindableInterfaceForProperty<Property, std::void_t<decltype(std::declval<Property>().binding())>>
0594 {
0595 using T = typename Property::value_type;
0596 public:
0597 static constexpr QBindableInterface iface = {
0598 [](const QUntypedPropertyData *d, void *value) -> void
0599 { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
0600 [](QUntypedPropertyData *d, const void *value) -> void
0601 { static_cast<Property *>(d)->setValue(*static_cast<const T*>(value)); },
0602 [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
0603 { return static_cast<const Property *>(d)->binding(); },
0604 [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding
0605 { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },
0606 [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
0607 { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
0608 [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
0609 { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
0610 []() { return QMetaType::fromType<T>(); }
0611 };
0612 };
0613
0614 }
0615
0616 namespace QtPrivate {
0617
0618 namespace BindableWarnings {
0619 enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface };
0620 Q_CORE_EXPORT void printUnsuitableBindableWarning(QAnyStringView prefix, Reason reason);
0621 Q_CORE_EXPORT void printMetaTypeMismatch(QMetaType actual, QMetaType expected);
0622 }
0623
0624 namespace PropertyAdaptorSlotObjectHelpers {
0625 Q_CORE_EXPORT void getter(const QUntypedPropertyData *d, void *value);
0626 Q_CORE_EXPORT void setter(QUntypedPropertyData *d, const void *value);
0627 Q_CORE_EXPORT QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d);
0628 Q_CORE_EXPORT bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
0629 QtPrivate::QPropertyBindingFunction binding,
0630 QUntypedPropertyData *temp, void *value);
0631 Q_CORE_EXPORT QUntypedPropertyBinding setBinding(QUntypedPropertyData *d,
0632 const QUntypedPropertyBinding &binding,
0633 QPropertyBindingWrapper wrapper);
0634 Q_CORE_EXPORT void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer);
0635
0636 template<typename T>
0637 bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
0638 QtPrivate::QPropertyBindingFunction binding)
0639 {
0640 struct Data : QPropertyData<T>
0641 {
0642 void *data() { return &this->val; }
0643 } temp;
0644 return bindingWrapper(type, d, binding, &temp, temp.data());
0645 }
0646
0647 template<typename T>
0648 QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding)
0649 {
0650 return setBinding(d, binding, &bindingWrapper<T>);
0651 }
0652
0653 template<typename T>
0654 QUntypedPropertyBinding makeBinding(const QUntypedPropertyData *d,
0655 const QPropertyBindingSourceLocation &location)
0656 {
0657 return Qt::makePropertyBinding(
0658 [d]() -> T {
0659 T r;
0660 getter(d, &r);
0661 return r;
0662 },
0663 location);
0664 }
0665
0666 template<class T>
0667 inline constexpr QBindableInterface iface = {
0668 &getter,
0669 &setter,
0670 &getBinding,
0671 &setBinding<T>,
0672 &makeBinding<T>,
0673 &setObserver,
0674 &QMetaType::fromType<T>,
0675 };
0676 }
0677 }
0678
0679 class QUntypedBindable
0680 {
0681 friend struct QUntypedBindablePrivate;
0682 protected:
0683 QUntypedPropertyData *data = nullptr;
0684 const QtPrivate::QBindableInterface *iface = nullptr;
0685 constexpr QUntypedBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
0686 : data(d), iface(i)
0687 {}
0688
0689 Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const QMetaProperty &property, const QtPrivate::QBindableInterface *i);
0690 Q_CORE_EXPORT explicit QUntypedBindable(QObject* obj, const char* property, const QtPrivate::QBindableInterface *i);
0691
0692 public:
0693 constexpr QUntypedBindable() = default;
0694 template<typename Property>
0695 QUntypedBindable(Property *p)
0696 : data(const_cast<std::remove_cv_t<Property> *>(p)),
0697 iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
0698 { Q_ASSERT(data && iface); }
0699
0700 bool isValid() const { return data != nullptr; }
0701 bool isBindable() const { return iface && iface->getBinding; }
0702 bool isReadOnly() const { return !(iface && iface->setBinding && iface->setObserver); }
0703
0704 QUntypedPropertyBinding makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
0705 {
0706 return iface ? iface->makeBinding(data, location) : QUntypedPropertyBinding();
0707 }
0708
0709 QUntypedPropertyBinding takeBinding()
0710 {
0711 if (!iface)
0712 return QUntypedPropertyBinding {};
0713
0714
0715
0716
0717 if (!(iface->getBinding && iface->setBinding))
0718 return QUntypedPropertyBinding {};
0719 QUntypedPropertyBinding binding = iface->getBinding(data);
0720 iface->setBinding(data, QUntypedPropertyBinding{});
0721 return binding;
0722 }
0723
0724 void observe(QPropertyObserver *observer) const
0725 {
0726 if (iface)
0727 iface->setObserver(data, observer);
0728 #ifndef QT_NO_DEBUG
0729 else
0730 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:",
0731 QtPrivate::BindableWarnings::InvalidInterface);
0732 #endif
0733 }
0734
0735 template<typename Functor>
0736 QPropertyChangeHandler<Functor> onValueChanged(Functor f) const
0737 {
0738 QPropertyChangeHandler<Functor> handler(f);
0739 observe(&handler);
0740 return handler;
0741 }
0742
0743 template<typename Functor>
0744 QPropertyChangeHandler<Functor> subscribe(Functor f) const
0745 {
0746 f();
0747 return onValueChanged(f);
0748 }
0749
0750 template<typename Functor>
0751 QPropertyNotifier addNotifier(Functor f)
0752 {
0753 QPropertyNotifier handler(f);
0754 observe(&handler);
0755 return handler;
0756 }
0757
0758 QUntypedPropertyBinding binding() const
0759 {
0760 if (!isBindable()) {
0761 #ifndef QT_NO_DEBUG
0762 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ",
0763 QtPrivate::BindableWarnings::NonBindableInterface);
0764 #endif
0765 return QUntypedPropertyBinding();
0766 }
0767 return iface->getBinding(data);
0768 }
0769 bool setBinding(const QUntypedPropertyBinding &binding)
0770 {
0771 if (isReadOnly()) {
0772 #ifndef QT_NO_DEBUG
0773 const auto errorType = iface ? QtPrivate::BindableWarnings::ReadOnlyInterface :
0774 QtPrivate::BindableWarnings::InvalidInterface;
0775 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType);
0776 #endif
0777 return false;
0778 }
0779 if (!binding.isNull() && binding.valueMetaType() != metaType()) {
0780 #ifndef QT_NO_DEBUG
0781 QtPrivate::BindableWarnings::printMetaTypeMismatch(metaType(), binding.valueMetaType());
0782 #endif
0783 return false;
0784 }
0785 iface->setBinding(data, binding);
0786 return true;
0787 }
0788 bool hasBinding() const
0789 {
0790 return !binding().isNull();
0791 }
0792
0793 QMetaType metaType() const
0794 {
0795 if (!(iface && data))
0796 return QMetaType();
0797 if (iface->metaType)
0798 return iface->metaType();
0799
0800
0801
0802 Q_ASSERT(iface->getter);
0803 QMetaType result;
0804 iface->getter(data, reinterpret_cast<void *>(quintptr(&result) | QtPrivate::QBindableInterface::MetaTypeAccessorFlag));
0805 return result;
0806 }
0807
0808 };
0809
0810 template<typename T>
0811 class QBindable : public QUntypedBindable
0812 {
0813 template<typename U>
0814 friend class QPropertyAlias;
0815 constexpr QBindable(QUntypedPropertyData *d, const QtPrivate::QBindableInterface *i)
0816 : QUntypedBindable(d, i)
0817 {}
0818 public:
0819 using QUntypedBindable::QUntypedBindable;
0820 explicit QBindable(const QUntypedBindable &b) : QUntypedBindable(b)
0821 {
0822 if (iface && metaType() != QMetaType::fromType<T>()) {
0823 data = nullptr;
0824 iface = nullptr;
0825 }
0826 }
0827
0828 explicit QBindable(QObject *obj, const QMetaProperty &property)
0829 : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
0830
0831 explicit QBindable(QObject *obj, const char *property)
0832 : QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}
0833
0834 QPropertyBinding<T> makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) const
0835 {
0836 return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::makeBinding(location));
0837 }
0838 QPropertyBinding<T> binding() const
0839 {
0840 return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::binding());
0841 }
0842
0843 QPropertyBinding<T> takeBinding()
0844 {
0845 return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::takeBinding());
0846 }
0847
0848 using QUntypedBindable::setBinding;
0849 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &binding)
0850 {
0851 Q_ASSERT(!iface || binding.isNull() || binding.valueMetaType() == metaType());
0852
0853 if (iface && iface->setBinding)
0854 return static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding));
0855 #ifndef QT_NO_DEBUG
0856 if (!iface)
0857 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding", QtPrivate::BindableWarnings::InvalidInterface);
0858 else
0859 QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", QtPrivate::BindableWarnings::ReadOnlyInterface);
0860 #endif
0861 return QPropertyBinding<T>();
0862 }
0863 #ifndef Q_QDOC
0864 template <typename Functor>
0865 QPropertyBinding<T> setBinding(Functor &&f,
0866 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0867 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0868 {
0869 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0870 }
0871 #else
0872 template <typename Functor>
0873 QPropertyBinding<T> setBinding(Functor f);
0874 #endif
0875
0876 T value() const
0877 {
0878 if (iface) {
0879 T result;
0880 iface->getter(data, &result);
0881 return result;
0882 }
0883 return T{};
0884 }
0885
0886 void setValue(const T &value)
0887 {
0888 if (iface && iface->setter)
0889 iface->setter(data, &value);
0890 }
0891 };
0892
0893 #if QT_DEPRECATED_SINCE(6, 6)
0894 template<typename T>
0895 class QT_DEPRECATED_VERSION_X_6_6("Class was only meant for internal use, use a QProperty and add a binding to the target")
0896 QPropertyAlias : public QPropertyObserver
0897 {
0898 Q_DISABLE_COPY_MOVE(QPropertyAlias)
0899 const QtPrivate::QBindableInterface *iface = nullptr;
0900
0901 public:
0902 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
0903 QPropertyAlias(QProperty<T> *property)
0904 : QPropertyObserver(property),
0905 iface(&QtPrivate::QBindableInterfaceForProperty<QProperty<T>>::iface)
0906 {
0907 if (iface)
0908 iface->setObserver(aliasedProperty(), this);
0909 }
0910
0911 template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
0912 QPropertyAlias(Property *property)
0913 : QPropertyObserver(property),
0914 iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
0915 {
0916 if (iface)
0917 iface->setObserver(aliasedProperty(), this);
0918 }
0919
0920 QPropertyAlias(QPropertyAlias<T> *alias)
0921 : QPropertyObserver(alias->aliasedProperty()),
0922 iface(alias->iface)
0923 {
0924 if (iface)
0925 iface->setObserver(aliasedProperty(), this);
0926 }
0927
0928 QPropertyAlias(const QBindable<T> &property)
0929 : QPropertyObserver(property.data),
0930 iface(property.iface)
0931 {
0932 if (iface)
0933 iface->setObserver(aliasedProperty(), this);
0934 }
0935
0936 T value() const
0937 {
0938 T t = T();
0939 if (auto *p = aliasedProperty())
0940 iface->getter(p, &t);
0941 return t;
0942 }
0943
0944 operator T() const { return value(); }
0945
0946 void setValue(const T &newValue)
0947 {
0948 if (auto *p = aliasedProperty())
0949 iface->setter(p, &newValue);
0950 }
0951
0952 QPropertyAlias<T> &operator=(const T &newValue)
0953 {
0954 setValue(newValue);
0955 return *this;
0956 }
0957
0958 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
0959 {
0960 return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
0961 }
0962
0963 bool setBinding(const QUntypedPropertyBinding &newBinding)
0964 {
0965 return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);
0966 }
0967
0968 #ifndef Q_QDOC
0969 template <typename Functor>
0970 QPropertyBinding<T> setBinding(Functor &&f,
0971 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
0972 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
0973 {
0974 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
0975 }
0976 #else
0977 template <typename Functor>
0978 QPropertyBinding<T> setBinding(Functor f);
0979 #endif
0980
0981 bool hasBinding() const
0982 {
0983 return QBindable<T>(aliasedProperty(), iface).hasBinding();
0984 }
0985
0986 QPropertyBinding<T> binding() const
0987 {
0988 return QBindable<T>(aliasedProperty(), iface).binding();
0989 }
0990
0991 QPropertyBinding<T> takeBinding()
0992 {
0993 return QBindable<T>(aliasedProperty(), iface).takeBinding();
0994 }
0995
0996 template<typename Functor>
0997 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
0998 {
0999 return QBindable<T>(aliasedProperty(), iface).onValueChanged(f);
1000 }
1001
1002 template<typename Functor>
1003 QPropertyChangeHandler<Functor> subscribe(Functor f)
1004 {
1005 return QBindable<T>(aliasedProperty(), iface).subscribe(f);
1006 }
1007
1008 template<typename Functor>
1009 QPropertyNotifier addNotifier(Functor f)
1010 {
1011 return QBindable<T>(aliasedProperty(), iface).addNotifier(f);
1012 }
1013
1014 bool isValid() const
1015 {
1016 return aliasedProperty() != nullptr;
1017 }
1018 QT_WARNING_POP
1019 };
1020 #endif
1021
1022 template<typename Class, typename T, auto Offset, auto Signal = nullptr>
1023 class QObjectBindableProperty : public QPropertyData<T>
1024 {
1025 using ThisType = QObjectBindableProperty<Class, T, Offset, Signal>;
1026 static bool constexpr HasSignal = !std::is_same_v<decltype(Signal), std::nullptr_t>;
1027 using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
1028 Class *owner()
1029 {
1030 char *that = reinterpret_cast<char *>(this);
1031 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1032 }
1033 const Class *owner() const
1034 {
1035 char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
1036 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1037 }
1038 static void signalCallBack(QUntypedPropertyData *o)
1039 {
1040 QObjectBindableProperty *that = static_cast<QObjectBindableProperty *>(o);
1041 if constexpr (HasSignal) {
1042 if constexpr (SignalTakesValue::value)
1043 (that->owner()->*Signal)(that->valueBypassingBindings());
1044 else
1045 (that->owner()->*Signal)();
1046 }
1047 }
1048 public:
1049 using value_type = typename QPropertyData<T>::value_type;
1050 using parameter_type = typename QPropertyData<T>::parameter_type;
1051 using rvalue_ref = typename QPropertyData<T>::rvalue_ref;
1052 using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;
1053
1054 QObjectBindableProperty() = default;
1055 explicit QObjectBindableProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}
1056 explicit QObjectBindableProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}
1057 explicit QObjectBindableProperty(const QPropertyBinding<T> &binding)
1058 : QObjectBindableProperty()
1059 { setBinding(binding); }
1060 #ifndef Q_QDOC
1061 template <typename Functor>
1062 explicit QObjectBindableProperty(Functor &&f, const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1063 typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * = nullptr)
1064 : QObjectBindableProperty(QPropertyBinding<T>(std::forward<Functor>(f), location))
1065 {}
1066 #else
1067 template <typename Functor>
1068 explicit QObjectBindableProperty(Functor &&f);
1069 #endif
1070
1071 parameter_type value() const
1072 {
1073 qGetBindingStorage(owner())->registerDependency(this);
1074 return this->val;
1075 }
1076
1077 arrow_operator_result operator->() const
1078 {
1079 if constexpr (QTypeTraits::is_dereferenceable_v<T>) {
1080 return value();
1081 } else if constexpr (std::is_pointer_v<T>) {
1082 value();
1083 return this->val;
1084 } else {
1085 return;
1086 }
1087 }
1088
1089 parameter_type operator*() const
1090 {
1091 return value();
1092 }
1093
1094 operator parameter_type() const
1095 {
1096 return value();
1097 }
1098
1099 void setValue(parameter_type t)
1100 {
1101 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1102 if (bd)
1103 bd->removeBinding();
1104 if (this->val == t)
1105 return;
1106 this->val = t;
1107 notify(bd);
1108 }
1109
1110 void notify() {
1111 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1112 notify(bd);
1113 }
1114
1115 void setValue(rvalue_ref t)
1116 {
1117 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1118 if (bd)
1119 bd->removeBinding();
1120 if (this->val == t)
1121 return;
1122 this->val = std::move(t);
1123 notify(bd);
1124 }
1125
1126 QObjectBindableProperty &operator=(rvalue_ref newValue)
1127 {
1128 setValue(std::move(newValue));
1129 return *this;
1130 }
1131
1132 QObjectBindableProperty &operator=(parameter_type newValue)
1133 {
1134 setValue(newValue);
1135 return *this;
1136 }
1137
1138 QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding)
1139 {
1140 QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true);
1141 QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, HasSignal ? &signalCallBack : nullptr));
1142 return static_cast<QPropertyBinding<T> &>(oldBinding);
1143 }
1144
1145 bool setBinding(const QUntypedPropertyBinding &newBinding)
1146 {
1147 if (!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())
1148 return false;
1149 setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));
1150 return true;
1151 }
1152
1153 #ifndef Q_QDOC
1154 template <typename Functor>
1155 QPropertyBinding<T> setBinding(Functor &&f,
1156 const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,
1157 std::enable_if_t<std::is_invocable_v<Functor>> * = nullptr)
1158 {
1159 return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));
1160 }
1161 #else
1162 template <typename Functor>
1163 QPropertyBinding<T> setBinding(Functor f);
1164 #endif
1165
1166 bool hasBinding() const
1167 {
1168 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1169 return bd && bd->binding() != nullptr;
1170 }
1171
1172 QPropertyBinding<T> binding() const
1173 {
1174 auto *bd = qGetBindingStorage(owner())->bindingData(this);
1175 return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() : nullptr));
1176 }
1177
1178 QPropertyBinding<T> takeBinding()
1179 {
1180 return setBinding(QPropertyBinding<T>());
1181 }
1182
1183 template<typename Functor>
1184 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1185 {
1186 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1187 return QPropertyChangeHandler<Functor>(*this, f);
1188 }
1189
1190 template<typename Functor>
1191 QPropertyChangeHandler<Functor> subscribe(Functor f)
1192 {
1193 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1194 f();
1195 return onValueChanged(f);
1196 }
1197
1198 template<typename Functor>
1199 QPropertyNotifier addNotifier(Functor f)
1200 {
1201 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1202 return QPropertyNotifier(*this, f);
1203 }
1204
1205 const QtPrivate::QPropertyBindingData &bindingData() const
1206 {
1207 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1208 return *storage->bindingData(const_cast<ThisType *>(this), true);
1209 }
1210 private:
1211 void notify(const QtPrivate::QPropertyBindingData *binding)
1212 {
1213 if (binding)
1214 binding->notifyObservers(this, qGetBindingStorage(owner()));
1215 if constexpr (HasSignal) {
1216 if constexpr (SignalTakesValue::value)
1217 (owner()->*Signal)(this->valueBypassingBindings());
1218 else
1219 (owner()->*Signal)();
1220 }
1221 }
1222 };
1223
1224 #define QT_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \
1225 static constexpr size_t _qt_property_##name##_offset() { \
1226 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1227 return offsetof(Class, name); \
1228 QT_WARNING_POP \
1229 } \
1230 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name;
1231
1232 #define QT_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, Signal) \
1233 static constexpr size_t _qt_property_##name##_offset() { \
1234 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1235 return offsetof(Class, name); \
1236 QT_WARNING_POP \
1237 } \
1238 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name;
1239
1240 #define Q_OBJECT_BINDABLE_PROPERTY(...) \
1241 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1242 QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \
1243 QT_WARNING_POP
1244
1245 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(Class, Type, name, value) \
1246 static constexpr size_t _qt_property_##name##_offset() \
1247 { \
1248 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1249 return offsetof(Class, name); \
1250 QT_WARNING_POP \
1251 } \
1252 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name = \
1253 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr>( \
1254 value);
1255
1256 #define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(Class, Type, name, value, Signal) \
1257 static constexpr size_t _qt_property_##name##_offset() \
1258 { \
1259 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1260 return offsetof(Class, name); \
1261 QT_WARNING_POP \
1262 } \
1263 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name = \
1264 QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal>( \
1265 value);
1266
1267 #define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...) \
1268 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1269 QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \
1270 QT_WARNING_POP
1271
1272 template<typename Class, typename T, auto Offset, auto Getter>
1273 class QObjectComputedProperty : public QUntypedPropertyData
1274 {
1275 Class *owner()
1276 {
1277 char *that = reinterpret_cast<char *>(this);
1278 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1279 }
1280 const Class *owner() const
1281 {
1282 char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
1283 return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
1284 }
1285
1286 public:
1287 using value_type = T;
1288 using parameter_type = T;
1289
1290 QObjectComputedProperty() = default;
1291
1292 parameter_type value() const
1293 {
1294 qGetBindingStorage(owner())->registerDependency(this);
1295 return (owner()->*Getter)();
1296 }
1297
1298 std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type, void>
1299 operator->() const
1300 {
1301 if constexpr (QTypeTraits::is_dereferenceable_v<T>)
1302 return value();
1303 else
1304 return;
1305 }
1306
1307 parameter_type operator*() const
1308 {
1309 return value();
1310 }
1311
1312 operator parameter_type() const
1313 {
1314 return value();
1315 }
1316
1317 constexpr bool hasBinding() const { return false; }
1318
1319 template<typename Functor>
1320 QPropertyChangeHandler<Functor> onValueChanged(Functor f)
1321 {
1322 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1323 return QPropertyChangeHandler<Functor>(*this, f);
1324 }
1325
1326 template<typename Functor>
1327 QPropertyChangeHandler<Functor> subscribe(Functor f)
1328 {
1329 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1330 f();
1331 return onValueChanged(f);
1332 }
1333
1334 template<typename Functor>
1335 QPropertyNotifier addNotifier(Functor f)
1336 {
1337 static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
1338 return QPropertyNotifier(*this, f);
1339 }
1340
1341 QtPrivate::QPropertyBindingData &bindingData() const
1342 {
1343 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1344 return *storage->bindingData(const_cast<QObjectComputedProperty *>(this), true);
1345 }
1346
1347 void notify() {
1348
1349 auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
1350 auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this), false);
1351 if (bd)
1352 bd->notifyObservers(this, qGetBindingStorage(owner()));
1353 }
1354 };
1355
1356 #define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \
1357 static constexpr size_t _qt_property_##name##_offset() { \
1358 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
1359 return offsetof(Class, name); \
1360 QT_WARNING_POP \
1361 } \
1362 QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;
1363
1364 #undef QT_SOURCE_LOCATION_NAMESPACE
1365
1366 QT_END_NAMESPACE
1367
1368 #endif