diff --git a/NEWS.md b/NEWS.md index db2d38532b..86d61e2f4d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ * Allow adding maps to image collection tilesets (#3447) * Added file system actions to the tile context menu (#3448) * Fixed possible crash in Custom Types Editor (#3465) +* Fixed display of overridden values from a nested class * Fixed ability to reset nested string and file properties (#3409) * Fixed changing nested property values for multiple objects (#3344) * Fixed possible duplication of Automapping Rules Tileset (#3462) diff --git a/src/tiled/custompropertieshelper.cpp b/src/tiled/custompropertieshelper.cpp index 197a35ad4f..a64dd7ed3a 100644 --- a/src/tiled/custompropertieshelper.cpp +++ b/src/tiled/custompropertieshelper.cpp @@ -61,13 +61,18 @@ QtVariantProperty *CustomPropertiesHelper::createProperty(const QString &name, { Q_ASSERT(!mProperties.contains(name)); + QScopedValueRollback updating(mUpdating, true); + QtVariantProperty *property = createPropertyInternal(name, value); + property->setValue(toDisplayValue(value)); + mProperties.insert(name, property); return property; } -QtVariantProperty *CustomPropertiesHelper::createPropertyInternal(const QString &name, const QVariant &value) +QtVariantProperty *CustomPropertiesHelper::createPropertyInternal(const QString &name, + const QVariant &value) { int type = value.userType(); @@ -119,11 +124,6 @@ QtVariantProperty *CustomPropertiesHelper::createPropertyInternal(const QString mPropertyTypeIds.insert(property, 0); } - // Avoids emitting propertyValueChanged - QScopedValueRollback initializing(mApplyingToChildren, true); - - property->setValue(toDisplayValue(value)); - return property; } @@ -193,63 +193,37 @@ void CustomPropertiesHelper::onValueChanged(QtProperty *property, const QVariant if (!mPropertyTypeIds.contains(property)) return; - if (!mApplyingToChildren) { + if (!mUpdating) { const auto propertyValue = fromDisplayValue(property, value); + const auto path = propertyPath(property); - // If this is the most nested change - if (!mApplyingToParent) { - const auto path = propertyPath(property); - - QScopedValueRollback updating(mEmittingValueChanged, true); - emit propertyMemberValueChanged(path, propertyValue); - } - - if (auto parent = static_cast(mPropertyParents.value(property))) { - // Bubble the value up to the parent - - auto variantMap = parent->value().toMap(); - variantMap.insert(property->propertyName(), propertyValue); - - // This might trigger another call of this function, in case of - // recursive class members. - QScopedValueRollback updating(mApplyingToParent, true); - parent->setValue(variantMap); - - property->setModified(!variantMap.isEmpty()); - } + QScopedValueRollback emittingValueChanged(mEmittingValueChanged, true); + emit propertyMemberValueChanged(path, propertyValue); } - if (!mApplyingToParent) { - if (auto type = propertyType(property); type && type->isClass()) { - // Apply the change to the children - - auto &members = static_cast(*type).members; + if (auto type = propertyType(property); type && type->isClass()) { + // Apply the change to the children - const auto subProperties = property->subProperties(); - const auto map = value.toMap(); + auto &members = static_cast(*type).members; - QScopedValueRollback updating(mApplyingToChildren, true); + const auto subProperties = property->subProperties(); + const auto map = value.toMap(); - for (QtProperty *subProperty : subProperties) { - const auto name = subProperty->propertyName(); - const bool modified = map.contains(name); - const auto value = modified ? map.value(name) - : members.value(name); + QScopedValueRollback updating(mUpdating, true); - subProperty->setModified(modified); + for (QtProperty *subProperty : subProperties) { + const auto name = subProperty->propertyName(); + const bool modified = map.contains(name); + const auto value = modified ? map.value(name) + : members.value(name); - // Avoid setting child class members as modified, just because - // the class definition sets different defaults on them. - if (!modified) { - auto memberType = propertyType(subProperty); - if (memberType && memberType->isClass()) { - static_cast(subProperty)->setValue(QVariantMap()); - continue; - } - } + // Avoid setting child class members as modified, just because + // the class definition sets different defaults on them. + const bool isParentTopLevel = !mPropertyParents.contains(property); + const bool isParentModified = property->isModified(); + subProperty->setModified(modified && (isParentTopLevel || isParentModified)); - static_cast(subProperty)->setValue(toDisplayValue(value)); - } + static_cast(subProperty)->setValue(toDisplayValue(value)); } } } @@ -292,12 +266,20 @@ void CustomPropertiesHelper::propertyTypesChanged() if (!typeId) continue; - if (const auto type = Object::propertyTypes().findTypeById(typeId)) + if (const auto type = Object::propertyTypes().findTypeById(typeId)) { setPropertyAttributes(property, *type); + + if (type->isClass()) { + // Restore the existing member values + QScopedValueRollback updating(mUpdating, true); + onValueChanged(property, property->value()); + } + } } } -void CustomPropertiesHelper::setPropertyAttributes(QtVariantProperty *property, const PropertyType &propertyType) +void CustomPropertiesHelper::setPropertyAttributes(QtVariantProperty *property, + const PropertyType &propertyType) { switch (propertyType.type) { case Tiled::PropertyType::PT_Invalid: @@ -308,8 +290,6 @@ void CustomPropertiesHelper::setPropertyAttributes(QtVariantProperty *property, // Delete any existing sub-properties deleteSubProperties(property); - const auto propertyValue = property->value().toMap(); - // Create a sub-property for each member QMapIterator it(classType.members); while (it.hasNext()) { @@ -317,14 +297,7 @@ void CustomPropertiesHelper::setPropertyAttributes(QtVariantProperty *property, const QString &name = it.key(); const QVariant &value = it.value(); - QtVariantProperty *subProperty = createPropertyInternal(name, value); - - if (propertyValue.contains(name)) { - QScopedValueRollback initializing(mApplyingToChildren, true); - subProperty->setModified(true); - subProperty->setValue(toDisplayValue(propertyValue.value(name))); - } - + auto subProperty = createPropertyInternal(name, value); property->addSubProperty(subProperty); mPropertyParents.insert(subProperty, property); } @@ -342,7 +315,7 @@ void CustomPropertiesHelper::setPropertyAttributes(QtVariantProperty *property, } // Setting these attributes leads to emission of valueChanged... - QScopedValueRollback suppressValueChanged(mApplyingToChildren, true); + QScopedValueRollback updating(mUpdating, true); if (enumType.valuesAsFlags) { mPropertyManager->setAttribute(property, QStringLiteral("flagNames"), enumType.values); diff --git a/src/tiled/custompropertieshelper.h b/src/tiled/custompropertieshelper.h index c51b154106..1006b4a071 100644 --- a/src/tiled/custompropertieshelper.h +++ b/src/tiled/custompropertieshelper.h @@ -48,6 +48,7 @@ class CustomPropertiesHelper : public QObject void clear(); bool hasProperty(QtProperty *property) const; QtVariantProperty *property(const QString &name); + const QHash &properties() const; QVariant toDisplayValue(QVariant value) const; QVariant fromDisplayValue(QtProperty *property, QVariant value) const; @@ -59,7 +60,8 @@ class CustomPropertiesHelper : public QObject void recreateProperty(QtVariantProperty *property, const QVariant &value); private: - QtVariantProperty *createPropertyInternal(const QString &name, const QVariant &value); + QtVariantProperty *createPropertyInternal(const QString &name, + const QVariant &value); void deletePropertyInternal(QtProperty *property); void deleteSubProperties(QtProperty *property); @@ -67,7 +69,8 @@ class CustomPropertiesHelper : public QObject void resetProperty(QtProperty *property); void propertyTypesChanged(); - void setPropertyAttributes(QtVariantProperty *property, const PropertyType &propertyType); + void setPropertyAttributes(QtVariantProperty *property, + const PropertyType &propertyType); const PropertyType *propertyType(QtProperty *property) const; QStringList propertyPath(QtProperty *property) const; @@ -78,8 +81,7 @@ class CustomPropertiesHelper : public QObject QHash mProperties; QHash mPropertyTypeIds; QHash mPropertyParents; - bool mApplyingToParent = false; - bool mApplyingToChildren = false; + bool mUpdating = false; bool mEmittingValueChanged = false; }; @@ -93,6 +95,11 @@ inline QtVariantProperty *CustomPropertiesHelper::property(const QString &name) return mProperties.value(name); } +inline const QHash &CustomPropertiesHelper::properties() const +{ + return mProperties; +} + inline void CustomPropertiesHelper::setMapDocument(MapDocument *mapDocument) { mMapDocument = mapDocument;