QObjectBindableProperty: Allow signals taking a value

If the signal takes a value, we pass the current value of the property
to it.
As we now use eager evaluation, accessing the current value is now
possible.

Change-Id: I5e6947a6575bfa8ca5143f56620c645d4750a686
Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Fabian Kosmale 2021-04-20 11:00:46 +02:00
parent d558ebf79b
commit cdabe1d64c
3 changed files with 41 additions and 5 deletions

View File

@ -1344,6 +1344,10 @@ QString QPropertyBindingError::description() const
\snippet code/src_corelib_kernel_qproperty.cpp 2
The change handler can optionally accept one argument, of the same type as the property,
in which case it is passed the new value of the property. Otherwise, it should take no
arguments.
If the property does not need a changed notification, you can leave out the
"NOTIFY xChanged" in the Q_PROPERTY macro as well as the last argument
of the Q_OBJECT_BINDABLE_PROPERTY and Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS

View File

@ -884,6 +884,7 @@ class QObjectBindableProperty : public QPropertyData<T>
{
using ThisType = QObjectBindableProperty<Class, T, Offset, Signal>;
static bool constexpr 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);
@ -897,8 +898,12 @@ class QObjectBindableProperty : public QPropertyData<T>
static void signalCallBack(QUntypedPropertyData *o)
{
QObjectBindableProperty *that = static_cast<QObjectBindableProperty *>(o);
if constexpr (HasSignal)
(that->owner()->*Signal)();
if constexpr (HasSignal) {
if constexpr (SignalTakesValue::value)
(that->owner()->*Signal)(that->valueBypassingBindings());
else
(that->owner()->*Signal)();
}
}
public:
using value_type = typename QPropertyData<T>::value_type;
@ -1060,8 +1065,12 @@ private:
{
if (binding)
binding->notifyObservers(this);
if constexpr (HasSignal)
(owner()->*Signal)();
if constexpr (HasSignal) {
if constexpr (SignalTakesValue::value)
(owner()->*Signal)(this->valueBypassingBindings());
else
(owner()->*Signal)();
}
}
};

View File

@ -83,6 +83,7 @@ private slots:
void quntypedBindableApi();
void readonlyConstQBindable();
void qobjectBindableManualNotify();
void qobjectBindableSignalTakingNewValue();
void testNewStuff();
void qobjectObservers();
@ -1088,7 +1089,7 @@ class MyQObject : public QObject
Q_PROPERTY(int compat READ compat WRITE setCompat NOTIFY compatChanged)
signals:
void fooChanged();
void fooChanged(int newFoo);
void barChanged();
void compatChanged();
@ -1182,6 +1183,28 @@ void tst_QProperty::qobjectBindableManualNotify()
QCOMPARE(object.foo(), 1);
}
void tst_QProperty::qobjectBindableSignalTakingNewValue()
{
// Given an object of type MyQObject,
MyQObject object;
// and tracking the values emitted via its fooChanged signal,
int newValue = -1;
QObject::connect(&object, &MyQObject::fooChanged, [&](int i){ newValue = i; } );
// when we change the property's value via the bindable interface
object.bindableFoo().setValue(1);
// we obtain the newly set value.
QCOMPARE(newValue, 1);
// The same holds true when we set a binding
QProperty<int> i {2};
object.bindableFoo().setBinding(Qt::makePropertyBinding(i));
QCOMPARE(newValue, 2);
// and when the binding gets reevaluated to a new value
i = 3;
QCOMPARE(newValue, 3);
}
void tst_QProperty::testNewStuff()
{
MyQObject testReadOnly;