From b758df71939b6ebc847c143c6ae0f7b73913cb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Wed, 7 Dec 2016 06:23:54 +0100 Subject: [PATCH] Port attachment UI to Part for general use Furthermore change PartDesign primitives to use the new task dialog --- src/Mod/Part/App/AttachExtension.cpp | 1 + src/Mod/Part/Gui/CMakeLists.txt | 4 + src/Mod/Part/Gui/TaskAttacher.cpp | 974 ++++++++++++++++++ src/Mod/Part/Gui/TaskAttacher.h | 174 ++++ .../Gui/TaskAttacher.ui} | 278 ++--- src/Mod/PartDesign/Gui/CMakeLists.txt | 2 - .../PartDesign/Gui/TaskDatumParameters.cpp | 950 +---------------- src/Mod/PartDesign/Gui/TaskDatumParameters.h | 111 +- .../Gui/TaskPrimitiveParameters.cpp | 6 +- .../PartDesign/Gui/TaskPrimitiveParameters.h | 4 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 2 +- 11 files changed, 1329 insertions(+), 1177 deletions(-) create mode 100644 src/Mod/Part/Gui/TaskAttacher.cpp create mode 100644 src/Mod/Part/Gui/TaskAttacher.h rename src/Mod/{PartDesign/Gui/TaskDatumParameters.ui => Part/Gui/TaskAttacher.ui} (60%) diff --git a/src/Mod/Part/App/AttachExtension.cpp b/src/Mod/Part/App/AttachExtension.cpp index f7b9cb542..26f03c3dd 100644 --- a/src/Mod/Part/App/AttachExtension.cpp +++ b/src/Mod/Part/App/AttachExtension.cpp @@ -59,6 +59,7 @@ AttachExtension::AttachExtension() EXTENSION_ADD_PROPERTY_TYPE(superPlacement, (Base::Placement()), "Attachment", App::Prop_None, "Extra placement to apply in addition to attachment (in local coordinates)"); setAttacher(new AttachEngine3D);//default attacher + initExtension(AttachExtension::getExtensionClassTypeId()); } AttachExtension::~AttachExtension() diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index 44f84a737..62c592098 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -47,6 +47,7 @@ set(PartGui_MOC_HDRS TaskThickness.h TaskDimension.h TaskCheckGeometry.h + TaskAttacher.h ) fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartGui_MOC_SRCS}) @@ -76,6 +77,7 @@ set(PartGui_UIC_SRCS TaskLoft.ui TaskOffset.ui TaskSweep.ui + TaskAttacher.ui ) qt4_wrap_ui(PartGui_UIC_HDRS ${PartGui_UIC_SRCS}) @@ -219,6 +221,8 @@ SET(PartGui_SRCS TaskDimension.h TaskCheckGeometry.cpp TaskCheckGeometry.h + TaskAttacher.h + TaskAttacher.cpp ) SET(PartGui_Scripts diff --git a/src/Mod/Part/Gui/TaskAttacher.cpp b/src/Mod/Part/Gui/TaskAttacher.cpp new file mode 100644 index 000000000..41828caf1 --- /dev/null +++ b/src/Mod/Part/Gui/TaskAttacher.cpp @@ -0,0 +1,974 @@ +/*************************************************************************** + * 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 +# include +# include +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui_TaskAttacher.h" +#include "TaskAttacher.h" + +using namespace PartGui; +using namespace Gui; +using namespace Attacher; + +/* TRANSLATOR PartDesignGui::TaskAttacher */ + +// Create reference name from PropertyLinkSub values in a translatable fashion +const QString makeRefString(const App::DocumentObject* obj, const std::string& sub) +{ + if (obj == NULL) + return QObject::tr("No reference selected"); + + if (obj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) || + obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + // App::Plane, Line or Datum feature + return QString::fromLatin1(obj->getNameInDocument()); + + if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) { + int subId = std::atoi(&sub[4]); + return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Face") + QString::number(subId); + } else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) { + int subId = std::atoi(&sub[4]); + return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Edge") + QString::number(subId); + } else if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) { + int subId = std::atoi(&sub[6]); + return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Vertex") + QString::number(subId); + } else { + //something else that face/edge/vertex. Can be empty string. + return QString::fromLatin1(obj->getNameInDocument()) + + (sub.length()>0 ? QString::fromLatin1(":") : QString()) + + QString::fromLatin1(sub.c_str()); + } +} + +void TaskAttacher::makeRefStrings(std::vector& refstrings, std::vector& refnames) { + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::vector refs = pcAttach->Support.getValues(); + refnames = pcAttach->Support.getSubValues(); + + for (size_t r = 0; r < 4; r++) { + if ((r < refs.size()) && (refs[r] != NULL)) { + refstrings.push_back(makeRefString(refs[r], refnames[r])); + } else { + refstrings.push_back(QObject::tr("No reference selected")); + refnames.push_back(""); + } + } +} + +TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider,QWidget *parent, QString picture, QString text) + : TaskBox(Gui::BitmapFactory().pixmap(picture.toLatin1()), text, true, parent), + ViewProvider(ViewProvider) +{ + //check if we are attachable + if(!ViewProvider->getObject()->hasExtension(Part::AttachExtension::getExtensionClassTypeId())) + throw Base::Exception("Object has no PArt::AttachExtension"); + + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskAttacher(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->superplacementX, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementXChanged(double))); + connect(ui->superplacementY, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementYChanged(double))); + connect(ui->superplacementZ, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementZChanged(double))); + connect(ui->superplacementYaw, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementYawChanged(double))); + connect(ui->superplacementPitch, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementPitchChanged(double))); + connect(ui->superplacementRoll, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementRollChanged(double))); + connect(ui->checkBoxFlip, SIGNAL(toggled(bool)), + this, SLOT(onCheckFlip(bool))); + connect(ui->buttonRef1, SIGNAL(clicked(bool)), + this, SLOT(onButtonRef1(bool))); + connect(ui->lineRef1, SIGNAL(textEdited(QString)), + this, SLOT(onRefName1(QString))); + connect(ui->buttonRef2, SIGNAL(clicked(bool)), + this, SLOT(onButtonRef2(bool))); + connect(ui->lineRef2, SIGNAL(textEdited(QString)), + this, SLOT(onRefName2(QString))); + connect(ui->buttonRef3, SIGNAL(clicked(bool)), + this, SLOT(onButtonRef3(bool))); + connect(ui->lineRef3, SIGNAL(textEdited(QString)), + this, SLOT(onRefName3(QString))); + connect(ui->buttonRef4, SIGNAL(clicked(bool)), + this, SLOT(onButtonRef4(bool))); + connect(ui->lineRef4, SIGNAL(textEdited(QString)), + this, SLOT(onRefName4(QString))); + connect(ui->listOfModes,SIGNAL(itemSelectionChanged()), + this, SLOT(onModeSelect())); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->checkBoxFlip->blockSignals(true); + ui->buttonRef1->blockSignals(true); + ui->lineRef1->blockSignals(true); + ui->buttonRef2->blockSignals(true); + ui->lineRef2->blockSignals(true); + ui->buttonRef3->blockSignals(true); + ui->lineRef3->blockSignals(true); + ui->buttonRef4->blockSignals(true); + ui->lineRef4->blockSignals(true); + ui->listOfModes->blockSignals(true); + + // Get the feature data + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::vector refnames = pcAttach->Support.getSubValues(); + + ui->checkBoxFlip->setChecked(pcAttach->MapReversed.getValue()); + std::vector refstrings; + makeRefStrings(refstrings, refnames); + ui->lineRef1->setText(refstrings[0]); + ui->lineRef1->setProperty("RefName", QByteArray(refnames[0].c_str())); + ui->lineRef2->setText(refstrings[1]); + ui->lineRef2->setProperty("RefName", QByteArray(refnames[1].c_str())); + ui->lineRef3->setText(refstrings[2]); + ui->lineRef3->setProperty("RefName", QByteArray(refnames[2].c_str())); + ui->lineRef4->setText(refstrings[3]); + ui->lineRef4->setProperty("RefName", QByteArray(refnames[3].c_str())); + + // activate and de-activate dialog elements as appropriate + ui->checkBoxFlip->blockSignals(false); + ui->buttonRef1->blockSignals(false); + ui->lineRef1->blockSignals(false); + ui->buttonRef2->blockSignals(false); + ui->lineRef2->blockSignals(false); + ui->buttonRef3->blockSignals(false); + ui->lineRef3->blockSignals(false); + ui->buttonRef4->blockSignals(false); + ui->lineRef4->blockSignals(false); + ui->listOfModes->blockSignals(false); + + this->iActiveRef = 0; + if (pcAttach->Support.getSize() == 0){ + autoNext = true; + } else { + autoNext = false; + } + + ui->superplacementX->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Base.x"))); + ui->superplacementY->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Base.y"))); + ui->superplacementZ->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Base.z"))); + visibilityAutomation(true); + updateSuperplacementUI(); + updateReferencesUI(); + updateListOfModes(eMapMode(pcAttach->MapMode.getValue())); + updatePreview(); + + // connect object deletion with slot + auto bnd = boost::bind(&TaskAttacher::objectDeleted, this, _1); + Gui::Document* document = Gui::Application::Instance->getDocument(ViewProvider->getObject()->getDocument()); + connectDelObject = document->signalDeletedObject.connect(bnd); +} + +TaskAttacher::~TaskAttacher() +{ + visibilityAutomation(false); + + connectDelObject.disconnect(); + delete ui; +} + +void TaskAttacher::objectDeleted(const Gui::ViewProviderDocumentObject& view) +{ + if (ViewProvider == &view) + ViewProvider = nullptr; +} + +const QString makeHintText(std::set hint) +{ + QString result; + for (std::set::const_iterator t = hint.begin(); t != hint.end(); t++) { + QString tText; + tText = AttacherGui::getShapeTypeText(*t); + result += QString::fromLatin1(result.size() == 0 ? "" : "/") + tText; + } + + return result; +} + +void TaskAttacher::updateReferencesUI() +{ + + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + + std::vector refs = pcAttach->Support.getValues(); + completed = false; + + // Get hints for further required references... + // DeepSOIC: hint system became useless since inertial system attachment + // modes have been introduced, becuase they accept any number of references + // of any type, so the hint will always be 'Any'. I keep the logic + // nevertheless, in case it is decided to resurrect hint system. + + pcAttach->attacher().suggestMapModes(this->lastSuggestResult); + + if (this->lastSuggestResult.message != SuggestResult::srOK) { + if(this->lastSuggestResult.nextRefTypeHint.size() > 0){ + //message = "Need more references"; + } + } else { + completed = true; + } + + updateRefButton(0); + updateRefButton(1); + updateRefButton(2); + updateRefButton(3); +} + +bool TaskAttacher::updatePreview() +{ + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + QString errMessage; + bool attached = false; + try{ + attached = pcAttach->positionBySupport(); + } catch (Base::Exception &err){ + errMessage = QString::fromLatin1(err.what()); + } catch (Standard_Failure &err){ + errMessage = tr("OCC error: %1").arg(QString::fromLatin1(err.GetMessageString())); + } catch (...) { + errMessage = tr("unknown error"); + } + if (errMessage.length()>0){ + ui->message->setText(tr("Attachment mode failed: %1").arg(errMessage)); + ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}")); + } else { + if (!attached){ + ui->message->setText(tr("Not attached")); + ui->message->setStyleSheet(QString()); + } else { + std::vector strs = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(),eMapMode(pcAttach->MapMode.getValue())); + ui->message->setText(tr("Attached with mode %1").arg(strs[0])); + ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: green;}")); + } + } + QString splmLabelText = attached ? tr("Extra placement:") : tr("Extra placement (inactive - not attached):"); + ui->groupBox_superplacement->setTitle(splmLabelText); + return attached; +} + +QLineEdit* TaskAttacher::getLine(unsigned idx) +{ + switch(idx) { + case 0: return ui->lineRef1; + case 1: return ui->lineRef2; + case 2: return ui->lineRef3; + case 3: return ui->lineRef4; + default: return NULL; + } +} + +void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (iActiveRef < 0) + return; + + // Note: The validity checking has already been done in ReferenceSelection.cpp + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::vector refs = pcAttach->Support.getValues(); + std::vector refnames = pcAttach->Support.getSubValues(); + App::DocumentObject* selObj = ViewProvider->getObject()->getDocument()->getObject(msg.pObjectName); + if (selObj == ViewProvider->getObject()) return;//prevent self-referencing + + std::string subname = msg.pSubName; + + // Remove subname for planes and datum features + if (selObj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) || + selObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + subname = ""; + + // eliminate duplicate selections + for (size_t r = 0; r < refs.size(); r++) + if ((refs[r] == selObj) && (refnames[r] == subname)) + return; + + if (autoNext && iActiveRef > 0 && iActiveRef == (ssize_t) refnames.size()){ + if (refs[iActiveRef-1] == selObj + && refnames[iActiveRef-1].length() != 0 && subname.length() == 0){ + //A whole object was selected by clicking it twice. Fill it + //into previous reference, where a sub-named reference filled by + //the first click is already stored. + + iActiveRef--; + } + } + if (iActiveRef < (ssize_t) refs.size()) { + refs[iActiveRef] = selObj; + refnames[iActiveRef] = subname; + } else { + refs.push_back(selObj); + refnames.push_back(subname); + } + + //bool error = false; + try { + pcAttach->Support.setValues(refs, refnames); + updateListOfModes(); + eMapMode mmode = getActiveMapMode();//will be mmDeactivated, if no modes are available + if(mmode == mmDeactivated){ + //error = true; + this->completed = false; + } else { + this->completed = true; + } + pcAttach->MapMode.setValue(mmode); + updatePreview(); + } + catch(Base::Exception& e) { + //error = true; + ui->message->setText(QString::fromLatin1(e.what())); + ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}")); + } + + QLineEdit* line = getLine(iActiveRef); + if (line != NULL) { + line->blockSignals(true); + line->setText(makeRefString(selObj, subname)); + line->setProperty("RefName", QByteArray(subname.c_str())); + line->blockSignals(false); + } + + if (autoNext) { + if (iActiveRef == -1){ + //nothing to do + } else if (iActiveRef == 4 || this->lastSuggestResult.nextRefTypeHint.size() == 0){ + iActiveRef = -1; + } else { + iActiveRef++; + } + } + + updateReferencesUI(); + } +} + +void TaskAttacher::onSuperplacementChanged(double /*val*/, int idx) +{ + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + Base::Placement pl = pcAttach->superPlacement.getValue(); + + Base::Vector3d pos = pl.getPosition(); + if (idx == 0) { + pos.x = ui->superplacementX->value().getValueAs(Base::Quantity::MilliMetre); + } + if (idx == 1) { + pos.y = ui->superplacementY->value().getValueAs(Base::Quantity::MilliMetre); + } + if (idx == 2) { + pos.z = ui->superplacementZ->value().getValueAs(Base::Quantity::MilliMetre); + } + if (idx >= 0 && idx <= 2){ + pl.setPosition(pos); + } + + Base::Rotation rot = pl.getRotation(); + double yaw, pitch, roll; + rot.getYawPitchRoll(yaw, pitch, roll); + if (idx == 3) { + yaw = ui->superplacementYaw->value().getValueAs(Base::Quantity::Degree); + } + if (idx == 4) { + pitch = ui->superplacementPitch->value().getValueAs(Base::Quantity::Degree); + } + if (idx == 5) { + roll = ui->superplacementRoll->value().getValueAs(Base::Quantity::Degree); + } + if (idx >= 3 && idx <= 5){ + rot.setYawPitchRoll(yaw,pitch,roll); + pl.setRotation(rot); + } + + pcAttach->superPlacement.setValue(pl); + updatePreview(); +} + +void TaskAttacher::onSuperplacementXChanged(double val) +{ + onSuperplacementChanged(val, 0); +} +void TaskAttacher::onSuperplacementYChanged(double val) +{ + onSuperplacementChanged(val, 1); +} +void TaskAttacher::onSuperplacementZChanged(double val) +{ + onSuperplacementChanged(val, 2); +} +void TaskAttacher::onSuperplacementYawChanged(double val) +{ + onSuperplacementChanged(val, 3); +} +void TaskAttacher::onSuperplacementPitchChanged(double val) +{ + onSuperplacementChanged(val, 4); +} +void TaskAttacher::onSuperplacementRollChanged(double val) +{ + onSuperplacementChanged(val, 5); +} + +void TaskAttacher::onCheckFlip(bool on) +{ + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + pcAttach->MapReversed.setValue(on); + ViewProvider->getObject()->getDocument()->recomputeFeature(ViewProvider->getObject()); +} + +void TaskAttacher::onButtonRef(const bool checked, unsigned idx) +{ + autoNext = false; + if (checked) { + Gui::Selection().clearSelection(); + iActiveRef = idx; + } else { + iActiveRef = -1; + } + updateRefButton(0); + updateRefButton(1); + updateRefButton(2); + updateRefButton(3); +} + +void TaskAttacher::onButtonRef1(const bool checked) { + onButtonRef(checked, 0); +} +void TaskAttacher::onButtonRef2(const bool checked) { + onButtonRef(checked, 1); +} +void TaskAttacher::onButtonRef3(const bool checked) { + onButtonRef(checked, 2); +} +void TaskAttacher::onButtonRef4(const bool checked) { + onButtonRef(checked, 3); +} + +void TaskAttacher::onModeSelect() +{ + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + pcAttach->MapMode.setValue(getActiveMapMode()); + updatePreview(); +} + +void TaskAttacher::onRefName(const QString& text, unsigned idx) +{ + QLineEdit* line = getLine(idx); + if (line == NULL) return; + + if (text.length() == 0) { + // Reference was removed + // Update the reference list + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::vector refs = pcAttach->Support.getValues(); + std::vector refnames = pcAttach->Support.getSubValues(); + std::vector newrefs; + std::vector newrefnames; + for (size_t r = 0; r < refs.size(); r++) { + if (r != idx) { + newrefs.push_back(refs[r]); + newrefnames.push_back(refnames[r]); + } + } + pcAttach->Support.setValues(newrefs, newrefnames); + updateListOfModes(); + pcAttach->MapMode.setValue(getActiveMapMode()); + + updatePreview(); + + // Update the UI + std::vector refstrings; + makeRefStrings(refstrings, newrefnames); + ui->lineRef1->setText(refstrings[0]); + ui->lineRef1->setProperty("RefName", QByteArray(newrefnames[0].c_str())); + ui->lineRef2->setText(refstrings[1]); + ui->lineRef2->setProperty("RefName", QByteArray(newrefnames[1].c_str())); + ui->lineRef3->setText(refstrings[2]); + ui->lineRef3->setProperty("RefName", QByteArray(newrefnames[2].c_str())); + ui->lineRef4->setText(refstrings[3]); + ui->lineRef4->setProperty("RefName", QByteArray(newrefnames[3].c_str())); + updateReferencesUI(); + return; + } + + QStringList parts = text.split(QChar::fromLatin1(':')); + if (parts.length() < 2) + parts.push_back(QString::fromLatin1("")); + // Check whether this is the name of an App::Plane or Part::Datum feature + App::DocumentObject* obj = ViewProvider->getObject()->getDocument()->getObject(parts[0].toLatin1()); + if (obj == NULL) return; + + std::string subElement; + + if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + // everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) + subElement = ""; + } else if (obj->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { + // everything is OK (we assume a Part can only have exactly 3 App::Line objects located at the base of the feature tree) + subElement = ""; + } else if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + subElement = ""; + } else { + // TODO: check validity of the text that was entered: Does subElement actually reference to an element on the obj? + + // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. + QRegExp rx; + std::stringstream ss; + + rx.setPattern(QString::fromLatin1("^") + tr("Face") + QString::fromLatin1("(\\d+)$")); + if (parts[1].indexOf(rx) >= 0) { + int faceId = rx.cap(1).toInt(); + ss << "Face" << faceId; + } else { + rx.setPattern(QString::fromLatin1("^") + tr("Edge") + QString::fromLatin1("(\\d+)$")); + if (parts[1].indexOf(rx) >= 0) { + int lineId = rx.cap(1).toInt(); + ss << "Edge" << lineId; + } else { + rx.setPattern(QString::fromLatin1("^") + tr("Vertex") + QString::fromLatin1("(\\d+)$")); + if (parts[1].indexOf(rx) >= 0) { + int vertexId = rx.cap(1).toInt(); + ss << "Vertex" << vertexId; + } else { + //none of Edge/Vertex/Face. May be empty string. + //Feed in whatever user supplied, even if invalid. + ss << parts[1].toLatin1().constData(); + } + } + } + + line->setProperty("RefName", QByteArray(ss.str().c_str())); + subElement = ss.str(); + } + + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::vector refs = pcAttach->Support.getValues(); + std::vector refnames = pcAttach->Support.getSubValues(); + if (idx < refs.size()) { + refs[idx] = obj; + refnames[idx] = subElement.c_str(); + } else { + refs.push_back(obj); + refnames.push_back(subElement.c_str()); + } + pcAttach->Support.setValues(refs, refnames); + updateListOfModes(); + pcAttach->MapMode.setValue(getActiveMapMode()); + + updateReferencesUI(); +} + +void TaskAttacher::updateRefButton(int idx) +{ + QAbstractButton* b; + switch(idx){ + case 0: b = ui->buttonRef1; break; + case 1: b = ui->buttonRef2; break; + case 2: b = ui->buttonRef3; break; + case 3: b = ui->buttonRef4; break; + default: throw Base::Exception("button index out of range"); + } + + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::vector refs = pcAttach->Support.getValues(); + + int numrefs = refs.size(); + bool enable = true; + if (idx > numrefs) + enable = false; + if (idx == numrefs && this->lastSuggestResult.nextRefTypeHint.size() == 0) + enable = false; + b->setEnabled(enable); + + b->setChecked(iActiveRef == idx); + + if (iActiveRef == idx) { + b->setText(tr("Selecting...")); + } else if (idx < static_cast(this->lastSuggestResult.references_Types.size())){ + b->setText(AttacherGui::getShapeTypeText(this->lastSuggestResult.references_Types[idx])); + } else { + b->setText(tr("Reference%1").arg(idx+1)); + } +} + +void TaskAttacher::updateSuperplacementUI() +{ + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + Base::Placement pl = pcAttach->superPlacement.getValue(); + Base::Vector3d pos = pl.getPosition(); + Base::Rotation rot = pl.getRotation(); + double yaw, pitch, roll; + rot.getYawPitchRoll(yaw, pitch, roll); + + bool bBlock = true; + ui->superplacementX->blockSignals(bBlock); + ui->superplacementY->blockSignals(bBlock); + ui->superplacementZ->blockSignals(bBlock); + ui->superplacementYaw->blockSignals(bBlock); + ui->superplacementPitch->blockSignals(bBlock); + ui->superplacementRoll->blockSignals(bBlock); + + ui->superplacementX->setValue(Base::Quantity(pos.x,Base::Unit::Length)); + ui->superplacementY->setValue(Base::Quantity(pos.y,Base::Unit::Length)); + ui->superplacementZ->setValue(Base::Quantity(pos.z,Base::Unit::Length)); + ui->superplacementYaw->setValue(yaw); + ui->superplacementPitch->setValue(pitch); + ui->superplacementRoll->setValue(roll); + + auto expressions = ViewProvider->getObject()->ExpressionEngine.getExpressions(); + bool bRotationBound = false; + bRotationBound = bRotationBound || + expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Rotation.Angle"))) != expressions.end(); + bRotationBound = bRotationBound || + expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Rotation.Axis.x"))) != expressions.end(); + bRotationBound = bRotationBound || + expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Rotation.Axis.y"))) != expressions.end(); + bRotationBound = bRotationBound || + expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("superPlacement.Rotation.Axis.z"))) != expressions.end(); + + ui->superplacementYaw->setEnabled(!bRotationBound); + ui->superplacementPitch->setEnabled(!bRotationBound); + ui->superplacementRoll->setEnabled(!bRotationBound); + + QString tooltip = bRotationBound ? tr("Not editable because rotation part of superplacement is bound by expressions.") : QString(); + ui->superplacementYaw->setToolTip(tooltip); + ui->superplacementPitch->setToolTip(tooltip); + ui->superplacementRoll->setToolTip(tooltip); + + bBlock = false; + ui->superplacementX->blockSignals(bBlock); + ui->superplacementY->blockSignals(bBlock); + ui->superplacementZ->blockSignals(bBlock); + ui->superplacementYaw->blockSignals(bBlock); + ui->superplacementPitch->blockSignals(bBlock); + ui->superplacementRoll->blockSignals(bBlock); +} + +void TaskAttacher::updateListOfModes(eMapMode curMode) +{ + //first up, remember currently selected mode. + if (curMode == mmDeactivated){ + auto sel = ui->listOfModes->selectedItems(); + if (sel.count() > 0) + curMode = modesInList[ui->listOfModes->row(sel[0])]; + } + + //obtain list of available modes: + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + this->lastSuggestResult.bestFitMode = mmDeactivated; + size_t lastValidModeItemIndex = mmDummy_NumberOfModes; + if (pcAttach->Support.getSize() > 0){ + pcAttach->attacher().suggestMapModes(this->lastSuggestResult); + modesInList = this->lastSuggestResult.allApplicableModes; + //add reachable modes to the list, too, but gray them out (using lastValidModeItemIndex, later) + lastValidModeItemIndex = modesInList.size()-1; + for(std::pair &rm: this->lastSuggestResult.reachableModes){ + modesInList.push_back(rm.first); + } + } else { + //no references - display all modes + modesInList.clear(); + for( int mmode = 0 ; mmode < mmDummy_NumberOfModes ; mmode++){ + if (pcAttach->attacher().modeEnabled[mmode]) + modesInList.push_back(eMapMode(mmode)); + } + } + + //populate list + ui->listOfModes->blockSignals(true); + ui->listOfModes->clear(); + QListWidgetItem* iSelect = 0; + if (modesInList.size()>0) { + for (size_t i = 0 ; i < modesInList.size() ; ++i){ + eMapMode mmode = modesInList[i]; + std::vector mstr = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(),mmode); + ui->listOfModes->addItem(mstr[0]); + QListWidgetItem* item = ui->listOfModes->item(i); + item->setToolTip(mstr[1] + QString::fromLatin1("\n\n") + + tr("Reference combinations:\n") + + AttacherGui::getRefListForMode(pcAttach->attacher(),mmode).join(QString::fromLatin1("\n"))); + if (mmode == curMode) + iSelect = ui->listOfModes->item(i); + if (i > lastValidModeItemIndex){ + //potential mode - can be reached by selecting more stuff + item->setFlags(item->flags() & ~(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable)); + + refTypeStringList &extraRefs = this->lastSuggestResult.reachableModes[mmode]; + if (extraRefs.size() == 1){ + QStringList buf; + for(eRefType rt : extraRefs[0]){ + buf.append(AttacherGui::getShapeTypeText(rt)); + } + item->setText(tr("%1 (add %2)").arg( + item->text(), + buf.join(QString::fromLatin1("+")) + )); + } else { + item->setText(tr("%1 (add more references)").arg(item->text())); + } + } else if (mmode == this->lastSuggestResult.bestFitMode){ + //suggested mode - make bold + assert (item); + QFont fnt = item->font(); + fnt.setBold(true); + item->setFont(fnt); + } + + } + } + //restore selection + ui->listOfModes->selectedItems().clear(); + if (iSelect) + iSelect->setSelected(true); + ui->listOfModes->blockSignals(false); +} + +Attacher::eMapMode TaskAttacher::getActiveMapMode() +{ + auto sel = ui->listOfModes->selectedItems(); + if (sel.count() > 0) + return modesInList[ui->listOfModes->row(sel[0])]; + else { + if (this->lastSuggestResult.message == SuggestResult::srOK) + return this->lastSuggestResult.bestFitMode; + else + return mmDeactivated; + }; +} + +void TaskAttacher::onRefName1(const QString& text) +{ + onRefName(text, 0); +} +void TaskAttacher::onRefName2(const QString& text) +{ + onRefName(text, 1); +} +void TaskAttacher::onRefName3(const QString& text) +{ + onRefName(text, 2); +} +void TaskAttacher::onRefName4(const QString &text) +{ + onRefName(text, 3); +} + + +bool TaskAttacher::getFlip() const +{ + return ui->checkBoxFlip->isChecked(); +} + +void TaskAttacher::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->checkBoxFlip->blockSignals(true); + ui->buttonRef1->blockSignals(true); + ui->lineRef1->blockSignals(true); + ui->buttonRef2->blockSignals(true); + ui->lineRef2->blockSignals(true); + ui->buttonRef3->blockSignals(true); + ui->lineRef3->blockSignals(true); + ui->buttonRef4->blockSignals(true); + ui->lineRef4->blockSignals(true); + ui->retranslateUi(proxy); + + std::vector refnames; + std::vector refstrings; + makeRefStrings(refstrings, refnames); + ui->lineRef1->setText(refstrings[0]); + ui->lineRef2->setText(refstrings[1]); + ui->lineRef3->setText(refstrings[2]); + ui->lineRef3->setText(refstrings[3]); + updateListOfModes(); + + ui->checkBoxFlip->blockSignals(false); + ui->buttonRef1->blockSignals(false); + ui->lineRef1->blockSignals(false); + ui->buttonRef2->blockSignals(false); + ui->lineRef2->blockSignals(false); + ui->buttonRef3->blockSignals(false); + ui->lineRef3->blockSignals(false); + ui->buttonRef4->blockSignals(false); + ui->lineRef4->blockSignals(false); + } +} + +void TaskAttacher::visibilityAutomation(bool opening_not_closing) +{ + if (opening_not_closing){ + //crash guards + if (!ViewProvider) + return; + if (!ViewProvider->getObject()) + return; + if (!ViewProvider->getObject()->getNameInDocument()) + return; + try{ + QString code = QString::fromLatin1( + "import TempoVis\n" + "from Show.DepGraphTools import getAllDependent, isContainer\n" + "tv = TempoVis.TempoVis(App.ActiveDocument)\n" + "dep_features = [o for o in getAllDependent(%1) if not isContainer(o)]\n" + "if %1.isDerivedFrom('PartDesign::CoordinateSystem'):\n" + "\tvisible_features = [feat for feat in %1.InList if feat.isDerivedFrom('PartDesign::FeaturePrimitive')]\n" + "\tdep_features = [feat for feat in dep_features if feat not in visible_features]\n" + "tv.hide(dep_features)\n" + "if not %1.isDerivedFrom('PartDesign::CoordinateSystem'):\n" + "\t\tif len(%1.Support) > 0:\n" + "\t\t\ttv.show([lnk[0] for lnk in %1.Support])" + ); + QByteArray code_2 = code.arg( + QString::fromLatin1("App.ActiveDocument.") + + QString::fromLatin1(ViewProvider->getObject()->getNameInDocument()) + ).toLatin1(); + Base::Interpreter().runString(code_2.constData()); + } + catch (Base::PyException &e){ + e.ReportException(); + } + } + else { + try { + Base::Interpreter().runString("del(tv)"); + } + catch (Base::PyException &e) { + e.ReportException(); + } + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgAttacher::TaskDlgAttacher(Gui::ViewProviderDocumentObject *ViewProvider) + : TaskDialog(),ViewProvider(ViewProvider) +{ + assert(ViewProvider); + parameter = new TaskAttacher(ViewProvider); + + Content.push_back(parameter); +} + +TaskDlgAttacher::~TaskDlgAttacher() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgAttacher::open() +{ + +} + +void TaskDlgAttacher::clicked(int) +{ + +} + +bool TaskDlgAttacher::accept() +{ + + try { + Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType(); + std::string name = ViewProvider->getObject()->getNameInDocument(); + + //DeepSOIC: changed this to heavily rely on dialog constantly updating feature properties + if (pcAttach->superPlacement.isTouched()){ + Base::Placement plm = pcAttach->superPlacement.getValue(); + double yaw, pitch, roll; + plm.getRotation().getYawPitchRoll(yaw,pitch,roll); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.superPlacement = App.Placement(App.Vector(%.10f, %.10f, %.10f), App.Rotation(%.10f, %.10f, %.10f))", + name.c_str(), + plm.getPosition().x, plm.getPosition().y, plm.getPosition().z, + yaw, pitch, roll); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MapReversed = %s", name.c_str(), pcAttach->MapReversed.getValue() ? "True" : "False"); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Support = %s", name.c_str(), pcAttach->Support.getPyReprString().c_str()); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MapMode = '%s'", name.c_str(), AttachEngine::getModeName(eMapMode(pcAttach->MapMode.getValue())).c_str()); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!ViewProvider->getObject()->isValid()) + throw Base::Exception(ViewProvider->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Datum dialog: Input error"), QString::fromLatin1(e.what())); + return false; + } + + return true; +} + +bool TaskDlgAttacher::reject() +{ + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + return true; +} + + + +#include "moc_TaskAttacher.cpp" diff --git a/src/Mod/Part/Gui/TaskAttacher.h b/src/Mod/Part/Gui/TaskAttacher.h new file mode 100644 index 000000000..e8740c2c9 --- /dev/null +++ b/src/Mod/Part/Gui/TaskAttacher.h @@ -0,0 +1,174 @@ +/*************************************************************************** + * 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 GUI_TASKVIEW_TaskAttacher_H +#define GUI_TASKVIEW_TaskAttacher_H + +#include +#include +#include +#include + +#include "Gui/ViewProviderDocumentObject.h" + +class Ui_TaskAttacher; +class QLineEdit; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartGui { + +class Ui_TaskAttacher; + +class TaskAttacher : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider,QWidget *parent = 0, + QString picture = QString::fromLatin1(""), QString text = QString::fromLatin1("Attachment")); + ~TaskAttacher(); + + bool getFlip(void) const; + + /** + * @brief getActiveMapMode returns either the default mode for selected + * references, or the mode that was selected by the user in the list. If + * no modes fit current set of references, mmDeactivated is returned. + */ + Attacher::eMapMode getActiveMapMode(); + + bool isCompleted() const { return completed; } + +private Q_SLOTS: + void onSuperplacementChanged(double, int idx); + void onSuperplacementXChanged(double); + void onSuperplacementYChanged(double); + void onSuperplacementZChanged(double); + void onSuperplacementYawChanged(double); + void onSuperplacementPitchChanged(double); + void onSuperplacementRollChanged(double); + void onCheckFlip(bool); + void onRefName1(const QString& text); + void onRefName2(const QString& text); + void onRefName3(const QString& text); + void onRefName4(const QString& text); + void onButtonRef1(const bool checked = true); + void onButtonRef2(const bool checked = true); + void onButtonRef3(const bool checked = true); + void onButtonRef4(const bool checked = true); + void onModeSelect(void); + void visibilityAutomation(bool opening_not_closing); + +protected: + void changeEvent(QEvent *e); +private: + void objectDeleted(const Gui::ViewProviderDocumentObject&); + void onSelectionChanged(const Gui::SelectionChanges& msg) override; + void updateReferencesUI(); + + /** + * @brief updatePreview: calculate attachment, update 3d view, update status message + * @return true if attachment calculation was successful, false otherwise + */ + bool updatePreview(); + + void makeRefStrings(std::vector& refstrings, std::vector& refnames); + QLineEdit* getLine(unsigned idx); + void onButtonRef(const bool checked, unsigned idx); + void onRefName(const QString& text, unsigned idx); + void updateRefButton(int idx); + void updateSuperplacementUI(); + + /** + * @brief updateListOfModes Fills the mode list with modes that apply to + * current set of references. + * @param curMode the mode to select in the list. If the mode isn't + * contained in the list, nothing is selected. If mmDeactivated is passed, + * currently selected mode is kept. + */ + void updateListOfModes(Attacher::eMapMode curMode = Attacher::mmDeactivated); + +protected: + Gui::ViewProviderDocumentObject *ViewProvider; + +private: + QWidget* proxy; + Ui_TaskAttacher* ui; + + // TODO fix documentation here (2015-11-10, Fat-Zer) + int iActiveRef; //what reference is being picked in 3d view now? -1 means no one, 0-3 means a reference is being picked. + bool autoNext;//if we should automatically switch to next reference (true after dialog launch, false afterwards) + std::vector modesInList; //this list is synchronous to what is populated into listOfModes widget. + Attacher::SuggestResult lastSuggestResult; + bool completed; + + typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection; + Connection connectDelObject; +}; + +/// simulation dialog for the TaskView +class TaskDlgAttacher : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgAttacher(Gui::ViewProviderDocumentObject *ViewProvider); + ~TaskDlgAttacher(); + + Gui::ViewProviderDocumentObject* getViewProvider() const + { return ViewProvider; } + + +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: + Gui::ViewProviderDocumentObject *ViewProvider; + + TaskAttacher *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui b/src/Mod/Part/Gui/TaskAttacher.ui similarity index 60% rename from src/Mod/PartDesign/Gui/TaskDatumParameters.ui rename to src/Mod/Part/Gui/TaskAttacher.ui index a193dc06e..d3130c6af 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui +++ b/src/Mod/Part/Gui/TaskAttacher.ui @@ -1,7 +1,7 @@ - PartDesignGui::TaskDatumParameters - + PartGui::TaskAttacher + 0 @@ -125,118 +125,118 @@ - - - - 0 - 0 - - - + + + + 0 + 0 + + + X: - + labelOffset - - - + + + - - - - 0 - 0 - - - + + + + 0 + 0 + + + Y: - - - + + + - - - - 0 - 0 - - + + + + 0 + 0 + + 0 5 - - + + - - - - 0 - 0 - - - + + + + 0 + 0 + + + Z: - - - + + + - - - - 0 - 0 - - + + + + 0 + 0 + + 0 5 - - + + - - - - 0 - 0 - - - + + + + 0 + 0 + + + Yaw: - - - + + + - + - 0 - 0 - - + 0 + 0 + + Pitch: - - - + + + - - - 0 - 0 - - - + + + 0 + 0 + + + Roll: - - - + + + @@ -254,72 +254,72 @@ - - - - 0 - 0 - - - - deg - - - -360.000000000000000 - - - 360.000000000000000 - - - 0.000000000000000 - - - - - - + + - 0 - 0 - - + 0 + 0 + + deg - + -360.000000000000000 - + 360.000000000000000 - + 0.000000000000000 - - - + + + + + + + + 0 + 0 + + + + deg + + + -360.000000000000000 + + + 360.000000000000000 + + + 0.000000000000000 + + + - - - - 0 - 0 - - - - deg - - - -360.000000000000000 - - - 360.000000000000000 - - - 0.000000000000000 - - - - + + + + 0 + 0 + + + + deg + + + -360.000000000000000 + + + 360.000000000000000 + + + 0.000000000000000 + + + + diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 3ecf6f512..46506f28f 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -76,7 +76,6 @@ set(PartDesignGui_UIC_SRCS TaskPolarPatternParameters.ui TaskScaledParameters.ui TaskMultiTransformParameters.ui - TaskDatumParameters.ui TaskShapeBinder.ui TaskPrimitiveParameters.ui TaskPipeParameters.ui @@ -207,7 +206,6 @@ SET(PartDesignGuiTaskDlgs_SRCS #TaskHoleParameters.ui #TaskHoleParameters.cpp #TaskHoleParameters.h - TaskDatumParameters.ui TaskDatumParameters.cpp TaskDatumParameters.h TaskShapeBinder.ui diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 370218d61..7d1cd8915 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -58,7 +58,6 @@ #include "ReferenceSelection.h" #include "Utils.h" -#include "ui_TaskDatumParameters.h" #include "TaskDatumParameters.h" #include "TaskFeaturePick.h" @@ -68,881 +67,34 @@ using namespace Attacher; /* TRANSLATOR PartDesignGui::TaskDatumParameters */ -// Create reference name from PropertyLinkSub values in a translatable fashion -const QString makeRefString(const App::DocumentObject* obj, const std::string& sub) +TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *ViewProvider,QWidget *parent) + : PartGui::TaskAttacher(ViewProvider, parent, QString::fromLatin1("PartDesign_") + ViewProvider->datumType, + ViewProvider->datumType + tr(" parameters")) { - if (obj == NULL) - return QObject::tr("No reference selected"); - - if (obj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) || - obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - // App::Plane, Liine or Datum feature - return QString::fromLatin1(obj->getNameInDocument()); - - if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) { - int subId = std::atoi(&sub[4]); - return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Face") + QString::number(subId); - } else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) { - int subId = std::atoi(&sub[4]); - return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Edge") + QString::number(subId); - } else if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) { - int subId = std::atoi(&sub[6]); - return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Vertex") + QString::number(subId); - } else { - //something else that face/edge/vertex. Can be empty string. - return QString::fromLatin1(obj->getNameInDocument()) - + (sub.length()>0 ? QString::fromLatin1(":") : QString()) - + QString::fromLatin1(sub.c_str()); - } -} - -void TaskDatumParameters::makeRefStrings(std::vector& refstrings, std::vector& refnames) { - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->Support.getValues(); - refnames = pcDatum->Support.getSubValues(); - - for (size_t r = 0; r < 4; r++) { - if ((r < refs.size()) && (refs[r] != NULL)) { - refstrings.push_back(makeRefString(refs[r], refnames[r])); - } else { - refstrings.push_back(QObject::tr("No reference selected")); - refnames.push_back(""); - } - } -} - -TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap((QString::fromLatin1("PartDesign_") + DatumView->datumType).toLatin1()), - DatumView->datumType + tr(" parameters"), true, parent), - DatumView(DatumView) -{ - // we need a separate container widget to add all controls to - proxy = new QWidget(this); - ui = new Ui_TaskDatumParameters(); - ui->setupUi(proxy); - QMetaObject::connectSlotsByName(this); - - connect(ui->superplacementX, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementXChanged(double))); - connect(ui->superplacementY, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementYChanged(double))); - connect(ui->superplacementZ, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementZChanged(double))); - connect(ui->superplacementYaw, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementYawChanged(double))); - connect(ui->superplacementPitch, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementPitchChanged(double))); - connect(ui->superplacementRoll, SIGNAL(valueChanged(double)), this, SLOT(onSuperplacementRollChanged(double))); - connect(ui->checkBoxFlip, SIGNAL(toggled(bool)), - this, SLOT(onCheckFlip(bool))); - connect(ui->buttonRef1, SIGNAL(clicked(bool)), - this, SLOT(onButtonRef1(bool))); - connect(ui->lineRef1, SIGNAL(textEdited(QString)), - this, SLOT(onRefName1(QString))); - connect(ui->buttonRef2, SIGNAL(clicked(bool)), - this, SLOT(onButtonRef2(bool))); - connect(ui->lineRef2, SIGNAL(textEdited(QString)), - this, SLOT(onRefName2(QString))); - connect(ui->buttonRef3, SIGNAL(clicked(bool)), - this, SLOT(onButtonRef3(bool))); - connect(ui->lineRef3, SIGNAL(textEdited(QString)), - this, SLOT(onRefName3(QString))); - connect(ui->buttonRef4, SIGNAL(clicked(bool)), - this, SLOT(onButtonRef4(bool))); - connect(ui->lineRef4, SIGNAL(textEdited(QString)), - this, SLOT(onRefName4(QString))); - connect(ui->listOfModes,SIGNAL(itemSelectionChanged()), - this, SLOT(onModeSelect())); - - this->groupLayout()->addWidget(proxy); - - // Temporarily prevent unnecessary feature recomputes - ui->checkBoxFlip->blockSignals(true); - ui->buttonRef1->blockSignals(true); - ui->lineRef1->blockSignals(true); - ui->buttonRef2->blockSignals(true); - ui->lineRef2->blockSignals(true); - ui->buttonRef3->blockSignals(true); - ui->lineRef3->blockSignals(true); - ui->buttonRef4->blockSignals(true); - ui->lineRef4->blockSignals(true); - ui->listOfModes->blockSignals(true); - - // Get the feature data - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - //std::vector refs = pcDatum->Support.getValues(); - std::vector refnames = pcDatum->Support.getSubValues(); - - ui->checkBoxFlip->setChecked(pcDatum->MapReversed.getValue()); - std::vector refstrings; - makeRefStrings(refstrings, refnames); - ui->lineRef1->setText(refstrings[0]); - ui->lineRef1->setProperty("RefName", QByteArray(refnames[0].c_str())); - ui->lineRef2->setText(refstrings[1]); - ui->lineRef2->setProperty("RefName", QByteArray(refnames[1].c_str())); - ui->lineRef3->setText(refstrings[2]); - ui->lineRef3->setProperty("RefName", QByteArray(refnames[2].c_str())); - ui->lineRef4->setText(refstrings[3]); - ui->lineRef4->setProperty("RefName", QByteArray(refnames[3].c_str())); - - // activate and de-activate dialog elements as appropriate - ui->checkBoxFlip->blockSignals(false); - ui->buttonRef1->blockSignals(false); - ui->lineRef1->blockSignals(false); - ui->buttonRef2->blockSignals(false); - ui->lineRef2->blockSignals(false); - ui->buttonRef3->blockSignals(false); - ui->lineRef3->blockSignals(false); - ui->buttonRef4->blockSignals(false); - ui->lineRef4->blockSignals(false); - ui->listOfModes->blockSignals(false); - - this->iActiveRef = 0; - if (pcDatum->Support.getSize() == 0){ - autoNext = true; - } else { - autoNext = false; - } - - ui->superplacementX->bind(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Base.x"))); - ui->superplacementY->bind(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Base.y"))); - ui->superplacementZ->bind(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Base.z"))); - visibilityAutomation(true); - updateSuperplacementUI(); - updateReferencesUI(); - updateListOfModes(eMapMode(pcDatum->MapMode.getValue())); - updatePreview(); - - //temporary show coordinate systems for selection - PartDesign::Body * body = PartDesign::Body::findBodyOf(DatumView->getObject()); - if (body) { - try { - App::Origin *origin = body->getOrigin(); - ViewProviderOrigin* vpOrigin; - vpOrigin = static_cast(Gui::Application::Instance->getViewProvider(origin)); - vpOrigin->setTemporaryVisibility(true, true); - } catch (const Base::Exception &ex) { - Base::Console().Error ("%s\n", ex.what () ); - } - } - - DatumView->setPickable(false); - - Gui::Selection().addSelectionGate(new NoDependentsSelection(DatumView->getObject())); - - // connect object deletion with slot - auto bnd = boost::bind(&TaskDatumParameters::objectDeleted, this, _1); - Gui::Document* document = Gui::Application::Instance->getDocument(DatumView->getObject()->getDocument()); - connectDelObject = document->signalDeletedObject.connect(bnd); + Gui::Selection().addSelectionGate(new NoDependentsSelection(ViewProvider->getObject())); + ViewProvider->setPickable(false); } TaskDatumParameters::~TaskDatumParameters() { - visibilityAutomation(false); Gui::Selection().rmvSelectionGate(); - - connectDelObject.disconnect(); - if (DatumView) - resetViewMode(); - delete ui; + static_cast(ViewProvider)->setPickable(true); } -void TaskDatumParameters::resetViewMode() -{ - //end temporary view mode of coordinate system - PartDesign::Body * body = PartDesign::Body::findBodyOf(DatumView->getObject()); - if (body) { - try { - App::Origin *origin = body->getOrigin(); - ViewProviderOrigin* vpOrigin; - vpOrigin = static_cast(Gui::Application::Instance->getViewProvider(origin)); - vpOrigin->resetTemporaryVisibility(); - } - catch (const Base::Exception &ex) { - Base::Console().Error("%s\n", ex.what()); - } - } - - DatumView->setPickable(true); -} - -void TaskDatumParameters::objectDeleted(const Gui::ViewProviderDocumentObject& view) -{ - if (DatumView == &view) - DatumView = nullptr; -} - -const QString makeHintText(std::set hint) -{ - QString result; - for (std::set::const_iterator t = hint.begin(); t != hint.end(); t++) { - QString tText; - tText = AttacherGui::getShapeTypeText(*t); - result += QString::fromLatin1(result.size() == 0 ? "" : "/") + tText; - } - - return result; -} - -void TaskDatumParameters::updateReferencesUI() -{ - - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - - std::vector refs = pcDatum->Support.getValues(); - completed = false; - - // Get hints for further required references... - // DeepSOIC: hint system became useless since inertial system attachment - // modes have been introduced, becuase they accept any number of references - // of any type, so the hint will always be 'Any'. I keep the logic - // nevertheless, in case it is decided to resurrect hint system. - - pcDatum->attacher().suggestMapModes(this->lastSuggestResult); - - if (this->lastSuggestResult.message != SuggestResult::srOK) { - if(this->lastSuggestResult.nextRefTypeHint.size() > 0){ - //message = "Need more references"; - } - } else { - completed = true; - } - - updateRefButton(0); - updateRefButton(1); - updateRefButton(2); - updateRefButton(3); -} - -bool TaskDatumParameters::updatePreview() -{ - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - QString errMessage; - bool attached = false; - try{ - attached = pcDatum->positionBySupport(); - } catch (Base::Exception &err){ - errMessage = QString::fromLatin1(err.what()); - } catch (Standard_Failure &err){ - errMessage = tr("OCC error: %1").arg(QString::fromLatin1(err.GetMessageString())); - } catch (...) { - errMessage = tr("unknown error"); - } - if (errMessage.length()>0){ - ui->message->setText(tr("Attachment mode failed: %1").arg(errMessage)); - ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}")); - } else { - if (!attached){ - ui->message->setText(tr("Not attached")); - ui->message->setStyleSheet(QString()); - } else { - std::vector strs = AttacherGui::getUIStrings(pcDatum->attacher().getTypeId(),eMapMode(pcDatum->MapMode.getValue())); - ui->message->setText(tr("Attached with mode %1").arg(strs[0])); - ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: green;}")); - } - } - QString splmLabelText = attached ? tr("Extra placement:") : tr("Extra placement (inactive - not attached):"); - ui->groupBox_superplacement->setTitle(splmLabelText); - return attached; -} - -QLineEdit* TaskDatumParameters::getLine(unsigned idx) -{ - switch(idx) { - case 0: return ui->lineRef1; - case 1: return ui->lineRef2; - case 2: return ui->lineRef3; - case 3: return ui->lineRef4; - default: return NULL; - } -} - -void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) -{ - if (msg.Type == Gui::SelectionChanges::AddSelection) { - if (iActiveRef < 0) - return; - - // Note: The validity checking has already been done in ReferenceSelection.cpp - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->Support.getValues(); - std::vector refnames = pcDatum->Support.getSubValues(); - App::DocumentObject* selObj = pcDatum->getDocument()->getObject(msg.pObjectName); - if (selObj == pcDatum) return;//prevent self-referencing - - std::string subname = msg.pSubName; - - // Remove subname for planes and datum features - if (selObj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) || - selObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - subname = ""; - - // eliminate duplicate selections - for (size_t r = 0; r < refs.size(); r++) - if ((refs[r] == selObj) && (refnames[r] == subname)) - return; - - if (autoNext && iActiveRef > 0 && iActiveRef == (ssize_t) refnames.size()){ - if (refs[iActiveRef-1] == selObj - && refnames[iActiveRef-1].length() != 0 && subname.length() == 0){ - //A whole object was selected by clicking it twice. Fill it - //into previous reference, where a sub-named reference filled by - //the first click is already stored. - - iActiveRef--; - } - } - if (iActiveRef < (ssize_t) refs.size()) { - refs[iActiveRef] = selObj; - refnames[iActiveRef] = subname; - } else { - refs.push_back(selObj); - refnames.push_back(subname); - } - - //bool error = false; - try { - pcDatum->Support.setValues(refs, refnames); - updateListOfModes(); - eMapMode mmode = getActiveMapMode();//will be mmDeactivated, if no modes are available - if(mmode == mmDeactivated){ - //error = true; - this->completed = false; - } else { - this->completed = true; - } - pcDatum->MapMode.setValue(mmode); - updatePreview(); - } - catch(Base::Exception& e) { - //error = true; - ui->message->setText(QString::fromLatin1(e.what())); - ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}")); - } - - QLineEdit* line = getLine(iActiveRef); - if (line != NULL) { - line->blockSignals(true); - line->setText(makeRefString(selObj, subname)); - line->setProperty("RefName", QByteArray(subname.c_str())); - line->blockSignals(false); - } - - if (autoNext) { - if (iActiveRef == -1){ - //nothing to do - } else if (iActiveRef == 4 || this->lastSuggestResult.nextRefTypeHint.size() == 0){ - iActiveRef = -1; - } else { - iActiveRef++; - } - } - - updateReferencesUI(); - } -} - -void TaskDatumParameters::onSuperplacementChanged(double /*val*/, int idx) -{ - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - Base::Placement pl = pcDatum->superPlacement.getValue(); - - Base::Vector3d pos = pl.getPosition(); - if (idx == 0) { - pos.x = ui->superplacementX->value().getValueAs(Base::Quantity::MilliMetre); - } - if (idx == 1) { - pos.y = ui->superplacementY->value().getValueAs(Base::Quantity::MilliMetre); - } - if (idx == 2) { - pos.z = ui->superplacementZ->value().getValueAs(Base::Quantity::MilliMetre); - } - if (idx >= 0 && idx <= 2){ - pl.setPosition(pos); - } - - Base::Rotation rot = pl.getRotation(); - double yaw, pitch, roll; - rot.getYawPitchRoll(yaw, pitch, roll); - if (idx == 3) { - yaw = ui->superplacementYaw->value().getValueAs(Base::Quantity::Degree); - } - if (idx == 4) { - pitch = ui->superplacementPitch->value().getValueAs(Base::Quantity::Degree); - } - if (idx == 5) { - roll = ui->superplacementRoll->value().getValueAs(Base::Quantity::Degree); - } - if (idx >= 3 && idx <= 5){ - rot.setYawPitchRoll(yaw,pitch,roll); - pl.setRotation(rot); - } - - pcDatum->superPlacement.setValue(pl); - updatePreview(); -} - -void TaskDatumParameters::onSuperplacementXChanged(double val) -{ - onSuperplacementChanged(val, 0); -} -void TaskDatumParameters::onSuperplacementYChanged(double val) -{ - onSuperplacementChanged(val, 1); -} -void TaskDatumParameters::onSuperplacementZChanged(double val) -{ - onSuperplacementChanged(val, 2); -} -void TaskDatumParameters::onSuperplacementYawChanged(double val) -{ - onSuperplacementChanged(val, 3); -} -void TaskDatumParameters::onSuperplacementPitchChanged(double val) -{ - onSuperplacementChanged(val, 4); -} -void TaskDatumParameters::onSuperplacementRollChanged(double val) -{ - onSuperplacementChanged(val, 5); -} - -void TaskDatumParameters::onCheckFlip(bool on) -{ - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - pcDatum->MapReversed.setValue(on); - pcDatum->getDocument()->recomputeFeature(pcDatum); -} - -void TaskDatumParameters::onButtonRef(const bool checked, unsigned idx) -{ - autoNext = false; - if (checked) { - Gui::Selection().clearSelection(); - iActiveRef = idx; - } else { - iActiveRef = -1; - } - updateRefButton(0); - updateRefButton(1); - updateRefButton(2); - updateRefButton(3); -} - -void TaskDatumParameters::onButtonRef1(const bool checked) { - onButtonRef(checked, 0); -} -void TaskDatumParameters::onButtonRef2(const bool checked) { - onButtonRef(checked, 1); -} -void TaskDatumParameters::onButtonRef3(const bool checked) { - onButtonRef(checked, 2); -} -void TaskDatumParameters::onButtonRef4(const bool checked) { - onButtonRef(checked, 3); -} - -void TaskDatumParameters::onModeSelect() -{ - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - pcDatum->MapMode.setValue(getActiveMapMode()); - updatePreview(); -} - -void TaskDatumParameters::onRefName(const QString& text, unsigned idx) -{ - QLineEdit* line = getLine(idx); - if (line == NULL) return; - - if (text.length() == 0) { - // Reference was removed - // Update the reference list - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->Support.getValues(); - std::vector refnames = pcDatum->Support.getSubValues(); - std::vector newrefs; - std::vector newrefnames; - for (size_t r = 0; r < refs.size(); r++) { - if (r != idx) { - newrefs.push_back(refs[r]); - newrefnames.push_back(refnames[r]); - } - } - pcDatum->Support.setValues(newrefs, newrefnames); - updateListOfModes(); - pcDatum->MapMode.setValue(getActiveMapMode()); - - updatePreview(); - - // Update the UI - std::vector refstrings; - makeRefStrings(refstrings, newrefnames); - ui->lineRef1->setText(refstrings[0]); - ui->lineRef1->setProperty("RefName", QByteArray(newrefnames[0].c_str())); - ui->lineRef2->setText(refstrings[1]); - ui->lineRef2->setProperty("RefName", QByteArray(newrefnames[1].c_str())); - ui->lineRef3->setText(refstrings[2]); - ui->lineRef3->setProperty("RefName", QByteArray(newrefnames[2].c_str())); - ui->lineRef4->setText(refstrings[3]); - ui->lineRef4->setProperty("RefName", QByteArray(newrefnames[3].c_str())); - updateReferencesUI(); - return; - } - - QStringList parts = text.split(QChar::fromLatin1(':')); - if (parts.length() < 2) - parts.push_back(QString::fromLatin1("")); - // Check whether this is the name of an App::Plane or Part::Datum feature - App::DocumentObject* obj = DatumView->getObject()->getDocument()->getObject(parts[0].toLatin1()); - if (obj == NULL) return; - - std::string subElement; - - if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - // everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) - subElement = ""; - } else if (obj->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { - // everything is OK (we assume a Part can only have exactly 3 App::Line objects located at the base of the feature tree) - subElement = ""; - } else if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { - subElement = ""; - } else { - // TODO: check validity of the text that was entered: Does subElement actually reference to an element on the obj? - - // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. - QRegExp rx; - std::stringstream ss; - - rx.setPattern(QString::fromLatin1("^") + tr("Face") + QString::fromLatin1("(\\d+)$")); - if (parts[1].indexOf(rx) >= 0) { - int faceId = rx.cap(1).toInt(); - ss << "Face" << faceId; - } else { - rx.setPattern(QString::fromLatin1("^") + tr("Edge") + QString::fromLatin1("(\\d+)$")); - if (parts[1].indexOf(rx) >= 0) { - int lineId = rx.cap(1).toInt(); - ss << "Edge" << lineId; - } else { - rx.setPattern(QString::fromLatin1("^") + tr("Vertex") + QString::fromLatin1("(\\d+)$")); - if (parts[1].indexOf(rx) >= 0) { - int vertexId = rx.cap(1).toInt(); - ss << "Vertex" << vertexId; - } else { - //none of Edge/Vertex/Face. May be empty string. - //Feed in whatever user supplied, even if invalid. - ss << parts[1].toLatin1().constData(); - } - } - } - - line->setProperty("RefName", QByteArray(ss.str().c_str())); - subElement = ss.str(); - } - - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->Support.getValues(); - std::vector refnames = pcDatum->Support.getSubValues(); - if (idx < refs.size()) { - refs[idx] = obj; - refnames[idx] = subElement.c_str(); - } else { - refs.push_back(obj); - refnames.push_back(subElement.c_str()); - } - pcDatum->Support.setValues(refs, refnames); - updateListOfModes(); - pcDatum->MapMode.setValue(getActiveMapMode()); - - updateReferencesUI(); -} - -void TaskDatumParameters::updateRefButton(int idx) -{ - QAbstractButton* b; - switch(idx){ - case 0: b = ui->buttonRef1; break; - case 1: b = ui->buttonRef2; break; - case 2: b = ui->buttonRef3; break; - case 3: b = ui->buttonRef4; break; - default: throw Base::Exception("button index out of range"); - } - - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->Support.getValues(); - - int numrefs = refs.size(); - bool enable = true; - if (idx > numrefs) - enable = false; - if (idx == numrefs && this->lastSuggestResult.nextRefTypeHint.size() == 0) - enable = false; - b->setEnabled(enable); - - b->setChecked(iActiveRef == idx); - - if (iActiveRef == idx) { - b->setText(tr("Selecting...")); - } else if (idx < static_cast(this->lastSuggestResult.references_Types.size())){ - b->setText(AttacherGui::getShapeTypeText(this->lastSuggestResult.references_Types[idx])); - } else { - b->setText(tr("Reference%1").arg(idx+1)); - } -} - -void TaskDatumParameters::updateSuperplacementUI() -{ - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - Base::Placement pl = pcDatum->superPlacement.getValue(); - Base::Vector3d pos = pl.getPosition(); - Base::Rotation rot = pl.getRotation(); - double yaw, pitch, roll; - rot.getYawPitchRoll(yaw, pitch, roll); - - bool bBlock = true; - ui->superplacementX->blockSignals(bBlock); - ui->superplacementY->blockSignals(bBlock); - ui->superplacementZ->blockSignals(bBlock); - ui->superplacementYaw->blockSignals(bBlock); - ui->superplacementPitch->blockSignals(bBlock); - ui->superplacementRoll->blockSignals(bBlock); - - ui->superplacementX->setValue(Base::Quantity(pos.x,Base::Unit::Length)); - ui->superplacementY->setValue(Base::Quantity(pos.y,Base::Unit::Length)); - ui->superplacementZ->setValue(Base::Quantity(pos.z,Base::Unit::Length)); - ui->superplacementYaw->setValue(yaw); - ui->superplacementPitch->setValue(pitch); - ui->superplacementRoll->setValue(roll); - - auto expressions = pcDatum->ExpressionEngine.getExpressions(); - bool bRotationBound = false; - bRotationBound = bRotationBound || - expressions.find(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Rotation.Angle"))) != expressions.end(); - bRotationBound = bRotationBound || - expressions.find(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Rotation.Axis.x"))) != expressions.end(); - bRotationBound = bRotationBound || - expressions.find(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Rotation.Axis.y"))) != expressions.end(); - bRotationBound = bRotationBound || - expressions.find(App::ObjectIdentifier::parse(pcDatum,std::string("superPlacement.Rotation.Axis.z"))) != expressions.end(); - - ui->superplacementYaw->setEnabled(!bRotationBound); - ui->superplacementPitch->setEnabled(!bRotationBound); - ui->superplacementRoll->setEnabled(!bRotationBound); - - QString tooltip = bRotationBound ? tr("Not editable because rotation part of superplacement is bound by expressions.") : QString(); - ui->superplacementYaw->setToolTip(tooltip); - ui->superplacementPitch->setToolTip(tooltip); - ui->superplacementRoll->setToolTip(tooltip); - - bBlock = false; - ui->superplacementX->blockSignals(bBlock); - ui->superplacementY->blockSignals(bBlock); - ui->superplacementZ->blockSignals(bBlock); - ui->superplacementYaw->blockSignals(bBlock); - ui->superplacementPitch->blockSignals(bBlock); - ui->superplacementRoll->blockSignals(bBlock); -} - -void TaskDatumParameters::updateListOfModes(eMapMode curMode) -{ - //first up, remember currently selected mode. - if (curMode == mmDeactivated){ - auto sel = ui->listOfModes->selectedItems(); - if (sel.count() > 0) - curMode = modesInList[ui->listOfModes->row(sel[0])]; - } - - //obtain list of available modes: - Part::Datum* pcDatum = static_cast(DatumView->getObject()); - this->lastSuggestResult.bestFitMode = mmDeactivated; - size_t lastValidModeItemIndex = mmDummy_NumberOfModes; - if (pcDatum->Support.getSize() > 0){ - pcDatum->attacher().suggestMapModes(this->lastSuggestResult); - modesInList = this->lastSuggestResult.allApplicableModes; - //add reachable modes to the list, too, but gray them out (using lastValidModeItemIndex, later) - lastValidModeItemIndex = modesInList.size()-1; - for(std::pair &rm: this->lastSuggestResult.reachableModes){ - modesInList.push_back(rm.first); - } - } else { - //no references - display all modes - modesInList.clear(); - for( int mmode = 0 ; mmode < mmDummy_NumberOfModes ; mmode++){ - if (pcDatum->attacher().modeEnabled[mmode]) - modesInList.push_back(eMapMode(mmode)); - } - } - - //populate list - ui->listOfModes->blockSignals(true); - ui->listOfModes->clear(); - QListWidgetItem* iSelect = 0; - if (modesInList.size()>0) { - for (size_t i = 0 ; i < modesInList.size() ; ++i){ - eMapMode mmode = modesInList[i]; - std::vector mstr = AttacherGui::getUIStrings(pcDatum->attacher().getTypeId(),mmode); - ui->listOfModes->addItem(mstr[0]); - QListWidgetItem* item = ui->listOfModes->item(i); - item->setToolTip(mstr[1] + QString::fromLatin1("\n\n") + - tr("Reference combinations:\n") + - AttacherGui::getRefListForMode(pcDatum->attacher(),mmode).join(QString::fromLatin1("\n"))); - if (mmode == curMode) - iSelect = ui->listOfModes->item(i); - if (i > lastValidModeItemIndex){ - //potential mode - can be reached by selecting more stuff - item->setFlags(item->flags() & ~(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable)); - - refTypeStringList &extraRefs = this->lastSuggestResult.reachableModes[mmode]; - if (extraRefs.size() == 1){ - QStringList buf; - for(eRefType rt : extraRefs[0]){ - buf.append(AttacherGui::getShapeTypeText(rt)); - } - item->setText(tr("%1 (add %2)").arg( - item->text(), - buf.join(QString::fromLatin1("+")) - )); - } else { - item->setText(tr("%1 (add more references)").arg(item->text())); - } - } else if (mmode == this->lastSuggestResult.bestFitMode){ - //suggested mode - make bold - assert (item); - QFont fnt = item->font(); - fnt.setBold(true); - item->setFont(fnt); - } - - } - } - //restore selection - ui->listOfModes->selectedItems().clear(); - if (iSelect) - iSelect->setSelected(true); - ui->listOfModes->blockSignals(false); -} - -Attacher::eMapMode TaskDatumParameters::getActiveMapMode() -{ - auto sel = ui->listOfModes->selectedItems(); - if (sel.count() > 0) - return modesInList[ui->listOfModes->row(sel[0])]; - else { - if (this->lastSuggestResult.message == SuggestResult::srOK) - return this->lastSuggestResult.bestFitMode; - else - return mmDeactivated; - }; -} - -void TaskDatumParameters::onRefName1(const QString& text) -{ - onRefName(text, 0); -} -void TaskDatumParameters::onRefName2(const QString& text) -{ - onRefName(text, 1); -} -void TaskDatumParameters::onRefName3(const QString& text) -{ - onRefName(text, 2); -} -void TaskDatumParameters::onRefName4(const QString &text) -{ - onRefName(text, 3); -} - - -bool TaskDatumParameters::getFlip() const -{ - return ui->checkBoxFlip->isChecked(); -} - -void TaskDatumParameters::changeEvent(QEvent *e) -{ - TaskBox::changeEvent(e); - if (e->type() == QEvent::LanguageChange) { - ui->checkBoxFlip->blockSignals(true); - ui->buttonRef1->blockSignals(true); - ui->lineRef1->blockSignals(true); - ui->buttonRef2->blockSignals(true); - ui->lineRef2->blockSignals(true); - ui->buttonRef3->blockSignals(true); - ui->lineRef3->blockSignals(true); - ui->buttonRef4->blockSignals(true); - ui->lineRef4->blockSignals(true); - ui->retranslateUi(proxy); - - std::vector refnames; - std::vector refstrings; - makeRefStrings(refstrings, refnames); - ui->lineRef1->setText(refstrings[0]); - ui->lineRef2->setText(refstrings[1]); - ui->lineRef3->setText(refstrings[2]); - ui->lineRef3->setText(refstrings[3]); - updateListOfModes(); - - ui->checkBoxFlip->blockSignals(false); - ui->buttonRef1->blockSignals(false); - ui->lineRef1->blockSignals(false); - ui->buttonRef2->blockSignals(false); - ui->lineRef2->blockSignals(false); - ui->buttonRef3->blockSignals(false); - ui->lineRef3->blockSignals(false); - ui->buttonRef4->blockSignals(false); - ui->lineRef4->blockSignals(false); - } -} - -void TaskDatumParameters::visibilityAutomation(bool opening_not_closing) -{ - if (opening_not_closing){ - //crash guards - if (!DatumView) - return; - if (!DatumView->getObject()) - return; - if (!DatumView->getObject()->getNameInDocument()) - return; - try{ - QString code = QString::fromLatin1( - "import TempoVis\n" - "from Show.DepGraphTools import getAllDependent, isContainer\n" - "tv = TempoVis.TempoVis(App.ActiveDocument)\n" - "dep_features = [o for o in getAllDependent(%1) if not isContainer(o)]\n" - "if %1.isDerivedFrom('PartDesign::CoordinateSystem'):\n" - "\tvisible_features = [feat for feat in %1.InList if feat.isDerivedFrom('PartDesign::FeaturePrimitive')]\n" - "\tdep_features = [feat for feat in dep_features if feat not in visible_features]\n" - "tv.hide(dep_features)\n" - "if not %1.isDerivedFrom('PartDesign::CoordinateSystem'):\n" - "\t\tif len(%1.Support) > 0:\n" - "\t\t\ttv.show([lnk[0] for lnk in %1.Support])" - ); - QByteArray code_2 = code.arg( - QString::fromLatin1("App.ActiveDocument.") + - QString::fromLatin1(DatumView->getObject()->getNameInDocument()) - ).toLatin1(); - Base::Interpreter().runString(code_2.constData()); - } - catch (Base::PyException &e){ - e.ReportException(); - } - } - else { - try { - Base::Interpreter().runString("del(tv)"); - } - catch (Base::PyException &e) { - e.ReportException(); - } - } -} //************************************************************************** //************************************************************************** // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgDatumParameters::TaskDlgDatumParameters(ViewProviderDatum *DatumView) - : TaskDialog(),DatumView(DatumView) +TaskDlgDatumParameters::TaskDlgDatumParameters(ViewProviderDatum *ViewProvider) + : TaskDlgAttacher(ViewProvider) { - assert(DatumView); - parameter = new TaskDatumParameters(DatumView); + assert(ViewProvider); + parameter = new TaskDatumParameters(ViewProvider); + Content.front()->deleteLater(); + Content.clear(); Content.push_back(parameter); } @@ -951,23 +103,10 @@ TaskDlgDatumParameters::~TaskDlgDatumParameters() } -//==== calls from the TaskView =============================================================== +bool TaskDlgDatumParameters::accept() { - -void TaskDlgDatumParameters::open() -{ - -} - -void TaskDlgDatumParameters::clicked(int) -{ - -} - -bool TaskDlgDatumParameters::accept() -{ - std::string name = DatumView->getObject()->getNameInDocument(); - Part::Datum* pcDatum = static_cast(DatumView->getObject()); + std::string name = ViewProvider->getObject()->getNameInDocument(); + Part::Datum* pcDatum = static_cast(ViewProvider->getObject()); auto pcActiveBody = PartDesignGui::getBodyFor(pcDatum, false); auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false); std::vector copies; @@ -985,7 +124,7 @@ bool TaskDlgDatumParameters::accept() msg.setDefaultButton(btNo); msg.setIcon(QMessageBox::Warning); msg.exec(); - if (msg.clickedButton() == btNo) + if (msg.buttonRole(msg.clickedButton()) == QMessageBox::NoRole) return false; } @@ -1027,56 +166,19 @@ bool TaskDlgDatumParameters::accept() pcDatum->Support.setValues(objs, subs); } } - - try { - //DeepSOIC: changed this to heavily rely on dialog constantly updating feature properties - if (pcDatum->superPlacement.isTouched()){ - Base::Placement plm = pcDatum->superPlacement.getValue(); - double yaw, pitch, roll; - plm.getRotation().getYawPitchRoll(yaw,pitch,roll); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.superPlacement = App.Placement(App.Vector(%.10f, %.10f, %.10f), App.Rotation(%.10f, %.10f, %.10f))", - name.c_str(), - plm.getPosition().x, plm.getPosition().y, plm.getPosition().z, - yaw, pitch, roll); - } - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MapReversed = %s", name.c_str(), pcDatum->MapReversed.getValue() ? "True" : "False"); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Support = %s", name.c_str(), pcDatum->Support.getPyReprString().c_str()); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MapMode = '%s'", name.c_str(), AttachEngine::getModeName(eMapMode(pcDatum->MapMode.getValue())).c_str()); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - if (!DatumView->getObject()->isValid()) - throw Base::Exception(DatumView->getObject()->getStatusString()); - Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().resetEdit()"); - Gui::Command::commitCommand(); - - //we need to add the copied features to the body after the command action, as otherwise freecad crashs unexplainable - for(auto obj : copies) { - if(pcActiveBody) - pcActiveBody->addFeature(obj); - else if (pcActivePart) - pcActivePart->addObject(obj); - } - } - catch (const Base::Exception& e) { - QMessageBox::warning(parameter, tr("Datum dialog: Input error"), QString::fromLatin1(e.what())); + + if(!PartGui::TaskDlgAttacher::accept()) return false; + + //we need to add the copied features to the body after the command action, as otherwise freecad crashs unexplainable + for(auto obj : copies) { + if(pcActiveBody) + pcActiveBody->addFeature(obj); + else if (pcActivePart) + pcActivePart->addObject(obj); } - + return true; } -bool TaskDlgDatumParameters::reject() -{ - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - return true; -} - - - #include "moc_TaskDatumParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.h b/src/Mod/PartDesign/Gui/TaskDatumParameters.h index 8e78788c5..ac977ba64 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "ViewProviderDatum.h" @@ -46,126 +46,25 @@ namespace PartDesignGui { -class TaskDatumParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +class TaskDatumParameters : public PartGui::TaskAttacher { Q_OBJECT public: TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *parent = 0); - ~TaskDatumParameters(); - - bool getFlip(void) const; - - /** - * @brief getActiveMapMode returns either the default mode for selected - * references, or the mode that was selected by the user in the list. If - * no modes fit current set of references, mmDeactivated is returned. - */ - Attacher::eMapMode getActiveMapMode(); - - bool isCompleted() const { return completed; } - -private Q_SLOTS: - void onSuperplacementChanged(double, int idx); - void onSuperplacementXChanged(double); - void onSuperplacementYChanged(double); - void onSuperplacementZChanged(double); - void onSuperplacementYawChanged(double); - void onSuperplacementPitchChanged(double); - void onSuperplacementRollChanged(double); - void onCheckFlip(bool); - void onRefName1(const QString& text); - void onRefName2(const QString& text); - void onRefName3(const QString& text); - void onRefName4(const QString& text); - void onButtonRef1(const bool checked = true); - void onButtonRef2(const bool checked = true); - void onButtonRef3(const bool checked = true); - void onButtonRef4(const bool checked = true); - void onModeSelect(void); - void visibilityAutomation(bool opening_not_closing); - -protected: - void changeEvent(QEvent *e); - -private: - void resetViewMode(); - void objectDeleted(const Gui::ViewProviderDocumentObject&); - void onSelectionChanged(const Gui::SelectionChanges& msg) override; - void updateReferencesUI(); - - /** - * @brief updatePreview: calculate attachment, update 3d view, update status message - * @return true if attachment calculation was successful, false otherwise - */ - bool updatePreview(); - - void makeRefStrings(std::vector& refstrings, std::vector& refnames); - QLineEdit* getLine(unsigned idx); - void onButtonRef(const bool checked, unsigned idx); - void onRefName(const QString& text, unsigned idx); - void updateRefButton(int idx); - void updateSuperplacementUI(); - - /** - * @brief updateListOfModes Fills the mode list with modes that apply to - * current set of references. - * @param curMode the mode to select in the list. If the mode isn't - * contained in the list, nothing is selected. If mmDeactivated is passed, - * currently selected mode is kept. - */ - void updateListOfModes(Attacher::eMapMode curMode = Attacher::mmDeactivated); - -private: - QWidget* proxy; - Ui_TaskDatumParameters* ui; - ViewProviderDatum *DatumView; - - // TODO fix documentation here (2015-11-10, Fat-Zer) - int iActiveRef; //what reference is being picked in 3d view now? -1 means no one, 0-3 means a reference is being picked. - bool autoNext;//if we should automatically switch to next reference (true after dialog launch, false afterwards) - std::vector modesInList; //this list is synchronous to what is populated into listOfModes widget. - Attacher::SuggestResult lastSuggestResult; - bool completed; - - typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection; - Connection connectDelObject; + ~TaskDatumParameters(); }; /// simulation dialog for the TaskView -class TaskDlgDatumParameters : public Gui::TaskView::TaskDialog +class TaskDlgDatumParameters : public PartGui::TaskDlgAttacher { Q_OBJECT public: TaskDlgDatumParameters(ViewProviderDatum *DatumView); ~TaskDlgDatumParameters(); - - ViewProviderDatum* getDatumView() const - { return DatumView; } - - -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: - ViewProviderDatum *DatumView; - - TaskDatumParameters *parameter; }; } //namespace PartDesignGui diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp index 25087c5d0..2ab3738ce 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.cpp @@ -602,11 +602,11 @@ TaskPrimitiveParameters::TaskPrimitiveParameters(ViewProviderPrimitive* Primitiv assert(PrimitiveView); - //parameter = new TaskDatumParameters(vp); - //Content.push_back(parameter); - primitive = new TaskBoxPrimitives(PrimitiveView); Content.push_back(primitive); + + parameter = new PartGui::TaskAttacher(PrimitiveView); + Content.push_back(parameter); } TaskPrimitiveParameters::~TaskPrimitiveParameters() diff --git a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h index 370cb8e08..4f605ac9b 100644 --- a/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPrimitiveParameters.h @@ -120,8 +120,8 @@ protected: virtual bool reject(); private: - TaskBoxPrimitives* primitive; - TaskDatumParameters* parameter; + TaskBoxPrimitives* primitive; + PartGui::TaskAttacher* parameter; ViewProviderPrimitive* vp_prm; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 5e1a6c4cf..915f0f30f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -236,7 +236,7 @@ bool ViewProviderDatum::setEdit(int ModNum) // the task panel Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); TaskDlgDatumParameters *datumDlg = qobject_cast(dlg); - if (datumDlg && datumDlg->getDatumView() != this) + if (datumDlg && datumDlg->getViewProvider() != this) datumDlg = 0; // another datum feature left open its task panel if (dlg && !datumDlg) { QMessageBox msgBox;