From da866e5b4d7bca0f5fa189dda01e78d2f1bc7607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Fri, 17 Feb 2017 06:51:46 +0100 Subject: [PATCH] Allow add/remove multiple objects in a group --- src/App/GeoFeatureGroupExtension.cpp | 72 ++++++++++++++---------- src/App/GeoFeatureGroupExtension.h | 4 +- src/App/GroupExtension.cpp | 83 ++++++++++++++++++---------- src/App/GroupExtension.h | 7 ++- src/App/GroupExtensionPy.xml | 28 +++++++--- src/App/GroupExtensionPyImp.cpp | 74 +++++++++++++++++++++++++ src/App/OriginGroupExtension.cpp | 9 ++- src/App/OriginGroupExtension.h | 2 +- 8 files changed, 205 insertions(+), 74 deletions(-) diff --git a/src/App/GeoFeatureGroupExtension.cpp b/src/App/GeoFeatureGroupExtension.cpp index 19d88828f7..87bee84eb2 100644 --- a/src/App/GeoFeatureGroupExtension.cpp +++ b/src/App/GeoFeatureGroupExtension.cpp @@ -119,47 +119,61 @@ Base::Placement GeoFeatureGroupExtension::recursiveGroupPlacement(GeoFeatureGrou return group->placement().getValue(); } -std::vector GeoFeatureGroupExtension::addObject(App::DocumentObject* object) { +std::vector GeoFeatureGroupExtension::addObjects(std::vector objects) { - if(!allowObject(object)) - return std::vector(); - - //cross CoordinateSystem links are not allowed, so we need to move the whole link group - auto links = getCSRelevantLinks(object); - links.push_back(object); - - auto ret = links; std::vector grp = Group.getValues(); - for( auto obj : links) { - //only one geofeaturegroup per object. - auto *group = App::GeoFeatureGroupExtension::getGroupOfObject(obj); - if(group && group != getExtendedObject()) - group->getExtensionByType()->removeObject(obj); + std::vector ret; + + for(auto object : objects) { - if (!hasObject(obj)) - grp.push_back(obj); - else - ret.erase(std::remove(ret.begin(), ret.end(), obj), ret.end()); + if(!allowObject(object)) + continue; + + //cross CoordinateSystem links are not allowed, so we need to move the whole link group + auto links = getCSRelevantLinks(object); + links.push_back(object); + + for( auto obj : links) { + //only one geofeaturegroup per object. + auto *group = App::GeoFeatureGroupExtension::getGroupOfObject(obj); + if(group && group != getExtendedObject()) + group->getExtensionByType()->removeObject(obj); + + if (!hasObject(obj)) { + grp.push_back(obj); + ret.push_back(obj); + } + } } Group.setValues(grp); return ret; } - -std::vector GeoFeatureGroupExtension::removeObject(App::DocumentObject* object) { - - //cross CoordinateSystem links are not allowed, so we need to remove the whole link group - auto links = getCSRelevantLinks(object); - links.push_back(object); +std::vector GeoFeatureGroupExtension::removeObjects(std::vector objects) { - //remove all links out of group + std::vector removed; std::vector grp = Group.getValues(); - for(auto link : links) - grp.erase(std::remove(grp.begin(), grp.end(), link), grp.end()); - Group.setValues(grp); - return links; + for(auto object : objects) { + //cross CoordinateSystem links are not allowed, so we need to remove the whole link group + auto links = getCSRelevantLinks(object); + links.push_back(object); + + //remove all links out of group + for(auto link : links) { + auto end = std::remove(grp.begin(), grp.end(), link); + if(end != grp.end()) { + grp.erase(end, grp.end()); + removed.push_back(link); + } + } + } + + if(!removed.empty()) + Group.setValues(grp); + + return removed; } std::vector< DocumentObject* > GeoFeatureGroupExtension::getObjectsFromLinks(DocumentObject* obj) { diff --git a/src/App/GeoFeatureGroupExtension.h b/src/App/GeoFeatureGroupExtension.h index d4ec727b67..522b32103b 100644 --- a/src/App/GeoFeatureGroupExtension.h +++ b/src/App/GeoFeatureGroupExtension.h @@ -96,8 +96,8 @@ public: !obj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId()); } - virtual std::vector addObject(DocumentObject* obj) override; - virtual std::vector removeObject(DocumentObject* obj) override; + virtual std::vector< DocumentObject* > addObjects(std::vector< DocumentObject* > obj) override; + virtual std::vector< DocumentObject* > removeObjects(std::vector< DocumentObject* > obj) override; /// returns GeoFeatureGroup relevant objects that are linked from the given one. That meas all linked objects /// including their linkes (recursively) except GeoFeatureGroups, where the recursion stops. Expressions diff --git a/src/App/GroupExtension.cpp b/src/App/GroupExtension.cpp index b34da464b5..bd3b123d66 100644 --- a/src/App/GroupExtension.cpp +++ b/src/App/GroupExtension.cpp @@ -62,35 +62,46 @@ DocumentObject* GroupExtension::addObject(const char* sType, const char* pObject std::vector GroupExtension::addObject(DocumentObject* obj) { - if(!allowObject(obj)) - return std::vector(); + std::vector vec = {obj}; + return addObjects(vec); +} + +std::vector< DocumentObject* > GroupExtension::addObjects(std::vector< DocumentObject* > objs) { - if (hasObject(obj)) - return std::vector(); + std::vector added; + std::vector grp = Group.getValues(); + for(auto obj : objs) { + + if(!allowObject(obj)) + continue; - //only one group per object. Note that it is allowed to be in a group and geofeaturegroup. However, - //getGroupOfObject() returns only normal groups, no GeoFeatureGroups. Hence this works. - auto *group = App::GroupExtension::getGroupOfObject(obj); - if(group && group != getExtendedObject()) - group->getExtensionByType()->removeObject(obj); - - //if we are on a geofeaturegroup we need to ensure the object is too - auto geogrp = GeoFeatureGroupExtension::getGroupOfObject(getExtendedObject()); - auto objgrp = GeoFeatureGroupExtension::getGroupOfObject(obj); - if( geogrp != objgrp ) { - //what to doo depends on if we are in geofeature group or not - if(geogrp) - geogrp->getExtensionByType()->addObject(obj); - else - objgrp->getExtensionByType()->removeObject(obj); + if (hasObject(obj)) + continue; + + //only one group per object. Note that it is allowed to be in a group and geofeaturegroup. However, + //getGroupOfObject() returns only normal groups, no GeoFeatureGroups. Hence this works. + auto *group = App::GroupExtension::getGroupOfObject(obj); + if(group && group != getExtendedObject()) + group->getExtensionByType()->removeObject(obj); + + //if we are in a geofeaturegroup we need to ensure the object is too + auto geogrp = GeoFeatureGroupExtension::getGroupOfObject(getExtendedObject()); + auto objgrp = GeoFeatureGroupExtension::getGroupOfObject(obj); + if( geogrp != objgrp ) { + //what to doo depends on if we are in geofeature group or not + if(geogrp) + geogrp->getExtensionByType()->addObject(obj); + else + objgrp->getExtensionByType()->removeObject(obj); + } + + grp.push_back(obj); + added.push_back(obj); } - std::vector grp = Group.getValues(); - grp.push_back(obj); Group.setValues(grp); - std::vector vec = {obj}; - return vec; + return added; } void GroupExtension::addObjects(const std::vector& objs) @@ -118,18 +129,34 @@ void GroupExtension::addObjects(const std::vector& objs) std::vector GroupExtension::removeObject(DocumentObject* obj) { - const std::vector & grp = Group.getValues(); - std::vector newGrp; + std::vector vec = {obj}; + return removeObjects(vec); +} - std::remove_copy (grp.begin(), grp.end(), std::back_inserter (newGrp), obj); +std::vector< DocumentObject* > GroupExtension::removeObjects(std::vector< DocumentObject* > objs) { + + const std::vector & grp = Group.getValues(); + std::vector newGrp = grp; + std::vector removed; + + std::vector::iterator end = newGrp.end(); + for(auto obj : objs) { + auto res = std::remove(newGrp.begin(), end, obj); + if(res != end) { + end = res; + removed.push_back(obj); + } + } + + newGrp.erase(end, newGrp.end()); if (grp.size() != newGrp.size()) { Group.setValues (newGrp); } - std::vector vec = {obj}; - return vec; + return removed; } + void GroupExtension::removeObjectsFromDocument() { const std::vector & grp = Group.getValues(); diff --git a/src/App/GroupExtension.h b/src/App/GroupExtension.h index 0dd0e91413..9332512d8d 100644 --- a/src/App/GroupExtension.h +++ b/src/App/GroupExtension.h @@ -53,9 +53,9 @@ public: /* Adds the object \a obj to this group. Returns all objects that have been added. */ virtual std::vector addObject(DocumentObject* obj); - /* Adds an array of object \a objs to this group. + /* Adds the objects \a objs to this group. Returns all objects that have been added. */ - virtual void addObjects(const std::vector& objs); + virtual std::vector addObjects(std::vector obj); /*override this function if you want only special objects */ virtual bool allowObject(DocumentObject* ) {return true;} @@ -63,6 +63,9 @@ public: /** Removes an object from this group. Returns all objects that have been removed. */ virtual std::vector removeObject(DocumentObject* obj); + /** Removes objects from this group. Returns all objects that have been removed. + */ + virtual std::vector removeObjects(std::vector obj); /** Removes all children objects from this group and the document. */ virtual void removeObjectsFromDocument(); diff --git a/src/App/GroupExtensionPy.xml b/src/App/GroupExtensionPy.xml index 703d310cb7..252ce45ccf 100644 --- a/src/App/GroupExtensionPy.xml +++ b/src/App/GroupExtensionPy.xml @@ -18,15 +18,25 @@ Create and add an object with given type and name to the group - - - Add an object to the group - - - - - Remove an object from the group - + + + Add an object to the group + + + + + Adds multiple objects to the group. Expects a list. + + + + + Remove an object from the group + + + + + Remove multiple objects from the group. Expects a list. + diff --git a/src/App/GroupExtensionPyImp.cpp b/src/App/GroupExtensionPyImp.cpp index 4d3fd7aa3e..c9cb181150 100644 --- a/src/App/GroupExtensionPyImp.cpp +++ b/src/App/GroupExtensionPyImp.cpp @@ -94,6 +94,43 @@ PyObject* GroupExtensionPy::addObject(PyObject *args) return Py::new_reference_to(list); } +PyObject* GroupExtensionPy::addObjects(PyObject *args) { + + PyObject *object; + if (!PyArg_ParseTuple(args, "O", &object)) // convert args: Python->C + return NULL; // NULL triggers exception + + if (PyTuple_Check(object) || PyList_Check(object)) { + Py::Sequence list(object); + Py::Sequence::size_type size = list.size(); + std::vector values; + values.resize(size); + + for (Py::Sequence::size_type i = 0; i < size; i++) { + Py::Object item = list[i]; + if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { + std::string error = std::string("type in list must be 'DocumentObject', not "); + error += (*item)->ob_type->tp_name; + throw Base::TypeError(error); + } + + values[i] = static_cast(*item)->getDocumentObjectPtr(); + } + + GroupExtension* grp = getGroupExtensionPtr(); + auto vec = grp->addObjects(values); + Py::List result; + for (App::DocumentObject* obj : vec) + result.append(Py::asObject(obj->getPyObject())); + + return Py::new_reference_to(result); + } + + std::string error = std::string("type must be list of 'DocumentObject', not "); + error += object->ob_type->tp_name; + throw Base::TypeError(error); +}; + PyObject* GroupExtensionPy::removeObject(PyObject *args) { PyObject *object; @@ -120,6 +157,43 @@ PyObject* GroupExtensionPy::removeObject(PyObject *args) return Py::new_reference_to(list); } +PyObject* GroupExtensionPy::removeObjects(PyObject *args) { + + PyObject *object; + if (!PyArg_ParseTuple(args, "O", &object)) // convert args: Python->C + return NULL; // NULL triggers exception + + if (PyTuple_Check(object) || PyList_Check(object)) { + Py::Sequence list(object); + Py::Sequence::size_type size = list.size(); + std::vector values; + values.resize(size); + + for (Py::Sequence::size_type i = 0; i < size; i++) { + Py::Object item = list[i]; + if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) { + std::string error = std::string("type in list must be 'DocumentObject', not "); + error += (*item)->ob_type->tp_name; + throw Base::TypeError(error); + } + + values[i] = static_cast(*item)->getDocumentObjectPtr(); + } + + GroupExtension* grp = getGroupExtensionPtr(); + auto vec = grp->removeObjects(values); + Py::List result; + for (App::DocumentObject* obj : vec) + result.append(Py::asObject(obj->getPyObject())); + + return Py::new_reference_to(result); + } + + std::string error = std::string("type must be list of 'DocumentObject', not "); + error += object->ob_type->tp_name; + throw Base::TypeError(error); +}; + PyObject* GroupExtensionPy::removeObjectsFromDocument(PyObject *args) { if (!PyArg_ParseTuple(args, "")) // convert args: Python->C diff --git a/src/App/OriginGroupExtension.cpp b/src/App/OriginGroupExtension.cpp index 55418ebce5..ca4b694bea 100644 --- a/src/App/OriginGroupExtension.cpp +++ b/src/App/OriginGroupExtension.cpp @@ -184,9 +184,12 @@ void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj) } } -std::vector< DocumentObject* > OriginGroupExtension::addObject(DocumentObject* obj) { - relinkToOrigin(obj); - return App::GeoFeatureGroupExtension::addObject(obj); +std::vector< DocumentObject* > OriginGroupExtension::addObjects(std::vector objs) { + + for(auto obj : objs) + relinkToOrigin(obj); + + return App::GeoFeatureGroupExtension::addObjects(objs); } diff --git a/src/App/OriginGroupExtension.h b/src/App/OriginGroupExtension.h index c802308e29..d79ed2d2f7 100644 --- a/src/App/OriginGroupExtension.h +++ b/src/App/OriginGroupExtension.h @@ -66,7 +66,7 @@ public: //changes all links of obj to a origin to point to this groupes origin void relinkToOrigin(App::DocumentObject* obj); - virtual std::vector addObject(DocumentObject* obj) override; + virtual std::vector addObjects(std::vector obj) override; protected: /// Checks integrity of the Origin