From 3e1d2e46ceea202120b4ff814fbd872bc6fc60f3 Mon Sep 17 00:00:00 2001 From: Louie S Date: Thu, 14 Mar 2024 18:46:37 -0400 Subject: RulesDialog menu working (functionality WIP) --- CMakeLists.txt | 3 ++ src/assignmentList.cpp | 12 +---- src/assignmentList.h | 4 -- src/backend/db_sqlite.cpp | 48 +++++++++++++++++- src/backend/db_sqlite.h | 3 +- src/entryLayout.cpp | 21 ++++---- src/lib.cpp | 9 ++++ src/lib.h | 5 ++ src/rule.h | 10 ++-- src/ruleLayout.cpp | 42 ++++++++-------- src/ruleLayout.h | 15 +++++- src/rulesDialog.cpp | 81 ++++++++++++++++++++++++++++++ src/rulesDialog.h | 30 +++++++++++ src/rulesDialog.ui | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 351 insertions(+), 55 deletions(-) create mode 100644 src/rulesDialog.cpp create mode 100644 src/rulesDialog.h create mode 100644 src/rulesDialog.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 077981d..bd8c8d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,9 @@ set(project_sources "src/rule.h" "src/ruleLayout.cpp" "src/ruleLayout.h" + "src/rulesDialog.cpp" + "src/rulesDialog.h" + "src/rulesDialog.ui" ) add_executable(assignment-list diff --git a/src/assignmentList.cpp b/src/assignmentList.cpp index 953d443..673e0b5 100644 --- a/src/assignmentList.cpp +++ b/src/assignmentList.cpp @@ -18,6 +18,7 @@ #include "backend/db_sqlite.h" #include "entryLayout.h" #include "groupLayout.h" +#include "lib.h" #include "preferencesDialog.h" AssignmentList::AssignmentList() { @@ -76,7 +77,7 @@ void AssignmentList::displayWidgets() { int i; // clear out old layouts if they exist - this->recursiveClear(ui.groups_layout); + recursiveClear(ui.groups_layout); for(i = 0; i < groups.size(); ++i) { if(groups[i]->hidden) continue; @@ -138,12 +139,3 @@ void AssignmentList::aboutDialog() { QMessageBox about; about.about(this, "About Assignment List", "Created by Louie S. - 2023"); } - -void AssignmentList::recursiveClear(QLayout *layout) { - QLayoutItem *child; - while((child = layout->takeAt(0)) != nullptr) { - if(child->layout()) this->recursiveClear(child->layout()); - delete child->widget(); - delete child; - } -} diff --git a/src/assignmentList.h b/src/assignmentList.h index d5da023..8b028d7 100644 --- a/src/assignmentList.h +++ b/src/assignmentList.h @@ -31,10 +31,6 @@ class AssignmentList : public QMainWindow { void drawGroups(); void drawEntries(); - // helpers - // used to clear out the grid layout when a refresh occurs - void recursiveClear(QLayout *layout); - private slots: void preferences(); void reload(); diff --git a/src/backend/db_sqlite.cpp b/src/backend/db_sqlite.cpp index 4319b67..32108e1 100644 --- a/src/backend/db_sqlite.cpp +++ b/src/backend/db_sqlite.cpp @@ -134,7 +134,33 @@ QList BackendDB::loadRules() { QSqlDatabase database(this->openDB()); QSqlQuery query; - query.exec("SELECT * FROM groups"); + query.exec("SELECT * FROM rules"); + while(query.next()) { + output.append(new Rule( + query.record().field("id").value().toInt(), + query.record().field("entry_id").value().toInt(), + (Rule::When) query.record().field("before_after").value().toInt(), + query.record().field("date").value().toDateTime(), + query.record().field("color").value().toString(), + query.record().field("highlight").value().toString())); + } + } + + QSqlDatabase::removeDatabase("qt_sql_default_connection"); + return output; +} + +// load entries +QList BackendDB::loadRules(int entry_id) { + QList output; + + { + QSqlDatabase database(this->openDB()); + QSqlQuery query; + + query.prepare("SELECT * FROM rules WHERE entry_id = ?"); + query.bindValue(0, entry_id); + query.exec(); while(query.next()) { output.append(new Rule( query.record().field("id").value().toInt(), @@ -295,6 +321,26 @@ int BackendDB::removeEntry(const Entry &entry) { return output; } +// return value: number of affected rows +int BackendDB::removeRule(const Rule &rule) { + int output; + + { + QSqlDatabase database(this->openDB()); + QSqlQuery query; + + query.prepare("DELETE FROM rules WHERE id = ?"); + query.bindValue(0, rule.id); + query.exec(); + + // FIXME not sure if this also needs to be called after the first query... + output = query.numRowsAffected(); + } + + QSqlDatabase::removeDatabase("qt_sql_default_connection"); + return output; +} + // permanently delete removed/hidden groups and entries void BackendDB::cleanHidden() { { diff --git a/src/backend/db_sqlite.h b/src/backend/db_sqlite.h index 1db61e8..ce2d900 100644 --- a/src/backend/db_sqlite.h +++ b/src/backend/db_sqlite.h @@ -16,6 +16,7 @@ class BackendDB : QSqlDatabase { QList loadEntries(); QList loadEntries(int parent_id); QList loadRules(); + QList loadRules(int entry_id); int insertGroup(const Group &new_group); int insertEntry(const Entry &new_entry); int insertRule(int new_rule); // param datatype TBD @@ -24,7 +25,7 @@ class BackendDB : QSqlDatabase { void updateRule(int rule); // param datatype TBD int removeGroup(const Group &group); int removeEntry(const Entry &entry); - void removeRule(int rule); // param datatype TBD + int removeRule(const Rule &rule); void cleanHidden(); private: diff --git a/src/entryLayout.cpp b/src/entryLayout.cpp index 48b2888..54aa5f8 100644 --- a/src/entryLayout.cpp +++ b/src/entryLayout.cpp @@ -7,6 +7,7 @@ #include "editEntryForm.h" #include "entryLayout.h" #include "lib.h" +#include "rulesDialog.h" EntryLayout::EntryLayout(const Entry &e) : entry(e) @@ -38,13 +39,11 @@ EntryLayout::EntryLayout(const Entry &e) : // set conditional styling if(this->entry.done) { bullet->setText("\u2713"); - /* bullet->setStyleSheet( "QLabel {" " color: green;" "}" ); - */ } else bullet->setText("- "); @@ -69,24 +68,20 @@ EntryLayout::EntryLayout(const Entry &e) : QFont body_font = body->font(); body_font.setStrikeOut(true); body->setFont(body_font); - /* body->setStyleSheet( "QLabel {" " color: green" "}" ); - */ } else { - /* body->setStyleSheet( "QLabel {" - " color: " + (this->color.isEmpty() ? "default" : this->color) + ";" - " background-color: " + (this->highlight.isEmpty() ? "none" : this->highlight) + ";" - " font-weight: " + (this->due.isValid() && this->due <= QDateTime::currentDateTime() ? "bold" : "normal") + ";" - ";" + " color: " + (this->entry.color.isEmpty() ? "default" : this->entry.color) + ";" + " background-color: " + (this->entry.highlight.isEmpty() ? "none" : this->entry.highlight) + ";" + " font-weight: " + (this->entry.due.isValid() && this->entry.due <= QDateTime::currentDateTime() ? "bold" : "normal") + ";" + "}" ); - */ } this->addWidget(body); @@ -100,7 +95,7 @@ void EntryLayout::showContextMenu() { menu.addAction(edit_entry_act); QAction *set_rules_act = new QAction("Rules"); - QObject::connect(edit_entry_act, &QAction::triggered, this, &EntryLayout::setRules); + QObject::connect(set_rules_act, &QAction::triggered, this, &EntryLayout::setRules); menu.addAction(set_rules_act); QAction *toggle_done_act = new QAction("Done"); @@ -123,7 +118,9 @@ void EntryLayout::editEntry() { } void EntryLayout::setRules() { - qDebug() << "WIP"; + RulesDialog rules_dialog(this->entry); + if(rules_dialog.exec() == QDialog::Accepted) + getMainWindow()->displayWidgets(); } void EntryLayout::toggleDone() { diff --git a/src/lib.cpp b/src/lib.cpp index 2815863..2290472 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -11,3 +11,12 @@ AssignmentList *getMainWindow() { return mainWin; return nullptr; } + +void recursiveClear(QLayout *layout) { + QLayoutItem *child; + while((child = layout->takeAt(0)) != nullptr) { + if(child->layout()) recursiveClear(child->layout()); + delete child->widget(); + delete child; + } +} diff --git a/src/lib.h b/src/lib.h index b9b876b..14f63c1 100644 --- a/src/lib.h +++ b/src/lib.h @@ -5,3 +5,8 @@ #include "assignmentList.h" AssignmentList *getMainWindow(); + +QDialog *getParentDialog(); + +// used to clear out a layout when a refresh occurs +void recursiveClear(QLayout *layout); diff --git a/src/rule.h b/src/rule.h index 2120401..1d7e90a 100644 --- a/src/rule.h +++ b/src/rule.h @@ -10,16 +10,16 @@ struct Rule { int entry_id; When when; QDateTime date; - QString color = ""; - QString highlight = ""; + QString color; // consider making this a QColor instead + QString highlight; // see color comment Rule( int id, int entry_id, When when, - QDateTime date, - QString color, - QString highlight + QDateTime date = QDateTime::currentDateTime(), + QString color = "", + QString highlight = "" ); }; diff --git a/src/ruleLayout.cpp b/src/ruleLayout.cpp index f922f1a..11abf80 100644 --- a/src/ruleLayout.cpp +++ b/src/ruleLayout.cpp @@ -1,38 +1,40 @@ -#include -#include -#include -#include +#include "lib.h" #include "ruleLayout.h" RuleLayout::RuleLayout(const Rule &r) : rule(r) { - QComboBox *when_widget = new QComboBox; - QDateTimeEdit *date_widget = new QDateTimeEdit(QDate::currentDate()); - QLineEdit *color_widget = new QLineEdit; // TODO consider making this a color selector widget - QLineEdit *highlight_widget = new QLineEdit; // TODO consider making this a color selector widget + this->when_widget = new QComboBox; + this->date_widget = new QDateTimeEdit(QDate::currentDate()); + this->color_widget = new QLineEdit; + this->highlight_widget = new QLineEdit; + this->del_button = new QPushButton; QStringList when_options; when_options.append("Before"); when_options.append("After"); - when_widget->addItems(when_options); - when_widget->setCurrentIndex(this->rule.when); - this->addWidget(when_widget); + this->when_widget->addItems(when_options); + this->when_widget->setCurrentIndex(this->rule.when); + this->addWidget(this->when_widget); - date_widget->setDisplayFormat("MM/dd/yyyy"); - date_widget->setDateTime(this->rule.date); - this->addWidget(date_widget); + this->date_widget->setDisplayFormat("MM/dd/yyyy"); + this->date_widget->setDateTime(this->rule.date); + this->addWidget(this->date_widget); this->addStretch(); - color_widget->setPlaceholderText("Color"); + this->color_widget->setPlaceholderText("Color"); if(!this->rule.color.isEmpty()) - color_widget->setText(this->rule.color); - this->addWidget(color_widget); + this->color_widget->setText(this->rule.color); + this->addWidget(this->color_widget); - highlight_widget->setPlaceholderText("Highlight"); + this->highlight_widget->setPlaceholderText("Highlight"); if(!this->rule.highlight.isEmpty()) - highlight_widget->setText(this->rule.highlight); - this->addWidget(highlight_widget); + this->highlight_widget->setText(this->rule.highlight); + this->addWidget(this->highlight_widget); + + this->del_button->setText("Delete"); + // connection needs to be made in rulesDialog.cpp + this->addWidget(this->del_button); } diff --git a/src/ruleLayout.h b/src/ruleLayout.h index 45aafc1..29a4deb 100644 --- a/src/ruleLayout.h +++ b/src/ruleLayout.h @@ -1,14 +1,25 @@ #ifndef RULELAYOUT_H #define RULELAYOUT_H +#include +#include +#include #include +#include +#include #include "rule.h" -// TODO consider getting rid of this class (unneccesary) -class RuleLayout : QHBoxLayout { +class RuleLayout : public QHBoxLayout { + Q_OBJECT + public: Rule rule; + QComboBox *when_widget; + QDateTimeEdit *date_widget; + QLineEdit *color_widget; // TODO consider making this a color selector widget + QLineEdit *highlight_widget; // TODO consider making this a color selector widget + QPushButton *del_button; RuleLayout(const Rule &r); }; diff --git a/src/rulesDialog.cpp b/src/rulesDialog.cpp new file mode 100644 index 0000000..b856ebb --- /dev/null +++ b/src/rulesDialog.cpp @@ -0,0 +1,81 @@ +#include +#include +#include + +#include + +#include "backend/db_sqlite.h" +#include "lib.h" +#include "ruleLayout.h" +#include "rulesDialog.h" + +RulesDialog::RulesDialog(const Entry &entry) { + BackendDB database; + + this->entry_id = entry.id; + + // load uic + ui.setupUi(this); + + // load rules into object member + this->rules = database.loadRules(entry_id); + + // display widgets + this->drawRules(); + + // set connections + QObject::connect(ui.add_rule_button, &QPushButton::released, this, &RulesDialog::addRule); +} + +// for maintaining values when adding/removing rules +void RulesDialog::updateRulesList() { + int i; + + for(i = 0; i < ui.rules_layout->children().size(); ++i) { + this->rules[i]->when = Rule::When(qobject_cast(ui.rules_layout->children()[i])->when_widget->currentIndex()); + this->rules[i]->date = qobject_cast(ui.rules_layout->children()[i])->date_widget->dateTime(); + this->rules[i]->color = qobject_cast(ui.rules_layout->children()[i])->color_widget->text(); + this->rules[i]->highlight = qobject_cast(ui.rules_layout->children()[i])->highlight_widget->text(); + } +} + +void RulesDialog::drawRules() { + RuleLayout *new_layout; + int i; + + + // remove all children from layout + recursiveClear(ui.rules_layout); + + // Draw each rule + for(i = 0; i < this->rules.size(); ++i) { + new_layout = new RuleLayout(*rules[i]); + + // connect delete button + QObject::connect(new_layout->del_button, &QPushButton::released, this, [=](){ this->deleteRule(i); }); + + ui.rules_layout->addLayout(new_layout); + } +} + +void RulesDialog::addRule() { + // TODO handle in db backend to insert instead of updating if id is 0 + Rule *new_rule = new Rule(0, this->entry_id, Rule::before); + RuleLayout *new_layout = new RuleLayout(*new_rule); + + // add new rule to the member variable + this->rules.append(new_rule); + + // redraw rules + this->updateRulesList(); + this->drawRules(); +} + +void RulesDialog::deleteRule(int i) { + if(i < 0) return; + if(i >= this->rules.size()) return; + + this->updateRulesList(); + this->rules.removeAt(i); + this->drawRules(); +} diff --git a/src/rulesDialog.h b/src/rulesDialog.h new file mode 100644 index 0000000..8f0fd81 --- /dev/null +++ b/src/rulesDialog.h @@ -0,0 +1,30 @@ +#ifndef RULESDIALOG_H +#define RULESDIALOG_H + +#include + +#include "entry.h" +#include "rule.h" +#include "ui_rulesDialog.h" + +// show the list of rules associated with an entry +class RulesDialog : public QDialog { + Q_OBJECT + + public: + RulesDialog(const Entry &entry); + void drawRules(); + + private: + Ui::rulesDialog ui; + int entry_id; + QList rules; + + void updateRulesList(); + + private slots: + void addRule(); + void deleteRule(int i); +}; + +#endif diff --git a/src/rulesDialog.ui b/src/rulesDialog.ui new file mode 100644 index 0000000..c362887 --- /dev/null +++ b/src/rulesDialog.ui @@ -0,0 +1,123 @@ + + + rulesDialog + + + + 0 + 0 + 500 + 320 + + + + Dialog + + + + + + true + + + + + 0 + 0 + 480 + 269 + + + + + + + + + + + + Add Rule + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + rulesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + rulesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + -- cgit