From 358bc8de5dc2454b87daed1e4dd463a84383955b Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Sun, 4 Mar 2018 09:05:20 +0100 Subject: [PATCH 1/5] Added new recipe dialog, improved ingredient list display --- RecipeDB.pro | 9 ++- gui/mainwindow.ui | 76 +++++++++++++++---- gui/newrecipedialog.cpp | 14 ++++ gui/newrecipedialog.h | 22 ++++++ gui/newrecipedialog.ui | 19 +++++ main.cpp | 18 ++--- model/database/recipedatabase.cpp | 2 - .../ingredients/ingredientlistmodel.cpp | 14 +++- model/recipe/ingredients/unitofmeasure.cpp | 12 ++- model/recipe/ingredients/unitofmeasure.h | 11 ++- 10 files changed, 161 insertions(+), 36 deletions(-) create mode 100644 gui/newrecipedialog.cpp create mode 100644 gui/newrecipedialog.h create mode 100644 gui/newrecipedialog.ui diff --git a/RecipeDB.pro b/RecipeDB.pro index 2c957a5..0153b2b 100644 --- a/RecipeDB.pro +++ b/RecipeDB.pro @@ -25,7 +25,8 @@ SOURCES += model/recipe/instruction.cpp \ SQLite/sqlite3.c \ model/database/resulttable.cpp \ model/database/recipedatabase.cpp \ - utils/fileutils.cpp + utils/fileutils.cpp \ + gui/newrecipedialog.cpp HEADERS += model/recipe/instruction.h \ model/recipe/recipe.h \ @@ -40,11 +41,13 @@ HEADERS += model/recipe/instruction.h \ SQLite/sqlite3ext.h \ model/database/resulttable.h \ model/database/recipedatabase.h \ - utils/fileutils.h + utils/fileutils.h \ + gui/newrecipedialog.h LIBS += -ldl \ -FORMS += gui/mainwindow.ui +FORMS += gui/mainwindow.ui \ + gui/newrecipedialog.ui DISTFILES += \ .gitignore diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 1db1cc9..267cc6b 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -109,12 +109,25 @@ - Source Sans Pro Light + Noto Sans CJK KR Light 20 + PreferAntialias + + false + - background-color: rgb(83, 75, 255); + QPushButton#newButton { + background-color: rgb(235, 235, 255); + border: 0px; +} +QPushButton#newButton:hover{ + background-color: rgb(245, 245, 255); +} +QPushButton#newButton:pressed{ + background-color: rgb(255, 255, 255); +} New @@ -134,12 +147,22 @@ - Source Sans Pro Light + Noto Sans CJK KR Light 20 + PreferAntialias - background-color: rgb(112, 105, 255); + QPushButton#openButton { + background-color: rgb(222, 226, 255); + border: 0px; +} +QPushButton#openButton:hover{ + background-color: rgb(232, 236, 255); +} +QPushButton#openButton:pressed{ + background-color: rgb(255, 255, 255); +} Open @@ -156,16 +179,32 @@ - Source Sans Pro Light + Noto Sans CJK KR Light 20 + PreferAntialias + + false + - background-color: rgb(137, 131, 255); + QPushButton#browseButton { + background-color: rgb(215, 215, 255); + border: 0px; +} +QPushButton#browseButton:hover{ + background-color: rgb(225, 225, 255); +} +QPushButton#browseButton:pressed{ + background-color: rgb(255, 255, 255); +} Browse + + false + @@ -214,8 +253,13 @@ - Source Sans Pro Light + Noto Sans CJK KR Light 24 + 50 + false + false + PreferAntialias + true @@ -299,7 +343,7 @@ - Source Sans Pro Light + Noto Sans CJK KR Thin 18 @@ -324,8 +368,9 @@ - Source Sans Pro Light - 16 + Noto Sans CJK KR Light + 12 + PreferAntialias @@ -343,6 +388,9 @@ Qt::ScrollBarAlwaysOff + + QAbstractItemView::NoSelection + true @@ -397,7 +445,7 @@ - Source Sans Pro Light + Noto Sans CJK KR Thin 18 @@ -445,11 +493,11 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#00ff40;">This is some </span><span style=" font-size:16pt; color:#a33c3e;">colored text and </span><a href="https://www.google.com"><span style=" font-size:8pt; text-decoration: underline; color:#0000ff;">link</span></a></p></body></html> +</style></head><body style=" font-family:'Liberation Serif Bold'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; color:#00ff40;">This is some </span><span style=" font-family:'MS Shell Dlg 2'; font-size:16pt; color:#a33c3e;">colored text and </span><a href="https://www.google.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">link</span></a></p></body></html> - Qt::LinksAccessibleByMouse + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse diff --git a/gui/newrecipedialog.cpp b/gui/newrecipedialog.cpp new file mode 100644 index 0000000..818f180 --- /dev/null +++ b/gui/newrecipedialog.cpp @@ -0,0 +1,14 @@ +#include "newrecipedialog.h" +#include "ui_newrecipedialog.h" + +NewRecipeDialog::NewRecipeDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::NewRecipeDialog) +{ + ui->setupUi(this); +} + +NewRecipeDialog::~NewRecipeDialog() +{ + delete ui; +} diff --git a/gui/newrecipedialog.h b/gui/newrecipedialog.h new file mode 100644 index 0000000..30c34a2 --- /dev/null +++ b/gui/newrecipedialog.h @@ -0,0 +1,22 @@ +#ifndef NEWRECIPEDIALOG_H +#define NEWRECIPEDIALOG_H + +#include + +namespace Ui { +class NewRecipeDialog; +} + +class NewRecipeDialog : public QDialog +{ + Q_OBJECT + + public: + explicit NewRecipeDialog(QWidget *parent = 0); + ~NewRecipeDialog(); + + private: + Ui::NewRecipeDialog *ui; +}; + +#endif // NEWRECIPEDIALOG_H diff --git a/gui/newrecipedialog.ui b/gui/newrecipedialog.ui new file mode 100644 index 0000000..5248942 --- /dev/null +++ b/gui/newrecipedialog.ui @@ -0,0 +1,19 @@ + + + NewRecipeDialog + + + + 0 + 0 + 640 + 480 + + + + Dialog + + + + + diff --git a/main.cpp b/main.cpp index d67a414..1cadc3c 100644 --- a/main.cpp +++ b/main.cpp @@ -13,22 +13,16 @@ int main(int argc, char *argv[]) //TESTING CODE RecipeDatabase recipeDB("recipes"); -// recipeDB.storeIngredient(Ingredient("Apple", "Fruit")); -// recipeDB.storeIngredient(Ingredient("Corn", "Vegetable")); -// recipeDB.storeIngredient(Ingredient("Lettuce", "Vegetable")); -// recipeDB.storeIngredient(Ingredient("Carrot", "Vegetable")); - -// recipeDB.executeSQL("SELECT * FROM ingredient;").printData(); //TESTING CODE - vector ri; - ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c"))); - ri.push_back(RecipeIngredient("Baking Powder", "Additives", 1.0f, UnitOfMeasure("Teaspoon", "Teaspoons", "Tsp"))); +// vector ri; +// ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c"))); +// ri.push_back(RecipeIngredient("Baking Powder", "Additives", 1.0f, UnitOfMeasure("Teaspoon", "Teaspoons", "Tsp"))); - Recipe rec("Example", ri, Instruction("BOLDiTaLiCs"), QImage(), vector(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f); +// Recipe rec("Example", ri, Instruction("BOLDiTaLiCs"), QImage(), vector(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f); - bool success = recipeDB.storeRecipe(rec); - printf("Storage successful: %d\n", success); +// bool success = recipeDB.storeRecipe(rec); +// printf("Storage successful: %d\n", success); Recipe reloadRec = recipeDB.retrieveRecipe("Example"); reloadRec.print(); diff --git a/model/database/recipedatabase.cpp b/model/database/recipedatabase.cpp index 4c991da..bc23000 100644 --- a/model/database/recipedatabase.cpp +++ b/model/database/recipedatabase.cpp @@ -117,7 +117,6 @@ Recipe RecipeDatabase::retrieveRecipe(string name){ fprintf(stderr, "Error: No recipe with name %s found!\n", name.c_str()); return Recipe(); } - t.printData(); Recipe r; int id = std::stoi(t.valueAt(0, 0)); r.setName(t.valueAt(0, 1)); @@ -137,7 +136,6 @@ vector RecipeDatabase::retrieveRecipeIngredients(int recipeId) "INNER JOIN recipeIngredient " "ON ingredient.ingredientId = recipeIngredient.ingredientId " "AND recipeIngredient.recipeId = "+std::to_string(recipeId)+";"); - t.printData(); vector ings; for (unsigned int row = 0; row < t.rowCount(); row++){ RecipeIngredient r(t.valueAt(row, 0), t.valueAt(row, 1), std::stof(t.valueAt(row, 2)), UnitOfMeasure(t.valueAt(row, 3))); diff --git a/model/recipe/ingredients/ingredientlistmodel.cpp b/model/recipe/ingredients/ingredientlistmodel.cpp index de88da5..bd1a41e 100644 --- a/model/recipe/ingredients/ingredientlistmodel.cpp +++ b/model/recipe/ingredients/ingredientlistmodel.cpp @@ -10,10 +10,22 @@ int IngredientListModel::rowCount(const QModelIndex &parent) const{ QVariant IngredientListModel::data(const QModelIndex &index, int role) const{ int row = index.row(); + RecipeIngredient i = this->ingredients[row]; + + string displayStr; + + if (std::ceil(i.getQuantity()) == i.getQuantity()){ + //The quantity is an integer and should be casted. + displayStr += std::to_string((int)i.getQuantity()); + } else { + displayStr += std::to_string(i.getQuantity()); + } + + displayStr += " " + i.getUnit().getAbbreviation() + " " + i.getName(); switch(role){ case Qt::DisplayRole: - return QString::fromStdString(ingredients[row].getName()); + return QString::fromStdString(displayStr); } return QVariant(); diff --git a/model/recipe/ingredients/unitofmeasure.cpp b/model/recipe/ingredients/unitofmeasure.cpp index ddf62c8..7b4a0f8 100644 --- a/model/recipe/ingredients/unitofmeasure.cpp +++ b/model/recipe/ingredients/unitofmeasure.cpp @@ -1,19 +1,21 @@ #include "unitofmeasure.h" -UnitOfMeasure::UnitOfMeasure(string name, string plural, string abbreviation){ +UnitOfMeasure::UnitOfMeasure(string name, string plural, string abbreviation, int type){ this->name = name; this->plural = plural; this->abbreviation = abbreviation; + this->type = type; } UnitOfMeasure::UnitOfMeasure(string name){ this->name = name; this->plural = name + "s"; this->abbreviation = "NULL"; + this->type = MISC; ///TODO: Make actual guessing of this stuff. } -UnitOfMeasure::UnitOfMeasure() : UnitOfMeasure::UnitOfMeasure("", "", ""){ +UnitOfMeasure::UnitOfMeasure() : UnitOfMeasure::UnitOfMeasure("", "", "", MISC){ //Default constructor initializes all fields to empty strings. } @@ -26,5 +28,9 @@ string UnitOfMeasure::getNamePlural() const{ } string UnitOfMeasure::getAbbreviation() const{ - return this->abbreviation; + return this->abbreviation; +} + +int UnitOfMeasure::getType() const{ + return this->type; } diff --git a/model/recipe/ingredients/unitofmeasure.h b/model/recipe/ingredients/unitofmeasure.h index 1787f14..1197089 100644 --- a/model/recipe/ingredients/unitofmeasure.h +++ b/model/recipe/ingredients/unitofmeasure.h @@ -12,8 +12,14 @@ using namespace std; class UnitOfMeasure { public: + //Constants Declarations. + static const int MASS = 1; + static const int VOLUME = 2; + static const int LENGTH = 3; + static const int MISC = 4; + //Full constructor. - UnitOfMeasure(string name, string plural, string abbreviation); + UnitOfMeasure(string name, string plural, string abbreviation, int type); //Attempt to guess unit from just a string. UnitOfMeasure(string name); //Constructor with default values. @@ -23,10 +29,13 @@ public: string getName() const; string getNamePlural() const; string getAbbreviation() const; + int getType() const; private: string name; //The name of the unit of measure. string plural; //The plural name. string abbreviation; //A short version of the unit. + int type; //The type of unit, as one of the constants above. + double metricCoefficient; //The conversion from this unit to the standard metric unit. }; #endif // UNITOFMEASURE_H -- 2.34.1 From 49d9004eae5c66f0cb757877b57b6af82f41f71a Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Sun, 4 Mar 2018 10:19:32 +0100 Subject: [PATCH 2/5] New Recipe Dialog is almost done. --- gui/mainwindow.ui | 2 +- gui/newrecipedialog.ui | 372 ++++++++++++++++++++++++++++++++++++++++- main.cpp | 5 + 3 files changed, 374 insertions(+), 5 deletions(-) diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 267cc6b..e93bbfd 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -497,7 +497,7 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; color:#00ff40;">This is some </span><span style=" font-family:'MS Shell Dlg 2'; font-size:16pt; color:#a33c3e;">colored text and </span><a href="https://www.google.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">link</span></a></p></body></html> - Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + Qt::TextSelectableByMouse diff --git a/gui/newrecipedialog.ui b/gui/newrecipedialog.ui index 5248942..0482bfe 100644 --- a/gui/newrecipedialog.ui +++ b/gui/newrecipedialog.ui @@ -1,18 +1,382 @@ - + NewRecipeDialog + + true + 0 0 640 - 480 + 640 - - Dialog + + + 0 + 0 + + + New Recipe + + + font: 25 14pt "Noto Sans CJK KR"; + + + + + + + + + + Noto Sans CJK KR + 14 + 3 + false + false + + + + New Recipe Name + + + Qt::AlignCenter + + + + + + + Qt::AlignCenter + + + Recipe Name + + + + + + + + + + + + + Prep Time + + + Qt::AlignCenter + + + + + + + + 0 + 0 + 0 + 1999 + 12 + 29 + + + + QDateTimeEdit::HourSection + + + hh:mm:ss + + + Qt::UTC + + + + + + + + + + + + + + + + Cook Time + + + Qt::AlignCenter + + + + + + + QDateTimeEdit::HourSection + + + hh:mm:ss + + + Qt::UTC + + + + + + + + + + + + + + + + Servings + + + Qt::AlignCenter + + + + + + + 1 + + + 1.000000000000000 + + + + + + + + + + + + + + 0 + 0 + + + + + QLayout::SetMaximumSize + + + + + Ingredients + + + Qt::AlignCenter + + + + + + + + + + 100 + + + + + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Add Ingredient + + + Qt::AlignCenter + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + + + New + + + + + + + + + + + 0 + 36 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Noto Sans CJK KR + 14 + 3 + false + false + + + + Amount + + + + + + + + 0 + 0 + + + + 10000.000000000000000 + + + 1.000000000000000 + + + + + + + + + + + + + + 0 + 0 + + + + false + + + Qt::AlignCenter + + + Comments + + + false + + + + + + + Add + + + + + + + + + + + + + + + + diff --git a/main.cpp b/main.cpp index 1cadc3c..38b8ee6 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include "userInterface/mainwindow.h" +#include "gui/newrecipedialog.h" #include #include "model/database/database.h" @@ -29,5 +30,9 @@ int main(int argc, char *argv[]) w.loadFromRecipe(reloadRec); + NewRecipeDialog d; + d.show(); + d.exec(); + return a.exec(); } -- 2.34.1 From ceab72177a88a38c8f48725a1a9e01e5e0c8d572 Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Sat, 10 Mar 2018 08:51:17 +0100 Subject: [PATCH 3/5] Added units as a table, populate ingredient and unit boxes in new recipe dialog. --- gui/newrecipedialog.cpp | 36 +++++- gui/newrecipedialog.h | 14 +++ gui/newrecipedialog.ui | 112 ++++++++++++------ main.cpp | 14 +-- model/database/database.cpp | 5 +- model/database/recipedatabase.cpp | 104 ++++++++++++---- model/database/recipedatabase.h | 7 +- model/recipe/ingredients/recipeingredient.cpp | 6 +- model/recipe/ingredients/recipeingredient.h | 4 +- model/recipe/ingredients/unitofmeasure.cpp | 10 +- model/recipe/ingredients/unitofmeasure.h | 3 +- 11 files changed, 234 insertions(+), 81 deletions(-) diff --git a/gui/newrecipedialog.cpp b/gui/newrecipedialog.cpp index 818f180..15364f0 100644 --- a/gui/newrecipedialog.cpp +++ b/gui/newrecipedialog.cpp @@ -3,12 +3,40 @@ NewRecipeDialog::NewRecipeDialog(QWidget *parent) : QDialog(parent), - ui(new Ui::NewRecipeDialog) -{ + ui(new Ui::NewRecipeDialog){ ui->setupUi(this); } -NewRecipeDialog::~NewRecipeDialog() -{ +NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecipeDialog(parent){ + this->recipeDB = db; + + + this->populateIngredientsBox(); + this->populateUnitsBox(); +} + +NewRecipeDialog::~NewRecipeDialog(){ delete ui; } + +void NewRecipeDialog::on_toolButton_clicked(){ + ui->instructionsTextEdit->setFontItalic(!ui->instructionsTextEdit->fontItalic()); +} + +void NewRecipeDialog::populateIngredientsBox(){ + this->ingredients = this->recipeDB->retrieveAllIngredients(); + ui->ingredientNameBox->clear(); + for (unsigned int i = 0; i < this->ingredients.size(); i++){ + QString s = QString::fromStdString(this->ingredients[i].getName()); + ui->ingredientNameBox->insertItem(i, s); + } +} + +void NewRecipeDialog::populateUnitsBox(){ + this->units = this->recipeDB->retrieveAllUnitsOfMeasure(); + ui->unitComboBox->clear(); + for (unsigned int i = 0; i < this->units.size(); i++){ + QString s = QString::fromStdString(this->units[i].getName()); + ui->unitComboBox->insertItem(i, s); + } +} diff --git a/gui/newrecipedialog.h b/gui/newrecipedialog.h index 30c34a2..81272e4 100644 --- a/gui/newrecipedialog.h +++ b/gui/newrecipedialog.h @@ -2,6 +2,9 @@ #define NEWRECIPEDIALOG_H #include +#include + +#include "model/database/recipedatabase.h" namespace Ui { class NewRecipeDialog; @@ -13,10 +16,21 @@ class NewRecipeDialog : public QDialog public: explicit NewRecipeDialog(QWidget *parent = 0); + NewRecipeDialog(RecipeDatabase *db, QWidget *parent = 0); ~NewRecipeDialog(); + private slots: + void on_toolButton_clicked(); + private: Ui::NewRecipeDialog *ui; + RecipeDatabase *recipeDB; + vector ingredients; + vector units; + + //Helper functions to fill fields. + void populateIngredientsBox(); + void populateUnitsBox(); }; #endif // NEWRECIPEDIALOG_H diff --git a/gui/newrecipedialog.ui b/gui/newrecipedialog.ui index 0482bfe..9be836e 100644 --- a/gui/newrecipedialog.ui +++ b/gui/newrecipedialog.ui @@ -10,7 +10,7 @@ 0 0 640 - 640 + 689 @@ -22,40 +22,43 @@ New Recipe - - font: 25 14pt "Noto Sans CJK KR"; - - + - - - - Noto Sans CJK KR - 14 - 3 - false - false - - - - New Recipe Name - - - Qt::AlignCenter - - - - - - - Qt::AlignCenter - - - Recipe Name - + + + + + + + Noto Sans CJK KR + 14 + 50 + false + false + + + + Edit Recipe + + + Qt::AlignCenter + + + + + + + Qt::AlignCenter + + + Recipe Name + + + + @@ -83,7 +86,7 @@ 0 1999 12 - 29 + 28 @@ -185,7 +188,7 @@ QLayout::SetMaximumSize - + Ingredients @@ -198,7 +201,7 @@ - + 100 @@ -303,7 +306,7 @@ Noto Sans CJK KR 14 - 3 + 50 false false @@ -329,12 +332,12 @@ + + + - - - @@ -373,6 +376,39 @@ + + + + + + + Instructions + + + Qt::AlignCenter + + + + + + + italics + + + Qt::ToolButtonIconOnly + + + + + + + Enter instructions here. + + + + + + diff --git a/main.cpp b/main.cpp index 38b8ee6..3f700e5 100644 --- a/main.cpp +++ b/main.cpp @@ -16,21 +16,21 @@ int main(int argc, char *argv[]) RecipeDatabase recipeDB("recipes"); //TESTING CODE -// vector ri; -// ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c"))); -// ri.push_back(RecipeIngredient("Baking Powder", "Additives", 1.0f, UnitOfMeasure("Teaspoon", "Teaspoons", "Tsp"))); + vector ri; + ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c", UnitOfMeasure::VOLUME, 1.0), "")); + ri.push_back(RecipeIngredient("Baking Powder", "Additives", 1.0f, UnitOfMeasure("Teaspoon", "Teaspoons", "Tsp", UnitOfMeasure::VOLUME, 1.0), "")); -// Recipe rec("Example", ri, Instruction("BOLDiTaLiCs"), QImage(), vector(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f); + Recipe rec("Example", ri, Instruction("BOLDiTaLiCs"), QImage(), vector(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f); -// bool success = recipeDB.storeRecipe(rec); -// printf("Storage successful: %d\n", success); + bool success = recipeDB.storeRecipe(rec); + printf("Storage successful: %d\n", success); Recipe reloadRec = recipeDB.retrieveRecipe("Example"); reloadRec.print(); w.loadFromRecipe(reloadRec); - NewRecipeDialog d; + NewRecipeDialog d(&recipeDB); d.show(); d.exec(); diff --git a/model/database/database.cpp b/model/database/database.cpp index 6fb4394..636a137 100644 --- a/model/database/database.cpp +++ b/model/database/database.cpp @@ -42,7 +42,7 @@ ResultTable Database::selectFrom(string tableName, string columnNames, string co if (columnNames.size() == 0 || tableName.empty()){ return ResultTable(); } - string query = "SELECT " + columnNames + " FROM " + tableName + " WHERE " + conditions + ";"; + string query = "SELECT " + columnNames + " FROM " + tableName + " " + conditions + ";"; return this->executeSQL(query); } @@ -81,8 +81,7 @@ bool Database::tableExists(string tableName){ if (tableName.empty() || this->db == NULL || !this->dbIsOpen){ return false; } - ResultTable t = this->selectFrom("sqlite_master", "name", "type='table' AND name='"+tableName+"'"); - //ResultTable t = executeSQL("SELECT name FROM sqlite_master WHERE type='table' AND name='"+tableName+"';"); + ResultTable t = this->selectFrom("sqlite_master", "name", "WHERE type='table' AND name='"+tableName+"'"); return !t.isEmpty(); } diff --git a/model/database/recipedatabase.cpp b/model/database/recipedatabase.cpp index bc23000..37f23ce 100644 --- a/model/database/recipedatabase.cpp +++ b/model/database/recipedatabase.cpp @@ -5,9 +5,9 @@ RecipeDatabase::RecipeDatabase(string filename) : Database(filename){ } bool RecipeDatabase::storeRecipe(Recipe recipe){ - ///TODO: Implement this in a smart way using transaction. + //Store a recipe, if it doesn't already exist. This first tries to create the recipe entry, then all subsequent supporting table entries. this->executeSQL("BEGIN;"); - ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(recipe.getName(), "'")); + ResultTable t = this->selectFrom("recipe", "*", "WHERE name="+surroundString(recipe.getName(), "'")); if (!t.isEmpty()){ fprintf(stderr, "Error storing recipe: Recipe with name %s already exists.\n", recipe.getName().c_str()); } else { @@ -50,17 +50,11 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){ } bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){ - //First check if the base ingredient has been added to the database. This is done within storeIngredient(). - ResultTable t = this->selectFrom("ingredient", "ingredientId", "name="+surroundString(ri.getName(), "'")); - int ingId = 0; - if (t.isEmpty()){ - if (!this->insertInto("ingredient", vector({"foodGroup", "name"}), vector({ri.getFoodGroup(), ri.getName()}))){ - return false; - } - ingId = this->getLastInsertedRowId(); - } else { - ingId = std::stoi(t.valueAt(0, 0)); - } + int ingId = this->storeIngredient(ri); + if (ingId < 0) return false; + + if (!this->storeUnitOfMeasure(ri.getUnit())) return false; + return this->insertInto("recipeIngredient", vector({ "ingredientId", @@ -78,13 +72,43 @@ bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){ })); } -void RecipeDatabase::storeIngredient(Ingredient ingredient){ - ResultTable t = this->selectFrom("ingredient", "*", "name="+surroundString(ingredient.getName(), "'")); +int RecipeDatabase::storeIngredient(Ingredient ingredient){ + ResultTable t = this->selectFrom("ingredient", "*", "WHERE name="+surroundString(ingredient.getName(), "'")); if (t.isEmpty()){ - this->insertInto("ingredient", vector({"foodGroup", "name"}), vector({ingredient.getFoodGroup(), ingredient.getName()})); + bool success = this->insertInto("ingredient", vector({"foodGroup", "name"}), vector({ingredient.getFoodGroup(), ingredient.getName()})); + if (success){ + return this->getLastInsertedRowId(); + } else { + return -1; + } + } else { + return std::stoi(t.valueAt(0, 0)); } } +bool RecipeDatabase::storeUnitOfMeasure(UnitOfMeasure u){ + ResultTable t = this->selectFrom("unitOfMeasure", "name", "WHERE name="+surroundString(u.getName(), "'")); + if (!t.isEmpty()){ + return true; + } + bool success = this->insertInto("unitOfMeasure", + vector({ + "name", + "plural", + "abbreviation", + "type", + "metricCoefficient" + }), + vector({ + u.getName(), + u.getNamePlural(), + u.getAbbreviation(), + std::to_string(u.getType()), + std::to_string(u.getMetricCoefficient()) + })); + return success; +} + bool RecipeDatabase::storeInstruction(Instruction instruction, int recipeId){ return FileUtils::saveInstruction(recipeId, instruction); } @@ -112,7 +136,7 @@ bool RecipeDatabase::storeTags(vector tags, int recipeId){ } Recipe RecipeDatabase::retrieveRecipe(string name){ - ResultTable t = this->selectFrom("recipe", "*", "name="+surroundString(name, "'")); + ResultTable t = this->selectFrom("recipe", "*", "WHERE name="+surroundString(name, "'")); if (t.isEmpty()){ fprintf(stderr, "Error: No recipe with name %s found!\n", name.c_str()); return Recipe(); @@ -131,19 +155,49 @@ Recipe RecipeDatabase::retrieveRecipe(string name){ } vector RecipeDatabase::retrieveRecipeIngredients(int recipeId){ - ResultTable t = this->executeSQL("SELECT ingredient.name, ingredient.foodGroup, recipeIngredient.quantity, recipeIngredient.unitName, recipeIngredient.comment " + ResultTable t = this->executeSQL("SELECT ingredient.name, ingredient.foodGroup, "//0, 1 + "recipeIngredient.quantity, recipeIngredient.unitName, recipeIngredient.comment,"//2, 3, 4 + "unitOfMeasure.name, unitOfMeasure.plural, unitOfMeasure.abbreviation, unitOfMeasure.type, unitOfMeasure.metricCoefficient "//5, 6, 7, 8, 9 "FROM ingredient " "INNER JOIN recipeIngredient " "ON ingredient.ingredientId = recipeIngredient.ingredientId " - "AND recipeIngredient.recipeId = "+std::to_string(recipeId)+";"); + "INNER JOIN unitOfMeasure " + "ON recipeIngredient.unitName = unitOfMeasure.name " + "WHERE recipeIngredient.recipeId = "+std::to_string(recipeId)+";"); vector ings; for (unsigned int row = 0; row < t.rowCount(); row++){ - RecipeIngredient r(t.valueAt(row, 0), t.valueAt(row, 1), std::stof(t.valueAt(row, 2)), UnitOfMeasure(t.valueAt(row, 3))); + RecipeIngredient r(t.valueAt(row, 0), + t.valueAt(row, 1), + std::stof(t.valueAt(row, 2)), + UnitOfMeasure(t.valueAt(row, 5), t.valueAt(row, 6), t.valueAt(row, 7), std::stoi(t.valueAt(row, 8)), std::stod(t.valueAt(row, 9))), + t.valueAt(row, 4)); ings.push_back(r); } return ings; } +vector RecipeDatabase::retrieveAllIngredients(){ + ResultTable t = this->selectFrom("ingredient", "*", "ORDER BY name"); + vector ings; + for (unsigned int row = 0; row < t.rowCount(); row++){ + Ingredient i(t.valueAt(row, 2), t.valueAt(row, 1)); + ings.push_back(i); + } + return ings; +} + +vector RecipeDatabase::retrieveAllUnitsOfMeasure(){ + ResultTable t = this->selectFrom("unitOfMeasure", "*", "ORDER BY name"); + vector units; + if (!t.isEmpty()){ + for (unsigned int row = 0; row < t.rowCount(); row++){ + UnitOfMeasure u(t.valueAt(row, 0), t.valueAt(row, 1), t.valueAt(row, 2), std::stoi(t.valueAt(row, 3)), std::stod(t.valueAt(row, 4))); + units.push_back(u); + } + } + return units; +} + void RecipeDatabase::ensureTablesExist(){ //Make sure that foreign keys are enabled. this->executeSQL("PRAGMA foreign_keys = ON;"); @@ -154,6 +208,13 @@ void RecipeDatabase::ensureTablesExist(){ "ingredientId INTEGER PRIMARY KEY," "foodGroup varchar," "name varchar UNIQUE);"); + //Unit of Measure table. + this->executeSQL("CREATE TABLE IF NOT EXISTS unitOfMeasure(" + "name varchar UNIQUE PRIMARY KEY," + "plural varchar," + "abbreviation varchar," + "type int," + "metricCoefficient real);"); //Recipe table. Each recipe can have at most one instruction, and one image. this->executeSQL("CREATE TABLE IF NOT EXISTS recipe(" "recipeId INTEGER PRIMARY KEY," @@ -175,6 +236,7 @@ void RecipeDatabase::ensureTablesExist(){ "unitName varchar," "comment varchar," "FOREIGN KEY (ingredientId) REFERENCES ingredient(ingredientId)," - "FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));"); + "FOREIGN KEY (recipeId) REFERENCES recipe(recipeId)," + "FOREIGN KEY (unitName) REFERENCES unitOfMeasure(name));"); this->executeSQL("COMMIT;"); } diff --git a/model/database/recipedatabase.h b/model/database/recipedatabase.h index e91b45d..446536c 100644 --- a/model/database/recipedatabase.h +++ b/model/database/recipedatabase.h @@ -22,14 +22,19 @@ class RecipeDatabase : public Database bool storeRecipe(Recipe recipe); //SQL Helper methods. + //Storage. bool storeRecipeIngredient(RecipeIngredient ri, int recipeId); - void storeIngredient(Ingredient ingredient); + int storeIngredient(Ingredient ingredient); + bool storeUnitOfMeasure(UnitOfMeasure u); bool storeInstruction(Instruction instruction, int recipeId); bool storeImage(QImage image, int recipeId); bool storeTags(vector tags, int recipeId); + //Retrieval. Recipe retrieveRecipe(string name); vector retrieveRecipeIngredients(int recipeId); + vector retrieveAllIngredients(); + vector retrieveAllUnitsOfMeasure(); private: //Utility methods. diff --git a/model/recipe/ingredients/recipeingredient.cpp b/model/recipe/ingredients/recipeingredient.cpp index c48155c..7a3b75a 100644 --- a/model/recipe/ingredients/recipeingredient.cpp +++ b/model/recipe/ingredients/recipeingredient.cpp @@ -1,15 +1,17 @@ #include "model/recipe/ingredients/recipeingredient.h" -RecipeIngredient::RecipeIngredient(string name, string foodGroup, float quantity, UnitOfMeasure unit) : Ingredient(name, foodGroup){ +RecipeIngredient::RecipeIngredient(string name, string foodGroup, float quantity, UnitOfMeasure unit, string comment) : Ingredient(name, foodGroup){ setQuantity(quantity); setUnit(unit); + setComment(comment); } -RecipeIngredient::RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure unit){ +RecipeIngredient::RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure unit, string comment){ setName(i.getName()); setFoodGroup(i.getFoodGroup()); setQuantity(quantity); setUnit(unit); + setComment(comment); } RecipeIngredient::RecipeIngredient(){ diff --git a/model/recipe/ingredients/recipeingredient.h b/model/recipe/ingredients/recipeingredient.h index 70c20f6..ae5fef9 100644 --- a/model/recipe/ingredients/recipeingredient.h +++ b/model/recipe/ingredients/recipeingredient.h @@ -16,9 +16,9 @@ class RecipeIngredient : public Ingredient { public: //Constructor for new RecipeIngredient without starting child ingredient. - RecipeIngredient(string name, string foodGroup, float quantity, UnitOfMeasure unit); + RecipeIngredient(string name, string foodGroup, float quantity, UnitOfMeasure unit, string comment); //Constructor using data from a child ingredient. - RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure unit); + RecipeIngredient(Ingredient i, float quantity, UnitOfMeasure unit, string comment); RecipeIngredient(); //Getters diff --git a/model/recipe/ingredients/unitofmeasure.cpp b/model/recipe/ingredients/unitofmeasure.cpp index 7b4a0f8..dedcb75 100644 --- a/model/recipe/ingredients/unitofmeasure.cpp +++ b/model/recipe/ingredients/unitofmeasure.cpp @@ -1,10 +1,11 @@ #include "unitofmeasure.h" -UnitOfMeasure::UnitOfMeasure(string name, string plural, string abbreviation, int type){ +UnitOfMeasure::UnitOfMeasure(string name, string plural, string abbreviation, int type, double coef){ this->name = name; this->plural = plural; this->abbreviation = abbreviation; this->type = type; + this->metricCoefficient = coef; } UnitOfMeasure::UnitOfMeasure(string name){ @@ -12,10 +13,11 @@ UnitOfMeasure::UnitOfMeasure(string name){ this->plural = name + "s"; this->abbreviation = "NULL"; this->type = MISC; + this->metricCoefficient = 1; ///TODO: Make actual guessing of this stuff. } -UnitOfMeasure::UnitOfMeasure() : UnitOfMeasure::UnitOfMeasure("", "", "", MISC){ +UnitOfMeasure::UnitOfMeasure() : UnitOfMeasure::UnitOfMeasure("", "", "", MISC, 1.0){ //Default constructor initializes all fields to empty strings. } @@ -34,3 +36,7 @@ string UnitOfMeasure::getAbbreviation() const{ int UnitOfMeasure::getType() const{ return this->type; } + +double UnitOfMeasure::getMetricCoefficient() const{ + return this->metricCoefficient; +} diff --git a/model/recipe/ingredients/unitofmeasure.h b/model/recipe/ingredients/unitofmeasure.h index 1197089..b446e2e 100644 --- a/model/recipe/ingredients/unitofmeasure.h +++ b/model/recipe/ingredients/unitofmeasure.h @@ -19,7 +19,7 @@ public: static const int MISC = 4; //Full constructor. - UnitOfMeasure(string name, string plural, string abbreviation, int type); + UnitOfMeasure(string name, string plural, string abbreviation, int type, double coef); //Attempt to guess unit from just a string. UnitOfMeasure(string name); //Constructor with default values. @@ -30,6 +30,7 @@ public: string getNamePlural() const; string getAbbreviation() const; int getType() const; + double getMetricCoefficient() const; private: string name; //The name of the unit of measure. string plural; //The plural name. -- 2.34.1 From 61711323ccfc3438fdbd079f653f0ed867b7c7ba Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Sat, 10 Mar 2018 10:42:22 +0100 Subject: [PATCH 4/5] Polished up adding ingredients to the recipes list. --- gui/mainwindow.ui | 8 ++- gui/newrecipedialog.cpp | 26 +++++-- gui/newrecipedialog.h | 8 ++- gui/newrecipedialog.ui | 67 ++++++++++++++++--- main.cpp | 6 +- .../ingredients/ingredientlistmodel.cpp | 37 +++++++++- .../recipe/ingredients/ingredientlistmodel.h | 6 ++ 7 files changed, 139 insertions(+), 19 deletions(-) diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index e93bbfd..ae24fae 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -462,6 +462,12 @@ QPushButton#browseButton:pressed{ + + + Noto Sans CJK KR Medium + PreferAntialias + + background-color: rgb(244, 244, 244); @@ -493,7 +499,7 @@ QPushButton#browseButton:pressed{ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Liberation Serif Bold'; font-size:11pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Noto Sans CJK KR Medium'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; color:#00ff40;">This is some </span><span style=" font-family:'MS Shell Dlg 2'; font-size:16pt; color:#a33c3e;">colored text and </span><a href="https://www.google.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">link</span></a></p></body></html> diff --git a/gui/newrecipedialog.cpp b/gui/newrecipedialog.cpp index 15364f0..7467d30 100644 --- a/gui/newrecipedialog.cpp +++ b/gui/newrecipedialog.cpp @@ -5,6 +5,8 @@ NewRecipeDialog::NewRecipeDialog(QWidget *parent) : QDialog(parent), ui(new Ui::NewRecipeDialog){ ui->setupUi(this); + + ui->ingredientsListView->setModel(&this->ingredientListModel); } NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecipeDialog(parent){ @@ -19,10 +21,6 @@ NewRecipeDialog::~NewRecipeDialog(){ delete ui; } -void NewRecipeDialog::on_toolButton_clicked(){ - ui->instructionsTextEdit->setFontItalic(!ui->instructionsTextEdit->fontItalic()); -} - void NewRecipeDialog::populateIngredientsBox(){ this->ingredients = this->recipeDB->retrieveAllIngredients(); ui->ingredientNameBox->clear(); @@ -40,3 +38,23 @@ void NewRecipeDialog::populateUnitsBox(){ ui->unitComboBox->insertItem(i, s); } } + +void NewRecipeDialog::on_addIngredientButton_clicked(){ + //Construct a recipe ingredient from the supplied data. + Ingredient i = this->ingredients[ui->ingredientNameBox->currentIndex()]; + UnitOfMeasure u = this->units[ui->unitComboBox->currentIndex()]; + RecipeIngredient ri(i, ui->quantitySpinBox->value(), u, ui->commentsLineEdit->text().toStdString()); + this->ingredientListModel.addIngredient(ri); +} + +void NewRecipeDialog::on_italicsButton_clicked(){ + ui->instructionsTextEdit->setFontItalic(ui->italicsButton->isChecked()); +} + +void NewRecipeDialog::on_boldButton_clicked(){ + if (ui->boldButton->isChecked()){ + ui->instructionsTextEdit->setFontWeight(QFont::Bold); + } else { + ui->instructionsTextEdit->setFontWeight(QFont::Normal); + } +} diff --git a/gui/newrecipedialog.h b/gui/newrecipedialog.h index 81272e4..51322ed 100644 --- a/gui/newrecipedialog.h +++ b/gui/newrecipedialog.h @@ -5,6 +5,7 @@ #include #include "model/database/recipedatabase.h" +#include "model/recipe/ingredients/ingredientlistmodel.h" namespace Ui { class NewRecipeDialog; @@ -20,13 +21,18 @@ class NewRecipeDialog : public QDialog ~NewRecipeDialog(); private slots: - void on_toolButton_clicked(); + void on_addIngredientButton_clicked(); + + void on_italicsButton_clicked(); + + void on_boldButton_clicked(); private: Ui::NewRecipeDialog *ui; RecipeDatabase *recipeDB; vector ingredients; vector units; + IngredientListModel ingredientListModel; //Helper functions to fill fields. void populateIngredientsBox(); diff --git a/gui/newrecipedialog.ui b/gui/newrecipedialog.ui index 9be836e..91c523e 100644 --- a/gui/newrecipedialog.ui +++ b/gui/newrecipedialog.ui @@ -86,7 +86,7 @@ 0 1999 12 - 28 + 27 @@ -160,7 +160,7 @@ - + 1 @@ -335,6 +335,13 @@ + + + + New + + + @@ -389,14 +396,54 @@ - - - - italics - - - Qt::ToolButtonIconOnly - + + + + + + + + Liberation Serif + 12 + true + + + + I + + + true + + + Qt::ToolButtonIconOnly + + + + + + + + Liberation Serif + 12 + 75 + true + + + + B + + + true + + + false + + + false + + + + diff --git a/main.cpp b/main.cpp index 3f700e5..5d09adf 100644 --- a/main.cpp +++ b/main.cpp @@ -18,13 +18,17 @@ int main(int argc, char *argv[]) //TESTING CODE vector ri; ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c", UnitOfMeasure::VOLUME, 1.0), "")); - ri.push_back(RecipeIngredient("Baking Powder", "Additives", 1.0f, UnitOfMeasure("Teaspoon", "Teaspoons", "Tsp", UnitOfMeasure::VOLUME, 1.0), "")); + ri.push_back(RecipeIngredient("baking powder", "Additives", 1.0f, UnitOfMeasure("teaspoon", "teaspoons", "tsp", UnitOfMeasure::VOLUME, 1.0), "")); Recipe rec("Example", ri, Instruction("BOLDiTaLiCs"), QImage(), vector(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f); bool success = recipeDB.storeRecipe(rec); printf("Storage successful: %d\n", success); + recipeDB.storeUnitOfMeasure(UnitOfMeasure("tablespoon", "tablespoons", "tbsp", UnitOfMeasure::VOLUME, 1.0)); + recipeDB.storeUnitOfMeasure(UnitOfMeasure("pinch", "pinches", "pch", UnitOfMeasure::VOLUME, 1.0)); + recipeDB.storeUnitOfMeasure(UnitOfMeasure("gram", "grams", "g", UnitOfMeasure::MASS, 1.0)); + Recipe reloadRec = recipeDB.retrieveRecipe("Example"); reloadRec.print(); diff --git a/model/recipe/ingredients/ingredientlistmodel.cpp b/model/recipe/ingredients/ingredientlistmodel.cpp index bd1a41e..1370bc7 100644 --- a/model/recipe/ingredients/ingredientlistmodel.cpp +++ b/model/recipe/ingredients/ingredientlistmodel.cpp @@ -18,7 +18,8 @@ QVariant IngredientListModel::data(const QModelIndex &index, int role) const{ //The quantity is an integer and should be casted. displayStr += std::to_string((int)i.getQuantity()); } else { - displayStr += std::to_string(i.getQuantity()); + float q = i.getQuantity(); + displayStr += toString(q); } displayStr += " " + i.getUnit().getAbbreviation() + " " + i.getName(); @@ -35,5 +36,37 @@ void IngredientListModel::setIngredients(vector ingredients){ this->ingredients = ingredients; QModelIndex index = createIndex(0, 0); QModelIndex bottomIndex = createIndex(ingredients.size()-1, 0); - emit dataChanged(index, bottomIndex); + emit dataChanged(index, bottomIndex); +} + +bool IngredientListModel::addIngredient(RecipeIngredient ri){ + //Add only if it doesn't exist already. + for (unsigned int i = 0; i < this->ingredients.size(); i++){ + if (!this->ingredients[i].getName().compare(ri.getName())){ + return false; + } + } + this->ingredients.push_back(ri); + QModelIndex index = createIndex(this->ingredients.size()-1, 0); + QModelIndex bottomIndex = createIndex(this->ingredients.size()-1, 0); + emit dataChanged(index, bottomIndex); + return true; +} + +vector IngredientListModel::getIngredients(){ + return this->ingredients; +} + +string toString(float val){ + float decimal = std::fmod(val, 1.0f); + int places = 1; + while (std::fmod(decimal * 10, 1.0f) > 0){ + decimal *= 10; + places++; + } + char buffer[50]; + string arg = "%."+std::to_string(places)+"f"; + sprintf(buffer, arg.c_str(), val); + string s = buffer; + return s; } diff --git a/model/recipe/ingredients/ingredientlistmodel.h b/model/recipe/ingredients/ingredientlistmodel.h index 64ca72a..803c2ca 100644 --- a/model/recipe/ingredients/ingredientlistmodel.h +++ b/model/recipe/ingredients/ingredientlistmodel.h @@ -17,9 +17,15 @@ public: //Custom methods to handle ingredient data. void setIngredients(vector ingredients); + bool addIngredient(RecipeIngredient ri); private: vector ingredients; + + //Helper for printing. + }; +string toString(float val); + #endif // INGREDIENTLISTMODEL_H -- 2.34.1 From cb3be5e1e2ae6abab3fbc006480293d5ca9f1949 Mon Sep 17 00:00:00 2001 From: andrewlalis Date: Sat, 10 Mar 2018 12:36:14 +0100 Subject: [PATCH 5/5] Added tags area to dialog, made it look better, and added tag model. --- RecipeDB.pro | 6 +- gui/newrecipedialog.cpp | 43 ++ gui/newrecipedialog.h | 13 + gui/newrecipedialog.ui | 467 +++++++++++++----- main.cpp | 17 +- model/database/recipedatabase.cpp | 25 + model/database/recipedatabase.h | 2 + .../recipe/ingredients/ingredientlistmodel.h | 1 + model/recipe/tags/recipetag.cpp | 2 +- model/recipe/tags/recipetag.h | 2 +- model/recipe/tags/taglistmodel.cpp | 44 ++ model/recipe/tags/taglistmodel.h | 24 + 12 files changed, 516 insertions(+), 130 deletions(-) create mode 100644 model/recipe/tags/taglistmodel.cpp create mode 100644 model/recipe/tags/taglistmodel.h diff --git a/RecipeDB.pro b/RecipeDB.pro index 0153b2b..0071690 100644 --- a/RecipeDB.pro +++ b/RecipeDB.pro @@ -26,7 +26,8 @@ SOURCES += model/recipe/instruction.cpp \ model/database/resulttable.cpp \ model/database/recipedatabase.cpp \ utils/fileutils.cpp \ - gui/newrecipedialog.cpp + gui/newrecipedialog.cpp \ + model/recipe/tags/taglistmodel.cpp HEADERS += model/recipe/instruction.h \ model/recipe/recipe.h \ @@ -42,7 +43,8 @@ HEADERS += model/recipe/instruction.h \ model/database/resulttable.h \ model/database/recipedatabase.h \ utils/fileutils.h \ - gui/newrecipedialog.h + gui/newrecipedialog.h \ + model/recipe/tags/taglistmodel.h LIBS += -ldl \ diff --git a/gui/newrecipedialog.cpp b/gui/newrecipedialog.cpp index 7467d30..7405d09 100644 --- a/gui/newrecipedialog.cpp +++ b/gui/newrecipedialog.cpp @@ -6,7 +6,10 @@ NewRecipeDialog::NewRecipeDialog(QWidget *parent) : ui(new Ui::NewRecipeDialog){ ui->setupUi(this); + setModal(true); + ui->ingredientsListView->setModel(&this->ingredientListModel); + ui->tagsListView->setModel(&this->tagsListModel); } NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecipeDialog(parent){ @@ -15,12 +18,29 @@ NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecip this->populateIngredientsBox(); this->populateUnitsBox(); + this->populateTagsBox(); } NewRecipeDialog::~NewRecipeDialog(){ delete ui; } +Recipe NewRecipeDialog::getRecipe(){ + Recipe r(ui->recipeNameEdit->text().toStdString(), + this->ingredientListModel.getIngredients(), + ui->instructionsTextEdit->toHtml().toStdString(), + QImage(),//Image + this->tagsListModel.getTags(),//Tags + QDate::currentDate(), + ui->prepTimeEdit->time(), + ui->cookTimeEdit->time(), + (float)ui->servingsSpinBox->value()); +} + +bool NewRecipeDialog::isAccepted() const{ + return this->accepted; +} + void NewRecipeDialog::populateIngredientsBox(){ this->ingredients = this->recipeDB->retrieveAllIngredients(); ui->ingredientNameBox->clear(); @@ -39,6 +59,15 @@ void NewRecipeDialog::populateUnitsBox(){ } } +void NewRecipeDialog::populateTagsBox(){ + this->tags = this->recipeDB->retrieveAllTags(); + ui->tagsComboBox->clear(); + for (unsigned int i = 0; i < this->tags.size(); i++){ + QString s = QString::fromStdString(this->tags[i].getValue()); + ui->tagsComboBox->insertItem(i, s); + } +} + void NewRecipeDialog::on_addIngredientButton_clicked(){ //Construct a recipe ingredient from the supplied data. Ingredient i = this->ingredients[ui->ingredientNameBox->currentIndex()]; @@ -58,3 +87,17 @@ void NewRecipeDialog::on_boldButton_clicked(){ ui->instructionsTextEdit->setFontWeight(QFont::Normal); } } + +void NewRecipeDialog::on_buttonBox_accepted(){ + this->accepted = true; + this->close(); +} + +void NewRecipeDialog::on_buttonBox_rejected(){ + this->close(); +} + +void NewRecipeDialog::on_addTagButton_clicked(){ + //Add a tag to the list of those prepared to be added. + this->tagsListModel.addTag(this->tags[ui->tagsComboBox->currentIndex()]); +} diff --git a/gui/newrecipedialog.h b/gui/newrecipedialog.h index 51322ed..47cd848 100644 --- a/gui/newrecipedialog.h +++ b/gui/newrecipedialog.h @@ -6,6 +6,7 @@ #include "model/database/recipedatabase.h" #include "model/recipe/ingredients/ingredientlistmodel.h" +#include "model/recipe/tags/taglistmodel.h" namespace Ui { class NewRecipeDialog; @@ -20,6 +21,8 @@ class NewRecipeDialog : public QDialog NewRecipeDialog(RecipeDatabase *db, QWidget *parent = 0); ~NewRecipeDialog(); + Recipe getRecipe(); + bool isAccepted() const; private slots: void on_addIngredientButton_clicked(); @@ -27,16 +30,26 @@ class NewRecipeDialog : public QDialog void on_boldButton_clicked(); + void on_buttonBox_accepted(); + + void on_buttonBox_rejected(); + + void on_addTagButton_clicked(); + private: Ui::NewRecipeDialog *ui; RecipeDatabase *recipeDB; vector ingredients; vector units; + vector tags; IngredientListModel ingredientListModel; + TagListModel tagsListModel; + bool accepted = false; //Helper functions to fill fields. void populateIngredientsBox(); void populateUnitsBox(); + void populateTagsBox(); }; #endif // NEWRECIPEDIALOG_H diff --git a/gui/newrecipedialog.ui b/gui/newrecipedialog.ui index 91c523e..78e7f57 100644 --- a/gui/newrecipedialog.ui +++ b/gui/newrecipedialog.ui @@ -23,149 +23,309 @@ New Recipe + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - Noto Sans CJK KR - 14 - 50 - false - false - + + + Qt::LeftToRight - - Edit Recipe + + background-color: rgb(234, 235, 255); - - Qt::AlignCenter - - - - - - - Qt::AlignCenter - - - Recipe Name - - - - - - - - - - - - + - - - Prep Time - - - Qt::AlignCenter - + + + + + + + Noto Sans CJK KR + 14 + 50 + false + false + + + + Edit Recipe + + + Qt::AlignCenter + + + + + + + + PreferAntialias + + + + Qt::AlignCenter + + + Recipe Name + + + + - - - - 0 - 0 - 0 - 1999 - 12 - 27 - - - - QDateTimeEdit::HourSection - - - hh:mm:ss - - - Qt::UTC - - - - + + + + + + + + + Prep Time + + + Qt::AlignCenter + + + + + + + + 0 + 0 + 0 + 1999 + 12 + 27 + + + + QDateTimeEdit::HourSection + + + hh:mm:ss + + + Qt::UTC + + + + + + + + + + + + + + + + Cook Time + + + Qt::AlignCenter + + + + + + + QDateTimeEdit::HourSection + + + hh:mm:ss + + + Qt::UTC + + + + + + + + + + + + + + + + Servings + + + Qt::AlignCenter + + + + + + + 1 + + + 1.000000000000000 + + + + + + + - - - - - + + + + background-color: rgb(222, 226, 255); + + + + - Cook Time + Tags Qt::AlignCenter - - - - QDateTimeEdit::HourSection - - - hh:mm:ss - - - Qt::UTC - - - - - - - - - - - - - - - - Servings - - - Qt::AlignCenter - + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + New + + + + - - - 1 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Add + + + + + + + Delete + + + + + + + + + + false - - 1.000000000000000 + + background-color: rgb(255, 255, 255); + + + QFrame::NoFrame @@ -183,10 +343,28 @@ 0 + + background-color: rgb(245, 245, 255); + + + 0 + QLayout::SetMaximumSize + + 0 + + + 0 + + + 0 + + + 0 + @@ -200,14 +378,20 @@ - + + + background-color: rgb(255, 255, 255); + + + QFrame::NoFrame + 100 - + @@ -239,7 +423,7 @@ - 0 + 2 0 @@ -286,7 +470,7 @@ - 0 + 2 0 @@ -368,10 +552,35 @@ - - - Add - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Add + + + + + + + Delete + + + + @@ -456,6 +665,16 @@ + + + + Qt::LeftToRight + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + diff --git a/main.cpp b/main.cpp index 5d09adf..23f8db2 100644 --- a/main.cpp +++ b/main.cpp @@ -18,9 +18,18 @@ int main(int argc, char *argv[]) //TESTING CODE vector ri; ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c", UnitOfMeasure::VOLUME, 1.0), "")); - ri.push_back(RecipeIngredient("baking powder", "Additives", 1.0f, UnitOfMeasure("teaspoon", "teaspoons", "tsp", UnitOfMeasure::VOLUME, 1.0), "")); + ri.push_back(RecipeIngredient("baking powder", "additives", 1.0f, UnitOfMeasure("teaspoon", "teaspoons", "tsp", UnitOfMeasure::VOLUME, 1.0), "")); - Recipe rec("Example", ri, Instruction("BOLDiTaLiCs"), QImage(), vector(), QDate::currentDate(), QTime(0, 30), QTime(0, 25), 10.0f); + Recipe rec("Example", + ri, + Instruction("BOLDiTaLiCs"), + QImage(), + vector({RecipeTag("testing"), + RecipeTag("fake")}), + QDate::currentDate(), + QTime(0, 30), + QTime(0, 25), + 10.0f); bool success = recipeDB.storeRecipe(rec); printf("Storage successful: %d\n", success); @@ -38,5 +47,9 @@ int main(int argc, char *argv[]) d.show(); d.exec(); + if (d.isAccepted()){ + printf("Accepted the dialog.\n"); + } + return a.exec(); } diff --git a/model/database/recipedatabase.cpp b/model/database/recipedatabase.cpp index 37f23ce..b64a660 100644 --- a/model/database/recipedatabase.cpp +++ b/model/database/recipedatabase.cpp @@ -151,6 +151,7 @@ Recipe RecipeDatabase::retrieveRecipe(string name){ r.setInstruction(FileUtils::loadInstruction(id)); r.setImage(FileUtils::loadImage(id)); r.setIngredients(this->retrieveRecipeIngredients(id)); + r.setTags(this->retrieveTags(id)); return r; } @@ -198,6 +199,30 @@ vector RecipeDatabase::retrieveAllUnitsOfMeasure(){ return units; } +vector RecipeDatabase::retrieveTags(int recipeId){ + ResultTable t = this->selectFrom("recipeTag", "tagName", "WHERE recipeId="+std::to_string(recipeId)); + vector tags; + if (!t.isEmpty()){ + for (unsigned int row = 0; row < t.rowCount(); row++){ + RecipeTag tag(t.valueAt(row, 0)); + tags.push_back(tag); + } + } + return tags; +} + +vector RecipeDatabase::retrieveAllTags(){ + ResultTable t = this->selectFrom("recipeTag", "tagName", "ORDER BY tagName"); + vector tags; + if (!t.isEmpty()){ + for (unsigned int row = 0; row < t.rowCount(); row++){ + RecipeTag tag(t.valueAt(row, 0)); + tags.push_back(tag); + } + } + return tags; +} + void RecipeDatabase::ensureTablesExist(){ //Make sure that foreign keys are enabled. this->executeSQL("PRAGMA foreign_keys = ON;"); diff --git a/model/database/recipedatabase.h b/model/database/recipedatabase.h index 446536c..f1d9867 100644 --- a/model/database/recipedatabase.h +++ b/model/database/recipedatabase.h @@ -35,6 +35,8 @@ class RecipeDatabase : public Database vector retrieveRecipeIngredients(int recipeId); vector retrieveAllIngredients(); vector retrieveAllUnitsOfMeasure(); + vector retrieveTags(int recipeId); + vector retrieveAllTags(); private: //Utility methods. diff --git a/model/recipe/ingredients/ingredientlistmodel.h b/model/recipe/ingredients/ingredientlistmodel.h index 803c2ca..1f3605c 100644 --- a/model/recipe/ingredients/ingredientlistmodel.h +++ b/model/recipe/ingredients/ingredientlistmodel.h @@ -18,6 +18,7 @@ public: //Custom methods to handle ingredient data. void setIngredients(vector ingredients); bool addIngredient(RecipeIngredient ri); + vector getIngredients(); private: vector ingredients; diff --git a/model/recipe/tags/recipetag.cpp b/model/recipe/tags/recipetag.cpp index 22cd27d..3b1442a 100644 --- a/model/recipe/tags/recipetag.cpp +++ b/model/recipe/tags/recipetag.cpp @@ -8,7 +8,7 @@ RecipeTag::RecipeTag(string val){ this->value = val; } -string RecipeTag::getValue(){ +string RecipeTag::getValue() const{ return this->value; } diff --git a/model/recipe/tags/recipetag.h b/model/recipe/tags/recipetag.h index 5613af7..cd382fe 100644 --- a/model/recipe/tags/recipetag.h +++ b/model/recipe/tags/recipetag.h @@ -16,7 +16,7 @@ public: RecipeTag(string val); //Getters - string getValue(); + string getValue() const; //Setters void setValue(string newValue); private: diff --git a/model/recipe/tags/taglistmodel.cpp b/model/recipe/tags/taglistmodel.cpp new file mode 100644 index 0000000..dd70b3f --- /dev/null +++ b/model/recipe/tags/taglistmodel.cpp @@ -0,0 +1,44 @@ +#include "taglistmodel.h" + +TagListModel::TagListModel(){ + +} + +int TagListModel::rowCount(const QModelIndex &parent) const{ + return this->tags.size(); +} + +QVariant TagListModel::data(const QModelIndex &index, int role) const{ + string displayString = this->tags[index.row()].getValue(); + switch(role){ + case Qt::DisplayRole: + return QString::fromStdString(displayString); + } + + return QVariant(); +} + +void TagListModel::setTags(vector tags){ + this->tags = tags; + QModelIndex index = createIndex(0, 0); + QModelIndex bottomIndex = createIndex(this->tags.size()-1, 0); + emit dataChanged(index, bottomIndex); +} + +bool TagListModel::addTag(RecipeTag tag){ + //Add only if it's different. + for (unsigned int i = 0; i < this->tags.size(); i++){ + if (!this->tags[i].getValue().compare(tag.getValue())){ + return false; + } + } + this->tags.push_back(tag); + QModelIndex index = createIndex(this->tags.size()-1, 0); + QModelIndex bottomIndex = createIndex(this->tags.size()-1, 0); + emit dataChanged(index, bottomIndex); + return true; +} + +vector TagListModel::getTags(){ + return this->tags; +} diff --git a/model/recipe/tags/taglistmodel.h b/model/recipe/tags/taglistmodel.h new file mode 100644 index 0000000..e524e23 --- /dev/null +++ b/model/recipe/tags/taglistmodel.h @@ -0,0 +1,24 @@ +#ifndef TAGLISTMODEL_H +#define TAGLISTMODEL_H + +#include + +#include "model/recipe/tags/recipetag.h" + +class TagListModel : public QAbstractListModel +{ + public: + TagListModel(); + //Overridden methods. + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + + void setTags(vector tags); + bool addTag(RecipeTag tag); + vector getTags(); + private: + vector tags; +}; + +#endif // TAGLISTMODEL_H -- 2.34.1