diff --git a/TaskBoard.pro b/TaskBoard.pro index 0958cf9..af339db 100644 --- a/TaskBoard.pro +++ b/TaskBoard.pro @@ -68,6 +68,7 @@ linux-* { #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + src/frames/filterdialog.cpp \ src/frames/aboutdialog.cpp \ src/models/board.cpp \ src/main.cpp \ @@ -82,6 +83,7 @@ SOURCES += \ src/tools.cpp HEADERS += \ + src/frames/filterdialog.h \ src/frames/aboutdialog.h \ src/models/board.h \ src/frames/mainwindow.h \ @@ -95,6 +97,7 @@ HEADERS += \ src/tools.h FORMS += \ + src/frames/filterdialog.ui \ src/frames/aboutdialog.ui \ src/frames/mainwindow.ui \ src/frames/namedialog.ui \ diff --git a/resources.qrc b/resources.qrc index d479d41..e9b45f4 100644 --- a/resources.qrc +++ b/resources.qrc @@ -1,5 +1,8 @@ resources/logo.png + resources/board_add.png + resources/task_add.png + resources/add_filter.png diff --git a/resources/add_filter.png b/resources/add_filter.png new file mode 100644 index 0000000..67323fd Binary files /dev/null and b/resources/add_filter.png differ diff --git a/resources/board_add.png b/resources/board_add.png new file mode 100644 index 0000000..1d5e3bd Binary files /dev/null and b/resources/board_add.png differ diff --git a/resources/task_add.png b/resources/task_add.png new file mode 100644 index 0000000..3ba8b0f Binary files /dev/null and b/resources/task_add.png differ diff --git a/src/frames/filterdialog.cpp b/src/frames/filterdialog.cpp new file mode 100644 index 0000000..97aa56e --- /dev/null +++ b/src/frames/filterdialog.cpp @@ -0,0 +1,80 @@ +#include "filterdialog.h" +#include "ui_filterdialog.h" + +FilterDialog::FilterDialog(QString dialogTitle, QVector boards, QVector status, QVector priorities, QWidget *parent) : + QDialog(parent), + ui(new Ui::FilterDialog) +{ + ui->setupUi(this); + this->setWindowTitle(dialogTitle); + + for (Board *b : boards) + { + QListWidgetItem *item = new QListWidgetItem(); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Unchecked); + item->setText(b->getName()); + item->setData(1, b->getUuid()); + ui->boardListWidget->addItem(item); + } + + for (Status s : status) + { + QListWidgetItem *item = new QListWidgetItem(); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Unchecked); + item->setText(s.getName()); + item->setData(1, s.getUUID()); + ui->statusListWidget->addItem(item); + } + + for (Priority p : priorities) + { + QListWidgetItem *item = new QListWidgetItem(); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Unchecked); + item->setText(p.getName()); + item->setData(1, p.getUUID()); + ui->priorityListWidget->addItem(item); + } +} + +FilterDialog::~FilterDialog() +{ + delete ui; +} + +const Filter FilterDialog::getFilter() +{ + QString name = ui->nameEdit->text(); + uint8_t dateComparation = 0; + if (ui->dateComparationCombobox->currentIndex() > -1) + { + dateComparation = ui->dateComparationCombobox->currentIndex(); + } + QVector boards; + for (int i = 0; i < ui->boardListWidget->count(); ++i) { + QListWidgetItem *item = ui->boardListWidget->item(i); + if (item->checkState() == Qt::Checked) + { + boards.append(item->data(1).toString()); + } + } + QVector status; + for (int i = 0; i < ui->statusListWidget->count(); ++i) { + QListWidgetItem *item = ui->statusListWidget->item(i); + if (item->checkState() == Qt::Checked) + { + status.append(item->data(1).toString()); + } + } + QVector priorities; + for (int i = 0; i < ui->priorityListWidget->count(); ++i) { + QListWidgetItem *item = ui->priorityListWidget->item(i); + if (item->checkState() == Qt::Checked) + { + priorities.append(item->data(1).toString()); + } + } + return Filter(name, dateComparation, boards, status, priorities); +} diff --git a/src/frames/filterdialog.h b/src/frames/filterdialog.h new file mode 100644 index 0000000..1aeaf59 --- /dev/null +++ b/src/frames/filterdialog.h @@ -0,0 +1,28 @@ +#ifndef FILTERDIALOG_H +#define FILTERDIALOG_H + +#include + +#include "../models/board.h" +#include "../models/priority.h" +#include "../models/status.h" +#include "../models/filter.h" + +namespace Ui { +class FilterDialog; +} + +class FilterDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FilterDialog(QString dialogTitle, QVector boards, QVector status, QVector priorities, QWidget *parent = nullptr); + ~FilterDialog(); + const Filter getFilter(); + +private: + Ui::FilterDialog *ui; +}; + +#endif // FILTERDIALOG_H diff --git a/src/frames/filterdialog.ui b/src/frames/filterdialog.ui new file mode 100644 index 0000000..a99baf0 --- /dev/null +++ b/src/frames/filterdialog.ui @@ -0,0 +1,169 @@ + + + FilterDialog + + + Qt::WindowModal + + + + 0 + 0 + 449 + 509 + + + + Dialog + + + true + + + + + + + + Filter name + + + + + + + + + + + + Date comparation + + + + + + + + Ignore date + + + + + On time + + + + + End today + + + + + Ended + + + + + + + + + + Boards (None = all) + + + + + + + Qt::NoContextMenu + + + QAbstractItemView::NoEditTriggers + + + false + + + false + + + + + + + Status (None = all) + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + + + + + Priority (None = all) + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + + + + + + + buttonBox + accepted() + FilterDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FilterDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/frames/mainwindow.cpp b/src/frames/mainwindow.cpp index 77efbb5..ef0eba2 100644 --- a/src/frames/mainwindow.cpp +++ b/src/frames/mainwindow.cpp @@ -15,6 +15,7 @@ #include "aboutdialog.h" #include "namedialog.h" #include "taskdialog.h" +#include "filterdialog.h" #include "../tools.h" MainWindow::MainWindow(QWidget *parent) @@ -32,6 +33,7 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::openAbout); connect(ui->actionNew, &QAction::triggered, this, &MainWindow::onNewBoardClick); connect(ui->actionNew_task, &QAction::triggered, this, &MainWindow::onNewTaskClick); + 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->taskList, &QTreeWidget::itemDoubleClicked, this, &MainWindow::onEditTask); @@ -70,51 +72,57 @@ void MainWindow::openAbout() void MainWindow::prepareBoardMenu(const QPoint &pos) { + QMenu menu(this); if (ui->boardList->selectedItems().length() == 1) { - QMenu menu(this); - - QAction *renameAction = new QAction(tr("Rename this board"), this); + QAction *renameAction = new QAction(tr("Edit board"), this); connect(renameAction, &QAction::triggered, this, &MainWindow::onEditNameBoardMenu); menu.addAction(renameAction); - menu.addSeparator(); - - QAction *deleteAction = new QAction(tr("Delete this board"), this); + QAction *deleteAction = new QAction(tr("Delete the board and all the tasks"), this); connect(deleteAction, &QAction::triggered, this, &MainWindow::onRemoveBoardMenu); menu.addAction(deleteAction); - menu.exec(ui->boardList->mapToGlobal(pos)); + menu.addSeparator(); } + QAction *addAction = new QAction(tr("New board"), this); + connect(addAction, &QAction::triggered, this, &MainWindow::onNewBoardClick); + menu.addAction(addAction); + + menu.exec(ui->boardList->mapToGlobal(pos)); } void MainWindow::prepareTaskMenu(const QPoint &pos) { + QMenu menu(this); if (ui->taskList->selectedItems().length() == 1) { - QMenu menu(this); - QAction *renameAction = new QAction(tr("Edit the task"), this); connect(renameAction, &QAction::triggered, this, &MainWindow::onEditNameTaskMenu); menu.addAction(renameAction); - menu.addSeparator(); - QAction *deleteAction = new QAction(tr("Delete from the board"), this); connect(deleteAction, &QAction::triggered, this, &MainWindow::onRemoveTaskMenu); menu.addAction(deleteAction); - menu.exec(ui->taskList->mapToGlobal(pos)); + menu.addSeparator(); } + QAction *addAction = new QAction(tr("New task"), this); + connect(addAction, &QAction::triggered, this, &MainWindow::onNewTaskClick); + menu.addAction(addAction); + + menu.exec(ui->taskList->mapToGlobal(pos)); } void MainWindow::onNewBoardClick() { - NameDialog dialog("Create a board", "New empty board", this); + NameDialog dialog("Create a board", "New empty board", "", this); if (dialog.exec() == QDialog::DialogCode::Accepted) { QString name = dialog.getChoosenName(); - Board *b = new Board(name); + QString desc = dialog.getDescription(); + Board *b = new Board(name, desc); boards.append(b); QListWidgetItem *item = new QListWidgetItem(name); + item->setStatusTip(desc); ui->boardList->addItem(item); save(); } @@ -138,6 +146,17 @@ void MainWindow::onNewTaskClick() } } +void MainWindow::onNewFilterClick() +{ + FilterDialog dialog("New filter", boards, status, priorities, this); + if (dialog.exec() == QDialog::DialogCode::Accepted) + { + Filter f = dialog.getFilter(); + QListWidgetItem *item = new QListWidgetItem(f.getName()); + ui->filterListWidget->addItem(item); + } +} + void MainWindow::onBoardSelected(int i) { selectedBoardIndex = i; @@ -145,11 +164,13 @@ void MainWindow::onBoardSelected(int i) { Board *b = boards[selectedBoardIndex]; ui->label->setText(b->getName()); + ui->boardDescription->setText(b->getDescription()); ui->actionNew_task->setDisabled(false); } else { - ui->label->setText("<- Select a board"); + ui->label->setText("No board selected"); + ui->boardDescription->clear(); ui->actionNew_task->setDisabled(true); } redrawTaskTree(); @@ -213,13 +234,18 @@ void MainWindow::onEditNameBoardMenu() if (selectedBoardIndex > -1) { Board *b = boards.at(selectedBoardIndex); - NameDialog dialog("Edit board name", b->getName(), this); + NameDialog dialog("Edit board name", b->getName(), b->getDescription(), this); if (dialog.exec() == QDialog::DialogCode::Accepted) { - QString newName= dialog.getChoosenName(); + QString newName = dialog.getChoosenName(); + QString newDesc = dialog.getDescription(); b->setName(newName); - ui->boardList->item(selectedBoardIndex)->setText(newName); + b->setDescription(newDesc); + QListWidgetItem *item = ui->boardList->item(selectedBoardIndex); + item->setText(newName); + item->setToolTip(newDesc); ui->label->setText(newName); + ui->boardDescription->setText(newDesc); save(); } } @@ -281,6 +307,12 @@ QVector MainWindow::defaultStatus() return res; } +QVector MainWindow::defaultFilters() +{ + QVector res; + return res; +} + const QString MainWindow::getPriorityLabel(QString uuid) { QString res = ""; @@ -416,6 +448,7 @@ void MainWindow::redrawBoardList() foreach (Board *b, boards) { QListWidgetItem *item = new QListWidgetItem(b->getName()); + item->setToolTip(b->getDescription()); l->addItem(item); } } diff --git a/src/frames/mainwindow.h b/src/frames/mainwindow.h index 807dedd..c48e89d 100644 --- a/src/frames/mainwindow.h +++ b/src/frames/mainwindow.h @@ -9,6 +9,7 @@ #include "../models/priority.h" #include "../models/status.h" #include "../models/board.h" +#include "../models/filter.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -27,6 +28,7 @@ private slots: void openAbout(); void onNewBoardClick(); void onNewTaskClick(); + void onNewFilterClick(); void onBoardSelected(int i); void onEditTask(QTreeWidgetItem*); void onRemoveBoardMenu(); @@ -45,9 +47,11 @@ private: QVector priorities; QVector status; QVector boards; + QVector filters; QVector defaultPriorities(); QVector defaultStatus(); + QVector defaultFilters(); const QString getPriorityLabel(QString uuid); const QString getStatusLabel(QString uuid); diff --git a/src/frames/mainwindow.ui b/src/frames/mainwindow.ui index 677e527..4d7effd 100644 --- a/src/frames/mainwindow.ui +++ b/src/frames/mainwindow.ui @@ -27,35 +27,82 @@ - - - - 250 - 0 - + + + QLayout::SetMinimumSize - - - 250 - 16777215 - - - - true - - + + + + Filters + + + + + + + + 250 + 0 + + + + + 250 + 250 + + + + + + + + Boards + + + + + + + + 250 + 0 + + + + + 250 + 16777215 + + + + true + + + + + + QLayout::SetMaximumSize + - 26 + 19 - <- Select a board + No board selected + + + + + + + Create or select a board to start @@ -101,7 +148,7 @@ 0 0 1159 - 24 + 23 @@ -128,15 +175,49 @@ + + + true + + + toolBar + + + false + + + Qt::ToolButtonTextUnderIcon + + + false + + + TopToolBarArea + + + false + + + + + + Preferences + + + :/images/resources/board_add.png:/images/resources/board_add.png + New Board + + Ctrl+N, Ctrl+B + @@ -147,11 +228,32 @@ false + + + :/images/resources/task_add.png:/images/resources/task_add.png + New task + + Ctrl+N, Ctrl+T + + + + + + :/images/resources/add_filter.png:/images/resources/add_filter.png + + + New filter + + + Ctrl+N, Ctrl+F + - + + + diff --git a/src/frames/namedialog.cpp b/src/frames/namedialog.cpp index 624f48e..909fd31 100644 --- a/src/frames/namedialog.cpp +++ b/src/frames/namedialog.cpp @@ -1,7 +1,7 @@ #include "namedialog.h" #include "ui_namedialog.h" -NameDialog::NameDialog(QString label, QString defaultName, QWidget *parent) : +NameDialog::NameDialog(QString label, QString defaultName, QString description, QWidget *parent) : QDialog(parent), ui(new Ui::NameDialog) { @@ -9,6 +9,7 @@ NameDialog::NameDialog(QString label, QString defaultName, QWidget *parent) : this->setWindowTitle(label); this->defaultName = defaultName; ui->lineEdit->setText(defaultName); + ui->descriptionTextEdit->setPlainText(description); } NameDialog::~NameDialog() @@ -24,3 +25,10 @@ const QString NameDialog::getChoosenName() } return defaultName; } + +const QString NameDialog::getDescription() +{ + return ui->descriptionTextEdit->toPlainText(); +} + + diff --git a/src/frames/namedialog.h b/src/frames/namedialog.h index 0982c39..8f6cf33 100644 --- a/src/frames/namedialog.h +++ b/src/frames/namedialog.h @@ -12,9 +12,10 @@ class NameDialog : public QDialog Q_OBJECT public: - explicit NameDialog(QString label, QString defaultName, QWidget *parent = nullptr); + explicit NameDialog(QString label, QString defaultName, QString description, QWidget *parent = nullptr); ~NameDialog(); const QString getChoosenName(); + const QString getDescription(); private: Ui::NameDialog *ui; diff --git a/src/frames/namedialog.ui b/src/frames/namedialog.ui index 41a3dff..1e4eb9c 100644 --- a/src/frames/namedialog.ui +++ b/src/frames/namedialog.ui @@ -10,19 +10,19 @@ 0 0 400 - 133 + 227 400 - 133 + 227 400 - 133 + 227 @@ -34,8 +34,8 @@ - 40 - 90 + 50 + 190 341 32 @@ -51,7 +51,7 @@ 10 - 50 + 33 381 21 @@ -61,7 +61,7 @@ 10 - 30 + 13 58 16 @@ -70,6 +70,29 @@ Name + + + + 10 + 70 + 181 + 18 + + + + Description + + + + + + 10 + 90 + 381 + 91 + + + diff --git a/src/models/board.cpp b/src/models/board.cpp index 6db71a0..79bedf2 100644 --- a/src/models/board.cpp +++ b/src/models/board.cpp @@ -3,16 +3,18 @@ #define NAME_KEY "name" #define TASKS_KEY "tasks" #define UUID_KEY "uuid" +#define DESCRIPTION_KEY "description" #include #include #include -Board::Board(QString name) +Board::Board(QString name, QString description) { QUuid uuid = QUuid::createUuid(); this->uuid = uuid.toString(QUuid::WithoutBraces); this->name = name; + this->description = description; } Board::Board(QJsonObject obj) @@ -20,8 +22,9 @@ Board::Board(QJsonObject obj) QUuid uuid = QUuid::createUuid(); this->uuid = obj[UUID_KEY].toString(uuid.toString(QUuid::WithoutBraces)); this->name = obj[NAME_KEY].toString("!Missing name!"); + this->description = obj[DESCRIPTION_KEY].toString(""); QJsonArray jsonTasks = obj[TASKS_KEY].toArray(); - for (QJsonValue value : jsonTasks) { + foreach (QJsonValue value, jsonTasks) { Task *t = new Task(value.toObject()); this->tasks.append(t); } @@ -46,11 +49,21 @@ const QString Board::getName() return name; } +const QString Board::getDescription() +{ + return description; +} + void Board::setName(const QString name) { this->name = name; } +void Board::setDescription(const QString description) +{ + this->description = description; +} + void Board::add(Task t) { tasks.append(new Task(t)); @@ -87,6 +100,7 @@ const QJsonObject Board::toJson() QJsonObject obj; obj[NAME_KEY] = this->name; obj[TASKS_KEY] = array; + obj[DESCRIPTION_KEY] = description; return obj; } diff --git a/src/models/board.h b/src/models/board.h index 4089e81..bf1dffb 100644 --- a/src/models/board.h +++ b/src/models/board.h @@ -10,13 +10,15 @@ class Board { public: - Board(QString name); + Board(QString name, QString description); Board(QJsonObject); ~Board(); const QString getUuid(); const QString getName(); + const QString getDescription(); void setName(const QString name); + void setDescription(const QString description); void add(Task); void remove(uint16_t index); Task *taskAt(uint16_t); @@ -28,6 +30,7 @@ private: QVector tasks; QString uuid; QString name; + QString description; }; diff --git a/src/models/filter.cpp b/src/models/filter.cpp index 6542c1c..6f58df9 100644 --- a/src/models/filter.cpp +++ b/src/models/filter.cpp @@ -1,4 +1,5 @@ #include "filter.h" +#include "qjsonarray.h" #define NAME_KEY "name" #define DATE_KEY "date" @@ -6,7 +7,7 @@ #define STATUS_KEY "status" #define PRIORITY_KEY "priority" -filter::filter(QString name, uint8 expectedForComparator, QVector boards, QVector status, QVector priorities) +Filter::Filter(QString name, uint8_t expectedForComparator, QVector boards, QVector status, QVector priorities) { this->name = name; this->expectedForComparator = expectedForComparator; @@ -15,7 +16,7 @@ filter::filter(QString name, uint8 expectedForComparator, QVector board this->priorities = priorities; } -filter::filter(QJsonObject obj) +Filter::Filter(QJsonObject obj) { this->name = obj[NAME_KEY].toString("!Missing name!"); this->expectedForComparator = obj[DATE_KEY].toInt(); @@ -45,7 +46,7 @@ filter::filter(QJsonObject obj) } } -QVector filter::get(QVector allBoards) +QVector Filter::get(QVector allBoards) { QDate now = QDate::currentDate(); QVector selectedBoards; @@ -85,7 +86,7 @@ QVector filter::get(QVector allBoards) return result; } -bool filter::filterStatus(Task *t) +bool Filter::filterStatus(Task *t) { if (status.count() == 0) { @@ -102,7 +103,7 @@ bool filter::filterStatus(Task *t) return result; } -bool filter::filterPriority(Task *t) +bool Filter::filterPriority(Task *t) { if (priorities.count() == 0) { @@ -119,7 +120,7 @@ bool filter::filterPriority(Task *t) return result; } -bool filter::filterDate(Task *t, QDate now) +bool Filter::filterDate(Task *t, QDate now) { switch (expectedForComparator) { case 0: @@ -134,7 +135,12 @@ bool filter::filterDate(Task *t, QDate now) return false; } -const QJsonObject filter::toJson() +const QString Filter::getName() +{ + return name; +} + +const QJsonObject Filter::toJson() { QJsonObject obj; obj[name] = name; diff --git a/src/models/filter.h b/src/models/filter.h index df3929c..c0f0513 100644 --- a/src/models/filter.h +++ b/src/models/filter.h @@ -8,7 +8,7 @@ #include "task.h" #include "board.h" -class filter +class Filter { private: QString name; @@ -19,14 +19,17 @@ private: QVector status; QVector priorities; public: - filter(QString name, uint8 expectedForComparator,QVector boards,QVector status,QVector priorities); - filter(QJsonObject obj); + 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); + + const QString getName(); + const QJsonObject toJson(); };