PD: Fix possible crashes in dress-up task panels

This commit is contained in:
wmayer
2024-07-18 15:13:29 +02:00
parent 839fd1fec0
commit c1a7edc221
6 changed files with 162 additions and 123 deletions

View File

@@ -162,13 +162,16 @@ void TaskChamferParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
void TaskChamferParameters::onCheckBoxUseAllEdgesToggled(bool checked)
{
if(checked)
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
ui->buttonRefSel->setEnabled(!checked);
ui->listWidgetReferences->setEnabled(!checked);
pcChamfer->UseAllEdges.setValue(checked);
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
if (auto chamfer = getObject<PartDesign::Chamfer>()) {
if (checked) {
setSelectionMode(none);
}
ui->buttonRefSel->setEnabled(!checked);
ui->listWidgetReferences->setEnabled(!checked);
chamfer->UseAllEdges.setValue(checked);
chamfer->recomputeFeature();
}
}
void TaskChamferParameters::setButtons(const selectionModes mode)
@@ -189,58 +192,63 @@ void TaskChamferParameters::onAddAllEdges()
void TaskChamferParameters::onTypeChanged(int index)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
pcChamfer->ChamferType.setValue(index);
ui->stackedWidget->setCurrentIndex(index);
ui->flipDirection->setEnabled(index != 0); // Enable if type is not "Equal distance"
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
// hide the chamfer if there was a computation error
hideOnError();
if (auto chamfer = getObject<PartDesign::Chamfer>()) {
setSelectionMode(none);
chamfer->ChamferType.setValue(index);
ui->stackedWidget->setCurrentIndex(index);
ui->flipDirection->setEnabled(index != 0); // Enable if type is not "Equal distance"
chamfer->recomputeFeature();
// hide the chamfer if there was a computation error
hideOnError();
}
}
void TaskChamferParameters::onSizeChanged(double len)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->Size.setValue(len);
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
// hide the chamfer if there was a computation error
hideOnError();
if (auto chamfer = getObject<PartDesign::Chamfer>()) {
setSelectionMode(none);
setupTransaction();
chamfer->Size.setValue(len);
chamfer->recomputeFeature();
// hide the chamfer if there was a computation error
hideOnError();
}
}
void TaskChamferParameters::onSize2Changed(double len)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->Size2.setValue(len);
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
// hide the chamfer if there was a computation error
hideOnError();
if (auto chamfer = getObject<PartDesign::Chamfer>()) {
setSelectionMode(none);
setupTransaction();
chamfer->Size2.setValue(len);
chamfer->recomputeFeature();
// hide the chamfer if there was a computation error
hideOnError();
}
}
void TaskChamferParameters::onAngleChanged(double angle)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->Angle.setValue(angle);
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
// hide the chamfer if there was a computation error
hideOnError();
if (auto chamfer = getObject<PartDesign::Chamfer>()) {
setSelectionMode(none);
setupTransaction();
chamfer->Angle.setValue(angle);
chamfer->recomputeFeature();
// hide the chamfer if there was a computation error
hideOnError();
}
}
void TaskChamferParameters::onFlipDirection(bool flip)
{
setSelectionMode(none);
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
setupTransaction();
pcChamfer->FlipDirection.setValue(flip);
pcChamfer->getDocument()->recomputeFeature(pcChamfer);
// hide the chamfer if there was a computation error
hideOnError();
if (auto chamfer = getObject<PartDesign::Chamfer>()) {
setSelectionMode(none);
setupTransaction();
chamfer->FlipDirection.setValue(flip);
chamfer->recomputeFeature();
// hide the chamfer if there was a computation error
hideOnError();
}
}
int TaskChamferParameters::getType() const
@@ -295,13 +303,9 @@ void TaskChamferParameters::changeEvent(QEvent *e)
void TaskChamferParameters::apply()
{
std::string name = DressUpView->getObject()->getNameInDocument();
auto chamfer = getObject<PartDesign::Chamfer>();
//Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Chamfer changed"));
PartDesign::Chamfer* pcChamfer = static_cast<PartDesign::Chamfer*>(DressUpView->getObject());
const int chamfertype = pcChamfer->ChamferType.getValue();
const int chamfertype = chamfer->ChamferType.getValue();
switch(chamfertype) {

View File

@@ -126,9 +126,9 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
referenceSelected(msg, ui->listWidgetReferences);
}
else if (selectionMode == plane) {
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
auto pcDraft = getObject<PartDesign::Draft>();
std::vector<std::string> planes;
App::DocumentObject* selObj;
App::DocumentObject* selObj {};
getReferencedSelection(pcDraft, msg, selObj, planes);
if(!selObj)
return;
@@ -138,12 +138,12 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
pcDraft->getDocument()->recomputeFeature(pcDraft);
// highlight existing references for possible further selections
DressUpView->highlightReferences(true);
getDressUpView()->highlightReferences(true);
// hide the draft if there was a computation error
hideOnError();
}
else if (selectionMode == line) {
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
auto pcDraft = getObject<PartDesign::Draft>();
std::vector<std::string> edges;
App::DocumentObject* selObj;
getReferencedSelection(pcDraft, msg, selObj, edges);
@@ -155,7 +155,7 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
pcDraft->getDocument()->recomputeFeature(pcDraft);
// highlight existing references for possible further selections
DressUpView->highlightReferences(true);
getDressUpView()->highlightReferences(true);
// hide the draft if there was a computation error
hideOnError();
}
@@ -204,7 +204,7 @@ void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector<std::s
{
sub = std::vector<std::string>(1,"");
QStringList parts = ui->linePlane->text().split(QChar::fromLatin1(':'));
obj = DressUpView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str());
obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str());
if (parts.size() > 1)
sub[0] = parts[1].toStdString();
}
@@ -213,20 +213,21 @@ void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector<std::st
{
sub = std::vector<std::string>(1,"");
QStringList parts = ui->lineLine->text().split(QChar::fromLatin1(':'));
obj = DressUpView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str());
obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str());
if (parts.size() > 1)
sub[0] = parts[1].toStdString();
}
void TaskDraftParameters::onAngleChanged(double angle)
{
setButtons(none);
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
setupTransaction();
pcDraft->Angle.setValue(angle);
pcDraft->getDocument()->recomputeFeature(pcDraft);
// hide the draft if there was a computation error
hideOnError();
if (auto draft = getObject<PartDesign::Draft>()) {
setButtons(none);
setupTransaction();
draft->Angle.setValue(angle);
draft->recomputeFeature();
// hide the draft if there was a computation error
hideOnError();
}
}
double TaskDraftParameters::getAngle() const
@@ -234,14 +235,16 @@ double TaskDraftParameters::getAngle() const
return ui->draftAngle->value().getValue();
}
void TaskDraftParameters::onReversedChanged(const bool on) {
setButtons(none);
PartDesign::Draft* pcDraft = static_cast<PartDesign::Draft*>(DressUpView->getObject());
setupTransaction();
pcDraft->Reversed.setValue(on);
pcDraft->getDocument()->recomputeFeature(pcDraft);
// hide the draft if there was a computation error
hideOnError();
void TaskDraftParameters::onReversedChanged(const bool on)
{
if (auto draft = getObject<PartDesign::Draft>()) {
setButtons(none);
setupTransaction();
draft->Reversed.setValue(on);
draft->recomputeFeature();
// hide the draft if there was a computation error
hideOnError();
}
}
bool TaskDraftParameters::getReversed() const

View File

@@ -60,11 +60,11 @@ TaskDressUpParameters::TaskDressUpParameters(ViewProviderDressUp *DressUpView, b
true,
parent)
, proxy(nullptr)
, DressUpView(DressUpView)
, deleteAction(nullptr)
, addAllEdgesAction(nullptr)
, allowFaces(selectFaces)
, allowEdges(selectEdges)
, DressUpView(DressUpView)
{
// remember initial transaction ID
App::GetApplication().getActiveTransaction(&transactionID);
@@ -93,7 +93,7 @@ const QString TaskDressUpParameters::btnSelectStr()
void TaskDressUpParameters::setupTransaction()
{
if (!DressUpView)
if (DressUpView.expired())
return;
int tid = 0;
@@ -143,7 +143,7 @@ void TaskDressUpParameters::addAllEdges(QListWidget* widget)
#ifdef FC_USE_TNP_FIX
Q_UNUSED(widget)
if (!DressUpView) {
if (DressUpView.expired()) {
return;
}
@@ -401,18 +401,31 @@ void TaskDressUpParameters::showObject()
}
}
ViewProviderDressUp* TaskDressUpParameters::getDressUpView() const
{
return DressUpView.expired() ? nullptr : DressUpView.get();
}
Part::Feature* TaskDressUpParameters::getBase() const
{
PartDesign::DressUp* pcDressUp = static_cast<PartDesign::DressUp*>(DressUpView->getObject());
// Unlikely but this may throw an exception in case we are started to edit an object which base feature
// was deleted. This exception will be likely unhandled inside the dialog and pass upper, But an error
// message inside the report view is better than a SEGFAULT.
// Generally this situation should be prevented in ViewProviderDressUp::setEdit()
return pcDressUp->getBaseObject();
if (ViewProviderDressUp* vp = getDressUpView()) {
auto dressUp = dynamic_cast<PartDesign::DressUp*>(vp->getObject());
// Unlikely but this may throw an exception in case we are started to edit an object which
// base feature was deleted. This exception will be likely unhandled inside the dialog and
// pass upper. But an error message inside the report view is better than a SEGFAULT.
// Generally this situation should be prevented in ViewProviderDressUp::setEdit()
return dressUp->getBaseObject();
}
return nullptr;
}
void TaskDressUpParameters::setSelectionMode(selectionModes mode)
{
if (DressUpView.expired()) {
return;
}
selectionMode = mode;
setButtons(mode);

View File

@@ -24,6 +24,7 @@
#ifndef GUI_TASKVIEW_TaskDressUpParameters_H
#define GUI_TASKVIEW_TaskDressUpParameters_H
#include <Gui/DocumentObserver.h>
#include <Gui/TaskView/TaskView.h>
#include <Mod/PartDesign/App/FeatureDressUp.h>
@@ -87,12 +88,20 @@ protected:
virtual void setButtons(const selectionModes mode) = 0;
static void removeItemFromListWidget(QListWidget* widget, const char* itemstr);
ViewProviderDressUp* getDressUpView() const
{ return DressUpView; }
ViewProviderDressUp* getDressUpView() const;
template<typename T = App::DocumentObject> T* getObject() const
{
static_assert(std::is_base_of<App::DocumentObject, T>::value, "Wrong template argument");
if (!DressUpView.expired()) {
return dynamic_cast<T*>(DressUpView->getObject());
}
return nullptr;
}
protected:
QWidget* proxy;
ViewProviderDressUp *DressUpView;
QAction* deleteAction;
QAction* addAllEdgesAction;
@@ -102,6 +111,9 @@ protected:
static const QString btnPreviewStr();
static const QString btnSelectStr();
private:
Gui::WeakPtrT<ViewProviderDressUp> DressUpView;
};
/// simulation dialog for the TaskView

View File

@@ -115,13 +115,16 @@ void TaskFilletParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
void TaskFilletParameters::onCheckBoxUseAllEdgesToggled(bool checked)
{
if (checked)
setSelectionMode(none);
PartDesign::Fillet* pcFillet = static_cast<PartDesign::Fillet*>(DressUpView->getObject());
ui->buttonRefSel->setEnabled(!checked);
ui->listWidgetReferences->setEnabled(!checked);
pcFillet->UseAllEdges.setValue(checked);
pcFillet->getDocument()->recomputeFeature(pcFillet);
if (auto fillet = getObject<PartDesign::Fillet>()) {
if (checked) {
setSelectionMode(none);
}
ui->buttonRefSel->setEnabled(!checked);
ui->listWidgetReferences->setEnabled(!checked);
fillet->UseAllEdges.setValue(checked);
fillet->recomputeFeature();
}
}
void TaskFilletParameters::setButtons(const selectionModes mode)
@@ -142,13 +145,14 @@ void TaskFilletParameters::onAddAllEdges()
void TaskFilletParameters::onLengthChanged(double len)
{
setSelectionMode(none);
PartDesign::Fillet* pcFillet = static_cast<PartDesign::Fillet*>(DressUpView->getObject());
setupTransaction();
pcFillet->Radius.setValue(len);
pcFillet->getDocument()->recomputeFeature(pcFillet);
// hide the fillet if there was a computation error
hideOnError();
if (auto fillet = getObject<PartDesign::Fillet>()) {
setSelectionMode(none);
setupTransaction();
fillet->Radius.setValue(len);
fillet->recomputeFeature();
// hide the fillet if there was a computation error
hideOnError();
}
}
double TaskFilletParameters::getLength() const

View File

@@ -63,8 +63,8 @@ void TaskThicknessParameters::addContainerWidget()
void TaskThicknessParameters::initControls()
{
auto pcThickness = dynamic_cast<PartDesign::Thickness*>(DressUpView->getObject());
double a = pcThickness->Value.getValue();
auto thickness = getObject<PartDesign::Thickness>();
double a = thickness->Value.getValue();
ui->Value->setMinimum(0.0);
ui->Value->setValue(a);
@@ -72,25 +72,25 @@ void TaskThicknessParameters::initControls()
QMetaObject::invokeMethod(ui->Value, "setFocus", Qt::QueuedConnection);
// Bind input fields to properties
ui->Value->bind(pcThickness->Value);
ui->Value->bind(thickness->Value);
bool r = pcThickness->Reversed.getValue();
bool r = thickness->Reversed.getValue();
ui->checkReverse->setChecked(r);
bool i = pcThickness->Intersection.getValue();
bool i = thickness->Intersection.getValue();
ui->checkIntersection->setChecked(i);
std::vector<std::string> strings = pcThickness->Base.getSubValues();
std::vector<std::string> strings = thickness->Base.getSubValues();
for (const auto& string : strings) {
ui->listWidgetReferences->addItem(QString::fromStdString(string));
}
setupConnections();
int mode = static_cast<int>(pcThickness->Mode.getValue());
int mode = static_cast<int>(thickness->Mode.getValue());
ui->modeComboBox->setCurrentIndex(mode);
int join = static_cast<int>(pcThickness->Join.getValue());
int join = static_cast<int>(thickness->Join.getValue());
ui->joinComboBox->setCurrentIndex(join);
if (strings.empty()) {
@@ -156,7 +156,7 @@ PartDesign::Thickness* TaskThicknessParameters::onBeforeChange()
{
setButtons(none);
setupTransaction();
return dynamic_cast<PartDesign::Thickness*>(DressUpView->getObject());
return getObject<PartDesign::Thickness>();
}
void TaskThicknessParameters::onAfterChange(PartDesign::Thickness* obj)
@@ -168,25 +168,26 @@ void TaskThicknessParameters::onAfterChange(PartDesign::Thickness* obj)
void TaskThicknessParameters::onValueChanged(double angle)
{
PartDesign::Thickness* thickness = onBeforeChange();
thickness->Value.setValue(angle);
onAfterChange(thickness);
if (PartDesign::Thickness* thickness = onBeforeChange()) {
thickness->Value.setValue(angle);
onAfterChange(thickness);
}
}
void TaskThicknessParameters::onJoinTypeChanged(int join)
{
PartDesign::Thickness* thickness = onBeforeChange();
thickness->Join.setValue(join);
onAfterChange(thickness);
if (PartDesign::Thickness* thickness = onBeforeChange()) {
thickness->Join.setValue(join);
onAfterChange(thickness);
}
}
void TaskThicknessParameters::onModeChanged(int mode)
{
PartDesign::Thickness* thickness = onBeforeChange();
thickness->Mode.setValue(mode);
onAfterChange(thickness);
if (PartDesign::Thickness* thickness = onBeforeChange()) {
thickness->Mode.setValue(mode);
onAfterChange(thickness);
}
}
double TaskThicknessParameters::getValue() const
@@ -196,9 +197,10 @@ double TaskThicknessParameters::getValue() const
void TaskThicknessParameters::onReversedChanged(bool on)
{
PartDesign::Thickness* thickness = onBeforeChange();
thickness->Reversed.setValue(on);
onAfterChange(thickness);
if (PartDesign::Thickness* thickness = onBeforeChange()) {
thickness->Reversed.setValue(on);
onAfterChange(thickness);
}
}
bool TaskThicknessParameters::getReversed() const
@@ -208,9 +210,10 @@ bool TaskThicknessParameters::getReversed() const
void TaskThicknessParameters::onIntersectionChanged(bool on)
{
PartDesign::Thickness* thickness = onBeforeChange();
thickness->Intersection.setValue(on);
onAfterChange(thickness);
if (PartDesign::Thickness* thickness = onBeforeChange()) {
thickness->Intersection.setValue(on);
onAfterChange(thickness);
}
}
bool TaskThicknessParameters::getIntersection() const