Stable first release #10
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 "";
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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(){
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue