From 2d8c97b5f0605841930aad8cb70fae7e911935d3 Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Mon, 2 Mar 2026 19:25:27 +0100 Subject: [PATCH] NewItemDialog uses dynamically generated control widgets for model data as well. Added a WidgetHelper class to consolidate identical source code for ItemDetailMapper and NewItemDialog. --- CMakeLists.txt | 1 + dialogs/newitemdialog.cpp | 119 +++++++++++++++++++++++-------------- dialogs/newitemdialog.h | 17 ++---- views/itemdetailmapper.cpp | 42 ++----------- views/itemdetailmapper.h | 2 - widgethelper.cpp | 45 ++++++++++++++ widgethelper.h | 17 ++++++ 7 files changed, 146 insertions(+), 97 deletions(-) create mode 100644 widgethelper.cpp create mode 100644 widgethelper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 46d5c15..98d1b32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) dialogs/settingsdialog.h dialogs/settingsdialog.cpp views/itemdetailmapper.h views/itemdetailmapper.cpp widgets/controls/comboboxdelegate.h widgets/controls/comboboxdelegate.cpp + widgethelper.h widgethelper.cpp ) # Define target properties for Android with Qt 6 as: # set_property(TARGET ${TARGET_APP} APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR diff --git a/dialogs/newitemdialog.cpp b/dialogs/newitemdialog.cpp index a3760c2..6abc382 100644 --- a/dialogs/newitemdialog.cpp +++ b/dialogs/newitemdialog.cpp @@ -1,11 +1,15 @@ #include "newitemdialog.h" +#include #include #include #include #include #include #include +#include + +#include "../widgethelper.h" #include "formats/jsonparser.h" #include "model/metadata.h" @@ -21,61 +25,84 @@ void NewItemDialog::createContent() { m_contentContainer = new QWidget(this); - // REFACTOR use a data structure for input widgets which can be iterated through - // using a factory which iterates through the roles from metadata.h - // and create the input widgets based on the data type of this role - m_nameLabel = new QLabel("&Name"); - m_nameEdit = new QLineEdit(); - m_nameLabel->setBuddy(m_nameEdit); + m_layout = new QGridLayout(); - m_descriptionLabel = new QLabel("&Description"); - m_descriptionEdit = new QLineEdit(); - m_descriptionLabel->setBuddy(m_descriptionEdit); + for (int i = 0; i < USER_FACING_ROLES.size(); ++i) { + setupWidgetPairForColumn(i); + } - m_infoLabel = new QLabel("&Info"); - m_infoEdit = new QLineEdit(); - m_infoLabel->setBuddy(m_infoEdit); - - m_amountLabel = new QLabel("&Amount"); - m_amountBox = new QSpinBox(); - m_amountBox->setMaximum(1000); - m_amountLabel->setBuddy(m_amountBox); - - m_factorLabel = new QLabel("&Factor"); - m_factorBox = new QDoubleSpinBox(); - m_factorBox->setMaximum(1000); - m_factorLabel->setBuddy(m_factorBox); - - QGridLayout* layout = new QGridLayout(); - layout->addWidget(m_nameLabel, 0, 0, 1, 1); - layout->addWidget(m_nameEdit, 0, 1, 1, 1); - layout->addWidget(m_descriptionLabel, 1, 0, 1, 1); - layout->addWidget(m_descriptionEdit, 1, 1, 1, 1); - layout->addWidget(m_infoLabel, 2, 0, 1, 1); - layout->addWidget(m_infoEdit, 2, 1, 1, 1); - layout->addWidget(m_amountLabel, 3, 0, 1, 1); - layout->addWidget(m_amountBox, 3, 1, 1, 1); - layout->addWidget(m_factorLabel, 4, 0, 1, 1); - layout->addWidget(m_factorBox, 4, 1, 1, 1); - - m_contentContainer->setLayout(layout); + m_contentContainer->setLayout(m_layout); m_outerLayout->insertWidget(0, m_contentContainer); } void NewItemDialog::accept() { + addItemToModel(); + + resetContent(); + + AbstractDialog::accept(); +} + +void NewItemDialog::setupWidgetPairForColumn(const int column) { + // REFACTOR consolidate NewItemDialog::setupWidgetPairForColumn(...) + // with ItemDetailMapper::setupWidgetPairForColumn(...) + const UserRoles role = GET_ROLE_FOR_COLUMN(column); + + QWidget* control = WidgetHelper::createControlWidget(role, this); + + const QString string = QString("&%1").arg(GET_HEADER_FOR_COLUMN(column)); + QLabel* label = new QLabel(string); + label->setBuddy(control); + + m_layout->addWidget(label, column, 0); + m_layout->addWidget(control, column, 1); + m_controlWidgets.append(control); +} + +void NewItemDialog::addItemToModel() { ModelItemValues itemValues; - // TODO (after refactoring data structure for input widgets) use iteration through the relevant - // roles and their input widgets - itemValues.insert(NameRole, m_nameEdit->text()); - itemValues.insert(DescriptionRole, m_descriptionEdit->text()); - itemValues.insert(InfoRole, m_infoEdit->text()); - itemValues.insert(AmountRole, m_amountBox->value()); - itemValues.insert(FactorRole, m_factorBox->value()); + + for (int i = 0; i < m_controlWidgets.size(); ++i) { + const UserRoles role = GET_ROLE_FOR_COLUMN(i); + if (STRING_ROLES.contains(role)) { + QLineEdit* lineEdit = dynamic_cast(m_controlWidgets[i]); + itemValues.insert(role, lineEdit->text()); + } else if (TYPE_ROLES.contains(role)) { + QComboBox* comboBox = dynamic_cast(m_controlWidgets[i]); + itemValues.insert(role, comboBox->currentText()); + } else if (INT_ROLES.contains(role)) { + QSpinBox* spinBox = dynamic_cast(m_controlWidgets[i]); + itemValues.insert(role, spinBox->value()); + } else if (DOUBLE_ROLES.contains(role)) { + QDoubleSpinBox* doubleSpinBox = dynamic_cast(m_controlWidgets[i]); + itemValues.insert(role, doubleSpinBox->value()); + } else { + qCritical() << "Could not reset content for control widget in column:" << i << "!"; + } + } const QByteArray jsonDoc = JsonParser::itemValuesListToJson({itemValues}, ITEMS_KEY_STRING); emit addItems(jsonDoc); - - // resetContent(); - AbstractDialog::accept(); +} + +void NewItemDialog::resetContent() { + for (int i = 0; i < m_controlWidgets.size(); ++i) { + const UserRoles role = GET_ROLE_FOR_COLUMN(i); + if (STRING_ROLES.contains(role)) { + QLineEdit* lineEdit = dynamic_cast(m_controlWidgets[i]); + lineEdit->clear(); + } else if (TYPE_ROLES.contains(role)) { + QComboBox* comboBox = dynamic_cast(m_controlWidgets[i]); + comboBox->setCurrentText(""); + } else if (INT_ROLES.contains(role)) { + QSpinBox* spinBox = dynamic_cast(m_controlWidgets[i]); + spinBox->setValue(0); + } else if (DOUBLE_ROLES.contains(role)) { + QDoubleSpinBox* doubleSpinBox = dynamic_cast(m_controlWidgets[i]); + doubleSpinBox->setValue(0.0); + } else { + qCritical() << "Could not reset content for control widget in column:" << i << "!"; + } + } } diff --git a/dialogs/newitemdialog.h b/dialogs/newitemdialog.h index 23b1987..9a46ae5 100644 --- a/dialogs/newitemdialog.h +++ b/dialogs/newitemdialog.h @@ -24,20 +24,13 @@ class NewItemDialog : public AbstractDialog { // void reject() override; private: - QLabel* m_nameLabel = nullptr; - QLineEdit* m_nameEdit = nullptr; + QGridLayout* m_layout; + QList m_controlWidgets; - QLabel* m_descriptionLabel = nullptr; - QLineEdit* m_descriptionEdit = nullptr; + void setupWidgetPairForColumn(const int column); - QLabel* m_infoLabel = nullptr; - QLineEdit* m_infoEdit = nullptr; - - QLabel* m_amountLabel = nullptr; - QSpinBox* m_amountBox = nullptr; - - QLabel* m_factorLabel = nullptr; - QDoubleSpinBox* m_factorBox = nullptr; + void addItemToModel(); + void resetContent(); }; #endif // NEWITEMDIALOG_H diff --git a/views/itemdetailmapper.cpp b/views/itemdetailmapper.cpp index a2a52e9..b887b27 100644 --- a/views/itemdetailmapper.cpp +++ b/views/itemdetailmapper.cpp @@ -11,6 +11,8 @@ #include #include +#include "../widgethelper.h" + ItemDetailMapper::ItemDetailMapper(QTableView* tableView, QWidget* parent) : QWidget{parent} { /// model mapping @@ -127,9 +129,11 @@ void ItemDetailMapper::setupWidgets() { } void ItemDetailMapper::setupWidgetPairForColumn(const int column) { + // REFACTOR consolidate ItemDetailMapper::setupWidgetPairForColumn(...) + // with NewItemDialog::setupWidgetPairForColumn(...) const UserRoles role = GET_ROLE_FOR_COLUMN(column); - QWidget* control = createControlWidget(role); + QWidget* control = WidgetHelper::createControlWidget(role, this); const QString string = QString("&%1").arg(GET_HEADER_FOR_COLUMN(column)); QLabel* label = new QLabel(string); @@ -146,42 +150,6 @@ void ItemDetailMapper::setupWidgetPairForColumn(const int column) { } } -QWidget* ItemDetailMapper::createControlWidget(const UserRoles role) { - QWidget* control; - if (STRING_ROLES.contains(role)) { - control = new QLineEdit(); - } else if (TYPE_ROLES.contains(role)) { - control = createComboBox(role); - } else if (INT_ROLES.contains(role)) { - QSpinBox* spinBox = new QSpinBox(); - spinBox->setMaximum(1000); - control = spinBox; - } else if (DOUBLE_ROLES.contains(role)) { - QDoubleSpinBox* spinBox = new QDoubleSpinBox(); - spinBox->setMaximum(1000); - control = spinBox; - } else { - qCritical() << QString("Unsupported role %1!!!").arg(role); - qDebug() << "Using line edit as well and pretend it's a string role..."; - control = new QLineEdit(); - } - return control; -} - -QWidget* ItemDetailMapper::createComboBox(const UserRoles role) { - QStringListModel* typeModel; - if (role == TypeRole) { - typeModel = new QStringListModel(TYPES, this); - } else { - qCritical() << "Unsupported type with role:" << role - << "- Using string list model with only one empty string!"; - typeModel = new QStringListModel({""}, this); - } - QComboBox* comboBox = new QComboBox(); - comboBox->setModel(typeModel); - return comboBox; -} - void ItemDetailMapper::clearControlWidgets() { setEnabled(false); diff --git a/views/itemdetailmapper.h b/views/itemdetailmapper.h index ef87b52..11e9118 100644 --- a/views/itemdetailmapper.h +++ b/views/itemdetailmapper.h @@ -58,8 +58,6 @@ class ItemDetailMapper : public QWidget { void setupWidgets(); void setupWidgetPairForColumn(const int column); - QWidget* createControlWidget(const UserRoles role); - QWidget* createComboBox(const UserRoles role); void clearControlWidgets(); void clearLineEdit(const int column); diff --git a/widgethelper.cpp b/widgethelper.cpp new file mode 100644 index 0000000..2a8e790 --- /dev/null +++ b/widgethelper.cpp @@ -0,0 +1,45 @@ +#include "widgethelper.h" + +#include +#include +#include +#include + +QWidget* WidgetHelper::createControlWidget(const UserRoles role, QWidget* parent) { + QWidget* control; + if (STRING_ROLES.contains(role)) { + control = new QLineEdit(); + } else if (TYPE_ROLES.contains(role)) { + control = createComboBox(role, parent); + } else if (INT_ROLES.contains(role)) { + QSpinBox* spinBox = new QSpinBox(); + spinBox->setMaximum(1000); + control = spinBox; + } else if (DOUBLE_ROLES.contains(role)) { + QDoubleSpinBox* spinBox = new QDoubleSpinBox(); + spinBox->setMaximum(1000); + control = spinBox; + } else { + qCritical() << QString("Unsupported role %1!!!").arg(role); + qDebug() << "Using line edit as well and pretend it's a string role..."; + control = new QLineEdit(); + } + return control; +} + +QWidget* WidgetHelper::createComboBox(const UserRoles role, QWidget* parent) { + QStringListModel* typeModel; + if (role == TypeRole) { + typeModel = new QStringListModel(TYPES, parent); + } else { + qCritical() << "Unsupported type with role:" << role + << "- Using string list model with only one empty string!"; + typeModel = new QStringListModel({""}, parent); + } + QComboBox* comboBox = new QComboBox(); + comboBox->setModel(typeModel); + comboBox->setCurrentText(""); + return comboBox; +} + +WidgetHelper::WidgetHelper() {} diff --git a/widgethelper.h b/widgethelper.h new file mode 100644 index 0000000..e86b286 --- /dev/null +++ b/widgethelper.h @@ -0,0 +1,17 @@ +#ifndef WIDGETHELPER_H +#define WIDGETHELPER_H + +#include "model/metadata.h" + +class QWidget; + +class WidgetHelper { + public: + static QWidget* createControlWidget(const UserRoles role, QWidget* parent); + static QWidget* createComboBox(const UserRoles role, QWidget* parent); + + private: + explicit WidgetHelper(); +}; + +#endif // WIDGETHELPER_H