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); +} 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/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(); 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