From 195d9c01b0401774e9f02219200b7bd5acf43e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 28 Jul 2023 16:48:52 +0200 Subject: [PATCH] Fixed crash when changing file member of custom class This crash was caused by an infinite recursion happening when changing top-level FilePath values. It only affected Qt 6 builds, because two QVariant values that both hold a FilePath value always compared as unequal due to FilePath not defining a comparision operator. In addition to adding the comparison operator, I've also added a condition to the updating of the property value. It should only be necessary to update the top-level value when a nested value was changed. Further more, it now sets mUpdatingDetails as another protection against recursive calls. For completeness I've also added the comparision operator to PropertyValue and ObjectRef, though they would not have caused problems in this context since they're not used as property display values. Closes #3783 --- NEWS.md | 1 + src/libtiled/properties.h | 9 +++++++++ src/tiled/propertytypeseditor.cpp | 13 +++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5a83d92a98..c97c2bf3b8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ * Scripting: Added API for editing tile layers using terrain sets (with a-morphous, #3758) * Scripting: Support erasing tiles in Tool.preview and TileMap.merge * Scripting: Added WangSet.effectiveTypeForColor +* Fixed crash when changing file property of custom class (#3783) * Fixed object preview position with parallax factor on group layer (#3669) * Fixed hover highlight rendering with active parallax factor (#3669) * Fixed updating of object selection outlines when changing parallax factor (#3669) diff --git a/src/libtiled/properties.h b/src/libtiled/properties.h index 4f32db6a8d..a27d972f7d 100644 --- a/src/libtiled/properties.h +++ b/src/libtiled/properties.h @@ -60,6 +60,9 @@ class TILEDSHARED_EXPORT PropertyValue const PropertyType *type() const; QString typeName() const; + + bool operator==(const PropertyValue &o) const + { return typeId == o.typeId && value == o.value; } }; class TILEDSHARED_EXPORT FilePath @@ -70,6 +73,9 @@ class TILEDSHARED_EXPORT FilePath public: QUrl url; + bool operator==(const FilePath &o) const + { return url == o.url; } + static QString toString(const FilePath &path); static FilePath fromString(const QString &string); }; @@ -82,6 +88,9 @@ class TILEDSHARED_EXPORT ObjectRef public: int id; + bool operator==(const ObjectRef &o) const + { return id == o.id; } + static int toInt(const ObjectRef &ref) { return ref.id; } static ObjectRef fromInt(int id) { return ObjectRef { id }; } }; diff --git a/src/tiled/propertytypeseditor.cpp b/src/tiled/propertytypeseditor.cpp index c6b4d19c15..8667fb999e 100644 --- a/src/tiled/propertytypeseditor.cpp +++ b/src/tiled/propertytypeseditor.cpp @@ -1133,13 +1133,18 @@ void PropertyTypesEditor::memberValueChanged(const QStringList &path, const QVar if (!classType) return; - auto &topLevelName = path.first(); - if (!setPropertyMemberValue(classType->members, path, value)) return; - if (auto property = mPropertiesHelper->property(topLevelName)) - property->setValue(mPropertiesHelper->toDisplayValue(classType->members.value(topLevelName))); + // When a nested property was changed, we need to update the value of the + // top-level property to match. + if (path.size() > 1) { + auto &topLevelName = path.first(); + if (auto property = mPropertiesHelper->property(topLevelName)) { + QScopedValueRollback updatingDetails(mUpdatingDetails, true); + property->setValue(mPropertiesHelper->toDisplayValue(classType->members.value(topLevelName))); + } + } applyPropertyTypes(); }