Stable first release #10
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -95,11 +95,12 @@ void MainWindow::on_exitButton_clicked(){
 | 
			
		|||
 | 
			
		||||
void MainWindow::on_editButton_clicked(){
 | 
			
		||||
	NewRecipeDialog d(this->recipeDB, this->currentRecipe, this);
 | 
			
		||||
	string originalName = this->currentRecipe.getName();
 | 
			
		||||
	d.show();
 | 
			
		||||
	d.exec();
 | 
			
		||||
	if (d.isAccepted()){
 | 
			
		||||
		Recipe r = d.getRecipe();
 | 
			
		||||
		if (!this->recipeDB->storeRecipe(r)){
 | 
			
		||||
		if (!this->recipeDB->updateRecipe(r, originalName)){
 | 
			
		||||
			QMessageBox::critical(this, QString("Unable to Save Recipe"), QString("The program was not able to successfully save the recipe. Make sure to give the recipe a name, instructions, and some ingredients!"));
 | 
			
		||||
		} else {
 | 
			
		||||
			this->loadFromRecipe(r);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,6 @@
 | 
			
		|||
                <widget class="QLineEdit" name="recipeNameEdit">
 | 
			
		||||
                 <property name="font">
 | 
			
		||||
                  <font>
 | 
			
		||||
                   <pointsize>16</pointsize>
 | 
			
		||||
                   <weight>3</weight>
 | 
			
		||||
                   <italic>false</italic>
 | 
			
		||||
                   <bold>false</bold>
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +141,7 @@
 | 
			
		|||
                      <second>0</second>
 | 
			
		||||
                      <year>1999</year>
 | 
			
		||||
                      <month>12</month>
 | 
			
		||||
                      <day>24</day>
 | 
			
		||||
                      <day>23</day>
 | 
			
		||||
                     </datetime>
 | 
			
		||||
                    </property>
 | 
			
		||||
                    <property name="currentSection">
 | 
			
		||||
| 
						 | 
				
			
			@ -352,6 +351,9 @@
 | 
			
		|||
              <property name="selectionMode">
 | 
			
		||||
               <enum>QAbstractItemView::MultiSelection</enum>
 | 
			
		||||
              </property>
 | 
			
		||||
              <property name="verticalScrollMode">
 | 
			
		||||
               <enum>QAbstractItemView::ScrollPerPixel</enum>
 | 
			
		||||
              </property>
 | 
			
		||||
             </widget>
 | 
			
		||||
            </item>
 | 
			
		||||
           </layout>
 | 
			
		||||
| 
						 | 
				
			
			@ -667,6 +669,9 @@
 | 
			
		|||
                 <property name="selectionMode">
 | 
			
		||||
                  <enum>QAbstractItemView::MultiSelection</enum>
 | 
			
		||||
                 </property>
 | 
			
		||||
                 <property name="verticalScrollMode">
 | 
			
		||||
                  <enum>QAbstractItemView::ScrollPerPixel</enum>
 | 
			
		||||
                 </property>
 | 
			
		||||
                 <property name="batchSize">
 | 
			
		||||
                  <number>100</number>
 | 
			
		||||
                 </property>
 | 
			
		||||
| 
						 | 
				
			
			@ -746,16 +751,6 @@
 | 
			
		|||
         <string notr="true">background-color: rgb(250, 250, 255);</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <layout class="QVBoxLayout" name="verticalLayout_8">
 | 
			
		||||
         <item>
 | 
			
		||||
          <widget class="QLabel" name="instructionsLabel">
 | 
			
		||||
           <property name="text">
 | 
			
		||||
            <string>Instructions</string>
 | 
			
		||||
           </property>
 | 
			
		||||
           <property name="alignment">
 | 
			
		||||
            <set>Qt::AlignCenter</set>
 | 
			
		||||
           </property>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
         <item alignment="Qt::AlignLeft|Qt::AlignTop">
 | 
			
		||||
          <widget class="QWidget" name="textControlPanel" native="true">
 | 
			
		||||
           <layout class="QHBoxLayout" name="horizontalLayout_5">
 | 
			
		||||
| 
						 | 
				
			
			@ -769,7 +764,7 @@
 | 
			
		|||
               </font>
 | 
			
		||||
              </property>
 | 
			
		||||
              <property name="text">
 | 
			
		||||
               <string>I</string>
 | 
			
		||||
               <string>Italic</string>
 | 
			
		||||
              </property>
 | 
			
		||||
              <property name="checkable">
 | 
			
		||||
               <bool>true</bool>
 | 
			
		||||
| 
						 | 
				
			
			@ -789,7 +784,7 @@
 | 
			
		|||
               </font>
 | 
			
		||||
              </property>
 | 
			
		||||
              <property name="text">
 | 
			
		||||
               <string>B</string>
 | 
			
		||||
               <string>Bold</string>
 | 
			
		||||
              </property>
 | 
			
		||||
              <property name="checkable">
 | 
			
		||||
               <bool>true</bool>
 | 
			
		||||
| 
						 | 
				
			
			@ -827,7 +822,7 @@
 | 
			
		|||
         <enum>Qt::LeftToRight</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="autoFillBackground">
 | 
			
		||||
         <bool>true</bool>
 | 
			
		||||
         <bool>false</bool>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="styleSheet">
 | 
			
		||||
         <string notr="true">background-color: rgb(255, 255, 255);</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,3 +127,11 @@ void OpenRecipeDialog::on_foodGroupsListWidget_itemSelectionChanged(){
 | 
			
		|||
	}
 | 
			
		||||
	this->populateRecipesTable(this->recipeDB->retrieveRecipesWithFoodGroups(groups));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenRecipeDialog::on_clearSearchButton_clicked(){
 | 
			
		||||
	ui->nameEdit->clear();
 | 
			
		||||
	ui->foodGroupsListWidget->selectionModel()->clearSelection();
 | 
			
		||||
	ui->tagsListView->selectionModel()->clearSelection();
 | 
			
		||||
	ui->ingredientsListView->selectionModel()->clearSelection();
 | 
			
		||||
	this->populateRecipesTable(this->recipeDB->retrieveAllRecipes());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,8 @@ class OpenRecipeDialog : public QDialog
 | 
			
		|||
 | 
			
		||||
		void on_foodGroupsListWidget_itemSelectionChanged();
 | 
			
		||||
 | 
			
		||||
		void on_clearSearchButton_clicked();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Ui::OpenRecipeDialog *ui;
 | 
			
		||||
		RecipeDatabase *recipeDB;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -147,13 +147,9 @@
 | 
			
		|||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item>
 | 
			
		||||
       <widget class="QPushButton" name="searchButton">
 | 
			
		||||
       <widget class="QPushButton" name="clearSearchButton">
 | 
			
		||||
        <property name="text">
 | 
			
		||||
         <string/>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="icon">
 | 
			
		||||
         <iconset resource="../images.qrc">
 | 
			
		||||
          <normaloff>:/images/images/search_icon.png</normaloff>:/images/images/search_icon.png</iconset>
 | 
			
		||||
         <string>Clear search criteria</string>
 | 
			
		||||
        </property>
 | 
			
		||||
       </widget>
 | 
			
		||||
      </item>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,12 +14,11 @@ ResultTable Database::executeSQL(string statement){
 | 
			
		|||
	sqlite3_stmt* stmt;
 | 
			
		||||
	this->sql = statement;
 | 
			
		||||
	this->returnCode = sqlite3_prepare_v2(this->db, statement.c_str(), -1, &stmt, NULL);
 | 
			
		||||
	ResultTable t(statement);
 | 
			
		||||
	if (this->returnCode != SQLITE_OK){
 | 
			
		||||
		fprintf(stderr, "Unable to successfully prepare SQL statement. Error code: %d\n\tError Message: %s\n", this->returnCode, sqlite3_errmsg(this->db));
 | 
			
		||||
		return t;
 | 
			
		||||
		return ResultTable(this->returnCode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ResultTable t(statement);
 | 
			
		||||
	t.extractData(stmt);
 | 
			
		||||
 | 
			
		||||
	this->returnCode = sqlite3_finalize(stmt);
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +77,18 @@ void Database::closeConnection(){
 | 
			
		|||
	this->dbIsOpen = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Database::beginTransaction(){
 | 
			
		||||
	this->executeSQL("BEGIN;");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Database::commitTransaction(){
 | 
			
		||||
	this->executeSQL("COMMIT;");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Database::rollbackTransaction(){
 | 
			
		||||
	this->executeSQL("ROLLBACK;");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
string Database::combineVector(std::vector<string> strings, string mid){
 | 
			
		||||
	if (strings.empty()){
 | 
			
		||||
		return "";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,10 @@ public:
 | 
			
		|||
 | 
			
		||||
	void closeConnection();
 | 
			
		||||
 | 
			
		||||
	void beginTransaction();
 | 
			
		||||
	void commitTransaction();
 | 
			
		||||
	void rollbackTransaction();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	string surroundString(string s, string surround);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -253,6 +253,18 @@ vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId)
 | 
			
		|||
	return ings;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int RecipeDatabase::retrieveIngredientId(string ingredientName){
 | 
			
		||||
	return std::stoi(this->selectFrom("ingredient", "ingredientId", "WHERE name = '"+ingredientName+"'").at(0, 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RecipeDatabase::deleteRecipeTags(int recipeId){
 | 
			
		||||
	return this->deleteFrom("recipeTag", "WHERE recipeId = "+std::to_string(recipeId));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RecipeDatabase::deleteRecipeIngredients(int recipeId){
 | 
			
		||||
	return this->deleteFrom("recipeIngredient", "WHERE recipeId = "+std::to_string(recipeId));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){
 | 
			
		||||
	ResultTable t = this->selectFrom("ingredient", "name, foodGroup", "ORDER BY name");
 | 
			
		||||
	vector<Ingredient> ings;
 | 
			
		||||
| 
						 | 
				
			
			@ -356,8 +368,71 @@ bool RecipeDatabase::deleteTag(RecipeTag tag){
 | 
			
		|||
	return this->deleteFrom("recipeTag", "WHERE tagName='"+tag.getValue()+"'");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RecipeDatabase::updateRecipe(Recipe recipe){
 | 
			
		||||
 | 
			
		||||
bool RecipeDatabase::updateRecipe(Recipe recipe, string originalName) {
 | 
			
		||||
	string idS = this->selectFrom("recipe", "recipeId", "WHERE name="+surroundString(originalName, "'")).at(0, 0);
 | 
			
		||||
	int id = std::stoi(idS);
 | 
			
		||||
	this->beginTransaction();
 | 
			
		||||
	ResultTable t = this->executeSQL("UPDATE recipe "
 | 
			
		||||
									 "SET name = '"+recipe.getName()+"', "
 | 
			
		||||
									 "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(){
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,9 +26,6 @@ class RecipeDatabase : public Database
 | 
			
		|||
		bool storeRecipeIngredient(RecipeIngredient ri, int recipeId);
 | 
			
		||||
		int storeIngredient(Ingredient ingredient);
 | 
			
		||||
		bool storeUnitOfMeasure(UnitOfMeasure u);
 | 
			
		||||
		bool storeInstruction(Instruction instruction, int recipeId);
 | 
			
		||||
		bool storeImage(QImage image, int recipeId);
 | 
			
		||||
		bool storeTags(vector<RecipeTag> tags, int recipeId);
 | 
			
		||||
 | 
			
		||||
		//Retrieval.
 | 
			
		||||
		Recipe retrieveRecipe(string name);
 | 
			
		||||
| 
						 | 
				
			
			@ -39,10 +36,8 @@ class RecipeDatabase : public Database
 | 
			
		|||
		vector<Recipe> retrieveRecipesWithSubstring(string s);
 | 
			
		||||
		vector<Recipe> retrieveRecipesWithFoodGroups(vector<string> groups);
 | 
			
		||||
		vector<string> retrieveAllFoodGroups();
 | 
			
		||||
		vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
 | 
			
		||||
		vector<Ingredient> retrieveAllIngredients();
 | 
			
		||||
		vector<UnitOfMeasure> retrieveAllUnitsOfMeasure();
 | 
			
		||||
		vector<RecipeTag> retrieveTags(int recipeId);
 | 
			
		||||
		vector<RecipeTag> retrieveAllTags();
 | 
			
		||||
 | 
			
		||||
		//Deletion.
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +48,7 @@ class RecipeDatabase : public Database
 | 
			
		|||
		bool deleteTag(RecipeTag tag);
 | 
			
		||||
 | 
			
		||||
		//Updating.
 | 
			
		||||
		bool updateRecipe(Recipe recipe);
 | 
			
		||||
		bool updateRecipe(Recipe recipe, string originalName);
 | 
			
		||||
	private:
 | 
			
		||||
 | 
			
		||||
		//Utility methods.
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +56,20 @@ class RecipeDatabase : public Database
 | 
			
		|||
		//Read a recipe from a row of a result table.
 | 
			
		||||
		Recipe readFromResultTable(ResultTable t, int row=0);
 | 
			
		||||
		vector<Recipe> readRecipesFromTable(ResultTable t);
 | 
			
		||||
 | 
			
		||||
		//Storage
 | 
			
		||||
		bool storeInstruction(Instruction instruction, int recipeId);
 | 
			
		||||
		bool storeImage(QImage image, int recipeId);
 | 
			
		||||
		bool storeTags(vector<RecipeTag> tags, int recipeId);
 | 
			
		||||
 | 
			
		||||
		//Retrieval
 | 
			
		||||
		vector<RecipeTag> retrieveTags(int recipeId);
 | 
			
		||||
		vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
 | 
			
		||||
		int retrieveIngredientId(string ingredientName);
 | 
			
		||||
 | 
			
		||||
		//Deletion
 | 
			
		||||
		bool deleteRecipeTags(int recipeId);
 | 
			
		||||
		bool deleteRecipeIngredients(int recipeId);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // RECIPEDATABASE_H
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,10 @@ ResultTable::ResultTable(string query){
 | 
			
		|||
	this->originalQuery = query;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ResultTable::ResultTable(int resultCode){
 | 
			
		||||
	this->queryCode = resultCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ResultTable::extractData(sqlite3_stmt *stmt){
 | 
			
		||||
	this->values.clear();
 | 
			
		||||
	int res = sqlite3_step(stmt);
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +34,7 @@ void ResultTable::processRow(sqlite3_stmt *stmt){
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void ResultTable::printData(){
 | 
			
		||||
	printf("--> Result Code: [%d] <--\n", this->getReturnCode());
 | 
			
		||||
	if (this->isEmpty()){
 | 
			
		||||
		printf("Result table is empty.\n");
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,8 @@ class ResultTable
 | 
			
		|||
		ResultTable();
 | 
			
		||||
		//Constructs a table with the original query saved.
 | 
			
		||||
		ResultTable(string query);
 | 
			
		||||
		//Constructs an empty table with a result code.
 | 
			
		||||
		ResultTable(int resultCode);
 | 
			
		||||
 | 
			
		||||
		//Gets all the data from the result set and stores it internally as strings.
 | 
			
		||||
		void extractData(sqlite3_stmt* stmt);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue