Stable first release #10

Merged
andrewlalis merged 3 commits from development into master 2018-03-31 18:36:02 +00:00
11 changed files with 141 additions and 33 deletions
Showing only changes of commit b736410044 - Show all commits

View File

@ -95,11 +95,12 @@ void MainWindow::on_exitButton_clicked(){
void MainWindow::on_editButton_clicked(){ void MainWindow::on_editButton_clicked(){
NewRecipeDialog d(this->recipeDB, this->currentRecipe, this); NewRecipeDialog d(this->recipeDB, this->currentRecipe, this);
string originalName = this->currentRecipe.getName();
d.show(); d.show();
d.exec(); d.exec();
if (d.isAccepted()){ if (d.isAccepted()){
Recipe r = d.getRecipe(); 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!")); 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 { } else {
this->loadFromRecipe(r); this->loadFromRecipe(r);

View File

@ -100,7 +100,6 @@
<widget class="QLineEdit" name="recipeNameEdit"> <widget class="QLineEdit" name="recipeNameEdit">
<property name="font"> <property name="font">
<font> <font>
<pointsize>16</pointsize>
<weight>3</weight> <weight>3</weight>
<italic>false</italic> <italic>false</italic>
<bold>false</bold> <bold>false</bold>
@ -142,7 +141,7 @@
<second>0</second> <second>0</second>
<year>1999</year> <year>1999</year>
<month>12</month> <month>12</month>
<day>24</day> <day>23</day>
</datetime> </datetime>
</property> </property>
<property name="currentSection"> <property name="currentSection">
@ -352,6 +351,9 @@
<property name="selectionMode"> <property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum> <enum>QAbstractItemView::MultiSelection</enum>
</property> </property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -667,6 +669,9 @@
<property name="selectionMode"> <property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum> <enum>QAbstractItemView::MultiSelection</enum>
</property> </property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="batchSize"> <property name="batchSize">
<number>100</number> <number>100</number>
</property> </property>
@ -746,16 +751,6 @@
<string notr="true">background-color: rgb(250, 250, 255);</string> <string notr="true">background-color: rgb(250, 250, 255);</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_8"> <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"> <item alignment="Qt::AlignLeft|Qt::AlignTop">
<widget class="QWidget" name="textControlPanel" native="true"> <widget class="QWidget" name="textControlPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5"> <layout class="QHBoxLayout" name="horizontalLayout_5">
@ -769,7 +764,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>I</string> <string>Italic</string>
</property> </property>
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
@ -789,7 +784,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>B</string> <string>Bold</string>
</property> </property>
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
@ -827,7 +822,7 @@
<enum>Qt::LeftToRight</enum> <enum>Qt::LeftToRight</enum>
</property> </property>
<property name="autoFillBackground"> <property name="autoFillBackground">
<bool>true</bool> <bool>false</bool>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string> <string notr="true">background-color: rgb(255, 255, 255);</string>

View File

@ -127,3 +127,11 @@ void OpenRecipeDialog::on_foodGroupsListWidget_itemSelectionChanged(){
} }
this->populateRecipesTable(this->recipeDB->retrieveRecipesWithFoodGroups(groups)); 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());
}

View File

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

View File

@ -147,13 +147,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="searchButton"> <widget class="QPushButton" name="clearSearchButton">
<property name="text"> <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> </property>
</widget> </widget>
</item> </item>

View File

@ -14,12 +14,11 @@ ResultTable Database::executeSQL(string statement){
sqlite3_stmt* stmt; sqlite3_stmt* stmt;
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);
ResultTable t(statement);
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\n", this->returnCode, sqlite3_errmsg(this->db)); 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); t.extractData(stmt);
this->returnCode = sqlite3_finalize(stmt); this->returnCode = sqlite3_finalize(stmt);
@ -78,6 +77,18 @@ void Database::closeConnection(){
this->dbIsOpen = false; 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){ string Database::combineVector(std::vector<string> strings, string mid){
if (strings.empty()){ if (strings.empty()){
return ""; return "";

View File

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

View File

@ -253,6 +253,18 @@ vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId)
return ings; 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(){ vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){
ResultTable t = this->selectFrom("ingredient", "name, foodGroup", "ORDER BY name"); ResultTable t = this->selectFrom("ingredient", "name, foodGroup", "ORDER BY name");
vector<Ingredient> ings; vector<Ingredient> ings;
@ -356,8 +368,71 @@ bool RecipeDatabase::deleteTag(RecipeTag tag){
return this->deleteFrom("recipeTag", "WHERE tagName='"+tag.getValue()+"'"); 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()+"', "
"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;
}
} }
void RecipeDatabase::ensureTablesExist(){ void RecipeDatabase::ensureTablesExist(){

View File

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

View File

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

View File

@ -21,6 +21,8 @@ class ResultTable
ResultTable(); ResultTable();
//Constructs a table with the original query saved. //Constructs a table with the original query saved.
ResultTable(string query); 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. //Gets all the data from the result set and stores it internally as strings.
void extractData(sqlite3_stmt* stmt); void extractData(sqlite3_stmt* stmt);