From cc710ab71be78fd795cdfe1ef78299201126b004 Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Fri, 8 Aug 2025 14:58:03 +0200 Subject: [PATCH 1/2] Core: Add test for a prop rename with expression --- tests/src/App/Property.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/src/App/Property.cpp b/tests/src/App/Property.cpp index 6eaab505cb..f21893cdf0 100644 --- a/tests/src/App/Property.cpp +++ b/tests/src/App/Property.cpp @@ -321,6 +321,43 @@ TEST_F(RenameProperty, updateExpressionDifferentDocument) doc->removeObject(varSet2->getNameInDocument()); } +// Test if we can rename a property which value is the result of an expression +TEST_F(RenameProperty, renamePropertyWithExpression) +{ + // Arrange + auto* prop2 = freecad_cast( + varSet->addDynamicProperty("App::PropertyInteger", "Variable2", "Variables")); + prop2->setValue(Value); + + App::ObjectIdentifier path(*prop); + std::shared_ptr expr(App::Expression::parse(varSet, "Variable2")); + varSet->setExpression(path, expr); + varSet->ExpressionEngine.execute(); + + // Assert before the rename + EXPECT_EQ(prop2->getValue(), Value); + EXPECT_EQ(prop->getValue(), Value); + + // Act + bool isRenamed = varSet->renameDynamicProperty(prop, "NewName"); + varSet->ExpressionEngine.execute(); + + // Assert after the rename + EXPECT_TRUE(isRenamed); + EXPECT_STREQ(varSet->getPropertyName(prop), "NewName"); + EXPECT_EQ(prop->getValue(), Value); + EXPECT_EQ(varSet->getDynamicPropertyByName("Variable"), nullptr); + EXPECT_EQ(varSet->getDynamicPropertyByName("NewName"), prop); + + // Act + prop2->setValue(Value + 1); + varSet->ExpressionEngine.execute(); + + // Assert + EXPECT_EQ(prop2->getValue(), Value + 1); + EXPECT_EQ(prop->getValue(), Value + 1); +} + // Tests whether we can rename a property and undo it TEST_F(RenameProperty, undoRenameProperty) { From 8b8d4eb32a771df0ee28542fb626ab80c849f33e Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Fri, 8 Aug 2025 15:00:43 +0200 Subject: [PATCH 2/2] Core: Add logic for updating exprs on prop rename --- src/App/DocumentObject.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index b21509cbe0..cf572492fb 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -32,16 +32,17 @@ #include #endif -#include #include #include #include #include +#include "Expression.h" #include "Application.h" #include "ElementNamingUtils.h" #include "Document.h" #include "DocumentObject.h" +#include "DocumentObjectPy.h" #include "DocumentObjectExtension.h" #include "DocumentObjectGroup.h" #include "GeoFeatureGroupExtension.h" @@ -715,10 +716,33 @@ bool DocumentObject::removeDynamicProperty(const char* name) bool DocumentObject::renameDynamicProperty(Property* prop, const char* name) { std::string oldName = prop->getName(); + + auto expressions = ExpressionEngine.getExpressions(); + std::vector> expressionsToMove; + std::vector idsWithExprsToRemove; + + for (const auto& [id, expr] : expressions) { + if (id.getProperty() == prop) { + idsWithExprsToRemove.push_back(id); + expressionsToMove.emplace_back(expr->copy()); + } + } + + for (const auto& it : idsWithExprsToRemove) { + ExpressionEngine.setValue(it, std::shared_ptr()); + } + bool renamed = TransactionalObject::renameDynamicProperty(prop, name); if (renamed && _pDoc) { _pDoc->renamePropertyOfObject(this, prop, oldName.c_str()); } + + + App::ObjectIdentifier idNewProp(prop->getContainer(), std::string(name)); + for (auto& exprToMove : expressionsToMove) { + ExpressionEngine.setValue(idNewProp, exprToMove); + } + return renamed; }