diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-05-25 12:54:51 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-05-27 14:41:52 +0200 |
commit | a64a0ce3317afa1ff633d1d08904c967dbc6ecad (patch) | |
tree | 51fe001645681907fbeefce9236809a805d7b4ff /src/corelib/kernel/qproperty.h | |
parent | 0a07f9528c56615a38b305e8ba8b8b9dc433f260 (diff) |
Add a QPropertyAlias
A property alias is the equivalent of the "alias" keyword in QML. It
provides the same API as QProperty, but redirects any access to the
QProperty it was initialized with. When the original property is
destroyed the binding becomes invalid and ignores any further acccess.
Task-number: QTBUG-84370
Change-Id: I0aef8d50e73a2aa9e7703d51194d4c5480573578
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/kernel/qproperty.h')
-rw-r--r-- | src/corelib/kernel/qproperty.h | 159 |
1 files changed, 152 insertions, 7 deletions
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index 938de61fd5..76c41f356c 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -378,10 +378,10 @@ class Q_CORE_EXPORT QPropertyObserver public: // Internal enum ObserverTag { - ObserverNotifiesBinding = 0x0, - ObserverNotifiesChangeHandler = 0x1, + ObserverNotifiesBinding, + ObserverNotifiesChangeHandler, + ObserverNotifiesAlias, }; - Q_DECLARE_FLAGS(ObserverTags, ObserverTag) QPropertyObserver(); QPropertyObserver(QPropertyObserver &&other); @@ -394,18 +394,26 @@ public: protected: QPropertyObserver(void (*callback)(QPropertyObserver*, void *)); + QPropertyObserver(void *aliasedPropertyPtr); + + template<typename PropertyType> + QProperty<PropertyType> *aliasedProperty() const + { + return reinterpret_cast<QProperty<PropertyType> *>(aliasedPropertyPtr); + } private: void setSource(QtPrivate::QPropertyBase &property); - QTaggedPointer<QPropertyObserver, ObserverTags> next; + 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, ObserverTags> prev; + QtPrivate::QTagPreservingPointerToPointer<QPropertyObserver, ObserverTag> prev; union { QPropertyBindingPrivate *bindingToMarkDirty = nullptr; void (*changeHandler)(QPropertyObserver*, void *); + quintptr aliasedPropertyPtr; }; QPropertyObserver(const QPropertyObserver &) = delete; @@ -416,8 +424,6 @@ private: friend class QPropertyBindingPrivate; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QPropertyObserver::ObserverTags) - template <typename Functor> class QPropertyChangeHandler : public QPropertyObserver { @@ -487,6 +493,145 @@ struct QPropertyMemberChangeHandler<PropertyMember, Callback> : public QProperty } }; +template<typename T> +class QPropertyAlias : public QPropertyObserver +{ + Q_DISABLE_COPY_MOVE(QPropertyAlias) +public: + QPropertyAlias(QProperty<T> *property) + : QPropertyObserver(property) + { + if (property) + setSource(*property); + } + + QPropertyAlias(QPropertyAlias<T> *alias) + : QPropertyAlias(alias->aliasedProperty<T>()) + {} + + T value() const + { + if (auto *p = aliasedProperty<T>()) + return p->value(); + return T(); + } + + operator T() const { return value(); } + + void setValue(T &&newValue) + { + if (auto *p = aliasedProperty<T>()) + p->setValue(std::move(newValue)); + } + + void setValue(const T &newValue) + { + if (auto *p = aliasedProperty<T>()) + p->setValue(newValue); + } + + QPropertyAlias<T> &operator=(T &&newValue) + { + if (auto *p = aliasedProperty<T>()) + *p = std::move(newValue); + return *this; + } + + QPropertyAlias<T> &operator=(const T &newValue) + { + if (auto *p = aliasedProperty<T>()) + *p = newValue; + return *this; + } + + QPropertyAlias<T> &operator=(const QPropertyBinding<T> &newBinding) + { + setBinding(newBinding); + return *this; + } + + QPropertyAlias<T> &operator=(QPropertyBinding<T> &&newBinding) + { + setBinding(std::move(newBinding)); + return *this; + } + + QPropertyBinding<T> setBinding(const QPropertyBinding<T> &newBinding) + { + if (auto *p = aliasedProperty<T>()) + return p->setBinding(newBinding); + return QPropertyBinding<T>(); + } + + QPropertyBinding<T> setBinding(QPropertyBinding<T> &&newBinding) + { + if (auto *p = aliasedProperty<T>()) + return p->setBinding(std::move(newBinding)); + return QPropertyBinding<T>(); + } + + bool setBinding(const QUntypedPropertyBinding &newBinding) + { + if (auto *p = aliasedProperty<T>()) + return p->setBinding(newBinding); + return false; + } + +#ifndef Q_CLANG_QDOC + template <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) + { + return setBinding(Qt::makePropertyBinding(std::forward<Functor>(f), location)); + } +#else + template <typename Functor> + QPropertyBinding<T> setBinding(Functor f); +#endif + + bool hasBinding() const + { + if (auto *p = aliasedProperty<T>()) + return p->hasBinding(); + return false; + } + + QPropertyBinding<T> binding() const + { + if (auto *p = aliasedProperty<T>()) + return p->binding(); + return QPropertyBinding<T>(); + } + + QPropertyBinding<T> takeBinding() + { + if (auto *p = aliasedProperty<T>()) + return p->takeBinding(); + return QPropertyBinding<T>(); + } + + template<typename Functor> + QPropertyChangeHandler<Functor> onValueChanged(Functor f) + { + if (auto *p = aliasedProperty<T>()) + return p->onValueChanged(f); + return QPropertyChangeHandler<Functor>(f); + } + + template<typename Functor> + QPropertyChangeHandler<Functor> subscribe(Functor f) + { + if (auto *p = aliasedProperty<T>()) + return p->subscribe(f); + return QPropertyChangeHandler<Functor>(f); + } + + bool isValid() const + { + return aliasedProperty<T>() != nullptr; + } +}; QT_END_NAMESPACE |