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