From 43ecd2601e21964936491468b9984ffabf83d979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lie=20Delhaie?= Date: Sun, 15 Jan 2023 12:39:03 +0100 Subject: [PATCH] Adding filters --- src/frames/filterdialog.cpp | 68 +++++++++++- src/frames/filterdialog.h | 6 + src/frames/filterdialog.ui | 28 ++--- src/frames/mainwindow.cpp | 214 ++++++++++++++++++++++++++++++++---- src/frames/mainwindow.h | 11 ++ src/models/filter.cpp | 35 +++++- src/models/filter.h | 17 ++- 7 files changed, 333 insertions(+), 46 deletions(-) diff --git a/src/frames/filterdialog.cpp b/src/frames/filterdialog.cpp index 97aa56e..20277e5 100644 --- a/src/frames/filterdialog.cpp +++ b/src/frames/filterdialog.cpp @@ -1,13 +1,66 @@ #include "filterdialog.h" #include "ui_filterdialog.h" +#include + FilterDialog::FilterDialog(QString dialogTitle, QVector boards, QVector status, QVector priorities, QWidget *parent) : QDialog(parent), ui(new Ui::FilterDialog) { ui->setupUi(this); this->setWindowTitle(dialogTitle); + init(boards, status, priorities); +} +FilterDialog::FilterDialog(QString dialogTitle, Filter f, QVector boards, QVector status, QVector priorities, QWidget *parent) : + QDialog(parent), + ui(new Ui::FilterDialog) +{ + ui->setupUi(this); + this->setWindowTitle(dialogTitle); + init(boards, status, priorities); + + ui->nameEdit->setText(f.getName()); + ui->descriptionEdit->setPlainText(f.getDescription()); + ui->dateComparationCombobox->setCurrentIndex(f.getExpectedForComparator()); + foreach (QString uuid, f.getBoards()) + { + for (int i = 0; i < ui->boardListWidget->count(); ++i) + { + QListWidgetItem *item = ui->boardListWidget->item(i); + if (item->data(1).toString() == uuid) + { + item->setCheckState(Qt::Checked); + } + } + } + foreach (QString uuid, f.getStatus()) + { + for (int i = 0; i < ui->statusListWidget->count(); ++i) + { + QListWidgetItem *item = ui->statusListWidget->item(i); + if (item->data(1).toString() == uuid) + { + item->setCheckState(Qt::Checked); + } + } + } + foreach (QString uuid, f.getPriorities()) + { + for (int i = 0; i < ui->priorityListWidget->count(); ++i) + { + QListWidgetItem *item = ui->priorityListWidget->item(i); + if (item->data(1).toString() == uuid) + { + item->setCheckState(Qt::Checked); + } + } + } +} + + +void FilterDialog::init(QVector boards, QVector status, QVector priorities) +{ for (Board *b : boards) { QListWidgetItem *item = new QListWidgetItem(); @@ -37,6 +90,8 @@ FilterDialog::FilterDialog(QString dialogTitle, QVector boards, QVector< item->setData(1, p.getUUID()); ui->priorityListWidget->addItem(item); } + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &FilterDialog::validateAndAccept); } FilterDialog::~FilterDialog() @@ -47,6 +102,7 @@ FilterDialog::~FilterDialog() const Filter FilterDialog::getFilter() { QString name = ui->nameEdit->text(); + QString description = ui->descriptionEdit->toPlainText(); uint8_t dateComparation = 0; if (ui->dateComparationCombobox->currentIndex() > -1) { @@ -76,5 +132,15 @@ const Filter FilterDialog::getFilter() priorities.append(item->data(1).toString()); } } - return Filter(name, dateComparation, boards, status, priorities); + return Filter(name, description, dateComparation, boards, status, priorities); +} + +void FilterDialog::validateAndAccept() +{ + if (ui->nameEdit->text().count() == 0) + { + QMessageBox::critical(this, "This filter needs a name", "You need to enter a name to save this filter"); + return; + } + accept(); } diff --git a/src/frames/filterdialog.h b/src/frames/filterdialog.h index 1aeaf59..6d08f40 100644 --- a/src/frames/filterdialog.h +++ b/src/frames/filterdialog.h @@ -18,11 +18,17 @@ class FilterDialog : public QDialog public: explicit FilterDialog(QString dialogTitle, QVector boards, QVector status, QVector priorities, QWidget *parent = nullptr); + FilterDialog(QString dialogTitle, Filter f, QVector boards, QVector status, QVector priorities, QWidget *parent = nullptr); ~FilterDialog(); const Filter getFilter(); +private slots: + void validateAndAccept(); + private: Ui::FilterDialog *ui; + + void init(QVector boards, QVector status, QVector priorities); }; #endif // FILTERDIALOG_H diff --git a/src/frames/filterdialog.ui b/src/frames/filterdialog.ui index a99baf0..f0b03b2 100644 --- a/src/frames/filterdialog.ui +++ b/src/frames/filterdialog.ui @@ -10,7 +10,7 @@ 0 0 449 - 509 + 656 @@ -32,6 +32,16 @@ + + + + Description + + + + + + @@ -133,22 +143,6 @@ - - buttonBox - accepted() - FilterDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - buttonBox rejected() diff --git a/src/frames/mainwindow.cpp b/src/frames/mainwindow.cpp index ef0eba2..3f575a2 100644 --- a/src/frames/mainwindow.cpp +++ b/src/frames/mainwindow.cpp @@ -4,6 +4,7 @@ #define PRIORITIES_KEY "priorities" #define STATUS_KEY "status" #define BOARDS_KEY "boards" +#define FILTERS_KEY "filters" #include #include @@ -36,10 +37,13 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->actionNew_filter, &QAction::triggered, this, &MainWindow::onNewFilterClick); connect(ui->boardList, &QListWidget::currentRowChanged, this, &MainWindow::onBoardSelected); connect(ui->boardList, &QListWidget::customContextMenuRequested, this, &MainWindow::prepareBoardMenu); + connect(ui->filterListWidget, &QListWidget::currentRowChanged, this, &MainWindow::onFilterSelected); + connect(ui->filterListWidget, &QListWidget::customContextMenuRequested, this, &MainWindow::prepareFilterMenu); connect(ui->taskList, &QTreeWidget::itemDoubleClicked, this, &MainWindow::onEditTask); connect(ui->taskList, &QTreeWidget::customContextMenuRequested, this, &MainWindow::prepareTaskMenu); ui->boardList->setContextMenuPolicy(Qt::CustomContextMenu); ui->taskList->setContextMenuPolicy(Qt::CustomContextMenu); + ui->filterListWidget->setContextMenuPolicy(Qt::CustomContextMenu); } MainWindow::~MainWindow() @@ -93,8 +97,10 @@ void MainWindow::prepareBoardMenu(const QPoint &pos) void MainWindow::prepareTaskMenu(const QPoint &pos) { + bool show = false; QMenu menu(this); if (ui->taskList->selectedItems().length() == 1) { + show = true; QAction *renameAction = new QAction(tr("Edit the task"), this); connect(renameAction, &QAction::triggered, this, &MainWindow::onEditNameTaskMenu); menu.addAction(renameAction); @@ -105,11 +111,18 @@ void MainWindow::prepareTaskMenu(const QPoint &pos) menu.addSeparator(); } - QAction *addAction = new QAction(tr("New task"), this); - connect(addAction, &QAction::triggered, this, &MainWindow::onNewTaskClick); - menu.addAction(addAction); + if (selectedBoardIndex > -1) + { + show = true; + QAction *addAction = new QAction(tr("New task"), this); + connect(addAction, &QAction::triggered, this, &MainWindow::onNewTaskClick); + menu.addAction(addAction); + } - menu.exec(ui->taskList->mapToGlobal(pos)); + if (show) + { + menu.exec(ui->taskList->mapToGlobal(pos)); + } } void MainWindow::onNewBoardClick() @@ -152,14 +165,24 @@ void MainWindow::onNewFilterClick() if (dialog.exec() == QDialog::DialogCode::Accepted) { Filter f = dialog.getFilter(); + filters.append(f); QListWidgetItem *item = new QListWidgetItem(f.getName()); + item->setToolTip(f.getDescription()); ui->filterListWidget->addItem(item); + save(); } } void MainWindow::onBoardSelected(int i) { selectedBoardIndex = i; + selectedFilterIndex = -1; + + ui->filterListWidget->blockSignals(true); + ui->filterListWidget->setCurrentIndex(ui->filterListWidget->currentIndex().sibling(-1, -1)); + ui->filterListWidget->blockSignals(false); + + filterResult.clear(); if (selectedBoardIndex > -1) { Board *b = boards[selectedBoardIndex]; @@ -176,22 +199,46 @@ void MainWindow::onBoardSelected(int i) redrawTaskTree(); } +void MainWindow::onFilterSelected(int i) +{ + selectedFilterIndex = i; + selectedBoardIndex = -1; + + ui->boardList->blockSignals(true); + ui->boardList->setCurrentIndex(ui->boardList->currentIndex().sibling(-1, -1)); + ui->boardList->blockSignals(false); + + filterResult.clear(); + ui->actionNew_task->setDisabled(true); + if (selectedFilterIndex > -1) + { + Filter f = filters[selectedFilterIndex]; + ui->label->setText(f.getName()); + ui->boardDescription->setText(f.getDescription()); + } + else + { + ui->label->setText("No board selected"); + ui->boardDescription->clear(); + } + redrawTaskTree(); +} + void MainWindow::onEditTask(QTreeWidgetItem *item) { - if (item != nullptr && selectedBoardIndex > -1) + Task *t = getSelectedTask(); + if (t != nullptr) { - Board *b = boards[selectedBoardIndex]; - int row = ui->taskList->indexOfTopLevelItem(item); - Task *t = b->taskAt(row); - if (t != nullptr) + TaskDialog dialog(t, status, priorities, this); + if (dialog.exec() == QDialog::DialogCode::Accepted) { - TaskDialog dialog(t, status, priorities, this); - if (dialog.exec() == QDialog::DialogCode::Accepted) + Task editedTask = dialog.getTask(); + t->update(editedTask); + updateTaskRow(item, editedTask); + save(); + if (selectedFilterIndex > -1) { - Task editedTask = dialog.getTask(); - t->update(editedTask); - updateTaskRow(item, editedTask); - save(); + redrawTaskTree(); } } } @@ -229,6 +276,22 @@ void MainWindow::onRemoveTaskMenu() } } +void MainWindow::onRemoveFilterMenu() +{ + if (selectedFilterIndex > -1) + { + QMessageBox::StandardButton result = QMessageBox::question(this, "Delete a filter", "Do you want to delete this filter?"); + if (result == QMessageBox::Yes) + { + filters.removeAt(selectedFilterIndex); + delete ui->filterListWidget->takeItem(selectedFilterIndex); + selectedFilterIndex = -1; + redrawTaskTree(); + save(); + } + } +} + void MainWindow::onEditNameBoardMenu() { if (selectedBoardIndex > -1) @@ -253,12 +316,55 @@ void MainWindow::onEditNameBoardMenu() void MainWindow::onEditNameTaskMenu() { - if (selectedBoardIndex > -1 && ui->taskList->selectedItems().length() == 1) + Task *t = getSelectedTask(); + if (t != nullptr) { onEditTask(ui->taskList->currentItem()); } } +void MainWindow::onEditFilterMenu() +{ + if (selectedFilterIndex > -1) + { + Filter f = filters[selectedFilterIndex]; + FilterDialog dialog("Edit the filter", f, boards, status, priorities, this); + if (dialog.exec() == QDialog::DialogCode::Accepted) + { + Filter f = dialog.getFilter(); + filters[selectedFilterIndex] = f; + QListWidgetItem *item = ui->filterListWidget->item(selectedFilterIndex); + item->setText(f.getName()); + item->setToolTip(f.getDescription()); + ui->label->setText(f.getName()); + ui->boardDescription->setText(f.getDescription()); + redrawTaskTree(); + save(); + } + } +} + +void MainWindow::prepareFilterMenu(const QPoint &pos) +{ + QMenu menu(this); + if (ui->filterListWidget->selectedItems().length() == 1) { + QAction *renameAction = new QAction(tr("Edit the filter"), this); + connect(renameAction, &QAction::triggered, this, &MainWindow::onEditFilterMenu); + menu.addAction(renameAction); + + QAction *deleteAction = new QAction(tr("Delete"), this); + connect(deleteAction, &QAction::triggered, this, &MainWindow::onRemoveFilterMenu); + menu.addAction(deleteAction); + + menu.addSeparator(); + } + QAction *addAction = new QAction(tr("New filter"), this); + connect(addAction, &QAction::triggered, this, &MainWindow::onNewFilterClick); + menu.addAction(addAction); + + menu.exec(ui->filterListWidget->mapToGlobal(pos)); +} + void MainWindow::init() { if (Tools::isSaveFileExist()) @@ -270,15 +376,24 @@ void MainWindow::init() QJsonArray jsonPriorities = save[PRIORITIES_KEY].toArray(); QJsonArray jsonStatus = save[STATUS_KEY].toArray(); QJsonArray jsonBoards = save[BOARDS_KEY].toArray(); - for (QJsonValueRef value : jsonPriorities) { + QJsonArray jsonFilters = save[FILTERS_KEY].toArray(); + for (QJsonValueRef value : jsonPriorities) + { priorities.append(Priority(value.toObject())); } - for (QJsonValueRef value : jsonStatus) { + for (QJsonValueRef value : jsonStatus) + { status.append(Status(value.toObject())); } - for (QJsonValueRef value : jsonBoards) { + for (QJsonValueRef value : jsonBoards) + { boards.append(new Board(value.toObject())); } + for (QJsonValueRef value : jsonFilters) + { + filters.append(Filter(value.toObject())); + } + redrawFilterList(); redrawBoardList(); return; } @@ -381,13 +496,46 @@ const QJsonDocument MainWindow::getJsonSave() foreach (Board *b, this->boards) { jsonBoards.append(b->toJson()); } + QJsonArray jsonFilters; + foreach (Filter f, this->filters) + { + jsonFilters.append(f.toJson()); + } obj[PRIORITIES_KEY] = jsonPriorities; obj[STATUS_KEY] = jsonStatus; obj[BOARDS_KEY] = jsonBoards; + obj[FILTERS_KEY] = jsonFilters; doc.setObject(obj); return doc; } +Task *MainWindow::getSelectedTask() +{ + if (selectedBoardIndex > -1) + { + Board *b = boards[selectedBoardIndex]; + QList items = ui->taskList->selectedItems(); + if (items.count() == 1) + { + int16_t i = ui->taskList->indexOfTopLevelItem(items[0]); + return b->taskAt(i); + } + } + else if (selectedFilterIndex > -1) + { + if (!filterResult.empty()) + { + QList items = ui->taskList->selectedItems(); + if (items.count() == 1) + { + int16_t i = ui->taskList->indexOfTopLevelItem(items[0]); + return filterResult[i]; + } + } + } + return nullptr; +} + void MainWindow::updateTaskRow(QTreeWidgetItem *item, Task t) { item->setText(0, t.getTitle()); @@ -453,6 +601,22 @@ void MainWindow::redrawBoardList() } } +void MainWindow::redrawFilterList() +{ + QListWidget *l = ui->filterListWidget; + uint16_t itemCount = l->count(); + for (int16_t i = itemCount; i >= 0; i--) + { + delete l->takeItem(i); + } + foreach (Filter f, filters) + { + QListWidgetItem *item = new QListWidgetItem(f.getName()); + item->setToolTip(f.getDescription()); + l->addItem(item); + } +} + void MainWindow::redrawTaskTree() { QTreeWidget *l = ui->taskList; @@ -471,7 +635,17 @@ void MainWindow::redrawTaskTree() ui->taskList->addTopLevelItem(item); } } - + else if (selectedFilterIndex > -1) + { + Filter f = filters[selectedFilterIndex]; + filterResult = f.filter(boards); + foreach (Task *t, filterResult) + { + QTreeWidgetItem *item = new QTreeWidgetItem(); + updateTaskRow(item, *t); + ui->taskList->addTopLevelItem(item); + } + } } void MainWindow::save() diff --git a/src/frames/mainwindow.h b/src/frames/mainwindow.h index c48e89d..af2b6d5 100644 --- a/src/frames/mainwindow.h +++ b/src/frames/mainwindow.h @@ -30,11 +30,15 @@ private slots: void onNewTaskClick(); void onNewFilterClick(); void onBoardSelected(int i); + void onFilterSelected(int i); void onEditTask(QTreeWidgetItem*); void onRemoveBoardMenu(); void onRemoveTaskMenu(); + void onRemoveFilterMenu(); void onEditNameBoardMenu(); void onEditNameTaskMenu(); + void onEditFilterMenu(); + void prepareFilterMenu(const QPoint &pos); void prepareBoardMenu(const QPoint &pos); void prepareTaskMenu(const QPoint &pos); @@ -44,6 +48,10 @@ private: void init(); int16_t selectedBoardIndex; + int16_t selectedFilterIndex; + + QVector filterResult; + QVector priorities; QVector status; QVector boards; @@ -61,8 +69,11 @@ private: const QJsonDocument getJsonSave(); + Task *getSelectedTask(); + void updateTaskRow(QTreeWidgetItem *item, Task t); void redrawBoardList(); + void redrawFilterList(); void redrawTaskTree(); void save(); }; diff --git a/src/models/filter.cpp b/src/models/filter.cpp index 6f58df9..d101aec 100644 --- a/src/models/filter.cpp +++ b/src/models/filter.cpp @@ -2,14 +2,16 @@ #include "qjsonarray.h" #define NAME_KEY "name" +#define DESCRIPTION_KEY "description" #define DATE_KEY "date" #define BOARDS_KEY "boards" #define STATUS_KEY "status" #define PRIORITY_KEY "priority" -Filter::Filter(QString name, uint8_t expectedForComparator, QVector boards, QVector status, QVector priorities) +Filter::Filter(QString name, QString description, uint8_t expectedForComparator, QVector boards, QVector status, QVector priorities) { this->name = name; + this->description = description; this->expectedForComparator = expectedForComparator; this->boards = boards; this->status = status; @@ -19,6 +21,7 @@ Filter::Filter(QString name, uint8_t expectedForComparator, QVector boa Filter::Filter(QJsonObject obj) { this->name = obj[NAME_KEY].toString("!Missing name!"); + this->description = obj[DESCRIPTION_KEY].toString(); this->expectedForComparator = obj[DATE_KEY].toInt(); QJsonArray b = obj[BOARDS_KEY].toArray(); QJsonArray s = obj[STATUS_KEY].toArray(); @@ -46,7 +49,7 @@ Filter::Filter(QJsonObject obj) } } -QVector Filter::get(QVector allBoards) +QVector Filter::filter(QVector allBoards) { QDate now = QDate::currentDate(); QVector selectedBoards; @@ -140,10 +143,36 @@ const QString Filter::getName() return name; } +const QString Filter::getDescription() +{ + return description; +} + +uint8_t Filter::getExpectedForComparator() +{ + return expectedForComparator; +} + +const QVector Filter::getBoards() +{ + return boards; +} + +const QVector Filter::getStatus() +{ + return status; +} + +const QVector Filter::getPriorities() +{ + return priorities; +} + const QJsonObject Filter::toJson() { QJsonObject obj; - obj[name] = name; + obj[NAME_KEY] = name; + obj[DESCRIPTION_KEY] = description; obj[DATE_KEY] = expectedForComparator; QJsonArray b; foreach (QString uuid, boards) diff --git a/src/models/filter.h b/src/models/filter.h index c0f0513..a869d83 100644 --- a/src/models/filter.h +++ b/src/models/filter.h @@ -12,23 +12,30 @@ class Filter { private: QString name; + QString description; // 0 none, 1 lower, 2 equal, 3 upper uint8_t expectedForComparator; // if empty => all QVector boards; QVector status; QVector priorities; -public: - Filter(QString name, uint8_t expectedForComparator,QVector boards,QVector status,QVector priorities); - Filter(QJsonObject obj); - - QVector get(QVector); bool filterStatus(Task *t); bool filterPriority(Task *t); bool filterDate(Task *t, QDate now); +public: + Filter(QString name, QString description, uint8_t expectedForComparator,QVector boards,QVector status,QVector priorities); + Filter(QJsonObject obj); + + QVector filter(QVector); + const QString getName(); + const QString getDescription(); + uint8_t getExpectedForComparator(); + const QVector getBoards(); + const QVector getStatus(); + const QVector getPriorities(); const QJsonObject toJson(); };