From 63f782d8f081f8ed1ba0e6d1b1f47117e438dfb3 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 12 Apr 2013 16:16:34 +0430 Subject: [PATCH] More bug fixes for Body insertion/deletion of features --- src/Mod/PartDesign/App/Body.cpp | 83 +++++++++++++++---- src/Mod/PartDesign/App/Body.h | 11 ++- src/Mod/PartDesign/App/BodyPy.xml | 4 +- src/Mod/PartDesign/App/BodyPyImp.cpp | 4 +- src/Mod/PartDesign/Gui/Command.cpp | 6 +- .../PartDesign/Gui/TaskGrooveParameters.cpp | 28 +++---- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 27 +++--- .../PartDesign/Gui/TaskPocketParameters.cpp | 30 +++---- .../Gui/TaskRevolutionParameters.cpp | 30 +++---- 9 files changed, 125 insertions(+), 98 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 5d80d34d0..9278ef825 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -50,25 +50,55 @@ Body::Body() ADD_PROPERTY(IsActive,(0)); } +/* +// Note: The following code will catch Python Document::removeObject() modifications. If the object removed is +// a member of the Body::Model, then it will be automatically removed from the Model property which triggers the +// following two methods +// But since we require the Python user to call both Document::addObject() and Body::addFeature(), we should +// also require calling both Document::removeObject and Body::removeFeature() in order to be consistent +void Body::onBeforeChange(const App::Property *prop) +{ + // Remember the feature before the current Tip. If the Tip is already at the first feature, remember the next feature + if (prop == &Model) { + std::vector features = Model.getValues(); + if (features.empty()) { + rememberTip = NULL; + } else { + std::vector::iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + if (it == features.begin()) { + it++; + if (it == features.end()) + rememberTip = NULL; + else + rememberTip = *it; + } else { + it--; + rememberTip = *it; + } + } + } + + return Part::Feature::onBeforeChange(prop); +} + void Body::onChanged(const App::Property *prop) { - Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); - App::DocumentObject* tip = Tip.getValue(); - Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); - std::vector model = Model.getValues(); - Base::Console().Error(" Model:\n"); - for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { - Base::Console().Error(" %s", (*m)->getNameInDocument()); - if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { - App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); - Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); + if (prop == &Model) { + std::vector features = Model.getValues(); + if (features.empty()) { + Tip.setValue(NULL); } else { - Base::Console().Error("\n"); + std::vector::iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + if (it == features.end()) { + // Tip feature was deleted + Tip.setValue(rememberTip); + } } } return Part::Feature::onChanged(prop); } +*/ short Body::mustExecute() const { @@ -189,7 +219,7 @@ Body* Body::findBodyOf(const App::DocumentObject* f) return NULL; } -void Body::insertFeature(App::DocumentObject *feature) +void Body::addFeature(App::DocumentObject *feature) { // Set the BaseFeature property // Note: This is not strictly necessary for Datum features @@ -236,6 +266,8 @@ void Body::insertFeature(App::DocumentObject *feature) void Body::removeFeature(App::DocumentObject* feature) { + // This method must be called BEFORE the feature is removed from the Document! + if (isSolidFeature(feature)) { // This is a solid feature // If the next feature is solid, reroute its BaseFeature property to the previous solid feature @@ -250,10 +282,11 @@ void Body::removeFeature(App::DocumentObject* feature) } } - // Adjust Tip feature if it is pointing to the deleted object - App::DocumentObject* tipFeature = Tip.getValue(); std::vector model = Model.getValues(); std::vector::iterator it = std::find(model.begin(), model.end(), feature); + + // Adjust Tip feature if it is pointing to the deleted object + App::DocumentObject* tipFeature = Tip.getValue(); if (tipFeature == feature) { // Set the Tip to the previous feature if possible, otherwise to the next feature std::vector::const_iterator prev = it, next = it; @@ -270,7 +303,11 @@ void Body::removeFeature(App::DocumentObject* feature) Tip.setValue(NULL); } } else { - Tip.setValue(NULL); + next++; + if (next != model.end()) + Tip.setValue(*next); + else + Tip.setValue(NULL); } } @@ -281,6 +318,22 @@ void Body::removeFeature(App::DocumentObject* feature) App::DocumentObjectExecReturn *Body::execute(void) { + Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); + App::DocumentObject* tip = Tip.getValue(); + Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); + std::vector model = Model.getValues(); + Base::Console().Error(" Model:\n"); + for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { + if (*m == NULL) continue; + Base::Console().Error(" %s", (*m)->getNameInDocument()); + if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { + App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); + Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); + } else { + Base::Console().Error("\n"); + } + } + const Part::TopoShape& TipShape = getTipShape(); if (TipShape._Shape.IsNull()) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 26391ba17..763fe6ef1 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -48,9 +48,7 @@ public: //@{ /// recalculate the feature App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// Just for debugging, remove when Body functionality is stable - void onChanged(const App::Property* prop); + short mustExecute() const; /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderBody"; @@ -83,8 +81,8 @@ public: /// Return true if the feature is located after the current Tip feature const bool isAfterTip(const App::DocumentObject *f); - /// Insert the feature into the body at the current insert point (Tip feature) - void insertFeature(App::DocumentObject* feature); + /// Add the feature into the body at the current insert point (Tip feature) + void addFeature(App::DocumentObject* feature); /// Remove the feature from the body void removeFeature(App::DocumentObject* feature); @@ -102,7 +100,8 @@ public: PyObject *getPyObject(void); - +private: + App::DocumentObject* rememberTip; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/BodyPy.xml b/src/Mod/PartDesign/App/BodyPy.xml index 2903e2a58..9d86dd0cb 100644 --- a/src/Mod/PartDesign/App/BodyPy.xml +++ b/src/Mod/PartDesign/App/BodyPy.xml @@ -13,9 +13,9 @@ PartDesign body class - + - insertFeature(feat) - Insert the given feature after the current Tip feature + addFeature(feat) - Add the given feature after the current Tip feature diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp index cce3db236..8bc88ca60 100644 --- a/src/Mod/PartDesign/App/BodyPyImp.cpp +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -29,7 +29,7 @@ int BodyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) return 0; } -PyObject* BodyPy::insertFeature(PyObject *args) +PyObject* BodyPy::addFeature(PyObject *args) { PyObject* featurePy; if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) @@ -45,7 +45,7 @@ PyObject* BodyPy::insertFeature(PyObject *args) Body* body = this->getBodyPtr(); try { - body->insertFeature(feature); + body->addFeature(feature); } catch (Base::Exception& e) { PyErr_SetString(PyExc_SystemError, e.what()); return 0; diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 21c15d917..f7246ceab 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -280,7 +280,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) openCommand("Create a Sketch on Face"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); @@ -354,7 +354,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -478,7 +478,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2 which.c_str(), FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", FeatName.c_str(), sketch->getNameInDocument()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); } diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index 50699fb46..38f9eabe2 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -331,15 +331,22 @@ bool TaskDlgGrooveParameters::reject() // get the support and Sketch PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcGroove->Sketch.getValue()) { pcSketch = static_cast(pcGroove->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); + } + + // role back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the support is visible again + if (!Gui::Application::Instance->getViewProvider(pcGroove)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); } // Body housekeeping if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcGroove); // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = ActivePartObject->Tip.getValue(); App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); @@ -350,21 +357,6 @@ bool TaskDlgGrooveParameters::reject() } } - // role back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcGroove)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - } - - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); - return true; } diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index dd00f657b..b19314705 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -553,20 +553,7 @@ bool TaskDlgPadParameters::reject() Sketcher::SketchObject *pcSketch = 0; if (pcPad->Sketch.getValue()) { pcSketch = static_cast(pcPad->Sketch.getValue()); - } - - // Body housekeeping - if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcPad); - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } + } // roll back the done things Gui::Command::abortCommand(); @@ -578,6 +565,18 @@ bool TaskDlgPadParameters::reject() Gui::Application::Instance->getViewProvider(pcSketch)->show(); } + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + return true; } diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 8163f8dfb..4e9bce7f8 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -495,15 +495,22 @@ bool TaskDlgPocketParameters::reject() // get the support and Sketch PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcPocket->Sketch.getValue()) { - pcSketch = static_cast(pcPocket->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); + pcSketch = static_cast(pcPocket->Sketch.getValue()); + } + + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the sketch is visible again + if (!Gui::Application::Instance->getViewProvider(pcPocket)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); } // Body housekeeping if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcPocket); // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = ActivePartObject->Tip.getValue(); App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); @@ -514,21 +521,6 @@ bool TaskDlgPocketParameters::reject() } } - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcPocket)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - } - - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); - return true; } diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 3454ab93b..838a1c037 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -332,23 +332,8 @@ bool TaskDlgRevolutionParameters::reject() // get the support and Sketch PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcRevolution->Sketch.getValue()) { pcSketch = static_cast(pcRevolution->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); - } - - // Body housekeeping - if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcRevolution); - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } } // role back the done things @@ -359,12 +344,19 @@ bool TaskDlgRevolutionParameters::reject() if (!Gui::Application::Instance->getViewProvider(pcRevolution)) { if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); } - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } return true; }