From 1b6069798aa7088457eb5e033aa2fa1d809ec3e4 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 21 Jun 2022 16:25:45 +0200 Subject: Allow resetting value type properties Fixes: QTBUG-60909 Change-Id: I589c0b30cead134f746def2ffc853ff43d2598e0 Reviewed-by: Qt CI Bot Reviewed-by: Sami Shalayel Reviewed-by: Fabian Kosmale --- src/qml/qml/qqmlproperty.cpp | 146 ++++++++++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 43 deletions(-) (limited to 'src/qml/qml/qqmlproperty.cpp') diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index f2b4cc85ed..6925af297f 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1259,67 +1259,118 @@ bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlProperty return writeValueProperty(object, core, valueTypeData, value, effectiveContext(), flags); } -bool -QQmlPropertyPrivate::writeValueProperty(QObject *object, - const QQmlPropertyData &core, - const QQmlPropertyData &valueTypeData, - const QVariant &value, - const QQmlRefPointer &context, - QQmlPropertyData::WriteFlags flags) +static void removeValuePropertyBinding( + QObject *object, const QQmlPropertyData &core, + const QQmlPropertyData &valueTypeData, QQmlPropertyData::WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) - removeBinding(object, encodedIndex(core, valueTypeData)); - - bool rv = false; - if (valueTypeData.isValid()) { - auto doWrite = [&](QQmlGadgetPtrWrapper *wrapper) { - wrapper->read(object, core.coreIndex()); - rv = write(wrapper, valueTypeData, value, context, flags); - wrapper->write(object, core.coreIndex(), flags); - }; - - QQmlGadgetPtrWrapper *wrapper = context - ? QQmlGadgetPtrWrapper::instance(context->engine(), core.propType()) - : nullptr; - if (wrapper) { - doWrite(wrapper); - } else if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) { - QQmlGadgetPtrWrapper wrapper(valueType, nullptr); - doWrite(&wrapper); - } - - } else { - rv = write(object, core, value, context, flags); + if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) { + QQmlPropertyPrivate::removeBinding( + object, QQmlPropertyPrivate::encodedIndex(core, valueTypeData)); } +} +template +bool changePropertyAndWriteBack( + QObject *object, int coreIndex, QQmlGadgetPtrWrapper *wrapper, + QQmlPropertyData::WriteFlags flags, Op op) +{ + wrapper->read(object, coreIndex); + const bool rv = op(wrapper); + wrapper->write(object, coreIndex, flags); return rv; } -bool QQmlPropertyPrivate::write( - QObject *object, const QQmlPropertyData &property, const QVariant &value, - const QQmlRefPointer &context, QQmlPropertyData::WriteFlags flags) +template +bool changeThroughGadgetPtrWrapper( + QObject *object, const QQmlPropertyData &core, + const QQmlRefPointer &context, QQmlPropertyData::WriteFlags flags, + Op op) { - const QMetaType propertyMetaType = property.propType(); - const QMetaType variantMetaType = value.metaType(); + if (QQmlGadgetPtrWrapper *wrapper = context + ? QQmlGadgetPtrWrapper::instance(context->engine(), core.propType()) + : nullptr) { + return changePropertyAndWriteBack(object, core.coreIndex(), wrapper, flags, op); + } + + if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) { + QQmlGadgetPtrWrapper wrapper(valueType, nullptr); + return changePropertyAndWriteBack(object, core.coreIndex(), &wrapper, flags, op); + } + + return false; +} + +bool QQmlPropertyPrivate::writeValueProperty( + QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, + const QVariant &value, const QQmlRefPointer &context, + QQmlPropertyData::WriteFlags flags) +{ + removeValuePropertyBinding(object, core, valueTypeData, flags); + + if (!valueTypeData.isValid()) + return write(object, core, value, context, flags); + + return changeThroughGadgetPtrWrapper(object, core, context, flags, + [&](QQmlGadgetPtrWrapper *wrapper) { + return write(wrapper, valueTypeData, value, context, flags); + }); +} + +bool QQmlPropertyPrivate::resetValueProperty( + QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, + const QQmlRefPointer &context, QQmlPropertyData::WriteFlags flags) +{ + removeValuePropertyBinding(object, core, valueTypeData, flags); + + if (!valueTypeData.isValid()) + return reset(object, core, flags); + + return changeThroughGadgetPtrWrapper(object, core, context, flags, + [&](QQmlGadgetPtrWrapper *wrapper) { + return reset(wrapper, valueTypeData, flags); + }); +} + +// We need to prevent new-style bindings from being removed. +struct BindingFixer +{ + Q_DISABLE_COPY_MOVE(BindingFixer); + + BindingFixer(QObject *object, const QQmlPropertyData &property, + QQmlPropertyData::WriteFlags flags) + { + if (!property.isBindable() || !(flags & QQmlPropertyData::DontRemoveBinding)) + return; - // we need to prevent new-style bindings from being removed - QUntypedPropertyBinding untypedBinding; - if (property.isBindable() && (flags & QQmlPropertyData::DontRemoveBinding)) { QUntypedBindable bindable; void *argv[] = {&bindable}; QMetaObject::metacall(object, QMetaObject::BindableProperty, property.coreIndex(), argv); untypedBinding = bindable.binding(); - auto priv = QPropertyBindingPrivate::get(untypedBinding); - if (priv) - priv->setSticky(true); + if (auto priv = QPropertyBindingPrivate::get(untypedBinding)) + priv->setSticky(true); } - auto bindingFixer = qScopeGuard([&](){ + + ~BindingFixer() + { if (untypedBinding.isNull()) return; auto priv = QPropertyBindingPrivate::get(untypedBinding); priv->setSticky(false); - }); + } + +private: + QUntypedPropertyBinding untypedBinding; +}; + +bool QQmlPropertyPrivate::write( + QObject *object, const QQmlPropertyData &property, const QVariant &value, + const QQmlRefPointer &context, QQmlPropertyData::WriteFlags flags) +{ + const QMetaType propertyMetaType = property.propType(); + const QMetaType variantMetaType = value.metaType(); + + const BindingFixer bindingFixer(object, property, flags); if (property.isEnum()) { QMetaProperty prop = object->metaObject()->property(property.coreIndex()); @@ -1565,6 +1616,15 @@ bool QQmlPropertyPrivate::write( return true; } +bool QQmlPropertyPrivate::reset( + QObject *object, const QQmlPropertyData &property, + QQmlPropertyData::WriteFlags flags) +{ + const BindingFixer bindingFixer(object, property, flags); + property.resetProperty(object, flags); + return true; +} + QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QMetaType metaType) { if (metaType.flags() & QMetaType::PointerToQObject) { -- cgit v1.2.3