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.
This commit is contained in:
Ajinkya Dahale
2021-09-16 13:27:46 -04:00
committed by GitHub
parent c123bc2bf8
commit 28d8d808a8
8 changed files with 324 additions and 42 deletions

View File

@@ -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})

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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 <QMessageBox>
#endif
#include <Gui/Application.h>
#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<App::DocumentObject*>();
if (selectedBody)
activeBody = makeBodyActive(selectedBody, _doc);
else
activeBody = makeBody(_doc);
QDialog::accept();
}
#include "moc_DlgActiveBody.cpp"

View File

@@ -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 <App/Document.h>
#include <Mod/PartDesign/App/Body.h>
// 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_DlgActiveBody> ui;
App::Document* _doc;
PartDesign::Body* activeBody;
};
} // namespace PartDesignGui
#endif // PARTDESIGNGUI_DLGACTIVEBODY_H

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PartDesignGui::DlgActiveBody</class>
<widget class="QDialog" name="PartDesignGui::DlgActiveBody">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>480</width>
<height>270</height>
</rect>
</property>
<property name="windowTitle">
<string>Active Body Required</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>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.</string>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="bodySelect">
<item>
<property name="text">
<string>Create new body</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PartDesignGui::DlgActiveBody</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PartDesignGui::DlgActiveBody</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -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<PartDesign::Body*>(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<PartDesign::Body*>(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<PartDesign::Body*>(PDBODYKEY,topParent,subname);
}
return dynamic_cast<PartDesign::Body*>(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<PartDesign::Body*>(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;
}

View File

@@ -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);