From 89c24714df3169e2d882d285f89ad3d9c37c6dcb Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 16 Dec 2022 15:33:52 +0100 Subject: [PATCH] Gui: refactor Placement dialog --- src/Gui/Placement.cpp | 413 +++++++++++++++++++++++++----------------- src/Gui/Placement.h | 62 +++++-- 2 files changed, 295 insertions(+), 180 deletions(-) diff --git a/src/Gui/Placement.cpp b/src/Gui/Placement.cpp index a73c67899a..9aa366755a 100644 --- a/src/Gui/Placement.cpp +++ b/src/Gui/Placement.cpp @@ -98,6 +98,207 @@ public: } } +PlacementHandler::PlacementHandler() + : propertyName{"Placement"} + , changeProperty{false} +{ + +} + +void PlacementHandler::openTransactionIfNeeded() +{ + if (propertyName != "Placement") { + changeProperty = true; + openTransaction(); + } +} + +void PlacementHandler::setPropertyName(const std::string& name) +{ + propertyName = name; +} + +const std::string& PlacementHandler::getPropertyName() const +{ + return propertyName; +} + +void PlacementHandler::appendDocument(const std::string& name) +{ + documents.insert(name); +} + +void PlacementHandler::activatedDocument(const std::string& name) +{ + appendDocument(name); + + if (changeProperty) { + QMetaObject::invokeMethod(this, "openTransaction", Qt::QueuedConnection); + } +} + +void PlacementHandler::openTransaction() +{ + App::Document* activeDoc = App::GetApplication().getActiveDocument(); + if (activeDoc) + activeDoc->openTransaction("Placement"); +} + +void PlacementHandler::revertTransformation() +{ + for (const auto & it : documents) { + Gui::Document* document = Application::Instance->getDocument(it.c_str()); + if (document) { + if (!changeProperty) { + revertTransformationOfViewProviders(document); + } + else { + document->abortCommand(); + } + } + } +} + +std::vector PlacementHandler::getObjects(Gui::Document* document) const +{ + return document->getDocument()->getObjectsOfType(App::DocumentObject::getClassTypeId()); +} + +std::vector PlacementHandler::getSelectedObjects(Gui::Document* document) const +{ + return Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId(), document->getDocument()->getName()); +} + +void PlacementHandler::revertTransformationOfViewProviders(Gui::Document* document) +{ + std::vector obj = getObjects(document); + for (const auto & it : obj) { + auto property = find_placement::getProperty(it, this->propertyName); + if (property) { + Base::Placement cur = property->getValue(); + Gui::ViewProvider* vp = document->getViewProvider(it); + if (vp) { + vp->setTransformation(cur.toMatrix()); + } + } + } +} + +void PlacementHandler::applyPlacement(const Base::Placement& p, bool incremental) +{ + Gui::Document* document = Application::Instance->activeDocument(); + if (!document) + return; + + std::vector sel = getSelectedObjects(document); + if (!sel.empty()) { + // apply transformation only on view matrix not on placement property + for (const auto & it : sel) { + applyPlacement(document, it, p, incremental); + } + } + else { + Base::Console().Warning("No object selected.\n"); + } +} + +void PlacementHandler::applyPlacement(Gui::Document* document, App::DocumentObject* obj, const Base::Placement& p, bool incremental) +{ + auto property = find_placement::getProperty(obj, this->propertyName); + if (property) { + Base::Placement cur = property->getValue(); + if (incremental) + cur = p * cur; + else + cur = p; + + if (!changeProperty) { + Gui::ViewProvider* vp = document->getViewProvider(obj); + if (vp) { + vp->setTransformation(cur.toMatrix()); + } + } + else { + property->setValue(cur); + } + } +} + +void PlacementHandler::applyPlacement(const QString& data, bool incremental) +{ + Gui::Document* document = Application::Instance->activeDocument(); + if (!document) + return; + + // When directly changing the property we now only have to commit the transaction, + // do a recompute and open a new transaction + if (changeProperty) { + document->commitCommand(); + tryRecompute(document); + document->openCommand(QT_TRANSLATE_NOOP("Command", "Placement")); + } + else { + std::vector sel = getSelectedObjects(document); + if (!sel.empty()) { + document->openCommand(QT_TRANSLATE_NOOP("Command", "Placement")); + for (const auto & it : sel) { + applyPlacement(it, data, incremental); + } + + document->commitCommand(); + tryRecompute(document); + } + else { + Base::Console().Warning("No object selected.\n"); + } + } +} + +void PlacementHandler::applyPlacement(App::DocumentObject* obj, const QString& data, bool incremental) +{ + auto property = find_placement::getProperty(obj, this->propertyName); + if (property) { + QString cmd; + if (incremental) { + cmd = getIncrementalPlacement(obj, data); + } + else { + cmd = getSimplePlacement(obj, data); + } + + Gui::Command::runCommand(Gui::Command::App, cmd.toLatin1()); + } +} + +QString PlacementHandler::getIncrementalPlacement(App::DocumentObject* obj, const QString& data) const +{ + return QString::fromLatin1( + "App.getDocument(\"%1\").%2.%3=%4.multiply(App.getDocument(\"%1\").%2.%3)") + .arg(QString::fromLatin1(obj->getDocument()->getName()), + QString::fromLatin1(obj->getNameInDocument()), + QString::fromLatin1(this->propertyName.c_str()), + data); +} + +QString PlacementHandler::getSimplePlacement(App::DocumentObject* obj, const QString& data) const +{ + return QString::fromLatin1( + "App.getDocument(\"%1\").%2.%3=%4") + .arg(QString::fromLatin1(obj->getDocument()->getName()), + QString::fromLatin1(obj->getNameInDocument()), + QString::fromLatin1(this->propertyName.c_str()), + data); +} + +void PlacementHandler::tryRecompute(Gui::Document* document) +{ + try { + document->getDocument()->recompute(); + } + catch (...) { + } +} + // ---------------------------------------------------------------------------- /* TRANSLATOR Gui::Dialog::Placement */ @@ -105,8 +306,6 @@ public: Placement::Placement(QWidget* parent, Qt::WindowFlags fl) : QDialog(parent, fl) , ui{nullptr} - , propertyName{"Placement"} - , changeProperty{false} { setupUi(); setupConnections(); @@ -187,8 +386,9 @@ void Placement::setupDocument() connectAct = Application::Instance->signalActiveDocument.connect (boost::bind(&Placement::slotActiveDocument, this, bp::_1)); App::Document* activeDoc = App::GetApplication().getActiveDocument(); - if (activeDoc) - documents.insert(activeDoc->getName()); + if (activeDoc) { + handler.appendDocument(activeDoc->getName()); + } } void Placement::setupRotationMethod() @@ -215,26 +415,12 @@ void Placement::showDefaultButtons(bool ok) void Placement::open() { - if (propertyName != "Placement") { - changeProperty = true; - openTransaction(); - } + handler.openTransactionIfNeeded(); } void Placement::slotActiveDocument(const Gui::Document& doc) { - documents.insert(doc.getDocument()->getName()); - - if (changeProperty) { - QMetaObject::invokeMethod(this, "openTransaction", Qt::QueuedConnection); - } -} - -void Placement::openTransaction() -{ - App::Document* activeDoc = App::GetApplication().getActiveDocument(); - if (activeDoc) - activeDoc->openTransaction("Placement"); + handler.activatedDocument(doc.getDocument()->getName()); } QWidget* Placement::getInvalidInput() const @@ -247,130 +433,6 @@ QWidget* Placement::getInvalidInput() const return nullptr; } -void Placement::revertTransformation() -{ - for (const auto & it : documents) { - Gui::Document* document = Application::Instance->getDocument(it.c_str()); - if (!document) - continue; - - if (!changeProperty) { - std::vector obj = document->getDocument()-> - getObjectsOfType(App::DocumentObject::getClassTypeId()); - if (!obj.empty()) { - for (const auto & it : obj) { - auto property = find_placement::getProperty(it, this->propertyName); - if (property) { - Base::Placement cur = property->getValue(); - Gui::ViewProvider* vp = document->getViewProvider(it); - if (vp) { - vp->setTransformation(cur.toMatrix()); - } - } - } - } - } - else { - document->abortCommand(); - } - } -} - -void Placement::applyPlacement(const Base::Placement& p, bool incremental) -{ - Gui::Document* document = Application::Instance->activeDocument(); - if (!document) - return; - - std::vector sel = Gui::Selection().getObjectsOfType - (App::DocumentObject::getClassTypeId(), document->getDocument()->getName()); - if (!sel.empty()) { - // apply transformation only on view matrix not on placement property - for (const auto & it : sel) { - auto property = find_placement::getProperty(it, this->propertyName); - if (property) { - Base::Placement cur = property->getValue(); - if (incremental) - cur = p * cur; - else - cur = p; - - if (!changeProperty) { - Gui::ViewProvider* vp = document->getViewProvider(it); - if (vp) { - vp->setTransformation(cur.toMatrix()); - } - } - else { - property->setValue(cur); - } - } - } - } - else { - Base::Console().Warning("No object selected.\n"); - } -} - -void Placement::applyPlacement(const QString& data, bool incremental) -{ - Gui::Document* document = Application::Instance->activeDocument(); - if (!document) - return; - - // When directly changing the property we now only have to commit the transaction, - // do a recompute and open a new transaction - if (changeProperty) { - document->commitCommand(); - try { - document->getDocument()->recompute(); - } - catch (...) { - } - document->openCommand(QT_TRANSLATE_NOOP("Command", "Placement")); - } - else { - std::vector sel = Gui::Selection().getObjectsOfType - (App::DocumentObject::getClassTypeId(), document->getDocument()->getName()); - if (!sel.empty()) { - document->openCommand(QT_TRANSLATE_NOOP("Command", "Placement")); - for (const auto & it : sel) { - auto property = find_placement::getProperty(it, this->propertyName); - if (property) { - QString cmd; - if (incremental) - cmd = QString::fromLatin1( - "App.getDocument(\"%1\").%2.%3=%4.multiply(App.getDocument(\"%1\").%2.%3)") - .arg(QString::fromLatin1(it->getDocument()->getName()), - QString::fromLatin1(it->getNameInDocument()), - QString::fromLatin1(this->propertyName.c_str()), - data); - else { - cmd = QString::fromLatin1( - "App.getDocument(\"%1\").%2.%3=%4") - .arg(QString::fromLatin1(it->getDocument()->getName()), - QString::fromLatin1(it->getNameInDocument()), - QString::fromLatin1(this->propertyName.c_str()), - data); - } - - Gui::Command::runCommand(Gui::Command::App, cmd.toLatin1()); - } - } - - document->commitCommand(); - try { - document->getDocument()->recompute(); - } - catch (...) { - } - } - else { - Base::Console().Warning("No object selected.\n"); - } - } -} - void Placement::onPlacementChanged(int) { // If there are listeners to the 'placementChanged' signal we rely @@ -379,7 +441,7 @@ void Placement::onPlacementChanged(int) // automatically. bool incr = ui->applyIncrementalPlacement->isChecked(); Base::Placement plm = this->getPlacement(); - applyPlacement(plm, incr); + handler.applyPlacement(plm, incr); QVariant data = QVariant::fromValue(plm); Q_EMIT placementChanged(data, incr, false); @@ -392,19 +454,7 @@ void Placement::onCenterOfMassToggled(bool on) ui->zCnt->setDisabled(on); if (on) { - cntOfMass.Set(0,0,0); - std::vector sel = Gui::Selection().getObjectsOfType - (App::GeoFeature::getClassTypeId()); - if (!sel.empty()) { - for (auto it : sel) { - const App::PropertyComplexGeoData* propgeo = static_cast(it)->getPropertyOfGeometry(); - const Data::ComplexGeoData* geodata = propgeo ? propgeo->getComplexData() : nullptr; - if (geodata && geodata->getCenterOfGravity(cntOfMass)) { - break; - } - } - } - + cntOfMass = getCenterOfMass(); ui->xCnt->setValue(cntOfMass.x); ui->yCnt->setValue(cntOfMass.y); ui->zCnt->setValue(cntOfMass.z); @@ -612,12 +662,12 @@ void Placement::keyPressEvent(QKeyEvent* ke) void Placement::reject() { Base::Placement plm; - applyPlacement(plm, true); + handler.applyPlacement(plm, true); QVariant data = QVariant::fromValue(plm); Q_EMIT placementChanged(data, true, false); - revertTransformation(); + handler.revertTransformation(); // One of the quantity spin boxes still can emit a signal when it has the focus // but its content is not fully updated. @@ -631,7 +681,7 @@ void Placement::reject() void Placement::accept() { if (onApply()) { - revertTransformation(); + handler.revertTransformation(); QDialog::accept(); } } @@ -666,7 +716,7 @@ bool Placement::onApply() // automatically. bool incr = ui->applyIncrementalPlacement->isChecked(); Base::Placement plm = this->getPlacement(); - applyPlacement(getPlacementString(), incr); + handler.applyPlacement(getPlacementString(), incr); QVariant data = QVariant::fromValue(plm); Q_EMIT placementChanged(data, incr, true); @@ -708,6 +758,11 @@ void Placement::setSelection(const std::vector& selection) selectionObjects = selection; } +void Placement::setPropertyName(const std::string& name) +{ + handler.setPropertyName(name); +} + /*! * \brief Placement::bindObject * Binds the spin boxes to the placement components of the first object of the selection. @@ -718,6 +773,7 @@ void Placement::bindObject() if (!selectionObjects.empty()) { App::DocumentObject* obj = selectionObjects.front().getObject(); + std::string propertyName = handler.getPropertyName(); ui->xPos->bind(App::ObjectIdentifier::parse(obj, propertyName + std::string(".Base.x"))); ui->yPos->bind(App::ObjectIdentifier::parse(obj, propertyName + std::string(".Base.y"))); ui->zPos->bind(App::ObjectIdentifier::parse(obj, propertyName + std::string(".Base.z"))); @@ -803,6 +859,13 @@ Base::Vector3d Placement::getPositionData() const ui->zPos->value().getValue()); } +Base::Vector3d Placement::getAnglesData() const +{ + return Base::Vector3d(ui->yawAngle->value().getValue(), + ui->pitchAngle->value().getValue(), + ui->rollAngle->value().getValue()); +} + Base::Vector3d Placement::getCenterData() const { if (ui->centerOfMass->isChecked()) @@ -812,6 +875,23 @@ Base::Vector3d Placement::getCenterData() const ui->zCnt->value().getValue()); } +Base::Vector3d Placement::getCenterOfMass() const +{ + Base::Vector3d centerOfMass; + std::vector sel = Gui::Selection().getObjectsOfType + (App::GeoFeature::getClassTypeId()); + if (!sel.empty()) { + for (auto it : sel) { + const App::PropertyComplexGeoData* propgeo = static_cast(it)->getPropertyOfGeometry(); + const Data::ComplexGeoData* geodata = propgeo ? propgeo->getComplexData() : nullptr; + if (geodata && geodata->getCenterOfGravity(centerOfMass)) { + break; + } + } + } + return centerOfMass; +} + Base::Placement Placement::getPlacementData() const { Base::Rotation rot = getRotationData(); @@ -825,15 +905,16 @@ Base::Placement Placement::getPlacementData() const QString Placement::getPlacementFromEulerAngles() const { Base::Vector3d pos = getPositionData(); + Base::Vector3d ypr = getAnglesData(); Base::Vector3d cnt = getCenterData(); return QString::fromLatin1( "App.Placement(App.Vector(%1,%2,%3), App.Rotation(%4,%5,%6), App.Vector(%7,%8,%9))") .arg(pos.x) .arg(pos.y) .arg(pos.z) - .arg(ui->yawAngle->value().getValue()) - .arg(ui->pitchAngle->value().getValue()) - .arg(ui->rollAngle->value().getValue()) + .arg(ypr.x) + .arg(ypr.y) + .arg(ypr.z) .arg(cnt.x) .arg(cnt.y) .arg(cnt.z); @@ -967,7 +1048,7 @@ void TaskPlacement::open() void TaskPlacement::setPropertyName(const QString& name) { - widget->propertyName = (const char*)name.toLatin1(); + widget->setPropertyName(name.toStdString()); } QDialogButtonBox::StandardButtons TaskPlacement::getStandardButtons() const diff --git a/src/Gui/Placement.h b/src/Gui/Placement.h index 7858c80c89..463147c79d 100644 --- a/src/Gui/Placement.h +++ b/src/Gui/Placement.h @@ -32,6 +32,9 @@ class QSignalMapper; +namespace App { +class DocumentObject; +} namespace Gui { class Document; @@ -40,6 +43,43 @@ namespace Dialog { class Ui_Placement; class TaskPlacement; +class GuiExport PlacementHandler : public QObject +{ + Q_OBJECT + +public: + PlacementHandler(); + void openTransactionIfNeeded(); + void setPropertyName(const std::string&); + const std::string& getPropertyName() const; + void appendDocument(const std::string&); + void activatedDocument(const std::string&); + void revertTransformation(); + void applyPlacement(const Base::Placement& p, bool incremental); + void applyPlacement(const QString& p, bool incremental); + +private: + std::vector getObjects(Gui::Document*) const; + std::vector getSelectedObjects(Gui::Document*) const; + void revertTransformationOfViewProviders(Gui::Document*); + void tryRecompute(Gui::Document*); + void applyPlacement(Gui::Document*, App::DocumentObject*, const Base::Placement& p, bool incremental); + void applyPlacement(App::DocumentObject*, const QString& p, bool incremental); + QString getIncrementalPlacement(App::DocumentObject*, const QString&) const; + QString getSimplePlacement(App::DocumentObject*, const QString&) const; + +private Q_SLOTS: + void openTransaction(); + +private: + std::string propertyName; // the name of the placement property + std::set documents; + /** If false apply the placement directly to the transform nodes, + * otherwise change the placement property. + */ + bool changeProperty; +}; + class GuiExport Placement : public QDialog { Q_OBJECT @@ -47,9 +87,11 @@ class GuiExport Placement : public QDialog public: explicit Placement(QWidget* parent = nullptr, Qt::WindowFlags fl = Qt::WindowFlags()); ~Placement() override; + void open() override; void accept() override; void reject() override; + void setPropertyName(const std::string&); void setSelection(const std::vector&); void bindObject(); Base::Vector3d getDirection() const; @@ -58,13 +100,13 @@ public: void showDefaultButtons(bool); protected: - void open() override; void changeEvent(QEvent *e) override; void keyPressEvent(QKeyEvent*) override; -private Q_SLOTS: - void openTransaction(); +public Q_SLOTS: void onApplyButtonClicked(); + +private Q_SLOTS: void onApplyIncrementalPlacementToggled(bool); void onPlacementChanged(int); void onResetButtonClicked(); @@ -85,13 +127,12 @@ private: Base::Placement getPlacementData() const; Base::Rotation getRotationData() const; Base::Vector3d getPositionData() const; + Base::Vector3d getAnglesData() const; Base::Vector3d getCenterData() const; + Base::Vector3d getCenterOfMass() const; QString getPlacementString() const; QString getPlacementFromEulerAngles() const; QString getPlacementFromAxisWithAngle() const; - void applyPlacement(const Base::Placement& p, bool incremental); - void applyPlacement(const QString& p, bool incremental); - void revertTransformation(); void slotActiveDocument(const Gui::Document&); QWidget* getInvalidInput() const; void showErrorMessage(); @@ -104,21 +145,14 @@ private: Ui_Placement* ui; QSignalMapper* signalMapper; Connection connectAct; + PlacementHandler handler; Base::Placement ref; Base::Vector3d cntOfMass; - std::string propertyName; // the name of the placement property - std::set documents; /** * store these so we can reselect original object * after user selects points and clicks Selected point(s) */ std::vector selectionObjects; - /** If false apply the placement directly to the transform nodes, - * otherwise change the placement property. - */ - bool changeProperty; - - friend class TaskPlacement; }; class GuiExport DockablePlacement : public Placement