Mon, 11 Apr 2022 17:22:43 +0200
Split recipes source in tabs.
--- a/src/EditRecipe.cpp Mon Apr 11 16:18:40 2022 +0200 +++ b/src/EditRecipe.cpp Mon Apr 11 17:22:43 2022 +0200 @@ -519,325 +519,6 @@ } -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, 82); /* 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; -} - - -bool EditRecipe::hop_sort_test(const Hops &D1, const Hops &D2) -{ - if (D1.h_useat > D2.h_useat) - return false; - if (D1.h_useat < D2.h_useat) - return true; - /* Same useat moments, test time. */ - if (D1.h_time < D2.h_time) - return false; - if (D1.h_time > D2.h_time) - return true; - /* Finally consider the amounts */ - return (D1.h_amount > D2.h_amount); -} - - -void EditRecipe::refreshHops() -{ - QString w; - QWidget* pWidget; - QHBoxLayout* pLayout; - QTableWidgetItem *item; - - qDebug() << "refreshHops" << recipe->hops.size(); - std::sort(recipe->hops.begin(), recipe->hops.end(), hop_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("Origin"), tr("Hop"), tr("Type"), tr("Form"), tr("Alpha"), tr("Use at"), tr("Time"), - tr("IBU"), tr("Amount"), tr("Delete"), tr("Edit") }); - - ui->hopsTable->setColumnCount(11); - ui->hopsTable->setColumnWidth(0, 150); /* Origin */ - ui->hopsTable->setColumnWidth(1, 225); /* Hop */ - ui->hopsTable->setColumnWidth(2, 75); /* Type */ - ui->hopsTable->setColumnWidth(3, 75); /* Form */ - ui->hopsTable->setColumnWidth(4, 75); /* Alpha% */ - ui->hopsTable->setColumnWidth(5, 75); /* Added */ - ui->hopsTable->setColumnWidth(6, 75); /* Time */ - ui->hopsTable->setColumnWidth(7, 60); /* IBU */ - ui->hopsTable->setColumnWidth(8, 75); /* Amount */ - ui->hopsTable->setColumnWidth(9, 80); /* Delete */ - ui->hopsTable->setColumnWidth(10, 80); /* Edit */ - ui->hopsTable->setHorizontalHeaderLabels(labels); - ui->hopsTable->verticalHeader()->hide(); - ui->hopsTable->setRowCount(recipe->hops.size()); - - for (int i = 0; i < recipe->hops.size(); i++) { - - ui->hopsTable->setItem(i, 0, new QTableWidgetItem(recipe->hops.at(i).h_origin)); - ui->hopsTable->setItem(i, 1, new QTableWidgetItem(recipe->hops.at(i).h_name)); - - item = new QTableWidgetItem(h_types[recipe->hops.at(i).h_type]); - item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 2, item); - - item = new QTableWidgetItem(h_forms[recipe->hops.at(i).h_form]); - item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 3, item); - - item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(i).h_alpha, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 4, item); - - item = new QTableWidgetItem(h_useat[recipe->hops.at(i).h_useat]); - item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 5, item); - - if (recipe->hops.at(i).h_useat == 2 || recipe->hops.at(i).h_useat == 4) { // Boil or whirlpool - item = new QTableWidgetItem(QString("%1 min.").arg(recipe->hops.at(i).h_time, 1, 'f', 0, '0')); - } else if (recipe->hops.at(i).h_useat == 5) { // Dry-hop - item = new QTableWidgetItem(QString("%1 days.").arg(recipe->hops.at(i).h_time / 1440, 1, 'f', 0, '0')); - } else { - item = new QTableWidgetItem(QString("")); - } - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 6, item); - - double ibu = Utils::toIBU(recipe->hops.at(i).h_useat, recipe->hops.at(i).h_form, recipe->preboil_sg, recipe->batch_size, recipe->hops.at(i).h_amount, - recipe->hops.at(i).h_time, recipe->hops.at(i).h_alpha, recipe->ibu_method, 0, recipe->hops.at(i).h_time, 0); - item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 7, item); - - if (recipe->hops.at(i).h_amount < 1.0) { - item = new QTableWidgetItem(QString("%1 gr").arg(recipe->hops.at(i).h_amount * 1000.0, 2, 'f', 1, '0')); - } else { - item = new QTableWidgetItem(QString("%1 kg").arg(recipe->hops.at(i).h_amount, 4, 'f', 3, '0')); - } - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(i, 8, item); - - /* 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_deleteHopRow_clicked())); - pLayout = new QHBoxLayout(pWidget); - pLayout->addWidget(btn_dele); - pLayout->setContentsMargins(5, 0, 5, 0); - pWidget->setLayout(pLayout); - ui->hopsTable->setCellWidget(i, 9, 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_editHopRow_clicked())); - pLayout = new QHBoxLayout(pWidget); - pLayout->addWidget(btn_edit); - pLayout->setContentsMargins(5, 0, 5, 0); - pWidget->setLayout(pLayout); - ui->hopsTable->setCellWidget(i, 10, pWidget); - } - this->ignoreChanges = false; -} - - -void EditRecipe::on_Flavour_valueChanged(int value) -{ - if (value < 20) { - ui->hop_tasteShow->setStyleSheet(bar_20); - ui->hop_tasteShow->setFormat(tr("Very low")); - } else if (value < 40) { - ui->hop_tasteShow->setStyleSheet(bar_40); - ui->hop_tasteShow->setFormat(tr("Low")); - } else if (value < 60) { - ui->hop_tasteShow->setStyleSheet(bar_60); - ui->hop_tasteShow->setFormat(tr("Moderate")); - } else if (value < 80) { - ui->hop_tasteShow->setStyleSheet(bar_80); - ui->hop_tasteShow->setFormat(tr("High")); - } else { - ui->hop_tasteShow->setStyleSheet(bar_100); - ui->hop_tasteShow->setFormat(tr("Very high")); - } -} - - -void EditRecipe::on_Aroma_valueChanged(int value) -{ - if (value < 20) { - ui->hop_aromaShow->setStyleSheet(bar_20); - ui->hop_aromaShow->setFormat(tr("Very low")); - } else if (value < 40) { - ui->hop_aromaShow->setStyleSheet(bar_40); - ui->hop_aromaShow->setFormat(tr("Low")); - } else if (value < 60) { - ui->hop_aromaShow->setStyleSheet(bar_60); - ui->hop_aromaShow->setFormat(tr("Moderate")); - } else if (value < 80) { - ui->hop_aromaShow->setStyleSheet(bar_80); - ui->hop_aromaShow->setFormat(tr("High")); - } else { - ui->hop_aromaShow->setStyleSheet(bar_100); - ui->hop_aromaShow->setFormat(tr("Very high")); - } -} - - -void EditRecipe::calcIBUs() -{ - double hop_flavour = 0, hop_aroma = 0, ibus = 0; - - for (int i = 0; i < recipe->hops.size(); i++) { - - ibus += Utils::toIBU(recipe->hops.at(i).h_useat, recipe->hops.at(i).h_form, recipe->preboil_sg, recipe->batch_size, recipe->hops.at(i).h_amount, - recipe->hops.at(i).h_time, recipe->hops.at(i).h_alpha, recipe->ibu_method, 0, recipe->hops.at(i).h_time, 0); - hop_flavour += Utils::hopFlavourContribution(recipe->hops.at(i).h_time, recipe->batch_size, recipe->hops.at(i).h_useat, recipe->hops.at(i).h_amount); - hop_aroma += Utils::hopAromaContribution(recipe->hops.at(i).h_time, recipe->batch_size, recipe->hops.at(i).h_useat, recipe->hops.at(i).h_amount); - } - - hop_flavour = round(hop_flavour * 1000.0 / 5.0) / 10; - hop_aroma = round(hop_aroma * 1000.0 / 6.0) / 10; - if (hop_flavour > 100) - hop_flavour = 100; - if (hop_aroma > 100) - hop_aroma = 100; - qDebug() << "ibu" << recipe->est_ibu << ibus << "flavour" << hop_flavour << "aroma" << hop_aroma; - - recipe->est_ibu = ibus; - ui->est_ibuEdit->setValue(recipe->est_ibu); - ui->est_ibu2Edit->setValue(recipe->est_ibu); - ui->hop_tasteShow->setValue(hop_flavour); - ui->hop_aromaShow->setValue(hop_aroma); -} - - void EditRecipe::refreshMiscs() { } @@ -865,243 +546,6 @@ } -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); - - recipe->preboil_sg = Utils::estimate_sg(sugarsm, ui->boil_sizeEdit->value()); - qDebug() << " preboil SG" << recipe->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 '**' */ @@ -1454,6 +898,11 @@ } +#include "EditRecipeTab1.cpp" +#include "EditRecipeTab2.cpp" +#include "EditRecipeTab3.cpp" + + void EditRecipe::on_deleteButton_clicked() { QSqlQuery query; @@ -1486,998 +935,6 @@ } -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_addHopRow_clicked() -{ - Hops newh; - - qDebug() << "Add hop row"; - - for (int i = 0; i < recipe->hops.size(); i++) { - if (recipe->hops.at(i).h_amount == 0 && recipe->hops.at(i).h_alpha == 0) - return; // Add only one at a time. - } - - 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::on_deleteHopRow_clicked() -{ - QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); - int row = pb->objectName().toInt(); - qDebug() << "Delete hop row" << row << recipe->hops.size(); - - if (recipe->hops.size() < 1) - return; - - int rc = QMessageBox::warning(this, tr("Delete hop"), tr("Delete %1").arg(recipe->hops.at(row).h_name), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - if (rc == QMessageBox::No) - return; - - -} - - -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::hop_amount_changed(double val) -{ - QTableWidgetItem *item; - - qDebug() << "hop_amount_changed()" << recipe->hops_row << val; - this->ignoreChanges = true; - - recipe->hops[recipe->hops_row].h_amount = val / 1000.0; - item = new QTableWidgetItem(QString("%1 gr").arg(val, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 8, item); - - double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, - recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, - recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); - - ibuEdit->setValue(ibu); - item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 7, item); - - this->ignoreChanges = false; - calcIBUs(); - 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->famountEdit->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::hop_time_changed(int val) -{ - QTableWidgetItem *item; - - qDebug() << "hop_time_changed()" << recipe->hops_row << val; - - this->ignoreChanges = true; - recipe->hops[recipe->hops_row].h_time = val; - - if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) { // Boil or whirlpool - item = new QTableWidgetItem(QString("%1 min.").arg(val, 1, 'f', 0, '0')); - } else if (recipe->hops.at(recipe->hops_row).h_useat == 5) { // Dry-hop - item = new QTableWidgetItem(QString("%1 days.").arg(val / 1440, 1, 'f', 0, '0')); - } else { - item = new QTableWidgetItem(QString("")); - } - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 6, item); - - double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, - recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, - recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); - - ibuEdit->setValue(ibu); - item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 7, item); - - this->ignoreChanges = false; - calcIBUs(); - 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); - famountEdit->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); - famountEdit->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 = finstockEdit->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 - */ - fnameEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_name); - fsupplierEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_supplier); - fmaxEdit->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::hop_select_changed(int val) -{ - QSqlQuery query; - bool instock = hinstockEdit->isChecked(); - QString w; - QTableWidgetItem *item; - - if (val < 1) - return; - - qDebug() << "hop_select_changed()" << recipe->fermentables_row << val << instock; - - /* - * Search the hop pointed by the index and instock flag. - */ - QString sql = "SELECT name,origin,alpha,beta,humulene,caryophyllene,cohumulone,myrcene,hsi,total_oil,type,form,cost FROM inventory_hops "; - if (instock) - sql.append("WHERE inventory > 0 "); - sql.append("ORDER BY origin,name"); - query.prepare(sql); - query.exec(); - query.first(); - for (int i = 0; i < (val - 1); i++) { - query.next(); - } - qDebug() << "found" << query.value(1).toString() << query.value(0).toString(); - - /* - * Replace the hop record contents - */ - this->ignoreChanges = true; - recipe->hops[recipe->hops_row].h_name = query.value(0).toString(); - recipe->hops[recipe->hops_row].h_origin = query.value(1).toString(); - recipe->hops[recipe->hops_row].h_alpha = query.value(2).toDouble(); - recipe->hops[recipe->hops_row].h_beta = query.value(3).toDouble(); - recipe->hops[recipe->hops_row].h_humulene = query.value(4).toDouble(); - recipe->hops[recipe->hops_row].h_caryophyllene = query.value(5).toDouble(); - recipe->hops[recipe->hops_row].h_cohumulone = query.value(6).toDouble(); - recipe->hops[recipe->hops_row].h_myrcene = query.value(7).toDouble(); - recipe->hops[recipe->hops_row].h_hsi = query.value(8).toDouble(); - recipe->hops[recipe->hops_row].h_total_oil = query.value(9).toDouble(); - recipe->hops[recipe->hops_row].h_type = query.value(10).toInt(); - recipe->hops[recipe->hops_row].h_form = query.value(11).toInt(); - recipe->hops[recipe->hops_row].h_cost = query.value(12).toDouble(); - - /* - * Update the visible fields - */ - hnameEdit->setText(recipe->hops.at(recipe->hops_row).h_name); - horiginEdit->setText(recipe->hops.at(recipe->hops_row).h_origin); - - double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, - recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, - recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); - ibuEdit->setValue(ibu); - - ui->hopsTable->setItem(recipe->hops_row, 0, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).h_origin)); - ui->hopsTable->setItem(recipe->hops_row, 1, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).h_name)); - - item = new QTableWidgetItem(h_types[recipe->hops.at(recipe->hops_row).h_type]); - item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 2, item); - - item = new QTableWidgetItem(h_forms[recipe->hops.at(recipe->hops_row).h_form]); - item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 3, item); - - item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(recipe->hops_row).h_alpha, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 4, item); - - item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); - item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 7, item); - - this->ignoreChanges = false; - calcIBUs(); - is_changed(); -} - - -void EditRecipe::ferment_instock_changed(bool val) -{ - QSqlQuery query; - - qDebug() << "ferment_instock_changed()" << recipe->fermentables_row << val; - - this->fselectEdit->setCurrentIndex(-1); - this->fselectEdit->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->fselectEdit->addItem(""); // Start with empty value - for (int i = 0; i < query.size(); i++) { - this->fselectEdit->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::hop_instock_changed(bool val) -{ - QSqlQuery query; - - qDebug() << "hop_instock_changed()" << recipe->hops_row << val; - - this->hselectEdit->setCurrentIndex(-1); - this->hselectEdit->clear(); - QString sql = "SELECT origin,name,alpha,inventory FROM inventory_hops "; - if (val) - sql.append("WHERE inventory > 0 "); - sql.append("ORDER BY origin,name"); - query.prepare(sql); - query.exec(); - query.first(); - this->hselectEdit->addItem(""); // Start with empty value - for (int i = 0; i < query.size(); i++) { - this->hselectEdit->addItem(query.value(0).toString()+" - "+query.value(1).toString()+" ("+query.value(2).toString()+"%) "+ - QString("%1 gr").arg(query.value(3).toDouble() * 1000.0, 2, 'f', 1, '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::hop_useat_changed(int val) -{ - qDebug() << "hop_useat_changed()" << recipe->hops_row << val; - - this->ignoreChanges = true; - recipe->hops[recipe->hops_row].h_useat = val; - QTableWidgetItem *item = new QTableWidgetItem(h_useat[val]); - item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); - ui->hopsTable->setItem(recipe->hops_row, 5, item); - - if (val == 2 || val == 4) { // Boil or whirlpool - htimeLabel->setText(tr("Time in minutes:")); - htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time); - htimeEdit->setReadOnly(false); - } else if (val == 5) { // Dry-hop - htimeLabel->setText(tr("Time in days:")); - htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time / 1440); - htimeEdit->setReadOnly(false); - } else { - htimeLabel->setText(""); - htimeEdit->setValue(0); - htimeEdit->setReadOnly(true); - } - - 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); - - fselectEdit = new QComboBox(dialog); - fselectEdit->setObjectName(QString::fromUtf8("fselectEdit")); - fselectEdit->setGeometry(QRect(160, 70, 371, 23)); - - fnameEdit = new QLineEdit(dialog); - fnameEdit->setObjectName(QString::fromUtf8("fnameEdit")); - fnameEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_name); - fnameEdit->setGeometry(QRect(160, 10, 511, 23)); - fnameEdit->setReadOnly(true); - fsupplierEdit = new QLineEdit(dialog); - fsupplierEdit->setObjectName(QString::fromUtf8("fsupplierEdit")); - fsupplierEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_supplier); - fsupplierEdit->setGeometry(QRect(160, 40, 511, 23)); - fsupplierEdit->setReadOnly(true); - famountEdit = new QDoubleSpinBox(dialog); - famountEdit->setObjectName(QString::fromUtf8("famountEdit")); - famountEdit->setGeometry(QRect(160, 100, 121, 24)); - famountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - famountEdit->setAccelerated(true); - famountEdit->setDecimals(3); - famountEdit->setReadOnly(recipe->fermentables_use100); - famountEdit->setMaximum(100000.0); - famountEdit->setSingleStep(0.0010); - famountEdit->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); - - faddedEdit = new QComboBox(dialog); - faddedEdit->setObjectName(QString::fromUtf8("faddedEdit")); - faddedEdit->setGeometry(QRect(160, 190, 161, 23)); - faddedEdit->addItem(tr("Mash")); - faddedEdit->addItem(tr("Boil")); - faddedEdit->addItem(tr("Fermentation")); - faddedEdit->addItem(tr("Lagering")); - faddedEdit->addItem(tr("Bottle")); - faddedEdit->addItem(tr("Kegs")); - faddedEdit->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); - - finstockEdit = new QCheckBox(dialog); - finstockEdit->setObjectName(QString::fromUtf8("instockEdit")); - finstockEdit->setGeometry(QRect(655, 70, 85, 21)); - finstockEdit->setChecked(true); - - fmaxEdit = new QDoubleSpinBox(dialog); - fmaxEdit->setObjectName(QString::fromUtf8("fmaxEdit")); - fmaxEdit->setGeometry(QRect(550, 130, 121, 24)); - fmaxEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - fmaxEdit->setReadOnly(true); - fmaxEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); - fmaxEdit->setDecimals(1); - fmaxEdit->setValue(recipe->fermentables.at(recipe->fermentables_row).f_max_in_batch); - - ferment_instock_changed(true); - - connect(fselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::ferment_select_changed); - connect(famountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_amount_changed); - connect(pctEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_pct_changed); - connect(faddedEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::ferment_added_changed); - connect(to100Edit, &QCheckBox::stateChanged, this, &EditRecipe::ferment_to100_changed); - connect(finstockEdit, &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(fselectEdit, nullptr, nullptr, nullptr); - disconnect(famountEdit, nullptr, nullptr, nullptr); - disconnect(pctEdit, nullptr, nullptr, nullptr); - disconnect(faddedEdit, nullptr, nullptr, nullptr); - disconnect(to100Edit, nullptr, nullptr, nullptr); - disconnect(finstockEdit, nullptr, nullptr, nullptr); - disconnect(buttonBox, nullptr, nullptr, nullptr); - - emit refreshAll(); -} - - -void EditRecipe::on_editHopRow_clicked() -{ - QSqlQuery query; - - QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); - recipe->hops_row = pb->objectName().toInt(); - qDebug() << "Edit hop row" << recipe->hops_row; - Hops backup = recipe->hops.at(recipe->hops_row); - - QDialog* dialog = new QDialog(this); - dialog->resize(738, 260); - QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); - buttonBox->setObjectName(QString::fromUtf8("buttonBox")); - buttonBox->setGeometry(QRect(30, 210, 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 hop:")); - nameLabel->setGeometry(QRect(10, 10, 141, 20)); - nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - QLabel *originLabel = new QLabel(dialog); - originLabel->setObjectName(QString::fromUtf8("originLabel")); - originLabel->setText(tr("Origin:")); - originLabel->setGeometry(QRect(10, 40, 141, 20)); - originLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - QLabel *amountLabel = new QLabel(dialog); - amountLabel->setObjectName(QString::fromUtf8("amountLabel")); - amountLabel->setText(tr("Amount in gr:")); - amountLabel->setGeometry(QRect(10, 100, 141, 20)); - amountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - htimeLabel = new QLabel(dialog); - htimeLabel->setObjectName(QString::fromUtf8("htimeLabel")); - if (recipe->hops.at(recipe->hops_row).h_useat == 5) // Dry-hop - htimeLabel->setText(tr("Time in days:")); - else if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) // Boil or whirlpool - htimeLabel->setText(tr("Time in minutes:")); - else - htimeLabel->setText(""); - - htimeLabel->setGeometry(QRect(10, 130, 141, 20)); - htimeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - QLabel *useatLabel = new QLabel(dialog); - useatLabel->setObjectName(QString::fromUtf8("useatLabel")); - useatLabel->setText(tr("Use at:")); - useatLabel->setGeometry(QRect(10, 160, 141, 20)); - useatLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - QLabel *selectLabel = new QLabel(dialog); - selectLabel->setObjectName(QString::fromUtf8("selectLabel")); - selectLabel->setText(tr("Select hop:")); - 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 *ibuLabel = new QLabel(dialog); - ibuLabel->setObjectName(QString::fromUtf8("maxLabel")); - ibuLabel->setText(tr("Bitterness IBU:")); - ibuLabel->setGeometry(QRect(420, 130, 121, 20)); - ibuLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - - hselectEdit = new QComboBox(dialog); - hselectEdit->setObjectName(QString::fromUtf8("selectEdit")); - hselectEdit->setGeometry(QRect(160, 70, 371, 23)); - - hnameEdit = new QLineEdit(dialog); - hnameEdit->setObjectName(QString::fromUtf8("hnameEdit")); - hnameEdit->setText(recipe->hops.at(recipe->hops_row).h_name); - hnameEdit->setGeometry(QRect(160, 10, 511, 23)); - hnameEdit->setReadOnly(true); - horiginEdit = new QLineEdit(dialog); - horiginEdit->setObjectName(QString::fromUtf8("horiginEdit")); - horiginEdit->setText(recipe->hops.at(recipe->hops_row).h_origin); - horiginEdit->setGeometry(QRect(160, 40, 511, 23)); - horiginEdit->setReadOnly(true); - hamountEdit = new QDoubleSpinBox(dialog); - hamountEdit->setObjectName(QString::fromUtf8("hamountEdit")); - hamountEdit->setGeometry(QRect(160, 100, 121, 24)); - hamountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - hamountEdit->setAccelerated(true); - hamountEdit->setDecimals(1); - hamountEdit->setMaximum(1000000.0); - hamountEdit->setSingleStep(0.5); - hamountEdit->setValue(recipe->hops.at(recipe->hops_row).h_amount * 1000.0); - htimeEdit = new QSpinBox(dialog); - htimeEdit->setObjectName(QString::fromUtf8("htimeEdit")); - htimeEdit->setGeometry(QRect(160, 130, 121, 24)); - htimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - htimeEdit->setAccelerated(true); - htimeEdit->setMaximum(10000.0); - if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) { // Boil or whirlpool - htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time); - htimeEdit->setReadOnly(false); - } else if (recipe->hops.at(recipe->hops_row).h_useat == 5){ // Dry-hop - htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time / 1440); - htimeEdit->setReadOnly(false); - } else { - htimeEdit->setReadOnly(true); - } - useatEdit = new QComboBox(dialog); - useatEdit->setObjectName(QString::fromUtf8("useatEdit")); - useatEdit->setGeometry(QRect(160, 160, 161, 23)); - useatEdit->addItem(tr("Mash")); - useatEdit->addItem(tr("First wort")); - useatEdit->addItem(tr("Boil")); - useatEdit->addItem(tr("Aroma")); - useatEdit->addItem(tr("Whirlpool")); - useatEdit->addItem(tr("Dry hop")); - useatEdit->setCurrentIndex(recipe->hops.at(recipe->hops_row).h_useat); - - hinstockEdit = new QCheckBox(dialog); - hinstockEdit->setObjectName(QString::fromUtf8("hinstockEdit")); - hinstockEdit->setGeometry(QRect(655, 70, 85, 21)); - hinstockEdit->setChecked(true); - - ibuEdit = new QDoubleSpinBox(dialog); - ibuEdit->setObjectName(QString::fromUtf8("ibuEdit")); - ibuEdit->setGeometry(QRect(550, 130, 121, 24)); - ibuEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); - ibuEdit->setReadOnly(true); - ibuEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); - ibuEdit->setDecimals(1); - double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, - recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, - recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); - ibuEdit->setValue(ibu); - - hop_instock_changed(true); - - connect(hselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_select_changed); - connect(hamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::hop_amount_changed); - connect(htimeEdit, QOverload<int>::of(&QSpinBox::valueChanged), this, &EditRecipe::hop_time_changed); - connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_useat_changed); - connect(hinstockEdit, &QCheckBox::stateChanged, this, &EditRecipe::hop_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->hops[recipe->hops_row] = backup; - } else { - /* Clear time if hop is not used for boil, whirlpool or dry-hop. */ - if (! (recipe->hops.at(recipe->hops_row).h_useat == 2 || - recipe->hops.at(recipe->hops_row).h_useat == 4 || - recipe->hops.at(recipe->hops_row).h_useat == 5)) { - if (recipe->hops.at(recipe->hops_row).h_time) { - recipe->hops[recipe->hops_row].h_time = 0; - is_changed(); - } - } - } - - disconnect(hselectEdit, nullptr, nullptr, nullptr); - disconnect(hamountEdit, nullptr, nullptr, nullptr); - disconnect(htimeEdit, nullptr, nullptr, nullptr); - disconnect(useatEdit, nullptr, nullptr, nullptr); - disconnect(hinstockEdit, nullptr, nullptr, nullptr); - disconnect(buttonBox, nullptr, nullptr, nullptr); - - emit refreshAll(); -} - - void EditRecipe::on_quitButton_clicked() { if (this->textIsChanged) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EditRecipeTab1.cpp Mon Apr 11 17:22:43 2022 +0200 @@ -0,0 +1,98 @@ +/** + * EditRecipe.cpp is part of bmsapp. + * + * Tab 1, generic settings. + * + * 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/>. + */ + + + +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(); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EditRecipeTab2.cpp Mon Apr 11 17:22:43 2022 +0200 @@ -0,0 +1,901 @@ +/** + * EditRecipe.cpp is part of bmsapp. + * + * Tab 2, fermetables + * + * 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/>. + */ + + + +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, 82); /* 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::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); + + recipe->preboil_sg = Utils::estimate_sg(sugarsm, ui->boil_sizeEdit->value()); + qDebug() << " preboil SG" << recipe->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); +} + + +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->famountEdit->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); + famountEdit->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); + famountEdit->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 = finstockEdit->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 + */ + fnameEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_name); + fsupplierEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_supplier); + fmaxEdit->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->fselectEdit->setCurrentIndex(-1); + this->fselectEdit->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->fselectEdit->addItem(""); // Start with empty value + for (int i = 0; i < query.size(); i++) { + this->fselectEdit->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); + + fselectEdit = new QComboBox(dialog); + fselectEdit->setObjectName(QString::fromUtf8("fselectEdit")); + fselectEdit->setGeometry(QRect(160, 70, 371, 23)); + + fnameEdit = new QLineEdit(dialog); + fnameEdit->setObjectName(QString::fromUtf8("fnameEdit")); + fnameEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_name); + fnameEdit->setGeometry(QRect(160, 10, 511, 23)); + fnameEdit->setReadOnly(true); + fsupplierEdit = new QLineEdit(dialog); + fsupplierEdit->setObjectName(QString::fromUtf8("fsupplierEdit")); + fsupplierEdit->setText(recipe->fermentables.at(recipe->fermentables_row).f_supplier); + fsupplierEdit->setGeometry(QRect(160, 40, 511, 23)); + fsupplierEdit->setReadOnly(true); + famountEdit = new QDoubleSpinBox(dialog); + famountEdit->setObjectName(QString::fromUtf8("famountEdit")); + famountEdit->setGeometry(QRect(160, 100, 121, 24)); + famountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + famountEdit->setAccelerated(true); + famountEdit->setDecimals(3); + famountEdit->setReadOnly(recipe->fermentables_use100); + famountEdit->setMaximum(100000.0); + famountEdit->setSingleStep(0.0010); + famountEdit->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); + + faddedEdit = new QComboBox(dialog); + faddedEdit->setObjectName(QString::fromUtf8("faddedEdit")); + faddedEdit->setGeometry(QRect(160, 190, 161, 23)); + faddedEdit->addItem(tr("Mash")); + faddedEdit->addItem(tr("Boil")); + faddedEdit->addItem(tr("Fermentation")); + faddedEdit->addItem(tr("Lagering")); + faddedEdit->addItem(tr("Bottle")); + faddedEdit->addItem(tr("Kegs")); + faddedEdit->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); + + finstockEdit = new QCheckBox(dialog); + finstockEdit->setObjectName(QString::fromUtf8("instockEdit")); + finstockEdit->setGeometry(QRect(655, 70, 85, 21)); + finstockEdit->setChecked(true); + + fmaxEdit = new QDoubleSpinBox(dialog); + fmaxEdit->setObjectName(QString::fromUtf8("fmaxEdit")); + fmaxEdit->setGeometry(QRect(550, 130, 121, 24)); + fmaxEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + fmaxEdit->setReadOnly(true); + fmaxEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + fmaxEdit->setDecimals(1); + fmaxEdit->setValue(recipe->fermentables.at(recipe->fermentables_row).f_max_in_batch); + + ferment_instock_changed(true); + + connect(fselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::ferment_select_changed); + connect(famountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_amount_changed); + connect(pctEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_pct_changed); + connect(faddedEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::ferment_added_changed); + connect(to100Edit, &QCheckBox::stateChanged, this, &EditRecipe::ferment_to100_changed); + connect(finstockEdit, &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(fselectEdit, nullptr, nullptr, nullptr); + disconnect(famountEdit, nullptr, nullptr, nullptr); + disconnect(pctEdit, nullptr, nullptr, nullptr); + disconnect(faddedEdit, nullptr, nullptr, nullptr); + disconnect(to100Edit, nullptr, nullptr, nullptr); + disconnect(finstockEdit, nullptr, nullptr, nullptr); + disconnect(buttonBox, nullptr, nullptr, nullptr); + + emit refreshAll(); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EditRecipeTab3.cpp Mon Apr 11 17:22:43 2022 +0200 @@ -0,0 +1,612 @@ +/** + * EditRecipe.cpp is part of bmsapp. + * + * Tab 3, hops + * + * 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/>. + */ + + + +bool EditRecipe::hop_sort_test(const Hops &D1, const Hops &D2) +{ + if (D1.h_useat > D2.h_useat) + return false; + if (D1.h_useat < D2.h_useat) + return true; + /* Same useat moments, test time. */ + if (D1.h_time < D2.h_time) + return false; + if (D1.h_time > D2.h_time) + return true; + /* Finally consider the amounts */ + return (D1.h_amount > D2.h_amount); +} + + +void EditRecipe::refreshHops() +{ + QString w; + QWidget* pWidget; + QHBoxLayout* pLayout; + QTableWidgetItem *item; + + qDebug() << "refreshHops" << recipe->hops.size(); + std::sort(recipe->hops.begin(), recipe->hops.end(), hop_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("Origin"), tr("Hop"), tr("Type"), tr("Form"), tr("Alpha"), tr("Use at"), tr("Time"), + tr("IBU"), tr("Amount"), tr("Delete"), tr("Edit") }); + + ui->hopsTable->setColumnCount(11); + ui->hopsTable->setColumnWidth(0, 150); /* Origin */ + ui->hopsTable->setColumnWidth(1, 225); /* Hop */ + ui->hopsTable->setColumnWidth(2, 75); /* Type */ + ui->hopsTable->setColumnWidth(3, 75); /* Form */ + ui->hopsTable->setColumnWidth(4, 75); /* Alpha% */ + ui->hopsTable->setColumnWidth(5, 75); /* Added */ + ui->hopsTable->setColumnWidth(6, 75); /* Time */ + ui->hopsTable->setColumnWidth(7, 60); /* IBU */ + ui->hopsTable->setColumnWidth(8, 75); /* Amount */ + ui->hopsTable->setColumnWidth(9, 80); /* Delete */ + ui->hopsTable->setColumnWidth(10, 80); /* Edit */ + ui->hopsTable->setHorizontalHeaderLabels(labels); + ui->hopsTable->verticalHeader()->hide(); + ui->hopsTable->setRowCount(recipe->hops.size()); + + for (int i = 0; i < recipe->hops.size(); i++) { + + ui->hopsTable->setItem(i, 0, new QTableWidgetItem(recipe->hops.at(i).h_origin)); + ui->hopsTable->setItem(i, 1, new QTableWidgetItem(recipe->hops.at(i).h_name)); + + item = new QTableWidgetItem(h_types[recipe->hops.at(i).h_type]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 2, item); + + item = new QTableWidgetItem(h_forms[recipe->hops.at(i).h_form]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 3, item); + + item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(i).h_alpha, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 4, item); + + item = new QTableWidgetItem(h_useat[recipe->hops.at(i).h_useat]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 5, item); + + if (recipe->hops.at(i).h_useat == 2 || recipe->hops.at(i).h_useat == 4) { // Boil or whirlpool + item = new QTableWidgetItem(QString("%1 min.").arg(recipe->hops.at(i).h_time, 1, 'f', 0, '0')); + } else if (recipe->hops.at(i).h_useat == 5) { // Dry-hop + item = new QTableWidgetItem(QString("%1 days.").arg(recipe->hops.at(i).h_time / 1440, 1, 'f', 0, '0')); + } else { + item = new QTableWidgetItem(QString("")); + } + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 6, item); + + double ibu = Utils::toIBU(recipe->hops.at(i).h_useat, recipe->hops.at(i).h_form, recipe->preboil_sg, recipe->batch_size, recipe->hops.at(i).h_amount, + recipe->hops.at(i).h_time, recipe->hops.at(i).h_alpha, recipe->ibu_method, 0, recipe->hops.at(i).h_time, 0); + item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 7, item); + + if (recipe->hops.at(i).h_amount < 1.0) { + item = new QTableWidgetItem(QString("%1 gr").arg(recipe->hops.at(i).h_amount * 1000.0, 2, 'f', 1, '0')); + } else { + item = new QTableWidgetItem(QString("%1 kg").arg(recipe->hops.at(i).h_amount, 4, 'f', 3, '0')); + } + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(i, 8, item); + + /* 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_deleteHopRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_dele); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->hopsTable->setCellWidget(i, 9, 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_editHopRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_edit); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->hopsTable->setCellWidget(i, 10, pWidget); + } + this->ignoreChanges = false; +} + + +void EditRecipe::on_Flavour_valueChanged(int value) +{ + if (value < 20) { + ui->hop_tasteShow->setStyleSheet(bar_20); + ui->hop_tasteShow->setFormat(tr("Very low")); + } else if (value < 40) { + ui->hop_tasteShow->setStyleSheet(bar_40); + ui->hop_tasteShow->setFormat(tr("Low")); + } else if (value < 60) { + ui->hop_tasteShow->setStyleSheet(bar_60); + ui->hop_tasteShow->setFormat(tr("Moderate")); + } else if (value < 80) { + ui->hop_tasteShow->setStyleSheet(bar_80); + ui->hop_tasteShow->setFormat(tr("High")); + } else { + ui->hop_tasteShow->setStyleSheet(bar_100); + ui->hop_tasteShow->setFormat(tr("Very high")); + } +} + + +void EditRecipe::on_Aroma_valueChanged(int value) +{ + if (value < 20) { + ui->hop_aromaShow->setStyleSheet(bar_20); + ui->hop_aromaShow->setFormat(tr("Very low")); + } else if (value < 40) { + ui->hop_aromaShow->setStyleSheet(bar_40); + ui->hop_aromaShow->setFormat(tr("Low")); + } else if (value < 60) { + ui->hop_aromaShow->setStyleSheet(bar_60); + ui->hop_aromaShow->setFormat(tr("Moderate")); + } else if (value < 80) { + ui->hop_aromaShow->setStyleSheet(bar_80); + ui->hop_aromaShow->setFormat(tr("High")); + } else { + ui->hop_aromaShow->setStyleSheet(bar_100); + ui->hop_aromaShow->setFormat(tr("Very high")); + } +} + + +void EditRecipe::calcIBUs() +{ + double hop_flavour = 0, hop_aroma = 0, ibus = 0; + + for (int i = 0; i < recipe->hops.size(); i++) { + + ibus += Utils::toIBU(recipe->hops.at(i).h_useat, recipe->hops.at(i).h_form, recipe->preboil_sg, recipe->batch_size, recipe->hops.at(i).h_amount, + recipe->hops.at(i).h_time, recipe->hops.at(i).h_alpha, recipe->ibu_method, 0, recipe->hops.at(i).h_time, 0); + hop_flavour += Utils::hopFlavourContribution(recipe->hops.at(i).h_time, recipe->batch_size, recipe->hops.at(i).h_useat, recipe->hops.at(i).h_amount); + hop_aroma += Utils::hopAromaContribution(recipe->hops.at(i).h_time, recipe->batch_size, recipe->hops.at(i).h_useat, recipe->hops.at(i).h_amount); + } + + hop_flavour = round(hop_flavour * 1000.0 / 5.0) / 10; + hop_aroma = round(hop_aroma * 1000.0 / 6.0) / 10; + if (hop_flavour > 100) + hop_flavour = 100; + if (hop_aroma > 100) + hop_aroma = 100; + qDebug() << "ibu" << recipe->est_ibu << ibus << "flavour" << hop_flavour << "aroma" << hop_aroma; + + recipe->est_ibu = ibus; + ui->est_ibuEdit->setValue(recipe->est_ibu); + ui->est_ibu2Edit->setValue(recipe->est_ibu); + ui->hop_tasteShow->setValue(hop_flavour); + ui->hop_aromaShow->setValue(hop_aroma); +} + + +void EditRecipe::on_addHopRow_clicked() +{ + Hops newh; + + qDebug() << "Add hop row"; + + for (int i = 0; i < recipe->hops.size(); i++) { + if (recipe->hops.at(i).h_amount == 0 && recipe->hops.at(i).h_alpha == 0) + return; // Add only one at a time. + } + + emit refreshAll(); +} + + +void EditRecipe::on_deleteHopRow_clicked() +{ + QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); + int row = pb->objectName().toInt(); + qDebug() << "Delete hop row" << row << recipe->hops.size(); + + if (recipe->hops.size() < 1) + return; + + int rc = QMessageBox::warning(this, tr("Delete hop"), tr("Delete %1").arg(recipe->hops.at(row).h_name), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (rc == QMessageBox::No) + return; + + +} + + +void EditRecipe::hop_amount_changed(double val) +{ + QTableWidgetItem *item; + + qDebug() << "hop_amount_changed()" << recipe->hops_row << val; + this->ignoreChanges = true; + + recipe->hops[recipe->hops_row].h_amount = val / 1000.0; + item = new QTableWidgetItem(QString("%1 gr").arg(val, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 8, item); + + double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, + recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, + recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); + + ibuEdit->setValue(ibu); + item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 7, item); + + this->ignoreChanges = false; + calcIBUs(); + is_changed(); +} + + +void EditRecipe::hop_time_changed(int val) +{ + QTableWidgetItem *item; + + qDebug() << "hop_time_changed()" << recipe->hops_row << val; + + this->ignoreChanges = true; + recipe->hops[recipe->hops_row].h_time = val; + + if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) { // Boil or whirlpool + item = new QTableWidgetItem(QString("%1 min.").arg(val, 1, 'f', 0, '0')); + } else if (recipe->hops.at(recipe->hops_row).h_useat == 5) { // Dry-hop + item = new QTableWidgetItem(QString("%1 days.").arg(val / 1440, 1, 'f', 0, '0')); + } else { + item = new QTableWidgetItem(QString("")); + } + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 6, item); + + double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, + recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, + recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); + + ibuEdit->setValue(ibu); + item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 7, item); + + this->ignoreChanges = false; + calcIBUs(); + is_changed(); +} + + +void EditRecipe::hop_select_changed(int val) +{ + QSqlQuery query; + bool instock = hinstockEdit->isChecked(); + QString w; + QTableWidgetItem *item; + + if (val < 1) + return; + + qDebug() << "hop_select_changed()" << recipe->fermentables_row << val << instock; + + /* + * Search the hop pointed by the index and instock flag. + */ + QString sql = "SELECT name,origin,alpha,beta,humulene,caryophyllene,cohumulone,myrcene,hsi,total_oil,type,form,cost FROM inventory_hops "; + if (instock) + sql.append("WHERE inventory > 0 "); + sql.append("ORDER BY origin,name"); + query.prepare(sql); + query.exec(); + query.first(); + for (int i = 0; i < (val - 1); i++) { + query.next(); + } + qDebug() << "found" << query.value(1).toString() << query.value(0).toString(); + + /* + * Replace the hop record contents + */ + this->ignoreChanges = true; + recipe->hops[recipe->hops_row].h_name = query.value(0).toString(); + recipe->hops[recipe->hops_row].h_origin = query.value(1).toString(); + recipe->hops[recipe->hops_row].h_alpha = query.value(2).toDouble(); + recipe->hops[recipe->hops_row].h_beta = query.value(3).toDouble(); + recipe->hops[recipe->hops_row].h_humulene = query.value(4).toDouble(); + recipe->hops[recipe->hops_row].h_caryophyllene = query.value(5).toDouble(); + recipe->hops[recipe->hops_row].h_cohumulone = query.value(6).toDouble(); + recipe->hops[recipe->hops_row].h_myrcene = query.value(7).toDouble(); + recipe->hops[recipe->hops_row].h_hsi = query.value(8).toDouble(); + recipe->hops[recipe->hops_row].h_total_oil = query.value(9).toDouble(); + recipe->hops[recipe->hops_row].h_type = query.value(10).toInt(); + recipe->hops[recipe->hops_row].h_form = query.value(11).toInt(); + recipe->hops[recipe->hops_row].h_cost = query.value(12).toDouble(); + + /* + * Update the visible fields + */ + hnameEdit->setText(recipe->hops.at(recipe->hops_row).h_name); + horiginEdit->setText(recipe->hops.at(recipe->hops_row).h_origin); + + double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, + recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, + recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); + ibuEdit->setValue(ibu); + + ui->hopsTable->setItem(recipe->hops_row, 0, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).h_origin)); + ui->hopsTable->setItem(recipe->hops_row, 1, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).h_name)); + + item = new QTableWidgetItem(h_types[recipe->hops.at(recipe->hops_row).h_type]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 2, item); + + item = new QTableWidgetItem(h_forms[recipe->hops.at(recipe->hops_row).h_form]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 3, item); + + item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(recipe->hops_row).h_alpha, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 4, item); + + item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 7, item); + + this->ignoreChanges = false; + calcIBUs(); + is_changed(); +} + + +void EditRecipe::hop_instock_changed(bool val) +{ + QSqlQuery query; + + qDebug() << "hop_instock_changed()" << recipe->hops_row << val; + + this->hselectEdit->setCurrentIndex(-1); + this->hselectEdit->clear(); + QString sql = "SELECT origin,name,alpha,inventory FROM inventory_hops "; + if (val) + sql.append("WHERE inventory > 0 "); + sql.append("ORDER BY origin,name"); + query.prepare(sql); + query.exec(); + query.first(); + this->hselectEdit->addItem(""); // Start with empty value + for (int i = 0; i < query.size(); i++) { + this->hselectEdit->addItem(query.value(0).toString()+" - "+query.value(1).toString()+" ("+query.value(2).toString()+"%) "+ + QString("%1 gr").arg(query.value(3).toDouble() * 1000.0, 2, 'f', 1, '0')); + query.next(); + } +} + + +void EditRecipe::hop_useat_changed(int val) +{ + qDebug() << "hop_useat_changed()" << recipe->hops_row << val; + + this->ignoreChanges = true; + recipe->hops[recipe->hops_row].h_useat = val; + QTableWidgetItem *item = new QTableWidgetItem(h_useat[val]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->hopsTable->setItem(recipe->hops_row, 5, item); + + if (val == 2 || val == 4) { // Boil or whirlpool + htimeLabel->setText(tr("Time in minutes:")); + htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time); + htimeEdit->setReadOnly(false); + } else if (val == 5) { // Dry-hop + htimeLabel->setText(tr("Time in days:")); + htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time / 1440); + htimeEdit->setReadOnly(false); + } else { + htimeLabel->setText(""); + htimeEdit->setValue(0); + htimeEdit->setReadOnly(true); + } + + this->ignoreChanges = false; + is_changed(); + emit refreshAll(); +} + + +void EditRecipe::on_editHopRow_clicked() +{ + QSqlQuery query; + + QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); + recipe->hops_row = pb->objectName().toInt(); + qDebug() << "Edit hop row" << recipe->hops_row; + Hops backup = recipe->hops.at(recipe->hops_row); + + QDialog* dialog = new QDialog(this); + dialog->resize(738, 260); + QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); + buttonBox->setObjectName(QString::fromUtf8("buttonBox")); + buttonBox->setGeometry(QRect(30, 210, 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 hop:")); + nameLabel->setGeometry(QRect(10, 10, 141, 20)); + nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + QLabel *originLabel = new QLabel(dialog); + originLabel->setObjectName(QString::fromUtf8("originLabel")); + originLabel->setText(tr("Origin:")); + originLabel->setGeometry(QRect(10, 40, 141, 20)); + originLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + QLabel *amountLabel = new QLabel(dialog); + amountLabel->setObjectName(QString::fromUtf8("amountLabel")); + amountLabel->setText(tr("Amount in gr:")); + amountLabel->setGeometry(QRect(10, 100, 141, 20)); + amountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + htimeLabel = new QLabel(dialog); + htimeLabel->setObjectName(QString::fromUtf8("htimeLabel")); + if (recipe->hops.at(recipe->hops_row).h_useat == 5) // Dry-hop + htimeLabel->setText(tr("Time in days:")); + else if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) // Boil or whirlpool + htimeLabel->setText(tr("Time in minutes:")); + else + htimeLabel->setText(""); + + htimeLabel->setGeometry(QRect(10, 130, 141, 20)); + htimeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + QLabel *useatLabel = new QLabel(dialog); + useatLabel->setObjectName(QString::fromUtf8("useatLabel")); + useatLabel->setText(tr("Use at:")); + useatLabel->setGeometry(QRect(10, 160, 141, 20)); + useatLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + QLabel *selectLabel = new QLabel(dialog); + selectLabel->setObjectName(QString::fromUtf8("selectLabel")); + selectLabel->setText(tr("Select hop:")); + 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 *ibuLabel = new QLabel(dialog); + ibuLabel->setObjectName(QString::fromUtf8("maxLabel")); + ibuLabel->setText(tr("Bitterness IBU:")); + ibuLabel->setGeometry(QRect(420, 130, 121, 20)); + ibuLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + + hselectEdit = new QComboBox(dialog); + hselectEdit->setObjectName(QString::fromUtf8("selectEdit")); + hselectEdit->setGeometry(QRect(160, 70, 371, 23)); + + hnameEdit = new QLineEdit(dialog); + hnameEdit->setObjectName(QString::fromUtf8("hnameEdit")); + hnameEdit->setText(recipe->hops.at(recipe->hops_row).h_name); + hnameEdit->setGeometry(QRect(160, 10, 511, 23)); + hnameEdit->setReadOnly(true); + horiginEdit = new QLineEdit(dialog); + horiginEdit->setObjectName(QString::fromUtf8("horiginEdit")); + horiginEdit->setText(recipe->hops.at(recipe->hops_row).h_origin); + horiginEdit->setGeometry(QRect(160, 40, 511, 23)); + horiginEdit->setReadOnly(true); + hamountEdit = new QDoubleSpinBox(dialog); + hamountEdit->setObjectName(QString::fromUtf8("hamountEdit")); + hamountEdit->setGeometry(QRect(160, 100, 121, 24)); + hamountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + hamountEdit->setAccelerated(true); + hamountEdit->setDecimals(1); + hamountEdit->setMaximum(1000000.0); + hamountEdit->setSingleStep(0.5); + hamountEdit->setValue(recipe->hops.at(recipe->hops_row).h_amount * 1000.0); + htimeEdit = new QSpinBox(dialog); + htimeEdit->setObjectName(QString::fromUtf8("htimeEdit")); + htimeEdit->setGeometry(QRect(160, 130, 121, 24)); + htimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + htimeEdit->setAccelerated(true); + htimeEdit->setMaximum(10000.0); + if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) { // Boil or whirlpool + htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time); + htimeEdit->setReadOnly(false); + } else if (recipe->hops.at(recipe->hops_row).h_useat == 5){ // Dry-hop + htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time / 1440); + htimeEdit->setReadOnly(false); + } else { + htimeEdit->setReadOnly(true); + } + useatEdit = new QComboBox(dialog); + useatEdit->setObjectName(QString::fromUtf8("useatEdit")); + useatEdit->setGeometry(QRect(160, 160, 161, 23)); + useatEdit->addItem(tr("Mash")); + useatEdit->addItem(tr("First wort")); + useatEdit->addItem(tr("Boil")); + useatEdit->addItem(tr("Aroma")); + useatEdit->addItem(tr("Whirlpool")); + useatEdit->addItem(tr("Dry hop")); + useatEdit->setCurrentIndex(recipe->hops.at(recipe->hops_row).h_useat); + + hinstockEdit = new QCheckBox(dialog); + hinstockEdit->setObjectName(QString::fromUtf8("hinstockEdit")); + hinstockEdit->setGeometry(QRect(655, 70, 85, 21)); + hinstockEdit->setChecked(true); + + ibuEdit = new QDoubleSpinBox(dialog); + ibuEdit->setObjectName(QString::fromUtf8("ibuEdit")); + ibuEdit->setGeometry(QRect(550, 130, 121, 24)); + ibuEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ibuEdit->setReadOnly(true); + ibuEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + ibuEdit->setDecimals(1); + double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, + recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, + recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); + ibuEdit->setValue(ibu); + + hop_instock_changed(true); + + connect(hselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_select_changed); + connect(hamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::hop_amount_changed); + connect(htimeEdit, QOverload<int>::of(&QSpinBox::valueChanged), this, &EditRecipe::hop_time_changed); + connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_useat_changed); + connect(hinstockEdit, &QCheckBox::stateChanged, this, &EditRecipe::hop_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->hops[recipe->hops_row] = backup; + } else { + /* Clear time if hop is not used for boil, whirlpool or dry-hop. */ + if (! (recipe->hops.at(recipe->hops_row).h_useat == 2 || + recipe->hops.at(recipe->hops_row).h_useat == 4 || + recipe->hops.at(recipe->hops_row).h_useat == 5)) { + if (recipe->hops.at(recipe->hops_row).h_time) { + recipe->hops[recipe->hops_row].h_time = 0; + is_changed(); + } + } + } + + disconnect(hselectEdit, nullptr, nullptr, nullptr); + disconnect(hamountEdit, nullptr, nullptr, nullptr); + disconnect(htimeEdit, nullptr, nullptr, nullptr); + disconnect(useatEdit, nullptr, nullptr, nullptr); + disconnect(hinstockEdit, nullptr, nullptr, nullptr); + disconnect(buttonBox, nullptr, nullptr, nullptr); + + emit refreshAll(); +} + +