From 638cfd26829be2a19f85e496cb29569f9afe3397 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 22 May 2013 20:47:31 +0430 Subject: [PATCH] Allow booleans of bodies in PartDesign --- src/Mod/PartDesign/App/AppPartDesign.cpp | 2 + src/Mod/PartDesign/App/CMakeLists.txt | 2 + src/Mod/PartDesign/App/FeatureBoolean.cpp | 133 +++++++ src/Mod/PartDesign/App/FeatureBoolean.h | 69 ++++ src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 2 + src/Mod/PartDesign/Gui/CMakeLists.txt | 7 + src/Mod/PartDesign/Gui/Command.cpp | 63 ++++ .../PartDesign/Gui/TaskBooleanParameters.cpp | 355 ++++++++++++++++++ .../PartDesign/Gui/TaskBooleanParameters.h | 118 ++++++ .../PartDesign/Gui/TaskBooleanParameters.ui | 72 ++++ .../PartDesign/Gui/ViewProviderBoolean.cpp | 124 ++++++ src/Mod/PartDesign/Gui/ViewProviderBoolean.h | 56 +++ src/Mod/PartDesign/Gui/Workbench.cpp | 19 +- 13 files changed, 1020 insertions(+), 2 deletions(-) create mode 100644 src/Mod/PartDesign/App/FeatureBoolean.cpp create mode 100644 src/Mod/PartDesign/App/FeatureBoolean.h create mode 100644 src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskBooleanParameters.h create mode 100644 src/Mod/PartDesign/Gui/TaskBooleanParameters.ui create mode 100644 src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderBoolean.h diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 55e52e5ec..c352fb030 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -52,6 +52,7 @@ #include "DatumPlane.h" #include "DatumLine.h" #include "DatumPoint.h" +#include "FeatureBoolean.h" namespace PartDesign { extern PyObject* initModule(); @@ -102,6 +103,7 @@ PyMODINIT_FUNC init_PartDesign() PartDesign::Plane ::init(); PartDesign::Line ::init(); PartDesign::Point ::init(); + PartDesign::Boolean ::init(); PartDesign::Point::initHints(); PartDesign::Line ::initHints(); diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 77d3cb68a..d7201d894 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -94,6 +94,8 @@ SET(FeaturesSketchBased_SRCS FeatureSubtractive.cpp FeatureHole.h FeatureHole.cpp + FeatureBoolean.h + FeatureBoolean.cpp ) SOURCE_GROUP("SketchBasedFeatures" FILES ${FeaturesSketchBased_SRCS}) diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp new file mode 100644 index 000000000..73a5a633b --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp @@ -0,0 +1,133 @@ +/****************************************************************************** + * Copyright (c)2013 Jan Rheinlaender * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ******************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +#endif + +#include "Body.h" +#include "FeatureBoolean.h" + +#include +#include + +using namespace PartDesign; + +namespace PartDesign { + +PROPERTY_SOURCE(PartDesign::Boolean, PartDesign::Feature) + +const char* Boolean::TypeEnums[]= {"Fuse","Cut","Common","Section",NULL}; + +Boolean::Boolean() +{ + ADD_PROPERTY(Type,((long)0)); + Type.setEnums(TypeEnums); + ADD_PROPERTY(Bodies,(0)); + Bodies.setSize(0); +} + +short Boolean::mustExecute() const +{ + if (Bodies.isTouched()) + return 1; + return PartDesign::Feature::mustExecute(); +} + +App::DocumentObjectExecReturn *Boolean::execute(void) +{ + std::vector bodies = Bodies.getValues(); + if (bodies.empty()) + return App::DocumentObject::StdReturn; + + // Get the first body + if (bodies.front() == NULL) + return new App::DocumentObjectExecReturn("No body for boolean"); + PartDesign::Body* body = static_cast(bodies.front()); + const Part::TopoShape& bodyTopShape = body->Shape.getShape(); + if (bodyTopShape._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Cannot do boolean operation on invalid body shape"); + + // create an untransformed copy of the body shape + Part::TopoShape bodyShape(bodyTopShape); + bodyShape.setTransform(Base::Matrix4D()); + TopoDS_Shape result = bodyShape._Shape; + + // Position this feature by the first body + this->Placement.setValue(body->Placement.getValue()); + + // Get the operation type + std::string type = Type.getValueAsString(); + + std::vector::const_iterator b = bodies.begin(); + b++; + + for (; b != bodies.end(); b++) + { + // Extract the body shape + PartDesign::Body* body = static_cast(*b); + TopoDS_Shape shape = body->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); + // 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); + } else if (type == "Cut") { + BRepAlgoAPI_Cut mkCut(result, shape); + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Cut out of first body failed", *b); + 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); + 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); + // 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); + } + + result = boolOp; // Use result of this operation for fuse/cut of next body + } + + this->Shape.setValue(result); + return App::DocumentObject::StdReturn; +} + +} diff --git a/src/Mod/PartDesign/App/FeatureBoolean.h b/src/Mod/PartDesign/App/FeatureBoolean.h new file mode 100644 index 000000000..f6b937cfa --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureBoolean.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c)2013 Jan Rheinlaender * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ******************************************************************************/ + + +#ifndef PARTDESIGN_FeatureBoolean_H +#define PARTDESIGN_FeatureBoolean_H + +#include +#include "Feature.h" + + +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 +{ + PROPERTY_HEADER(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 */ + //@{ + /// Recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderBoolean"; + } + //@} + +private: + static const char* TypeEnums[]; + +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_FeatureBoolean_H diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index 47b6930d3..ac2ec7f27 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -51,6 +51,7 @@ #include "ViewProviderDatumPoint.h" #include "ViewProviderDatumLine.h" #include "ViewProviderDatumPlane.h" +#include "ViewProviderBoolean.h" // use a different name to CreateCommand() void CreatePartDesignCommands(void); @@ -126,6 +127,7 @@ PyMODINIT_FUNC initPartDesignGui() PartDesignGui::ViewProviderDatumPoint ::init(); PartDesignGui::ViewProviderDatumLine ::init(); PartDesignGui::ViewProviderDatumPlane ::init(); + PartDesignGui::ViewProviderBoolean ::init(); // add resources and reloads the translators loadPartDesignResource(); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index b0e60d69b..7fa5810d6 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -46,6 +46,7 @@ set(PartDesignGui_MOC_HDRS TaskScaledParameters.h TaskMultiTransformParameters.h TaskDatumParameters.h + TaskBooleanParameters.h ) fc_wrap_cpp(PartDesignGui_MOC_SRCS ${PartDesignGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartDesignGui_MOC_SRCS}) @@ -59,6 +60,7 @@ set(PartDesignGui_UIC_SRCS TaskChamferParameters.ui TaskFilletParameters.ui TaskDraftParameters.ui + TaskBooleanParameters.ui TaskHoleParameters.ui TaskRevolutionParameters.ui TaskGrooveParameters.ui @@ -113,6 +115,8 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderDatumLine.h ViewProviderDatumPlane.cpp ViewProviderDatumPlane.h + ViewProviderBoolean.cpp + ViewProviderBoolean.h ) SOURCE_GROUP("ViewProvider" FILES ${PartDesignGuiViewProvider_SRCS}) @@ -171,6 +175,9 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskDatumParameters.ui TaskDatumParameters.cpp TaskDatumParameters.h + TaskBooleanParameters.ui + TaskBooleanParameters.cpp + TaskBooleanParameters.h ) SOURCE_GROUP("TaskDialogs" FILES ${PartDesignGuiTaskDlgs_SRCS}) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 2ec6fb6b3..f8145dfab 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -1593,6 +1594,66 @@ bool CmdPartDesignMultiTransform::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_Boolean +//=========================================================================== + +/* Boolean commands =======================================================*/ +DEF_STD_CMD_A(CmdPartDesignBoolean); + +CmdPartDesignBoolean::CmdPartDesignBoolean() + :Command("PartDesign_Boolean") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Boolean operation"); + sToolTipText = QT_TR_NOOP("Boolean operation with two or more boies"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Boolean"; +} + + +void CmdPartDesignBoolean::activated(int iMsg) +{ + Gui::SelectionFilter BodyFilter("SELECT PartDesign::Body COUNT 1.."); + std::string bodyString("["); + + if (BodyFilter.match()) { + std::vector bodies; + for (std::vector >::iterator i = BodyFilter.Result.begin(); + i != BodyFilter.Result.end(); i++) { + for (std::vector::iterator j = i->begin(); j != i->end(); j++) { + bodies.push_back(j->getObject()); + } + } + + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + bodyString += std::string("App.activeDocument().") + (*b)->getNameInDocument() + ","; + bodyString += "]"; + } else { + bodyString = ""; + } + + std::string FeatName = getUniqueObjectName("Boolean"); + + openCommand("Create Boolean"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Boolean','%s')",FeatName.c_str()); + if (!bodyString.empty()) + doCommand(Doc,"App.activeDocument().%s.Bodies = %s",FeatName.c_str(),bodyString.c_str()); + //doCommand(Gui,"App.activeDocument().recompute()"); + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdPartDesignBoolean::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // Initialization @@ -1627,4 +1688,6 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + + rcCmdMgr.addCommand(new CmdPartDesignBoolean()); } diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp new file mode 100644 index 000000000..ee14dbf53 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp @@ -0,0 +1,355 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +#endif + +#include "ui_TaskBooleanParameters.h" +#include "TaskBooleanParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskBooleanParameters */ + +TaskBooleanParameters::TaskBooleanParameters(ViewProviderBoolean *BooleanView,QWidget *parent) + : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Boolean"),tr("Boolean parameters"),true, parent),BooleanView(BooleanView) +{ + selectionMode = none; + + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskBooleanParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->buttonBodyAdd, SIGNAL(toggled(bool)), + this, SLOT(onButtonBodyAdd(bool))); + connect(ui->buttonBodyRemove, SIGNAL(toggled(bool)), + this, SLOT(onButtonBodyRemove(bool))); + connect(ui->comboType, SIGNAL(currentIndexChanged(int)), + this, SLOT(onTypeChanged(int))); + + this->groupLayout()->addWidget(proxy); + + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + std::vector bodies = pcBoolean->Bodies.getValues(); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + { + ui->listWidgetBodies->insertItem(0, QString::fromAscii((*b)->getNameInDocument())); + } + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetBodies->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onBodyDeleted())); + ui->listWidgetBodies->setContextMenuPolicy(Qt::ActionsContextMenu); + + int index = pcBoolean->Type.getValue(); + ui->comboType->setCurrentIndex(index); +} + +void TaskBooleanParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == none) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (strcmp(msg.pDocName, BooleanView->getObject()->getDocument()->getName()) != 0) + return; + + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + std::string body(msg.pObjectName); + if (body.empty()) + return; + App::DocumentObject* pcBody = pcBoolean->getDocument()->getObject(body.c_str()); + if (pcBody == NULL) + return; + if (!pcBody->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { + pcBody = PartDesign::Body::findBodyOf(pcBody); + if (pcBody == NULL) + return; + } + + std::vector bodies = pcBoolean->Bodies.getValues(); + + if (selectionMode == bodyAdd) { + if (std::find(bodies.begin(), bodies.end(), pcBody) == bodies.end()) { + bodies.push_back(pcBody); + pcBoolean->Bodies.setValues(bodies); + ui->listWidgetBodies->insertItem(ui->listWidgetBodies->count(), + QString::fromStdString(pcBody->getNameInDocument())); + + pcBoolean->getDocument()->recomputeFeature(pcBoolean); + ui->buttonBodyAdd->setChecked(false); + exitSelectionMode(); + + // Hide the bodies if there are more than two + if (bodies.size() == 2) { + // Hide both bodies + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.front())); + if (vp != NULL) + vp->hide(); + vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.back())); + if (vp != NULL) + vp->hide(); + BooleanView->show(); + } else { + // Hide newly added body + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.back())); + if (vp != NULL) + vp->hide(); + } + } + } else if (selectionMode == bodyRemove) { + std::vector::iterator b = std::find(bodies.begin(), bodies.end(), pcBody); + if (b != bodies.end()) { + bodies.erase(b); + pcBoolean->Bodies.setValues(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++) { + QListWidgetItem* it = ui->listWidgetBodies->takeItem(ui->listWidgetBodies->row(*i)); + delete it; + } + } + pcBoolean->getDocument()->recomputeFeature(pcBoolean); + ui->buttonBodyRemove->setChecked(false); + exitSelectionMode(); + + // Make bodies visible again + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(*b)); + if (vp != NULL) + vp->show(); + if (bodies.size() == 1) { + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.front())); + if (vp != NULL) + vp->show(); + BooleanView->hide(); + } + } + } + } +} + +void TaskBooleanParameters::onButtonBodyAdd(bool checked) +{ + if (checked) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setHide(BooleanView->getObject()->getNameInDocument()); + selectionMode = bodyAdd; + Gui::Selection().clearSelection(); + } else { + exitSelectionMode(); + } +} + +void TaskBooleanParameters::onButtonBodyRemove(bool checked) +{ + if (checked) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setHide(BooleanView->getObject()->getNameInDocument()); + selectionMode = bodyRemove; + Gui::Selection().clearSelection(); + } else { + exitSelectionMode(); + } +} + +void TaskBooleanParameters::onTypeChanged(int index) +{ + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + + switch (index) { + case 0: pcBoolean->Type.setValue("Fuse"); break; + case 1: pcBoolean->Type.setValue("Cut"); break; + case 2: pcBoolean->Type.setValue("Common"); break; + case 3: pcBoolean->Type.setValue("Section"); break; + default: pcBoolean->Type.setValue("Fuse"); + } + + pcBoolean->getDocument()->recomputeFeature(pcBoolean); +} + +const std::vector TaskBooleanParameters::getBodies(void) const +{ + std::vector result; + for (int i = 0; i < ui->listWidgetBodies->count(); i++) + result.push_back(ui->listWidgetBodies->item(i)->text().toStdString()); + return result; +} + +int TaskBooleanParameters::getType(void) const +{ + return ui->comboType->currentIndex(); +} + +void TaskBooleanParameters::onBodyDeleted(void) +{ + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + std::vector bodies = pcBoolean->Bodies.getValues(); + int index = ui->listWidgetBodies->currentRow(); + if (index > bodies.size()) + return; + App::DocumentObject* body = bodies[index]; + bodies.erase(bodies.begin() + ui->listWidgetBodies->currentRow()); + pcBoolean->Bodies.setValues(bodies); + ui->listWidgetBodies->model()->removeRow(ui->listWidgetBodies->currentRow()); + pcBoolean->getDocument()->recomputeFeature(pcBoolean); + + // Make bodies visible again + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(body)); + if (vp != NULL) + vp->show(); + if (bodies.size() == 1) { + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.front())); + if (vp != NULL) + vp->show(); + BooleanView->hide(); + } +} + +TaskBooleanParameters::~TaskBooleanParameters() +{ + delete ui; +} + +void TaskBooleanParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->comboType->blockSignals(true); + int index = ui->comboType->currentIndex(); + ui->retranslateUi(proxy); + ui->comboType->setCurrentIndex(index); + } +} + +void TaskBooleanParameters::exitSelectionMode() +{ + selectionMode = none; + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setShow(BooleanView->getObject()->getNameInDocument()); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgBooleanParameters::TaskDlgBooleanParameters(ViewProviderBoolean *BooleanView) + : TaskDialog(),BooleanView(BooleanView) +{ + assert(BooleanView); + parameter = new TaskBooleanParameters(BooleanView); + + Content.push_back(parameter); +} + +TaskDlgBooleanParameters::~TaskDlgBooleanParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgBooleanParameters::open() +{ + +} + +void TaskDlgBooleanParameters::clicked(int) +{ + +} + +bool TaskDlgBooleanParameters::accept() +{ + std::string name = BooleanView->getObject()->getNameInDocument(); + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setShow(name.c_str()); + + try { + std::vector bodies = parameter->getBodies(); + std::stringstream str; + str << "App.ActiveDocument." << name.c_str() << ".Bodies = ["; + for (std::vector::const_iterator it = bodies.begin(); it != bodies.end(); ++it) + str << "App.ActiveDocument." << *it << ","; + str << "]"; + Gui::Command::doCommand(Gui::Command::Doc,str.str().c_str()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Boolean: Accept: Input error"), QString::fromAscii(e.what())); + return false; + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getType()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + + return true; +} + +bool TaskDlgBooleanParameters::reject() +{ + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + return true; +} + + + +#include "moc_TaskBooleanParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.h b/src/Mod/PartDesign/Gui/TaskBooleanParameters.h new file mode 100644 index 000000000..6c64a9587 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.h @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_TASKVIEW_TaskBooleanParameters_H +#define GUI_TASKVIEW_TaskBooleanParameters_H + +#include +#include +#include + +#include "ViewProviderBoolean.h" + +class Ui_TaskBooleanParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + + +namespace PartDesignGui { + +class TaskBooleanParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskBooleanParameters(ViewProviderBoolean *BooleanView, QWidget *parent=0); + ~TaskBooleanParameters(); + + const std::vector getBodies(void) const; + int getType(void) const; + +private Q_SLOTS: + void onButtonBodyAdd(const bool checked); + void onButtonBodyRemove(const bool checked); + void onBodyDeleted(void); + void onTypeChanged(int index); + +protected: + void exitSelectionMode(); + +protected: + void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +private: + QWidget* proxy; + Ui_TaskBooleanParameters* ui; + ViewProviderBoolean *BooleanView; + + enum selectionModes { none, bodyAdd, bodyRemove }; + selectionModes selectionMode; + +}; + +/// simulation dialog for the TaskView +class TaskDlgBooleanParameters : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgBooleanParameters(ViewProviderBoolean *BooleanView); + ~TaskDlgBooleanParameters(); + + ViewProviderBoolean* getBooleanView() const + { return BooleanView; } + + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderBoolean *BooleanView; + + TaskBooleanParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.ui b/src/Mod/PartDesign/Gui/TaskBooleanParameters.ui new file mode 100644 index 000000000..8384eb9fd --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.ui @@ -0,0 +1,72 @@ + + + PartDesignGui::TaskBooleanParameters + + + + 0 + 0 + 209 + 185 + + + + Form + + + + + + + + Add body + + + true + + + + + + + Remove body + + + true + + + + + + + + + + + + + Fuse + + + + + Cut + + + + + Common + + + + + Section + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp b/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp new file mode 100644 index 000000000..ffeaa16e6 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +#endif + +#include "ViewProviderBoolean.h" +#include "TaskBooleanParameters.h" +#include +#include +#include +#include +#include + + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderBoolean,PartDesignGui::ViewProvider) + +ViewProviderBoolean::ViewProviderBoolean() +{ + sPixmap = "PartDesign_Boolean.svg"; +} + +ViewProviderBoolean::~ViewProviderBoolean() +{ +} + + +void ViewProviderBoolean::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit boolean"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderBoolean::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this fillet the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgBooleanParameters *booleanDlg = qobject_cast(dlg); + if (booleanDlg && booleanDlg->getBooleanView() != this) + booleanDlg = 0; // another pad left open its task panel + if (dlg && !booleanDlg) { + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + + // start the edit dialog + if (booleanDlg) + Gui::Control().showDialog(booleanDlg); + else + Gui::Control().showDialog(new TaskDlgBooleanParameters(this)); + + return true; + } + else { + return PartGui::ViewProviderPart::setEdit(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(); + 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(); + } + + return ViewProvider::onDelete(s); +} + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderBoolean.h b/src/Mod/PartDesign/Gui/ViewProviderBoolean.h new file mode 100644 index 000000000..90de97000 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderBoolean.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef PARTGUI_ViewProviderBoolean_H +#define PARTGUI_ViewProviderBoolean_H + +#include "ViewProvider.h" + + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderBoolean : public ViewProvider +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderBoolean); + +public: + /// constructor + ViewProviderBoolean(); + /// destructor + virtual ~ViewProviderBoolean(); + + /// grouping handling + void setupContextMenu(QMenu*, QObject*, const char*); + std::vector claimChildren(void)const; + + virtual bool onDelete(const std::vector &); + +protected: + virtual bool setEdit(int ModNum); + +}; + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderBoolean_H diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index b85029593..a4dc29293 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -342,6 +342,16 @@ void Workbench::activated() "Part_Box" )); + const char* Body2[] = { + "PartDesign_Boolean", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::Body COUNT 1..", + Body2, + "Start Boolean", + "Part_Box" + )); + const char* Plane1[] = { "PartDesign_NewSketch", "PartDesign_Plane", @@ -520,7 +530,10 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "PartDesign_LinearPattern" << "PartDesign_PolarPattern" // << "PartDesign_Scaled" - << "PartDesign_MultiTransform"; + << "PartDesign_MultiTransform" + << "Separator" + << "PartDesign_Boolean"; + // For 0.13 a couple of python packages like numpy, matplotlib and others // are not deployed with the installer on Windows. Thus, the WizardShaft is // not deployed either hence the check for the existence of the command. @@ -566,7 +579,9 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "PartDesign_LinearPattern" << "PartDesign_PolarPattern" // << "PartDesign_Scaled" - << "PartDesign_MultiTransform"; + << "PartDesign_MultiTransform" + << "Separator" + << "PartDesign_Boolean"; Gui::ToolBarItem* geom = new Gui::ToolBarItem(root); geom->setCommand("Sketcher geometries");