Compare commits

..

10 Commits

Author SHA1 Message Date
Andrew Lalis c8b8cc1d0f
Merge pull request #12 from andrewlalis/development
Updated readme and linux static build settings.
2018-04-18 21:21:13 +01:00
Andrew Lalis c7b39cda21
Merge pull request #11 from andrewlalis/development
Release 1.0 Ready!
2018-04-01 09:31:08 +02:00
Andrew Lalis ce6effff91
Merge pull request #10 from andrewlalis/development
Stable first release
2018-03-31 20:36:01 +02:00
Andrew Lalis e60fe413db
Merge pull request #9 from andrewlalis/development
Almost at full release.
2018-03-30 23:30:20 +02:00
Andrew Lalis c971a60666
Merge pull request #8 from andrewlalis/development
More security and less unexpected behaviour.
2018-03-30 16:20:54 +02:00
Andrew Lalis 626fe91bb1
Merge pull request #7 from andrewlalis/development
Actually Usable Version
2018-03-29 16:11:26 +02:00
Andrew Lalis 1af1511779
Merge pull request #6 from andrewlalis/development
Completed viewing of recipes, beginning of browsing feature.
2018-03-11 09:35:33 +01:00
Andrew Lalis e2ccde9030
Merge pull request #5 from andrewlalis/development
First ability to create recipe in gui
2018-03-10 16:03:09 +01:00
Andrew Lalis cf099c1b52
Merge pull request #4 from andrewlalis/development
Periodic update of progress.
2018-03-10 12:38:20 +01:00
Andrew Lalis 9b377a5548
Merge pull request #3 from andrewlalis/development
Shift to master. Not done but database abstraction is nearly done.
2018-03-03 10:20:11 +01:00
35 changed files with 1717 additions and 112 deletions

View File

@ -16,8 +16,10 @@ SOURCES += model/recipe/instruction.cpp \
model/recipe/recipe.cpp \ model/recipe/recipe.cpp \
main.cpp \ main.cpp \
model/database/database.cpp \ model/database/database.cpp \
model/recipe/ingredients/unitofmeasure.cpp \
model/recipe/ingredients/ingredient.cpp \ model/recipe/ingredients/ingredient.cpp \
model/recipe/ingredients/ingredientlistmodel.cpp \ model/recipe/ingredients/ingredientlistmodel.cpp \
model/recipe/ingredients/recipeingredient.cpp \
model/recipe/tags/recipetag.cpp \ model/recipe/tags/recipetag.cpp \
SQLite/sqlite3.c \ SQLite/sqlite3.c \
model/database/resulttable.cpp \ model/database/resulttable.cpp \
@ -25,18 +27,24 @@ SOURCES += model/recipe/instruction.cpp \
utils/fileutils.cpp \ utils/fileutils.cpp \
gui/newrecipedialog.cpp \ gui/newrecipedialog.cpp \
model/recipe/tags/taglistmodel.cpp \ model/recipe/tags/taglistmodel.cpp \
gui/newDialogs/newingredientdialog.cpp \
gui/newDialogs/newtagdialog.cpp \ gui/newDialogs/newtagdialog.cpp \
gui/newDialogs/newunitdialog.cpp \
utils/aspectratiopixmaplabel.cpp \ utils/aspectratiopixmaplabel.cpp \
utils/stringutils.cpp \ utils/stringutils.cpp \
gui/openrecipedialog.cpp \ gui/openrecipedialog.cpp \
model/recipe/recipetablemodel.cpp \ model/recipe/recipetablemodel.cpp \
gui/mainwindow.cpp gui/mainwindow.cpp \
gui/newDialogs/newfoodgroupdialog.cpp \
model/recipe/ingredients/recipeingredientlistmodel.cpp
HEADERS += model/recipe/instruction.h \ HEADERS += model/recipe/instruction.h \
model/recipe/recipe.h \ model/recipe/recipe.h \
model/database/database.h \ model/database/database.h \
model/recipe/ingredients/unitofmeasure.h \
model/recipe/ingredients/ingredient.h \ model/recipe/ingredients/ingredient.h \
model/recipe/ingredients/ingredientlistmodel.h \ model/recipe/ingredients/ingredientlistmodel.h \
model/recipe/ingredients/recipeingredient.h \
model/recipe/tags/recipetag.h \ model/recipe/tags/recipetag.h \
SQLite/sqlite3.h \ SQLite/sqlite3.h \
SQLite/sqlite3ext.h \ SQLite/sqlite3ext.h \
@ -45,20 +53,27 @@ HEADERS += model/recipe/instruction.h \
utils/fileutils.h \ utils/fileutils.h \
gui/newrecipedialog.h \ gui/newrecipedialog.h \
model/recipe/tags/taglistmodel.h \ model/recipe/tags/taglistmodel.h \
gui/newDialogs/newingredientdialog.h \
gui/newDialogs/newtagdialog.h \ gui/newDialogs/newtagdialog.h \
gui/newDialogs/newunitdialog.h \
utils/aspectratiopixmaplabel.h \ utils/aspectratiopixmaplabel.h \
utils/stringutils.h \ utils/stringutils.h \
gui/openrecipedialog.h \ gui/openrecipedialog.h \
model/recipe/recipetablemodel.h \ model/recipe/recipetablemodel.h \
gui/mainwindow.h gui/mainwindow.h \
gui/newDialogs/newfoodgroupdialog.h \
model/recipe/ingredients/recipeingredientlistmodel.h
LIBS += -ldl \ LIBS += -ldl \
FORMS += gui/mainwindow.ui \ FORMS += gui/mainwindow.ui \
gui/newrecipedialog.ui \ gui/newrecipedialog.ui \
gui/newDialogs/newingredientdialog.ui \
gui/newDialogs/newtagdialog.ui \ gui/newDialogs/newtagdialog.ui \
gui/newDialogs/newunitdialog.ui \
gui/openrecipedialog.ui \ gui/openrecipedialog.ui \
gui/mainwindow.ui gui/mainwindow.ui \
gui/newDialogs/newfoodgroupdialog.ui
DISTFILES += \ DISTFILES += \
.gitignore .gitignore

View File

@ -48,7 +48,7 @@ void MainWindow::setInstruction(Instruction instruction){
ui->instructionsTextEdit->setHtml(QString::fromStdString(instruction.getHTML())); ui->instructionsTextEdit->setHtml(QString::fromStdString(instruction.getHTML()));
} }
void MainWindow::setIngredients(vector<Ingredient> ingredients){ void MainWindow::setIngredients(vector<RecipeIngredient> ingredients){
this->ingredientModel.setIngredients(ingredients); this->ingredientModel.setIngredients(ingredients);
} }

View File

@ -6,7 +6,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include "model/recipe/recipe.h" #include "model/recipe/recipe.h"
#include "model/recipe/ingredients/ingredientlistmodel.h" #include "model/recipe/ingredients/recipeingredientlistmodel.h"
#include "gui/newrecipedialog.h" #include "gui/newrecipedialog.h"
#include "gui/openrecipedialog.h" #include "gui/openrecipedialog.h"
#include "utils/stringutils.h" #include "utils/stringutils.h"
@ -41,14 +41,14 @@ public:
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
RecipeDatabase *recipeDB; RecipeDatabase *recipeDB;
IngredientListModel ingredientModel; RecipeIngredientListModel ingredientModel;
TagListModel tagsListModel; TagListModel tagsListModel;
Recipe currentRecipe; Recipe currentRecipe;
//Hidden manipulation methods. //Hidden manipulation methods.
void setRecipeName(string name); void setRecipeName(string name);
void setInstruction(Instruction instruction); void setInstruction(Instruction instruction);
void setIngredients(vector<Ingredient> ingredients); void setIngredients(vector<RecipeIngredient> ingredients);
void setImage(QImage img); void setImage(QImage img);
void setPrepTime(QTime prepTime); void setPrepTime(QTime prepTime);
void setCookTime(QTime cookTime); void setCookTime(QTime cookTime);

View File

@ -0,0 +1,18 @@
#include "newfoodgroupdialog.h"
#include "ui_newfoodgroupdialog.h"
newFoodGroupDialog::newFoodGroupDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::newFoodGroupDialog)
{
ui->setupUi(this);
}
newFoodGroupDialog::~newFoodGroupDialog()
{
delete ui;
}
string newFoodGroupDialog::getFoodGroup() const{
return ui->lineEdit->text().toStdString();
}

View File

@ -0,0 +1,27 @@
#ifndef NEWFOODGROUPDIALOG_H
#define NEWFOODGROUPDIALOG_H
#include <QDialog>
#include <string>
using namespace std;
namespace Ui {
class newFoodGroupDialog;
}
class newFoodGroupDialog : public QDialog
{
Q_OBJECT
public:
explicit newFoodGroupDialog(QWidget *parent = 0);
~newFoodGroupDialog();
string getFoodGroup() const;
private:
Ui::newFoodGroupDialog *ui;
};
#endif // NEWFOODGROUPDIALOG_H

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>newFoodGroupDialog</class>
<widget class="QDialog" name="newFoodGroupDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>240</width>
<height>114</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="windowTitle">
<string>New Food Group</string>
</property>
<property name="windowIcon">
<iconset resource="../../res.qrc">
<normaloff>:/images/images/icon.png</normaloff>:/images/images/icon.png</iconset>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Add New Food Group</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>newFoodGroupDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>newFoodGroupDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,49 @@
#include "newingredientdialog.h"
#include "ui_newingredientdialog.h"
NewIngredientDialog::NewIngredientDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewIngredientDialog)
{
ui->setupUi(this);
}
NewIngredientDialog::NewIngredientDialog(RecipeDatabase *recipeDB, QWidget *parent) : NewIngredientDialog(parent){
this->recipeDB = recipeDB;
this->populateFoodGroupBox();
}
NewIngredientDialog::~NewIngredientDialog()
{
delete ui;
}
Ingredient NewIngredientDialog::getIngredient(){
return Ingredient(ui->nameEdit->text().toLower().toStdString(), ui->foodGroupBox->currentText().toStdString());
}
void NewIngredientDialog::populateFoodGroupBox(){
vector<string> foodGroups = this->recipeDB->retrieveAllFoodGroups();
ui->foodGroupBox->clear();
for (unsigned int i = 0; i < foodGroups.size(); i++){
QString s = QString::fromStdString(foodGroups[i]);
ui->foodGroupBox->insertItem(i, s);
}
}
void NewIngredientDialog::on_addFoodGroupButton_clicked(){
newFoodGroupDialog d(this);
if (d.exec() == QDialog::Accepted){
string s = d.getFoodGroup();
if (!s.empty()){
ui->foodGroupBox->addItem(QString::fromStdString(s));
ui->foodGroupBox->setCurrentText(QString::fromStdString(s));
} else {
QMessageBox::warning(this, "Empty Food Group", "The food group you entered is empty!");
}
}
}
void NewIngredientDialog::on_deleteFoodGroupButton_clicked(){
ui->foodGroupBox->removeItem(ui->foodGroupBox->currentIndex());
}

View File

@ -0,0 +1,39 @@
#ifndef NEWINGREDIENTDIALOG_H
#define NEWINGREDIENTDIALOG_H
#include <QDialog>
#include <QMessageBox>
#include "model/recipe/ingredients/ingredient.h"
#include "model/database/recipedatabase.h"
#include "gui/newDialogs/newfoodgroupdialog.h"
namespace Ui {
class NewIngredientDialog;
}
class NewIngredientDialog : public QDialog
{
Q_OBJECT
public:
explicit NewIngredientDialog(QWidget *parent = 0);
NewIngredientDialog(RecipeDatabase *recipeDB, QWidget *parent = 0);
~NewIngredientDialog();
//Access values.
Ingredient getIngredient();
private slots:
void on_addFoodGroupButton_clicked();
void on_deleteFoodGroupButton_clicked();
private:
Ui::NewIngredientDialog *ui;
RecipeDatabase *recipeDB;
void populateFoodGroupBox();
};
#endif // NEWINGREDIENTDIALOG_H

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewIngredientDialog</class>
<widget class="QDialog" name="NewIngredientDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>367</width>
<height>228</height>
</rect>
</property>
<property name="windowTitle">
<string>New Ingredient</string>
</property>
<property name="windowIcon">
<iconset resource="../../res.qrc">
<normaloff>:/images/images/icon.png</normaloff>:/images/images/icon.png</iconset>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="mainContentPanel" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="namePanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>Name</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameEdit"/>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="foodGroupPanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="foodGroupLabel">
<property name="text">
<string>Food Group</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="foodGroupSelectionWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="foodGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAlphabetically</enum>
</property>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="addFoodGroupButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../res.qrc">
<normaloff>:/images/images/plus_icon.png</normaloff>:/images/images/plus_icon.png</iconset>
</property>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="deleteFoodGroupButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../res.qrc">
<normaloff>:/images/images/minus_icon.png</normaloff>:/images/images/minus_icon.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewIngredientDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewIngredientDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,31 @@
#include "newunitdialog.h"
#include "ui_newunitdialog.h"
NewUnitDialog::NewUnitDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewUnitDialog)
{
ui->setupUi(this);
ui->typeComboBox->clear();
QStringList list({"Mass", "Volume", "Length", "Misc"});
ui->typeComboBox->insertItems(0, list);
}
NewUnitDialog::~NewUnitDialog()
{
delete ui;
}
UnitOfMeasure NewUnitDialog::getUnit(){
return UnitOfMeasure(ui->unitNameEdit->text().toLower().toStdString(),
ui->pluralNameEdit->text().toLower().toStdString(),
ui->abbreviationEdit->text().toStdString(),
this->getSelectedType(),
ui->coefficientSpinBox->value());
}
int NewUnitDialog::getSelectedType(){
return ui->typeComboBox->currentIndex();
}

View File

@ -0,0 +1,27 @@
#ifndef NEWUNITDIALOG_H
#define NEWUNITDIALOG_H
#include <QDialog>
#include "model/recipe/ingredients/unitofmeasure.h"
namespace Ui {
class NewUnitDialog;
}
class NewUnitDialog : public QDialog
{
Q_OBJECT
public:
explicit NewUnitDialog(QWidget *parent = 0);
~NewUnitDialog();
UnitOfMeasure getUnit();
private:
Ui::NewUnitDialog *ui;
int getSelectedType();
};
#endif // NEWUNITDIALOG_H

View File

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewUnitDialog</class>
<widget class="QDialog" name="NewUnitDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>195</width>
<height>340</height>
</rect>
</property>
<property name="windowTitle">
<string>New Unit</string>
</property>
<property name="windowIcon">
<iconset resource="../../res.qrc">
<normaloff>:/images/images/icon.png</normaloff>:/images/images/icon.png</iconset>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="contentPanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Unit Name</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="unitNameEdit"/>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Plural Name</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="pluralNameEdit"/>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Abbreviation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="abbreviationEdit"/>
</item>
<item>
<widget class="QWidget" name="unitTypePanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<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="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="typeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="coefficientPanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Metric Coefficient</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="coefficientSpinBox">
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewUnitDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewUnitDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -15,6 +15,9 @@ NewRecipeDialog::NewRecipeDialog(QWidget *parent) :
NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecipeDialog(parent){ NewRecipeDialog::NewRecipeDialog(RecipeDatabase *db, QWidget *parent) : NewRecipeDialog(parent){
this->recipeDB = db; this->recipeDB = db;
this->populateIngredientsBox();
this->populateUnitsBox();
this->populateTagsBox(); this->populateTagsBox();
} }
@ -52,6 +55,24 @@ bool NewRecipeDialog::isAccepted() const{
return this->accepted; return this->accepted;
} }
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);
}
}
void NewRecipeDialog::populateTagsBox(){ void NewRecipeDialog::populateTagsBox(){
this->tags = this->recipeDB->retrieveAllTags(); this->tags = this->recipeDB->retrieveAllTags();
ui->tagsComboBox->clear(); ui->tagsComboBox->clear();
@ -62,9 +83,12 @@ void NewRecipeDialog::populateTagsBox(){
} }
void NewRecipeDialog::on_addIngredientButton_clicked(){ void NewRecipeDialog::on_addIngredientButton_clicked(){
Ingredient ing(ui->ingredientLineEdit->text().toStdString()); //Construct a recipe ingredient from the supplied data.
this->ingredientListModel.addIngredient(ing); Ingredient i = this->ingredients[ui->ingredientNameBox->currentIndex()];
ui->ingredientLineEdit->clear(); UnitOfMeasure u = this->units[ui->unitComboBox->currentIndex()];
RecipeIngredient ri(i, ui->quantitySpinBox->value(), u, ui->commentsLineEdit->text().toStdString());
this->ingredientListModel.addIngredient(ri);
ui->commentsLineEdit->clear();
} }
void NewRecipeDialog::on_italicsButton_clicked(){ void NewRecipeDialog::on_italicsButton_clicked(){
@ -89,6 +113,7 @@ void NewRecipeDialog::on_buttonBox_rejected(){
} }
void NewRecipeDialog::on_addTagButton_clicked(){ 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()]); this->tagsListModel.addTag(this->tags[ui->tagsComboBox->currentIndex()]);
} }
@ -115,6 +140,37 @@ void NewRecipeDialog::on_removeIngredientButton_clicked(){
} }
} }
void NewRecipeDialog::on_deleteIngredientButton_clicked(){
int index = ui->ingredientNameBox->currentIndex();
Ingredient ing = this->ingredients.at(index);
QMessageBox::StandardButton reply = QMessageBox::question(this,
QString::fromStdString("Delete Ingredient"),
QString::fromStdString("Are you sure you want to delete the ingredient " + ing.getName() + "?"));
if (reply == QMessageBox::Yes){
bool success = this->recipeDB->deleteIngredient(ing.getName());
if (!success){
QMessageBox::critical(this, QString::fromStdString("Error"), QString::fromStdString("Unable to delete ingredient: " + ing.getName() + ", some recipes use it!"));
} else {
this->populateIngredientsBox();
}
}
}
void NewRecipeDialog::on_newIngredientButton_clicked(){
NewIngredientDialog d(this->recipeDB, this);
d.show();
if (d.exec() == QDialog::Accepted){
Ingredient i = d.getIngredient();
if (!i.getName().empty() && !i.getFoodGroup().empty() && this->recipeDB->storeIngredient(i)){
this->populateIngredientsBox();
ui->ingredientNameBox->setCurrentText(QString::fromStdString(i.getName()));
} else {
QMessageBox::critical(this, "Error", "Unable to add ingredient.");
}
}
}
void NewRecipeDialog::on_newTagButton_clicked(){ void NewRecipeDialog::on_newTagButton_clicked(){
NewTagDialog d(this); NewTagDialog d(this);
d.show(); d.show();
@ -150,6 +206,31 @@ void NewRecipeDialog::on_removeTagButton_clicked(){
} }
} }
void NewRecipeDialog::on_ingredientLineEdit_returnPressed(){ void NewRecipeDialog::on_newUnitButton_clicked(){
this->on_addIngredientButton_clicked(); NewUnitDialog d(this);
d.show();
if (d.exec() == QDialog::Accepted){
UnitOfMeasure u = d.getUnit();
if (u.getName().empty() || u.getNamePlural().empty() || u.getAbbreviation().empty() || !this->recipeDB->storeUnitOfMeasure(u)){
QMessageBox::critical(this, "Error", "Unable to store new unit. Make sure all the information is filled in!");
} else {
this->populateUnitsBox();
ui->unitComboBox->setCurrentText(QString::fromStdString(u.getName()));
}
}
}
void NewRecipeDialog::on_deleteUnitButton_clicked(){
int index = ui->unitComboBox->currentIndex();
UnitOfMeasure unit = this->units[index];
QMessageBox::StandardButton reply = QMessageBox::question(this,
QString::fromStdString("Delete Unit Of Measure"),
QString::fromStdString("Are you sure you want to delete the unit " + unit.getName() + "?"));
if (reply == QMessageBox::Yes){
if (!this->recipeDB->deleteUnitOfMeasure(unit.getName())){
QMessageBox::critical(this, "Error", "Unable to delete unit. There may be recipes which still use it!");
} else {
this->populateUnitsBox();
}
}
} }

View File

@ -8,10 +8,12 @@
#include <QMessageBox> #include <QMessageBox>
#include "model/database/recipedatabase.h" #include "model/database/recipedatabase.h"
#include "model/recipe/ingredients/ingredientlistmodel.h" #include "model/recipe/ingredients/recipeingredientlistmodel.h"
#include "model/recipe/tags/taglistmodel.h" #include "model/recipe/tags/taglistmodel.h"
#include "gui/newDialogs/newingredientdialog.h"
#include "gui/newDialogs/newtagdialog.h" #include "gui/newDialogs/newtagdialog.h"
#include "gui/newDialogs/newunitdialog.h"
namespace Ui { namespace Ui {
class NewRecipeDialog; class NewRecipeDialog;
@ -27,7 +29,6 @@ class NewRecipeDialog : public QDialog
NewRecipeDialog(RecipeDatabase *db, Recipe recipe, QWidget *parent = 0); NewRecipeDialog(RecipeDatabase *db, Recipe recipe, QWidget *parent = 0);
~NewRecipeDialog(); ~NewRecipeDialog();
//Extracts a recipe from all the information entered in the ui.
Recipe getRecipe(); Recipe getRecipe();
bool isAccepted() const; bool isAccepted() const;
private slots: private slots:
@ -37,10 +38,8 @@ class NewRecipeDialog : public QDialog
void on_boldButton_clicked(); void on_boldButton_clicked();
//Sets the dialog as accepted, as in, the user accepts that they want to create the recipe.
void on_buttonBox_accepted(); void on_buttonBox_accepted();
//The user has rejected the creation of the recipe.
void on_buttonBox_rejected(); void on_buttonBox_rejected();
void on_addTagButton_clicked(); void on_addTagButton_clicked();
@ -51,22 +50,31 @@ class NewRecipeDialog : public QDialog
void on_removeIngredientButton_clicked(); void on_removeIngredientButton_clicked();
void on_deleteIngredientButton_clicked();
void on_newIngredientButton_clicked();
void on_newTagButton_clicked(); void on_newTagButton_clicked();
void on_removeTagButton_clicked(); void on_removeTagButton_clicked();
void on_ingredientLineEdit_returnPressed(); void on_newUnitButton_clicked();
void on_deleteUnitButton_clicked();
private: private:
Ui::NewRecipeDialog *ui; Ui::NewRecipeDialog *ui;
RecipeDatabase *recipeDB; RecipeDatabase *recipeDB;
vector<Ingredient> ingredients; vector<Ingredient> ingredients;
vector<UnitOfMeasure> units;
vector<RecipeTag> tags; vector<RecipeTag> tags;
IngredientListModel ingredientListModel; RecipeIngredientListModel ingredientListModel;
TagListModel tagsListModel; TagListModel tagsListModel;
bool accepted = false; bool accepted = false;
//Helper functions to fill fields. //Helper functions to fill fields.
void populateIngredientsBox();
void populateUnitsBox();
void populateTagsBox(); void populateTagsBox();
}; };

View File

@ -175,7 +175,7 @@
<second>0</second> <second>0</second>
<year>1999</year> <year>1999</year>
<month>12</month> <month>12</month>
<day>20</day> <day>21</day>
</datetime> </datetime>
</property> </property>
<property name="currentSection"> <property name="currentSection">
@ -530,7 +530,176 @@ QPushButton#deleteTagButton:pressed{
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="ingredientLineEdit"> <widget class="QWidget" name="ingredientNamePanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>2</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="QComboBox" name="ingredientNameBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(113, 119, 255);</string>
</property>
<property name="editable">
<bool>false</bool>
</property>
<property name="currentText">
<string/>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAlphabetically</enum>
</property>
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="newIngredientButton">
<property name="toolTip">
<string>Create a new ingredient</string>
</property>
<property name="icon">
<iconset resource="../res.qrc">
<normaloff>:/images/images/plus_icon.png</normaloff>:/images/images/plus_icon.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteIngredientButton">
<property name="toolTip">
<string>Delete this ingredient</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../res.qrc">
<normaloff>:/images/images/minus_icon.png</normaloff>:/images/images/minus_icon.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="quantityPanel" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>36</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>2</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="QLabel" name="amountLabel">
<property name="font">
<font>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Amount</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="quantitySpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="unitComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(113, 119, 255);</string>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAlphabetically</enum>
</property>
</widget>
</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="../res.qrc">
<normaloff>:/images/images/plus_icon.png</normaloff>:/images/images/plus_icon.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteUnitButton">
<property name="toolTip">
<string>Delete this unit of measure</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../res.qrc">
<normaloff>:/images/images/minus_icon.png</normaloff>:/images/images/minus_icon.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLineEdit" name="commentsLineEdit">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
@ -541,10 +710,10 @@ QPushButton#deleteTagButton:pressed{
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
<property name="placeholderText"> <property name="placeholderText">
<string>Write ingredient here...</string> <string>Comments</string>
</property> </property>
<property name="clearButtonEnabled"> <property name="clearButtonEnabled">
<bool>false</bool> <bool>false</bool>
@ -640,14 +809,11 @@ QPushButton#removeIngredientButton:pressed{
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="selectionMode"> <property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum> <enum>QAbstractItemView::MultiSelection</enum>
</property> </property>
<property name="verticalScrollMode"> <property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum> <enum>QAbstractItemView::ScrollPerPixel</enum>
</property> </property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="batchSize"> <property name="batchSize">
<number>100</number> <number>100</number>
</property> </property>

View File

@ -8,8 +8,13 @@ OpenRecipeDialog::OpenRecipeDialog(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
ui->recipeTableView->setModel(&this->recipeTableModel); ui->recipeTableView->setModel(&this->recipeTableModel);
ui->ingredientsListView->setModel(&this->ingredientsModel);
ui->tagsListView->setModel(&this->tagsModel); ui->tagsListView->setModel(&this->tagsModel);
QObject::connect(ui->ingredientsListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this,
SLOT(onIngredientsListViewSelectionChanged(QItemSelection)));
QObject::connect(ui->tagsListView->selectionModel(), QObject::connect(ui->tagsListView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, this,
@ -18,7 +23,9 @@ OpenRecipeDialog::OpenRecipeDialog(QWidget *parent) :
OpenRecipeDialog::OpenRecipeDialog(RecipeDatabase *recipeDB, QWidget *parent) : OpenRecipeDialog(parent){ OpenRecipeDialog::OpenRecipeDialog(RecipeDatabase *recipeDB, QWidget *parent) : OpenRecipeDialog(parent){
this->recipeDB = recipeDB; this->recipeDB = recipeDB;
this->populateIngredientsList();
this->populateTagsList(); this->populateTagsList();
this->populateFoodGroupsList();
this->populateRecipesTable(this->recipeDB->retrieveAllRecipes()); this->populateRecipesTable(this->recipeDB->retrieveAllRecipes());
} }
@ -38,10 +45,21 @@ void OpenRecipeDialog::populateRecipesTable(vector<Recipe> recipes){
ui->recipeTableView->show(); ui->recipeTableView->show();
} }
void OpenRecipeDialog::populateIngredientsList(){
this->ingredientsModel.setIngredients(this->recipeDB->retrieveAllIngredients());
}
void OpenRecipeDialog::populateTagsList(){ void OpenRecipeDialog::populateTagsList(){
this->tagsModel.setTags(this->recipeDB->retrieveAllTags()); this->tagsModel.setTags(this->recipeDB->retrieveAllTags());
} }
void OpenRecipeDialog::populateFoodGroupsList(){
for (string s : this->recipeDB->retrieveAllFoodGroups()){
ui->foodGroupsListWidget->addItem(QString::fromStdString(s));
}
//ui->foodGroupsListWidget->show();
}
void OpenRecipeDialog::on_deleteRecipeButton_clicked(){ void OpenRecipeDialog::on_deleteRecipeButton_clicked(){
QItemSelectionModel *selectModel = ui->recipeTableView->selectionModel(); QItemSelectionModel *selectModel = ui->recipeTableView->selectionModel();
if (!selectModel->hasSelection()){ if (!selectModel->hasSelection()){
@ -74,6 +92,17 @@ void OpenRecipeDialog::on_recipeTableView_doubleClicked(const QModelIndex &index
this->close(); this->close();
} }
void OpenRecipeDialog::onIngredientsListViewSelectionChanged(const QItemSelection &selection){
Q_UNUSED(selection);
vector<Ingredient> ingredients;
QModelIndexList indexes = ui->ingredientsListView->selectionModel()->selectedRows();
for (QModelIndex index : indexes){
Ingredient i = this->ingredientsModel.getIngredients().at(index.row());
ingredients.push_back(i);
}
this->populateRecipesTable(this->recipeDB->retrieveRecipesWithIngredients(ingredients));
}
void OpenRecipeDialog::onTagsListViewSelectionChanged(const QItemSelection &selection){ void OpenRecipeDialog::onTagsListViewSelectionChanged(const QItemSelection &selection){
Q_UNUSED(selection); Q_UNUSED(selection);
vector<RecipeTag> tags; vector<RecipeTag> tags;
@ -90,9 +119,20 @@ void OpenRecipeDialog::on_nameEdit_textChanged(const QString &arg1){
this->populateRecipesTable(this->recipeDB->retrieveRecipesWithSubstring(ui->nameEdit->text().toStdString())); this->populateRecipesTable(this->recipeDB->retrieveRecipesWithSubstring(ui->nameEdit->text().toStdString()));
} }
void OpenRecipeDialog::on_foodGroupsListWidget_itemSelectionChanged(){
vector<string> groups;
for (QModelIndex index : ui->foodGroupsListWidget->selectionModel()->selectedRows()){
QListWidgetItem *item = ui->foodGroupsListWidget->item(index.row());
groups.push_back(item->text().toStdString());
}
this->populateRecipesTable(this->recipeDB->retrieveRecipesWithFoodGroups(groups));
}
void OpenRecipeDialog::on_clearSearchButton_clicked(){ void OpenRecipeDialog::on_clearSearchButton_clicked(){
ui->nameEdit->clear(); ui->nameEdit->clear();
ui->foodGroupsListWidget->selectionModel()->clearSelection();
ui->tagsListView->selectionModel()->clearSelection(); ui->tagsListView->selectionModel()->clearSelection();
ui->ingredientsListView->selectionModel()->clearSelection();
this->populateRecipesTable(this->recipeDB->retrieveAllRecipes()); this->populateRecipesTable(this->recipeDB->retrieveAllRecipes());
} }

View File

@ -30,10 +30,14 @@ class OpenRecipeDialog : public QDialog
void on_recipeTableView_doubleClicked(const QModelIndex &index); void on_recipeTableView_doubleClicked(const QModelIndex &index);
void onIngredientsListViewSelectionChanged(const QItemSelection &selection);
void onTagsListViewSelectionChanged(const QItemSelection &selection); void onTagsListViewSelectionChanged(const QItemSelection &selection);
void on_nameEdit_textChanged(const QString &arg1); void on_nameEdit_textChanged(const QString &arg1);
void on_foodGroupsListWidget_itemSelectionChanged();
void on_clearSearchButton_clicked(); void on_clearSearchButton_clicked();
void on_exitButton_clicked(); void on_exitButton_clicked();
@ -44,10 +48,13 @@ class OpenRecipeDialog : public QDialog
RecipeTableModel recipeTableModel; RecipeTableModel recipeTableModel;
Recipe selectedRecipe; Recipe selectedRecipe;
IngredientListModel ingredientsModel;
TagListModel tagsModel; TagListModel tagsModel;
void populateRecipesTable(vector<Recipe> recipes); void populateRecipesTable(vector<Recipe> recipes);
void populateIngredientsList();
void populateTagsList(); void populateTagsList();
void populateFoodGroupsList();
}; };
#endif // OPENRECIPEDIALOG_H #endif // OPENRECIPEDIALOG_H

View File

@ -48,7 +48,7 @@
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
<item> <item alignment="Qt::AlignLeft">
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
@ -63,7 +63,7 @@
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>2</number>
</property> </property>
<widget class="QWidget" name="Tags"> <widget class="QWidget" name="Tags">
<attribute name="icon"> <attribute name="icon">
@ -119,6 +119,105 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="ingredientsTab">
<attribute name="icon">
<iconset resource="../res.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">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="foodGroups">
<attribute name="icon">
<iconset resource="../res.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">
<enum>QFrame::NoFrame</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -8,11 +8,34 @@
#include "model/database/recipedatabase.h" #include "model/database/recipedatabase.h"
#include "utils/fileutils.h" #include "utils/fileutils.h"
void test(RecipeDatabase *recipeDB){
vector<RecipeIngredient> 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",
"Andrew Lalis",
ri,
Instruction("Placeholder Text"),
QImage(),
vector<RecipeTag>({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);
}
Recipe checkForFirstRun(RecipeDatabase *recipeDB){ Recipe checkForFirstRun(RecipeDatabase *recipeDB){
Recipe r = recipeDB->retrieveRandomRecipe(); Recipe r = recipeDB->retrieveRandomRecipe();
if (r.isEmpty()){//There are no recipes in the database. if (r.isEmpty()){//There are no recipes in the database.
//Add some basic units to the units, and some basic ingredients. //Add some basic units to the units, and some basic ingredients.
recipeDB->addBasicUnits();
recipeDB->addBasicIngredients();
} }
return r; return r;
} }

View File

@ -15,10 +15,7 @@ ResultTable Database::executeSQL(string statement){
this->sql = statement; this->sql = statement;
this->returnCode = sqlite3_prepare_v2(this->db, statement.c_str(), -1, &stmt, NULL); this->returnCode = sqlite3_prepare_v2(this->db, statement.c_str(), -1, &stmt, NULL);
if (this->returnCode != SQLITE_OK){ if (this->returnCode != SQLITE_OK){
fprintf(stderr, "Unable to successfully prepare SQL statement. Error code: %d\n\tError Message: %s\nSQL Statement: %s\n", fprintf(stderr, "Unable to successfully prepare SQL statement. Error code: %d\n\tError Message: %s\n", this->returnCode, sqlite3_errmsg(this->db));
this->returnCode,
sqlite3_errmsg(this->db),
statement.c_str());
return ResultTable(this->returnCode); return ResultTable(this->returnCode);
} }
ResultTable t(statement); ResultTable t(statement);
@ -42,15 +39,6 @@ bool Database::insertInto(string tableName, vector<string> columnNames, vector<s
return (t.getReturnCode() == SQLITE_DONE); return (t.getReturnCode() == SQLITE_DONE);
} }
bool Database::insertInto(string tableName, string columnName, string value){
if (columnName.empty() || value.empty() || tableName.empty()){
return false;
}
string query = "INSERT INTO " + tableName + " (" + columnName + ") VALUES (" + value + ");";
ResultTable t = this->executeSQL(query);
return (t.getReturnCode() == SQLITE_DONE);
}
ResultTable Database::selectFrom(string tableName, string columnNames, string conditions){ ResultTable Database::selectFrom(string tableName, string columnNames, string conditions){
if (columnNames.size() == 0 || tableName.empty()){ if (columnNames.size() == 0 || tableName.empty()){
return ResultTable(); return ResultTable();

View File

@ -24,12 +24,8 @@ public:
//Executes an SQL string statement in a safe way and returns the result. //Executes an SQL string statement in a safe way and returns the result.
ResultTable executeSQL(string statement); ResultTable executeSQL(string statement);
//Inserts into a table.
bool insertInto(string tableName, vector<string> columnNames, vector<string> values); bool insertInto(string tableName, vector<string> columnNames, vector<string> values);
bool insertInto(string tableName, string columnName, string value);
//Selects from a table.
ResultTable selectFrom(string tableName, string columnNames, string conditions); ResultTable selectFrom(string tableName, string columnNames, string conditions);
//Deletes from a table.
bool deleteFrom(string tableName, string conditions); bool deleteFrom(string tableName, string conditions);
bool tableExists(string tableName); bool tableExists(string tableName);

View File

@ -57,18 +57,66 @@ bool RecipeDatabase::storeRecipe(Recipe recipe){
return false; return false;
} }
bool RecipeDatabase::storeRecipeIngredient(Ingredient i, int recipeId){ bool RecipeDatabase::storeRecipeIngredient(RecipeIngredient ri, int recipeId){
int ingId = this->storeIngredient(ri);
if (ingId < 0) return false;
if (!this->storeUnitOfMeasure(ri.getUnit())) return false;
return this->insertInto("recipeIngredient", return this->insertInto("recipeIngredient",
vector<string>({ vector<string>({
"content", "ingredientId",
"recipeId" "recipeId",
"quantity",
"unitName",
"comment"
}), }),
vector<string>({ vector<string>({
i.getContent(), std::to_string(ingId),
std::to_string(recipeId) std::to_string(recipeId),
std::to_string(ri.getQuantity()),
ri.getUnit().getName(),
ri.getComment()
})); }));
} }
int RecipeDatabase::storeIngredient(Ingredient ingredient){
ResultTable t = this->selectFrom("ingredient", "*", "WHERE name="+surroundString(ingredient.getName(), "'"));
if (t.isEmpty()){
bool success = this->insertInto("ingredient", vector<string>({"foodGroup", "name"}), vector<string>({ingredient.getFoodGroup(), ingredient.getName()}));
if (success){
return this->getLastInsertedRowId();
} else {
return -1;
}
} else {
return std::stoi(t.at(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<string>({
"name",
"plural",
"abbreviation",
"type",
"metricCoefficient"
}),
vector<string>({
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){ bool RecipeDatabase::storeInstruction(Instruction instruction, int recipeId){
return FileUtils::saveInstruction(recipeId, instruction); return FileUtils::saveInstruction(recipeId, instruction);
} }
@ -118,6 +166,31 @@ vector<Recipe> RecipeDatabase::retrieveAllRecipes(){
return this->readRecipesFromTable(t); return this->readRecipesFromTable(t);
} }
vector<Recipe> RecipeDatabase::retrieveRecipesWithIngredients(vector<Ingredient> ingredients){
vector<Recipe> recipes;
if (ingredients.empty()){
return recipes;
}
string filterList = surroundString(ingredients.at(0).getName(), "'");
for (unsigned int i = 1; i < ingredients.size(); i++){
filterList += ", " + surroundString(ingredients[i].getName(), "'");
}
filterList = '(' + filterList + ')';
ResultTable t = this->executeSQL("SELECT * "
"FROM recipe "
"WHERE recipeId IN ("
" SELECT recipeIngredient.recipeId "
" FROM recipeIngredient "
" INNER JOIN ("
" SELECT ingredientId "
" FROM ingredient "
" WHERE name IN "+filterList+""
" ) filteredIngredients "
" ON recipeIngredient.ingredientId = filteredIngredients.ingredientId"
") ORDER BY name;");
return this->readRecipesFromTable(t);
}
vector<Recipe> RecipeDatabase::retrieveRecipesWithTags(vector<RecipeTag> tags){ vector<Recipe> RecipeDatabase::retrieveRecipesWithTags(vector<RecipeTag> tags){
vector<Recipe> recipes; vector<Recipe> recipes;
if (tags.empty()){ if (tags.empty()){
@ -137,15 +210,53 @@ vector<Recipe> RecipeDatabase::retrieveRecipesWithSubstring(string s){
return this->readRecipesFromTable(t); return this->readRecipesFromTable(t);
} }
vector<Ingredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId){ vector<Recipe> RecipeDatabase::retrieveRecipesWithFoodGroups(vector<string> groups){
ResultTable t = this->executeSQL("SELECT content " vector<Recipe> recipes;
"FROM recipeIngredient " if (groups.empty()){
"WHERE recipeId = "+std::to_string(recipeId)+";"); return recipes;
vector<Ingredient> ingredients;
for (TableRow row : t.rows()){
ingredients.push_back(Ingredient(row.at(0)));
} }
return ingredients; string filterList = surroundString(groups.at(0), "'");
for (unsigned int i = 1; i < groups.size(); i++){
filterList += ", " + surroundString(groups.at(i), "'");
}
filterList = '(' + filterList + ')';
ResultTable t = this->executeSQL("SELECT * FROM recipe WHERE recipeId IN (SELECT recipeId FROM recipeIngredient WHERE ingredientId IN (SELECT ingredientId FROM ingredient WHERE foodGroup IN "+filterList+" ) ) ORDER BY name;");
return this->readRecipesFromTable(t);
}
vector<string> RecipeDatabase::retrieveAllFoodGroups(){
ResultTable t = this->executeSQL("SELECT DISTINCT foodGroup FROM ingredient ORDER BY foodGroup;");
vector<string> foodGroups;
for (TableRow row : t.rows()){
foodGroups.push_back(row.at(0));
}
return foodGroups;
}
vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId){
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 "
"INNER JOIN unitOfMeasure "
"ON recipeIngredient.unitName = unitOfMeasure.name "
"WHERE recipeIngredient.recipeId = "+std::to_string(recipeId)+";");
vector<RecipeIngredient> ings;
for (TableRow row : t.rows()){
RecipeIngredient r(row.at(0),
row.at(1),
std::stof(row.at(2)),
UnitOfMeasure(row.at(5), row.at(6), row.at(7), std::stoi(row.at(8)), std::stod(row.at(9))),
row.at(4));
ings.push_back(r);
}
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){ bool RecipeDatabase::deleteRecipeTags(int recipeId){
@ -157,14 +268,27 @@ bool RecipeDatabase::deleteRecipeIngredients(int recipeId){
} }
vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){ vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){
ResultTable t = this->selectFrom("recipeIngredient", "content", "ORDER BY content"); ResultTable t = this->selectFrom("ingredient", "name, foodGroup", "ORDER BY name");
vector<Ingredient> ings; vector<Ingredient> ings;
for (TableRow row : t.rows()){ for (TableRow row : t.rows()){
ings.push_back(Ingredient(row.at(0))); Ingredient i(row.at(0), row.at(1));
ings.push_back(i);
} }
return ings; return ings;
} }
vector<UnitOfMeasure> RecipeDatabase::retrieveAllUnitsOfMeasure(){
ResultTable t = this->selectFrom("unitOfMeasure", "name, plural, abbreviation, type, metricCoefficient", "ORDER BY name");
vector<UnitOfMeasure> units;
if (!t.isEmpty()){
for (TableRow row : t.rows()){
UnitOfMeasure u(row.at(0), row.at(1), row.at(2), std::stoi(row.at(3)), std::stod(row.at(4)));
units.push_back(u);
}
}
return units;
}
vector<RecipeTag> RecipeDatabase::retrieveTags(int recipeId){ vector<RecipeTag> RecipeDatabase::retrieveTags(int recipeId){
ResultTable t = this->selectFrom("recipeTag", "tagName", "WHERE recipeId="+std::to_string(recipeId)+" ORDER BY tagName"); ResultTable t = this->selectFrom("recipeTag", "tagName", "WHERE recipeId="+std::to_string(recipeId)+" ORDER BY tagName");
vector<RecipeTag> tags; vector<RecipeTag> tags;
@ -234,6 +358,14 @@ bool RecipeDatabase::deleteIngredient(string name){
return this->deleteFrom("ingredient", "WHERE name='"+name+"'"); return this->deleteFrom("ingredient", "WHERE name='"+name+"'");
} }
bool RecipeDatabase::deleteUnitOfMeasure(string name){
ResultTable t = this->selectFrom("recipeIngredient", "recipeId", "WHERE unitName='"+name+"'");
if (!t.isEmpty()){
return false;
}
return this->deleteFrom("unitOfMeasure", "WHERE name='"+name+"'");
}
bool RecipeDatabase::deleteTag(RecipeTag tag){ bool RecipeDatabase::deleteTag(RecipeTag tag){
return this->deleteFrom("recipeTag", "WHERE tagName='"+tag.getValue()+"'"); return this->deleteFrom("recipeTag", "WHERE tagName='"+tag.getValue()+"'");
} }
@ -273,16 +405,22 @@ bool RecipeDatabase::updateRecipe(Recipe recipe, string originalName) {
return false; return false;
} }
bool ingredientsSuccess = this->deleteRecipeIngredients(id); bool ingredientsSuccess = this->deleteRecipeIngredients(id);
for (Ingredient i : recipe.getIngredients()){ for (RecipeIngredient ri : recipe.getIngredients()){
ingredientsSuccess = ingredientsSuccess && this->insertInto( ingredientsSuccess = ingredientsSuccess && this->insertInto(
"recipeIngredient", "recipeIngredient",
vector<string>({ vector<string>({
"recipeId", "recipeId",
"content" "ingredientId",
"unitName",
"quantity",
"comment"
}), }),
vector<string>({ vector<string>({
idS, idS,
i.getContent() std::to_string(this->retrieveIngredientId(ri.getName())),
ri.getUnit().getName(),
std::to_string(ri.getQuantity()),
ri.getComment()
})); }));
} }
if (!ingredientsSuccess){ if (!ingredientsSuccess){
@ -300,11 +438,67 @@ bool RecipeDatabase::updateRecipe(Recipe recipe, string originalName) {
} }
} }
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(){ void RecipeDatabase::ensureTablesExist(){
//Make sure that foreign keys are enabled. //Make sure that foreign keys are enabled.
this->executeSQL("PRAGMA foreign_keys = ON;"); this->executeSQL("PRAGMA foreign_keys = ON;");
this->beginTransaction(); this->beginTransaction();
//Ingredients table.
this->executeSQL("CREATE TABLE IF NOT EXISTS ingredient("
"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. //Recipe table. Each recipe can have at most one instruction, and one image.
this->executeSQL("CREATE TABLE IF NOT EXISTS recipe(" this->executeSQL("CREATE TABLE IF NOT EXISTS recipe("
"recipeId INTEGER PRIMARY KEY," "recipeId INTEGER PRIMARY KEY,"
@ -321,9 +515,14 @@ void RecipeDatabase::ensureTablesExist(){
"FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));"); "FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));");
//RecipeIngredient table. //RecipeIngredient table.
this->executeSQL("CREATE TABLE IF NOT EXISTS recipeIngredient(" this->executeSQL("CREATE TABLE IF NOT EXISTS recipeIngredient("
"ingredientId int,"
"recipeId int," "recipeId int,"
"content," "quantity real,"
"FOREIGN KEY (recipeId) REFERENCES recipe(recipeId));"); "unitName varchar,"
"comment varchar,"
"FOREIGN KEY (ingredientId) REFERENCES ingredient(ingredientId),"
"FOREIGN KEY (recipeId) REFERENCES recipe(recipeId),"
"FOREIGN KEY (unitName) REFERENCES unitOfMeasure(name));");
this->commitTransaction(); this->commitTransaction();
} }

View File

@ -23,15 +23,21 @@ class RecipeDatabase : public Database
//SQL Helper methods. //SQL Helper methods.
//Storage. //Storage.
bool storeRecipeIngredient(Ingredient i, int recipeId); bool storeRecipeIngredient(RecipeIngredient ri, int recipeId);
int storeIngredient(Ingredient ingredient);
bool storeUnitOfMeasure(UnitOfMeasure u);
//Retrieval. //Retrieval.
Recipe retrieveRecipe(string name); Recipe retrieveRecipe(string name);
Recipe retrieveRandomRecipe(); Recipe retrieveRandomRecipe();
vector<Recipe> retrieveAllRecipes(); vector<Recipe> retrieveAllRecipes();
vector<Recipe> retrieveRecipesWithIngredients(vector<Ingredient> ingredients);
vector<Recipe> retrieveRecipesWithTags(vector<RecipeTag> tags); vector<Recipe> retrieveRecipesWithTags(vector<RecipeTag> tags);
vector<Recipe> retrieveRecipesWithSubstring(string s); vector<Recipe> retrieveRecipesWithSubstring(string s);
vector<Recipe> retrieveRecipesWithFoodGroups(vector<string> groups);
vector<string> retrieveAllFoodGroups();
vector<Ingredient> retrieveAllIngredients(); vector<Ingredient> retrieveAllIngredients();
vector<UnitOfMeasure> retrieveAllUnitsOfMeasure();
vector<RecipeTag> retrieveAllTags(); vector<RecipeTag> retrieveAllTags();
//Deletion. //Deletion.
@ -44,6 +50,9 @@ class RecipeDatabase : public Database
//Updating. //Updating.
bool updateRecipe(Recipe recipe, string originalName); bool updateRecipe(Recipe recipe, string originalName);
//Adding basic information at start.
bool addBasicUnits();
bool addBasicIngredients();
private: private:
//Utility methods. //Utility methods.
@ -59,7 +68,8 @@ class RecipeDatabase : public Database
//Retrieval //Retrieval
vector<RecipeTag> retrieveTags(int recipeId); vector<RecipeTag> retrieveTags(int recipeId);
vector<Ingredient> retrieveRecipeIngredients(int recipeId); vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
int retrieveIngredientId(string ingredientName);
//Deletion //Deletion
bool deleteRecipeTags(int recipeId); bool deleteRecipeTags(int recipeId);

View File

@ -1,18 +1,31 @@
#include "model/recipe/ingredients/ingredient.h" #include "model/recipe/ingredients/ingredient.h"
Ingredient::Ingredient(){ Ingredient::Ingredient(){
setContent("NULL"); setName("NULL");
setFoodGroup("NULL");
} }
Ingredient::Ingredient(string content){ Ingredient::Ingredient(string name, string foodGroup){
setContent(content); setName(name);
setFoodGroup(foodGroup);
} }
string Ingredient::getContent() const{ string Ingredient::getName() const{
return this->content; return this->name;
} }
void Ingredient::setContent(string newContent){ string Ingredient::getFoodGroup() const{
this->content = newContent; return this->foodGroup;
} }
void Ingredient::setName(string newName){
this->name = newName;
}
void Ingredient::setFoodGroup(string newFoodGroup){
this->foodGroup = newFoodGroup;
}
string Ingredient::toString(){
return this->getName();
}

View File

@ -6,25 +6,28 @@
using namespace std; using namespace std;
/** /**
* @brief The Ingredient class represents an ingredient, which is a string representing one component of a recipe. * @brief The Ingredient class represents an ingredient, which is classified by a food group, and has a name and an ID.
* The user is free to compose a recipe string however they like. However, the program will restrict obviously * An ingredient cannot be included on its own in a recipe, and must be paired with a Unit in a RecipeIngredient Object.
* invalid input, and try to be smart about determining if an ingredient is valid.
*/ */
class Ingredient class Ingredient
{ {
public: public:
Ingredient(); Ingredient();
Ingredient(string content); Ingredient(string name, string foodGroup);
//Getters //Getters
string getContent() const; string getName() const;
string getFoodGroup() const;
//Setters //Setters
void setContent(string newContent); void setName(string newName);
void setFoodGroup(string newFoodGroup);
string toString();
protected: protected:
string content; string name;
string foodGroup;
}; };
#endif // INGREDIENT_H #endif // INGREDIENT_H

View File

@ -13,7 +13,7 @@ QVariant IngredientListModel::data(const QModelIndex &index, int role) const{
int row = index.row(); int row = index.row();
Ingredient i = this->ingredients[row]; Ingredient i = this->ingredients[row];
string displayStr = i.getContent(); string displayStr = i.toString();
switch(role){ switch(role){
case Qt::DisplayRole: case Qt::DisplayRole:
@ -30,15 +30,14 @@ void IngredientListModel::setIngredients(vector<Ingredient> ingredients){
emit dataChanged(index, bottomIndex); emit dataChanged(index, bottomIndex);
} }
bool IngredientListModel::addIngredient(Ingredient i){ bool IngredientListModel::addIngredient(Ingredient ri){
//Add only if it doesn't exist already. //Add only if it doesn't exist already.
for (Ingredient ing : this->ingredients){ for (unsigned int i = 0; i < this->ingredients.size(); i++){
if (!ing.getContent().compare(i.getContent())){ if (!this->ingredients[i].getName().compare(ri.getName())){
return false; return false;
} }
} }
//The ingredient doesn't exist already, so we'll add it. this->ingredients.push_back(ri);
this->ingredients.push_back(i);
QModelIndex index = createIndex(this->ingredients.size()-1, 0); QModelIndex index = createIndex(this->ingredients.size()-1, 0);
QModelIndex bottomIndex = createIndex(this->ingredients.size()-1, 0); QModelIndex bottomIndex = createIndex(this->ingredients.size()-1, 0);
emit dataChanged(index, bottomIndex); emit dataChanged(index, bottomIndex);

View File

@ -3,16 +3,9 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QModelIndex> #include <QModelIndex>
#include <vector>
#include "model/recipe/ingredients/ingredient.h" #include "model/recipe/ingredients/recipeingredient.h"
/**
* @brief The IngredientListModel class
*
* The ingredient list model extends the QAbstractListModel and is used for lists of ingredients,
* whether they appear in the NewRecipe dialog or in the main recipe view.
*/
class IngredientListModel : public QAbstractListModel class IngredientListModel : public QAbstractListModel
{ {
public: public:
@ -24,13 +17,15 @@ public:
//Custom methods to handle ingredient data. //Custom methods to handle ingredient data.
void setIngredients(vector<Ingredient> ingredients); void setIngredients(vector<Ingredient> ingredients);
bool addIngredient(Ingredient i); bool addIngredient(Ingredient ri);
void deleteIngredient(int index); void deleteIngredient(int index);
vector<Ingredient> getIngredients(); vector<Ingredient> getIngredients();
private: private:
vector<Ingredient> ingredients; vector<Ingredient> ingredients;
//Helper for printing.
}; };
#endif // INGREDIENTLISTMODEL_H #endif // INGREDIENTLISTMODEL_H

View File

@ -0,0 +1,60 @@
#include "model/recipe/ingredients/recipeingredient.h"
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, string comment){
setName(i.getName());
setFoodGroup(i.getFoodGroup());
setQuantity(quantity);
setUnit(unit);
setComment(comment);
}
RecipeIngredient::RecipeIngredient(Ingredient &i) : RecipeIngredient(i, 0.0f, UnitOfMeasure("bleh"), "Fuck"){
//Constructs recipe ingredient from ingredient which is a hidden recipe ingredient.
}
RecipeIngredient::RecipeIngredient(){
}
float RecipeIngredient::getQuantity() const{
return this->quantity;
}
UnitOfMeasure RecipeIngredient::getUnit() const{
return this->unit;
}
string RecipeIngredient::getComment() const{
return this->comment;
}
void RecipeIngredient::setQuantity(float newQuantity){
this->quantity = newQuantity;
}
void RecipeIngredient::setUnit(UnitOfMeasure newUnit){
this->unit = newUnit;
}
void RecipeIngredient::setComment(string newComment){
this->comment = newComment;
}
string RecipeIngredient::toString(){
string result;
if (std::ceil(this->getQuantity()) == this->getQuantity()){
result += std::to_string((int)this->getQuantity());
} else {
result += StringUtils::toString(this->getQuantity());
}
result += " " + this->getUnit().getAbbreviation() + " " + this->getName();
if (!this->getComment().empty()) result += " (" + this->getComment() + ")";
return result;
}

View File

@ -0,0 +1,43 @@
#ifndef RECIPEINGREDIENT_H
#define RECIPEINGREDIENT_H
#include <string>
#include <cmath>
#include "model/recipe/ingredients/ingredient.h"
#include "model/recipe/ingredients/unitofmeasure.h"
#include "utils/stringutils.h"
using namespace std;
/**
* @brief The RecipeIngredient class represents both an ingredient and a unit of measure, to be used in a recipe object.
*/
class RecipeIngredient : public Ingredient
{
public:
//Constructor for new RecipeIngredient without starting child ingredient.
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, string comment);
RecipeIngredient(Ingredient &i);
RecipeIngredient();
//Getters
float getQuantity() const;
UnitOfMeasure getUnit() const;
string getComment() const;
//Setters
void setQuantity(float newQuantity);
void setUnit(UnitOfMeasure newUnit);
void setComment(string newComment);
string toString();
private:
float quantity;
UnitOfMeasure unit;
string comment;
};
#endif // RECIPEINGREDIENT_H

View File

@ -0,0 +1,54 @@
#include "recipeingredientlistmodel.h"
RecipeIngredientListModel::RecipeIngredientListModel(){
this->ingredients = vector<RecipeIngredient>();
}
int RecipeIngredientListModel::rowCount(const QModelIndex &parent) const{
Q_UNUSED(parent);
return this->ingredients.size();
}
QVariant RecipeIngredientListModel::data(const QModelIndex &index, int role) const{
int row = index.row();
RecipeIngredient i = this->ingredients[row];
string displayStr = i.toString();
switch(role){
case Qt::DisplayRole:
return QString::fromStdString(displayStr);
}
return QVariant();
}
void RecipeIngredientListModel::setIngredients(vector<RecipeIngredient> ingredients){
this->ingredients = ingredients;
QModelIndex index = createIndex(0, 0);
QModelIndex bottomIndex = createIndex(ingredients.size()-1, 0);
emit dataChanged(index, bottomIndex);
}
bool RecipeIngredientListModel::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;
}
void RecipeIngredientListModel::deleteIngredient(int index){
this->ingredients.erase(this->ingredients.begin() + index);
emit dataChanged(createIndex(0, 0), createIndex(this->ingredients.size()-1, 0));
}
vector<RecipeIngredient> RecipeIngredientListModel::getIngredients(){
return this->ingredients;
}

View File

@ -0,0 +1,28 @@
#ifndef RECIPEINGREDIENTLISTMODEL_H
#define RECIPEINGREDIENTLISTMODEL_H
#include <QAbstractListModel>
#include "model/recipe/ingredients/recipeingredient.h"
class RecipeIngredientListModel : public QAbstractListModel
{
public:
RecipeIngredientListModel();
//Overridden methods.
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
//Custom methods to handle ingredient data.
void setIngredients(vector<RecipeIngredient> ingredients);
bool addIngredient(RecipeIngredient ri);
void deleteIngredient(int index);
vector<RecipeIngredient> getIngredients();
private:
vector<RecipeIngredient> ingredients;
};
#endif // RECIPEINGREDIENTLISTMODEL_H

View File

@ -0,0 +1,42 @@
#include "unitofmeasure.h"
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){
this->name = 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, 1.0){
//Default constructor initializes all fields to empty strings.
}
string UnitOfMeasure::getName() const{
return this->name;
}
string UnitOfMeasure::getNamePlural() const{
return this->plural;
}
string UnitOfMeasure::getAbbreviation() const{
return this->abbreviation;
}
int UnitOfMeasure::getType() const{
return this->type;
}
double UnitOfMeasure::getMetricCoefficient() const{
return this->metricCoefficient;
}

View File

@ -0,0 +1,42 @@
#ifndef UNITOFMEASURE_H
#define UNITOFMEASURE_H
#include <string>
using namespace std;
/**
* @brief The UnitOfMeasure class represents a way to measure an ingredient. It contains a name, an abbreviation, plural name, and some information on conversion.
*/
class UnitOfMeasure
{
public:
//Constants Declarations.
static const int MASS = 0;
static const int VOLUME = 1;
static const int LENGTH = 2;
static const int MISC = 3;
//Full constructor.
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.
UnitOfMeasure();
//Getters
string getName() const;
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.
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

View File

@ -1,6 +1,6 @@
#include "model/recipe/recipe.h" #include "model/recipe/recipe.h"
Recipe::Recipe(string name, string author, vector<Ingredient> 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); setName(name);
setAuthor(author); setAuthor(author);
setIngredients(ingredients); setIngredients(ingredients);
@ -13,7 +13,7 @@ Recipe::Recipe(string name, string author, vector<Ingredient> ingredients, Instr
setServings(servings); setServings(servings);
} }
Recipe::Recipe() : Recipe::Recipe("", "", vector<Ingredient>(), Instruction(), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(), QTime(), 1.0f){ Recipe::Recipe() : Recipe::Recipe("", "", vector<RecipeIngredient>(), Instruction(), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(), QTime(), 1.0f){
//Set default values when none are specified. //Set default values when none are specified.
} }
@ -25,10 +25,20 @@ string Recipe::getAuthor() const{
return this->authorName; return this->authorName;
} }
vector<Ingredient> Recipe::getIngredients() const{ vector<RecipeIngredient> Recipe::getIngredients() const{
return this->ingredients; return this->ingredients;
} }
vector<string> Recipe::getFoodGroups() const{
vector<string> foodGroups;
for (RecipeIngredient ri : this->ingredients){
if (find(foodGroups.begin(), foodGroups.end(), ri.getFoodGroup()) == foodGroups.end()){
foodGroups.push_back(ri.getFoodGroup());
}
}
return foodGroups;
}
Instruction Recipe::getInstruction() const{ Instruction Recipe::getInstruction() const{
return this->instruction; return this->instruction;
} }
@ -73,7 +83,7 @@ void Recipe::setAuthor(string newName){
this->authorName = newName; this->authorName = newName;
} }
void Recipe::setIngredients(vector<Ingredient> ingredients){ void Recipe::setIngredients(vector<RecipeIngredient> ingredients){
this->ingredients = ingredients; this->ingredients = ingredients;
} }
@ -81,7 +91,7 @@ void Recipe::setTags(vector<RecipeTag> tags){
this->tags = tags; this->tags = tags;
} }
void Recipe::addIngredient(Ingredient newIngredient){ void Recipe::addIngredient(RecipeIngredient newIngredient){
this->ingredients.push_back(newIngredient); this->ingredients.push_back(newIngredient);
} }
@ -119,11 +129,17 @@ void Recipe::print(){
this->servings); this->servings);
printf("\tInstruction: %s\n", this->instruction.getHTML().c_str()); printf("\tInstruction: %s\n", this->instruction.getHTML().c_str());
printf("\tIngredients:\n"); printf("\tIngredients:\n");
for (Ingredient i : this->ingredients){ for (vector<RecipeIngredient>::iterator it = this->ingredients.begin(); it != this->ingredients.end(); ++it){
printf("\t\t%s\n", i.getContent().c_str()); RecipeIngredient ri = *it;
printf("\t\t%s, Food Group: %s, Quantity: %f, Unit: %s\n",
ri.getName().c_str(),
ri.getFoodGroup().c_str(),
ri.getQuantity(),
ri.getUnit().getName().c_str());
} }
printf("\tTags:\n"); printf("\tTags:\n");
for (RecipeTag t : this->tags){ for (vector<RecipeTag>::iterator it = this->tags.begin(); it != this->tags.end(); ++it){
RecipeTag t = *it;
printf("\t\t%s\n", t.getValue().c_str()); printf("\t\t%s\n", t.getValue().c_str());
} }
} }

View File

@ -8,7 +8,7 @@
#include <QImage> #include <QImage>
#include <algorithm> #include <algorithm>
#include "model/recipe/ingredients/ingredient.h" #include "model/recipe/ingredients/recipeingredient.h"
#include "model/recipe/instruction.h" #include "model/recipe/instruction.h"
#include "model/recipe/tags/recipetag.h" #include "model/recipe/tags/recipetag.h"
@ -32,14 +32,14 @@ class Recipe
{ {
public: public:
//Full constructor //Full constructor
Recipe(string name, string author, vector<Ingredient> 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. //Constructor with default values.
Recipe(); Recipe();
//Getters //Getters
string getName() const; string getName() const;
string getAuthor() const; string getAuthor() const;
vector<Ingredient> getIngredients() const; vector<RecipeIngredient> getIngredients() const;
vector<string> getFoodGroups() const; vector<string> getFoodGroups() const;
Instruction getInstruction() const; Instruction getInstruction() const;
QImage getImage() const; QImage getImage() const;
@ -54,9 +54,9 @@ public:
//Setters //Setters
void setName(string newName); void setName(string newName);
void setAuthor(string newName); void setAuthor(string newName);
void setIngredients(vector<Ingredient> ingredients); void setIngredients(vector<RecipeIngredient> ingredients);
void setTags(vector<RecipeTag> tags); void setTags(vector<RecipeTag> tags);
void addIngredient(Ingredient newIngredient); void addIngredient(RecipeIngredient newIngredient);
void setInstruction(Instruction newInstruction); void setInstruction(Instruction newInstruction);
void setImage(QImage newImage); void setImage(QImage newImage);
void setCreatedDate(QDate newDate); void setCreatedDate(QDate newDate);
@ -64,13 +64,12 @@ public:
void setCookTime(QTime newTime); void setCookTime(QTime newTime);
void setServings(float newServingsCount); void setServings(float newServingsCount);
//Prints information about the recipe to the console, for debugging.
void print(); void print();
private: private:
//Main information. //Main information.
string name; //The name of the recipe. string name; //The name of the recipe.
string authorName; //The name of the author of this recipe. string authorName; //The name of the author of this recipe.
vector<Ingredient> ingredients; //The list of ingredients in the recipe. vector<RecipeIngredient> ingredients; //The list of ingredients in the recipe.
Instruction instruction; //The instruction HTML document. Instruction instruction; //The instruction HTML document.
QImage image; //An image displayed alongside the recipe. QImage image; //An image displayed alongside the recipe.
//Auxiliary Information. //Auxiliary Information.