NewItemDialog uses dynamically generated control widgets for model data as well. Added a WidgetHelper class to consolidate identical source code for ItemDetailMapper and NewItemDialog.

This commit is contained in:
2026-03-02 19:25:27 +01:00
parent 2fb7560e6e
commit 2d8c97b5f0
7 changed files with 146 additions and 97 deletions

View File

@ -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

View File

@ -1,11 +1,15 @@
#include "newitemdialog.h"
#include <QComboBox>
#include <QGridLayout>
#include <QJsonArray>
#include <QJsonObject>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
#include <QStringListModel>
#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<QLineEdit*>(m_controlWidgets[i]);
itemValues.insert(role, lineEdit->text());
} else if (TYPE_ROLES.contains(role)) {
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[i]);
itemValues.insert(role, comboBox->currentText());
} else if (INT_ROLES.contains(role)) {
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(m_controlWidgets[i]);
itemValues.insert(role, spinBox->value());
} else if (DOUBLE_ROLES.contains(role)) {
QDoubleSpinBox* doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(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<QLineEdit*>(m_controlWidgets[i]);
lineEdit->clear();
} else if (TYPE_ROLES.contains(role)) {
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[i]);
comboBox->setCurrentText("");
} else if (INT_ROLES.contains(role)) {
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(m_controlWidgets[i]);
spinBox->setValue(0);
} else if (DOUBLE_ROLES.contains(role)) {
QDoubleSpinBox* doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(m_controlWidgets[i]);
doubleSpinBox->setValue(0.0);
} else {
qCritical() << "Could not reset content for control widget in column:" << i << "!";
}
}
}

View File

@ -24,20 +24,13 @@ class NewItemDialog : public AbstractDialog {
// void reject() override;
private:
QLabel* m_nameLabel = nullptr;
QLineEdit* m_nameEdit = nullptr;
QGridLayout* m_layout;
QList<QWidget*> 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

View File

@ -11,6 +11,8 @@
#include <QSpinBox>
#include <QTableView>
#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);

View File

@ -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);

45
widgethelper.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "widgethelper.h"
#include <QComboBox>
#include <QLineEdit>
#include <QSpinBox>
#include <QStringListModel>
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() {}

17
widgethelper.h Normal file
View File

@ -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