From 5f4dd814ea36e412ff8ad52d4ea3f176041ffa98 Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Fri, 10 May 2024 11:26:33 +0200 Subject: [PATCH] Core: Add getRootObjectsIgnoreLinks and fix bugs in tree.cpp and AssemblyObject.cpp, CommandInsertLink.py, UtilsAssembly.py --- src/App/Document.cpp | 26 +++++++++++++++++++++++++ src/App/Document.h | 2 ++ src/App/DocumentPy.xml | 6 ++++++ src/App/DocumentPyImp.cpp | 12 ++++++++++++ src/Gui/Tree.cpp | 2 +- src/Mod/Assembly/App/AssemblyObject.cpp | 2 +- src/Mod/Assembly/CommandInsertLink.py | 2 +- src/Mod/Assembly/UtilsAssembly.py | 4 ++-- 8 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 149a47fd7d..5d8a170204 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -4005,6 +4005,32 @@ std::vector Document::getRootObjects() const return ret; } +std::vector Document::getRootObjectsIgnoreLinks() const +{ + std::vector ret; + + for (auto objectIt : d->objectArray) { + auto list = objectIt->getInList(); + bool noParents = list.empty(); + + if (!noParents) { + // App::Document getRootObjects returns the root objects of the dependency graph. + // So if an object is referenced by a App::Link, it will not be returned by that function. + // So here, as we want the tree-root level objects, + // we check if all the parents are links. In which case its still a root object. + noParents = std::all_of(list.cbegin(), list.cend(), [](App::DocumentObject* obj) { + return obj->isDerivedFrom(); + }); + } + + if (noParents) { + ret.push_back(objectIt); + } + } + + return ret; +} + void DocumentP::findAllPathsAt(const std::vector &all_nodes, size_t id, std::vector &all_paths, Path tmp) { diff --git a/src/App/Document.h b/src/App/Document.h index 2250f5056e..0bb83361c5 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -470,6 +470,8 @@ public: std::vector topologicalSort() const; /// get all root objects (objects no other one reference too) std::vector getRootObjects() const; + /// get all tree root objects (objects that are at the root of the object tree) + std::vector getRootObjectsIgnoreLinks() const; /// get all possible paths from one object to another following the OutList std::vector > getPathsByOutList (const App::DocumentObject* from, const App::DocumentObject* to) const; diff --git a/src/App/DocumentPy.xml b/src/App/DocumentPy.xml index b8c397b3be..c43726622c 100644 --- a/src/App/DocumentPy.xml +++ b/src/App/DocumentPy.xml @@ -291,6 +291,12 @@ sort: whether to topologically sort the return list + + + The list of root objects in this document ignoring references from links. + + + The Undo mode of the Document (0 = no Undo, 1 = Undo/Redo) diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index a084a94338..c9beed7a99 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -746,6 +746,18 @@ Py::List DocumentPy::getRootObjects() const return res; } +Py::List DocumentPy::getRootObjectsIgnoreLinks() const +{ + std::vector objs = getDocumentPtr()->getRootObjectsIgnoreLinks(); + Py::List res; + + for (auto obj : objs) + //Note: Here we must force the Py::Object to own this Python object as getPyObject() increments the counter + res.append(Py::Object(obj->getPyObject(), true)); + + return res; +} + Py::Int DocumentPy::getUndoMode() const { return Py::Int(getDocumentPtr()->getUndoMode()); diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 9cc8fb157d..958aacf170 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -2662,7 +2662,7 @@ void TreeWidget::sortDroppedObjects(TargetItemInfo& targetInfo, std::vectorsetValue(sortedObjList); } else if (targetInfo.targetItem->type() == TreeWidget::DocumentType) { - objList = targetInfo.targetDoc->getRootObjects(); + objList = targetInfo.targetDoc->getRootObjectsIgnoreLinks(); // First we need to sort objList by treeRank. std::sort(objList.begin(), objList.end(), [](App::DocumentObject* a, App::DocumentObject* b) { diff --git a/src/Mod/Assembly/App/AssemblyObject.cpp b/src/Mod/Assembly/App/AssemblyObject.cpp index 62b9e979a0..2866997f49 100644 --- a/src/Mod/Assembly/App/AssemblyObject.cpp +++ b/src/Mod/Assembly/App/AssemblyObject.cpp @@ -2007,7 +2007,7 @@ Base::Placement AssemblyObject::getGlobalPlacement(App::DocumentObject* targetOb App::DocumentObject* container) { bool inContainerBranch = (container == nullptr); - auto rootObjects = App::GetApplication().getActiveDocument()->getRootObjects(); + auto rootObjects = App::GetApplication().getActiveDocument()->getRootObjectsIgnoreLinks(); for (auto& part : rootObjects) { Base::Placement foundPlc; bool found = diff --git a/src/Mod/Assembly/CommandInsertLink.py b/src/Mod/Assembly/CommandInsertLink.py index fa8f0a1d9d..743da1289b 100644 --- a/src/Mod/Assembly/CommandInsertLink.py +++ b/src/Mod/Assembly/CommandInsertLink.py @@ -203,7 +203,7 @@ class TaskAssemblyInsertLink(QtCore.QObject): ): process_objects(obj.OutList, objItem) - process_objects(doc.RootObjects, docItem) + process_objects(doc.RootObjectsIgnoreLinks, docItem) self.form.partList.expandAll() def onFilterChange(self): diff --git a/src/Mod/Assembly/UtilsAssembly.py b/src/Mod/Assembly/UtilsAssembly.py index 55d6e0cc3b..f79574e574 100644 --- a/src/Mod/Assembly/UtilsAssembly.py +++ b/src/Mod/Assembly/UtilsAssembly.py @@ -297,7 +297,7 @@ def getGlobalPlacement(targetObj, container=None): return App.Placement() inContainerBranch = container is None - for rootObj in App.activeDocument().RootObjects: + for rootObj in App.activeDocument().RootObjectsIgnoreLinks: foundPlacement = getTargetPlacementRelativeTo( targetObj, rootObj, container, inContainerBranch ) @@ -308,7 +308,7 @@ def getGlobalPlacement(targetObj, container=None): def isThereOneRootAssembly(): - for part in App.activeDocument().RootObjects: + for part in App.activeDocument().RootObjectsIgnoreLinks: if part.TypeId == "Assembly::AssemblyObject": return True return False