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.
*/
/*!
\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
be notified.
This can be useful for properties which do not only depend on bindable properties,
but also on non-bindable properties or some other state.
Programmatically signals a change of the property. Any binding which depend on it will
be notified, and if the property has a signal, it will be emitted.
\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);
}
void notify() {
auto *bd = qGetBindingStorage(owner())->bindingData(this);
notify(bd);
}
void setValue(rvalue_ref t)
{
auto *bd = qGetBindingStorage(owner())->bindingData(this);

View File

@ -82,6 +82,7 @@ private slots:
void bindingValueReplacement();
void quntypedBindableApi();
void readonlyConstQBindable();
void qobjectBindableManualNotify();
void testNewStuff();
void qobjectObservers();
@ -1137,6 +1138,50 @@ public:
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()
{
MyQObject testReadOnly;