Actually Usable Version #7

Merged
andrewlalis merged 7 commits from development into master 2018-03-29 14:11:27 +00:00
20 changed files with 321 additions and 77 deletions
Showing only changes of commit 076212e392 - Show all commits

View File

@ -58,7 +58,7 @@ void MainWindow::setCookTime(QTime cookTime){
}
void MainWindow::setServings(float servings){
ui->servingsLabel->setText(QString("Servings: ")+QString::fromStdString(StringUtils::toString(servings)));
ui->servingsLabel->setText(QString(QString::fromStdString(StringUtils::toString(servings) + " Serving" + ((servings != 1.0f) ? "s" : ""))));
}
void MainWindow::setTags(vector<RecipeTag> tags){
@ -72,14 +72,22 @@ void MainWindow::on_newButton_clicked(){
if (d.isAccepted()){
Recipe r = d.getRecipe();
if (!this->recipeDB->storeRecipe(r)){
QMessageBox::critical(this, QString("Unable to Save Recipe"), QString("The program was not able to successfully save the recipe."));
}
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);
}
}
}
void MainWindow::on_openButton_clicked(){
OpenRecipeDialog d(this->recipeDB, this);
d.show();
d.exec();
if (!d.getSelectedRecipe().isEmpty()){
this->loadFromRecipe(d.getSelectedRecipe());
}
}
void MainWindow::on_exitButton_clicked(){
this->close();
}

View File

@ -34,6 +34,8 @@ public:
void on_openButton_clicked();
void on_exitButton_clicked();
private:
Ui::MainWindow *ui;
RecipeDatabase *recipeDB;

View File

@ -143,6 +143,12 @@ QPushButton#newButton:pressed{
</item>
<item alignment="Qt::AlignTop">
<widget class="QPushButton" name="openButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
@ -175,6 +181,9 @@ QPushButton#openButton:pressed{
</item>
<item alignment="Qt::AlignTop">
<widget class="QPushButton" name="browseButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>150</width>
@ -211,6 +220,56 @@ QPushButton#browseButton:pressed{
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exitButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>150</horstretch>
<verstretch>80</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>80</height>
</size>
</property>
<property name="font">
<font>
<family>Noto Sans CJK KR Light</family>
<pointsize>20</pointsize>
<stylestrategy>PreferAntialias</stylestrategy>
</font>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#exitButton {
background-color: rgb(255, 216, 216);
border: 0px;
}
QPushButton#exitButton:hover{
background-color: rgb(255, 191, 191);
}
QPushButton#exitButton:pressed{
background-color: rgb(255, 147, 147);
}</string>
</property>
<property name="text">
<string>Exit</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -367,6 +426,9 @@ font: &quot;Noto Sans CJK KR&quot;;</string>
<property name="text">
<string>Prep Time:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
@ -383,6 +445,9 @@ font: &quot;Noto Sans CJK KR&quot;;</string>
<property name="text">
<string>Cook Time:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
@ -396,6 +461,9 @@ font: &quot;Noto Sans CJK KR&quot;;</string>
<property name="text">
<string>Servings:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>

View File

@ -119,7 +119,7 @@ void NewRecipeDialog::on_selectImageButton_clicked(){
}
}
void NewRecipeDialog::on_deleteIngredientButton_clicked(){
void NewRecipeDialog::on_removeIngredientButton_clicked(){
QModelIndexList indexList = ui->ingredientsListView->selectionModel()->selectedIndexes();
for (QModelIndexList::iterator it = indexList.begin(); it != indexList.end(); ++it){
QModelIndex i = *it;
@ -127,6 +127,22 @@ void NewRecipeDialog::on_deleteIngredientButton_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);
d.show();
@ -155,8 +171,8 @@ void NewRecipeDialog::on_newTagButton_clicked(){
}
void NewRecipeDialog::on_removeTagButton_clicked(){
int index = ui->tagsComboBox->currentIndex();
if (index < 0 || index >= this->tags.size()){
unsigned int index = ui->tagsComboBox->currentIndex();
if (index >= this->tags.size()){
return;
}
RecipeTag tag = this->tags[ui->tagsComboBox->currentIndex()];
@ -180,3 +196,18 @@ void NewRecipeDialog::on_newUnitButton_clicked(){
}
}
}
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

@ -47,6 +47,8 @@ class NewRecipeDialog : public QDialog
void on_selectImageButton_clicked();
void on_removeIngredientButton_clicked();
void on_deleteIngredientButton_clicked();
void on_newIngredientButton_clicked();
@ -57,6 +59,8 @@ class NewRecipeDialog : public QDialog
void on_newUnitButton_clicked();
void on_deleteUnitButton_clicked();
private:
Ui::NewRecipeDialog *ui;
RecipeDatabase *recipeDB;

View File

@ -158,7 +158,7 @@
<second>0</second>
<year>1999</year>
<month>12</month>
<day>26</day>
<day>25</day>
</datetime>
</property>
<property name="currentSection">
@ -504,6 +504,17 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteIngredientButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/minus_icon.png</normaloff>:/images/images/minus_icon.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -579,6 +590,17 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteUnitButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/minus_icon.png</normaloff>:/images/images/minus_icon.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -627,7 +649,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteIngredientButton">
<widget class="QPushButton" name="removeIngredientButton">
<property name="text">
<string>Delete</string>
</property>

View File

@ -20,13 +20,45 @@ OpenRecipeDialog::~OpenRecipeDialog()
delete ui;
}
Recipe OpenRecipeDialog::getSelectedRecipe(){
return this->selectedRecipe;
}
void OpenRecipeDialog::populateRecipesTable(){
this->recipeTableModel.clear();
vector<Recipe> recipes = this->recipeDB->retrieveAllRecipes();
// printf("Found %d recipes:\n", recipes.size());
// for (Recipe r : recipes){
// r.print();
// printf("\n------------------\n");
// }
this->recipeTableModel.setRecipes(recipes);
ui->recipeTableView->resizeColumnsToContents();
ui->recipeTableView->show();
}
void OpenRecipeDialog::on_deleteRecipeButton_clicked(){
QItemSelectionModel *selectModel = ui->recipeTableView->selectionModel();
if (!selectModel->hasSelection()){
return;
}
vector<int> rows;
QModelIndexList indexes = selectModel->selectedIndexes();
for (int i = 0; i < indexes.count(); i++){
rows.push_back(indexes.at(i).row());
}
string recipePlural = (rows.size() == 1) ? "recipe" : "recipes";
QString title = QString::fromStdString("Delete " + recipePlural);
QString content = QString::fromStdString("Are you sure you wish to delete the selected "+recipePlural+"?");
QMessageBox::StandardButton reply = QMessageBox::question(this, title, content);
if (reply == QMessageBox::Yes){
for (int row : rows){
Recipe r = this->recipeTableModel.getRecipeAt(row);
bool success = this->recipeDB->deleteRecipe(r.getName());
if (!success){
QMessageBox::critical(this, QString::fromStdString("Unable to Delete"), QString::fromStdString("Could not delete recipe "+r.getName()));
}
}
this->populateRecipesTable();
}
}
void OpenRecipeDialog::on_recipeTableView_doubleClicked(const QModelIndex &index){
this->selectedRecipe = this->recipeTableModel.getRecipeAt(index.row());
this->close();
}

View File

@ -2,6 +2,7 @@
#define OPENRECIPEDIALOG_H
#include <QDialog>
#include <QMessageBox>
#include "model/database/recipedatabase.h"
#include "model/recipe/recipetablemodel.h"
@ -19,10 +20,18 @@ class OpenRecipeDialog : public QDialog
OpenRecipeDialog(RecipeDatabase *recipeDB, QWidget *parent = 0);
~OpenRecipeDialog();
Recipe getSelectedRecipe();
private slots:
void on_deleteRecipeButton_clicked();
void on_recipeTableView_doubleClicked(const QModelIndex &index);
private:
Ui::OpenRecipeDialog *ui;
RecipeDatabase *recipeDB;
RecipeTableModel recipeTableModel;
Recipe selectedRecipe;
void populateRecipesTable();
};

View File

@ -86,6 +86,23 @@
</layout>
</widget>
</item>
<item alignment="Qt::AlignLeft|Qt::AlignTop">
<widget class="QWidget" name="interactionPanel" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="deleteRecipeButton">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/images/trash.png</normaloff>:/images/images/trash.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="contentPanel" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
@ -94,6 +111,9 @@
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>

View File

@ -5,5 +5,6 @@
<file>images/plus_icon.png</file>
<file>images/minus_icon.png</file>
<file>images/search_icon.png</file>
<file>images/trash.png</file>
</qresource>
</RCC>

View File

@ -13,45 +13,28 @@ int main(int argc, char *argv[])
w.show();
//TESTING CODE
// 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), ""));
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",
// ri,
// Instruction("<b>BOLD</b><i>iTaLiCs</i>"),
// QImage(),
// vector<RecipeTag>({RecipeTag("testing"),
// RecipeTag("fake")}),
// QDate::currentDate(),
// QTime(0, 30),
// QTime(0, 25),
// 10.0f);
Recipe rec("Example",
ri,
Instruction("<b>BOLD</b><i>iTaLiCs</i>"),
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);
bool success = recipeDB.storeRecipe(rec);
printf("Storage successful: %d\n", success);
// recipeDB.storeUnitOfMeasure(UnitOfMeasure("tablespoon", "tablespoons", "tbsp", UnitOfMeasure::VOLUME, 1.0));
// recipeDB.storeUnitOfMeasure(UnitOfMeasure("pinch", "pinches", "pch", UnitOfMeasure::VOLUME, 1.0));
// recipeDB.storeUnitOfMeasure(UnitOfMeasure("gram", "grams", "g", UnitOfMeasure::MASS, 1.0));
//recipeDB.selectFrom("recipe", "recipeId, name", "").printData();
w.loadFromRecipe(recipeDB.retrieveRandomRecipe());
// Recipe reloadRec = recipeDB.retrieveRecipe("Example");
// reloadRec.print();
// w.loadFromRecipe(reloadRec);
// NewRecipeDialog d(&recipeDB);
// d.show();
// d.exec();
// if (d.isAccepted()){
// printf("Accepted the dialog.\n");
// }
bool success = recipeDB.deleteRecipe(4);
printf("Success: %d\n", success);
recipeDB.selectFrom("recipe", "recipeId, name", "").printData();
w.loadFromRecipe(recipeDB.retrieveRecipe("Generic Bread"));
return a.exec();
a.exec();
recipeDB.closeConnection();
return 0;
}

View File

@ -31,6 +31,8 @@ public:
bool tableExists(string tableName);
int getLastInsertedRowId();
void closeConnection();
protected:
string surroundString(string s, string surround);
@ -44,7 +46,6 @@ private:
char* errorMsg;
void openConnection();
void closeConnection();
std::string combineVector(std::vector<std::string> strings, std::string mid);
};

View File

@ -147,18 +147,16 @@ Recipe RecipeDatabase::retrieveRecipe(string name){
fprintf(stderr, "Error: No recipe with name %s found!\n", name.c_str());
return Recipe();
}
Recipe r;
int id = std::stoi(t.valueAt(0, 0));
r.setName(t.valueAt(0, 1));
r.setCreatedDate(QDate::fromString(QString::fromStdString(t.valueAt(0, 2))));
r.setPrepTime(QTime::fromString(QString::fromStdString(t.valueAt(0, 3))));
r.setCookTime(QTime::fromString(QString::fromStdString(t.valueAt(0, 4))));
r.setServings(std::stof(t.valueAt(0, 5)));
r.setInstruction(FileUtils::loadInstruction(id));
r.setImage(FileUtils::loadImage(id));
r.setIngredients(this->retrieveRecipeIngredients(id));
r.setTags(this->retrieveTags(id));
return r;
return this->readFromResultTable(t);
}
Recipe RecipeDatabase::retrieveRandomRecipe(){
ResultTable t = this->selectFrom("recipe", "*", "ORDER BY RANDOM() LIMIT 1");
if (t.isEmpty()){
fprintf(stderr, "Unable to find a random recipe.\n");
return Recipe();
}
return this->readFromResultTable(t);
}
vector<Recipe> RecipeDatabase::retrieveAllRecipes(){
@ -239,7 +237,7 @@ vector<RecipeTag> RecipeDatabase::retrieveAllTags(){
}
bool RecipeDatabase::deleteRecipe(string name){
ResultTable t = this->selectFrom("recipe", "recipeId", "WHERE name="+name);
ResultTable t = this->selectFrom("recipe", "recipeId", "WHERE name='"+name+"'");
if (t.rowCount() != 1){
return false;
}
@ -250,6 +248,7 @@ bool RecipeDatabase::deleteRecipe(string name){
bool RecipeDatabase::deleteRecipe(int recipeId){
string idString = std::to_string(recipeId);
if (this->selectFrom("recipe", "recipeId", "WHERE recipeId="+idString).isEmpty()){
printf("Cannot delete. No recipe with ID %d exists.\n", recipeId);
return false;
}
this->executeSQL("BEGIN;");
@ -266,27 +265,28 @@ bool RecipeDatabase::deleteRecipe(int recipeId){
}
bool RecipeDatabase::deleteIngredient(string name){
ResultTable t = this->selectFrom("recipeIngredient", "recipeId", "WHERE ingredientId=("
"SELECT ingredientId"
"FROM ingredient"
"WHERE name="+name+")");
ResultTable t = this->executeSQL("SELECT recipeId "
"FROM recipeIngredient "
"INNER JOIN ingredient "
"ON recipeIngredient.ingredientId = ingredient.ingredientId "
"WHERE ingredient.name='"+name+"';");
if (!t.isEmpty()){
//There is at least one recipe dependent on the ingredient.
return false;
}
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);
ResultTable t = this->selectFrom("recipeIngredient", "recipeId", "WHERE unitName='"+name+"'");
if (!t.isEmpty()){
return false;
}
return this->deleteFrom("unitOfMeasure", "WHERE name="+name);
return this->deleteFrom("unitOfMeasure", "WHERE name='"+name+"'");
}
bool RecipeDatabase::deleteTag(RecipeTag tag){
return this->deleteFrom("recipeTag", "WHERE tagName="+tag.getValue());
return this->deleteFrom("recipeTag", "WHERE tagName='"+tag.getValue()+"'");
}
void RecipeDatabase::ensureTablesExist(){
@ -331,3 +331,18 @@ void RecipeDatabase::ensureTablesExist(){
"FOREIGN KEY (unitName) REFERENCES unitOfMeasure(name));");
this->executeSQL("COMMIT;");
}
Recipe RecipeDatabase::readFromResultTable(ResultTable t, int row){
Recipe r;
int id = std::stoi(t.valueAt(row, 0));
r.setName(t.valueAt(row, 1));
r.setCreatedDate(QDate::fromString(QString::fromStdString(t.valueAt(row, 2))));
r.setPrepTime(QTime::fromString(QString::fromStdString(t.valueAt(row, 3))));
r.setCookTime(QTime::fromString(QString::fromStdString(t.valueAt(row, 4))));
r.setServings(std::stof(t.valueAt(row, 5)));
r.setInstruction(FileUtils::loadInstruction(id));
r.setImage(FileUtils::loadImage(id));
r.setIngredients(this->retrieveRecipeIngredients(id));
r.setTags(this->retrieveTags(id));
return r;
}

View File

@ -32,6 +32,7 @@ class RecipeDatabase : public Database
//Retrieval.
Recipe retrieveRecipe(string name);
Recipe retrieveRandomRecipe();
vector<Recipe> retrieveAllRecipes();
vector<RecipeIngredient> retrieveRecipeIngredients(int recipeId);
vector<Ingredient> retrieveAllIngredients();
@ -49,6 +50,8 @@ class RecipeDatabase : public Database
//Utility methods.
void ensureTablesExist();
//Read a recipe from a row of a result table.
Recipe readFromResultTable(ResultTable t, int row=0);
};
#endif // RECIPEDATABASE_H

View File

@ -50,7 +50,7 @@ string RecipeIngredient::toString(){
result += StringUtils::toString(this->getQuantity());
}
result += " " + this->getUnit().getAbbreviation() + " " + this->getName();
if (!this->getComment().empty()) result += " ~" + this->getComment();
if (!this->getComment().empty()) result += " (" + this->getComment() + ")";
return result;
}

View File

@ -12,7 +12,7 @@ Recipe::Recipe(string name, vector<RecipeIngredient> ingredients, Instruction in
setServings(servings);
}
Recipe::Recipe() : Recipe::Recipe("Unnamed Recipe", vector<RecipeIngredient>(), Instruction(), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(1, 0), QTime(0, 30), 10.0f){
Recipe::Recipe() : Recipe::Recipe("", vector<RecipeIngredient>(), Instruction(), QImage(), vector<RecipeTag>(), QDate::currentDate(), QTime(1, 0), QTime(0, 30), 10.0f){
//Set default values when none are specified.
}
@ -56,6 +56,10 @@ float Recipe::getServings() const{
return this->servings;
}
bool Recipe::isEmpty() const{
return this->name.empty();
}
void Recipe::setName(string newName){
this->name = newName;
}

View File

@ -46,6 +46,7 @@ public:
QTime getCookTime() const;
QTime getTotalTime() const; //Derived method to add prep and cook times.
float getServings() const;
bool isEmpty() const;
//Setters
void setName(string newName);

View File

@ -16,7 +16,7 @@ int RecipeTableModel::rowCount(const QModelIndex &parent) const{
int RecipeTableModel::columnCount(const QModelIndex &parent) const{
Q_UNUSED(parent);
return 2;//FIX THIS TO BE MORE ADAPTIVE EVENTUALLY.
return 5;//FIX THIS TO BE MORE ADAPTIVE EVENTUALLY.
}
QVariant RecipeTableModel::data(const QModelIndex &index, int role) const{
@ -30,6 +30,12 @@ QVariant RecipeTableModel::data(const QModelIndex &index, int role) const{
return QString::fromStdString(r.getName());
case 1:
return QString::fromStdString(r.getCreatedDate().toString().toStdString());
case 2:
return QString::fromStdString(StringUtils::toString(r.getServings()));
case 3:
return r.getPrepTime().toString("hh:mm:ss");
case 4:
return r.getCookTime().toString("hh:mm:ss");
}
}
return QVariant();
@ -45,6 +51,12 @@ QVariant RecipeTableModel::headerData(int section, Qt::Orientation orientation,
return "Name";
case 1:
return "Created On";
case 2:
return "Servings";
case 3:
return "Prep Time";
case 4:
return "Cook Time";
default:
return QVariant();
}
@ -59,3 +71,16 @@ void RecipeTableModel::setRecipes(vector<Recipe> recipes){
this->recipes = recipes;
endInsertRows();
}
Recipe RecipeTableModel::getRecipeAt(int index){
if (index < 0 || index >= this->recipes.size()){
return Recipe();
}
return this->recipes[index];
}
void RecipeTableModel::clear(){
beginResetModel();
this->recipes.clear();
endResetModel();
}

View File

@ -4,6 +4,7 @@
#include <QAbstractTableModel>
#include "model/recipe/recipe.h"
#include "utils/stringutils.h"
class RecipeTableModel : public QAbstractTableModel
{
@ -19,7 +20,8 @@ class RecipeTableModel : public QAbstractTableModel
//Normal methods.
void setRecipes(vector<Recipe> recipes);
Recipe getRecipeAt(int index);
void clear();
private:
vector<Recipe> recipes;
};

View File

@ -2,6 +2,14 @@
namespace StringUtils{
bool stringEndsWith(std::string const &fullString, std::string const &ending){
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
} else {
return false;
}
}
std::string toString(float val){
float decimal = std::fmod(val, 1.0f);
int places = 1;
@ -13,6 +21,11 @@ std::string toString(float val){
std::string arg = "%."+std::to_string(places)+"f";
sprintf(buffer, arg.c_str(), val);
std::string s = buffer;
if (stringEndsWith(s, ".0")){
while (s.find('.') != std::string::npos){
s.pop_back();
}
}
return s;
}