123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368 | // Copyright (C) 2020 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#ifndef QPROPERTY_H#define QPROPERTY_H#include <QtCore/qglobal.h>#include <QtCore/qshareddata.h>#include <QtCore/qstring.h>#include <QtCore/qttypetraits.h>#include <QtCore/qbindingstorage.h>#include <type_traits>#include <QtCore/qpropertyprivate.h>#if __has_include(<source_location>) && __cplusplus >= 202002L && !defined(Q_QDOC)#include <source_location>#if defined(__cpp_lib_source_location)#define QT_SOURCE_LOCATION_NAMESPACE std#define QT_PROPERTY_COLLECT_BINDING_LOCATION#if defined(Q_CC_MSVC)/* MSVC runs into an issue with constexpr with source location (error C7595) so use the factory function as a workaround */# define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation::fromStdSourceLocation(std::source_location::current())#else/* some versions of gcc in turn run into expression ‘std::source_location::current()’ is not a constant expression so don't use the workaround there */# define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::source_location::current())#endif#endif#endif#if __has_include(<experimental/source_location>) && !defined(Q_QDOC)#include <experimental/source_location>#if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)#if defined(__cpp_lib_experimental_source_location)#define QT_SOURCE_LOCATION_NAMESPACE std::experimental#define QT_PROPERTY_COLLECT_BINDING_LOCATION#define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation(std::experimental::source_location::current())#endif// defined(__cpp_lib_experimental_source_location)#endif#endif#if !defined(QT_PROPERTY_COLLECT_BINDING_LOCATION)#define QT_PROPERTY_DEFAULT_BINDING_LOCATION QPropertyBindingSourceLocation()#endif QT_BEGIN_NAMESPACE namespace Qt { Q_CORE_EXPORT voidbeginPropertyUpdateGroup(); Q_CORE_EXPORT voidendPropertyUpdateGroup();}class QScopedPropertyUpdateGroup {Q_DISABLE_COPY_MOVE(QScopedPropertyUpdateGroup)public: Q_NODISCARD_CTOR QScopedPropertyUpdateGroup(){Qt::beginPropertyUpdateGroup(); }~QScopedPropertyUpdateGroup()noexcept(false){Qt::endPropertyUpdateGroup(); }};template<typename T>class QPropertyData :public QUntypedPropertyData {protected:mutable T val =T();private:class DisableRValueRefs {};protected:staticconstexprbool UseReferences = !(std::is_arithmetic_v<T> ||std::is_enum_v<T> ||std::is_pointer_v<T>);public:using value_type = T;using parameter_type =std::conditional_t<UseReferences,const T &, T>;using rvalue_ref = typename std::conditional_t<UseReferences, T &&, DisableRValueRefs>;using arrow_operator_result =std::conditional_t<std::is_pointer_v<T>,const T &,std::conditional_t<QTypeTraits::is_dereferenceable_v<T>,const T &,void>>;QPropertyData() =default;QPropertyData(parameter_type t) :val(t) {}QPropertyData(rvalue_ref t) :val(std::move(t)) {}~QPropertyData() =default; parameter_type valueBypassingBindings()const{return val; }voidsetValueBypassingBindings(parameter_type v) { val = v; }voidsetValueBypassingBindings(rvalue_ref v) { val =std::move(v); }};// ### Qt 7: un-exportstruct Q_CORE_EXPORT QPropertyBindingSourceLocation {const char*fileName =nullptr;const char*functionName =nullptr; quint32 line =0; quint32 column =0;QPropertyBindingSourceLocation() =default;#ifdef __cpp_lib_source_locationconstexprQPropertyBindingSourceLocation(conststd::source_location &cppLocation){ fileName = cppLocation.file_name(); functionName = cppLocation.function_name(); line = cppLocation.line(); column = cppLocation.column();} QT_POST_CXX17_API_IN_EXPORTED_CLASS static consteval QPropertyBindingSourceLocation fromStdSourceLocation(conststd::source_location &cppLocation){return cppLocation;}#endif#ifdef __cpp_lib_experimental_source_locationconstexprQPropertyBindingSourceLocation(conststd::experimental::source_location &cppLocation){ fileName = cppLocation.file_name(); functionName = cppLocation.function_name(); line = cppLocation.line(); column = cppLocation.column();}#endif};template<typename Functor>class QPropertyChangeHandler;class QPropertyBindingErrorPrivate;class Q_CORE_EXPORT QPropertyBindingError {public:enum Type { NoError, BindingLoop, EvaluationError, UnknownError };QPropertyBindingError();QPropertyBindingError(Type type,const QString &description =QString());QPropertyBindingError(const QPropertyBindingError &other); QPropertyBindingError &operator=(const QPropertyBindingError &other);QPropertyBindingError(QPropertyBindingError &&other); QPropertyBindingError &operator=(QPropertyBindingError &&other);~QPropertyBindingError();boolhasError()const{return d.get() !=nullptr; } Type type()const; QString description()const;private: QSharedDataPointer<QPropertyBindingErrorPrivate> d;};class Q_CORE_EXPORT QUntypedPropertyBinding {public:// writes binding result into dataPtrusing BindingFunctionVTable =QtPrivate::BindingFunctionVTable;QUntypedPropertyBinding();QUntypedPropertyBinding(QMetaType metaType,const BindingFunctionVTable *vtable,void*function,const QPropertyBindingSourceLocation &location);template<typename Functor>QUntypedPropertyBinding(QMetaType metaType, Functor &&f,const QPropertyBindingSourceLocation &location):QUntypedPropertyBinding(metaType, &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>>, &f, location){}QUntypedPropertyBinding(QUntypedPropertyBinding &&other);QUntypedPropertyBinding(const QUntypedPropertyBinding &other); QUntypedPropertyBinding &operator=(const QUntypedPropertyBinding &other); QUntypedPropertyBinding &operator=(QUntypedPropertyBinding &&other);~QUntypedPropertyBinding();boolisNull()const; QPropertyBindingError error()const; QMetaType valueMetaType()const;explicitQUntypedPropertyBinding(QPropertyBindingPrivate *priv);private:friend class QtPrivate::QPropertyBindingData;friend class QPropertyBindingPrivate;template<typename>friend class QPropertyBinding; QPropertyBindingPrivatePtr d;};template<typename PropertyType>class QPropertyBinding :public QUntypedPropertyBinding {public:QPropertyBinding() =default;template<typename Functor>QPropertyBinding(Functor &&f,const QPropertyBindingSourceLocation &location):QUntypedPropertyBinding(QMetaType::fromType<PropertyType>(), &QtPrivate::bindingFunctionVTable<std::remove_reference_t<Functor>, PropertyType>, &f, location){}// InternalexplicitQPropertyBinding(const QUntypedPropertyBinding &binding):QUntypedPropertyBinding(binding){}};namespace Qt {template<typename Functor>automakePropertyBinding(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,std::enable_if_t<std::is_invocable_v<Functor>> * =nullptr){return QPropertyBinding<std::invoke_result_t<Functor>>(std::forward<Functor>(f), location);}}struct QPropertyObserverPrivate;struct QPropertyObserverPointer;class QPropertyObserver;class QPropertyObserverBase {public:// Internalenum ObserverTag { ObserverNotifiesBinding,// observer was installed to notify bindings that obsverved property changed ObserverNotifiesChangeHandler,// observer is a change handler, which runs on every change ObserverIsPlaceholder,// the observer before this one is currently evaluated in QPropertyObserver::notifyObservers.#if QT_DEPRECATED_SINCE(6, 6) ObserverIsAlias QT_DEPRECATED_VERSION_X_6_6("Use QProperty and add a binding to the target.")#endif};protected:using ChangeHandler =void(*)(QPropertyObserver*, QUntypedPropertyData *);private:friendstruct QPropertyDelayedNotifications;friendstruct QPropertyObserverNodeProtector;friend class QPropertyObserver;friendstruct QPropertyObserverPointer;friendstruct QPropertyBindingDataPointer;friend class QPropertyBindingPrivate; QTaggedPointer<QPropertyObserver, ObserverTag> next;// prev is a pointer to the "next" element within the previous node, or to the "firstObserverPtr" if it is the// first node.QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTag> prev;union{ QPropertyBindingPrivate *binding =nullptr; ChangeHandler changeHandler; QUntypedPropertyData *aliasData;};};class Q_CORE_EXPORT QPropertyObserver :public QPropertyObserverBase {public:constexprQPropertyObserver() =default;QPropertyObserver(QPropertyObserver &&other) noexcept; QPropertyObserver &operator=(QPropertyObserver &&other) noexcept;~QPropertyObserver();template<typename Property,QtPrivate::IsUntypedPropertyData<Property> =true>voidsetSource(const Property &property){setSource(property.bindingData()); }voidsetSource(constQtPrivate::QPropertyBindingData &property);protected:QPropertyObserver(ChangeHandler changeHandler);#if QT_DEPRECATED_SINCE(6, 6)QT_DEPRECATED_VERSION_X_6_6("This constructor was only meant for internal use. Use QProperty and add a binding to the target.")QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr);#endif QUntypedPropertyData *aliasedProperty()const{return aliasData;}private:QPropertyObserver(const QPropertyObserver &) =delete; QPropertyObserver &operator=(const QPropertyObserver &) =delete;};template<typename Functor>class QPropertyChangeHandler :public QPropertyObserver { Functor m_handler;public: Q_NODISCARD_CTOR QPropertyChangeHandler(Functor handler):QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {auto This =static_cast<QPropertyChangeHandler<Functor>*>(self); This->m_handler();}),m_handler(handler){}template<typename Property,QtPrivate::IsUntypedPropertyData<Property> =true> Q_NODISCARD_CTOR QPropertyChangeHandler(const Property &property, Functor handler):QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {auto This =static_cast<QPropertyChangeHandler<Functor>*>(self); This->m_handler();}),m_handler(handler){setSource(property);}};class QPropertyNotifier :public QPropertyObserver {std::function<void()> m_handler;public: Q_NODISCARD_CTOR QPropertyNotifier() =default;template<typename Functor> Q_NODISCARD_CTOR QPropertyNotifier(Functor handler):QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {auto This =static_cast<QPropertyNotifier *>(self); This->m_handler();}),m_handler(handler){}template<typename Functor, typename Property,QtPrivate::IsUntypedPropertyData<Property> =true> Q_NODISCARD_CTOR QPropertyNotifier(const Property &property, Functor handler):QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {auto This =static_cast<QPropertyNotifier *>(self); This->m_handler();}),m_handler(handler){setSource(property);}};template<typename T>class QProperty :public QPropertyData<T>{QtPrivate::QPropertyBindingData d;boolis_equal(const T &v){ifconstexpr(QTypeTraits::has_operator_equal_v<T>) {if(v ==this->val)return true;}return false;}public:using value_type = typename QPropertyData<T>::value_type;using parameter_type = typename QPropertyData<T>::parameter_type;using rvalue_ref = typename QPropertyData<T>::rvalue_ref;using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;QProperty() =default;explicitQProperty(parameter_type initialValue) : QPropertyData<T>(initialValue) {}explicitQProperty(rvalue_ref initialValue) : QPropertyData<T>(std::move(initialValue)) {}explicitQProperty(const QPropertyBinding<T> &binding):QProperty(){setBinding(binding); }#ifndef Q_QDOCtemplate<typename Functor>explicitQProperty(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * =nullptr):QProperty(QPropertyBinding<T>(std::forward<Functor>(f), location)){}#elsetemplate<typename Functor>explicitQProperty(Functor &&f);#endif~QProperty() =default; parameter_type value()const{ d.registerWithCurrentlyEvaluatingBinding();return this->val;} arrow_operator_result operator->()const{ifconstexpr(QTypeTraits::is_dereferenceable_v<T>) {returnvalue();}else ifconstexpr(std::is_pointer_v<T>) {value();return this->val;}else{return;}} parameter_type operator*()const{returnvalue();}operatorparameter_type()const{returnvalue();}voidsetValue(rvalue_ref newValue){ d.removeBinding();if(is_equal(newValue))return;this->val =std::move(newValue);notify();}voidsetValue(parameter_type newValue){ d.removeBinding();if(is_equal(newValue))return;this->val = newValue;notify();} QProperty<T> &operator=(rvalue_ref newValue){setValue(std::move(newValue));return*this;} QProperty<T> &operator=(parameter_type newValue){setValue(newValue);return*this;} QPropertyBinding<T>setBinding(const QPropertyBinding<T> &newBinding){return QPropertyBinding<T>(d.setBinding(newBinding,this));}boolsetBinding(const QUntypedPropertyBinding &newBinding){if(!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())return false;setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));return true;}#ifndef Q_QDOCtemplate<typename Functor> QPropertyBinding<T>setBinding(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,std::enable_if_t<std::is_invocable_v<Functor>> * =nullptr){returnsetBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));}#elsetemplate<typename Functor> QPropertyBinding<T>setBinding(Functor f);#endifboolhasBinding()const{return d.hasBinding(); } QPropertyBinding<T>binding()const{return QPropertyBinding<T>(QUntypedPropertyBinding(d.binding()));} QPropertyBinding<T>takeBinding(){return QPropertyBinding<T>(d.setBinding(QUntypedPropertyBinding(),this));}template<typename Functor> QPropertyChangeHandler<Functor>onValueChanged(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");return QPropertyChangeHandler<Functor>(*this, f);}template<typename Functor> QPropertyChangeHandler<Functor>subscribe(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");f();returnonValueChanged(f);}template<typename Functor> QPropertyNotifier addNotifier(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");returnQPropertyNotifier(*this, f);}constQtPrivate::QPropertyBindingData &bindingData()const{return d; }private:voidnotify(){ d.notifyObservers(this);}Q_DISABLE_COPY_MOVE(QProperty)};namespace Qt {template<typename PropertyType> QPropertyBinding<PropertyType>makePropertyBinding(const QProperty<PropertyType> &otherProperty,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION){returnQt::makePropertyBinding([&otherProperty]() -> PropertyType {return otherProperty; }, location);}}namespace QtPrivate {struct QBindableInterface {using Getter =void(*)(const QUntypedPropertyData *d,void*value);using Setter =void(*)(QUntypedPropertyData *d,const void*value);using BindingGetter =QUntypedPropertyBinding(*)(const QUntypedPropertyData *d);using BindingSetter =QUntypedPropertyBinding(*)(QUntypedPropertyData *d,const QUntypedPropertyBinding &binding);using MakeBinding =QUntypedPropertyBinding(*)(const QUntypedPropertyData *d,const QPropertyBindingSourceLocation &location);using SetObserver =void(*)(const QUntypedPropertyData *d, QPropertyObserver *observer);using GetMetaType =QMetaType(*)(); Getter getter; Setter setter; BindingGetter getBinding; BindingSetter setBinding; MakeBinding makeBinding; SetObserver setObserver; GetMetaType metaType;staticconstexpr quintptr MetaTypeAccessorFlag =0x1;};template<typename Property, typename =void>class QBindableInterfaceForProperty {using T = typename Property::value_type;public:// interface for computed properties. Those do not have a binding()/setBinding() method, but one can// install observers on them.staticconstexpr QBindableInterface iface = {[](const QUntypedPropertyData *d,void*value) ->void{ *static_cast<T*>(value) =static_cast<const Property *>(d)->value(); },nullptr,nullptr,nullptr,[](const QUntypedPropertyData *d,const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding {returnQt::makePropertyBinding([d]() -> T {return static_cast<const Property *>(d)->value(); }, location); },[](const QUntypedPropertyData *d, QPropertyObserver *observer) ->void{ observer->setSource(static_cast<const Property *>(d)->bindingData()); },[]() {returnQMetaType::fromType<T>(); }};};template<typename Property>class QBindableInterfaceForProperty<const Property,std::void_t<decltype(std::declval<Property>().binding())>>{using T = typename Property::value_type;public:// A bindable created from a const property results in a read-only interface, too.staticconstexpr QBindableInterface iface = {[](const QUntypedPropertyData *d,void*value) ->void{ *static_cast<T*>(value) =static_cast<const Property *>(d)->value(); },/*setter=*/nullptr,[](const QUntypedPropertyData *d) -> QUntypedPropertyBinding {return static_cast<const Property *>(d)->binding(); },/*setBinding=*/nullptr,[](const QUntypedPropertyData *d,const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding {returnQt::makePropertyBinding([d]() -> T {return static_cast<const Property *>(d)->value(); }, location); },[](const QUntypedPropertyData *d, QPropertyObserver *observer) ->void{ observer->setSource(static_cast<const Property *>(d)->bindingData()); },[]() {returnQMetaType::fromType<T>(); }};};template<typename Property>class QBindableInterfaceForProperty<Property,std::void_t<decltype(std::declval<Property>().binding())>>{using T = typename Property::value_type;public:staticconstexpr QBindableInterface iface = {[](const QUntypedPropertyData *d,void*value) ->void{ *static_cast<T*>(value) =static_cast<const Property *>(d)->value(); },[](QUntypedPropertyData *d,const void*value) ->void{static_cast<Property *>(d)->setValue(*static_cast<const T*>(value)); },[](const QUntypedPropertyData *d) -> QUntypedPropertyBinding {return static_cast<const Property *>(d)->binding(); },[](QUntypedPropertyData *d,const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding {return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },[](const QUntypedPropertyData *d,const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding {returnQt::makePropertyBinding([d]() -> T {return static_cast<const Property *>(d)->value(); }, location); },[](const QUntypedPropertyData *d, QPropertyObserver *observer) ->void{ observer->setSource(static_cast<const Property *>(d)->bindingData()); },[]() {returnQMetaType::fromType<T>(); }};};}namespace QtPrivate {// used in Q(Untyped)Bindable to print warnings about various binding errorsnamespace BindableWarnings {enum Reason { InvalidInterface, NonBindableInterface, ReadOnlyInterface }; Q_CORE_EXPORT voidprintUnsuitableBindableWarning(QAnyStringView prefix, Reason reason); Q_CORE_EXPORT voidprintMetaTypeMismatch(QMetaType actual, QMetaType expected);}namespace PropertyAdaptorSlotObjectHelpers { Q_CORE_EXPORT voidgetter(const QUntypedPropertyData *d,void*value); Q_CORE_EXPORT voidsetter(QUntypedPropertyData *d,const void*value); Q_CORE_EXPORT QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d); Q_CORE_EXPORT boolbindingWrapper(QMetaType type, QUntypedPropertyData *d,QtPrivate::QPropertyBindingFunction binding, QUntypedPropertyData *temp,void*value); Q_CORE_EXPORT QUntypedPropertyBinding setBinding(QUntypedPropertyData *d,const QUntypedPropertyBinding &binding, QPropertyBindingWrapper wrapper); Q_CORE_EXPORT voidsetObserver(const QUntypedPropertyData *d, QPropertyObserver *observer);template<typename T>boolbindingWrapper(QMetaType type, QUntypedPropertyData *d,QtPrivate::QPropertyBindingFunction binding){struct Data : QPropertyData<T>{void*data() {return&this->val; }} temp;returnbindingWrapper(type, d, binding, &temp, temp.data());}template<typename T> QUntypedPropertyBinding setBinding(QUntypedPropertyData *d,const QUntypedPropertyBinding &binding){returnsetBinding(d, binding, &bindingWrapper<T>);}template<typename T> QUntypedPropertyBinding makeBinding(const QUntypedPropertyData *d,const QPropertyBindingSourceLocation &location){returnQt::makePropertyBinding([d]() -> T { T r;getter(d, &r);return r;}, location);}template<class T>inline constexpr QBindableInterface iface = {&getter,&setter,&getBinding,&setBinding<T>,&makeBinding<T>,&setObserver,&QMetaType::fromType<T>,};}}class QUntypedBindable {friendstruct QUntypedBindablePrivate;// allows access to internal dataprotected: QUntypedPropertyData *data =nullptr;constQtPrivate::QBindableInterface *iface =nullptr;constexprQUntypedBindable(QUntypedPropertyData *d,constQtPrivate::QBindableInterface *i):data(d),iface(i){} Q_CORE_EXPORT explicitQUntypedBindable(QObject* obj,const QMetaProperty &property,constQtPrivate::QBindableInterface *i); Q_CORE_EXPORT explicitQUntypedBindable(QObject* obj,const char* property,constQtPrivate::QBindableInterface *i);public:constexprQUntypedBindable() =default;template<typename Property>QUntypedBindable(Property *p):data(const_cast<std::remove_cv_t<Property> *>(p)),iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface){Q_ASSERT(data && iface); }boolisValid()const{return data !=nullptr; }boolisBindable()const{return iface && iface->getBinding; }boolisReadOnly()const{return!(iface && iface->setBinding && iface->setObserver); } QUntypedPropertyBinding makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION)const{return iface ? iface->makeBinding(data, location) :QUntypedPropertyBinding();} QUntypedPropertyBinding takeBinding(){if(!iface)return QUntypedPropertyBinding {};// We do not have a dedicated takeBinding function pointer in the interface// therefore we synthesize takeBinding by retrieving the binding with binding// and calling setBinding with a default constructed QUntypedPropertyBinding// afterwards.if(!(iface->getBinding && iface->setBinding))return QUntypedPropertyBinding {}; QUntypedPropertyBinding binding = iface->getBinding(data); iface->setBinding(data, QUntypedPropertyBinding{});return binding;}voidobserve(QPropertyObserver *observer)const{if(iface) iface->setObserver(data, observer);#ifndef QT_NO_DEBUGelseQtPrivate::BindableWarnings::printUnsuitableBindableWarning("observe:",QtPrivate::BindableWarnings::InvalidInterface);#endif}template<typename Functor> QPropertyChangeHandler<Functor>onValueChanged(Functor f)const{ QPropertyChangeHandler<Functor>handler(f);observe(&handler);return handler;}template<typename Functor> QPropertyChangeHandler<Functor>subscribe(Functor f)const{f();returnonValueChanged(f);}template<typename Functor> QPropertyNotifier addNotifier(Functor f){ QPropertyNotifier handler(f);observe(&handler);return handler;} QUntypedPropertyBinding binding()const{if(!isBindable()) {#ifndef QT_NO_DEBUGQtPrivate::BindableWarnings::printUnsuitableBindableWarning("binding: ",QtPrivate::BindableWarnings::NonBindableInterface);#endifreturnQUntypedPropertyBinding();}return iface->getBinding(data);}boolsetBinding(const QUntypedPropertyBinding &binding){if(isReadOnly()) {#ifndef QT_NO_DEBUGconstauto errorType = iface ?QtPrivate::BindableWarnings::ReadOnlyInterface :QtPrivate::BindableWarnings::InvalidInterface;QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.", errorType);#endifreturn false;}if(!binding.isNull() && binding.valueMetaType() !=metaType()) {#ifndef QT_NO_DEBUGQtPrivate::BindableWarnings::printMetaTypeMismatch(metaType(), binding.valueMetaType());#endifreturn false;} iface->setBinding(data, binding);return true;}boolhasBinding()const{return!binding().isNull();} QMetaType metaType()const{if(!(iface && data))returnQMetaType();if(iface->metaType)return iface->metaType();// ### Qt 7: Change the metatype function to take data as its argument// special casing for QML's proxy bindable: allow multiplexing in the getter// function to retrieve the metatype from dataQ_ASSERT(iface->getter); QMetaType result; iface->getter(data,reinterpret_cast<void*>(quintptr(&result) |QtPrivate::QBindableInterface::MetaTypeAccessorFlag));return result;}};template<typename T>class QBindable :public QUntypedBindable {template<typename U>friend class QPropertyAlias;constexprQBindable(QUntypedPropertyData *d,constQtPrivate::QBindableInterface *i):QUntypedBindable(d, i){}public:usingQUntypedBindable::QUntypedBindable;explicitQBindable(const QUntypedBindable &b) :QUntypedBindable(b){if(iface &&metaType() !=QMetaType::fromType<T>()) { data =nullptr; iface =nullptr;}}explicitQBindable(QObject *obj,const QMetaProperty &property):QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {}explicitQBindable(QObject *obj,const char*property):QUntypedBindable(obj, property, &QtPrivate::PropertyAdaptorSlotObjectHelpers::iface<T>) {} QPropertyBinding<T>makeBinding(const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION)const{return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::makeBinding(location));} QPropertyBinding<T>binding()const{return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::binding());} QPropertyBinding<T>takeBinding(){return static_cast<QPropertyBinding<T> &&>(QUntypedBindable::takeBinding());}usingQUntypedBindable::setBinding; QPropertyBinding<T>setBinding(const QPropertyBinding<T> &binding){Q_ASSERT(!iface || binding.isNull() || binding.valueMetaType() ==metaType());if(iface && iface->setBinding)return static_cast<QPropertyBinding<T> &&>(iface->setBinding(data, binding));#ifndef QT_NO_DEBUGif(!iface)QtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding",QtPrivate::BindableWarnings::InvalidInterface);elseQtPrivate::BindableWarnings::printUnsuitableBindableWarning("setBinding: Could not set binding via bindable interface.",QtPrivate::BindableWarnings::ReadOnlyInterface);#endifreturn QPropertyBinding<T>();}#ifndef Q_QDOCtemplate<typename Functor> QPropertyBinding<T>setBinding(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,std::enable_if_t<std::is_invocable_v<Functor>> * =nullptr){returnsetBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));}#elsetemplate<typename Functor> QPropertyBinding<T>setBinding(Functor f);#endif T value()const{if(iface) { T result; iface->getter(data, &result);return result;}return T{};}voidsetValue(const T &value){if(iface && iface->setter) iface->setter(data, &value);}};#if QT_DEPRECATED_SINCE(6, 6)template<typename T>classQT_DEPRECATED_VERSION_X_6_6("Class was only meant for internal use, use a QProperty and add a binding to the target") QPropertyAlias :public QPropertyObserver {Q_DISABLE_COPY_MOVE(QPropertyAlias)constQtPrivate::QBindableInterface *iface =nullptr;public: QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED QPropertyAlias(QProperty<T> *property):QPropertyObserver(property),iface(&QtPrivate::QBindableInterfaceForProperty<QProperty<T>>::iface){if(iface) iface->setObserver(aliasedProperty(),this);}template<typename Property,QtPrivate::IsUntypedPropertyData<Property> =true>QPropertyAlias(Property *property):QPropertyObserver(property),iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface){if(iface) iface->setObserver(aliasedProperty(),this);}QPropertyAlias(QPropertyAlias<T> *alias):QPropertyObserver(alias->aliasedProperty()),iface(alias->iface){if(iface) iface->setObserver(aliasedProperty(),this);}QPropertyAlias(const QBindable<T> &property):QPropertyObserver(property.data),iface(property.iface){if(iface) iface->setObserver(aliasedProperty(),this);} T value()const{ T t =T();if(auto*p =aliasedProperty()) iface->getter(p, &t);return t;}operatorT()const{returnvalue(); }voidsetValue(const T &newValue){if(auto*p =aliasedProperty()) iface->setter(p, &newValue);} QPropertyAlias<T> &operator=(const T &newValue){setValue(newValue);return*this;} QPropertyBinding<T>setBinding(const QPropertyBinding<T> &newBinding){return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);}boolsetBinding(const QUntypedPropertyBinding &newBinding){return QBindable<T>(aliasedProperty(), iface).setBinding(newBinding);}#ifndef Q_QDOCtemplate<typename Functor> QPropertyBinding<T>setBinding(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,std::enable_if_t<std::is_invocable_v<Functor>> * =nullptr){returnsetBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));}#elsetemplate<typename Functor> QPropertyBinding<T>setBinding(Functor f);#endifboolhasBinding()const{return QBindable<T>(aliasedProperty(), iface).hasBinding();} QPropertyBinding<T>binding()const{return QBindable<T>(aliasedProperty(), iface).binding();} QPropertyBinding<T>takeBinding(){return QBindable<T>(aliasedProperty(), iface).takeBinding();}template<typename Functor> QPropertyChangeHandler<Functor>onValueChanged(Functor f){return QBindable<T>(aliasedProperty(), iface).onValueChanged(f);}template<typename Functor> QPropertyChangeHandler<Functor>subscribe(Functor f){return QBindable<T>(aliasedProperty(), iface).subscribe(f);}template<typename Functor> QPropertyNotifier addNotifier(Functor f){return QBindable<T>(aliasedProperty(), iface).addNotifier(f);}boolisValid()const{returnaliasedProperty() !=nullptr;} QT_WARNING_POP };#endif// QT_DEPRECATED_SINCE(6, 6)template<typename Class, typename T,auto Offset,auto Signal =nullptr>class QObjectBindableProperty :public QPropertyData<T>{using ThisType = QObjectBindableProperty<Class, T, Offset, Signal>;static boolconstexpr HasSignal = !std::is_same_v<decltype(Signal),std::nullptr_t>;using SignalTakesValue =std::is_invocable<decltype(Signal), Class, T>; Class *owner(){char*that =reinterpret_cast<char*>(this);return reinterpret_cast<Class *>(that -QtPrivate::detail::getOffset(Offset));}const Class *owner()const{char*that =const_cast<char*>(reinterpret_cast<const char*>(this));return reinterpret_cast<Class *>(that -QtPrivate::detail::getOffset(Offset));}static voidsignalCallBack(QUntypedPropertyData *o){ QObjectBindableProperty *that =static_cast<QObjectBindableProperty *>(o);ifconstexpr(HasSignal) {ifconstexpr(SignalTakesValue::value)(that->owner()->*Signal)(that->valueBypassingBindings());else(that->owner()->*Signal)();}}public:using value_type = typename QPropertyData<T>::value_type;using parameter_type = typename QPropertyData<T>::parameter_type;using rvalue_ref = typename QPropertyData<T>::rvalue_ref;using arrow_operator_result = typename QPropertyData<T>::arrow_operator_result;QObjectBindableProperty() =default;explicitQObjectBindableProperty(const T &initialValue) : QPropertyData<T>(initialValue) {}explicitQObjectBindableProperty(T &&initialValue) : QPropertyData<T>(std::move(initialValue)) {}explicitQObjectBindableProperty(const QPropertyBinding<T> &binding):QObjectBindableProperty(){setBinding(binding); }#ifndef Q_QDOCtemplate<typename Functor>explicitQObjectBindableProperty(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION, typename std::enable_if_t<std::is_invocable_r_v<T, Functor&>> * =nullptr):QObjectBindableProperty(QPropertyBinding<T>(std::forward<Functor>(f), location)){}#elsetemplate<typename Functor>explicitQObjectBindableProperty(Functor &&f);#endif parameter_type value()const{qGetBindingStorage(owner())->registerDependency(this);return this->val;} arrow_operator_result operator->()const{ifconstexpr(QTypeTraits::is_dereferenceable_v<T>) {returnvalue();}else ifconstexpr(std::is_pointer_v<T>) {value();return this->val;}else{return;}} parameter_type operator*()const{returnvalue();}operatorparameter_type()const{returnvalue();}voidsetValue(parameter_type t){auto*bd =qGetBindingStorage(owner())->bindingData(this);if(bd) bd->removeBinding();if(this->val == t)return;this->val = t;notify(bd);}voidnotify() {auto*bd =qGetBindingStorage(owner())->bindingData(this);notify(bd);}voidsetValue(rvalue_ref t){auto*bd =qGetBindingStorage(owner())->bindingData(this);if(bd) bd->removeBinding();if(this->val == t)return;this->val =std::move(t);notify(bd);} QObjectBindableProperty &operator=(rvalue_ref newValue){setValue(std::move(newValue));return*this;} QObjectBindableProperty &operator=(parameter_type newValue){setValue(newValue);return*this;} QPropertyBinding<T>setBinding(const QPropertyBinding<T> &newBinding){QtPrivate::QPropertyBindingData *bd =qGetBindingStorage(owner())->bindingData(this,true); QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding,this, HasSignal ? &signalCallBack :nullptr));return static_cast<QPropertyBinding<T> &>(oldBinding);}boolsetBinding(const QUntypedPropertyBinding &newBinding){if(!newBinding.isNull() && newBinding.valueMetaType().id() != qMetaTypeId<T>())return false;setBinding(static_cast<const QPropertyBinding<T> &>(newBinding));return true;}#ifndef Q_QDOCtemplate<typename Functor> QPropertyBinding<T>setBinding(Functor &&f,const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION,std::enable_if_t<std::is_invocable_v<Functor>> * =nullptr){returnsetBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location));}#elsetemplate<typename Functor> QPropertyBinding<T>setBinding(Functor f);#endifboolhasBinding()const{auto*bd =qGetBindingStorage(owner())->bindingData(this);return bd && bd->binding() !=nullptr;} QPropertyBinding<T>binding()const{auto*bd =qGetBindingStorage(owner())->bindingData(this);return static_cast<QPropertyBinding<T> &&>(QUntypedPropertyBinding(bd ? bd->binding() :nullptr));} QPropertyBinding<T>takeBinding(){returnsetBinding(QPropertyBinding<T>());}template<typename Functor> QPropertyChangeHandler<Functor>onValueChanged(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");return QPropertyChangeHandler<Functor>(*this, f);}template<typename Functor> QPropertyChangeHandler<Functor>subscribe(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");f();returnonValueChanged(f);}template<typename Functor> QPropertyNotifier addNotifier(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");returnQPropertyNotifier(*this, f);}constQtPrivate::QPropertyBindingData &bindingData()const{auto*storage =const_cast<QBindingStorage *>(qGetBindingStorage(owner()));return*storage->bindingData(const_cast<ThisType *>(this),true);}private:voidnotify(constQtPrivate::QPropertyBindingData *binding){if(binding) binding->notifyObservers(this,qGetBindingStorage(owner()));ifconstexpr(HasSignal) {ifconstexpr(SignalTakesValue::value)(owner()->*Signal)(this->valueBypassingBindings());else(owner()->*Signal)();}}};#define QT_OBJECT_BINDABLE_PROPERTY_3(Class, Type, name) \ static constexpr size_t _qt_property_##name##_offset() { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ return offsetof(Class, name); \ QT_WARNING_POP \ } \ QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name;#define QT_OBJECT_BINDABLE_PROPERTY_4(Class, Type, name, Signal) \ static constexpr size_t _qt_property_##name##_offset() { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ return offsetof(Class, name); \ QT_WARNING_POP \ } \ QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name;#define Q_OBJECT_BINDABLE_PROPERTY(...) \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY, __VA_ARGS__) \ QT_WARNING_POP#define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_4(Class, Type, name, value) \ static constexpr size_t _qt_property_##name##_offset() \ { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ return offsetof(Class, name); \ QT_WARNING_POP \ } \ QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr> name = \ QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, nullptr>( \ value);#define QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS_5(Class, Type, name, value, Signal) \ static constexpr size_t _qt_property_##name##_offset() \ { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ return offsetof(Class, name); \ QT_WARNING_POP \ } \ QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal> name = \ QObjectBindableProperty<Class, Type, Class::_qt_property_##name##_offset, Signal>( \ value);#define Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(...) \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ QT_OVERLOADED_MACRO(QT_OBJECT_BINDABLE_PROPERTY_WITH_ARGS, __VA_ARGS__) \ QT_WARNING_POPtemplate<typename Class, typename T,auto Offset,auto Getter>class QObjectComputedProperty :public QUntypedPropertyData { Class *owner(){char*that =reinterpret_cast<char*>(this);return reinterpret_cast<Class *>(that -QtPrivate::detail::getOffset(Offset));}const Class *owner()const{char*that =const_cast<char*>(reinterpret_cast<const char*>(this));return reinterpret_cast<Class *>(that -QtPrivate::detail::getOffset(Offset));}public:using value_type = T;using parameter_type = T;QObjectComputedProperty() =default; parameter_type value()const{qGetBindingStorage(owner())->registerDependency(this);return(owner()->*Getter)();}std::conditional_t<QTypeTraits::is_dereferenceable_v<T>, parameter_type,void>operator->()const{ifconstexpr(QTypeTraits::is_dereferenceable_v<T>)returnvalue();elsereturn;} parameter_type operator*()const{returnvalue();}operatorparameter_type()const{returnvalue();}constexprboolhasBinding()const{return false; }template<typename Functor> QPropertyChangeHandler<Functor>onValueChanged(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");return QPropertyChangeHandler<Functor>(*this, f);}template<typename Functor> QPropertyChangeHandler<Functor>subscribe(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");f();returnonValueChanged(f);}template<typename Functor> QPropertyNotifier addNotifier(Functor f){static_assert(std::is_invocable_v<Functor>,"Functor callback must be callable without any parameters");returnQPropertyNotifier(*this, f);}QtPrivate::QPropertyBindingData &bindingData()const{auto*storage =const_cast<QBindingStorage *>(qGetBindingStorage(owner()));return*storage->bindingData(const_cast<QObjectComputedProperty *>(this),true);}voidnotify() {// computed property can't store a binding, so there's nothing to markauto*storage =const_cast<QBindingStorage *>(qGetBindingStorage(owner()));auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this),false);if(bd) bd->notifyObservers(this,qGetBindingStorage(owner()));}};#define Q_OBJECT_COMPUTED_PROPERTY(Class, Type, name, ...) \ static constexpr size_t _qt_property_##name##_offset() { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ return offsetof(Class, name); \ QT_WARNING_POP \ } \ QObjectComputedProperty<Class, Type, Class::_qt_property_##name##_offset, __VA_ARGS__> name;#undef QT_SOURCE_LOCATION_NAMESPACE QT_END_NAMESPACE #endif// QPROPERTY_H
|