More security and less unexpected behaviour. #8
|
@ -195,6 +195,7 @@ void NewRecipeDialog::on_newUnitButton_clicked(){
|
||||||
QMessageBox::critical(this, "Error", "Unable to store new unit.");
|
QMessageBox::critical(this, "Error", "Unable to store new unit.");
|
||||||
} else {
|
} else {
|
||||||
this->populateUnitsBox();
|
this->populateUnitsBox();
|
||||||
|
ui->unitComboBox->setCurrentText(QString::fromStdString(u.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
35
main.cpp
35
main.cpp
|
@ -6,6 +6,8 @@
|
||||||
#include "model/database/recipedatabase.h"
|
#include "model/database/recipedatabase.h"
|
||||||
#include "utils/fileutils.h"
|
#include "utils/fileutils.h"
|
||||||
|
|
||||||
|
void test(RecipeDatabase *recipeDB);
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
RecipeDatabase recipeDB(QString(FileUtils::appDataPath+"recipes.db").toStdString());
|
RecipeDatabase recipeDB(QString(FileUtils::appDataPath+"recipes.db").toStdString());
|
||||||
|
@ -14,6 +16,18 @@ int main(int argc, char *argv[])
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
//TESTING CODE
|
//TESTING CODE
|
||||||
|
test(&recipeDB);
|
||||||
|
|
||||||
|
//END TESTING CODE.
|
||||||
|
|
||||||
|
w.loadFromRecipe(recipeDB.retrieveRandomRecipe());
|
||||||
|
|
||||||
|
a.exec();
|
||||||
|
recipeDB.closeConnection();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test(RecipeDatabase *recipeDB){
|
||||||
vector<RecipeIngredient> ri;
|
vector<RecipeIngredient> ri;
|
||||||
ri.push_back(RecipeIngredient("flour", "grains", 3.0f, UnitOfMeasure("cup", "cups", "c", UnitOfMeasure::VOLUME, 1.0), ""));
|
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), ""));
|
ri.push_back(RecipeIngredient("baking powder", "additives", 1.0f, UnitOfMeasure("teaspoon", "teaspoons", "tsp", UnitOfMeasure::VOLUME, 1.0), ""));
|
||||||
|
@ -29,12 +43,21 @@ int main(int argc, char *argv[])
|
||||||
QTime(0, 25),
|
QTime(0, 25),
|
||||||
10.0f);
|
10.0f);
|
||||||
|
|
||||||
bool success = recipeDB.storeRecipe(rec);
|
bool success = recipeDB->storeRecipe(rec);
|
||||||
printf("Storage successful: %d\n", success);
|
printf("Storage successful: %d\n", success);
|
||||||
|
|
||||||
w.loadFromRecipe(recipeDB.retrieveRandomRecipe());
|
vector<string> foodGroups = recipeDB->retrieveAllFoodGroups();
|
||||||
|
printf("Food Groups:\n");
|
||||||
a.exec();
|
for (string s : foodGroups){
|
||||||
recipeDB.closeConnection();
|
printf("\t%s\n", s.c_str());
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
//Get food groups from recipe.
|
||||||
|
Recipe r = recipeDB->retrieveRecipe("Pannenkoeken");
|
||||||
|
vector<string> foodGroupsR = r.getFoodGroups();
|
||||||
|
printf("Pannenkoeken Food Groups:\n");
|
||||||
|
for (string s : foodGroupsR){
|
||||||
|
printf("\t%s\n", s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ int RecipeDatabase::storeIngredient(Ingredient ingredient){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return std::stoi(t.valueAt(0, 0));
|
return std::stoi(t.at(0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,12 +162,21 @@ Recipe RecipeDatabase::retrieveRandomRecipe(){
|
||||||
vector<Recipe> RecipeDatabase::retrieveAllRecipes(){
|
vector<Recipe> RecipeDatabase::retrieveAllRecipes(){
|
||||||
ResultTable t = this->selectFrom("recipe", "name", "ORDER BY name");
|
ResultTable t = this->selectFrom("recipe", "name", "ORDER BY name");
|
||||||
vector<Recipe> recipes;
|
vector<Recipe> recipes;
|
||||||
for (unsigned int row = 0; row < t.rowCount(); row++){
|
for (TableRow row : t.rows()){
|
||||||
recipes.push_back(this->retrieveRecipe(t.valueAt(row, 0)));
|
recipes.push_back(this->retrieveRecipe(row.at(0)));
|
||||||
}
|
}
|
||||||
return recipes;
|
return recipes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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){
|
vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId){
|
||||||
ResultTable t = this->executeSQL("SELECT ingredient.name, ingredient.foodGroup, "//0, 1
|
ResultTable t = this->executeSQL("SELECT ingredient.name, ingredient.foodGroup, "//0, 1
|
||||||
"recipeIngredient.quantity, recipeIngredient.unitName, recipeIngredient.comment,"//2, 3, 4
|
"recipeIngredient.quantity, recipeIngredient.unitName, recipeIngredient.comment,"//2, 3, 4
|
||||||
|
@ -179,33 +188,33 @@ vector<RecipeIngredient> RecipeDatabase::retrieveRecipeIngredients(int recipeId)
|
||||||
"ON recipeIngredient.unitName = unitOfMeasure.name "
|
"ON recipeIngredient.unitName = unitOfMeasure.name "
|
||||||
"WHERE recipeIngredient.recipeId = "+std::to_string(recipeId)+";");
|
"WHERE recipeIngredient.recipeId = "+std::to_string(recipeId)+";");
|
||||||
vector<RecipeIngredient> ings;
|
vector<RecipeIngredient> ings;
|
||||||
for (unsigned int row = 0; row < t.rowCount(); row++){
|
for (TableRow row : t.rows()){
|
||||||
RecipeIngredient r(t.valueAt(row, 0),
|
RecipeIngredient r(row.at(0),
|
||||||
t.valueAt(row, 1),
|
row.at(1),
|
||||||
std::stof(t.valueAt(row, 2)),
|
std::stof(row.at(2)),
|
||||||
UnitOfMeasure(t.valueAt(row, 5), t.valueAt(row, 6), t.valueAt(row, 7), std::stoi(t.valueAt(row, 8)), std::stod(t.valueAt(row, 9))),
|
UnitOfMeasure(row.at(5), row.at(6), row.at(7), std::stoi(row.at(8)), std::stod(row.at(9))),
|
||||||
t.valueAt(row, 4));
|
row.at(4));
|
||||||
ings.push_back(r);
|
ings.push_back(r);
|
||||||
}
|
}
|
||||||
return ings;
|
return ings;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){
|
vector<Ingredient> RecipeDatabase::retrieveAllIngredients(){
|
||||||
ResultTable t = this->selectFrom("ingredient", "*", "ORDER BY name");
|
ResultTable t = this->selectFrom("ingredient", "name, foodGroup", "ORDER BY name");
|
||||||
vector<Ingredient> ings;
|
vector<Ingredient> ings;
|
||||||
for (unsigned int row = 0; row < t.rowCount(); row++){
|
for (TableRow row : t.rows()){
|
||||||
Ingredient i(t.valueAt(row, 2), t.valueAt(row, 1));
|
Ingredient i(row.at(0), row.at(1));
|
||||||
ings.push_back(i);
|
ings.push_back(i);
|
||||||
}
|
}
|
||||||
return ings;
|
return ings;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<UnitOfMeasure> RecipeDatabase::retrieveAllUnitsOfMeasure(){
|
vector<UnitOfMeasure> RecipeDatabase::retrieveAllUnitsOfMeasure(){
|
||||||
ResultTable t = this->selectFrom("unitOfMeasure", "*", "ORDER BY name");
|
ResultTable t = this->selectFrom("unitOfMeasure", "name, plural, abbreviation, type, metricCoefficient", "ORDER BY name");
|
||||||
vector<UnitOfMeasure> units;
|
vector<UnitOfMeasure> units;
|
||||||
if (!t.isEmpty()){
|
if (!t.isEmpty()){
|
||||||
for (unsigned int row = 0; row < t.rowCount(); row++){
|
for (TableRow row : t.rows()){
|
||||||
UnitOfMeasure u(t.valueAt(row, 0), t.valueAt(row, 1), t.valueAt(row, 2), std::stoi(t.valueAt(row, 3)), std::stod(t.valueAt(row, 4)));
|
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);
|
units.push_back(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,11 +222,11 @@ vector<UnitOfMeasure> RecipeDatabase::retrieveAllUnitsOfMeasure(){
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<RecipeTag> RecipeDatabase::retrieveTags(int recipeId){
|
vector<RecipeTag> RecipeDatabase::retrieveTags(int recipeId){
|
||||||
ResultTable t = this->selectFrom("recipeTag", "tagName", "WHERE recipeId="+std::to_string(recipeId));
|
ResultTable t = this->selectFrom("recipeTag", "tagName", "WHERE recipeId="+std::to_string(recipeId)+" ORDER BY tagName");
|
||||||
vector<RecipeTag> tags;
|
vector<RecipeTag> tags;
|
||||||
if (!t.isEmpty()){
|
if (!t.isEmpty()){
|
||||||
for (unsigned int row = 0; row < t.rowCount(); row++){
|
for (TableRow row : t.rows()){
|
||||||
RecipeTag tag(t.valueAt(row, 0));
|
RecipeTag tag(row.at(0));
|
||||||
tags.push_back(tag);
|
tags.push_back(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,8 +237,8 @@ vector<RecipeTag> RecipeDatabase::retrieveAllTags(){
|
||||||
ResultTable t = this->selectFrom("recipeTag", "tagName", "ORDER BY tagName");
|
ResultTable t = this->selectFrom("recipeTag", "tagName", "ORDER BY tagName");
|
||||||
vector<RecipeTag> tags;
|
vector<RecipeTag> tags;
|
||||||
if (!t.isEmpty()){
|
if (!t.isEmpty()){
|
||||||
for (unsigned int row = 0; row < t.rowCount(); row++){
|
for (TableRow row : t.rows()){
|
||||||
RecipeTag tag(t.valueAt(row, 0));
|
RecipeTag tag(row.at(0));
|
||||||
tags.push_back(tag);
|
tags.push_back(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +250,7 @@ bool RecipeDatabase::deleteRecipe(string name){
|
||||||
if (t.rowCount() != 1){
|
if (t.rowCount() != 1){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
string recipeId = t.valueAt(0, 0);
|
string recipeId = t.at(0, 0);
|
||||||
return this->deleteRecipe(std::stoi(recipeId));
|
return this->deleteRecipe(std::stoi(recipeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +266,8 @@ bool RecipeDatabase::deleteRecipe(int recipeId){
|
||||||
bool recipeDeleted = this->deleteFrom("recipe", "WHERE recipeId="+idString);
|
bool recipeDeleted = this->deleteFrom("recipe", "WHERE recipeId="+idString);
|
||||||
bool instructionDeleted = FileUtils::deleteInstruction(recipeId);
|
bool instructionDeleted = FileUtils::deleteInstruction(recipeId);
|
||||||
bool imageDeleted = FileUtils::deleteImage(recipeId);
|
bool imageDeleted = FileUtils::deleteImage(recipeId);
|
||||||
|
Q_UNUSED(instructionDeleted);
|
||||||
|
Q_UNUSED(imageDeleted);
|
||||||
if (tagsDeleted && recipeIngredientDeleted && recipeDeleted){
|
if (tagsDeleted && recipeIngredientDeleted && recipeDeleted){
|
||||||
this->executeSQL("COMMIT;");
|
this->executeSQL("COMMIT;");
|
||||||
return true;
|
return true;
|
||||||
|
@ -334,14 +345,15 @@ void RecipeDatabase::ensureTablesExist(){
|
||||||
this->executeSQL("COMMIT;");
|
this->executeSQL("COMMIT;");
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipe RecipeDatabase::readFromResultTable(ResultTable t, int row){
|
Recipe RecipeDatabase::readFromResultTable(ResultTable t, int tRow){
|
||||||
Recipe r;
|
Recipe r;
|
||||||
int id = std::stoi(t.valueAt(row, 0));
|
TableRow row = t.rows().at(tRow);
|
||||||
r.setName(t.valueAt(row, 1));
|
int id = std::stoi(row.at(0));
|
||||||
r.setCreatedDate(QDate::fromString(QString::fromStdString(t.valueAt(row, 2))));
|
r.setName(row.at(1));
|
||||||
r.setPrepTime(QTime::fromString(QString::fromStdString(t.valueAt(row, 3))));
|
r.setCreatedDate(QDate::fromString(QString::fromStdString(row.at(2))));
|
||||||
r.setCookTime(QTime::fromString(QString::fromStdString(t.valueAt(row, 4))));
|
r.setPrepTime(QTime::fromString(QString::fromStdString(row.at(3))));
|
||||||
r.setServings(std::stof(t.valueAt(row, 5)));
|
r.setCookTime(QTime::fromString(QString::fromStdString(row.at(4))));
|
||||||
|
r.setServings(std::stof(row.at(5)));
|
||||||
r.setInstruction(FileUtils::loadInstruction(id));
|
r.setInstruction(FileUtils::loadInstruction(id));
|
||||||
r.setImage(FileUtils::loadImage(id));
|
r.setImage(FileUtils::loadImage(id));
|
||||||
r.setIngredients(this->retrieveRecipeIngredients(id));
|
r.setIngredients(this->retrieveRecipeIngredients(id));
|
||||||
|
|
|
@ -34,6 +34,7 @@ class RecipeDatabase : public Database
|
||||||
Recipe retrieveRecipe(string name);
|
Recipe retrieveRecipe(string name);
|
||||||
Recipe retrieveRandomRecipe();
|
Recipe retrieveRandomRecipe();
|
||||||
vector<Recipe> retrieveAllRecipes();
|
vector<Recipe> retrieveAllRecipes();
|
||||||
|
vector<string> retrieveAllFoodGroups();
|
||||||
vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
|
vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
|
||||||
vector<Ingredient> retrieveAllIngredients();
|
vector<Ingredient> retrieveAllIngredients();
|
||||||
vector<UnitOfMeasure> retrieveAllUnitsOfMeasure();
|
vector<UnitOfMeasure> retrieveAllUnitsOfMeasure();
|
||||||
|
|
|
@ -47,7 +47,7 @@ bool ResultTable::isEmpty(){
|
||||||
return this->values.empty();
|
return this->values.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
string ResultTable::valueAt(unsigned int row, unsigned int col){
|
string ResultTable::at(unsigned int row, unsigned int col){
|
||||||
if (isIndexValid(row, col)){
|
if (isIndexValid(row, col)){
|
||||||
return this->values[row][col];
|
return this->values[row][col];
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,6 +78,10 @@ unsigned int ResultTable::rowCount(){
|
||||||
return this->values.size();
|
return this->values.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<vector<string> > ResultTable::rows(){
|
||||||
|
return this->values;
|
||||||
|
}
|
||||||
|
|
||||||
string ResultTable::convertToString(sqlite3_value *val){
|
string ResultTable::convertToString(sqlite3_value *val){
|
||||||
const unsigned char* raw_text = sqlite3_value_text(val);
|
const unsigned char* raw_text = sqlite3_value_text(val);
|
||||||
if (raw_text == 0){
|
if (raw_text == 0){
|
||||||
|
|
|
@ -12,6 +12,8 @@ using namespace std;
|
||||||
* @brief The ResultTable class is an object that contains the results of an SQL query, in string form.
|
* @brief The ResultTable class is an object that contains the results of an SQL query, in string form.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef vector<string> TableRow;
|
||||||
|
|
||||||
class ResultTable
|
class ResultTable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -28,11 +30,12 @@ class ResultTable
|
||||||
void printData();
|
void printData();
|
||||||
|
|
||||||
bool isEmpty();
|
bool isEmpty();
|
||||||
string valueAt(unsigned int row, unsigned int col);
|
string at(unsigned int row, unsigned int col);
|
||||||
int getReturnCode();
|
int getReturnCode();
|
||||||
string getOriginalQuery();
|
string getOriginalQuery();
|
||||||
unsigned int columnCount();
|
unsigned int columnCount();
|
||||||
unsigned int rowCount();
|
unsigned int rowCount();
|
||||||
|
vector<vector<string>> rows();
|
||||||
private:
|
private:
|
||||||
vector<vector<string>> values;
|
vector<vector<string>> values;
|
||||||
int queryCode;
|
int queryCode;
|
||||||
|
|
|
@ -24,6 +24,16 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "model/recipe/ingredients/recipeingredient.h"
|
#include "model/recipe/ingredients/recipeingredient.h"
|
||||||
#include "model/recipe/instruction.h"
|
#include "model/recipe/instruction.h"
|
||||||
|
@ -38,6 +39,7 @@ public:
|
||||||
//Getters
|
//Getters
|
||||||
string getName() const;
|
string getName() const;
|
||||||
vector<RecipeIngredient> getIngredients() const;
|
vector<RecipeIngredient> getIngredients() const;
|
||||||
|
vector<string> getFoodGroups() const;
|
||||||
Instruction getInstruction() const;
|
Instruction getInstruction() const;
|
||||||
QImage getImage() const;
|
QImage getImage() const;
|
||||||
vector<RecipeTag> getTags() const;
|
vector<RecipeTag> getTags() const;
|
||||||
|
|
|
@ -72,8 +72,8 @@ void RecipeTableModel::setRecipes(vector<Recipe> recipes){
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipe RecipeTableModel::getRecipeAt(int index){
|
Recipe RecipeTableModel::getRecipeAt(unsigned int index){
|
||||||
if (index < 0 || index >= this->recipes.size()){
|
if (index >= this->recipes.size()){
|
||||||
return Recipe();
|
return Recipe();
|
||||||
}
|
}
|
||||||
return this->recipes[index];
|
return this->recipes[index];
|
||||||
|
|
|
@ -20,7 +20,7 @@ class RecipeTableModel : public QAbstractTableModel
|
||||||
|
|
||||||
//Normal methods.
|
//Normal methods.
|
||||||
void setRecipes(vector<Recipe> recipes);
|
void setRecipes(vector<Recipe> recipes);
|
||||||
Recipe getRecipeAt(int index);
|
Recipe getRecipeAt(unsigned int index);
|
||||||
void clear();
|
void clear();
|
||||||
private:
|
private:
|
||||||
vector<Recipe> recipes;
|
vector<Recipe> recipes;
|
||||||
|
|
|
@ -29,4 +29,13 @@ std::string toString(float val){
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printVector(std::vector<std::string> &vect){
|
||||||
|
std::printf("Vector of %ld elements:\n", vect.size());
|
||||||
|
int c = 0;
|
||||||
|
for (std::string s : vect){
|
||||||
|
std::printf("\t[%d] = %s\n", c, s.c_str());
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define STRINGUTILS_H
|
#define STRINGUTILS_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace StringUtils{
|
namespace StringUtils{
|
||||||
|
|
Loading…
Reference in New Issue