summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2021-04-29 14:08:50 +0200
committerLars Knoll <lars.knoll@qt.io>2021-06-01 16:29:15 +0200
commit6c1a9f2b4d4e0d2bcea0989c852ed1c653588154 (patch)
tree34365f5f390cb6d8fae16743adb23825caa68e2b /src/corelib
parentde15836dbf5007092c19bc9ab15ca3d1a36901ad (diff)
Simplify storing of notification objects
QPropertyChangeHandler is a templated class and it's argument is a functor. That makes it inherently cumbersome to use the class in any context where the change handler needs to be stored. Introduce a QPropertyNotifier class that stores the functor in a std::function<void()>, and add a QProperty::addNotifier() method that can be used instead of onValueChanged(). Also make QPropertyNotifier default constructible. This significantly simplifies the code that needs to be written and makes it possible to store notifications as class members without major hassle. Fixes: QTBUG-92980 Change-Id: Id5b7baec093b9ac0467946cded943d92ad21030b Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qproperty.cpp97
-rw-r--r--src/corelib/kernel/qproperty.h62
-rw-r--r--src/corelib/kernel/qproperty_p.h7
3 files changed, 159 insertions, 7 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index 86a8285bc1..22e9e2d6e0 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -958,6 +958,18 @@ QString QPropertyBindingError::description() const
*/
/*!
+ \fn template<typename Functor> QPropertyNotifier QUntypedBindable::addNotifier(Functor f)
+
+ Installs \a f as a change handler. Whenever the underlying property changes, \a f will be called, as
+ long as the returned \c QPropertyNotifier and the property are kept alive.
+
+ This method is in some cases easier to use than onValueChanged(), as the returned object is not a template.
+ It can therefore more easily be stored, e.g. as a member in a class.
+
+ \sa onValueChanged(), subscribe()
+*/
+
+/*!
\fn QUntypedPropertyBinding QUntypedBindable::binding() const
Returns the underlying property's binding if there is any, or a default
@@ -1247,7 +1259,7 @@ QString QPropertyBindingError::description() const
is either called immediately, or deferred, depending on the context.
The callback \a f is expected to be a type that has a plain call operator () without any
- parameters. This means that you can provide a C++ lambda expression, an std::function
+ parameters. This means that you can provide a C++ lambda expression, a std::function
or even a custom struct with a call operator.
The returned property change handler object keeps track of the registration. When it
@@ -1261,12 +1273,31 @@ QString QPropertyBindingError::description() const
the value of the property changes in the future. On each value change, the handler
is either called immediately, or deferred, depending on the context.
+ The callback \a f is expected to be a type that can be copied and has a plain call
+ operator() without any parameters. This means that you can provide a C++ lambda expression,
+ a std::function or even a custom struct with a call operator.
+
+ The returned property change handler object keeps track of the subscription. When it
+ goes out of scope, the callback is unsubscribed.
+*/
+
+/*!
+ \fn QPropertyNotifier QProperty<T>::addNotifier(Functor f)
+
+ Subscribes the given functor \a f as a callback that is called whenever
+ the value of the property changes.
+
The callback \a f is expected to be a type that has a plain call operator () without any
- parameters. This means that you can provide a C++ lambda expression, an std::function
+ parameters. This means that you can provide a C++ lambda expression, a std::function
or even a custom struct with a call operator.
The returned property change handler object keeps track of the subscription. When it
goes out of scope, the callback is unsubscribed.
+
+ This method is in some cases easier to use than onValueChanged(), as the returned object is not a template.
+ It can therefore more easily be stored, e.g. as a member in a class.
+
+ \sa onValueChanged(), subscribe()
*/
/*!
@@ -1664,7 +1695,7 @@ QString QPropertyBindingError::description() const
is either called immediately, or deferred, depending on the context.
The callback \a f is expected to be a type that has a plain call operator () without any
- parameters. This means that you can provide a C++ lambda expression, an std::function
+ parameters. This means that you can provide a C++ lambda expression, a std::function
or even a custom struct with a call operator.
The returned property change handler object keeps track of the registration. When it
@@ -1679,11 +1710,30 @@ QString QPropertyBindingError::description() const
is either called immediately, or deferred, depending on the context.
The callback \a f is expected to be a type that has a plain call operator () without any
- parameters. This means that you can provide a C++ lambda expression, an std::function
+ parameters. This means that you can provide a C++ lambda expression, a std::function
+ or even a custom struct with a call operator.
+
+ The returned property change handler object keeps track of the subscription. When it
+ goes out of scope, the callback is unsubscribed.
+*/
+
+/*!
+ \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyNotifier QObjectBindableProperty<Class, T, offset, Callback>::addNotifier(Functor f)
+
+ Subscribes the given functor \a f as a callback that is called whenever
+ the value of the property changes.
+
+ The callback \a f is expected to be a type that has a plain call operator () without any
+ parameters. This means that you can provide a C++ lambda expression, a std::function
or even a custom struct with a call operator.
The returned property change handler object keeps track of the subscription. When it
goes out of scope, the callback is unsubscribed.
+
+ This method is in some cases easier to use than onValueChanged(), as the returned object is not a template.
+ It can therefore more easily be stored, e.g. as a member in a class.
+
+ \sa onValueChanged(), subscribe()
*/
/*!
@@ -1698,7 +1748,7 @@ QString QPropertyBindingError::description() const
\ingroup tools
- QPropertyChangeHandler\<PropertyType, Functor\> is created when registering a
+ QPropertyChangeHandler\<Functor\> is created when registering a
callback on a QProperty to listen to changes to the property's value, using QProperty::onValueChanged
and QProperty::subscribe. As long as the change handler is alive, the callback remains installed.
@@ -1706,6 +1756,20 @@ QString QPropertyBindingError::description() const
*/
/*!
+ \class QPropertyNotifier
+ \inmodule QtCore
+ \brief The QPropertyNotifier class controls the lifecycle of change callback installed on a QProperty.
+
+ \ingroup tools
+
+ QPropertyNotifier is created when registering a
+ callback on a QProperty to listen to changes to the property's value, using QProperty::addNotifier.
+ As long as the change handler is alive, the callback remains installed.
+
+ A handler instance can be transferred between C++ scopes using move semantics.
+*/
+
+/*!
\class QPropertyAlias
\inmodule QtCore
\internal
@@ -1881,7 +1945,7 @@ QString QPropertyBindingError::description() const
is either called immediately, or deferred, depending on the context.
The callback \a f is expected to be a type that has a plain call operator () without any
- parameters. This means that you can provide a C++ lambda expression, an std::function
+ parameters. This means that you can provide a C++ lambda expression, a std::function
or even a custom struct with a call operator.
The returned property change handler object keeps track of the registration. When it
@@ -1896,7 +1960,7 @@ QString QPropertyBindingError::description() const
is either called immediately, or deferred, depending on the context.
The callback \a f is expected to be a type that has a plain call operator () without any
- parameters. This means that you can provide a C++ lambda expression, an std::function
+ parameters. This means that you can provide a C++ lambda expression, a std::function
or even a custom struct with a call operator.
The returned property change handler object keeps track of the subscription. When it
@@ -1904,6 +1968,25 @@ QString QPropertyBindingError::description() const
*/
/*!
+ \fn template <typename T> QPropertyNotifier QPropertyAlias<T>::addNotifier(Functor f)
+
+ Subscribes the given functor \a f as a callback that is called whenever
+ the value of the aliased property changes.
+
+ The callback \a f is expected to be a type that has a plain call operator () without any
+ parameters. This means that you can provide a C++ lambda expression, a std::function
+ or even a custom struct with a call operator.
+
+ The returned property change handler object keeps track of the subscription. When it
+ goes out of scope, the callback is unsubscribed.
+
+ This method is in some cases easier to use than onValueChanged(), as the returned object is not a template.
+ It can therefore more easily be stored, e.g. as a member in a class.
+
+ \sa onValueChanged(), subscribe()
+*/
+
+/*!
\fn template <typename T> bool QPropertyAlias<T>::isValid() const
Returns true if the aliased property still exists; false otherwise.
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index 5a386f857e..5deb8fa9b7 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -294,6 +294,33 @@ public:
}
};
+class [[nodiscard]] QPropertyNotifier : public QPropertyObserver
+{
+ std::function<void()> m_handler;
+public:
+ QPropertyNotifier() = default;
+ template<typename Functor>
+ QPropertyNotifier(Functor handler)
+ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
+ auto This = static_cast<QPropertyNotifier *>(self);
+ This->m_handler();
+ })
+ , m_handler(handler)
+ {
+ }
+
+ template<typename Functor, typename Property, typename = typename Property::InheritsQUntypedPropertyData>
+ 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>
{
@@ -442,6 +469,13 @@ public:
return onValueChanged(f);
}
+ template<typename Functor>
+ QPropertyNotifier addNotifier(Functor f)
+ {
+ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
+ return QPropertyNotifier(*this, f);
+ }
+
const QtPrivate::QPropertyBindingData &bindingData() const { return d; }
private:
void notify()
@@ -630,6 +664,14 @@ public:
return onValueChanged(f);
}
+ template<typename Functor>
+ QPropertyNotifier addNotifier(Functor f)
+ {
+ QPropertyNotifier handler(f);
+ observe(&handler);
+ return handler;
+ }
+
QUntypedPropertyBinding binding() const
{
if (!isBindable()) {
@@ -871,6 +913,12 @@ public:
return QBindable<T>(aliasedProperty(), iface).subscribe(f);
}
+ template<typename Functor>
+ QPropertyNotifier addNotifier(Functor f)
+ {
+ return QBindable<T>(aliasedProperty(), iface).notify(f);
+ }
+
bool isValid() const
{
return aliasedProperty() != nullptr;
@@ -1109,6 +1157,13 @@ public:
return onValueChanged(f);
}
+ template<typename Functor>
+ QPropertyNotifier addNotifier(Functor f)
+ {
+ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
+ return QPropertyNotifier(*this, f);
+ }
+
const QtPrivate::QPropertyBindingData &bindingData() const
{
auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
@@ -1238,6 +1293,13 @@ public:
return onValueChanged(f);
}
+ template<typename Functor>
+ QPropertyNotifier addNotifier(Functor f)
+ {
+ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
+ return QPropertyNotifier(*this, f);
+ }
+
QtPrivate::QPropertyBindingData &bindingData() const
{
auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index 7cae247601..e92c8f878a 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -570,6 +570,13 @@ public:
return onValueChanged(f);
}
+ template<typename Functor>
+ QPropertyNotifier addNotifier(Functor f)
+ {
+ static_assert(std::is_invocable_v<Functor>, "Functor callback must be callable without any parameters");
+ return QPropertyNotifier(*this, f);
+ }
+
QtPrivate::QPropertyBindingData &bindingData() const
{
auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));