Sat, 09 Apr 2022 10:26:35 +0200
Show adjust_to100 in a function. Show percentages in fermentables table only before bottling or keggng. Implemented change add moment for fermentables.
/** * EditRecipe.cpp is part of bmsapp. * * bmsapp is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * bmsapp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "MainWindow.h" #include "EditRecipe.h" #include "../ui/ui_EditRecipe.h" #include "Utils.h" EditRecipe::EditRecipe(int id, QWidget *parent) : QDialog(parent), ui(new Ui::EditRecipe) { QSqlQuery query; qDebug() << "EditRecipe record:" << id; recipe = new Recipe; ui->setupUi(this); recipe->fermentables_row = recipe->hops_row = recipe->misc_row = recipe->yeasts_row = recipe->mashs_row = -1; recipe->fermentables_use100 = false; this->recno = id; WindowTitle(); ui->typeEdit->addItem(tr("Extract")); ui->typeEdit->addItem(tr("Partial Mash")); ui->typeEdit->addItem(tr("All Grain")); ui->color_methodEdit->addItem("Morey"); ui->color_methodEdit->addItem("Mosher"); ui->color_methodEdit->addItem("Daniels"); ui->color_methodEdit->addItem("Halberstadt"); ui->color_methodEdit->addItem("Naudts"); ui->ibu_methodEdit->addItem("Tinseth"); ui->ibu_methodEdit->addItem("Rager"); ui->ibu_methodEdit->addItem("Daniels"); ui->beerstyleEdit->addItem(""); // First add a dummy query.prepare("SELECT style_guide,style_letter,name FROM profile_styles ORDER BY style_guide,style_letter,name"); query.exec(); query.first(); for (int i = 0; i < query.size(); i++) { ui->beerstyleEdit->addItem(query.value(0).toString()+" "+query.value(1).toString()+" "+query.value(2).toString()); query.next(); } if (id >= 0) { query.prepare("SELECT * FROM recipes WHERE record = :recno"); query.bindValue(":recno", id); query.exec(); query.next(); recipe->record = query.value(0).toInt(); recipe->uuid = query.value(1).toString(); recipe->locked = query.value(2).toInt() ? true:false; recipe->st_name = query.value(3).toString(); recipe->st_letter = query.value(4).toString(); recipe->st_guide = query.value(5).toString(); recipe->st_category = query.value(6).toString(); recipe->st_category_number = query.value(7).toInt(); recipe->st_type = query.value(8).toInt(); recipe->st_og_min = query.value(9).toDouble(); recipe->st_og_max = query.value(10).toDouble(); recipe->st_fg_min = query.value(11).toDouble(); recipe->st_fg_max = query.value(12).toDouble(); recipe->st_ibu_min = query.value(13).toDouble(); recipe->st_ibu_max = query.value(14).toDouble(); recipe->st_color_min = query.value(15).toDouble(); recipe->st_color_max = query.value(16).toDouble(); recipe->st_carb_min = query.value(17).toDouble(); recipe->st_carb_max = query.value(18).toDouble(); recipe->st_abv_min = query.value(19).toDouble(); recipe->st_abv_max = query.value(20).toDouble(); recipe->name = query.value(21).toString(); recipe->notes = query.value(22).toString(); recipe->type = query.value(23).toInt(); recipe->batch_size = query.value(24).toDouble(); recipe->boil_size = query.value(25).toDouble(); recipe->boil_time = query.value(26).toDouble(); recipe->efficiency = query.value(27).toDouble(); recipe->est_og = query.value(28).toDouble(); recipe->est_fg = query.value(29).toDouble(); recipe->est_abv = query.value(30).toDouble(); recipe->est_color = query.value(31).toDouble(); recipe->color_method = query.value(32).toInt(); recipe->est_ibu = query.value(33).toDouble(); recipe->ibu_method = query.value(34).toInt(); recipe->est_carb = query.value(35).toDouble(); recipe->sparge_temp = query.value(36).toDouble(); recipe->sparge_ph = query.value(37).toDouble(); recipe->sparge_volume = query.value(38).toDouble(); recipe->sparge_source = query.value(39).toInt(); recipe->sparge_acid_type = query.value(40).toInt(); recipe->sparge_acid_perc = query.value(41).toDouble(); recipe->sparge_acid_amount = query.value(42).toDouble(); recipe->mash_ph = query.value(43).toDouble(); recipe->mash_name = query.value(44).toString(); recipe->calc_acid = query.value(45).toInt() ? true:false; recipe->w1_name = query.value(46).toString(); recipe->w1_amount = query.value(47).toDouble(); recipe->w1_calcium = query.value(48).toDouble(); recipe->w1_sulfate = query.value(49).toDouble(); recipe->w1_chloride = query.value(50).toDouble(); recipe->w1_sodium = query.value(51).toDouble(); recipe->w1_magnesium = query.value(52).toDouble(); recipe->w1_total_alkalinity = query.value(53).toDouble(); recipe->w1_ph = query.value(54).toDouble(); recipe->w1_cost = query.value(55).toDouble(); recipe->w2_name = query.value(56).toString(); recipe->w2_amount = query.value(57).toDouble(); recipe->w2_calcium = query.value(58).toDouble(); recipe->w2_sulfate = query.value(59).toDouble(); recipe->w2_chloride = query.value(60).toDouble(); recipe->w2_sodium = query.value(61).toDouble(); recipe->w2_magnesium = query.value(62).toDouble(); recipe->w2_total_alkalinity = query.value(63).toDouble(); recipe->w2_ph = query.value(64).toDouble(); recipe->w2_cost = query.value(65).toDouble(); recipe->wg_amount = query.value(66).toDouble(); recipe->wg_calcium = query.value(67).toDouble(); recipe->wg_sulfate = query.value(68).toDouble(); recipe->wg_chloride = query.value(69).toDouble(); recipe->wg_sodium = query.value(70).toDouble(); recipe->wg_magnesium = query.value(71).toDouble(); recipe->wg_total_alkalinity = query.value(72).toDouble(); recipe->wg_ph = query.value(73).toDouble(); recipe->wb_calcium = query.value(74).toDouble(); recipe->wb_sulfate = query.value(75).toDouble(); recipe->wb_chloride = query.value(76).toDouble(); recipe->wb_sodium = query.value(77).toDouble(); recipe->wb_magnesium = query.value(78).toDouble(); recipe->wb_total_alkalinity = query.value(79).toDouble(); recipe->wb_ph = query.value(80).toDouble(); recipe->wa_acid_name = query.value(81).toInt(); recipe->wa_acid_perc = query.value(82).toDouble(); recipe->wa_base_name = query.value(83).toInt(); QJsonParseError parseError; const auto& f_json = query.value(84).toString(); if (!f_json.trimmed().isEmpty()) { const auto& formattedJson = QString("%1").arg(f_json); QJsonDocument fermentables = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ; } else if (fermentables.isArray()) { for (int i = 0; i < fermentables.array().size(); i++) { QJsonObject obj = fermentables.array().at(i).toObject(); Fermentables f; f.f_name = obj["f_name"].toString(); f.f_origin = obj["f_origin"].toString(); f.f_supplier = obj["f_supplier"].toString(); f.f_amount = obj["f_amount"].toDouble(); f.f_cost = obj["f_cost"].toDouble(); f.f_type = obj["f_type"].toInt(); f.f_yield = obj["f_yield"].toDouble(); f.f_color = obj["f_color"].toDouble(); f.f_coarse_fine_diff = obj["f_coarse_fine_diff"].toDouble(); f.f_moisture = obj["f_moisture"].toDouble(); f.f_diastatic_power = obj["f_diastatic_power"].toDouble(); f.f_protein = obj["f_protein"].toDouble(); f.f_dissolved_protein = obj["f_dissolved_protein"].toDouble(); f.f_max_in_batch = obj["f_max_in_batch"].toDouble(); f.f_graintype = obj["f_graintype"].toInt(); f.f_added = obj["f_added"].toInt(); f.f_recommend_mash = obj["f_recommend_mash"].toInt() ? true:false; f.f_add_after_boil = obj["f_add_after_boil"].toInt() ? true:false; f.f_adjust_to_total_100 = obj["f_adjust_to_total_100"].toInt() ? true:false; f.f_percentage = obj["f_percentage"].toDouble(); f.f_di_ph = obj["f_di_ph"].toDouble(); f.f_acid_to_ph_57 = obj["f_acid_to_ph_57"].toDouble(); if (f.f_adjust_to_total_100) recipe->fermentables_use100 = true; recipe->fermentables.append(f); } qDebug() << "fermentables" << recipe->fermentables.size(); } } else { qDebug() << "empty fermentables"; } const auto& h_json = query.value(85).toString(); if (!h_json.trimmed().isEmpty()) { const auto& formattedJson = QString("%1").arg(h_json); QJsonDocument hops = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset; } else if (hops.isArray()) { for (int i = 0; i < hops.array().size(); i++) { QJsonObject obj = hops.array().at(i).toObject(); qDebug() << i << obj; Hops h; h.h_name = obj["h_name"].toString(); h.h_origin = obj["h_origin"].toString(); h.h_amount = obj["h_amount"].toDouble(); h.h_cost = obj["h_cost"].toDouble(); h.h_type = obj["h_type"].toInt(); h.h_form = obj["h_form"].toInt(); h.h_useat = obj["h_useat"].toInt(); h.h_time = obj["h_time"].toInt(); h.h_alpha = obj["h_alpha"].toDouble(); h.h_beta = obj["h_beta"].toDouble(); h.h_hsi = obj["h_hsi"].toDouble(); h.h_humulene = obj["h_humulene"].toDouble(); h.h_caryophyllene = obj["h_caryophyllene"].toDouble(); h.h_cohumulone = obj["h_cohumulone"].toDouble(); h.h_myrcene = obj["h_myrcene"].toDouble(); h.h_total_oil = obj["h_total_oil"].toDouble(); recipe->hops.append(h); } qDebug() << "hops" << recipe->hops.size(); } } else { qDebug() << "empty hops"; } const auto& m_json = query.value(86).toString(); if (!m_json.trimmed().isEmpty()) { const auto& formattedJson = QString("%1").arg(m_json); QJsonDocument miscs = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset; } else if (miscs.isArray()) { for (int i = 0; i < miscs.array().size(); i++) { QJsonObject obj = miscs.array().at(i).toObject(); qDebug() << i << obj; Miscs m; m.m_name = obj["m_name"].toString(); m.m_amount = obj["m_amount"].toDouble(); m.m_type = obj["m_type"].toInt(); m.m_use_use = obj["m_type"].toInt(); m.m_time = obj["m_time"].toDouble(); m.m_amount_is_weight = obj["m_amount_is_weight"].toInt() ? true:false; m.m_cost = obj["m_cost"].toDouble(); recipe->miscs.append(m); } qDebug() << "miscs" << recipe->miscs.size(); } } else { qDebug() << "empty miscs"; } const auto& y_json = query.value(87).toString(); if (!y_json.trimmed().isEmpty()) { const auto& formattedJson = QString("%1").arg(y_json); QJsonDocument yeasts = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ; } else if (yeasts.isArray()) { for (int i = 0; i < yeasts.array().size(); i++) { QJsonObject obj = yeasts.array().at(i).toObject(); qDebug() << i << obj; Yeasts y; y.y_name = obj["y_name"].toString(); y.y_laboratory = obj["y_laboratory"].toString(); y.y_product_id = obj["y_product_id"].toString(); y.y_amount = obj["y_amount"].toDouble(); y.y_type = obj["y_type"].toInt(); y.y_form = obj["y_form"].toInt(); y.y_min_temperature = obj["y_min_temperature"].toDouble(); y.y_max_temperature = obj["y_max_temperature"].toDouble(); y.y_flocculation = obj["y_flocculation"].toInt(); y.y_attenuation = obj["y_attenuation"].toDouble(); y.y_cells = obj["y_cells"].toDouble(); y.y_tolerance = obj["y_tolerance"].toDouble(); y.y_inventory = obj["y_inventory"].toDouble(); y.y_use = obj["y_use"].toInt(); y.y_sta1 = obj["y_sta1"].toInt() ? true:false; y.y_bacteria = obj["y_bacteria"].toInt() ? true:false; y.y_harvest_top = obj["y_harvest_top"].toInt() ? true:false; y.y_harvest_time = obj["y_harvest_time"].toInt(); y.y_pitch_temperature = obj["y_pitch_temperature"].toDouble(); y.y_pofpos = obj["y_pofpos"].toInt() ? true:false; y.y_zymocide = obj["y_zymocide"].toInt(); y.y_gr_hl_lo = obj["y_gr_hl_lo"].toInt(); y.y_sg_lo = obj["y_sg_lo"].toDouble(); y.y_gr_hl_hi = obj["y_gr_hl_hi"].toInt(); y.y_sg_hi = obj["y_sg_hi"].toDouble(); y.y_cost = obj["y_cost"].toDouble(); recipe->yeasts.append(y); } qDebug() << "yeasts" << recipe->yeasts.size(); } } else { qDebug() << "empty yeasts"; } const auto& ma_json = query.value(88).toString(); if (!ma_json.trimmed().isEmpty()) { const auto& formattedJson = QString("%1").arg(ma_json); QJsonDocument mashs = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ; } else if (mashs.isArray()) { for (int i = 0; i < mashs.array().size(); i++) { QJsonObject obj = mashs.array().at(i).toObject(); // qDebug() << i << obj; Mashs m; m.step_name = obj["step_name"].toString(); m.step_type = obj["step_type"].toInt(); m.step_volume = obj["step_volume"].toDouble(); m.step_infuse_amount = obj["step_infuse_amount"].toDouble(); m.step_infuse_temp = obj["step_infuse_temp"].toDouble(); m.step_temp = obj["step_temp"].toDouble(); m.step_time = obj["step_time"].toDouble(); m.ramp_time = obj["ramp_time"].toDouble(); m.end_temp = obj["end_temp"].toDouble(); m.step_wg_ratio = obj["step_wg_ratio"].toDouble(); recipe->mashs.append(m); } } } else { qDebug() << "empty mashs"; } qDebug() << "mashs" << recipe->mashs.size(); } else { /* Set some defaults */ recipe->locked = false; recipe->st_name = ""; recipe->st_letter = ""; recipe->st_guide = ""; recipe->st_category = ""; recipe->st_category_number = 0; recipe->st_type = 0; recipe->st_og_min = 1.025; recipe->st_og_max = 1.100; recipe->st_fg_min = 1.000; recipe->st_fg_max = 1.020; recipe->st_ibu_min = 5; recipe->st_ibu_max = 200; recipe->st_color_min = 3; recipe->st_color_max = 100; recipe->st_carb_min = 1.0; recipe->st_carb_max = 4.5; recipe->st_abv_min = 1; recipe->st_abv_max = 15; recipe->name = ""; recipe->notes = ""; recipe->efficiency = 75; recipe->batch_size = 20; recipe->boil_size = 24; recipe->boil_time = 60; recipe->type = 2; recipe->est_og = recipe->est_fg = recipe->est_color = recipe->est_ibu = recipe->est_abv = 0; recipe->sparge_temp = 80; recipe->sparge_ph = 5.4; recipe->sparge_volume = 8; recipe->sparge_source = 0; recipe->sparge_acid_type = 0; recipe->sparge_acid_perc = 80; recipe->sparge_acid_amount = 0; recipe->mash_ph = 5.4; recipe->mash_name = ""; recipe->calc_acid = true; recipe->w1_name = ""; recipe->w1_amount = 0; recipe->w1_calcium = 0; recipe->w1_sulfate = 0; recipe->w1_chloride = 0; recipe->w1_sodium = 0; recipe->w1_magnesium = 0; recipe->w1_total_alkalinity = 0; recipe->w1_ph = 7; recipe->w1_cost = 0; recipe->w2_name = ""; recipe->w2_amount = 0; recipe->w2_calcium = 0; recipe->w2_sulfate = 0; recipe->w2_chloride = 0; recipe->w2_sodium = 0; recipe->w2_magnesium = 0; recipe->w2_total_alkalinity = 0; recipe->w2_ph = 7; recipe->w2_cost = 0; recipe->wg_amount = 0; recipe->wg_calcium = 0; recipe->wg_sulfate = 0; recipe->wg_chloride = 0; recipe->wg_sodium = 0; recipe->wg_magnesium = 0; recipe->wg_total_alkalinity = 0; recipe->wg_ph = 7; recipe->wb_calcium = 0; recipe->wb_sulfate = 0; recipe->wb_chloride = 0; recipe->wb_sodium = 0; recipe->wb_magnesium = 0; recipe->wb_total_alkalinity = 0; recipe->wb_ph = 7; recipe->wa_acid_name = 0; recipe->wa_acid_perc = 80; recipe->wa_base_name = 0; } ui->lockedEdit->setChecked(recipe->locked); ui->st_nameEdit->setText(recipe->st_name); ui->st_groupEdit->setText(recipe->st_letter); ui->st_guideEdit->setText(recipe->st_guide); ui->st_catEdit->setText(recipe->st_category); ui->st_catnrEdit->setText(QString("%1").arg(recipe->st_category_number)); ui->st_typeEdit->setText(s_types[recipe->st_type]); ui->nameEdit->setText(recipe->name); ui->notesEdit->setPlainText(recipe->notes); ui->typeEdit->setCurrentIndex(recipe->type); ui->batch_sizeEdit->setValue(recipe->batch_size); ui->boil_sizeEdit->setValue(recipe->boil_size); ui->boil_timeEdit->setValue(recipe->boil_time); ui->efficiencyEdit->setValue(recipe->efficiency); ui->est_ogEdit->setValue(recipe->est_og); ui->est_og2Edit->setValue(recipe->est_og); ui->est_og3Edit->setValue(recipe->est_og); ui->est_ogShow->setRange(recipe->st_og_min, recipe->st_og_max); ui->est_ogShow->setPrecision(3); ui->est_ogShow->setMarkerTextIsValue(true); ui->est_ogShow->setValue(recipe->est_og); ui->est_fgEdit->setValue(recipe->est_fg); ui->est_fg3Edit->setValue(recipe->est_fg); ui->est_fgShow->setRange(recipe->st_fg_min, recipe->st_fg_max); ui->est_fgShow->setPrecision(3); ui->est_fgShow->setMarkerTextIsValue(true); ui->est_fgShow->setValue(recipe->est_fg); ui->est_abvEdit->setValue(recipe->est_abv); ui->est_abv2Edit->setValue(recipe->est_abv); ui->est_abvShow->setRange(recipe->st_abv_min, recipe->st_abv_max); ui->est_abvShow->setPrecision(1); ui->est_abvShow->setMarkerTextIsValue(true); ui->est_abvShow->setValue(recipe->est_abv); ui->est_colorEdit->setValue(recipe->est_color); ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(recipe->est_color)); ui->est_color2Edit->setValue(recipe->est_color); ui->est_color2Edit->setStyleSheet(Utils::ebc_to_style(recipe->est_color)); ui->est_colorShow->setPrecision(0); ui->est_colorShow->setMarkerTextIsValue(true); ui->est_colorShow->setRange(recipe->st_color_min, recipe->st_color_max); ui->est_colorShow->setValue(recipe->est_color); ui->color_methodEdit->setCurrentIndex(recipe->color_method); ui->est_ibuEdit->setValue(recipe->est_ibu); ui->est_ibu2Edit->setValue(recipe->est_ibu); ui->est_ibuShow->setPrecision(0); ui->est_ibuShow->setMarkerTextIsValue(true); ui->est_ibuShow->setRange(recipe->st_ibu_min, recipe->st_ibu_max); ui->est_ibuShow->setValue(recipe->est_ibu); ui->ibu_methodEdit->setCurrentIndex(recipe->ibu_method); ui->est_carbEdit->setValue(recipe->est_carb); ui->est_carbShow->setPrecision(1); ui->est_carbShow->setMarkerTextIsValue(true); ui->est_carbShow->setRange(recipe->st_carb_min, recipe->st_carb_max); ui->est_carbShow->setValue(recipe->est_carb); // All signals from tab "Generic" connect(ui->lockedEdit, &QCheckBox::stateChanged, this, &EditRecipe::is_changed); connect(ui->nameEdit, &QLineEdit::textChanged, this, &EditRecipe::name_changed); connect(ui->notesEdit, SIGNAL(textChanged()), this, SLOT(notes_changed())); connect(ui->typeEdit, &QComboBox::currentTextChanged, this, &EditRecipe::is_changed); connect(ui->batch_sizeEdit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed); connect(ui->boil_timeEdit, &QSpinBox::textChanged, this, &EditRecipe::is_changed); connect(ui->efficiencyEdit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed); connect(ui->beerstyleEdit, &QComboBox::currentTextChanged, this, &EditRecipe::style_changed); connect(ui->est_ogEdit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed); connect(ui->color_methodEdit, &QComboBox::currentTextChanged, this, &EditRecipe::colormethod_changed); connect(ui->ibu_methodEdit, &QComboBox::currentTextChanged, this, &EditRecipe::is_changed); // All signals from tab "Fermentables" ui->fermentablesTable->setEditTriggers(QAbstractItemView::NoEditTriggers); connect(ui->est_og2Edit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed); connect(ui->perc_mashShow, &QProgressBar::valueChanged, this, &EditRecipe::on_perc_mash_valueChanged); connect(ui->perc_sugarsShow, &QProgressBar::valueChanged, this, &EditRecipe::on_perc_sugars_valueChanged); connect(ui->perc_caraShow, &QProgressBar::valueChanged, this, &EditRecipe::on_perc_cara_valueChanged); connect(ui->lintnerShow, &QProgressBar::valueChanged, this, &EditRecipe::on_lintner_valueChanged); connect(ui->addFermentable, SIGNAL(clicked()), this, SLOT(on_addFermentRow_clicked())); // All signals from tab "Hops" // connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int))); // All signals from tab "Miscs" // connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int))); // All signals from tab "Yeasts" // connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int))); // All signals from tab "Mash" // connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int))); // All signals from tab "Water" ui->saveButton->setEnabled(false); ui->deleteButton->setEnabled((id >= 0) ? true:false); emit refreshAll(); } EditRecipe::~EditRecipe() { qDebug() << "EditRecipe done start"; delete ui; emit entry_changed(); qDebug() << "EditRecipe done final"; } bool EditRecipe::ferment_sort_test(const Fermentables &D1, const Fermentables &D2) { return (D1.f_added <= D2.f_added) && (D1.f_amount >= D2.f_amount) && (D1.f_color < D2.f_color); } void EditRecipe::to100Fermentables(int row) { if (recipe->fermentables.at(row).f_adjust_to_total_100) { QWidget *pWidget = new QWidget(); QLabel *label = new QLabel; label->setPixmap(QPixmap(":icons/silk/tick.png")); QHBoxLayout *pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(label); pLayout->setAlignment(Qt::AlignCenter); pLayout->setContentsMargins(0, 0, 0, 0); pWidget->setLayout(pLayout); ui->fermentablesTable->setCellWidget(row, 9, pWidget); } else { ui->fermentablesTable->removeCellWidget(row, 9); } } void EditRecipe::refreshFermentables() { QString w; QWidget* pWidget; QHBoxLayout* pLayout; QTableWidgetItem *item; qDebug() << "refreshFermentables" << recipe->fermentables.size(); std::sort(recipe->fermentables.begin(), recipe->fermentables.end(), ferment_sort_test); /* * During filling the table turn off the cellChanged signal because every cell that is filled * triggers the cellChanged signal. The QTableWidget has no better signal to use. */ this->ignoreChanges = true; const QStringList labels({tr("Supplier"), tr("Fermentable"), tr("EBC"), tr("Type"), tr("Graintype"), tr("When"), tr("Yield"), tr("Amount"), tr("Procent"), tr("100%"), tr("Delete"), tr("Edit") }); ui->fermentablesTable->setColumnCount(12); ui->fermentablesTable->setColumnWidth(0, 150); /* Supplier */ ui->fermentablesTable->setColumnWidth(1, 225); /* Fermentable */ ui->fermentablesTable->setColumnWidth(2, 50); /* Color */ ui->fermentablesTable->setColumnWidth(3, 75); /* Type */ ui->fermentablesTable->setColumnWidth(4, 75); /* Graintype */ ui->fermentablesTable->setColumnWidth(5, 75); /* Added */ ui->fermentablesTable->setColumnWidth(6, 60); /* Yield */ ui->fermentablesTable->setColumnWidth(7, 90); /* Amount */ ui->fermentablesTable->setColumnWidth(8, 60); /* Procent */ ui->fermentablesTable->setColumnWidth(9, 50); /* 100% */ ui->fermentablesTable->setColumnWidth(10, 80); /* Delete */ ui->fermentablesTable->setColumnWidth(11, 80); /* Edit */ ui->fermentablesTable->setHorizontalHeaderLabels(labels); ui->fermentablesTable->verticalHeader()->hide(); ui->fermentablesTable->setRowCount(recipe->fermentables.size()); for (int i = 0; i < recipe->fermentables.size(); i++) { ui->fermentablesTable->setItem(i, 0, new QTableWidgetItem(recipe->fermentables.at(i).f_supplier)); ui->fermentablesTable->setItem(i, 1, new QTableWidgetItem(recipe->fermentables.at(i).f_name)); w = QString("%1").arg(recipe->fermentables.at(i).f_color, 1, 'f', 0, '0'); item = new QTableWidgetItem(w); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 2, item); item = new QTableWidgetItem(f_types[recipe->fermentables.at(i).f_type]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 3, item); item = new QTableWidgetItem(f_graintypes[recipe->fermentables.at(i).f_graintype]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 4, item); item = new QTableWidgetItem(f_added[recipe->fermentables.at(i).f_added]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 5, item); item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables.at(i).f_yield, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 6, item); item = new QTableWidgetItem(QString("%1 Kg").arg(recipe->fermentables.at(i).f_amount, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 7, item); if (recipe->fermentables.at(i).f_added < 4) { item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables.at(i).f_percentage, 2, 'f', 1, '0')); } else { item = new QTableWidgetItem(QString("")); // Blank for bottling and kegging. } item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 8, item); to100Fermentables(i); /* Add the Delete row button */ pWidget = new QWidget(); QPushButton* btn_dele = new QPushButton(); btn_dele->setObjectName(QString("%1").arg(i)); /* Send row with the button */ btn_dele->setText(tr("Delete")); connect(btn_dele, SIGNAL(clicked()), this, SLOT(on_deleteFermentRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_dele); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->fermentablesTable->setCellWidget(i, 10, pWidget); pWidget = new QWidget(); QPushButton* btn_edit = new QPushButton(); btn_edit->setObjectName(QString("%1").arg(i)); /* Send row with the button */ btn_edit->setText(tr("Edit")); connect(btn_edit, SIGNAL(clicked()), this, SLOT(on_editFermentRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_edit); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->fermentablesTable->setCellWidget(i, 11, pWidget); } this->ignoreChanges = false; } void EditRecipe::refreshHops() { } void EditRecipe::refreshMiscs() { } void EditRecipe::refreshYeasts() { } void EditRecipe::refreshMashs() { } void EditRecipe::refreshAll() { refreshFermentables(); calcFermentables(); } void EditRecipe::calcFermentables() { int i; double psugar = 0, pcara = 0, d, s = 0, x, color; double vol = 0; // Volume sugars after boil double addedS = 0; // Added sugars after boil double addedmass = 0; // Added mass after boil double mvol = 0; // Mash volume double lintner = 0; // Total recipe lintner double mashkg = 0; double sugarsf = 0; // fermentable sugars mash + boil double sugarsm = 0; // fermentable sugars in mash double sugardensity = 1.611; // kg/l in solution double mashtime = 0; // Total mash time double mashtemp = 0; // Average mash temperature double mashinfuse = 0; // Mash infuse amount double colort = 0; // Colors srm * vol totals double colorh = 0; // Colors ebc * vol * kt double colorn = 0; // Colors ebc * pt * pct qDebug() << "calcFermentables()"; /* * Get average mashtemp and mashtime from the Mash schedule. * It is possible that the schedule is not (yet) present. */ if (recipe->mashs.size() > 0) { for (i = 0; i < recipe->mashs.size(); i++) { if (recipe->mashs.at(i).step_type == 0) // Infusion mashinfuse += recipe->mashs.at(i).step_infuse_amount; if (recipe->mashs.at(i).step_temp < 75) { // Ignore mashout mashtime += recipe->mashs.at(i).step_time; mashtemp += recipe->mashs.at(i).step_time * recipe->mashs.at(i).step_temp; } } mashtemp = mashtemp / mashtime; mvol = mashinfuse; qDebug() << " mash time" << mashtime << "temp" << mashtemp << "infuse" << mashinfuse; } else { qDebug() << " no mash schedule"; } if (recipe->fermentables.size() < 1) { qDebug() << " no fermentables, return."; recipe->est_og = 0.980; ui->est_ogEdit->setValue(0.980); ui->est_og2Edit->setValue(0.980); ui->est_og3Edit->setValue(0.980); ui->est_ogShow->setValue(0.980); recipe->est_color = 0; ui->est_colorEdit->setValue(0); ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(0)); ui->est_color2Edit->setValue(0); ui->est_color2Edit->setStyleSheet(Utils::ebc_to_style(0)); ui->est_colorShow->setValue(0); ui->perc_mashShow->setValue(0); ui->perc_sugarsShow->setValue(0); ui->perc_caraShow->setValue(0); ui->lintnerShow->setValue(0); recipe->est_fg = 0.980; ui->est_fgEdit->setValue(0.980); ui->est_fg3Edit->setValue(0.980); ui->est_fgShow->setValue(0.980); ui->est_abvEdit->setValue(0); ui->est_abv2Edit->setValue(0); ui->est_abvShow->setValue(0); recipe->est_abv = 0; ui->calEdit->setValue(0); return; } qDebug() << " adjust to 100" << recipe->fermentables_use100; for (i = 0; i < recipe->fermentables.size(); i++) { if (recipe->fermentables.at(i).f_type == 1 && recipe->fermentables.at(i).f_added < 4) // Sugars psugar += recipe->fermentables.at(i).f_percentage; if (recipe->fermentables.at(i).f_graintype == 2 && recipe->fermentables.at(i).f_added < 4) // Crystal/Cara pcara += recipe->fermentables.at(i).f_percentage; d = recipe->fermentables.at(i).f_amount * (recipe->fermentables.at(i).f_yield / 100) * (1 - recipe->fermentables.at(i).f_moisture / 100); if (recipe->fermentables.at(i).f_added == 0) { // Mash if (mvol > 0) { // If mash volume is known mvol += recipe->fermentables.at(i).f_amount * recipe->fermentables.at(i).f_moisture / 100; s += d; } d = ui->efficiencyEdit->value() / 100 * d; sugarsm += d; mashkg += recipe->fermentables.at(i).f_amount; } if (recipe->fermentables.at(i).f_added == 0 || recipe->fermentables.at(i).f_added == 1) // Mash or boil sugarsf += d; if (recipe->fermentables.at(i).f_added == 2 || recipe->fermentables.at(i).f_added == 3) { // Fermentation or lagering x = (recipe->fermentables.at(i).f_yield / 100) * (1 - recipe->fermentables.at(i).f_moisture / 100); addedS += recipe->fermentables.at(i).f_amount * x; addedmass += recipe->fermentables.at(i).f_amount; vol += (x * sugardensity + (1 - x) * 1) * recipe->fermentables.at(i).f_amount; } if (recipe->fermentables.at(i).f_added == 0 && (recipe->fermentables.at(i).f_type == 0 || recipe->fermentables.at(i).f_type == 4) && recipe->fermentables.at(i).f_color < 50) { lintner += recipe->fermentables.at(i).f_diastatic_power * recipe->fermentables.at(i).f_amount; } if (recipe->fermentables.at(i).f_added < 4) { colort += recipe->fermentables.at(i).f_amount * Utils::ebc_to_srm(recipe->fermentables.at(i).f_color); colorh += recipe->fermentables.at(i).f_amount * recipe->fermentables.at(i).f_color * Utils::get_kt(recipe->fermentables.at(i).f_color); colorn += (recipe->fermentables.at(i).f_percentage / 100) * recipe->fermentables.at(i).f_color; // For 8.6 Pt wort. } } qDebug() << " colort" << colort << "colorh" << colorh << "colorn" << colorn; qDebug() << " psugar" << psugar << "pcara" << pcara << "mvol" << mvol; qDebug() << " sugarsf" << sugarsf << "sugarsm" << sugarsm; double og = Utils::estimate_sg(sugarsf + addedS, ui->batch_sizeEdit->value()); qDebug() << " OG" << ui->est_ogEdit->value() << og; recipe->est_og = og; ui->est_ogEdit->setValue(og); ui->est_og2Edit->setValue(og); ui->est_og3Edit->setValue(og); ui->est_ogShow->setValue(og); double preboil_sg = Utils::estimate_sg(sugarsm, ui->boil_sizeEdit->value()); qDebug() << " preboil SG" << preboil_sg; /* * Color of the wort */ if (ui->color_methodEdit->currentIndex() == 4) { // Naudts color = round(((Utils::sg_to_plato(og) / 8.6) * colorn) + (ui->boil_timeEdit->value() / 60)); } else if (ui->color_methodEdit->currentIndex() == 3) { // Hans Halberstadt double bv = 0.925; // Beer loss efficiency double sr = 0.95; // Mash and sparge efficiency color = round((4.46 * bv * sr) / ui->batch_sizeEdit->value() * colorh); } else { double cw = colort / ui->batch_sizeEdit->value() * 8.34436; color = Utils::kw_to_ebc(ui->color_methodEdit->currentIndex(), cw); } qDebug() << " color" << ui->est_colorEdit->value() << color << recipe->est_color; recipe->est_color = color; ui->est_colorEdit->setValue(color); ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(color)); ui->est_color2Edit->setValue(color); ui->est_color2Edit->setStyleSheet(Utils::ebc_to_style(color)); ui->est_colorShow->setValue(color); /* * We don't have a equipment profile in recipes, * so we assume a certain guessed mashtun size. */ ui->perc_mashShow->setValue(round(mashkg / (ui->boil_sizeEdit->value() / 3) * 100)); ui->perc_sugarsShow->setValue(round(psugar)); ui->perc_caraShow->setValue(round(pcara)); qDebug() << " lintner" << lintner << " mashkg" << mashkg << "final" << round(lintner / mashkg); ui->lintnerShow->setValue(round(lintner / mashkg)); /* * Calculate the apparant attenuation. */ double svg = 0; if (recipe->yeasts.size() > 0) { for (i = 0; i < recipe->yeasts.size(); i++) { if (recipe->yeasts.at(i).y_use == 0) { // Used in primary if (recipe->yeasts.at(i).y_attenuation > svg) svg = recipe->yeasts.at(i).y_attenuation; // Take the highest if multiple yeasts. } // TODO: brett or others in secondary. } qDebug() << " SVG" << svg; } if (svg == 0) svg = 77.0; double fg; if (mashkg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0) fg = Utils::estimate_fg(psugar, pcara, mashinfuse / mashkg, mashtime, mashtemp, svg, og); else fg = Utils::estimate_fg(psugar, pcara, 0, 0, 0, svg, og); qDebug() << " FG" << ui->est_fgEdit->value() << fg; recipe->est_fg = fg; ui->est_fgEdit->setValue(fg); ui->est_fg3Edit->setValue(fg); ui->est_fgShow->setValue(fg); double abv = Utils::abvol(og, fg); qDebug() << " ABV" << ui->est_abvEdit->value() << abv; ui->est_abvEdit->setValue(abv); ui->est_abv2Edit->setValue(abv); ui->est_abvShow->setValue(abv); recipe->est_abv = abv; /* * Calculate kilocalories/liter. Formula from brouwhulp. * Take the alcohol and sugar parts and then combine. */ double alc = 1881.22 * fg * (og - fg) / (1.775 - og); double sug = 3550 * fg * (0.1808 * og + 0.8192 * fg - 1.0004); ui->calEdit->setValue(round((alc + sug) / (12 * 0.0295735296))); } void EditRecipe::on_perc_mash_valueChanged(int value) { if (value < 90) ui->perc_mashShow->setStyleSheet(bar_green); else if (value < 100) ui->perc_mashShow->setStyleSheet(bar_orange); else ui->perc_mashShow->setStyleSheet(bar_red); } void EditRecipe::on_perc_sugars_valueChanged(int value) { if (value < 20) ui->perc_sugarsShow->setStyleSheet(bar_green); else ui->perc_sugarsShow->setStyleSheet(bar_red); } void EditRecipe::on_perc_cara_valueChanged(int value) { if (value < 25) ui->perc_caraShow->setStyleSheet(bar_green); else ui->perc_caraShow->setStyleSheet(bar_red); } void EditRecipe::on_lintner_valueChanged(int value) { if (value < 30) ui->lintnerShow->setStyleSheet(bar_red); else if (value < 40) ui->lintnerShow->setStyleSheet(bar_orange); else ui->lintnerShow->setStyleSheet(bar_green); } /* * Window header, mark any change with '**' */ void EditRecipe::WindowTitle() { QString txt; if (this->recno < 0) { txt = QString(tr("BMSapp - Add new recipe")); } else { txt = QString(tr("BMSapp - Edit recipe %1").arg(this->recno)); } if (this->textIsChanged) { txt.append((QString(" **"))); } setWindowTitle(txt); } void EditRecipe::on_saveButton_clicked() { QSqlQuery query; /* If there are errors in the form, show a message and do "return;" */ if (ui->nameEdit->text().length() < 2) { QMessageBox::warning(this, tr("Edit Recipe"), tr("Name empty or too short.")); return; } if (ui->st_nameEdit->text().length() < 2) { QMessageBox::warning(this, tr("Edit Recipe"), tr("No beerstyle selected.")); return; } if (this->textIsChanged) { if (this->recno == -1) { query.prepare("INSERT INTO recipes SET locked=:locked, st_name=:st_name, st_letter=:st_letter, " "st_guide=:st_guide, st_category=:st_category, st_category_number=:st_catnr, st_type=:st_type, " "st_og_min=:st_og_min, st_og_max=:st_og_max, st_fg_min=:st_fg_min, st_fg_max=:st_fg_max, " "st_ibu_min=:st_ibu_min, st_ibu_max=:st_ibu_max, st_color_min=:st_color_min, st_color_max=:st_color_max, " "st_carb_min=:st_carb_min, st_carb_max=:st_carb_max, st_abv_min=:st_abv_min, st_abv_max=:st_abv_max, " "name=:name, notes=:notes, type=:type, batch_size=:batch_size, boil_size=:boil_size, " "boil_time=:boil_time, efficiency=:efficiency, est_og=:est_og, est_fg=:est_fg, est_abv=:est_abv, " "est_color=:est_color, color_method=:color_method, est_ibu=:est_ibu, ibu_method=:ibu_method, " "est_carb=:est_carb, sparge_temp=:sparge_temp, sparge_ph=:sparge_ph, " "sparge_volume=:sparge_volume, sparge_source=:sparge_source, sparge_acid_type=:sparge_acid_type, " "sparge_acid_perc=:sparge_acid_perc, sparge_acid_amount=:sparge_acid_amount, mash_ph=:mash_ph, " "mash_name=:mash_name, calc_acid=:calc_acid, " "w1_name=:w1_name, w1_amount=:w1_amount, w1_calcium=:w1_calcium, w1_sulfate=:w1_sulfate, " "w1_chloride=:w1_chloride, w1_sodium=:w1_sodium, w1_magnesium=:w1_magnesium, " "w1_total_alkalinity=:w1_total_alkalinity, w1_ph=:w1_ph, w1_cost=:w1_cost, " "w2_name=:w2_name, w2_amount=:w2_amount, w2_calcium=:w2_calcium, w2_sulfate=:w2_sulfate, " "w2_chloride=:w2_chloride, w2_sodium=:w2_sodium, w2_magnesium=:w2_magnesium, " "w2_total_alkalinity=:w2_total_alkalinity, w2_ph=:w2_ph, w2_cost=:w2_cost, " "wg_amount=:wg_amount, wg_calcium=:wg_calcium, wg_sulfate=:wg_sulfate, " "wg_chloride=:wg_chloride, wg_sodium=:wg_sodium, wg_magnesium=:wg_magnesium, " "wg_total_alkalinity=:wg_total_alkalinity, wg_ph=:wg_ph, " "wb_calcium=:wb_calcium, wb_sulfate=:wb_sulfate, wb_chloride=:wb_chloride, wb_sodium=:wb_sodium, " "wb_magnesium=:wb_magnesium, wb_total_alkalinity=:wb_total_alkalinity, wb_ph=:wb_ph, " "wa_acid_name=:wa_acid_name, wa_acid_perc=:wa_acid_perc, wa_base_name=:wa_base_name, " "json_fermentables=:json_fermentables, json_hops=:json_hops, json_miscs=:json_miscs, " "json_yeasts=:json_yeasts, json_mashs=:json_mashs, uuid=:uuid"); } else { query.prepare("UPDATE recipes SET locked=:locked, st_name=:st_name, st_letter=:st_letter, " "st_guide=:st_guide, st_category=:st_category, st_category_number=:st_catnr, st_type=:st_type, " "st_og_min=:st_og_min, st_og_max=:st_og_max, st_fg_min=:st_fg_min, st_fg_max=:st_fg_max, " "st_ibu_min=:st_ibu_min, st_ibu_max=:st_ibu_max, st_color_min=:st_color_min, st_color_max=:st_color_max, " "st_carb_min=:st_carb_min, st_carb_max=:st_carb_max, st_abv_min=:st_abv_min, st_abv_max=:st_abv_max, " "name=:name, notes=:notes, type=:type, batch_size=:batch_size, boil_size=:boil_size, " "boil_time=:boil_time, efficiency=:efficiency, est_og=:est_og, est_fg=:est_fg, est_abv=:est_abv, " "est_color=:est_color, color_method=:color_method, est_ibu=:est_ibu, ibu_method=:ibu_method, " "est_carb=:est_carb, sparge_temp=:sparge_temp, sparge_ph=:sparge_ph, " "sparge_volume=:sparge_volume, sparge_source=:sparge_source, sparge_acid_type=:sparge_acid_type, " "sparge_acid_perc=:sparge_acid_perc, sparge_acid_amount=:sparge_acid_amount, mash_ph=:mash_ph, " "mash_name=:mash_name, calc_acid=:calc_acid, " "w1_name=:w1_name, w1_amount=:w1_amount, w1_calcium=:w1_calcium, w1_sulfate=:w1_sulfate, " "w1_chloride=:w1_chloride, w1_sodium=:w1_sodium, w1_magnesium=:w1_magnesium, " "w1_total_alkalinity=:w1_total_alkalinity, w1_ph=:w1_ph, w1_cost=:w1_cost, " "w2_name=:w2_name, w2_amount=:w2_amount, w2_calcium=:w2_calcium, w2_sulfate=:w2_sulfate, " "w2_chloride=:w2_chloride, w2_sodium=:w2_sodium, w2_magnesium=:w2_magnesium, " "w2_total_alkalinity=:w2_total_alkalinity, w2_ph=:w2_ph, w2_cost=:w2_cost, " "wg_amount=:wg_amount, wg_calcium=:wg_calcium, wg_sulfate=:wg_sulfate, " "wg_chloride=:wg_chloride, wg_sodium=:wg_sodium, wg_magnesium=:wg_magnesium, " "wg_total_alkalinity=:wg_total_alkalinity, wg_ph=:wg_ph, " "wb_calcium=:wb_calcium, wb_sulfate=:wb_sulfate, wb_chloride=:wb_chloride, wb_sodium=:wb_sodium, " "wb_magnesium=:wb_magnesium, wb_total_alkalinity=:wb_total_alkalinity, wb_ph=:wb_ph, " "wa_acid_name=:wa_acid_name, wa_acid_perc=:wa_acid_perc, wa_base_name=:wa_base_name, " "json_fermentables=:json_fermentables, json_hops=:json_hops, json_miscs=:json_miscs, " "json_yeasts=:json_yeasts, json_mashs=:json_mashs WHERE record = :recno"); } query.bindValue(":locked", recipe->locked ? 1:0); query.bindValue(":st_name", recipe->st_name); query.bindValue(":st_letter", recipe->st_letter); query.bindValue(":st_guide", recipe->st_guide); query.bindValue(":st_category", recipe->st_category); query.bindValue(":st_catnr", recipe->st_category_number); query.bindValue(":st_type", recipe->st_type); query.bindValue(":st_og_min", round(recipe->st_og_min * 1000) / 1000); query.bindValue(":st_og_max", round(recipe->st_og_max * 1000) / 1000); query.bindValue(":st_fg_min", round(recipe->st_fg_min * 1000) / 1000); query.bindValue(":st_fg_max", round(recipe->st_fg_max * 1000) / 1000); query.bindValue(":st_ibu_min", round(recipe->st_ibu_min * 10) / 10); query.bindValue(":st_ibu_max", round(recipe->st_ibu_max * 10) / 10); query.bindValue(":st_color_min", round(recipe->st_color_min * 10) / 10); query.bindValue(":st_color_max", round(recipe->st_color_max * 10) / 10); query.bindValue(":st_carb_min", round(recipe->st_carb_min * 10) / 10); query.bindValue(":st_carb_max", round(recipe->st_carb_max * 10) / 10); query.bindValue(":st_abv_min", round(recipe->st_abv_min * 10) / 10); query.bindValue(":st_abv_max", round(recipe->st_abv_max * 10) / 10); query.bindValue(":name", recipe->name); query.bindValue(":notes", recipe->notes); query.bindValue(":type", recipe->type); query.bindValue(":batch_size", round(recipe->batch_size * 10) / 10); query.bindValue(":boil_size", round(recipe->boil_size * 10) / 10); query.bindValue(":boil_time", round(recipe->boil_time * 10) / 10); query.bindValue(":efficiency", round(recipe->efficiency * 10) / 10); query.bindValue(":est_og", round(recipe->est_og * 1000) / 1000); query.bindValue(":est_fg", round(recipe->est_fg * 1000) / 1000); query.bindValue(":est_abv", round(recipe->est_abv * 10) / 10); query.bindValue(":est_color", round(recipe->est_color * 10) / 10); query.bindValue(":color_method", recipe->color_method); query.bindValue(":est_ibu", round(recipe->est_ibu * 10) / 10); query.bindValue(":ibu_method", recipe->ibu_method); query.bindValue(":est_carb", round(recipe->est_carb * 10) / 10); query.bindValue(":sparge_temp", round(recipe->sparge_temp * 10) / 10); query.bindValue(":sparge_ph", round(recipe->sparge_ph * 100) / 100); query.bindValue(":sparge_volume", round(recipe->sparge_volume * 10) / 10); query.bindValue(":sparge_source", recipe->sparge_source); query.bindValue(":sparge_acid_type", recipe->sparge_acid_type); query.bindValue(":sparge_acid_perc", round(recipe->sparge_acid_perc * 10) / 10); query.bindValue(":sparge_acid_amount", round(recipe->sparge_acid_amount * 100000) / 100000); query.bindValue(":mash_ph", round(recipe->mash_ph * 100) / 100); query.bindValue(":mash_name", recipe->mash_name); query.bindValue(":calc_acid", recipe->calc_acid ?1:0); query.bindValue(":w1_name", recipe->w1_name); query.bindValue(":w1_amount", round(recipe->w1_amount * 10) / 10); query.bindValue(":w1_calcium", round(recipe->w1_calcium * 100000) / 100000); query.bindValue(":w1_sulfate", round(recipe->w1_sulfate * 100000) / 100000); query.bindValue(":w1_chloride", round(recipe->w1_chloride * 100000) / 100000); query.bindValue(":w1_sodium", round(recipe->w1_sodium * 100000) / 100000); query.bindValue(":w1_magnesium", round(recipe->w1_magnesium * 100000) / 100000); query.bindValue(":w1_total_alkalinity", round(recipe->w1_total_alkalinity * 100000) / 100000); query.bindValue(":w1_ph", round(recipe->w1_ph * 100) / 100); query.bindValue(":w1_cost", round(recipe->w1_cost * 100) / 100); query.bindValue(":w2_name", recipe->w2_name); query.bindValue(":w2_amount", round(recipe->w2_amount * 10) / 10); query.bindValue(":w2_calcium", round(recipe->w2_calcium * 100000) / 100000); query.bindValue(":w2_sulfate", round(recipe->w2_sulfate * 100000) / 100000); query.bindValue(":w2_chloride", round(recipe->w2_chloride * 100000) / 100000); query.bindValue(":w2_sodium", round(recipe->w2_sodium * 100000) / 100000); query.bindValue(":w2_magnesium", round(recipe->w2_magnesium * 100000) / 100000); query.bindValue(":w2_total_alkalinity", round(recipe->w2_total_alkalinity * 100000) / 100000); query.bindValue(":w2_ph", round(recipe->w2_ph * 100) / 100); query.bindValue(":w2_cost", round(recipe->w2_cost * 100) / 100); query.bindValue(":wg_amount", round(recipe->wg_amount * 10) / 10); query.bindValue(":wg_calcium", round(recipe->wg_calcium * 100000) / 100000); query.bindValue(":wg_sulfate", round(recipe->wg_sulfate * 100000) / 100000); query.bindValue(":wg_chloride", round(recipe->wg_chloride * 100000) / 100000); query.bindValue(":wg_sodium", round(recipe->wg_sodium * 100000) / 100000); query.bindValue(":wg_magnesium", round(recipe->wg_magnesium * 100000) / 100000); query.bindValue(":wg_total_alkalinity", round(recipe->wg_total_alkalinity * 100000) / 100000); query.bindValue(":wg_ph", round(recipe->wg_ph * 100) / 100); query.bindValue(":wb_calcium", round(recipe->wb_calcium * 100000) / 100000); query.bindValue(":wb_sulfate", round(recipe->wb_sulfate * 100000) / 100000); query.bindValue(":wb_chloride", round(recipe->wb_chloride * 100000) / 100000); query.bindValue(":wb_sodium", round(recipe->wb_sodium * 100000) / 100000); query.bindValue(":wb_magnesium", round(recipe->wb_magnesium * 100000) / 100000); query.bindValue(":wb_total_alkalinity", round(recipe->wb_total_alkalinity * 100000) / 100000); query.bindValue(":wb_ph", round(recipe->wb_ph * 100) / 100); query.bindValue(":wa_acid_name", recipe->wa_acid_name); query.bindValue(":wa_acid_perc", round(recipe->wa_acid_perc * 10) / 10); query.bindValue(":wa_base_name", recipe->wa_base_name); if (recipe->fermentables.size() == 0) { query.bindValue(":json_fermentables", "[]"); } else { QJsonArray array; for (int i = 0; i < recipe->fermentables.size(); i++) { QJsonObject obj; obj.insert("f_acid_to_ph_57", round(recipe->fermentables.at(i).f_acid_to_ph_57 * 100000) / 100000); obj.insert("f_add_after_boil", recipe->fermentables.at(i).f_add_after_boil); obj.insert("f_added", recipe->fermentables.at(i).f_added); obj.insert("f_adjust_to_total_100", recipe->fermentables.at(i).f_adjust_to_total_100); obj.insert("f_amount", round(recipe->fermentables.at(i).f_amount * 10000) / 10000); obj.insert("f_coarse_fine_diff", round(recipe->fermentables.at(i).f_coarse_fine_diff * 10) / 10); obj.insert("f_color", round(recipe->fermentables.at(i).f_color * 10) / 10); obj.insert("f_cost", round(recipe->fermentables.at(i).f_cost * 1000) / 1000); obj.insert("f_di_ph", round(recipe->fermentables.at(i).f_di_ph * 100000) / 100000); obj.insert("f_diastatic_power", round(recipe->fermentables.at(i).f_diastatic_power * 100000) / 100000); obj.insert("f_dissolved_protein", round(recipe->fermentables.at(i).f_dissolved_protein * 10) / 10); obj.insert("f_graintype", recipe->fermentables.at(i).f_graintype); obj.insert("f_max_in_batch", recipe->fermentables.at(i).f_max_in_batch); obj.insert("f_moisture", round(recipe->fermentables.at(i).f_moisture * 10) / 10); obj.insert("f_name", recipe->fermentables.at(i).f_name); obj.insert("f_origin", recipe->fermentables.at(i).f_origin); obj.insert("f_percentage", round(recipe->fermentables.at(i).f_percentage * 10) / 10); obj.insert("f_protein", round(recipe->fermentables.at(i).f_protein * 10) / 10); obj.insert("f_recommend_mash", recipe->fermentables.at(i).f_recommend_mash); obj.insert("f_supplier", recipe->fermentables.at(i).f_supplier); obj.insert("f_type", recipe->fermentables.at(i).f_type); obj.insert("f_yield", round(recipe->fermentables.at(i).f_yield * 10) / 10); array.append(obj); /* Append this object */ } QJsonDocument doc; doc.setArray(array); // qDebug() << doc.toJson(QJsonDocument::Compact); query.bindValue(":json_fermentables", doc.toJson(QJsonDocument::Compact)); } if (recipe->hops.size() == 0) { query.bindValue(":json_hops", "[]"); } else { QJsonArray array; for (int i = 0; i < recipe->hops.size(); i++) { QJsonObject obj; obj.insert("h_name", recipe->hops.at(i).h_name); obj.insert("h_origin", recipe->hops.at(i).h_origin); obj.insert("h_amount", round(recipe->hops.at(i).h_amount * 10000) / 10000); obj.insert("h_cost", round(recipe->hops.at(i).h_cost * 100) / 100); obj.insert("h_type", recipe->hops.at(i).h_type); obj.insert("h_form", recipe->hops.at(i).h_form); obj.insert("h_useat", recipe->hops.at(i).h_useat); obj.insert("h_time", recipe->hops.at(i).h_time); obj.insert("h_alpha", round(recipe->hops.at(i).h_alpha * 100) / 100); obj.insert("h_beta", round(recipe->hops.at(i).h_beta * 100) / 100); obj.insert("h_hsi", round(recipe->hops.at(i).h_hsi * 100) / 100); obj.insert("h_humulene", round(recipe->hops.at(i).h_humulene * 100) / 100); obj.insert("h_caryophyllene", round(recipe->hops.at(i).h_caryophyllene * 100) / 100); obj.insert("h_cohumulone", round(recipe->hops.at(i).h_cohumulone * 100) / 100); obj.insert("h_myrcene", round(recipe->hops.at(i).h_myrcene * 100) / 100); obj.insert("h_total_oil", round(recipe->hops.at(i).h_total_oil * 100) / 100); // qDebug() << "hops_Json" << i << obj; array.append(obj); /* Append this object */ } QJsonDocument doc; doc.setArray(array); query.bindValue(":json_hops", doc.toJson(QJsonDocument::Compact)); } if (recipe->miscs.size() == 0) { query.bindValue(":json_miscs", "[]"); } else { QJsonArray array; for (int i = 0; i < recipe->miscs.size(); i++) { QJsonObject obj; obj.insert("m_name", recipe->miscs.at(i).m_name); obj.insert("m_amount", round(recipe->miscs.at(i).m_amount * 10000) / 10000); obj.insert("m_type", recipe->miscs.at(i).m_type); obj.insert("m_use_use", recipe->miscs.at(i).m_use_use); obj.insert("m_time", recipe->miscs.at(i).m_time); obj.insert("m_amount_is_weight", recipe->miscs.at(i).m_amount_is_weight); obj.insert("m_cost", recipe->miscs.at(i).m_cost); // qDebug() << "miscs_Json" << i << obj; array.append(obj); /* Append this object */ } QJsonDocument doc; doc.setArray(array); // qDebug() << doc.toJson(QJsonDocument::Compact); query.bindValue(":json_miscs", doc.toJson(QJsonDocument::Compact)); } if (recipe->yeasts.size() == 0) { query.bindValue(":json_yeasts", "[]"); } else { QJsonArray array; for (int i = 0; i < recipe->yeasts.size(); i++) { QJsonObject obj; obj.insert("y_name", recipe->yeasts.at(i).y_name); obj.insert("y_laboratory", recipe->yeasts.at(i).y_laboratory); obj.insert("y_product_id", recipe->yeasts.at(i).y_product_id); obj.insert("y_amount", round(recipe->yeasts.at(i).y_amount * 10000) / 10000); obj.insert("y_type", recipe->yeasts.at(i).y_type); obj.insert("y_form", recipe->yeasts.at(i).y_form); obj.insert("y_min_temperature", round(recipe->yeasts.at(i).y_min_temperature * 10) / 10); obj.insert("y_max_temperature", round(recipe->yeasts.at(i).y_max_temperature * 10) / 10); obj.insert("y_flocculation", recipe->yeasts.at(i).y_flocculation); obj.insert("y_attenuation", round(recipe->yeasts.at(i).y_attenuation * 10) / 10); obj.insert("y_cells", recipe->yeasts.at(i).y_cells); obj.insert("y_tolerance", round(recipe->yeasts.at(i).y_tolerance * 10) / 10); obj.insert("y_inventory", round(recipe->yeasts.at(i).y_inventory * 10000) / 10000); obj.insert("y_use", recipe->yeasts.at(i).y_use); obj.insert("y_sta1", recipe->yeasts.at(i).y_sta1); obj.insert("y_bacteria", recipe->yeasts.at(i).y_bacteria); obj.insert("y_harvest_top", recipe->yeasts.at(i).y_harvest_top); obj.insert("y_harvest_time", recipe->yeasts.at(i).y_harvest_time); obj.insert("y_pitch_temperature", round(recipe->yeasts.at(i).y_pitch_temperature * 10) / 10); obj.insert("y_pofpos", recipe->yeasts.at(i).y_pofpos); obj.insert("y_zymocide", recipe->yeasts.at(i).y_zymocide); obj.insert("y_gr_hl_lo", recipe->yeasts.at(i).y_gr_hl_lo); obj.insert("y_sg_lo", round(recipe->yeasts.at(i).y_sg_lo * 1000) / 1000); obj.insert("y_gr_hl_hi", recipe->yeasts.at(i).y_gr_hl_hi); obj.insert("y_sg_hi", round(recipe->yeasts.at(i).y_sg_hi * 1000) / 1000); obj.insert("y_cost", recipe->yeasts.at(i).y_cost); // qDebug() << "yeasts_Json" << i << obj; array.append(obj); /* Append this object */ } QJsonDocument doc; doc.setArray(array); // qDebug() << doc.toJson(QJsonDocument::Compact); query.bindValue(":json_yeasts", doc.toJson(QJsonDocument::Compact)); } if (recipe->mashs.size() == 0) { query.bindValue(":json_mashs", "[]"); } else { QJsonArray array; for (int i = 0; i < recipe->mashs.size(); i++) { QJsonObject obj; obj.insert("step_name", recipe->mashs.at(i).step_name); obj.insert("step_type", recipe->mashs.at(i).step_type); obj.insert("step_volume", round(recipe->mashs.at(i).step_volume * 100) / 100); obj.insert("step_infuse_amount", round(recipe->mashs.at(i).step_infuse_amount * 100) / 100); obj.insert("step_infuse_temp", round(recipe->mashs.at(i).step_infuse_temp * 100) / 100); obj.insert("step_temp", round(recipe->mashs.at(i).step_temp * 100) / 100); obj.insert("step_time", round(recipe->mashs.at(i).step_time * 100) / 100); obj.insert("ramp_time", round(recipe->mashs.at(i).ramp_time * 100) / 100); obj.insert("end_temp", round(recipe->mashs.at(i).end_temp * 100) / 100); obj.insert("step_wg_ratio", round(recipe->mashs.at(i).step_wg_ratio * 100) / 100); // qDebug() << "mashs_Json" << i << obj; array.append(obj); /* Append this object */ } QJsonDocument doc; doc.setArray(array); // qDebug() << doc.toJson(QJsonDocument::Compact); query.bindValue(":json_mashs", doc.toJson(QJsonDocument::Compact)); } if (this->recno == -1) { query.bindValue(":uuid", QUuid::createUuid().toString().mid(1, 36)); } else { query.bindValue(":recno", this->recno); } query.exec(); qDebug() << query.lastQuery(); if (query.lastError().isValid()) { qDebug() << "EditRecipe" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()) .arg(query.lastError().driverText()) .arg(query.lastError().databaseText())); } else { qDebug() << "EditRecipe Saved"; } } ui->saveButton->setEnabled(false); this->textIsChanged = false; WindowTitle(); } void EditRecipe::on_deleteButton_clicked() { QSqlQuery query; query.prepare("DELETE FROM recipes WHERE record = :recno"); query.bindValue(":recno", this->recno); query.exec(); if (query.lastError().isValid()) { qDebug() << "EditRecipe" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()) .arg(query.lastError().driverText()) .arg(query.lastError().databaseText())); } else { qDebug() << "EditRecipe Deleted" << this->recno; } this->close(); this->setResult(1); } void EditRecipe::is_changed() { ui->saveButton->setEnabled(true); ui->deleteButton->setEnabled((this->recno >= 0) ? true:false); this->textIsChanged = true; WindowTitle(); } void EditRecipe::name_changed(QString name) { recipe->name = name; is_changed(); } void EditRecipe::notes_changed() { /* The text cannot be passed in a simple way :) */ recipe->notes = ui->notesEdit->toPlainText(); is_changed(); } /* * New beerstyle is selected. */ void EditRecipe::style_changed() { QSqlQuery query; if (ui->beerstyleEdit->currentIndex() < 1) return; query.prepare("SELECT * FROM profile_styles ORDER BY style_guide,style_letter,name"); query.exec(); query.first(); // Skip to the record index. for (int i = 0; i < (ui->beerstyleEdit->currentIndex() - 1); i++) { query.next(); } // Set relevant fields and update ranges. recipe->st_name = query.value(1).toString(); recipe->st_category = query.value(2).toString(); recipe->st_category_number = query.value(3).toInt(); recipe->st_letter = query.value(4).toString(); recipe->st_guide = query.value(5).toString(); recipe->st_type = query.value(6).toInt(); recipe->st_og_min = query.value(7).toDouble(); recipe->st_og_max = query.value(8).toDouble(); recipe->st_fg_min = query.value(9).toDouble(); recipe->st_fg_max = query.value(10).toDouble(); recipe->st_ibu_min = query.value(11).toDouble(); recipe->st_ibu_max = query.value(12).toDouble(); recipe->st_color_min = query.value(13).toDouble(); recipe->st_color_max = query.value(14).toDouble(); recipe->st_carb_min = query.value(15).toDouble(); recipe->st_carb_max = query.value(16).toDouble(); recipe->st_abv_min = query.value(17).toDouble(); recipe->st_abv_max = query.value(18).toDouble(); ui->st_nameEdit->setText(recipe->st_name); ui->st_groupEdit->setText(recipe->st_letter); ui->st_guideEdit->setText(recipe->st_guide); ui->st_catEdit->setText(recipe->st_category); ui->st_catnrEdit->setText(QString("%1").arg(recipe->st_category_number)); ui->st_typeEdit->setText(s_types[recipe->st_type]); ui->est_ogShow->setRange(query.value(7).toDouble(), query.value(8).toDouble()); ui->est_fgShow->setRange(query.value(9).toDouble(), query.value(10).toDouble()); ui->est_ibuShow->setRange(query.value(11).toDouble(), query.value(12).toDouble()); ui->est_colorShow->setRange(query.value(13).toDouble(), query.value(14).toDouble()); ui->est_carbShow->setRange(query.value(15).toDouble(), query.value(16).toDouble()); ui->est_abvShow->setRange(query.value(17).toDouble(), query.value(18).toDouble()); is_changed(); } void EditRecipe::colormethod_changed() { calcFermentables(); is_changed(); } void EditRecipe::on_addFermentRow_clicked() { Fermentables newf; qDebug() << "Add fermentable row"; for (int i = 0; i < recipe->fermentables.size(); i++) { if (recipe->fermentables.at(i).f_amount == 0 && recipe->fermentables.at(i).f_color == 0) return; // Add only one at a time. } newf.f_name = "Select one"; newf.f_origin = ""; newf.f_supplier = ""; newf.f_amount = 0; newf.f_cost = 0; newf.f_type = 0; newf.f_yield = 0; newf.f_color = 0; newf.f_coarse_fine_diff = 0; newf.f_moisture = 0; newf.f_diastatic_power = 0; newf.f_protein = 0; newf.f_dissolved_protein = 0; newf.f_max_in_batch = 100; newf.f_graintype = 0; newf.f_added = 0; newf.f_recommend_mash = true; newf.f_add_after_boil = false; newf.f_adjust_to_total_100 = false; newf.f_percentage = 0; newf.f_di_ph = 0; newf.f_acid_to_ph_57 = 0; recipe->fermentables.append(newf); emit refreshAll(); } void EditRecipe::on_deleteFermentRow_clicked() { QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); int row = pb->objectName().toInt(); qDebug() << "Delete fermentable row" << row << recipe->fermentables.size(); if (recipe->fermentables.size() < 1) return; int rc = QMessageBox::warning(this, tr("Delete fermentable"), tr("Delete %1").arg(recipe->fermentables.at(row).f_name), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (rc == QMessageBox::No) return; this->ignoreChanges = true; recipe->fermentables.removeAt(row); /* * Recalculate the percentages on the rows left. */ double total = 0; for (int i = 0; i < recipe->fermentables.size(); i++) if (recipe->fermentables.at(i).f_added < 4) // Only before bottle/kegging total += recipe->fermentables.at(i).f_amount; for (int i = 0; i < recipe->fermentables.size(); i++) if (recipe->fermentables.at(i).f_added < 4) recipe->fermentables[i].f_percentage = recipe->fermentables.at(i).f_amount / total * 100; this->ignoreChanges = false; emit refreshAll(); } void EditRecipe::ferment_amount_changed(double val) { QTableWidgetItem *item; double total = 0, perc; if (recipe->fermentables_use100) return; qDebug() << "ferment_amount_changed()" << recipe->fermentables_row << val; this->ignoreChanges = true; recipe->fermentables[recipe->fermentables_row].f_amount = val; item = new QTableWidgetItem(QString("%1 Kg").arg(val, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 7, item); for (int i = 0; i < recipe->fermentables.size(); i++) if (recipe->fermentables.at(i).f_added < 4) // Only before bottle/kegging total += recipe->fermentables.at(i).f_amount; /* * Recalculate the percentages */ for (int i = 0; i < recipe->fermentables.size(); i++) { if (recipe->fermentables.at(i).f_added < 4) { perc = recipe->fermentables.at(i).f_amount / total * 100; recipe->fermentables[i].f_percentage = perc; item = new QTableWidgetItem(QString("%1%").arg(perc, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 8, item); if (i == recipe->fermentables_row) this->pctEdit->setValue(perc); } } this->ignoreChanges = false; is_changed(); } void EditRecipe::ferment_pct_changed(double val) { QTableWidgetItem *item; double total = 0, row100 = -1; if (! recipe->fermentables_use100) return; qDebug() << "ferment_pct_changed()" << recipe->fermentables_row << val; /* * Since we have arrived here, adjust_to_100 is active and * this is not the entry to be adjusted to 100. */ for (int i = 0; i < recipe->fermentables.size(); i++) { if (recipe->fermentables.at(i).f_added < 4) // Only before bottle/kegging total += recipe->fermentables.at(i).f_amount; if (recipe->fermentables.at(i).f_adjust_to_total_100) row100 = i; } double oldperc = recipe->fermentables.at(recipe->fermentables_row).f_percentage; double diffp = val - oldperc; double diffw = (diffp / 100) * total; qDebug() << "row100" << row100 << "total" << total << "diff kg" << diffw << "diff %" << diffp; this->ignoreChanges = true; recipe->fermentables[recipe->fermentables_row].f_percentage += diffp; recipe->fermentables[recipe->fermentables_row].f_amount += diffw; recipe->fermentables[row100].f_percentage -= diffp; recipe->fermentables[row100].f_amount -= diffw; item = new QTableWidgetItem(QString("%1 Kg").arg(recipe->fermentables[recipe->fermentables_row].f_amount, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 7, item); this->amountEdit->setValue(recipe->fermentables[recipe->fermentables_row].f_amount); item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables[recipe->fermentables_row].f_percentage, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 8, item); item = new QTableWidgetItem(QString("%1 Kg").arg(recipe->fermentables[row100].f_amount, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(row100, 7, item); item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables[row100].f_percentage, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(row100, 8, item); this->ignoreChanges = false; is_changed(); } void EditRecipe::ferment_to100_changed(bool val) { qDebug() << "ferment_to100_changed()" << recipe->fermentables_row << val << recipe->fermentables_use100; /* * Three scenario's. * 1. There is no fermentable selected yet, just mark it. * 2. There is current one is selected, deselect it. * 3. There is another one selected, deselect and select this one. */ if (! recipe->fermentables_use100 && val) { /* Scenario 1. */ recipe->fermentables_use100 = true; recipe->fermentables[recipe->fermentables_row].f_adjust_to_total_100 = true; pctEdit->setReadOnly(false); amountEdit->setReadOnly(true); } else if (recipe->fermentables_use100 && recipe->fermentables[recipe->fermentables_row].f_adjust_to_total_100 && ! val) { /* Scenario 2. */ recipe->fermentables[recipe->fermentables_row].f_adjust_to_total_100 = false; recipe->fermentables_use100 = false; pctEdit->setReadOnly(true); amountEdit->setReadOnly(false); } else if (recipe->fermentables_use100 && ! recipe->fermentables[recipe->fermentables_row].f_adjust_to_total_100 && val) { /* Scenario 3. */ for (int i = 0; i < recipe->fermentables.size(); i++) { recipe->fermentables[i].f_adjust_to_total_100 = false; } recipe->fermentables[recipe->fermentables_row].f_adjust_to_total_100 = true; } else { qDebug() << "bug"; return; } this->ignoreChanges = true; for (int i = 0; i < recipe->fermentables.size(); i++) { to100Fermentables(i); } this->ignoreChanges = false; is_changed(); } void EditRecipe::ferment_select_changed(int val) { QSqlQuery query; bool instock = instockEdit->isChecked(); QString w; QTableWidgetItem *item; if (val < 1) return; qDebug() << "ferment_select_changed()" << recipe->fermentables_row << val << instock; /* * Search the fermentable pointed by the index and instock flag. */ QString sql = "SELECT name,origin,supplier,cost,type,yield,color,coarse_fine_diff,moisture,diastatic_power,protein,dissolved_protein,max_in_batch," "graintype,recommend_mash,add_after_boil,di_ph,acid_to_ph_57 FROM inventory_fermentables "; if (instock) sql.append("WHERE inventory > 0 "); sql.append("ORDER BY supplier,name"); query.prepare(sql); query.exec(); query.first(); for (int i = 0; i < (val - 1); i++) { query.next(); } qDebug() << "found" << query.value(2).toString() << query.value(0).toString(); /* * Replace the fermentable record contents */ this->ignoreChanges = true; recipe->fermentables[recipe->fermentables_row].f_name = query.value(0).toString(); recipe->fermentables[recipe->fermentables_row].f_origin = query.value(1).toString(); recipe->fermentables[recipe->fermentables_row].f_supplier = query.value(2).toString(); recipe->fermentables[recipe->fermentables_row].f_cost = query.value(3).toDouble(); recipe->fermentables[recipe->fermentables_row].f_type = query.value(4).toInt(); recipe->fermentables[recipe->fermentables_row].f_yield = query.value(5).toDouble(); recipe->fermentables[recipe->fermentables_row].f_color = query.value(6).toDouble(); recipe->fermentables[recipe->fermentables_row].f_coarse_fine_diff = query.value(7).toDouble(); recipe->fermentables[recipe->fermentables_row].f_moisture = query.value(8).toDouble(); recipe->fermentables[recipe->fermentables_row].f_diastatic_power = query.value(9).toDouble(); recipe->fermentables[recipe->fermentables_row].f_protein = query.value(10).toDouble(); recipe->fermentables[recipe->fermentables_row].f_dissolved_protein = query.value(11).toDouble(); recipe->fermentables[recipe->fermentables_row].f_max_in_batch = query.value(12).toDouble(); recipe->fermentables[recipe->fermentables_row].f_graintype = query.value(13).toInt(); recipe->fermentables[recipe->fermentables_row].f_recommend_mash = query.value(14).toInt() ? true:false; recipe->fermentables[recipe->fermentables_row].f_add_after_boil = query.value(15).toInt() ? true:false; recipe->fermentables[recipe->fermentables_row].f_di_ph = query.value(16).toDouble(); recipe->fermentables[recipe->fermentables_row].f_acid_to_ph_57 = query.value(17).toDouble(); /* * Update the visible fields */ nameEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_name); supplierEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_supplier); maxEdit->setValue(recipe->fermentables.at(recipe->fermentables_row).f_max_in_batch); ui->fermentablesTable->setItem(recipe->fermentables_row, 0, new QTableWidgetItem(recipe->fermentables.at(recipe->fermentables_row).f_supplier)); ui->fermentablesTable->setItem(recipe->fermentables_row, 1, new QTableWidgetItem(recipe->fermentables.at(recipe->fermentables_row).f_name)); w = QString("%1").arg(recipe->fermentables.at(recipe->fermentables_row).f_color, 1, 'f', 0, '0'); item = new QTableWidgetItem(w); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 2, item); item = new QTableWidgetItem(f_types[recipe->fermentables.at(recipe->fermentables_row).f_type]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 3, item); item = new QTableWidgetItem(f_graintypes[recipe->fermentables.at(recipe->fermentables_row).f_graintype]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 4, item); item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables.at(recipe->fermentables_row).f_yield, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 6, item); this->ignoreChanges = false; calcFermentables(); is_changed(); } void EditRecipe::ferment_instock_changed(bool val) { QSqlQuery query; qDebug() << "ferment_instock_changed()" << recipe->fermentables_row << val; this->selectEdit->setCurrentIndex(-1); this->selectEdit->clear(); QString sql = "SELECT supplier,name,color,inventory FROM inventory_fermentables "; if (val) sql.append("WHERE inventory > 0 "); sql.append("ORDER BY supplier,name"); query.prepare(sql); query.exec(); query.first(); this->selectEdit->addItem(""); // Start with empty value for (int i = 0; i < query.size(); i++) { this->selectEdit->addItem(query.value(0).toString()+" - "+query.value(1).toString()+" ("+query.value(2).toString()+" EBC) "+ QString("%1 kg").arg(query.value(3).toDouble(), 4, 'f', 3, '0')); query.next(); } } void EditRecipe::ferment_added_changed(int val) { qDebug() << "ferment_added_changed()" << recipe->fermentables_row << val; this->ignoreChanges = true; recipe->fermentables[recipe->fermentables_row].f_added = val; QTableWidgetItem *item = new QTableWidgetItem(f_added[val]); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(recipe->fermentables_row, 5, item); double total = 0; for (int i = 0; i < recipe->fermentables.size(); i++) if (recipe->fermentables.at(i).f_added < 4) // Only before bottle/kegging total += recipe->fermentables.at(i).f_amount; for (int i = 0; i < recipe->fermentables.size(); i++) if (recipe->fermentables.at(i).f_added < 4) recipe->fermentables[i].f_percentage = recipe->fermentables.at(i).f_amount / total * 100; this->ignoreChanges = false; is_changed(); emit refreshAll(); } void EditRecipe::on_editFermentRow_clicked() { QSqlQuery query; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); recipe->fermentables_row = pb->objectName().toInt(); qDebug() << "Edit fermentable row" << recipe->fermentables_row; Fermentables backup = recipe->fermentables.at(recipe->fermentables_row); QDialog* dialog = new QDialog(this); dialog->resize(738, 287); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setObjectName(QString::fromUtf8("buttonBox")); buttonBox->setGeometry(QRect(30, 240, 671, 32)); buttonBox->setLayoutDirection(Qt::LeftToRight); buttonBox->setOrientation(Qt::Horizontal); buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); buttonBox->setCenterButtons(true); QLabel *nameLabel = new QLabel(dialog); nameLabel->setObjectName(QString::fromUtf8("nameLabel")); nameLabel->setText(tr("Current ingredient:")); nameLabel->setGeometry(QRect(10, 10, 141, 20)); nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *supplierLabel = new QLabel(dialog); supplierLabel->setObjectName(QString::fromUtf8("supplierLabel")); supplierLabel->setText(tr("Supplier:")); supplierLabel->setGeometry(QRect(10, 40, 141, 20)); supplierLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *amountLabel = new QLabel(dialog); amountLabel->setObjectName(QString::fromUtf8("amountLabel")); amountLabel->setText(tr("Amount in kg:")); amountLabel->setGeometry(QRect(10, 100, 141, 20)); amountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *pctLabel = new QLabel(dialog); pctLabel->setObjectName(QString::fromUtf8("pctLabel")); pctLabel->setText(tr("Percentage in batch:")); pctLabel->setGeometry(QRect(10, 130, 141, 20)); pctLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *to100Label = new QLabel(dialog); to100Label->setObjectName(QString::fromUtf8("to100Label")); to100Label->setText(tr("Auto fill to 100%:")); to100Label->setGeometry(QRect(10, 160, 141, 20)); to100Label->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *addedLabel = new QLabel(dialog); addedLabel->setObjectName(QString::fromUtf8("addedLabel")); addedLabel->setText(tr("Use at:")); addedLabel->setGeometry(QRect(10, 190, 141, 20)); addedLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *selectLabel = new QLabel(dialog); selectLabel->setObjectName(QString::fromUtf8("selectLabel")); selectLabel->setText(tr("Select ingredient:")); selectLabel->setGeometry(QRect(10, 70, 141, 20)); selectLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *instockLabel = new QLabel(dialog); instockLabel->setObjectName(QString::fromUtf8("instockLabel")); instockLabel->setText(tr("In stock:")); instockLabel->setGeometry(QRect(525, 70, 121, 20)); instockLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *maxLabel = new QLabel(dialog); maxLabel->setObjectName(QString::fromUtf8("maxLabel")); maxLabel->setText(tr("Max in batch:")); maxLabel->setGeometry(QRect(420, 130, 121, 20)); maxLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); selectEdit = new QComboBox(dialog); selectEdit->setObjectName(QString::fromUtf8("selectEdit")); selectEdit->setGeometry(QRect(160, 70, 371, 23)); nameEdit = new QLineEdit(dialog); nameEdit->setObjectName(QString::fromUtf8("nameEdit")); nameEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_name); nameEdit->setGeometry(QRect(160, 10, 511, 23)); nameEdit->setReadOnly(true); supplierEdit = new QLineEdit(dialog); supplierEdit->setObjectName(QString::fromUtf8("supplierEdit")); supplierEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_supplier); supplierEdit->setGeometry(QRect(160, 40, 511, 23)); supplierEdit->setReadOnly(true); amountEdit = new QDoubleSpinBox(dialog); amountEdit->setObjectName(QString::fromUtf8("amountEdit")); amountEdit->setGeometry(QRect(160, 100, 121, 24)); amountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); amountEdit->setAccelerated(true); amountEdit->setDecimals(3); amountEdit->setReadOnly(recipe->fermentables_use100); amountEdit->setMaximum(100000.0); amountEdit->setSingleStep(0.0010); amountEdit->setValue(recipe->fermentables.at(recipe->fermentables_row).f_amount); pctEdit = new QDoubleSpinBox(dialog); pctEdit->setObjectName(QString::fromUtf8("pctEdit")); pctEdit->setGeometry(QRect(160, 130, 121, 24)); pctEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); pctEdit->setAccelerated(true); pctEdit->setDecimals(1); if (recipe->fermentables_use100) { if (recipe->fermentables.at(recipe->fermentables_row).f_adjust_to_total_100) pctEdit->setReadOnly(true); else pctEdit->setReadOnly(false); } else { pctEdit->setReadOnly(true); } pctEdit->setMaximum(100.0); pctEdit->setSingleStep(0.1); pctEdit->setValue(recipe->fermentables.at(recipe->fermentables_row).f_percentage); addedEdit = new QComboBox(dialog); addedEdit->setObjectName(QString::fromUtf8("addedEdit")); addedEdit->setGeometry(QRect(160, 190, 161, 23)); addedEdit->addItem(tr("Mash")); addedEdit->addItem(tr("Boil")); addedEdit->addItem(tr("Fermentation")); addedEdit->addItem(tr("Lagering")); addedEdit->addItem(tr("Bottle")); addedEdit->addItem(tr("Kegs")); addedEdit->setCurrentIndex(recipe->fermentables.at(recipe->fermentables_row).f_added); to100Edit = new QCheckBox(dialog); to100Edit->setObjectName(QString::fromUtf8("to100Edit")); to100Edit->setGeometry(QRect(160, 160, 85, 21)); to100Edit->setChecked(recipe->fermentables.at(recipe->fermentables_row).f_adjust_to_total_100); instockEdit = new QCheckBox(dialog); instockEdit->setObjectName(QString::fromUtf8("instockEdit")); instockEdit->setGeometry(QRect(655, 70, 85, 21)); instockEdit->setChecked(true); maxEdit = new QDoubleSpinBox(dialog); maxEdit->setObjectName(QString::fromUtf8("maxEdit")); maxEdit->setGeometry(QRect(550, 130, 121, 24)); maxEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); maxEdit->setReadOnly(true); maxEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); maxEdit->setDecimals(1); maxEdit->setValue(recipe->fermentables.at(recipe->fermentables_row).f_max_in_batch); ferment_instock_changed(true); connect(selectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::ferment_select_changed); connect(amountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_amount_changed); connect(pctEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_pct_changed); connect(addedEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::ferment_added_changed); connect(to100Edit, &QCheckBox::stateChanged, this, &EditRecipe::ferment_to100_changed); connect(instockEdit, &QCheckBox::stateChanged, this, &EditRecipe::ferment_instock_changed); connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); dialog->setModal(true); dialog->exec(); if (dialog->result() == QDialog::Rejected) { qDebug() << "reject and rollback"; recipe->fermentables[recipe->fermentables_row] = backup; /* * Recalculate the percentages */ double total = 0; for (int i = 0; i < recipe->fermentables.size(); i++) if (recipe->fermentables.at(i).f_added < 4) // Only before bottle/kegging total += recipe->fermentables.at(i).f_amount; recipe->fermentables_use100 = false; for (int i = 0; i < recipe->fermentables.size(); i++) { if (recipe->fermentables.at(i).f_adjust_to_total_100) recipe->fermentables_use100 = true; if (recipe->fermentables.at(i).f_added < 4) { recipe->fermentables[i].f_percentage = recipe->fermentables.at(i).f_amount / total * 100; } } } disconnect(selectEdit, nullptr, nullptr, nullptr); disconnect(amountEdit, nullptr, nullptr, nullptr); disconnect(pctEdit, nullptr, nullptr, nullptr); disconnect(addedEdit, nullptr, nullptr, nullptr); disconnect(to100Edit, nullptr, nullptr, nullptr); disconnect(instockEdit, nullptr, nullptr, nullptr); disconnect(buttonBox, nullptr, nullptr, nullptr); emit refreshAll(); } void EditRecipe::on_quitButton_clicked() { if (this->textIsChanged) { int rc = QMessageBox::warning(this, tr("Recipe changed"), tr("The recipe has been modified. Save changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save); switch (rc) { case QMessageBox::Save: on_saveButton_clicked(); break; /* Saved and then Quit */ case QMessageBox::Discard: break; /* Quit without Save */ case QMessageBox::Cancel: return; /* Return to the editor page */ } } this->close(); this->setResult(1); }