From 0c3d711513605fa592e4d89e68c502d529e3c14d Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Mon, 29 Dec 2025 10:30:12 +0100 Subject: [PATCH 1/5] Moved the model meta data for roles and columns into "model/metadata.h" to gather meta data like this in one central place. --- CMakeLists.txt | 1 + formats/jsonparser.cpp | 17 ++++------- model/commands/edititemcommand.cpp | 17 ++++++----- model/commands/edititemcommand.h | 3 ++ model/commands/removerowscommand.cpp | 11 +++---- model/metadata.h | 41 ++++++++++++++++++++++++++ model/modelitem.cpp | 17 ++++------- model/tablemodel.cpp | 44 ++++------------------------ model/tablemodel.h | 4 --- 9 files changed, 78 insertions(+), 77 deletions(-) create mode 100644 model/metadata.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ec6dc0a..6f599c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(${TARGET_APP} STATIC model/commands/removerowscommand.h model/commands/removerowscommand.cpp model/commands/edititemcommand.h model/commands/edititemcommand.cpp data/filehandler.h data/filehandler.cpp + model/metadata.h ) include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/formats/jsonparser.cpp b/formats/jsonparser.cpp index 10ba77a..01bab27 100644 --- a/formats/jsonparser.cpp +++ b/formats/jsonparser.cpp @@ -3,7 +3,7 @@ #include #include -#include "../model/tablemodel.h" +#include "../model/metadata.h" QList> JsonParser::toItemValuesList(const QByteArray& jsonData, const QString& objectName) { @@ -27,16 +27,11 @@ QHash JsonParser::jsonObjectToItemValues(const QJsonObject& itemJ QHash values; // TODO make this more generic (by reading from model meta data) - values[TableModel::NameRole] = - itemJsonObject[TableModel::ROLE_NAMES.value(TableModel::NameRole)].toString(); - values[TableModel::DescriptionRole] = - itemJsonObject[TableModel::ROLE_NAMES.value(TableModel::DescriptionRole)].toString(); - values[TableModel::InfoRole] = - itemJsonObject[TableModel::ROLE_NAMES.value(TableModel::InfoRole)].toString(); - values[TableModel::AmountRole] = - itemJsonObject[TableModel::ROLE_NAMES.value(TableModel::AmountRole)].toInt(); - values[TableModel::FactorRole] = - itemJsonObject[TableModel::ROLE_NAMES.value(TableModel::FactorRole)].toDouble(); + values[NameRole] = itemJsonObject[ROLE_NAMES.value(NameRole)].toString(); + values[DescriptionRole] = itemJsonObject[ROLE_NAMES.value(DescriptionRole)].toString(); + values[InfoRole] = itemJsonObject[ROLE_NAMES.value(InfoRole)].toString(); + values[AmountRole] = itemJsonObject[ROLE_NAMES.value(AmountRole)].toInt(); + values[FactorRole] = itemJsonObject[ROLE_NAMES.value(FactorRole)].toDouble(); return values; } diff --git a/model/commands/edititemcommand.cpp b/model/commands/edititemcommand.cpp index 4c57bc1..1e86550 100644 --- a/model/commands/edititemcommand.cpp +++ b/model/commands/edititemcommand.cpp @@ -2,6 +2,7 @@ #include +#include "../metadata.h" #include "../tablemodel.h" EditItemCommand::EditItemCommand(TableModel* model, @@ -20,23 +21,23 @@ EditItemCommand::EditItemCommand(TableModel* model, const QVariant value = changedValues.first(); QString roleName = model->roleNames().value(role); switch (role) { - case TableModel::NameRole: - case TableModel::DescriptionRole: - case TableModel::InfoRole: - case TableModel::AmountRole: - case TableModel::FactorRole: + case NameRole: + case DescriptionRole: + case InfoRole: + case AmountRole: + case FactorRole: commandText = QString("Setting '%1' of item '%2' to '%3'") .arg(roleName) - .arg(index.data(TableModel::NameRole).toString()) + .arg(index.data(NameRole).toString()) .arg(value.toString()); break; default: - commandText = QString("Edit item '%1'").arg(index.data(TableModel::NameRole).toString()); + commandText = QString("Edit item '%1'").arg(index.data(NameRole).toString()); break; } } else { qDebug() << "More than one value to change. Using a generic command text..."; - commandText = QString("Edit item '%1'").arg(index.data(TableModel::NameRole).toString()); + commandText = QString("Edit item '%1'").arg(index.data(NameRole).toString()); } setText(commandText); diff --git a/model/commands/edititemcommand.h b/model/commands/edititemcommand.h index a8a2c23..f0ea909 100644 --- a/model/commands/edititemcommand.h +++ b/model/commands/edititemcommand.h @@ -8,6 +8,9 @@ class TableModel; class EditItemCommand : public QUndoCommand { public: + // TODO don't use simple pointer to model + /// Using simple pointer to model because there was a crash when closing the application with an + /// unclean undo stack EditItemCommand(TableModel* model, const QModelIndex& index, QMap& changedValues, diff --git a/model/commands/removerowscommand.cpp b/model/commands/removerowscommand.cpp index 306c9aa..41351af 100644 --- a/model/commands/removerowscommand.cpp +++ b/model/commands/removerowscommand.cpp @@ -2,6 +2,7 @@ #include +#include "../metadata.h" #include "../tablemodel.h" RemoveRowsCommand::RemoveRowsCommand(TableModel* model, @@ -22,11 +23,11 @@ RemoveRowsCommand::RemoveRowsCommand(TableModel* model, // TODO use a (static) function "getRoleValueHash" or something QHash values; - values[TableModel::NameRole] = m_tableModel->data(index, TableModel::NameRole); - values[TableModel::DescriptionRole] = m_tableModel->data(index, TableModel::DescriptionRole); - values[TableModel::InfoRole] = m_tableModel->data(index, TableModel::InfoRole); - values[TableModel::AmountRole] = m_tableModel->data(index, TableModel::AmountRole); - values[TableModel::FactorRole] = m_tableModel->data(index, TableModel::FactorRole); + values[NameRole] = m_tableModel->data(index, NameRole); + values[DescriptionRole] = m_tableModel->data(index, DescriptionRole); + values[InfoRole] = m_tableModel->data(index, InfoRole); + values[AmountRole] = m_tableModel->data(index, AmountRole); + values[FactorRole] = m_tableModel->data(index, FactorRole); m_valueList.append(values); } diff --git a/model/metadata.h b/model/metadata.h new file mode 100644 index 0000000..76966e9 --- /dev/null +++ b/model/metadata.h @@ -0,0 +1,41 @@ +#ifndef METADATA_H +#define METADATA_H + +#include +#include +#include +#include + +enum UserRoles { NameRole = Qt::UserRole + 1, DescriptionRole, InfoRole, AmountRole, FactorRole }; +static QHash ROLE_NAMES = {{NameRole, "Name"}, + {DescriptionRole, "Description"}, + {InfoRole, "Info"}, + {AmountRole, "Amount"}, + {FactorRole, "Factor"}}; +static QList intColumns = {"Amount", "Factor"}; + +static int getRoleForColumn(const int column) { + switch (column) { + case 0: + return NameRole; + break; + case 1: + return DescriptionRole; + break; + case 2: + return InfoRole; + break; + case 3: + return AmountRole; + break; + case 4: + return FactorRole; + break; + default: + qWarning() << QString("No role found for column %1! Returning 'NameRole'...").arg(column); + return NameRole; + break; + } +} + +#endif // METADATA_H diff --git a/model/modelitem.cpp b/model/modelitem.cpp index 5df55b6..94fccbd 100644 --- a/model/modelitem.cpp +++ b/model/modelitem.cpp @@ -1,6 +1,6 @@ #include "modelitem.h" -#include "tablemodel.h" +#include "metadata.h" #include #include @@ -48,16 +48,11 @@ QJsonObject ModelItem::toJsonObject() const { QJsonObject itemObject; // itemObject.insert("uuid", m_uuid.toString()); // itemObject.insert("entryDateUTC", m_entryDateUTC.toString(Qt::ISODate)); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::NameRole), - data(TableModel::NameRole).toString()); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::DescriptionRole), - data(TableModel::DescriptionRole).toString()); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::InfoRole), - data(TableModel::InfoRole).toString()); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::AmountRole), - data(TableModel::AmountRole).toInt()); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::FactorRole), - data(TableModel::FactorRole).toReal()); + itemObject.insert(ROLE_NAMES.value(NameRole), data(NameRole).toString()); + itemObject.insert(ROLE_NAMES.value(DescriptionRole), data(DescriptionRole).toString()); + itemObject.insert(ROLE_NAMES.value(InfoRole), data(InfoRole).toString()); + itemObject.insert(ROLE_NAMES.value(AmountRole), data(AmountRole).toInt()); + itemObject.insert(ROLE_NAMES.value(FactorRole), data(FactorRole).toReal()); // if (m_modifiedDateUTC.isValid()) { // itemObject.insert("modifiedDateUTC", m_modifiedDateUTC.toString(Qt::ISODate)); diff --git a/model/tablemodel.cpp b/model/tablemodel.cpp index ce706fa..057f622 100644 --- a/model/tablemodel.cpp +++ b/model/tablemodel.cpp @@ -4,19 +4,13 @@ #include "commands/edititemcommand.h" #include "commands/insertrowscommand.h" #include "commands/removerowscommand.h" +#include "metadata.h" #include "modelitem.h" #include #include #include -QHash TableModel::ROLE_NAMES = {{NameRole, "Name"}, - {DescriptionRole, "Description"}, - {InfoRole, "Info"}, - {AmountRole, "Amount"}, - {FactorRole, "Factor"}}; -QList TableModel::intColumns = {"Amount", "Factor"}; - QByteArray TableModel::generateExampleItems() { QJsonDocument doc = QJsonDocument(); QJsonObject rootObject; @@ -26,14 +20,11 @@ QByteArray TableModel::generateExampleItems() { QJsonObject itemObject; // itemObject.insert("uuid", m_uuid.toString()); // itemObject.insert("entryDateUTC", m_entryDateUTC.toString(Qt::ISODate)); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::NameRole), - QString("Item %1").arg(row)); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::DescriptionRole), - QString("This is item %1").arg(row)); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::InfoRole), - QString("Info of item %1").arg(row)); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::AmountRole), row); - itemObject.insert(TableModel::ROLE_NAMES.value(TableModel::FactorRole), row * 1.1); + itemObject.insert(ROLE_NAMES.value(NameRole), QString("Item %1").arg(row)); + itemObject.insert(ROLE_NAMES.value(DescriptionRole), QString("This is item %1").arg(row)); + itemObject.insert(ROLE_NAMES.value(InfoRole), QString("Info of item %1").arg(row)); + itemObject.insert(ROLE_NAMES.value(AmountRole), row); + itemObject.insert(ROLE_NAMES.value(FactorRole), row * 1.1); array.append(itemObject); } @@ -219,29 +210,6 @@ void TableModel::execEditItemData(const int row, const QMap& chan } } -int TableModel::getRoleForColumn(const int column) const { - switch (column) { - case 0: - return NameRole; - break; - case 1: - return DescriptionRole; - break; - case 2: - return InfoRole; - break; - case 3: - return AmountRole; - break; - case 4: - return FactorRole; - break; - default: - return NameRole; - break; - } -} - QMap TableModel::onlyChangedValues(const QModelIndex& index, const QMap& roleValueMap) const { QMap result; diff --git a/model/tablemodel.h b/model/tablemodel.h index 2bb758a..ea21a21 100644 --- a/model/tablemodel.h +++ b/model/tablemodel.h @@ -16,9 +16,6 @@ class TableModel : public QAbstractTableModel { friend class EditItemCommand; public: - enum UserRoles { NameRole = Qt::UserRole + 1, DescriptionRole, InfoRole, AmountRole, FactorRole }; - static QHash ROLE_NAMES; - static QList intColumns; static QByteArray generateExampleItems(); explicit TableModel(QUndoStack* undoStack, QObject* parent = nullptr); @@ -59,7 +56,6 @@ class TableModel : public QAbstractTableModel { void execEditItemData(const int row, const QMap& changedValues); /// misc functions - int getRoleForColumn(const int column) const; QMap onlyChangedValues(const QModelIndex& index, const QMap& roleValueMap) const; bool isEmptyValueEqualToZero(const int role) const; From 3610aa3841b02d91bc93fa45a95788180b3df33c Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Mon, 29 Dec 2025 10:35:00 +0100 Subject: [PATCH 2/5] Using "model/metadata.h" for file and JSON object naming as well. Using all upper case for naming static meta data constants and functions. --- formats/jsonparser.cpp | 3 ++- genericcore.cpp | 5 +++-- model/metadata.h | 14 ++++++++++++-- model/tablemodel.cpp | 14 +++++++------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/formats/jsonparser.cpp b/formats/jsonparser.cpp index 01bab27..9de0ea1 100644 --- a/formats/jsonparser.cpp +++ b/formats/jsonparser.cpp @@ -26,7 +26,8 @@ QList> JsonParser::toItemValuesList(const QByteArray& jsonD QHash JsonParser::jsonObjectToItemValues(const QJsonObject& itemJsonObject) { QHash values; - // TODO make this more generic (by reading from model meta data) + // TODO iterate over "public & editable" roles (the ones that should occur in JSON file) + // & use a (static) function to retrieve it (i. e. getRoleValue(int role)) values[NameRole] = itemJsonObject[ROLE_NAMES.value(NameRole)].toString(); values[DescriptionRole] = itemJsonObject[ROLE_NAMES.value(DescriptionRole)].toString(); values[InfoRole] = itemJsonObject[ROLE_NAMES.value(InfoRole)].toString(); diff --git a/genericcore.cpp b/genericcore.cpp index 3893b9c..86459f5 100644 --- a/genericcore.cpp +++ b/genericcore.cpp @@ -12,6 +12,7 @@ #include "CoreConfig.h" #include "constants.h" #include "data/filehandler.h" +#include "model/metadata.h" #include "model/tablemodel.h" #include @@ -98,7 +99,7 @@ void GenericCore::saveItems() { qDebug() << "saving items..."; const QJsonDocument doc = m_mainModel->getAllItemsAsJsonDoc(); - const bool successfulSave = FileHandler::saveToFile(doc, "items.json"); + const bool successfulSave = FileHandler::saveToFile(doc, ITEM_FILE_NAME); if (successfulSave) { // QStringList completedTaskStrings = m_model->completedTasks(); // appendCompletedTasksToFile(completedTaskStrings, "completed.txt"); @@ -122,7 +123,7 @@ void GenericCore::setupModels() { */ void GenericCore::initModelData() { qInfo() << "Trying to read model data from file..."; - const QByteArray jsonDoc = FileHandler::loadJSONDataFromFile("items.json"); + const QByteArray jsonDoc = FileHandler::loadJSONDataFromFile(ITEM_FILE_NAME); // qDebug() << "jsonDoc:" << jsonDoc; // TODO decide on lack of file(s) (config, data) if example items should be generated // (see welcome wizard) diff --git a/model/metadata.h b/model/metadata.h index 76966e9..1c1342a 100644 --- a/model/metadata.h +++ b/model/metadata.h @@ -6,15 +6,25 @@ #include #include +/// model data enum UserRoles { NameRole = Qt::UserRole + 1, DescriptionRole, InfoRole, AmountRole, FactorRole }; static QHash ROLE_NAMES = {{NameRole, "Name"}, {DescriptionRole, "Description"}, {InfoRole, "Info"}, {AmountRole, "Amount"}, {FactorRole, "Factor"}}; -static QList intColumns = {"Amount", "Factor"}; +// TODO ? use a data structure containing the type information of each column +// ([QString, QString, QString, int, double], {{NameRole, QString},...}) +// instead of INT_COLUMNS,... +static QList INT_COLUMNS = {"Amount", "Factor"}; -static int getRoleForColumn(const int column) { +/// JSON keys +static const QString ITEM_KEY_STRING = "items"; + +/// file naming +static const QString ITEM_FILE_NAME = ITEM_KEY_STRING + ".json"; + +static int GET_ROLE_FOR_COLUMN(const int column) { switch (column) { case 0: return NameRole; diff --git a/model/tablemodel.cpp b/model/tablemodel.cpp index 057f622..9885a45 100644 --- a/model/tablemodel.cpp +++ b/model/tablemodel.cpp @@ -28,7 +28,7 @@ QByteArray TableModel::generateExampleItems() { array.append(itemObject); } - rootObject.insert("items", array); + rootObject.insert(ITEM_KEY_STRING, array); doc.setObject(rootObject); return doc.toJson(); @@ -65,7 +65,7 @@ QVariant TableModel::data(const QModelIndex& index, int role) const { return QVariant(); } - int roleForColumn = getRoleForColumn(column); + int roleForColumn = GET_ROLE_FOR_COLUMN(column); switch (role) { case Qt::DisplayRole: case Qt::EditRole: @@ -84,7 +84,7 @@ QVariant TableModel::data(const QModelIndex& index, int role) const { QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { - const int columnRole = getRoleForColumn(section); + const int columnRole = GET_ROLE_FOR_COLUMN(section); const QString headerName = ROLE_NAMES.value(columnRole); return QString("%1").arg(headerName); } else { @@ -97,7 +97,7 @@ QVariant TableModel::headerData(int section, Qt::Orientation orientation, int ro bool TableModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (role == Qt::EditRole && checkIndex(index)) { const int column = index.column(); - const int roleForColumn = getRoleForColumn(column); + const int roleForColumn = GET_ROLE_FOR_COLUMN(column); return setItemData(index, {{roleForColumn, value}}); } return false; @@ -129,7 +129,7 @@ QJsonDocument TableModel::getAllItemsAsJsonDoc() const { QJsonObject itemObject = item->toJsonObject(); array.append(itemObject); } - rootObject.insert("items", array); + rootObject.insert(ITEM_KEY_STRING, array); doc.setObject(rootObject); return doc; @@ -167,7 +167,7 @@ void TableModel::insertItems(int startPosition, startPosition = m_items.size(); } - QList> valueList = JsonParser::toItemValuesList(jsonDoc, "items"); + QList> valueList = JsonParser::toItemValuesList(jsonDoc, ITEM_KEY_STRING); InsertRowsCommand* insertCommand = new InsertRowsCommand(this, startPosition, valueList); m_undoStack->push(insertCommand); @@ -237,7 +237,7 @@ QMap TableModel::onlyChangedValues(const QModelIndex& index, bool TableModel::isEmptyValueEqualToZero(const int role) const { const QString roleName = ROLE_NAMES.value(role); - if (intColumns.contains(roleName)) { + if (INT_COLUMNS.contains(roleName)) { return true; } return false; From acb8be56023e2008a4bbe92e1f770e63b633d8ff Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Mon, 29 Dec 2025 13:03:09 +0100 Subject: [PATCH 3/5] Refactored JsonParser to not use roles (or their names) directly. --- formats/jsonparser.cpp | 39 +++++++++++++++++++++++++-------------- formats/jsonparser.h | 4 ++++ model/metadata.h | 8 ++++---- model/tablemodel.cpp | 8 +++++--- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/formats/jsonparser.cpp b/formats/jsonparser.cpp index 9de0ea1..1121949 100644 --- a/formats/jsonparser.cpp +++ b/formats/jsonparser.cpp @@ -23,20 +23,6 @@ QList> JsonParser::toItemValuesList(const QByteArray& jsonD return result; } -QHash JsonParser::jsonObjectToItemValues(const QJsonObject& itemJsonObject) { - QHash values; - - // TODO iterate over "public & editable" roles (the ones that should occur in JSON file) - // & use a (static) function to retrieve it (i. e. getRoleValue(int role)) - values[NameRole] = itemJsonObject[ROLE_NAMES.value(NameRole)].toString(); - values[DescriptionRole] = itemJsonObject[ROLE_NAMES.value(DescriptionRole)].toString(); - values[InfoRole] = itemJsonObject[ROLE_NAMES.value(InfoRole)].toString(); - values[AmountRole] = itemJsonObject[ROLE_NAMES.value(AmountRole)].toInt(); - values[FactorRole] = itemJsonObject[ROLE_NAMES.value(FactorRole)].toDouble(); - - return values; -} - JsonParser::JsonParser() {} QJsonArray JsonParser::extractItemArray(const QByteArray& jsonData, const QString& objectName) { @@ -52,3 +38,28 @@ QJsonArray JsonParser::extractItemArray(const QByteArray& jsonData, const QStrin return itemArray; } + +QHash JsonParser::jsonObjectToItemValues(const QJsonObject& itemJsonObject) { + QHash values; + + for (auto iter = ROLE_NAMES.cbegin(), end = ROLE_NAMES.cend(); iter != end; ++iter) { + std::pair keyValuePair = getKeyValuePair(itemJsonObject, iter.key()); + values.insert(keyValuePair.first, keyValuePair.second); + } + return values; +} + +pair JsonParser::getKeyValuePair(const QJsonObject& itemJsonObject, const int role) { + QVariant result; + const QJsonValue jsonValue = itemJsonObject[ROLE_NAMES.value(role)]; + if (STRING_ROLES.contains(role)) { + result = jsonValue.toString(); + } else if (INT_ROLES.contains(role)) { + result = jsonValue.toInt(); + } else if (DOUBLE_ROLES.contains(role)) { + result = jsonValue.toDouble(); + } else { + qCritical() << QString("Cant find data type of role %1!!!").arg(role); + } + return pair(role, result.toString()); +} diff --git a/formats/jsonparser.h b/formats/jsonparser.h index 36f557b..8feb08d 100644 --- a/formats/jsonparser.h +++ b/formats/jsonparser.h @@ -8,6 +8,8 @@ class QString; class QByteArray; class QJsonArray; +using namespace std; + class JsonParser { public: static QList> toItemValuesList(const QByteArray& jsonData, @@ -18,6 +20,8 @@ class JsonParser { static QJsonArray extractItemArray(const QByteArray& jsonData, const QString& objectName); static QHash jsonObjectToItemValues(const QJsonObject& itemJsonObject); + + static pair getKeyValuePair(const QJsonObject& itemJsonObject, const int role); }; #endif // JSONPARSER_H diff --git a/model/metadata.h b/model/metadata.h index 1c1342a..aac7c71 100644 --- a/model/metadata.h +++ b/model/metadata.h @@ -13,10 +13,9 @@ static QHash ROLE_NAMES = {{NameRole, "Name"}, {InfoRole, "Info"}, {AmountRole, "Amount"}, {FactorRole, "Factor"}}; -// TODO ? use a data structure containing the type information of each column -// ([QString, QString, QString, int, double], {{NameRole, QString},...}) -// instead of INT_COLUMNS,... -static QList INT_COLUMNS = {"Amount", "Factor"}; +static QList STRING_ROLES = {NameRole, DescriptionRole, InfoRole}; +static QList INT_ROLES = {AmountRole}; +static QList DOUBLE_ROLES = {FactorRole}; /// JSON keys static const QString ITEM_KEY_STRING = "items"; @@ -24,6 +23,7 @@ static const QString ITEM_KEY_STRING = "items"; /// file naming static const QString ITEM_FILE_NAME = ITEM_KEY_STRING + ".json"; +/// functions static int GET_ROLE_FOR_COLUMN(const int column) { switch (column) { case 0: diff --git a/model/tablemodel.cpp b/model/tablemodel.cpp index 9885a45..0071eb5 100644 --- a/model/tablemodel.cpp +++ b/model/tablemodel.cpp @@ -236,9 +236,11 @@ QMap TableModel::onlyChangedValues(const QModelIndex& index, } bool TableModel::isEmptyValueEqualToZero(const int role) const { - const QString roleName = ROLE_NAMES.value(role); - if (INT_COLUMNS.contains(roleName)) { + if (INT_ROLES.contains(role)) { return true; + } else if (DOUBLE_ROLES.contains(role)) { + return true; + } else { + return false; } - return false; } From b8fe4e65024baef929c54f5385caed6548f90dd4 Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Wed, 31 Dec 2025 10:39:32 +0100 Subject: [PATCH 4/5] Iterating over USER_FACING_ROLES to get all the item values when parsing and keeping them in edit and remove commands. Instead of using each role explicitly. --- formats/jsonparser.cpp | 39 ++++++++++++++++++++++++++-- formats/jsonparser.h | 2 ++ model/commands/edititemcommand.cpp | 25 +++++++----------- model/commands/removerowscommand.cpp | 9 +------ model/metadata.h | 19 ++++++++------ model/modelitem.cpp | 29 +++++++++++---------- model/tablemodel.cpp | 11 ++++++++ model/tablemodel.h | 1 + 8 files changed, 89 insertions(+), 46 deletions(-) diff --git a/formats/jsonparser.cpp b/formats/jsonparser.cpp index 1121949..e63005b 100644 --- a/formats/jsonparser.cpp +++ b/formats/jsonparser.cpp @@ -23,6 +23,39 @@ QList> JsonParser::toItemValuesList(const QByteArray& jsonD return result; } +QByteArray JsonParser::itemValuesListToJson(const QList>& itemValuesList, + const QString& objectName) { + QJsonDocument jsonDoc; + QJsonObject rootObject; + QJsonArray itemArray; + for (const QHash& itemValues : itemValuesList) { + QJsonObject itemObject; + + QListIterator i(USER_FACING_ROLES); + while (i.hasNext()) { + const UserRoles role = i.next(); + const QString roleName = ROLE_NAMES.value(role); + const QVariant value = itemValues.value(role); + if (STRING_ROLES.contains(role)) { + itemObject.insert(roleName, value.toString()); + } else if (INT_ROLES.contains(role)) { + itemObject.insert(roleName, value.toInt()); + } else if (DOUBLE_ROLES.contains(role)) { + itemObject.insert(roleName, value.toDouble()); + } else { + qCritical() << QString("Can't find data type for role %1!!!").arg(role); + } + } + + itemArray.append(itemObject); + } + + rootObject.insert(objectName, itemArray); + jsonDoc.setObject(rootObject); + + return jsonDoc.toJson(QJsonDocument::Compact); +} + JsonParser::JsonParser() {} QJsonArray JsonParser::extractItemArray(const QByteArray& jsonData, const QString& objectName) { @@ -42,8 +75,10 @@ QJsonArray JsonParser::extractItemArray(const QByteArray& jsonData, const QStrin QHash JsonParser::jsonObjectToItemValues(const QJsonObject& itemJsonObject) { QHash values; - for (auto iter = ROLE_NAMES.cbegin(), end = ROLE_NAMES.cend(); iter != end; ++iter) { - std::pair keyValuePair = getKeyValuePair(itemJsonObject, iter.key()); + QListIterator i(USER_FACING_ROLES); + while (i.hasNext()) { + const UserRoles role = i.next(); + std::pair keyValuePair = getKeyValuePair(itemJsonObject, role); values.insert(keyValuePair.first, keyValuePair.second); } return values; diff --git a/formats/jsonparser.h b/formats/jsonparser.h index 8feb08d..702414d 100644 --- a/formats/jsonparser.h +++ b/formats/jsonparser.h @@ -14,6 +14,8 @@ class JsonParser { public: static QList> toItemValuesList(const QByteArray& jsonData, const QString& objectName = ""); + static QByteArray itemValuesListToJson(const QList>& itemValuesList, + const QString& objectName = ""); private: explicit JsonParser(); diff --git a/model/commands/edititemcommand.cpp b/model/commands/edititemcommand.cpp index 1e86550..449272b 100644 --- a/model/commands/edititemcommand.cpp +++ b/model/commands/edititemcommand.cpp @@ -20,24 +20,19 @@ EditItemCommand::EditItemCommand(TableModel* model, const int role = changedValues.firstKey(); const QVariant value = changedValues.first(); QString roleName = model->roleNames().value(role); - switch (role) { - case NameRole: - case DescriptionRole: - case InfoRole: - case AmountRole: - case FactorRole: - commandText = QString("Setting '%1' of item '%2' to '%3'") - .arg(roleName) - .arg(index.data(NameRole).toString()) - .arg(value.toString()); - break; - default: - commandText = QString("Edit item '%1'").arg(index.data(NameRole).toString()); - break; + + if (USER_FACING_ROLES.contains(role)) { + commandText = QString("Setting '%1' of item '%2' to '%3'") + .arg(roleName) + .arg(index.data(DEFAULT_ROLE).toString()) + .arg(value.toString()); + } else { + qWarning() << "Role didn't match! Using a generic command text..."; + commandText = QString("Edit item '%1'").arg(index.data(DEFAULT_ROLE).toString()); } } else { qDebug() << "More than one value to change. Using a generic command text..."; - commandText = QString("Edit item '%1'").arg(index.data(NameRole).toString()); + commandText = QString("Edit item '%1'").arg(index.data(DEFAULT_ROLE).toString()); } setText(commandText); diff --git a/model/commands/removerowscommand.cpp b/model/commands/removerowscommand.cpp index 41351af..487a916 100644 --- a/model/commands/removerowscommand.cpp +++ b/model/commands/removerowscommand.cpp @@ -2,7 +2,6 @@ #include -#include "../metadata.h" #include "../tablemodel.h" RemoveRowsCommand::RemoveRowsCommand(TableModel* model, @@ -21,13 +20,7 @@ RemoveRowsCommand::RemoveRowsCommand(TableModel* model, const int rowPosition = startRow + row; QModelIndex index = m_tableModel->index(rowPosition, 0); - // TODO use a (static) function "getRoleValueHash" or something - QHash values; - values[NameRole] = m_tableModel->data(index, NameRole); - values[DescriptionRole] = m_tableModel->data(index, DescriptionRole); - values[InfoRole] = m_tableModel->data(index, InfoRole); - values[AmountRole] = m_tableModel->data(index, AmountRole); - values[FactorRole] = m_tableModel->data(index, FactorRole); + QHash values = m_tableModel->getItemValues(index); m_valueList.append(values); } diff --git a/model/metadata.h b/model/metadata.h index aac7c71..580d931 100644 --- a/model/metadata.h +++ b/model/metadata.h @@ -8,14 +8,17 @@ /// model data enum UserRoles { NameRole = Qt::UserRole + 1, DescriptionRole, InfoRole, AmountRole, FactorRole }; -static QHash ROLE_NAMES = {{NameRole, "Name"}, - {DescriptionRole, "Description"}, - {InfoRole, "Info"}, - {AmountRole, "Amount"}, - {FactorRole, "Factor"}}; -static QList STRING_ROLES = {NameRole, DescriptionRole, InfoRole}; -static QList INT_ROLES = {AmountRole}; -static QList DOUBLE_ROLES = {FactorRole}; +static UserRoles DEFAULT_ROLE = NameRole; +static QList USER_FACING_ROLES = {NameRole, DescriptionRole, InfoRole, AmountRole, + FactorRole}; +static QHash ROLE_NAMES = {{NameRole, "Name"}, + {DescriptionRole, "Description"}, + {InfoRole, "Info"}, + {AmountRole, "Amount"}, + {FactorRole, "Factor"}}; +static QList STRING_ROLES = {NameRole, DescriptionRole, InfoRole}; +static QList INT_ROLES = {AmountRole}; +static QList DOUBLE_ROLES = {FactorRole}; /// JSON keys static const QString ITEM_KEY_STRING = "items"; diff --git a/model/modelitem.cpp b/model/modelitem.cpp index 94fccbd..7abf6bf 100644 --- a/model/modelitem.cpp +++ b/model/modelitem.cpp @@ -46,19 +46,22 @@ bool ModelItem::setItemData(const QMap& changedValues) { QJsonObject ModelItem::toJsonObject() const { QJsonObject itemObject; - // itemObject.insert("uuid", m_uuid.toString()); - // itemObject.insert("entryDateUTC", m_entryDateUTC.toString(Qt::ISODate)); - itemObject.insert(ROLE_NAMES.value(NameRole), data(NameRole).toString()); - itemObject.insert(ROLE_NAMES.value(DescriptionRole), data(DescriptionRole).toString()); - itemObject.insert(ROLE_NAMES.value(InfoRole), data(InfoRole).toString()); - itemObject.insert(ROLE_NAMES.value(AmountRole), data(AmountRole).toInt()); - itemObject.insert(ROLE_NAMES.value(FactorRole), data(FactorRole).toReal()); + // TODO add UUID and dates (entry, modification, end) - // if (m_modifiedDateUTC.isValid()) { - // itemObject.insert("modifiedDateUTC", m_modifiedDateUTC.toString(Qt::ISODate)); - // } - // if (m_endDateUTC.isValid()) { - // itemObject.insert("endDateUTC", m_endDateUTC.toString(Qt::ISODate)); - // } + QListIterator i(USER_FACING_ROLES); + while (i.hasNext()) { + const UserRoles role = i.next(); + const QString roleName = ROLE_NAMES.value(role); + const QVariant value = data(role); + if (STRING_ROLES.contains(role)) { + itemObject.insert(roleName, value.toString()); + } else if (INT_ROLES.contains(role)) { + itemObject.insert(roleName, value.toInt()); + } else if (DOUBLE_ROLES.contains(role)) { + itemObject.insert(roleName, value.toDouble()); + } else { + qCritical() << QString("Cant find data type of role %1!!!").arg(role); + } + } return itemObject; } diff --git a/model/tablemodel.cpp b/model/tablemodel.cpp index 0071eb5..2ae6cdf 100644 --- a/model/tablemodel.cpp +++ b/model/tablemodel.cpp @@ -120,6 +120,17 @@ bool TableModel::setItemData(const QModelIndex& index, const QMap return false; } +QHash TableModel::getItemValues(const QModelIndex& index) const { + QHash values; + + QListIterator i(USER_FACING_ROLES); + while (i.hasNext()) { + const UserRoles role = i.next(); + values.insert(role, data(index, role)); + } + return values; +} + QJsonDocument TableModel::getAllItemsAsJsonDoc() const { QJsonDocument doc = QJsonDocument(); QJsonObject rootObject; diff --git a/model/tablemodel.h b/model/tablemodel.h index ea21a21..c7650f2 100644 --- a/model/tablemodel.h +++ b/model/tablemodel.h @@ -32,6 +32,7 @@ class TableModel : public QAbstractTableModel { bool setData(const QModelIndex& index, const QVariant& value, int role) override; bool setItemData(const QModelIndex& index, const QMap& roles) override; + QHash getItemValues(const QModelIndex& index) const; QJsonDocument getAllItemsAsJsonDoc() const; public slots: From 3266c99fc39eef5068a5be5a6ce79bbc62fc67ec Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Thu, 1 Jan 2026 10:26:29 +0100 Subject: [PATCH 5/5] Bugfix: When parsing JSON data to item values all the values were converted to strings. --- formats/jsonparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/formats/jsonparser.cpp b/formats/jsonparser.cpp index e63005b..075f607 100644 --- a/formats/jsonparser.cpp +++ b/formats/jsonparser.cpp @@ -96,5 +96,5 @@ pair JsonParser::getKeyValuePair(const QJsonObject& itemJsonObjec } else { qCritical() << QString("Cant find data type of role %1!!!").arg(role); } - return pair(role, result.toString()); + return pair(role, result); }