diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 4f6c29466a..eff22db584 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -3628,9 +3628,10 @@ void Document::_removeObject(DocumentObject* pcObject) else { // for a rollback delete the object signalTransactionRemove(*pcObject, 0); - breakDependency(pcObject, true); } + breakDependency(pcObject, true); + // remove from map pcObject->setStatus(ObjectStatus::Remove, false); // Unset the bit to be on the safe side d->objectIdMap.erase(pcObject->_Id); diff --git a/src/App/Graphviz.cpp b/src/App/Graphviz.cpp index 2971075ef7..567dc0728a 100644 --- a/src/App/Graphviz.cpp +++ b/src/App/Graphviz.cpp @@ -120,7 +120,14 @@ void Document::exportGraphviz(std::ostream& out) const */ std::string getId(const DocumentObject * docObj) { - return std::string((docObj)->getDocument()->getName()) + "#" + docObj->getNameInDocument(); + std::string id; + if (docObj->isAttachedToDocument()) { + auto doc = docObj->getDocument(); + id.append(doc->getName()); + id.append("#"); + id.append(docObj->getNameInDocument()); + } + return id; } /** @@ -437,11 +444,14 @@ void Document::exportGraphviz(std::ostream& out) const if (obj) { std::map::const_iterator item = GlobalVertexList.find(getId(obj)); - if (item == GlobalVertexList.end()) - add(obj, - std::string(obj->getDocument()->getName()) + "#" + obj->getNameInDocument(), - std::string(obj->getDocument()->getName()) + "#" + obj->Label.getValue(), - CSSubgraphs); + if (item == GlobalVertexList.end()) { + if (obj->isAttachedToDocument()) { + add(obj, + std::string(obj->getDocument()->getName()) + "#" + obj->getNameInDocument(), + std::string(obj->getDocument()->getName()) + "#" + obj->Label.getValue(), + CSSubgraphs); + } + } } } } diff --git a/src/Mod/PartDesign/CMakeLists.txt b/src/Mod/PartDesign/CMakeLists.txt index c48cc9679b..28cd8003f9 100644 --- a/src/Mod/PartDesign/CMakeLists.txt +++ b/src/Mod/PartDesign/CMakeLists.txt @@ -55,6 +55,7 @@ set(PartDesign_TestScripts PartDesignTests/TestThickness.py PartDesignTests/TestTopologicalNamingProblem.py PartDesignTests/TestInvoluteGear.py + PartDesignTests/TestSketch.py ) if(BUILD_GUI) diff --git a/src/Mod/PartDesign/Gui/SketchWorkflow.cpp b/src/Mod/PartDesign/Gui/SketchWorkflow.cpp index 25aa9f0cd9..2c623678e8 100644 --- a/src/Mod/PartDesign/Gui/SketchWorkflow.cpp +++ b/src/Mod/PartDesign/Gui/SketchWorkflow.cpp @@ -618,8 +618,13 @@ private: std::string FeatName = documentOfBody->getUniqueObjectName("Sketch"); std::string supportString = Gui::Command::getObjectCmd(plane,"(",",[''])"); + App::Document* doc = partDesignBody->getDocument(); + if (!doc->hasPendingTransaction()) { + doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Create a new Sketch")); + } + FCMD_OBJ_CMD(partDesignBody,"newObject('Sketcher::SketchObject','" << FeatName << "')"); - auto Feat = partDesignBody->getDocument()->getObject(FeatName.c_str()); + auto Feat = doc->getObject(FeatName.c_str()); FCMD_OBJ_CMD(Feat,"AttachmentSupport = " << supportString); FCMD_OBJ_CMD(Feat,"MapMode = '" << Attacher::AttachEngine::getModeName(Attacher::mmFlatFace)<<"'"); Gui::Command::updateActive(); // Make sure the AttachmentSupport's Placement property is updated diff --git a/src/Mod/PartDesign/PartDesignTests/TestSketch.py b/src/Mod/PartDesign/PartDesignTests/TestSketch.py new file mode 100644 index 0000000000..844bf04974 --- /dev/null +++ b/src/Mod/PartDesign/PartDesignTests/TestSketch.py @@ -0,0 +1,101 @@ +#*************************************************************************** +#* Copyright (c) 2024 Werner Mayer * +#* * +#* This file is part of FreeCAD. * +#* * +#* FreeCAD is free software: you can redistribute it and/or modify it * +#* under the terms of the GNU Lesser General Public License as * +#* published by the Free Software Foundation, either version 2.1 of the * +#* License, or (at your option) any later version. * +#* * +#* FreeCAD is distributed in the hope that it will be useful, but * +#* WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +#* Lesser General Public License for more details. * +#* * +#* You should have received a copy of the GNU Lesser General Public * +#* License along with FreeCAD. If not, see * +#* . * +#* * +#*************************************************************************** + +import unittest + +import FreeCAD + +""" Test transaction interaction """ +class TestSketch(unittest.TestCase): + def setUp(self): + self.doc = FreeCAD.newDocument("PartDesignTestSketch") + self.doc.UndoMode = True + + def testIssue17553(self): + self.doc.openTransaction("Create box") + box = self.doc.addObject("Part::Box", "Box") + self.doc.commitTransaction() + self.doc.recompute() + + self.doc.openTransaction("Create sketch") + body = self.doc.addObject('PartDesign::Body', 'Body') + plane = self.doc.getObject('XY_Plane') + self.doc.commitTransaction() + + self.doc.openTransaction("Rename object") + box.Label = "Object" + self.doc.commitTransaction() + + sketch = body.newObject('Sketcher::SketchObject', 'Sketch') + sketch.AttachmentSupport = (plane, ['']) + sketch.MapMode = 'FlatFace' + self.doc.recompute() + + self.assertEqual(sketch.InList, [body]) + self.assertEqual(sketch.OutList, [plane]) + sketch.AttachmentSupport == [(plane, ("",))] + + self.doc.undo() # undo renaming + self.doc.undo() # undo body creation + self.doc.undo() # undo box creation + + self.doc.openTransaction("Remove sketch") + self.doc.removeObject(sketch.Name) + self.doc.commitTransaction() + + self.doc.undo() # undo removal + + self.assertEqual(sketch.InList, []) + self.assertEqual(sketch.OutList, []) + self.assertEqual(sketch.AttachmentSupport, []) + + def testDependency(self): + self.doc.openTransaction("Create box") + box = self.doc.addObject("Part::Box", "Box") + self.doc.commitTransaction() + self.doc.recompute() + + self.doc.openTransaction("Create sketch") + body = self.doc.addObject('PartDesign::Body', 'Body') + plane = self.doc.getObject('XY_Plane') + self.doc.commitTransaction() + + self.doc.openTransaction("Rename object") + box.Label = "Object" + self.doc.commitTransaction() + + sketch = body.newObject('Sketcher::SketchObject', 'Sketch') + sketch.AttachmentSupport = (plane, ['']) + sketch.MapMode = 'FlatFace' + self.doc.recompute() + + sketch.OutList + sketch.AttachmentSupport + + self.doc.undo() # undo renaming + self.doc.undo() # undo body creation + self.doc.undo() # undo box creation + + self.doc.DependencyGraph + + def tearDown(self): + FreeCAD.closeDocument("PartDesignTestSketch") + diff --git a/src/Mod/PartDesign/TestPartDesignApp.py b/src/Mod/PartDesign/TestPartDesignApp.py index 36485bfff1..be25234622 100644 --- a/src/Mod/PartDesign/TestPartDesignApp.py +++ b/src/Mod/PartDesign/TestPartDesignApp.py @@ -55,6 +55,7 @@ from PartDesignTests.TestThickness import TestThickness # extras from PartDesignTests.TestInvoluteGear import TestInvoluteGear +from PartDesignTests.TestSketch import TestSketch # Topological naming problem from PartDesignTests.TestTopologicalNamingProblem import TestTopologicalNamingProblem