From 28d8d808a8da5a89c92974a2b4d0772cd380d93b Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Thu, 16 Sep 2021 13:27:46 -0400 Subject: [PATCH] PartDesign: Add new need active body dialog with option to choose body (#4949) * [PD] Add new need active body dialog Intended for use wherever an active body is needed but none exists. The dialog contains a list with the bodies present in the document, with an extra option to make a new body. Custom text can be provided if needed. This commit also replaces the warnings used by "new sketch" and "primitive" command with this new dialog. Addresses issue #4288. --- src/Mod/PartDesign/Gui/CMakeLists.txt | 3 + src/Mod/PartDesign/Gui/Command.cpp | 12 ++- src/Mod/PartDesign/Gui/CommandPrimitive.cpp | 12 ++- src/Mod/PartDesign/Gui/DlgActiveBody.cpp | 95 +++++++++++++++++++++ src/Mod/PartDesign/Gui/DlgActiveBody.h | 59 +++++++++++++ src/Mod/PartDesign/Gui/DlgActiveBody.ui | 88 +++++++++++++++++++ src/Mod/PartDesign/Gui/Utils.cpp | 81 ++++++++++-------- src/Mod/PartDesign/Gui/Utils.h | 16 ++++ 8 files changed, 324 insertions(+), 42 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/DlgActiveBody.cpp create mode 100644 src/Mod/PartDesign/Gui/DlgActiveBody.h create mode 100644 src/Mod/PartDesign/Gui/DlgActiveBody.ui diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 5db22b5752..01c0ad1cc0 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -59,6 +59,7 @@ set(PartDesignGui_UIC_SRCS TaskPipeScaling.ui TaskLoftParameters.ui DlgReference.ui + DlgActiveBody.ui TaskHelixParameters.ui ) @@ -213,6 +214,8 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskHelixParameters.ui TaskHelixParameters.h TaskHelixParameters.cpp + DlgActiveBody.h + DlgActiveBody.cpp ) SOURCE_GROUP("TaskDialogs" FILES ${PartDesignGuiTaskDlgs_SRCS}) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 6b268304d9..77a65c45a2 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -70,6 +70,7 @@ #include "WorkflowManager.h" #include "ViewProvider.h" #include "ViewProviderBody.h" +#include "DlgActiveBody.h" // TODO Remove this header after fixing code so it won;t be needed here (2015-10-20, Fat-Zer) #include "ui_DlgReference.h" @@ -505,12 +506,15 @@ void CmdPartDesignNewSketch::activated(int iMsg) // objects (in which case, just make one) to make a new sketch. pcActiveBody = PartDesignGui::getBody( /* messageIfNot = */ false ); - if (pcActiveBody == nullptr) { - if ( doc->getObjectsOfType(PartDesign::Body::getClassTypeId()).empty() ) { + if (!pcActiveBody) { + if ( doc->countObjectsOfType(PartDesign::Body::getClassTypeId()) == 0 ) { shouldMakeBody = true; } else { - PartDesignGui::needActiveBodyError(); - return; + PartDesignGui::DlgActiveBody dia(Gui::getMainWindow(), doc); + if (dia.exec() == QDialog::DialogCode::Accepted) + pcActiveBody = dia.getActiveBody(); + if (!pcActiveBody) + return; } } diff --git a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp index 22ba6540b7..6aceb1116d 100644 --- a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp +++ b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp @@ -41,6 +41,7 @@ #include "Utils.h" #include "WorkflowManager.h" +#include "DlgActiveBody.h" using namespace std; @@ -85,12 +86,15 @@ void CmdPrimtiveCompAdditive::activated(int iMsg) PartDesign::Body *pcActiveBody = PartDesignGui::getBody( /* messageIfNot = */ false ); auto shouldMakeBody( false ); - if (pcActiveBody == nullptr) { + if (!pcActiveBody) { if ( doc->getObjectsOfType(PartDesign::Body::getClassTypeId()).empty() ) { shouldMakeBody = true; } else { - PartDesignGui::needActiveBodyError(); - return; + PartDesignGui::DlgActiveBody dia(Gui::getMainWindow(), doc); + if (dia.exec() == QDialog::DialogCode::Accepted) + pcActiveBody = dia.getActiveBody(); + if (!pcActiveBody) + return; } } @@ -104,7 +108,7 @@ void CmdPrimtiveCompAdditive::activated(int iMsg) pcActiveBody = PartDesignGui::makeBody(doc); } - if (pcActiveBody == nullptr) { + if (!pcActiveBody) { return; } diff --git a/src/Mod/PartDesign/Gui/DlgActiveBody.cpp b/src/Mod/PartDesign/Gui/DlgActiveBody.cpp new file mode 100644 index 0000000000..aa916d6208 --- /dev/null +++ b/src/Mod/PartDesign/Gui/DlgActiveBody.cpp @@ -0,0 +1,95 @@ + /************************************************************************** + * Copyright (c) 2021 FreeCAD Developers * + * Author: Ajinkya Dahale * + * Based on src/Gui/DlgAddProperty.cpp * + * * + * 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 + +#include "DlgActiveBody.h" +#include "ReferenceSelection.h" +#include "Utils.h" + +Q_DECLARE_METATYPE(App::DocumentObject*); + +using namespace PartDesignGui; + +DlgActiveBody::DlgActiveBody(QWidget *parent, App::Document*& doc, + const QString& infoText) + : QDialog(parent), + ui(new Ui_DlgActiveBody), + _doc(doc), + activeBody(nullptr) +{ + ui->setupUi(this); + + QObject::connect(ui->bodySelect, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this, SLOT(accept())); + + if(!infoText.isEmpty()) { + ui->label->setText(infoText + QString::fromUtf8("\n\n") + + QObject::tr("Please select")); + } + + auto bodies = _doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); + + PartDesign::Body* bodyOfActiveObject = nullptr; + for (const auto &obj : Gui::Selection().getSelection()) { + bodyOfActiveObject = PartDesign::Body::findBodyOf(obj.pObject); + break; // Just get the body for first selected object + } + + for (const auto &body : bodies) { + auto item = new QListWidgetItem(QString::fromUtf8(body->Label.getValue())); + item->setData(Qt::UserRole, QVariant::fromValue(body)); + ui->bodySelect->addItem(item); + + if (body == bodyOfActiveObject) { + item->setSelected(true); + } + + // TODO: Any other logic (hover, select effects on view etc.) + } +} + +void DlgActiveBody::accept() +{ + auto selectedItems = ui->bodySelect->selectedItems(); + if (selectedItems.empty()) + return; + + App::DocumentObject* selectedBody = + selectedItems[0]->data(Qt::UserRole).value(); + if (selectedBody) + activeBody = makeBodyActive(selectedBody, _doc); + else + activeBody = makeBody(_doc); + + QDialog::accept(); +} + +#include "moc_DlgActiveBody.cpp" diff --git a/src/Mod/PartDesign/Gui/DlgActiveBody.h b/src/Mod/PartDesign/Gui/DlgActiveBody.h new file mode 100644 index 0000000000..c73f3c8bcd --- /dev/null +++ b/src/Mod/PartDesign/Gui/DlgActiveBody.h @@ -0,0 +1,59 @@ + /************************************************************************** + * Copyright (c) 2021 FreeCAD Developers * + * Author: Ajinkya Dahale * + * Based on src/Gui/DlgAddProperty.h * + * * + * 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 PARTDESIGNGUI_DLGACTIVEBODY_H +#define PARTDESIGNGUI_DLGACTIVEBODY_H + +#include +#include + +// TODO: Apparently this header can be avoided. See ./Command.cpp:74. +#include "ui_DlgActiveBody.h" + +namespace PartDesignGui { + +/** Dialog box to ask user to pick a Part Design body to make active + * or make a new one + */ +class PartDesignGuiExport DlgActiveBody : public QDialog +{ + Q_OBJECT + +public: + DlgActiveBody(QWidget* parent, App::Document*& doc, + const QString& infoText=QString()); + + void accept() override; + PartDesign::Body* getActiveBody() { return activeBody; }; + +private: + std::unique_ptr ui; + App::Document* _doc; + PartDesign::Body* activeBody; +}; + +} // namespace PartDesignGui + +#endif // PARTDESIGNGUI_DLGACTIVEBODY_H diff --git a/src/Mod/PartDesign/Gui/DlgActiveBody.ui b/src/Mod/PartDesign/Gui/DlgActiveBody.ui new file mode 100644 index 0000000000..84c6506a85 --- /dev/null +++ b/src/Mod/PartDesign/Gui/DlgActiveBody.ui @@ -0,0 +1,88 @@ + + + PartDesignGui::DlgActiveBody + + + + 0 + 0 + 480 + 270 + + + + Active Body Required + + + + + + To create a new PartDesign object, there must be an active Body object in the document. + +Please select a body from below, or create a new body. + + + true + + + true + + + + + + + + Create new body + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + PartDesignGui::DlgActiveBody + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PartDesignGui::DlgActiveBody + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/Mod/PartDesign/Gui/Utils.cpp b/src/Mod/PartDesign/Gui/Utils.cpp index 19536e3cfe..250dfbd280 100644 --- a/src/Mod/PartDesign/Gui/Utils.cpp +++ b/src/Mod/PartDesign/Gui/Utils.cpp @@ -52,6 +52,8 @@ #include "ReferenceSelection.h" #include "Utils.h" #include "WorkflowManager.h" +#include "DlgActiveBody.h" + FC_LOG_LEVEL_INIT("PartDesignGui",true,true) @@ -108,44 +110,30 @@ PartDesign::Body *getBody(bool messageIfNot, bool autoActivate, bool assertModer Gui::MDIView *activeView = Gui::Application::Instance->activeView(); if (activeView) { - bool singleBodyDocument = activeView->getAppDocument()-> - countObjectsOfType(PartDesign::Body::getClassTypeId()) == 1; - if (assertModern && PartDesignGui::assureModernWorkflow ( activeView->getAppDocument() ) ) { + auto doc = activeView->getAppDocument(); + bool singleBodyDocument = doc->countObjectsOfType(PartDesign::Body::getClassTypeId()) == 1; + if (assertModern && PartDesignGui::assureModernWorkflow (doc) ) { activeBody = activeView->getActiveObject(PDBODYKEY,topParent,subname); if (!activeBody && singleBodyDocument && autoActivate) { - auto doc = activeView->getAppDocument(); auto bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); - App::DocumentObject *parent = 0; App::DocumentObject *body = 0; - std::string sub; if(bodies.size()==1) { body = bodies[0]; - for(auto &v : body->getParents()) { - if(v.first->getDocument()!=doc) - continue; - if(parent) { - body = 0; - break; - } - parent = v.first; - sub = v.second; - } - } - if(body) { - auto doc = parent?parent->getDocument():body->getDocument(); - _FCMD_DOC_CMD(Gui,doc,"ActiveView.setActiveObject('" << PDBODYKEY << "'," - << Gui::Command::getObjectCmd(parent?parent:body) << ",'" << sub << "')"); - return activeView->getActiveObject(PDBODYKEY,topParent,subname); + activeBody = makeBodyActive(body, doc, topParent, subname); } } if (!activeBody && messageIfNot) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), + DlgActiveBody dia( + Gui::getMainWindow(), + doc, QObject::tr("In order to use PartDesign you need an active Body object in the document. " - "Please make one active (double click) or create one.\n\nIf you have a legacy document " - "with PartDesign objects without Body, use the migrate function in " - "PartDesign to put them into a Body." - )); + "Please make one active (double click) or create one." + "\n\nIf you have a legacy document with PartDesign objects without Body, " + "use the migrate function in PartDesign to put them into a Body." + )); + if (dia.exec() == QDialog::DialogCode::Accepted) + activeBody = dia.getActiveBody(); } } } @@ -153,6 +141,36 @@ PartDesign::Body *getBody(bool messageIfNot, bool autoActivate, bool assertModer return activeBody; } +PartDesign::Body * makeBodyActive(App::DocumentObject *body, App::Document *doc, + App::DocumentObject **topParent, + std::string *subname) +{ + App::DocumentObject *parent = 0; + std::string sub; + + for(auto &v : body->getParents()) { + if(v.first->getDocument()!=doc) + continue; + if(parent) { + body = 0; + break; + } + parent = v.first; + sub = v.second; + } + + if(body) { + auto _doc = parent?parent->getDocument():body->getDocument(); + _FCMD_DOC_CMD(Gui, _doc, "ActiveView.setActiveObject('" << PDBODYKEY + << "'," << Gui::Command::getObjectCmd(parent?parent:body) + << ",'" << sub << "')"); + return Gui::Application::Instance->activeView()-> + getActiveObject(PDBODYKEY,topParent,subname); + } + + return dynamic_cast(body); +} + void needActiveBodyError(void) { QMessageBox::warning( Gui::getMainWindow(), @@ -170,13 +188,8 @@ PartDesign::Body * makeBody(App::Document *doc) "App.getDocument('%s').addObject('PartDesign::Body','%s')", doc->getName(), bodyName.c_str() ); auto body = dynamic_cast(doc->getObject(bodyName.c_str())); - if(body) { - auto vp = Gui::Application::Instance->getViewProvider(body); - if(vp) { - // make the new body active - vp->doubleClicked(); - } - } + if(body) + makeBodyActive(body, doc); return body; } diff --git a/src/Mod/PartDesign/Gui/Utils.h b/src/Mod/PartDesign/Gui/Utils.h index e9a3aede92..e36725cbf1 100644 --- a/src/Mod/PartDesign/Gui/Utils.h +++ b/src/Mod/PartDesign/Gui/Utils.h @@ -50,6 +50,22 @@ bool setEdit(App::DocumentObject *obj, PartDesign::Body *body = 0); PartDesign::Body *getBody(bool messageIfNot, bool autoActivate=true, bool assertModern=true, App::DocumentObject **topParent=0, std::string *subname=0); +/// Display a dialog to select or create a Body object when none is active +PartDesign::Body * needActiveBodyMessage(App::Document *doc, + const QString& infoText=QString()); + +/** + * Set given body active, and return pointer to it. + * \param body the pointer to the body + * \param doc the pointer to the document in question + * \param topParent and + * \param subname to be passed under certain circumstances + * (currently only subshapebinder) + */ +PartDesign::Body * makeBodyActive(App::DocumentObject *body, App::Document *doc, + App::DocumentObject **topParent=0, + std::string *subname=0); + /// Display error when there are existing Body objects, but none are active void needActiveBodyError(void);