From 8841fb08053b4c12c5d6e49517dd57ddde18d2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Fri, 4 Aug 2017 20:08:52 +0200 Subject: [PATCH] Make PartDesign::Boolean work with new Link structure This is the first feature that used GeoFeatureGroupExtension and required links to the groups inside as well as to things on the same level. Hence a few modifications to link scopes have been nesseccary. --- src/App/GeoFeatureGroupExtension.cpp | 13 ++-- src/App/GroupExtension.cpp | 6 ++ src/App/GroupExtension.h | 5 ++ src/App/GroupExtensionPy.xml | 13 ++-- src/App/GroupExtensionPyImp.cpp | 38 ++++++++++ src/App/OriginGroupExtension.cpp | 1 + src/Mod/Part/App/BodyBase.cpp | 2 + src/Mod/PartDesign/App/Body.cpp | 1 - src/Mod/PartDesign/App/FeatureBoolean.cpp | 70 +++++++------------ src/Mod/PartDesign/App/FeatureBoolean.h | 8 +-- src/Mod/PartDesign/Gui/Command.cpp | 6 +- .../PartDesign/Gui/TaskBooleanParameters.cpp | 21 +++--- .../PartDesign/Gui/ViewProviderBoolean.cpp | 10 +-- src/Mod/PartDesign/Gui/ViewProviderBoolean.h | 7 +- .../PartDesign/PartDesignTests/TestBoolean.py | 6 +- 15 files changed, 124 insertions(+), 83 deletions(-) diff --git a/src/App/GeoFeatureGroupExtension.cpp b/src/App/GeoFeatureGroupExtension.cpp index 6674c42faa..0262cec270 100644 --- a/src/App/GeoFeatureGroupExtension.cpp +++ b/src/App/GeoFeatureGroupExtension.cpp @@ -33,6 +33,7 @@ #include "OriginFeature.h" #include "Origin.h" #include "OriginGroupExtension.h" +#include //#include "GeoFeatureGroupPy.h" //#include "FeaturePythonPyImp.h" @@ -49,6 +50,7 @@ EXTENSION_PROPERTY_SOURCE(App::GeoFeatureGroupExtension, App::GroupExtension) GeoFeatureGroupExtension::GeoFeatureGroupExtension(void) { initExtensionType(GeoFeatureGroupExtension::getExtensionClassTypeId()); + Group.setScope(LinkScope::Child); } GeoFeatureGroupExtension::~GeoFeatureGroupExtension(void) @@ -367,11 +369,14 @@ void GeoFeatureGroupExtension::getCSRelevantLinks(const DocumentObject* obj, std bool GeoFeatureGroupExtension::areLinksValid(const DocumentObject* obj) { //no cross CS link for local links. + //Base::Console().Message("Check object links: %s\n", obj->getNameInDocument()); std::vector list; obj->getPropertyList(list); for(App::Property* prop : list) { - if(!isLinkValid(prop)) + if(!isLinkValid(prop)) { + //Base::Console().Message("Invalid link: %s\n", prop->getName()); return false; + } } return true; @@ -386,16 +391,16 @@ bool GeoFeatureGroupExtension::isLinkValid(App::Property* prop) { //no cross CS link for local links. auto result = getScopedObjectsFromLink(prop, LinkScope::Local); - auto group = obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId()) ? obj : getGroupOfObject(obj); + auto group = getGroupOfObject(obj); for(auto link : result) { if(getGroupOfObject(link) != group) return false; } //for links with scope SubGroup we need to check if all features are part of subgroups - if(group) { + if(obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) { result = getScopedObjectsFromLink(prop, LinkScope::Child); - auto groupExt = group->getExtensionByType(); + auto groupExt = obj->getExtensionByType(); for(auto link : result) { if(!groupExt->hasObject(link, true)) return false; diff --git a/src/App/GroupExtension.cpp b/src/App/GroupExtension.cpp index 8b99a2e574..7c403ab6de 100644 --- a/src/App/GroupExtension.cpp +++ b/src/App/GroupExtension.cpp @@ -104,6 +104,12 @@ std::vector< DocumentObject* > GroupExtension::addObjects(std::vector< DocumentO return added; } +std::vector< DocumentObject* > GroupExtension::setObjects(std::vector< DocumentObject* > obj) { + + Group.setValues(std::vector< DocumentObject* > ()); + return addObjects(obj); +} + std::vector GroupExtension::removeObject(DocumentObject* obj) { std::vector vec = {obj}; diff --git a/src/App/GroupExtension.h b/src/App/GroupExtension.h index 0e1d27d0b8..a12ac5ce63 100644 --- a/src/App/GroupExtension.h +++ b/src/App/GroupExtension.h @@ -56,6 +56,11 @@ public: /* Adds the objects \a objs to this group. Returns all objects that have been added. */ virtual std::vector addObjects(std::vector obj); + + /* Sets the objects in this group. Everything contained already will be removed first + */ + virtual std::vector< DocumentObject* > setObjects(std::vector< DocumentObject* > obj); + /*override this function if you want only special objects */ virtual bool allowObject(DocumentObject* ) {return true;} diff --git a/src/App/GroupExtensionPy.xml b/src/App/GroupExtensionPy.xml index 252ce45ccf..9b0950bbb0 100644 --- a/src/App/GroupExtensionPy.xml +++ b/src/App/GroupExtensionPy.xml @@ -20,22 +20,27 @@ - Add an object to the group + Add an object to the group. Returns all objects that have been added. - Adds multiple objects to the group. Expects a list. + Adds multiple objects to the group. Expects a list and returns all objects that have been added. + + + + + Sets the objects of the group. Expects a list and returns all objects that are now in the group. - Remove an object from the group + Remove an object from the group and returns all objects that have been removed. - Remove multiple objects from the group. Expects a list. + Remove multiple objects from the group. Expects a list and returns all objects that have been removed. diff --git a/src/App/GroupExtensionPyImp.cpp b/src/App/GroupExtensionPyImp.cpp index c9cb181150..dc04eb930f 100644 --- a/src/App/GroupExtensionPyImp.cpp +++ b/src/App/GroupExtensionPyImp.cpp @@ -131,6 +131,44 @@ PyObject* GroupExtensionPy::addObjects(PyObject *args) { throw Base::TypeError(error); }; + +PyObject* GroupExtensionPy::setObjects(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->setObjects(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; diff --git a/src/App/OriginGroupExtension.cpp b/src/App/OriginGroupExtension.cpp index ca4b694bea..453f6d9e85 100644 --- a/src/App/OriginGroupExtension.cpp +++ b/src/App/OriginGroupExtension.cpp @@ -42,6 +42,7 @@ OriginGroupExtension::OriginGroupExtension () { initExtensionType(OriginGroupExtension::getExtensionClassTypeId()); EXTENSION_ADD_PROPERTY_TYPE ( Origin, (0), 0, App::Prop_Hidden, "Origin linked to the group" ); + Origin.setScope(LinkScope::Global); } OriginGroupExtension::~OriginGroupExtension () diff --git a/src/Mod/Part/App/BodyBase.cpp b/src/Mod/Part/App/BodyBase.cpp index 462f3588fb..a04b82dbd5 100644 --- a/src/Mod/Part/App/BodyBase.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -41,6 +41,8 @@ PROPERTY_SOURCE_WITH_EXTENSIONS(Part::BodyBase, Part::Feature) BodyBase::BodyBase() { ADD_PROPERTY(Tip , (0) ); + Tip.setScope(App::LinkScope::Child); + ADD_PROPERTY(BaseFeature , (0) ); App::OriginGroupExtension::initExtension(this); diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 7e4f67b644..3646b78bb9 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -55,7 +55,6 @@ using namespace PartDesign; PROPERTY_SOURCE(PartDesign::Body, Part::BodyBase) Body::Body() { - ADD_PROPERTY_TYPE (Origin, (0), 0, App::Prop_Hidden, "Origin linked to the body" ); } /* diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp index 29b37d973f..4ad361912b 100644 --- a/src/Mod/PartDesign/App/FeatureBoolean.cpp +++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp @@ -46,7 +46,7 @@ using namespace PartDesign; namespace PartDesign { -PROPERTY_SOURCE(PartDesign::Boolean, PartDesign::Feature) +PROPERTY_SOURCE_WITH_EXTENSIONS(PartDesign::Boolean, PartDesign::Feature) const char* Boolean::TypeEnums[]= {"Fuse","Cut","Common","Section",NULL}; @@ -54,13 +54,13 @@ Boolean::Boolean() { ADD_PROPERTY(Type,((long)0)); Type.setEnums(TypeEnums); - ADD_PROPERTY(Bodies,(0)); - Bodies.setSize(0); + + initExtension(this); } short Boolean::mustExecute() const { - if (Bodies.isTouched()) + if (Group.isTouched()) return 1; return PartDesign::Feature::mustExecute(); } @@ -74,8 +74,8 @@ App::DocumentObjectExecReturn *Boolean::execute(void) return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid BaseFeature"); } - std::vector bodies = Bodies.getValues(); - if (bodies.empty()) + std::vector tools = Group.getValues(); + if (tools.empty()) return App::DocumentObject::StdReturn; // Get the base shape to operate on @@ -89,84 +89,66 @@ App::DocumentObjectExecReturn *Boolean::execute(void) if(!baseBody) return new App::DocumentObjectExecReturn("Cannot do boolean on feature which is not in a body"); - // TODO: Why is Feature::getLocation() protected? - Base::Placement place = baseBody->Placement.getValue(); - Base::Rotation rot(place.getRotation()); - Base::Vector3d axis; - double angle; - rot.getValue(axis, angle); - gp_Trsf trf; - trf.SetRotation(gp_Ax1(gp_Pnt(), gp_Dir(axis.x, axis.y, axis.z)), angle); - trf.SetTranslationPart(gp_Vec(place.getPosition().x,place.getPosition().y,place.getPosition().z)); - TopLoc_Location objLoc(trf); - TopoDS_Shape result = baseTopShape.getShape(); - result.Move(objLoc); // Get the operation type std::string type = Type.getValueAsString(); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + for (auto tool : tools) { // Extract the body shape. Its important to get the actual feature that provides the last solid in the body // so that the placement will be right - PartDesign::Body* body = static_cast(*b); + if(!tool->isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Cannot do boolean with anything but Part::Feature and its derivatives"); - TopoDS_Shape shape = body->Shape.getValue(); - - // Move the shape to the location of the base shape in the other body - Base::Placement pl = body->Placement.getValue(); - // TODO: Why is Feature::getLocation() protected? - Base::Rotation rot(pl.getRotation()); - Base::Vector3d axis; - double angle; - rot.getValue(axis, angle); - gp_Trsf trf; - trf.SetRotation(gp_Ax1(gp_Pnt(), gp_Dir(axis.x, axis.y, axis.z)), angle); - trf.SetTranslationPart(gp_Vec(pl.getPosition().x,pl.getPosition().y,pl.getPosition().z)); - TopLoc_Location bLoc(trf); - shape.Move(bLoc); - + TopoDS_Shape shape = static_cast(tool)->Shape.getValue(); TopoDS_Shape boolOp; if (type == "Fuse") { BRepAlgoAPI_Fuse mkFuse(result, shape); if (!mkFuse.IsDone()) - return new App::DocumentObjectExecReturn("Fusion of bodies failed", *b); + return new App::DocumentObjectExecReturn("Fusion of tools failed"); // we have to get the solids (fuse sometimes creates compounds) boolOp = this->getSolid(mkFuse.Shape()); // lets check if the result is a solid if (boolOp.IsNull()) - return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *b); + return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); } else if (type == "Cut") { BRepAlgoAPI_Cut mkCut(result, shape); if (!mkCut.IsDone()) - return new App::DocumentObjectExecReturn("Cut out of first body failed", *b); + return new App::DocumentObjectExecReturn("Cut out failed"); boolOp = mkCut.Shape(); } else if (type == "Common") { BRepAlgoAPI_Common mkCommon(result, shape); if (!mkCommon.IsDone()) - return new App::DocumentObjectExecReturn("Common operation with first body failed", *b); + return new App::DocumentObjectExecReturn("Common operation failed"); boolOp = mkCommon.Shape(); } else if (type == "Section") { BRepAlgoAPI_Section mkSection(result, shape); if (!mkSection.IsDone()) - return new App::DocumentObjectExecReturn("Section out of first body failed", *b); + return new App::DocumentObjectExecReturn("Section failed"); // we have to get the solids boolOp = this->getSolid(mkSection.Shape()); // lets check if the result is a solid if (boolOp.IsNull()) - return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *b); + return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); } result = boolOp; // Use result of this operation for fuse/cut of next body - //bring the result geometry into the correct coordinance of the body the boolean belongs to - BRepBuilderAPI_GTransform mkTrf(result, objLoc.Inverted().Transformation()); - result = mkTrf.Shape(); } this->Shape.setValue(getSolid(result)); return App::DocumentObject::StdReturn; } +void Boolean::onChanged(const App::Property* prop) { + + if(strcmp(prop->getName(), "Group") == 0) + touch(); + + PartDesign::Feature::onChanged(prop); +} + + + } diff --git a/src/Mod/PartDesign/App/FeatureBoolean.h b/src/Mod/PartDesign/App/FeatureBoolean.h index f6b937cfad..61e2a21a6e 100644 --- a/src/Mod/PartDesign/App/FeatureBoolean.h +++ b/src/Mod/PartDesign/App/FeatureBoolean.h @@ -25,6 +25,7 @@ #define PARTDESIGN_FeatureBoolean_H #include +#include #include "Feature.h" @@ -35,17 +36,15 @@ namespace PartDesign * Abstract superclass of all features that are created by transformation of another feature * Transformations are translation, rotation and mirroring */ -class PartDesignExport Boolean : public PartDesign::Feature +class PartDesignExport Boolean : public PartDesign::Feature, public App::GeoFeatureGroupExtension { - PROPERTY_HEADER(PartDesign::Boolean); + PROPERTY_HEADER_WITH_EXTENSIONS(PartDesign::Boolean); public: Boolean(); /// The type of the boolean operation App::PropertyEnumeration Type; - /// The bodies for the operation - App::PropertyLinkList Bodies; /** @name methods override feature */ //@{ @@ -56,6 +55,7 @@ public: const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderBoolean"; } + virtual void onChanged(const App::Property* prop); //@} private: diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 4617dfe3e7..c614aa227c 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -2136,13 +2136,13 @@ void CmdPartDesignBoolean::activated(int iMsg) PartDesign::Body *pcActiveBody = PartDesignGui::getBody(/*messageIfNot = */true); if (!pcActiveBody) return; - Gui::SelectionFilter BodyFilter("SELECT PartDesign::Body COUNT 1.."); + Gui::SelectionFilter BodyFilter("SELECT Part::Feature COUNT 1.."); openCommand("Create Boolean"); std::string FeatName = getUniqueObjectName("Boolean"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Boolean','%s')",FeatName.c_str()); - if (BodyFilter.match()) { + if (BodyFilter.match() && !BodyFilter.Result.empty()) { std::vector bodies; std::vector >::iterator i = BodyFilter.Result.begin(); for (; i != BodyFilter.Result.end(); i++) { @@ -2152,7 +2152,7 @@ void CmdPartDesignBoolean::activated(int iMsg) } } std::string bodyString = PartDesignGui::buildLinkListPythonStr(bodies); - doCommand(Doc,"App.activeDocument().%s.Bodies = %s",FeatName.c_str(),bodyString.c_str()); + doCommand(Doc,"App.activeDocument().%s.addObjects(%s)",FeatName.c_str(),bodyString.c_str()); } finishFeature(this, FeatName, nullptr, false); diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp index c20db46af9..9bba9cc992 100644 --- a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp @@ -71,7 +71,7 @@ TaskBooleanParameters::TaskBooleanParameters(ViewProviderBoolean *BooleanView,QW this->groupLayout()->addWidget(proxy); PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); - std::vector bodies = pcBoolean->Bodies.getValues(); + std::vector bodies = pcBoolean->Group.getValues(); for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { ui->listWidgetBodies->insertItem(0, QString::fromLatin1((*b)->getNameInDocument())); @@ -108,12 +108,13 @@ void TaskBooleanParameters::onSelectionChanged(const Gui::SelectionChanges& msg) return; } - std::vector bodies = pcBoolean->Bodies.getValues(); + std::vector bodies = pcBoolean->Group.getValues(); if (selectionMode == bodyAdd) { if (std::find(bodies.begin(), bodies.end(), pcBody) == bodies.end()) { bodies.push_back(pcBody); - pcBoolean->Bodies.setValues(bodies); + pcBoolean->Group.setValues(std::vector()); + pcBoolean->addObjects(bodies); ui->listWidgetBodies->insertItem(ui->listWidgetBodies->count(), QString::fromStdString(pcBody->getNameInDocument())); @@ -145,7 +146,7 @@ void TaskBooleanParameters::onSelectionChanged(const Gui::SelectionChanges& msg) std::vector::iterator b = std::find(bodies.begin(), bodies.end(), pcBody); if (b != bodies.end()) { bodies.erase(b); - pcBoolean->Bodies.setValues(bodies); + pcBoolean->setObjects(bodies); QList items = ui->listWidgetBodies->findItems(QString::fromStdString(body), Qt::MatchExactly); if (!items.empty()) { for (QList::const_iterator i = items.begin(); i != items.end(); i++) { @@ -180,7 +181,7 @@ void TaskBooleanParameters::onButtonBodyAdd(bool checked) PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); Gui::Document* doc = BooleanView->getDocument(); BooleanView->hide(); - if (pcBoolean->Bodies.getValues().empty() && pcBoolean->BaseFeature.getValue()) + if (pcBoolean->Group.getValues().empty() && pcBoolean->BaseFeature.getValue()) doc->setHide(pcBoolean->BaseFeature.getValue()->getNameInDocument()); selectionMode = bodyAdd; Gui::Selection().clearSelection(); @@ -233,13 +234,13 @@ int TaskBooleanParameters::getType(void) const void TaskBooleanParameters::onBodyDeleted(void) { PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); - std::vector bodies = pcBoolean->Bodies.getValues(); + std::vector bodies = pcBoolean->Group.getValues(); int index = ui->listWidgetBodies->currentRow(); if (index < 0 && (size_t) index > bodies.size()) return; App::DocumentObject* body = bodies[index]; bodies.erase(bodies.begin() + ui->listWidgetBodies->currentRow()); - pcBoolean->Bodies.setValues(bodies); + pcBoolean->setObjects(bodies); ui->listWidgetBodies->model()->removeRow(ui->listWidgetBodies->currentRow()); pcBoolean->getDocument()->recomputeFeature(pcBoolean); @@ -323,10 +324,10 @@ bool TaskDlgBooleanParameters::accept() try { std::vector bodies = parameter->getBodies(); std::stringstream str; - str << "App.ActiveDocument." << name.c_str() << ".Bodies = ["; + str << "App.ActiveDocument." << name.c_str() << ".setObjects( ["; for (std::vector::const_iterator it = bodies.begin(); it != bodies.end(); ++it) str << "App.ActiveDocument." << *it << ","; - str << "]"; + str << "])"; Gui::Command::runCommand(Gui::Command::Doc,str.str().c_str()); } catch (const Base::Exception& e) { @@ -350,7 +351,7 @@ bool TaskDlgBooleanParameters::reject() if (doc != NULL) { if (obj->BaseFeature.getValue() != NULL) { doc->setShow(obj->BaseFeature.getValue()->getNameInDocument()); - std::vector bodies = obj->Bodies.getValues(); + std::vector bodies = obj->Group.getValues(); for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) doc->setShow((*b)->getNameInDocument()); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp b/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp index fe19263dc6..48ec58ce83 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp @@ -40,11 +40,12 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderBoolean,PartDesignGui::ViewProvider) +PROPERTY_SOURCE_WITH_EXTENSIONS(PartDesignGui::ViewProviderBoolean,PartDesignGui::ViewProvider) ViewProviderBoolean::ViewProviderBoolean() { sPixmap = "PartDesign_Boolean.svg"; + initExtension(this); } ViewProviderBoolean::~ViewProviderBoolean() @@ -101,17 +102,12 @@ bool ViewProviderBoolean::setEdit(int ModNum) } } -std::vector ViewProviderBoolean::claimChildren(void)const -{ - return static_cast(getObject())->Bodies.getValues(); -} - bool ViewProviderBoolean::onDelete(const std::vector &s) { PartDesign::Boolean* pcBoolean = static_cast(getObject()); // if abort command deleted the object the bodies are visible again - std::vector bodies = pcBoolean->Bodies.getValues(); + std::vector bodies = pcBoolean->Group.getValues(); for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { if (*b && Gui::Application::Instance->getViewProvider(*b)) Gui::Application::Instance->getViewProvider(*b)->show(); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBoolean.h b/src/Mod/PartDesign/Gui/ViewProviderBoolean.h index 90de970002..726ad0c80c 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBoolean.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBoolean.h @@ -25,13 +25,15 @@ #define PARTGUI_ViewProviderBoolean_H #include "ViewProvider.h" +#include namespace PartDesignGui { -class PartDesignGuiExport ViewProviderBoolean : public ViewProvider +class PartDesignGuiExport ViewProviderBoolean : public ViewProvider, + public Gui::ViewProviderGeoFeatureGroupExtension { - PROPERTY_HEADER(PartDesignGui::ViewProviderBoolean); + PROPERTY_HEADER_WITH_EXTENSIONS(PartDesignGui::ViewProviderBoolean); public: /// constructor @@ -41,7 +43,6 @@ public: /// grouping handling void setupContextMenu(QMenu*, QObject*, const char*); - std::vector claimChildren(void)const; virtual bool onDelete(const std::vector &); diff --git a/src/Mod/PartDesign/PartDesignTests/TestBoolean.py b/src/Mod/PartDesign/PartDesignTests/TestBoolean.py index 314e962d4b..7fb3d8d9b2 100644 --- a/src/Mod/PartDesign/PartDesignTests/TestBoolean.py +++ b/src/Mod/PartDesign/PartDesignTests/TestBoolean.py @@ -47,7 +47,7 @@ class TestBoolean(unittest.TestCase): self.BooleanFuse = self.Doc.addObject('PartDesign::Boolean','BooleanFuse') self.Body001.addObject(self.BooleanFuse) self.Doc.recompute() - self.BooleanFuse.Bodies = [self.Body,] + self.BooleanFuse.setObjects([self.Body,]) self.BooleanFuse.Type = 0 self.Doc.recompute() self.assertAlmostEqual(self.BooleanFuse.Shape.Volume, 1500) @@ -71,7 +71,7 @@ class TestBoolean(unittest.TestCase): self.BooleanCut = self.Doc.addObject('PartDesign::Boolean','BooleanCut') self.Body001.addObject(self.BooleanCut) self.Doc.recompute() - self.BooleanCut.Bodies = [self.Body,] + self.BooleanCut.setObjects([self.Body,]) self.BooleanCut.Type = 1 self.Doc.recompute() self.assertAlmostEqual(self.BooleanCut.Shape.Volume, 500) @@ -95,7 +95,7 @@ class TestBoolean(unittest.TestCase): self.BooleanCommon = self.Doc.addObject('PartDesign::Boolean','BooleanCommon') self.Body001.addObject(self.BooleanCommon) self.Doc.recompute() - self.BooleanCommon.Bodies = [self.Body,] + self.BooleanCommon.setObjects([self.Body,]) self.BooleanCommon.Type = 2 self.Doc.recompute() self.assertAlmostEqual(self.BooleanCommon.Shape.Volume, 500)