From 5673d299f91a060e0c65901a1dbe9c5090892aca Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 12 Jan 2020 01:09:25 +0100 Subject: [PATCH] implementation classes don't inherit from UI classes --- src/Gui/InputVector.cpp | 32 +++++ src/Gui/InputVector.h | 180 ++++++++++++++++++++++++ src/Mod/Part/Gui/DlgPartBoxImp.cpp | 3 +- src/Mod/Part/Gui/DlgPartBoxImp.h | 5 +- src/Mod/Part/Gui/DlgPartCylinderImp.cpp | 21 ++- src/Mod/Part/Gui/DlgPartCylinderImp.h | 8 +- 6 files changed, 233 insertions(+), 16 deletions(-) diff --git a/src/Gui/InputVector.cpp b/src/Gui/InputVector.cpp index 4911698385..c6a52cf7a8 100644 --- a/src/Gui/InputVector.cpp +++ b/src/Gui/InputVector.cpp @@ -256,4 +256,36 @@ void LocationDialog::on_direction_activated(int index) directionActivated(index); } +// ----------------------------------------------------------- + +LocationDialogUiImp::~LocationDialogUiImp() +{ + // no need to delete child widgets, Qt does it all for us +} + +Base::Vector3d LocationDialogUiImp::getDirection() const +{ + return ui->getDirection(); +} + +Base::Vector3d LocationDialogUiImp::getPosition() const +{ + return ui->getPosition(); +} + +void LocationDialogUiImp::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslate(this); + } + else { + QDialog::changeEvent(e); + } +} + +void LocationDialogUiImp::directionActivated(int index) +{ + ui->directionActivated(this,index); +} + #include "moc_InputVector.cpp" diff --git a/src/Gui/InputVector.h b/src/Gui/InputVector.h index c579e035a1..ec060358d9 100644 --- a/src/Gui/InputVector.h +++ b/src/Gui/InputVector.h @@ -24,6 +24,8 @@ #define GUI_INPUTVECTOR_H #include +#include +#include #include #include #include @@ -399,6 +401,184 @@ protected: LocationUi ui; }; +/** + * @brief The AbstractUi class + * Abstract base class the defines the class interface. + * @author Werner Mayer + */ +class AbstractUi +{ +public: + virtual ~AbstractUi() = default; + virtual void retranslate(QDialog *dlg) = 0; + virtual void setPosition(const Base::Vector3d& v) = 0; + virtual Base::Vector3d getPosition() const = 0; + virtual Base::Vector3d getDirection() const = 0; + virtual void setDirection(const Base::Vector3d& dir) = 0; + virtual bool directionActivated(LocationDialog* dlg, int index) = 0; + virtual boost::any get() = 0; +}; + +/** This is the template class that implements the interface of AbstractUi. + * The template argument is the Ui interface class built by uic out of a + * .ui file. + * @author Werner Mayer + */ +template +class LocationImpUi : public AbstractUi +{ +public: + LocationImpUi(Ui* ui) : ui(ui) + { + } + ~LocationImpUi() + { + } + + boost::any get() + { + return ui; + } + + void retranslate(QDialog *dlg) + { + ui->retranslateUi(dlg); + + if (ui->direction->count() == 0) { + ui->direction->insertItems(0, QStringList() + << QApplication::translate("Gui::LocationDialog", "X") + << QApplication::translate("Gui::LocationDialog", "Y") + << QApplication::translate("Gui::LocationDialog", "Z") + << QApplication::translate("Gui::LocationDialog", "User defined...") + ); + + ui->direction->setCurrentIndex(2); + + // Vector3d declared to use with QVariant see Gui/propertyeditor/PropertyItem.h + ui->direction->setItemData(0, QVariant::fromValue(Base::Vector3d(1,0,0))); + ui->direction->setItemData(1, QVariant::fromValue(Base::Vector3d(0,1,0))); + ui->direction->setItemData(2, QVariant::fromValue(Base::Vector3d(0,0,1))); + } + else { + ui->direction->setItemText(0, QApplication::translate("Gui::LocationDialog", "X")); + ui->direction->setItemText(1, QApplication::translate("Gui::LocationDialog", "Y")); + ui->direction->setItemText(2, QApplication::translate("Gui::LocationDialog", "Z")); + ui->direction->setItemText(ui->direction->count()-1, + QApplication::translate("Gui::LocationDialog", "User defined...")); + } + } + + void setPosition(const Base::Vector3d& v) + { + ui->xPos->setValue(v.x); + ui->yPos->setValue(v.y); + ui->zPos->setValue(v.z); + } + + Base::Vector3d getPosition() const + { + return Base::Vector3d(ui->xPos->value().getValue(), + ui->yPos->value().getValue(), + ui->zPos->value().getValue()); + } + + Base::Vector3d getDirection() const + { + QVariant data = ui->direction->itemData (ui->direction->currentIndex()); + if (data.canConvert()) { + return data.value(); + } + else { + return Base::Vector3d(0,0,1); + } + } + +public: + void setDirection(const Base::Vector3d& dir) + { + if (dir.Length() < Base::Vector3d::epsilon()) { + return; + } + + // check if the user-defined direction is already there + for (int i=0; idirection->count()-1; i++) { + QVariant data = ui->direction->itemData (i); + if (data.canConvert()) { + const Base::Vector3d val = data.value(); + if (val == dir) { + ui->direction->setCurrentIndex(i); + return; + } + } + } + + // add a new item before the very last item + QString display = QString::fromLatin1("(%1,%2,%3)") + .arg(dir.x) + .arg(dir.y) + .arg(dir.z); + ui->direction->insertItem(ui->direction->count()-1, display, + QVariant::fromValue(dir)); + ui->direction->setCurrentIndex(ui->direction->count()-2); + } + bool directionActivated(LocationDialog* dlg, int index) + { + // last item is selected to define direction by user + if (index+1 == ui->direction->count()) { + bool ok; + Base::Vector3d dir = dlg->getUserDirection(&ok); + if (ok) { + if (dir.Length() < Base::Vector3d::epsilon()) { + QMessageBox::critical(dlg, LocationDialog::tr("Wrong direction"), + LocationDialog::tr("Direction must not be the null vector")); + return false; + } + setDirection(dir); + } + } + return true; + } + +private: + std::shared_ptr ui; +}; + +/** This is a subclass of LocationDialog using AbstractUi that implements + * the pure virtual methods of its base class. + * Other dialog-based classes can directly inherit from this class if the + * location-interface is required. + * The advantage of this class compared to LocationDialogImp is that the + * ui_-header file doesn't need to be included in the header file of its + * sub-classes because it uses "type erasure with templates". + * @author Werner Mayer + */ +class LocationDialogUiImp : public LocationDialog +{ +public: + template + LocationDialogUiImp(T* t, QWidget* parent = 0, Qt::WindowFlags fl = 0) + : LocationDialog(parent, fl), ui(new LocationImpUi(t)) + { + std::shared_ptr uit = boost::any_cast< std::shared_ptr >(ui->get()); + uit->setupUi(this); + ui->retranslate(this); + } + virtual ~LocationDialogUiImp(); + + Base::Vector3d getDirection() const; + + Base::Vector3d getPosition() const; + +protected: + void changeEvent(QEvent *e); + +private: + void directionActivated(int index); + +protected: + std::unique_ptr ui; +}; + } // namespace Gui #endif // GUI_INPUTVECTOR_H diff --git a/src/Mod/Part/Gui/DlgPartBoxImp.cpp b/src/Mod/Part/Gui/DlgPartBoxImp.cpp index ea1443253b..28a9201311 100644 --- a/src/Mod/Part/Gui/DlgPartBoxImp.cpp +++ b/src/Mod/Part/Gui/DlgPartBoxImp.cpp @@ -26,6 +26,7 @@ #endif #include "DlgPartBoxImp.h" +#include "ui_DlgPartBox.h" using namespace PartGui; @@ -37,7 +38,7 @@ using namespace PartGui; * true to construct a modal dialog. */ DlgPartBoxImp::DlgPartBoxImp(QWidget* parent, Qt::WindowFlags fl) - : Gui::LocationDialogUi(parent, fl) + : Gui::LocationDialogUiImp(new Ui_DlgPartBox, parent, fl) { } diff --git a/src/Mod/Part/Gui/DlgPartBoxImp.h b/src/Mod/Part/Gui/DlgPartBoxImp.h index 2ff4fd5b42..4428c077c4 100644 --- a/src/Mod/Part/Gui/DlgPartBoxImp.h +++ b/src/Mod/Part/Gui/DlgPartBoxImp.h @@ -23,12 +23,13 @@ #ifndef PARTGUI_DLGPARTBOXIMP_H #define PARTGUI_DLGPARTBOXIMP_H -#include "ui_DlgPartBox.h" #include namespace PartGui { +class Ui_DlgPartBox; +typedef std::shared_ptr Ui_DlgPartBoxPtr; -class DlgPartBoxImp : public Gui::LocationDialogUi +class DlgPartBoxImp : public Gui::LocationDialogUiImp { Q_OBJECT diff --git a/src/Mod/Part/Gui/DlgPartCylinderImp.cpp b/src/Mod/Part/Gui/DlgPartCylinderImp.cpp index ce3053f479..16056adf58 100644 --- a/src/Mod/Part/Gui/DlgPartCylinderImp.cpp +++ b/src/Mod/Part/Gui/DlgPartCylinderImp.cpp @@ -26,22 +26,16 @@ #endif #include "DlgPartCylinderImp.h" +#include "ui_DlgPartCylinder.h" using namespace PartGui; -/* - * Constructs a DlgPartCylinder which is a child of 'parent', with the - * name 'name' and widget flags set to 'f' - * - * The dialog will by default be modeless, unless you set 'modal' to - * true to construct a modal dialog. - */ DlgPartCylinderImp::DlgPartCylinderImp(QWidget* parent, Qt::WindowFlags fl) - : Gui::LocationDialogUi(parent, fl) + : Gui::LocationDialogUiImp(new Ui_DlgPartCylinder, parent, fl) { } -/* +/* * Destroys the object and frees any allocated resources */ DlgPartCylinderImp::~DlgPartCylinderImp() @@ -49,14 +43,19 @@ DlgPartCylinderImp::~DlgPartCylinderImp() // no need to delete child widgets, Qt does it all for us } +Ui_DlgPartCylinderPtr DlgPartCylinderImp::getUi() const +{ + return boost::any_cast< Ui_DlgPartCylinderPtr >(ui->get()); +} + double DlgPartCylinderImp::getRadius() const { - return this->radius->value().getValue(); + return getUi()->radius->value().getValue(); } double DlgPartCylinderImp::getLength() const { - return this->length->value().getValue(); + return getUi()->length->value().getValue(); } #include "moc_DlgPartCylinderImp.cpp" diff --git a/src/Mod/Part/Gui/DlgPartCylinderImp.h b/src/Mod/Part/Gui/DlgPartCylinderImp.h index 64660e933d..090b885e13 100644 --- a/src/Mod/Part/Gui/DlgPartCylinderImp.h +++ b/src/Mod/Part/Gui/DlgPartCylinderImp.h @@ -23,12 +23,13 @@ #ifndef PARTGUI_DLGPARTCYLINDERIMP_H #define PARTGUI_DLGPARTCYLINDERIMP_H -#include "ui_DlgPartCylinder.h" #include namespace PartGui { +class Ui_DlgPartCylinder; +typedef std::shared_ptr Ui_DlgPartCylinderPtr; -class DlgPartCylinderImp : public Gui::LocationDialogUi +class DlgPartCylinderImp : public Gui::LocationDialogUiImp { Q_OBJECT @@ -38,6 +39,9 @@ public: double getRadius() const; double getLength() const; + +private: + Ui_DlgPartCylinderPtr getUi() const; }; } // namespace PartGui