fix out of bound crash when edit or remove a board, add board config dialog, fix glibc version in about dialog

This commit is contained in:
Aurelie Delhaie
2023-02-20 16:51:21 +01:00
parent 93026b1373
commit 22ebe6eded
11 changed files with 364 additions and 69 deletions

View File

@@ -68,6 +68,7 @@ linux-* {
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \ SOURCES += \
src/frames/boardconfigdialog.cpp \
src/frames/filterdialog.cpp \ src/frames/filterdialog.cpp \
src/frames/aboutdialog.cpp \ src/frames/aboutdialog.cpp \
src/models/board.cpp \ src/models/board.cpp \
@@ -84,6 +85,7 @@ SOURCES += \
src/tools.cpp src/tools.cpp
HEADERS += \ HEADERS += \
src/frames/boardconfigdialog.h \
src/frames/filterdialog.h \ src/frames/filterdialog.h \
src/frames/aboutdialog.h \ src/frames/aboutdialog.h \
src/models/board.h \ src/models/board.h \
@@ -99,6 +101,7 @@ HEADERS += \
src/tools.h src/tools.h
FORMS += \ FORMS += \
src/frames/boardconfigdialog.ui \
src/frames/filterdialog.ui \ src/frames/filterdialog.ui \
src/frames/aboutdialog.ui \ src/frames/aboutdialog.ui \
src/frames/mainwindow.ui \ src/frames/mainwindow.ui \

View File

@@ -1,10 +1,6 @@
#include "aboutdialog.h" #include "aboutdialog.h"
#include "ui_aboutdialog.h" #include "ui_aboutdialog.h"
#ifdef unix
#include <gnu/libc-version.h>
#endif
AboutDialog::AboutDialog(QWidget *parent) : AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::AboutDialog) ui(new Ui::AboutDialog)
@@ -33,7 +29,7 @@ QString AboutDialog::getCompilerInfo()
#ifdef __MINGW32__ #ifdef __MINGW32__
return QString("MinGW_%1.%2").arg(QString::number(__MINGW32_MAJOR_VERSION), QString::number(__MINGW32_MINOR_VERSION)); return QString("MinGW_%1.%2").arg(QString::number(__MINGW32_MAJOR_VERSION), QString::number(__MINGW32_MINOR_VERSION));
#else #else
return QString("GLIBC_%1").arg(gnu_get_libc_version()); return QString("GLIBC_%1.%2").arg(QString::number(__GLIBC__), QString::number(__GLIBC_MINOR__));
#endif #endif
#elif _MSC_VER #elif _MSC_VER
return QString("MSVC_%1").arg(_MSC_VER); return QString("MSVC_%1").arg(_MSC_VER);

View File

@@ -0,0 +1,75 @@
#include "boardconfigdialog.h"
#include "ui_boardconfigdialog.h"
#include "../services/taskstateservice.h"
#include <QVector>
BoardConfigDialog::BoardConfigDialog(Board *b, QWidget *parent) :
QDialog(parent),
ui(new Ui::BoardConfigDialog)
{
ui->setupUi(this);
ui->nameField->setText(b->getName());
ui->descriptionField->setPlainText(b->getDescription());
if (!b->isAutoStatus())
{
QVector<Status> statuses = TaskStateService::getInstance()->getStatuses();
foreach (Status s, statuses)
{
ui->statusCombobox->addItem(s.getName(), s.getUUID());
}
ui->autoStatusCheckbox->setChecked(false);
ui->statusCombobox->setEnabled(true);
}
connect(ui->autoStatusCheckbox, &QCheckBox::stateChanged, this, &BoardConfigDialog::onAutoStatusCheckboxChange);
}
BoardConfigDialog::~BoardConfigDialog()
{
delete ui;
}
const QString BoardConfigDialog::getName()
{
return ui->nameField->text();
}
const QString BoardConfigDialog::getDescription()
{
return ui->descriptionField->toPlainText();
}
bool BoardConfigDialog::isAutoStatus()
{
return ui->autoStatusCheckbox->isChecked();
}
const QString BoardConfigDialog::getStatus()
{
if (!ui->autoStatusCheckbox->isChecked())
{
if (!ui->statusCombobox->currentData().isNull())
{
return ui->statusCombobox->currentData().toString();
}
}
return "";
}
void BoardConfigDialog::onAutoStatusCheckboxChange(int state)
{
if (state == Qt::CheckState::Unchecked)
{
QVector<Status> statuses = TaskStateService::getInstance()->getStatuses();
foreach (Status s, statuses)
{
ui->statusCombobox->addItem(s.getName(), s.getUUID());
}
ui->statusCombobox->setEnabled(true);
}
else
{
ui->statusCombobox->setEnabled(false);
ui->statusCombobox->clear();
}
}

View File

@@ -0,0 +1,32 @@
#ifndef BOARDCONFIGDIALOG_H
#define BOARDCONFIGDIALOG_H
#include <QDialog>
#include "../models/board.h"
namespace Ui {
class BoardConfigDialog;
}
class BoardConfigDialog : public QDialog
{
Q_OBJECT
public:
explicit BoardConfigDialog(Board *b, QWidget *parent = nullptr);
~BoardConfigDialog();
const QString getName();
const QString getDescription();
bool isAutoStatus();
const QString getStatus();
private slots:
void onAutoStatusCheckboxChange(int);
private:
Ui::BoardConfigDialog *ui;
};
#endif // BOARDCONFIGDIALOG_H

View File

@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BoardConfigDialog</class>
<widget class="QDialog" name="BoardConfigDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>379</height>
</rect>
</property>
<property name="windowTitle">
<string>Board Configuration</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameField"/>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="descriptionField"/>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="autoStatusCheckbox">
<property name="text">
<string>Auto determine status</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Status</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="statusCombobox">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BoardConfigDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BoardConfigDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -17,6 +17,7 @@
#include "namedialog.h" #include "namedialog.h"
#include "taskdialog.h" #include "taskdialog.h"
#include "filterdialog.h" #include "filterdialog.h"
#include "boardconfigdialog.h"
#include "../tools.h" #include "../tools.h"
#include "../services/taskstateservice.h" #include "../services/taskstateservice.h"
@@ -197,7 +198,16 @@ void MainWindow::onBoardSelected(int i)
{ {
Board *b = boards[selectedBoardIndex]; Board *b = boards[selectedBoardIndex];
ui->label->setText(b->getName()); ui->label->setText(b->getName());
ui->boardDescription->setText(b->getDescription()); if (b->getDescription().length() > 0)
{
ui->boardDescription->setText(b->getDescription());
ui->boardDescription->setEnabled(true);
}
else
{
ui->boardDescription->setText("No description");
ui->boardDescription->setEnabled(false);
}
ui->actionNew_task->setDisabled(false); ui->actionNew_task->setDisabled(false);
} }
else else
@@ -224,7 +234,16 @@ void MainWindow::onFilterSelected(int i)
{ {
Filter f = filters[selectedFilterIndex]; Filter f = filters[selectedFilterIndex];
ui->label->setText(f.getName()); ui->label->setText(f.getName());
ui->boardDescription->setText(f.getDescription()); if (f.getDescription().length() > 0)
{
ui->boardDescription->setText(f.getDescription());
ui->boardDescription->setEnabled(true);
}
else
{
ui->boardDescription->setText("No description");
ui->boardDescription->setEnabled(false);
}
} }
else else
{ {
@@ -259,7 +278,11 @@ void MainWindow::onRemoveBoardMenu()
{ {
if (menuSelectedBoardItem != nullptr) if (menuSelectedBoardItem != nullptr)
{ {
int i = ui->filterListWidget->indexFromItem(menuSelectedFilterItem).row(); int i = ui->boardList->indexFromItem(menuSelectedBoardItem).row();
if (i == -1)
{
return;
}
QMessageBox::StandardButton result = QMessageBox::question(this, "Delete a board", "Do you want to delete this board?"); QMessageBox::StandardButton result = QMessageBox::question(this, "Delete a board", "Do you want to delete this board?");
if (result == QMessageBox::Yes) if (result == QMessageBox::Yes)
{ {
@@ -296,6 +319,10 @@ void MainWindow::onRemoveFilterMenu()
if (menuSelectedFilterItem != nullptr) if (menuSelectedFilterItem != nullptr)
{ {
int i = ui->filterListWidget->indexFromItem(menuSelectedFilterItem).row(); int i = ui->filterListWidget->indexFromItem(menuSelectedFilterItem).row();
if (i == -1)
{
return;
}
QMessageBox::StandardButton result = QMessageBox::question(this, "Delete a filter", "Do you want to delete this filter?"); QMessageBox::StandardButton result = QMessageBox::question(this, "Delete a filter", "Do you want to delete this filter?");
if (result == QMessageBox::Yes) if (result == QMessageBox::Yes)
{ {
@@ -315,20 +342,50 @@ void MainWindow::onEditNameBoardMenu()
{ {
if (menuSelectedBoardItem != nullptr) if (menuSelectedBoardItem != nullptr)
{ {
int i = ui->filterListWidget->indexFromItem(menuSelectedFilterItem).row(); int i = ui->boardList->indexFromItem(menuSelectedBoardItem).row();
if (i == -1)
{
return;
}
Board *b = boards.at(i); Board *b = boards.at(i);
NameDialog dialog("Edit board name", b->getName(), b->getDescription(), this); BoardConfigDialog dialog(b, this);
if (dialog.exec() == QDialog::DialogCode::Accepted) if (dialog.exec() == QDialog::DialogCode::Accepted)
{ {
QString newName = dialog.getChoosenName(); QString newName = dialog.getName();
QString newDesc = dialog.getDescription(); QString newDesc = dialog.getDescription();
b->setName(newName); b->setName(newName);
b->setDescription(newDesc); b->setDescription(newDesc);
if (!dialog.isAutoStatus())
{
std::optional<Status> status = TaskStateService::getInstance()->getStatusByUUID(dialog.getStatus());
if (status.has_value())
{
b->setDirtyStatus(status.value());
}
else
{
b->removeDirtyStatus();
}
}
else
{
b->removeDirtyStatus();
}
QListWidgetItem *item = ui->boardList->item(i); QListWidgetItem *item = ui->boardList->item(i);
item->setText(newName); item->setText(newName);
item->setToolTip(newDesc); item->setToolTip(newDesc);
ui->label->setText(newName); ui->label->setText(newName);
ui->boardDescription->setText(newDesc); if (newDesc.length() > 0)
{
ui->boardDescription->setText(newDesc);
ui->boardDescription->setEnabled(true);
}
else
{
ui->boardDescription->setText("No description");
ui->boardDescription->setEnabled(false);
}
redrawBoardStatus();
save(); save();
} }
} }
@@ -358,7 +415,16 @@ void MainWindow::onEditFilterMenu()
item->setText(f.getName()); item->setText(f.getName());
item->setToolTip(f.getDescription()); item->setToolTip(f.getDescription());
ui->label->setText(f.getName()); ui->label->setText(f.getName());
ui->boardDescription->setText(f.getDescription()); if (f.getDescription().length() > 0)
{
ui->boardDescription->setText(f.getDescription());
ui->boardDescription->setEnabled(true);
}
else
{
ui->boardDescription->setText("No description");
ui->boardDescription->setEnabled(false);
}
redrawTaskTree(); redrawTaskTree();
save(); save();
} }

View File

@@ -52,6 +52,9 @@
<height>250</height> <height>250</height>
</size> </size>
</property> </property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>

View File

@@ -10,19 +10,8 @@ TaskDialog::TaskDialog(QWidget *parent) :
ui(new Ui::TaskDialog) ui(new Ui::TaskDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
init();
this->setWindowTitle("New task"); this->setWindowTitle("New task");
this->status = TaskStateService::getInstance()->getStatuses();
this->priorities = TaskStateService::getInstance()->getPriorities();
foreach (Status s, this->status)
{
ui->statusCombo->addItem(s.getName());
}
foreach (Priority p, this->priorities)
{
ui->priorityCombo->addItem(p.getName());
}
QDate expectedFor = QDate::currentDate(); QDate expectedFor = QDate::currentDate();
expectedFor = expectedFor.addDays(10); expectedFor = expectedFor.addDays(10);
@@ -34,19 +23,8 @@ TaskDialog::TaskDialog(Task *t, QWidget *parent) :
ui(new Ui::TaskDialog) ui(new Ui::TaskDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
init();
this->setWindowTitle("Edit task"); this->setWindowTitle("Edit task");
this->status = TaskStateService::getInstance()->getStatuses();
this->priorities = TaskStateService::getInstance()->getPriorities();
foreach (Status s, this->status)
{
ui->statusCombo->addItem(s.getName());
}
foreach (Priority p, this->priorities)
{
ui->priorityCombo->addItem(p.getName());
}
// set fields // set fields
ui->nameEdit->setText(t->getTitle()); ui->nameEdit->setText(t->getTitle());
@@ -55,34 +33,12 @@ TaskDialog::TaskDialog(Task *t, QWidget *parent) :
if (t->getPriorityUUID().length() > 0) if (t->getPriorityUUID().length() > 0)
{ {
int16_t refindex = -1; initSelectionCombobox(t->getPriorityUUID(), ui->priorityCombo);
for (uint16_t i = 0; i < this->priorities.count(); i++)
{
if (this->priorities[i].getUUID() == t->getPriorityUUID())
{
refindex = i;
}
}
if (refindex > -1)
{
ui->priorityCombo->setCurrentIndex(refindex);
}
} }
if (t->getStatusUUID().length() > 0) if (t->getStatusUUID().length() > 0)
{ {
int16_t refindex = -1; initSelectionCombobox(t->getStatusUUID(), ui->statusCombo);
for (uint16_t i = 0; i < this->status.count(); i++)
{
if (this->status[i].getUUID() == t->getStatusUUID())
{
refindex = i;
}
}
if (refindex > -1)
{
ui->statusCombo->setCurrentIndex(refindex);
}
} }
} }
@@ -98,16 +54,42 @@ Task TaskDialog::getTask()
QString description = ui->descriptionEdit->toMarkdown(QTextDocument::MarkdownFeature::MarkdownDialectCommonMark); QString description = ui->descriptionEdit->toMarkdown(QTextDocument::MarkdownFeature::MarkdownDialectCommonMark);
QDate expectedFor = ui->expectedForEdit->date(); QDate expectedFor = ui->expectedForEdit->date();
QString priorityUUID = ""; QString priorityUUID = "";
if (ui->priorityCombo->currentIndex() > -1) if (!ui->priorityCombo->currentData().isNull())
{ {
Priority priority = priorities[ui->priorityCombo->currentIndex()]; priorityUUID = ui->priorityCombo->currentData().toString();
priorityUUID = priority.getUUID();
} }
QString statusUUID = ""; QString statusUUID = "";
if (ui->statusCombo->currentIndex() > -1) if (!ui->statusCombo->currentData().isNull())
{ {
Status s = status[ui->statusCombo->currentIndex()]; statusUUID = ui->statusCombo->currentData().toString();
statusUUID = s.getUUID();
} }
return Task(title, description, expectedFor, priorityUUID, statusUUID); return Task(title, description, expectedFor, priorityUUID, statusUUID);
} }
void TaskDialog::init()
{
QVector<Status> statuses = TaskStateService::getInstance()->getStatuses();
QVector<Priority> priorities = TaskStateService::getInstance()->getPriorities();
foreach (Status s, statuses)
{
ui->statusCombo->addItem(s.getName(), s.getUUID());
}
foreach (Priority p, priorities)
{
ui->priorityCombo->addItem(p.getName(), p.getUUID());
}
}
void TaskDialog::initSelectionCombobox(QString uuid, QComboBox *cbx)
{
for (uint16_t i = 0; i < cbx->count(); i++)
{
if (cbx->itemData(i).toString() == uuid)
{
cbx->setCurrentIndex(i);
break;
}
}
}

View File

@@ -3,6 +3,7 @@
#include <QDialog> #include <QDialog>
#include <QVector> #include <QVector>
#include <QComboBox>
#include "../models/status.h" #include "../models/status.h"
#include "../models/priority.h" #include "../models/priority.h"
@@ -26,8 +27,8 @@ public:
private: private:
Ui::TaskDialog *ui; Ui::TaskDialog *ui;
QVector<Status> status; void init();
QVector<Priority> priorities; void initSelectionCombobox(QString uuid, QComboBox *cbx);
}; };
#endif // TASKDIALOG_H #endif // TASKDIALOG_H

View File

@@ -96,6 +96,18 @@ void Board::setDescription(const QString description)
this->description = description; this->description = description;
} }
void Board::setDirtyStatus(Status s)
{
this->autoStatus = false;
this->statusUUID = s.getUUID();
}
void Board::removeDirtyStatus()
{
this->autoStatus = true;
this->statusUUID = "";
}
void Board::add(Task t) void Board::add(Task t)
{ {
tasks.append(new Task(t)); tasks.append(new Task(t));

View File

@@ -6,6 +6,7 @@
#include <QJsonObject> #include <QJsonObject>
#include "task.h" #include "task.h"
#include "status.h"
class Board class Board
{ {
@@ -19,10 +20,15 @@ public:
const QString getDescription(); const QString getDescription();
const QString getStatus(); const QString getStatus();
bool isAutoStatus(); bool isAutoStatus();
void setName(const QString name); void setName(const QString name);
void setDescription(const QString description); void setDescription(const QString description);
void setDirtyStatus(Status s);
void removeDirtyStatus();
void add(Task); void add(Task);
void remove(uint16_t index); void remove(uint16_t index);
Task *taskAt(uint16_t); Task *taskAt(uint16_t);
const QVector<Task*> getTasks(); const QVector<Task*> getTasks();