Add QObjectBindableProperyt::notify

This mirrors the functionality of QObjectCompatProperty::notify, and can
be useful to delay notifications until a class invariant has been
restored.

Change-Id: I1c16a0b1537a1b53d144c8abe48e546553edf877
Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Fabian Kosmale 2021-04-19 16:52:09 +02:00
parent 6969496e00
commit d558ebf79b
3 changed files with 60 additions and 7 deletions

View File

@ -1567,7 +1567,6 @@ QString QPropertyBindingError::description() const
owner is notified via the Callback function. owner is notified via the Callback function.
*/ */
/*! /*!
\fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Functor &&f) \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Functor &&f)
@ -1600,14 +1599,18 @@ QString QPropertyBindingError::description() const
*/ */
/*! /*!
\fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::markDirty() \fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::notify()
Programatically sets the property dirty. Any binding which depend on it will Programmatically signals a change of the property. Any binding which depend on it will
be notified. be notified, and if the property has a signal, it will be emitted.
This can be useful for properties which do not only depend on bindable properties,
but also on non-bindable properties or some other state.
\sa QProperty::markDirty() This can be useful in combination with setValueBypassingBindings to defer signalling the change
until a class invariant has been restored.
\note If this property has a binding (i.e. hasBinding() returns true), that binding is not reevaluated when
notify() is called. Any binding depending on this property is still reevaluated as usual.
\sa Qt::beginProperytUpdateGroup(), setValueBypassingBindings()
*/ */
/*! /*!

View File

@ -962,6 +962,11 @@ public:
notify(bd); notify(bd);
} }
void notify() {
auto *bd = qGetBindingStorage(owner())->bindingData(this);
notify(bd);
}
void setValue(rvalue_ref t) void setValue(rvalue_ref t)
{ {
auto *bd = qGetBindingStorage(owner())->bindingData(this); auto *bd = qGetBindingStorage(owner())->bindingData(this);

View File

@ -82,6 +82,7 @@ private slots:
void bindingValueReplacement(); void bindingValueReplacement();
void quntypedBindableApi(); void quntypedBindableApi();
void readonlyConstQBindable(); void readonlyConstQBindable();
void qobjectBindableManualNotify();
void testNewStuff(); void testNewStuff();
void qobjectObservers(); void qobjectObservers();
@ -1137,6 +1138,50 @@ public:
Q_OBJECT_COMPAT_PROPERTY(MyQObject, int, compatData, &MyQObject::setCompat) Q_OBJECT_COMPAT_PROPERTY(MyQObject, int, compatData, &MyQObject::setCompat)
}; };
void tst_QProperty::qobjectBindableManualNotify()
{
// Given an object of type MyQObject,
MyQObject object;
// track its foo property's change count
auto bindable = object.bindableFoo();
int fooChangeCount = 0;
auto changeHandler = bindable.onValueChanged([&](){++fooChangeCount;});
// and how many changed signals it emits.
QSignalSpy fooChangedSpy(&object, &MyQObject::fooChanged);
// If we bypass the bindings system,
object.fooData.setValueBypassingBindings(42);
// there is no change.
QCOMPARE(fooChangeCount, 0);
QCOMPARE(fooChangedSpy.count(), 0);
// Once we notify manually
object.fooData.notify();
// observers are notified and the signal arrives.
QCOMPARE(fooChangeCount, 1);
QCOMPARE(fooChangedSpy.count(), 1);
// If we set a binding
int i = 1;
object.fooData.setBinding([&](){return i;});
// then the value changes
QCOMPARE(object.foo(), 1);
// and the change and signal count are incremented.
QCOMPARE(fooChangeCount, 2);
QCOMPARE(fooChangedSpy.count(), 2);
// Changing a non-property won't trigger any notification.
i = 2;
QCOMPARE(fooChangeCount, 2);
QCOMPARE(fooChangedSpy.count(), 2);
// Manually triggering the notification
object.fooData.notify();
// increments the change count
QCOMPARE(fooChangeCount, 3);
QCOMPARE(fooChangedSpy.count(), 3);
// but doesn't actually cause a binding reevaluation.
QCOMPARE(object.foo(), 1);
}
void tst_QProperty::testNewStuff() void tst_QProperty::testNewStuff()
{ {
MyQObject testReadOnly; MyQObject testReadOnly;