From b3c83df151e51cef93a377e45a892dbd92233fee Mon Sep 17 00:00:00 2001 From: tetektoza Date: Sun, 22 Jun 2025 17:41:22 +0200 Subject: [PATCH 1/3] Core: Add a possibility to extract active object based on extension --- src/Gui/ActiveObjectList.cpp | 12 ++++++++++++ src/Gui/ActiveObjectList.h | 3 +++ src/Gui/MDIView.h | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/src/Gui/ActiveObjectList.cpp b/src/Gui/ActiveObjectList.cpp index 0c0a5693c6..e76882167a 100644 --- a/src/Gui/ActiveObjectList.cpp +++ b/src/Gui/ActiveObjectList.cpp @@ -197,3 +197,15 @@ void ActiveObjectList::objectDeleted(const ViewProviderDocumentObject &vp) } } } + +App::DocumentObject* ActiveObjectList::getObjectWithExtension(const Base::Type extensionTypeId) const +{ + for (const auto& pair : _ObjectMap) { + App::DocumentObject* obj = getObject(pair.second, true); + if (obj && obj->hasExtension(extensionTypeId)) { + return obj; + } + } + + return nullptr; +} diff --git a/src/Gui/ActiveObjectList.h b/src/Gui/ActiveObjectList.h index 8a75ce87bb..bd058d0607 100644 --- a/src/Gui/ActiveObjectList.h +++ b/src/Gui/ActiveObjectList.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -67,6 +68,8 @@ namespace Gui void objectDeleted(const ViewProviderDocumentObject& viewProviderIn); bool hasObject(App::DocumentObject *obj, const char *, const char *subname=nullptr) const; + App::DocumentObject* getObjectWithExtension(Base::Type extensionTypeId) const; + private: struct ObjectInfo; void setHighlight(const ObjectInfo &info, Gui::HighlightMode mode, bool enable); diff --git a/src/Gui/MDIView.h b/src/Gui/MDIView.h index f56a04578c..64c92ee4d8 100644 --- a/src/Gui/MDIView.h +++ b/src/Gui/MDIView.h @@ -147,6 +147,11 @@ public: return ActiveObjects.hasObject(o,n,subname); } + App::DocumentObject* getActiveObjectWithExtension(const Base::Type extensionTypeId) const + { + return ActiveObjects.getObjectWithExtension(extensionTypeId); + } + /*! * \brief containsViewProvider * Checks if the given view provider is part of this view. The default implementation From d2f35cee55d6a92137b3cb231b4f287030c35ff7 Mon Sep 17 00:00:00 2001 From: Benjamin Nauck Date: Sun, 22 Jun 2025 23:25:52 +0200 Subject: [PATCH 2/3] App: Expose allowObject for groups in python --- src/App/GroupExtension.pyi | 6 ++++++ src/App/GroupExtensionPyImp.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/App/GroupExtension.pyi b/src/App/GroupExtension.pyi index cef2617867..8d50bc416b 100644 --- a/src/App/GroupExtension.pyi +++ b/src/App/GroupExtension.pyi @@ -70,3 +70,9 @@ class GroupExtension(DocumentObjectExtension): @param recursive if true check also if the obj is child of some sub group (default is false). """ ... + + def allowObject(self, obj: Any) -> bool: + """ + Returns true if obj is allowed in the group extension. + """ + ... diff --git a/src/App/GroupExtensionPyImp.cpp b/src/App/GroupExtensionPyImp.cpp index a13fbd7f65..fc281215d8 100644 --- a/src/App/GroupExtensionPyImp.cpp +++ b/src/App/GroupExtensionPyImp.cpp @@ -318,3 +318,30 @@ int GroupExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj* { return 0; } + +// def allowObject(self, obj: Any) -> bool: +PyObject* GroupExtensionPy::allowObject(PyObject* args) +{ + PyObject* object; + if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object)) { + return nullptr; + } + + auto* docObj = static_cast(object); + if (!docObj->getDocumentObjectPtr() + || !docObj->getDocumentObjectPtr()->isAttachedToDocument()) { + PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an invalid object"); + return nullptr; + } + if (docObj->getDocumentObjectPtr()->getDocument() + != getGroupExtensionPtr()->getExtendedObject()->getDocument()) { + PyErr_SetString(Base::PyExc_FC_GeneralError, + "Cannot check an object from another document from this group"); + return nullptr; + } + + GroupExtension* grp = getGroupExtensionPtr(); + + bool allowed = grp->allowObject(docObj->getDocumentObjectPtr()); + return PyBool_FromLong(allowed ? 1 : 0); +} From 4c8be343b809f0bf8a41bedc8488567dd0455cfe Mon Sep 17 00:00:00 2001 From: tetektoza Date: Fri, 20 Jun 2025 20:20:58 +0200 Subject: [PATCH 3/3] Gui: Allow users to add groups to active objects As the title says, if right now there is Arch type active (like Level, Building, etc. etc.), then it's not possible to assign Group to it automatically (it's being created on root level of the document). So this patch basically takes an active object and tries to insert it. --- src/Gui/CommandStructure.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Gui/CommandStructure.cpp b/src/Gui/CommandStructure.cpp index b465c4055c..1fd797e675 100644 --- a/src/Gui/CommandStructure.cpp +++ b/src/Gui/CommandStructure.cpp @@ -32,6 +32,7 @@ #include "ActiveObjectList.h" #include "Application.h" #include "Document.h" +#include "MDIView.h" #include "ViewProviderDocumentObject.h" #include "Selection.h" @@ -121,9 +122,27 @@ void StdCmdGroup::activated(int iMsg) std::string GroupName; GroupName = getUniqueObjectName("Group"); QString label = QApplication::translate("Std_Group", "Group"); - doCommand(Doc,"App.activeDocument().Tip = App.activeDocument().addObject('App::DocumentObjectGroup','%s')",GroupName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Label = '%s'", GroupName.c_str(), - label.toUtf8().data()); + + // create a group + doCommand(Doc,"group = App.activeDocument().addObject('App::DocumentObjectGroup','%s')",GroupName.c_str()); + doCommand(Doc,"group.Label = '%s'", label.toUtf8().data()); + doCommand(Doc,"App.activeDocument().Tip = group"); + + // try to add the group to any active object that supports grouping (has GroupExtension) + if (auto* activeDoc = Gui::Application::Instance->activeDocument()) { + if (auto* activeView = activeDoc->getActiveView()) { + // find the first active object with GroupExtension + if (auto* activeObj = activeView->getActiveObjectWithExtension( + App::GroupExtension::getExtensionClassTypeId())) { + doCommand(Doc, + "active_obj = App.activeDocument().getObject('%s')\n" + "if active_obj and active_obj.allowObject(group):\n" + " active_obj.Group += [group]", + activeObj->getNameInDocument()); + } + } + } // if we have no active object, group will be added to root doc + commitCommand(); Gui::Document* gui = Application::Instance->activeDocument();