Compare commits

..

10 Commits

15 changed files with 397 additions and 316 deletions

View File

@ -27,7 +27,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(${TARGET_APP}
MANUAL_FINALIZATION
${PROJECT_SOURCES}
utils/messagehandler.h
assets/icons.qrc
dialogs/abstractdialog.h dialogs/abstractdialog.cpp
dialogs/newitemdialog.h dialogs/newitemdialog.cpp
@ -35,6 +35,8 @@ 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
widgets/controls/spinboxdelegate.h widgets/controls/spinboxdelegate.cpp
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET ${TARGET_APP} APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,7 +1,6 @@
<RCC>
<qresource prefix="/">
<file>software-application.png</file>
<file>feature.png</file>
<file>no-picture-taking.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -22,8 +22,7 @@ void EditItemDialog::createContent() {
QHBoxLayout* innerLayout = new QHBoxLayout();
m_contentContainer->setLayout(innerLayout);
m_detailMapper = new ItemDetailMapper(this);
m_detailMapper->setModelMappings(m_tableView);
m_detailMapper = new ItemDetailMapper(m_tableView, this);
innerLayout->addWidget(m_detailMapper);
updateQRCode();

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

@ -18,6 +18,7 @@
#include "model/metadata.h"
#include "model/tablemodel.h"
#include "widgets/controls/comboboxdelegate.h"
#include "widgets/controls/spinboxdelegate.h"
static QStandardPaths::StandardLocation standardLocation = QStandardPaths::HomeLocation;
static QString updateTextClean = "Do you want to update the application now?";
@ -33,12 +34,13 @@ MainWindow::MainWindow(QWidget* parent)
setWindowTitle(QCoreApplication::applicationName() + " [*]");
/// application icon
const QString iconString = "://feature.png";
const QString iconString = "://software-application.png";
#ifdef QT_DEBUG
QPixmap pixmap = QPixmap(iconString);
QTransform transform = QTransform();
transform.rotate(180);
QPixmap rotated = pixmap.transformed(transform);
QIcon appIcon = QIcon(rotated);
setWindowIcon(QIcon(rotated));
#else
setWindowIcon(QIcon(iconString));
@ -250,7 +252,6 @@ void MainWindow::importCSV() {
tr("CSV Files (*.csv)"));
if (QFileInfo::exists(csvFilePath)) {
m_core->importCSVFile(csvFilePath);
showStatusMessage(tr("Imported CSV file."));
} else {
qWarning() << "Selected CSV file path doesn't exist. Doing nothing...";
showStatusMessage(tr("Could't find CSV file!"));
@ -343,6 +344,16 @@ void MainWindow::setupModelViews() {
// ui->tableView->setModel(m_tableModel.get());
m_proxyModel = m_core->getSortFilterModel();
// TODO iterate over INT_ROLES and DOUBLE_ROLES to set spinbox delegate
/// setting number delegates to combo boxes
SpinboxDelegate* spinboxDelegate = new SpinboxDelegate(this);
const int amountColumn = GET_COLUMN_FOR_ROLE(AmountRole);
ui->tableView->setItemDelegateForColumn(amountColumn, spinboxDelegate);
const int factorColumn = GET_COLUMN_FOR_ROLE(FactorRole);
ui->tableView->setItemDelegateForColumn(factorColumn, spinboxDelegate);
// TODO iterate over TYPE_ROLES to set combobox delegate
/// setting type delegates to combo boxes
const int typeColumn = GET_COLUMN_FOR_ROLE(TypeRole);
ComboboxDelegate* shareTypeDelegate = new ComboboxDelegate(TYPES, this);
ui->tableView->setItemDelegateForColumn(typeColumn, shareTypeDelegate);

View File

@ -1,164 +0,0 @@
#ifndef MESSAGEHANDLER_H
#define MESSAGEHANDLER_H
/**
* Color and formatting codes
* @see: http://misc.flogisoft.com/bash/tip_colors_and_formatting
*/
#include <QObject>
// qSetMessagePattern("%{file}(%{line}): %{message}");
// qSetMessagePattern("%{type}(%{line}):\t%{message}");
// qSetMessagePattern("%{type}%{file}(%{line}):\t%{message}");
void consoleHandlerColoredVerbose(QtMsgType type,
const QMessageLogContext& context,
const QString& msg) {
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
// fprintf(stderr, "\033[1;30mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file,
// context.line, context.function, localMsg.constData()); // bold
fprintf(stderr, "\033[107;30mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
break;
case QtInfoMsg:
fprintf(stderr, "\033[107;32mInfo: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
break;
case QtWarningMsg:
fprintf(stderr, "\033[43;30mWarning: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
break;
case QtCriticalMsg:
fprintf(stderr, "\033[41;30mCritical: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
break;
case QtFatalMsg:
fprintf(stderr, "\033[41;30mFatal: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
abort();
}
}
void consoleHandlerColoredVerboseInDarkTheme(QtMsgType type,
const QMessageLogContext& context,
const QString& msg) {
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
// fprintf(stderr, "\033[1;30mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file,
// context.line, context.function, localMsg.constData()); // bold
fprintf(stderr, "\033[107;37mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
break;
case QtInfoMsg:
fprintf(stderr, "\033[107;32mInfo: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
break;
case QtWarningMsg:
fprintf(stderr, "\033[43;30mWarning: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
break;
case QtCriticalMsg:
fprintf(stderr, "\033[41;30mCritical: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
break;
case QtFatalMsg:
fprintf(stderr, "\033[41;30mFatal: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
context.function, localMsg.constData());
abort();
}
}
void consoleHandlerColored(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
fprintf(stderr, "\033[1;30mDebug: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
break;
case QtInfoMsg:
fprintf(stderr, "\033[0;30mInfo: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
break;
case QtWarningMsg:
fprintf(stderr, "\033[1;33mWarning: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
break;
case QtCriticalMsg:
fprintf(stderr, "\033[31mCritical: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
break;
case QtFatalMsg:
fprintf(stderr, "\033[31mFatal: (%s:%u) \t%s\n\033[0m", context.file, context.line,
localMsg.constData());
abort();
}
}
void myMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
context.function);
break;
case QtInfoMsg:
fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
context.function);
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
context.function);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file,
context.line, context.function);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
context.function);
abort();
}
}
#ifdef Q_OS_ANDROID
#include <android/log.h>
const char* const applicationName = "Pensieve";
void androidMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
QString report = msg;
if (context.file && !QString(context.file).isEmpty()) {
report += " in file ";
report += QString(context.file);
report += " line ";
report += QString::number(context.line);
}
if (context.function && !QString(context.function).isEmpty()) {
report += +" function ";
report += QString(context.function);
}
const char* const local = report.toLocal8Bit().constData();
switch (type) {
case QtDebugMsg:
__android_log_write(ANDROID_LOG_DEBUG, applicationName, local);
break;
case QtInfoMsg:
__android_log_write(ANDROID_LOG_INFO, applicationName, local);
break;
case QtWarningMsg:
__android_log_write(ANDROID_LOG_WARN, applicationName, local);
break;
case QtCriticalMsg:
__android_log_write(ANDROID_LOG_ERROR, applicationName, local);
break;
case QtFatalMsg:
default:
__android_log_write(ANDROID_LOG_FATAL, applicationName, local);
abort();
}
}
#endif
#endif // MESSAGEHANDLER_H

View File

@ -10,9 +10,10 @@
#include <QPushButton>
#include <QSpinBox>
#include <QTableView>
#include "model/metadata.h"
ItemDetailMapper::ItemDetailMapper(QWidget* parent)
#include "../widgethelper.h"
ItemDetailMapper::ItemDetailMapper(QTableView* tableView, QWidget* parent)
: QWidget{parent} {
/// model mapping
m_mapper = std::make_unique<QDataWidgetMapper>(this);
@ -25,76 +26,16 @@ ItemDetailMapper::ItemDetailMapper(QWidget* parent)
// m_mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
m_mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
/// model mapping buttons
m_nextButton = new QPushButton(tr("Ne&xt"));
m_previousButton = new QPushButton(tr("&Previous"));
connect(m_previousButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toPrevious);
connect(m_nextButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toNext);
/// the individual widgets
// REFACTOR deduce label names and types from meta data & use a factory
m_nameLabel = new QLabel("&Name");
m_nameEdit = new QLineEdit();
m_nameLabel->setBuddy(m_nameEdit);
m_descriptionLabel = new QLabel("&Description");
m_descriptionEdit = new QLineEdit();
m_descriptionLabel->setBuddy(m_descriptionEdit);
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);
layout->addWidget(m_previousButton, 5, 0, 1, 1);
layout->addWidget(m_nextButton, 5, 1, 1, 1);
setLayout(layout);
}
void ItemDetailMapper::setModelMappings(QTableView* tableView) {
qDebug() << "Setting model...";
m_tableView = tableView;
m_model = tableView->model();
m_selectionModel = tableView->selectionModel();
m_mapper->setModel(m_model);
m_mapper->addMapping(m_nameEdit, 0);
m_mapper->addMapping(m_descriptionEdit, 1);
m_mapper->addMapping(m_infoEdit, 2);
m_mapper->addMapping(m_amountBox, 3);
m_mapper->addMapping(m_factorBox, 4);
m_mapper->setCurrentIndex(m_selectionModel->currentIndex().row());
setupWidgets();
connect(m_model, &QAbstractItemModel::rowsInserted, this, &ItemDetailMapper::rowsInserted);
connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ItemDetailMapper::rowsRemoved);
connect(m_selectionModel, &QItemSelectionModel::currentChanged, this,
&ItemDetailMapper::onCurrentIndexChanged);
updateButtons(m_selectionModel->currentIndex().row());
setupConnections();
}
bool ItemDetailMapper::submit() { return m_mapper->submit(); }
@ -117,13 +58,7 @@ void ItemDetailMapper::rowsInserted(const QModelIndex& parent, int start, int en
void ItemDetailMapper::rowsRemoved(const QModelIndex& parent, int start, int end) {
if (m_model->rowCount() == 0) {
setEnabled(false);
m_nameEdit->clear();
m_descriptionEdit->clear();
m_infoEdit->clear();
m_amountBox->clear();
m_factorBox->clear();
clearControlWidgets();
}
updateButtons(m_mapper->currentIndex());
@ -158,3 +93,99 @@ void ItemDetailMapper::emitContentChanged(const QModelIndex& currentIndex) {
}
emit contentChanged(toStringText);
}
void ItemDetailMapper::setupConnections() {
m_mapper->setCurrentIndex(m_selectionModel->currentIndex().row());
connect(m_model, &QAbstractItemModel::rowsInserted, this, &ItemDetailMapper::rowsInserted);
connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ItemDetailMapper::rowsRemoved);
connect(m_selectionModel, &QItemSelectionModel::currentChanged, this,
&ItemDetailMapper::onCurrentIndexChanged);
updateButtons(m_selectionModel->currentIndex().row());
}
void ItemDetailMapper::setupNavigationButtons() {
m_nextButton = new QPushButton(tr("Ne&xt"));
m_previousButton = new QPushButton(tr("&Previous"));
connect(m_previousButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toPrevious);
connect(m_nextButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toNext);
const int nRows = m_layout->rowCount();
m_layout->addWidget(m_previousButton, nRows, 0);
m_layout->addWidget(m_nextButton, nRows, 1);
}
void ItemDetailMapper::setupWidgets() {
m_layout = new QGridLayout();
for (int i = 0; i < USER_FACING_ROLES.size(); ++i) {
setupWidgetPairForColumn(i);
}
setupNavigationButtons();
setLayout(m_layout);
}
void ItemDetailMapper::setupWidgetPairForColumn(const int column) {
// REFACTOR consolidate ItemDetailMapper::setupWidgetPairForColumn(...)
// with NewItemDialog::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);
if (TYPE_ROLES.contains(role)) {
m_mapper->addMapping(control, column, "currentText");
} else {
m_mapper->addMapping(control, column);
}
}
void ItemDetailMapper::clearControlWidgets() {
setEnabled(false);
for (int i = 0; i < m_controlWidgets.size(); ++i) {
const UserRoles role = GET_ROLE_FOR_COLUMN(i);
if (STRING_ROLES.contains(role)) {
clearLineEdit(i);
} else if (TYPE_ROLES.contains(role)) {
clearComboBox(i);
} else if (INT_ROLES.contains(role)) {
clearSpinBox(i);
} else if (DOUBLE_ROLES.contains(role)) {
clearSpinBox(i);
} else {
qCritical() << "Could not reset content for control widget in column:" << i << "!";
}
}
}
void ItemDetailMapper::clearLineEdit(const int column) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(m_controlWidgets[column]);
if (lineEdit) {
lineEdit->clear();
}
}
void ItemDetailMapper::clearComboBox(const int column) {
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[column]);
if (comboBox) {
comboBox->setCurrentText("");
}
}
void ItemDetailMapper::clearSpinBox(const int column) {
QAbstractSpinBox* spinBox = dynamic_cast<QAbstractSpinBox*>(m_controlWidgets[column]);
if (spinBox) {
spinBox->clear();
}
}

View File

@ -1,9 +1,13 @@
#ifndef ITEMDETAILMAPPER_H
#define ITEMDETAILMAPPER_H
#include <QComboBox>
#include <QDataWidgetMapper>
#include <QStringListModel>
#include <QWidget>
#include "model/metadata.h"
class QGridLayout;
class QLabel;
class QLineEdit;
class QDoubleSpinBox;
@ -16,9 +20,7 @@ class QTableView;
class ItemDetailMapper : public QWidget {
Q_OBJECT
public:
explicit ItemDetailMapper(QWidget* parent = nullptr);
void setModelMappings(QTableView* tableView);
explicit ItemDetailMapper(QTableView* tableView, QWidget* parent = nullptr);
bool submit();
void revert();
@ -45,23 +47,22 @@ class ItemDetailMapper : public QWidget {
std::unique_ptr<QDataWidgetMapper> m_mapper;
/// GUI elements
QLabel* m_nameLabel = nullptr;
QLineEdit* m_nameEdit = nullptr;
QLabel* m_descriptionLabel = nullptr;
QLineEdit* m_descriptionEdit = nullptr;
QLabel* m_infoLabel = nullptr;
QLineEdit* m_infoEdit = nullptr;
QLabel* m_amountLabel = nullptr;
QSpinBox* m_amountBox = nullptr;
QLabel* m_factorLabel = nullptr;
QDoubleSpinBox* m_factorBox = nullptr;
QGridLayout* m_layout;
QList<QWidget*> m_controlWidgets;
QPushButton* m_nextButton;
QPushButton* m_previousButton;
void setupConnections();
void setupNavigationButtons();
void setupWidgets();
void setupWidgetPairForColumn(const int column);
void clearControlWidgets();
void clearLineEdit(const int column);
void clearComboBox(const int column);
void clearSpinBox(const int column);
};
#endif // ITEMDETAILMAPPER_H

66
widgethelper.cpp Normal file
View File

@ -0,0 +1,66 @@
#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 = createLineEdit(role, parent);
} else if (TYPE_ROLES.contains(role)) {
control = createComboBox(role, parent);
} else if (NUMBER_ROLES.contains(role)) {
control = createSpinBox(role, parent);
} else {
qCritical() << QString("Unsupported role %1!!!").arg(role);
qDebug() << "Using line edit as well and pretend it's a string role...";
control = createLineEdit(role, parent);
}
return control;
}
WidgetHelper::WidgetHelper() {}
QWidget* WidgetHelper::createLineEdit(const UserRoles role, QWidget* /*parent*/) {
QLineEdit* lineEdit = new QLineEdit();
if (READ_ONLY_ROLES.contains(role)) {
lineEdit->setReadOnly(true);
}
return lineEdit;
}
QWidget* WidgetHelper::createSpinBox(const UserRoles role, QWidget* /*parent*/) {
QAbstractSpinBox* abstractSpinBox;
if (DOUBLE_ROLES.contains(role)) {
QDoubleSpinBox* spinBox = new QDoubleSpinBox();
spinBox->setMaximum(1000);
abstractSpinBox = spinBox;
} else {
QSpinBox* spinBox = new QSpinBox();
spinBox->setMaximum(1000);
abstractSpinBox = spinBox;
}
if (READ_ONLY_ROLES.contains(role)) {
abstractSpinBox->setReadOnly(true);
}
return abstractSpinBox;
}
QWidget* WidgetHelper::createComboBox(const UserRoles role, QWidget* parent) {
// TODO add support for read only type roles?
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;
}

20
widgethelper.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef WIDGETHELPER_H
#define WIDGETHELPER_H
#include "model/metadata.h"
class QWidget;
class WidgetHelper {
public:
static QWidget* createControlWidget(const UserRoles role, QWidget* parent);
private:
explicit WidgetHelper();
static QWidget* createLineEdit(const UserRoles role, QWidget* parent);
static QWidget* createSpinBox(const UserRoles role, QWidget* parent);
static QWidget* createComboBox(const UserRoles role, QWidget* parent);
};
#endif // WIDGETHELPER_H

View File

@ -0,0 +1,69 @@
#include "spinboxdelegate.h"
#include <QSpinBox>
#include "model/metadata.h"
SpinboxDelegate::SpinboxDelegate(QObject* parent)
: QStyledItemDelegate(parent) {}
void SpinboxDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const {
QStyledItemDelegate::paint(painter, option, index);
}
QSize SpinboxDelegate::sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const {
return QStyledItemDelegate::sizeHint(option, index);
}
QWidget* SpinboxDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem& /*option*/,
const QModelIndex& index) const {
const QAbstractItemModel* localModel = index.model();
QString headerText = localModel->headerData(index.column(), Qt::Horizontal).toString();
const UserRoles role = GET_ROLE_FOR_COLUMN(index.column());
const bool isInt = INT_ROLES.contains(role);
if (isInt) {
QSpinBox* editor = new QSpinBox(parent);
editor->setMinimum(0);
editor->setMaximum(23000);
return editor;
} else {
QDoubleSpinBox* editor = new QDoubleSpinBox(parent);
editor->setMinimum(0);
editor->setMaximum(23000);
return editor;
}
// return QStyledItemDelegate::createEditor(parent, option, index);
}
void SpinboxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
// Get the value via index of the Model
const QAbstractItemModel* localModel = index.model();
QString headerText = localModel->headerData(index.column(), Qt::Horizontal).toString();
const UserRoles role = GET_ROLE_FOR_COLUMN(index.column());
const bool isInt = INT_ROLES.contains(role);
if (isInt) {
int value = index.model()->data(index, Qt::EditRole).toInt();
// Put the value into the SpinBox
QSpinBox* spinbox = static_cast<QSpinBox*>(editor);
spinbox->setValue(value);
} else {
// Put the value into the SpinBox
qreal value = index.model()->data(index, Qt::EditRole).toReal();
QDoubleSpinBox* spinbox = static_cast<QDoubleSpinBox*>(editor);
spinbox->setValue(value);
}
// QStyledItemDelegate::setEditorData(editor, index);
}
void SpinboxDelegate::setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const {
QStyledItemDelegate::setModelData(editor, model, index);
}

View File

@ -0,0 +1,27 @@
#ifndef SPINBOXDELEGATE_H
#define SPINBOXDELEGATE_H
#include <QStyledItemDelegate>
class SpinboxDelegate : public QStyledItemDelegate {
// TODO move source code files into subfolder "widgets/delegate"
Q_OBJECT
public:
explicit SpinboxDelegate(QObject* parent = nullptr);
/// QAbstractItemDelegate interface
public:
void paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QWidget* createEditor(QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
void setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const override;
};
#endif // SPINBOXDELEGATE_H