Stable first release #10

Merged
andrewlalis merged 3 commits from development into master 2018-03-31 18:36:02 +00:00
22 changed files with 654 additions and 115 deletions

View File

@ -19,6 +19,10 @@ MainWindow::~MainWindow(){
}
void MainWindow::loadFromRecipe(Recipe recipe){
if (recipe.isEmpty()){
setRecipeName("No recipes found.");
setAuthorName("Click 'New' to get started.");
} else {
setRecipeName(recipe.getName());
setInstruction(recipe.getInstruction());
setIngredients(recipe.getIngredients());
@ -32,6 +36,7 @@ void MainWindow::loadFromRecipe(Recipe recipe){
setServings(recipe.getServings());
setTags(recipe.getTags());
this->currentRecipe = recipe;
}
}
void MainWindow::setRecipeName(string name){
@ -66,6 +71,10 @@ void MainWindow::setTags(vector<RecipeTag> tags){
this->tagsListModel.setTags(tags);
}
void MainWindow::setAuthorName(string name){
ui->authorLabel->setText(QString::fromStdString(name));
}
void MainWindow::on_newButton_clicked(){
NewRecipeDialog d(this->recipeDB, this);
d.show();
@ -95,11 +104,12 @@ void MainWindow::on_exitButton_clicked(){
void MainWindow::on_editButton_clicked(){
NewRecipeDialog d(this->recipeDB, this->currentRecipe, this);
string originalName = this->currentRecipe.getName();
d.show();
d.exec();
if (d.isAccepted()){
Recipe r = d.getRecipe();
if (!this->recipeDB->storeRecipe(r)){
if (!this->recipeDB->updateRecipe(r, originalName)){
QMessageBox::critical(this, QString("Unable to Save Recipe"), QString("The program was not able to successfully save the recipe. Make sure to give the recipe a name, instructions, and some ingredients!"));
} else {
this->loadFromRecipe(r);

View File

@ -54,6 +54,7 @@ public:
void setCookTime(QTime cookTime);
void setServings(float servings);
void setTags(vector<RecipeTag> tags);
void setAuthorName(string name);
};
#endif // MAINWINDOW_H

View File

@ -364,7 +364,7 @@ font: &quot;Noto Sans CJK KR&quot;;</string>
<item alignment="Qt::AlignLeft|Qt::AlignBottom">
<widget class="QLabel" name="authorLabel">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">

View File

@ -23,6 +23,7 @@ NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecip
NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, Recipe recipe, QWidget *parent) : NewRecipeDialog(db, parent){
ui->recipeNameEdit->setText(QString::fromStdString(recipe.getName()));
ui->authorNameEdit->setText(QString::fromStdString(recipe.getAuthor()));
ui->prepTimeEdit->setTime(recipe.getPrepTime());
ui->cookTimeEdit->setTime(recipe.getCookTime());
ui->servingsSpinBox->setValue((double)recipe.getServings());
@ -38,9 +39,10 @@ NewRecipeDialog::~NewRecipeDialog(){
Recipe NewRecipeDialog::getRecipe(){
Recipe r(ui->recipeNameEdit->text().toStdString(),
ui->authorNameEdit->text().toStdString(),
this->ingredientListModel.getIngredients(),
ui->instructionsTextEdit->toHtml().toStdString(),
this->img,//Image
ui->imageDisplayLabel->pixmap()->toImage(),//Image
this->tagsListModel.getTags(),//Tags
QDate::currentDate(),
ui->prepTimeEdit->time(),
@ -126,7 +128,6 @@ void NewRecipeDialog::on_deleteTagButton_clicked(){
void NewRecipeDialog::on_selectImageButton_clicked(){
QString filename = QFileDialog::getOpenFileName(this, "Open Image", QString(), "Image Files (*.png *.jpg *.bmp)");
if (!filename.isEmpty()){
this->img = QImage(filename);
ui->imageDisplayLabel->setPixmap(QPixmap(filename));
}
}

View File

@ -70,7 +70,6 @@ class NewRecipeDialog : public QDialog
vector<RecipeTag> tags;
RecipeIngredientListModel ingredientListModel;
TagListModel tagsListModel;
QImage img;
bool accepted = false;
//Helper functions to fill fields.

View File

@ -96,16 +96,25 @@
<item>
<widget class="QWidget" name="recipeNamePanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="recipeNameEdit">
<property name="font">
<font>
<pointsize>16</pointsize>
<pointsize>14</pointsize>
<weight>3</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
@ -114,6 +123,30 @@
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="authorNameEdit">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>3</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(245, 245, 255);</string>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="placeholderText">
<string>Author</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -142,7 +175,7 @@
<second>0</second>
<year>1999</year>
<month>12</month>
<day>24</day>
<day>22</day>
</datetime>
</property>
<property name="currentSection">
@ -253,6 +286,9 @@
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="newTagBoxPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -286,6 +322,9 @@
<property name="toolTip">
<string>Create a new tag</string>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/plus_icon.png</normaloff>:/images/images/plus_icon.png</iconset>
@ -297,6 +336,9 @@
<property name="toolTip">
<string>Permanently delete this tag</string>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/minus_icon.png</normaloff>:/images/images/minus_icon.png</iconset>
@ -309,6 +351,9 @@
<item>
<widget class="QWidget" name="tagsListControlPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -323,6 +368,27 @@
</property>
<item>
<widget class="QPushButton" name="addTagButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="toolTip">
<string>Add the above tag to the recipe</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#addTagButton {
background-color: rgb(235, 235, 255);
border: 0px;
}
QPushButton#addTagButton:hover{
background-color: rgb(245, 245, 255);
}
QPushButton#addTagButton:pressed{
background-color: rgb(255, 255, 255);
}</string>
</property>
<property name="text">
<string>Add</string>
</property>
@ -330,8 +396,29 @@
</item>
<item>
<widget class="QPushButton" name="deleteTagButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="toolTip">
<string>Remove this tag from the recipe</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#deleteTagButton {
background-color: rgb(225, 225, 255);
border: 0px;
}
QPushButton#deleteTagButton:hover{
background-color: rgb(235, 235, 255);
}
QPushButton#deleteTagButton:pressed{
background-color: rgb(245, 245, 255);
}</string>
</property>
<property name="text">
<string>Delete</string>
<string>Remove</string>
</property>
</widget>
</item>
@ -352,6 +439,9 @@
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
@ -432,7 +522,7 @@
<item>
<widget class="QLabel" name="addIngredientLabel">
<property name="text">
<string>Add Ingredient</string>
<string>Ingredients</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@ -495,6 +585,9 @@
</item>
<item>
<widget class="QPushButton" name="deleteIngredientButton">
<property name="toolTip">
<string>Delete this ingredient</string>
</property>
<property name="text">
<string/>
</property>
@ -579,6 +672,9 @@
</item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="newUnitButton">
<property name="toolTip">
<string>Create a new unit of measure</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/plus_icon.png</normaloff>:/images/images/plus_icon.png</iconset>
@ -587,6 +683,9 @@
</item>
<item>
<widget class="QPushButton" name="deleteUnitButton">
<property name="toolTip">
<string>Delete this unit of measure</string>
</property>
<property name="text">
<string/>
</property>
@ -624,6 +723,9 @@
<item>
<widget class="QWidget" name="ingredientsListControlPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -638,6 +740,27 @@
</property>
<item>
<widget class="QPushButton" name="addIngredientButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>Add the above ingredient to the recipe</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#addIngredientButton {
background-color: rgb(235, 235, 255);
border: 0px;
}
QPushButton#addIngredientButton:hover{
background-color: rgb(245, 245, 255);
}
QPushButton#addIngredientButton:pressed{
background-color: rgb(255, 255, 255);
}</string>
</property>
<property name="text">
<string>Add</string>
</property>
@ -645,8 +768,29 @@
</item>
<item>
<widget class="QPushButton" name="removeIngredientButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>Remove this ingredient from the recipe</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#removeIngredientButton {
background-color: rgb(225, 225, 255);
border: 0px;
}
QPushButton#removeIngredientButton:hover{
background-color: rgb(235, 235, 255);
}
QPushButton#removeIngredientButton:pressed{
background-color: rgb(245, 245, 255);
}</string>
</property>
<property name="text">
<string>Delete</string>
<string>Remove</string>
</property>
</widget>
</item>
@ -667,6 +811,9 @@
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="batchSize">
<number>100</number>
</property>
@ -746,16 +893,6 @@
<string notr="true">background-color: rgb(250, 250, 255);</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QLabel" name="instructionsLabel">
<property name="text">
<string>Instructions</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft|Qt::AlignTop">
<widget class="QWidget" name="textControlPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
@ -769,7 +906,7 @@
</font>
</property>
<property name="text">
<string>I</string>
<string>Italic</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -789,7 +926,7 @@
</font>
</property>
<property name="text">
<string>B</string>
<string>Bold</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -827,7 +964,7 @@
<enum>Qt::LeftToRight</enum>
</property>
<property name="autoFillBackground">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>

View File

@ -72,7 +72,7 @@ void OpenRecipeDialog::on_deleteRecipeButton_clicked(){
}
string recipePlural = (rows.size() == 1) ? "recipe" : "recipes";
QString title = QString::fromStdString("Delete " + recipePlural);
QString content = QString::fromStdString("Are you sure you wish to delete the selected "+recipePlural+"?");
QString content = QString::fromStdString("Are you sure you wish to delete the selected "+recipePlural+"?\nAll deleted recipes are permanently deleted.");
QMessageBox::StandardButton reply = QMessageBox::question(this, title, content);
if (reply == QMessageBox::Yes){
for (int row : rows){
@ -127,3 +127,15 @@ void OpenRecipeDialog::on_foodGroupsListWidget_itemSelectionChanged(){
}
this->populateRecipesTable(this->recipeDB->retrieveRecipesWithFoodGroups(groups));
}
void OpenRecipeDialog::on_clearSearchButton_clicked(){
ui->nameEdit->clear();
ui->foodGroupsListWidget->selectionModel()->clearSelection();
ui->tagsListView->selectionModel()->clearSelection();
ui->ingredientsListView->selectionModel()->clearSelection();
this->populateRecipesTable(this->recipeDB->retrieveAllRecipes());
}
void OpenRecipeDialog::on_exitButton_clicked(){
this->close();
}

View File

@ -38,6 +38,10 @@ class OpenRecipeDialog : public QDialog
void on_foodGroupsListWidget_itemSelectionChanged();
void on_clearSearchButton_clicked();
void on_exitButton_clicked();
private:
Ui::OpenRecipeDialog *ui;
RecipeDatabase *recipeDB;

View File

@ -17,13 +17,37 @@
<iconset resource="../images.qrc">
<normaloff>:/images/images/icon.png</normaloff>:/images/images/icon.png</iconset>
</property>
<property name="styleSheet">
<string notr="true">font: 25 &quot;Noto Sans CJK KR Light&quot;;</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item alignment="Qt::AlignLeft|Qt::AlignTop">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="searchPanel" native="true">
<property name="styleSheet">
<string notr="true">background-color: rgb(245, 245, 255);</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QTabWidget" name="tabWidget">
<property name="minimumSize">
@ -39,13 +63,35 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>2</number>
<number>1</number>
</property>
<widget class="QWidget" name="tagsTab">
<widget class="QWidget" name="Tags">
<attribute name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/tag.png</normaloff>:/images/images/tag.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Tags</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="tagsListView">
<property name="sizePolicy">
@ -74,10 +120,32 @@
</layout>
</widget>
<widget class="QWidget" name="ingredientsTab">
<attribute name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/ingredients.png</normaloff>:/images/images/ingredients.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Ingredients</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="ingredientsListView">
<property name="sizePolicy">
@ -105,11 +173,33 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab">
<widget class="QWidget" name="foodGroups">
<attribute name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/foodPyramid.png</normaloff>:/images/images/foodPyramid.png</iconset>
</attribute>
<attribute name="title">
<string/>
</attribute>
<attribute name="toolTip">
<string>Food Groups</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="foodGroupsListWidget">
<property name="frameShape">
@ -132,6 +222,9 @@
</item>
<item>
<widget class="QWidget" name="nameSearchPanel" native="true">
<property name="styleSheet">
<string notr="true">background-color: rgb(240, 240, 255);</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="nameLabel">
@ -141,33 +234,83 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameEdit"/>
<widget class="QLineEdit" name="nameEdit">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>3</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="frame">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="placeholderText">
<string>Recipe Name</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="searchButton">
<widget class="QPushButton" name="clearSearchButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#clearSearchButton {
background-color: rgb(235, 235, 255);
border: 0px;
}
QPushButton#clearSearchButton:hover{
background-color: rgb(245, 245, 255);
}
QPushButton#clearSearchButton:pressed{
background-color: rgb(255, 255, 255);
}</string>
</property>
<property name="text">
<string/>
<string>Clear search criteria</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/search_icon.png</normaloff>:/images/images/search_icon.png</iconset>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="contentPanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="interactionPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="deleteRecipeButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#deleteRecipeButton {
background-color: rgb(225, 225, 255);
border: 0px;
}
QPushButton#deleteRecipeButton:hover{
background-color: rgb(235, 235, 255);
}
QPushButton#deleteRecipeButton:pressed{
background-color: rgb(245, 245, 255);
}</string>
</property>
<property name="text">
<string/>
</property>
@ -177,20 +320,86 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exitButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#exitButton {
background-color: rgb(215, 215, 255);
border: 0px;
}
QPushButton#exitButton:hover{
background-color: rgb(225, 225, 255);
}
QPushButton#exitButton:pressed{
background-color: rgb(235, 235, 255);
}</string>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="contentPanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTableView" name="recipeTableView">
<property name="font">
<font>
<pointsize>14</pointsize>
<weight>3</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(250, 250, 255);</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>

View File

@ -6,5 +6,8 @@
<file>images/minus_icon.png</file>
<file>images/search_icon.png</file>
<file>images/trash.png</file>
<file>images/tag.png</file>
<file>images/foodPyramid.png</file>
<file>images/ingredients.png</file>
</qresource>
</RCC>

BIN
images/foodPyramid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
images/ingredients.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
images/tag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -8,23 +8,27 @@
void test(RecipeDatabase *recipeDB);
Recipe checkForFirstRun(RecipeDatabase *recipeDB){
Recipe r = recipeDB->retrieveRandomRecipe();
if (r.isEmpty()){//There are no recipes in the database.
//Add some basic units to the units, and some basic ingredients.
recipeDB->addBasicUnits();
recipeDB->addBasicIngredients();
}
return r;
}
int main(int argc, char *argv[])
{
RecipeDatabase recipeDB(QString(FileUtils::appDataPath+"recipes.db").toStdString());
QApplication a(argc, argv);
MainWindow w(&recipeDB);
w.loadFromRecipe(checkForFirstRun(&recipeDB));
w.show();
//TESTING CODE
test(&recipeDB);
//END TESTING CODE.
w.loadFromRecipe(recipeDB.retrieveRandomRecipe());
a.exec();
recipeDB.closeConnection();
printf("Total queries: %lu\n", recipeDB.getQueryCount());
return 0;
}
@ -35,6 +39,7 @@ void test(RecipeDatabase *recipeDB){
ri.push_back(RecipeIngredient("baking powder", "additives", 1.0f, UnitOfMeasure("teaspoon", "teaspoons", "tsp", UnitOfMeasure::VOLUME, 1.0), ""));
Recipe rec("Example",
"Andrew Lalis",
ri,
Instruction("Placeholder Text"),
QImage(),
@ -48,18 +53,4 @@ void test(RecipeDatabase *recipeDB){
bool success = recipeDB->storeRecipe(rec);
printf("Storage successful: %d\n", success);
// vector<string> foodGroups = recipeDB->retrieveAllFoodGroups();
// printf("Food Groups:\n");
// for (string s : foodGroups){
// printf("\t%s\n", s.c_str());
// }
//Get food groups from recipe.
// Recipe r = recipeDB->retrieveRecipe("Pannenkoeken");
// vector<string> foodGroupsR = r.getFoodGroups();
// printf("Pannenkoeken Food Groups:\n");
// for (string s : foodGroupsR){
// printf("\t%s\n", s.c_str());
// }
}

View File

@ -14,12 +14,11 @@ ResultTable Database::executeSQL(string statement){
sqlite3_stmt* stmt;
this->sql = statement;
this->returnCode = sqlite3_prepare_v2(this->db, statement.c_str(), -1, &stmt, NULL);
ResultTable t(statement);
if (this->returnCode != SQLITE_OK){
fprintf(stderr, "Unable to successfully prepare SQL statement. Error code: %d\n\tError Message: %s\n", this->returnCode, sqlite3_errmsg(this->db));
return t;
return ResultTable(this->returnCode);
}
ResultTable t(statement);
t.extractData(stmt);
this->returnCode = sqlite3_finalize(stmt);
@ -78,6 +77,18 @@ void Database::closeConnection(){
this->dbIsOpen = false;
}
void Database::beginTransaction(){
this->executeSQL("BEGIN;");
}
void Database::commitTransaction(){
this->executeSQL("COMMIT;");
}
void Database::rollbackTransaction(){
this->executeSQL("ROLLBACK;");
}
string Database::combineVector(std::vector<string> strings, string mid){
if (strings.empty()){
return "";

View File

@ -35,6 +35,10 @@ public:
void closeConnection();
void beginTransaction();
void commitTransaction();
void rollbackTransaction();
protected:
string surroundString(string s, string surround);

View File

@ -12,7 +12,7 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
return false;
}
//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;");
this->beginTransaction();
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());
@ -20,6 +20,7 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
bool success = this->insertInto("recipe",
vector<string>({
"name",
"authorName",
"createdDate",
"cookTime",
"prepTime",
@ -27,6 +28,7 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
}),
vector<string>({
recipe.getName(),
recipe.getAuthor(),
recipe.getCreatedDate().toString().toStdString(),
recipe.getCookTime().toString().toStdString(),
recipe.getPrepTime().toString().toStdString(),
@ -46,12 +48,12 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
this->storeInstruction(recipe.getInstruction(), recipeId) &&
this->storeImage(recipe.getImage(), recipeId) &&
this->storeTags(recipe.getTags(), recipeId)){
this->executeSQL("COMMIT;");
this->commitTransaction();
return true;
}
}
}
this->executeSQL("ROLLBACK;");
this->rollbackTransaction();
return false;
}
@ -158,7 +160,7 @@ Recipe RecipeDatabase::retrieveRandomRecipe(){
}
return this->readFromResultTable(t);
}
//TODO: Change this to be more efficient! One query per recipe is not good!
vector<Recipe> RecipeDatabase::retrieveAllRecipes(){
ResultTable t = this->executeSQL("SELECT * FROM recipe ORDER BY name;");
return this->readRecipesFromTable(t);
@ -204,7 +206,7 @@ vector<Recipe> RecipeDatabase::retrieveRecipesWithTags(vector<RecipeTag> tags){
}
vector<Recipe> RecipeDatabase::retrieveRecipesWithSubstring(string s){
ResultTable t = this->executeSQL("SELECT * FROM recipe WHERE name LIKE '%"+s+"%' COLLATE NOCASE;");
ResultTable t = this->executeSQL("SELECT * FROM recipe WHERE name LIKE '%"+s+"%' COLLATE NOCASE ORDER BY name;");
return this->readRecipesFromTable(t);
}
@ -253,6 +255,18 @@ vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId)
return ings;
}
int RecipeDatabase::retrieveIngredientId(string ingredientName){
return std::stoi(this->selectFrom("ingredient", "ingredientId", "WHERE name = '"+ingredientName+"'").at(0, 0));
}
bool RecipeDatabase::deleteRecipeTags(int recipeId){
return this->deleteFrom("recipeTag", "WHERE recipeId = "+std::to_string(recipeId));
}
bool RecipeDatabase::deleteRecipeIngredients(int recipeId){
return this->deleteFrom("recipeIngredient", "WHERE recipeId = "+std::to_string(recipeId));
}
vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){
ResultTable t = this->selectFrom("ingredient", "name, foodGroup", "ORDER BY name");
vector<Ingredient> ings;
@ -314,7 +328,7 @@ bool RecipeDatabase::deleteRecipe(int recipeId){
printf("Cannot delete. No recipe with ID %d exists.\n", recipeId);
return false;
}
this->executeSQL("BEGIN;");
this->beginTransaction();
bool tagsDeleted = this->deleteFrom("recipeTag", "WHERE recipeId="+idString);
bool recipeIngredientDeleted = this->deleteFrom("recipeIngredient", "WHERE recipeId="+idString);
bool recipeDeleted = this->deleteFrom("recipe", "WHERE recipeId="+idString);
@ -323,10 +337,10 @@ bool RecipeDatabase::deleteRecipe(int recipeId){
Q_UNUSED(instructionDeleted);
Q_UNUSED(imageDeleted);
if (tagsDeleted && recipeIngredientDeleted && recipeDeleted){
this->executeSQL("COMMIT;");
this->commitTransaction();
return true;
} else {
this->executeSQL("ROLLBACK;");
this->rollbackTransaction();
return false;
}
}
@ -356,15 +370,123 @@ bool RecipeDatabase::deleteTag(RecipeTag tag){
return this->deleteFrom("recipeTag", "WHERE tagName='"+tag.getValue()+"'");
}
bool RecipeDatabase::updateRecipe(Recipe recipe){
bool RecipeDatabase::updateRecipe(Recipe recipe, string originalName) {
string idS = this->selectFrom("recipe", "recipeId", "WHERE name="+surroundString(originalName, "'")).at(0, 0);
int id = std::stoi(idS);
this->beginTransaction();
ResultTable t = this->executeSQL("UPDATE recipe "
"SET name = '"+recipe.getName()+"', "
"authorName = '"+recipe.getAuthor()+"', "
"createdDate = '"+recipe.getCreatedDate().toString().toStdString()+"', "
"prepTime = '"+recipe.getPrepTime().toString().toStdString()+"', "
"cookTime = '"+recipe.getCookTime().toString().toStdString()+"', "
"servingCount = "+std::to_string(recipe.getServings())+" "
"WHERE recipeId = "+idS+";");
bool recipeSuccess = t.getReturnCode() == SQLITE_DONE;
if (!recipeSuccess){
this->rollbackTransaction();
return false;
}
bool tagsSuccess = this->deleteRecipeTags(id);
for (RecipeTag tag : recipe.getTags()){
tagsSuccess = tagsSuccess && this->insertInto(
"recipeTag",
vector<string>({
"recipeId",
"tagName"
}),
vector<string>({
idS,
tag.getValue()
}));
}
if (!tagsSuccess){
this->rollbackTransaction();
return false;
}
bool ingredientsSuccess = this->deleteRecipeIngredients(id);
for (RecipeIngredient ri : recipe.getIngredients()){
ingredientsSuccess = ingredientsSuccess && this->insertInto(
"recipeIngredient",
vector<string>({
"recipeId",
"ingredientId",
"unitName",
"quantity",
"comment"
}),
vector<string>({
idS,
std::to_string(this->retrieveIngredientId(ri.getName())),
ri.getUnit().getName(),
std::to_string(ri.getQuantity()),
ri.getComment()
}));
}
if (!ingredientsSuccess){
this->rollbackTransaction();
return false;
}
bool instructionSuccess = FileUtils::saveInstruction(id, recipe.getInstruction());
bool imageSuccess = FileUtils::saveImage(id, recipe.getImage());
if (!(instructionSuccess && imageSuccess)){
this->rollbackTransaction();
return false;
} else {
this->commitTransaction();
return true;
}
}
bool RecipeDatabase::addBasicUnits(){
this->beginTransaction();
//Volume
this->storeUnitOfMeasure(UnitOfMeasure("Teaspoon", "Teaspoons", "tsp", UnitOfMeasure::VOLUME, 5.0));
this->storeUnitOfMeasure(UnitOfMeasure("Tablespoon", "Tablespoons", "tbsp", UnitOfMeasure::VOLUME, 15.0));
this->storeUnitOfMeasure(UnitOfMeasure("Fluid Ounce", "Fluid Ounces", "fl oz", UnitOfMeasure::VOLUME, 30.0));
this->storeUnitOfMeasure(UnitOfMeasure("Cup", "Cups", "c", UnitOfMeasure::VOLUME, 250.0));
this->storeUnitOfMeasure(UnitOfMeasure("Milliliter", "Milliliters", "mL", UnitOfMeasure::VOLUME, 1.0));
this->storeUnitOfMeasure(UnitOfMeasure("Liter", "Liters", "L", UnitOfMeasure::VOLUME, 1000.0));
this->storeUnitOfMeasure(UnitOfMeasure("Gallon", "Gallons", "gal", UnitOfMeasure::VOLUME, 3800.0));
//Mass/Weight
this->storeUnitOfMeasure(UnitOfMeasure("Ounce", "Ounces", "oz", UnitOfMeasure::MASS, 28.0));
this->storeUnitOfMeasure(UnitOfMeasure("Pound", "Pounds", "lb", UnitOfMeasure::MASS, 454.0));
this->storeUnitOfMeasure(UnitOfMeasure("Gram", "Grams", "g", UnitOfMeasure::MASS, 1.0));
this->storeUnitOfMeasure(UnitOfMeasure("Milligram", "Milligrams", "mg", UnitOfMeasure::MASS, 0.001));
this->storeUnitOfMeasure(UnitOfMeasure("Kilogram", "Kilograms", "kg", UnitOfMeasure::MASS, 1000.0));
//Length
this->storeUnitOfMeasure(UnitOfMeasure("Inch", "Inches", "in", UnitOfMeasure::LENGTH, 2.54));
this->storeUnitOfMeasure(UnitOfMeasure("Centimeter", "Centimeters", "cm", UnitOfMeasure::LENGTH, 1.0));
//MISC
this->storeUnitOfMeasure(UnitOfMeasure("Piece", "Pieces", "pc", UnitOfMeasure::MISC, 1.0));
this->storeUnitOfMeasure(UnitOfMeasure("Item", "Items", "", UnitOfMeasure::MISC, 1.0));
this->commitTransaction();
return true;
}
bool RecipeDatabase::addBasicIngredients(){
this->beginTransaction();
this->storeIngredient(Ingredient("Flour", "grains"));
this->storeIngredient(Ingredient("Eggs", "eggs"));
this->storeIngredient(Ingredient("Milk", "dairy"));
this->storeIngredient(Ingredient("Cheese", "dairy"));
this->storeIngredient(Ingredient("Salt", "spices"));
this->storeIngredient(Ingredient("Sugar", "sugars"));
this->storeIngredient(Ingredient("Vegetable Oil", "oils"));
this->storeIngredient(Ingredient("Olive Oil", "oils"));
this->storeIngredient(Ingredient("Water", "water"));
this->storeIngredient(Ingredient("Bell Pepper", "vegetables"));
this->storeIngredient(Ingredient("Onion", "vegetables"));
this->storeIngredient(Ingredient("Garlic", "spices"));
this->commitTransaction();
return true;
}
void RecipeDatabase::ensureTablesExist(){
//Make sure that foreign keys are enabled.
this->executeSQL("PRAGMA foreign_keys = ON;");
this->executeSQL("BEGIN;");
this->beginTransaction();
//Ingredients table.
this->executeSQL("CREATE TABLE IF NOT EXISTS ingredient("
"ingredientId INTEGER PRIMARY KEY,"
@ -381,6 +503,7 @@ void RecipeDatabase::ensureTablesExist(){
this->executeSQL("CREATE TABLE IF NOT EXISTS recipe("
"recipeId INTEGER PRIMARY KEY,"
"name varchar UNIQUE,"
"authorName varchar,"
"createdDate date,"
"prepTime time,"
"cookTime time,"
@ -400,18 +523,19 @@ void RecipeDatabase::ensureTablesExist(){
"FOREIGN KEY (ingredientId) REFERENCES ingredient(ingredientId),"
"FOREIGN KEY (recipeId) REFERENCES recipe(recipeId),"
"FOREIGN KEY (unitName) REFERENCES unitOfMeasure(name));");
this->executeSQL("COMMIT;");
this->commitTransaction();
}
Recipe RecipeDatabase::readFromResultTable(ResultTable t, int tRow){
Recipe r;
TableRow row = t.rows().at(tRow);
int id = std::stoi(row.at(0));
r.setName(row.at(1));
r.setCreatedDate(QDate::fromString(QString::fromStdString(row.at(2))));
r.setPrepTime(QTime::fromString(QString::fromStdString(row.at(3))));
r.setCookTime(QTime::fromString(QString::fromStdString(row.at(4))));
r.setServings(std::stof(row.at(5)));
int id = std::stoi(row.at(0)); //id
r.setName(row.at(1)); //Name
r.setAuthor(row.at(2)); //author
r.setCreatedDate(QDate::fromString(QString::fromStdString(row.at(3)))); //createdDate
r.setPrepTime(QTime::fromString(QString::fromStdString(row.at(4)))); //prepTime
r.setCookTime(QTime::fromString(QString::fromStdString(row.at(5)))); //cookTime
r.setServings(std::stof(row.at(6))); //servings
r.setInstruction(FileUtils::loadInstruction(id));
r.setImage(FileUtils::loadImage(id));
r.setIngredients(this->retrieveRecipeIngredients(id));

View File

@ -26,9 +26,6 @@ class RecipeDatabase : public Database
bool storeRecipeIngredient(RecipeIngredient ri, int recipeId);
int storeIngredient(Ingredient ingredient);
bool storeUnitOfMeasure(UnitOfMeasure u);
bool storeInstruction(Instruction instruction, int recipeId);
bool storeImage(QImage image, int recipeId);
bool storeTags(vector<RecipeTag> tags, int recipeId);
//Retrieval.
Recipe retrieveRecipe(string name);
@ -39,10 +36,8 @@ class RecipeDatabase : public Database
vector<Recipe> retrieveRecipesWithSubstring(string s);
vector<Recipe> retrieveRecipesWithFoodGroups(vector<string> groups);
vector<string> retrieveAllFoodGroups();
vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
vector<Ingredient> retrieveAllIngredients();
vector<UnitOfMeasure> retrieveAllUnitsOfMeasure();
vector<RecipeTag> retrieveTags(int recipeId);
vector<RecipeTag> retrieveAllTags();
//Deletion.
@ -53,7 +48,11 @@ class RecipeDatabase : public Database
bool deleteTag(RecipeTag tag);
//Updating.
bool updateRecipe(Recipe recipe);
bool updateRecipe(Recipe recipe, string originalName);
//Adding basic information at start.
bool addBasicUnits();
bool addBasicIngredients();
private:
//Utility methods.
@ -61,6 +60,20 @@ class RecipeDatabase : public Database
//Read a recipe from a row of a result table.
Recipe readFromResultTable(ResultTable t, int row=0);
vector<Recipe> readRecipesFromTable(ResultTable t);
//Storage
bool storeInstruction(Instruction instruction, int recipeId);
bool storeImage(QImage image, int recipeId);
bool storeTags(vector<RecipeTag> tags, int recipeId);
//Retrieval
vector<RecipeTag> retrieveTags(int recipeId);
vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
int retrieveIngredientId(string ingredientName);
//Deletion
bool deleteRecipeTags(int recipeId);
bool deleteRecipeIngredients(int recipeId);
};
#endif // RECIPEDATABASE_H

View File

@ -8,6 +8,10 @@ ResultTable::ResultTable(string query){
this->originalQuery = query;
}
ResultTable::ResultTable(int resultCode){
this->queryCode = resultCode;
}
void ResultTable::extractData(sqlite3_stmt *stmt){
this->values.clear();
int res = sqlite3_step(stmt);
@ -30,6 +34,7 @@ void ResultTable::processRow(sqlite3_stmt *stmt){
}
void ResultTable::printData(){
printf("--> Result Code: [%d] <--\n", this->getReturnCode());
if (this->isEmpty()){
printf("Result table is empty.\n");
return;

View File

@ -21,6 +21,8 @@ class ResultTable
ResultTable();
//Constructs a table with the original query saved.
ResultTable(string query);
//Constructs an empty table with a result code.
ResultTable(int resultCode);
//Gets all the data from the result set and stores it internally as strings.
void extractData(sqlite3_stmt* stmt);

View File

@ -1,7 +1,8 @@
#include "model/recipe/recipe.h"
Recipe::Recipe(string name, vector<RecipeIngredient> ingredients, Instruction instruction, QImage image, vector<RecipeTag> tags, QDate createdDate, QTime prepTime, QTime cookTime, float servings){
Recipe::Recipe(string name, string author, vector<RecipeIngredient> ingredients, Instruction instruction, QImage image, vector<RecipeTag> tags, QDate createdDate, QTime prepTime, QTime cookTime, float servings){
setName(name);
setAuthor(author);
setIngredients(ingredients);
setInstruction(instruction);
setImage(image);
@ -12,7 +13,7 @@ Recipe::Recipe(string name, vector<RecipeIngredient> ingredients, Instruction in
setServings(servings);
}
Recipe::Recipe() : Recipe::Recipe("", vector<RecipeIngredient>(), Instruction(), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(1, 0), QTime(0, 30), 10.0f){
Recipe::Recipe() : Recipe::Recipe("", "", vector<RecipeIngredient>(), Instruction(), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(), QTime(), 1.0f){
//Set default values when none are specified.
}
@ -20,6 +21,10 @@ string Recipe::getName() const{
return this->name;
}
string Recipe::getAuthor() const{
return this->authorName;
}
vector<RecipeIngredient> Recipe::getIngredients() const{
return this->ingredients;
}
@ -74,6 +79,10 @@ void Recipe::setName(string newName){
this->name = newName;
}
void Recipe::setAuthor(string newName){
this->authorName = newName;
}
void Recipe::setIngredients(vector<RecipeIngredient> ingredients){
this->ingredients = ingredients;
}
@ -111,8 +120,9 @@ void Recipe::setServings(float newServingsCount){
}
void Recipe::print(){
printf("Recipe: %s, Created on: %s, Prep time: %s, Cook time: %s, Serves: %f\n",
printf("Recipe: %s, Created on: %s, by %s, Prep time: %s, Cook time: %s, Serves: %f\n",
this->name.c_str(),
this->authorName.c_str(),
this->createdDate.toString().toStdString().c_str(),
this->prepTime.toString().toStdString().c_str(),
this->cookTime.toString().toStdString().c_str(),

View File

@ -32,12 +32,13 @@ class Recipe
{
public:
//Full constructor
Recipe(string name, vector<RecipeIngredient> ingredients, Instruction instruction, QImage image, vector<RecipeTag> tags, QDate createdDate, QTime prepTime, QTime cookTime, float servings);
Recipe(string name, string author, vector<RecipeIngredient> ingredients, Instruction instruction, QImage image, vector<RecipeTag> tags, QDate createdDate, QTime prepTime, QTime cookTime, float servings);
//Constructor with default values.
Recipe();
//Getters
string getName() const;
string getAuthor() const;
vector<RecipeIngredient> getIngredients() const;
vector<string> getFoodGroups() const;
Instruction getInstruction() const;
@ -52,6 +53,7 @@ public:
//Setters
void setName(string newName);
void setAuthor(string newName);
void setIngredients(vector<RecipeIngredient> ingredients);
void setTags(vector<RecipeTag> tags);
void addIngredient(RecipeIngredient newIngredient);
@ -66,6 +68,7 @@ public:
private:
//Main information.
string name; //The name of the recipe.
string authorName; //The name of the author of this recipe.
vector<RecipeIngredient> ingredients; //The list of ingredients in the recipe.
Instruction instruction; //The instruction HTML document.
QImage image; //An image displayed alongside the recipe.