Sat, 11 Feb 2023 15:48:02 +0100
Monitor iSpindels: use global variables instead of repeated expensive MySQL calls. Use the yeast temperature ranges for the colors on the thermometer scale. Don't show SVG and ABV if the OG is not yet known. Turn statusfield red if offline. Extra mon_ispindles fields yeast_lo and yeast_hi. Need at least bmsd version 0.3.42. If a websocket message is received that cannot be parsed, show the whole received message.
/** * EditProduct.cpp is part of bmsapp. * * Tab 3, fermentables * * 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 EditProduct::ferment_sort_test(const Fermentables &D1, const Fermentables &D2) { if (D1.added > D2.added) return false; if (D1.added < D2.added) return true; return (D1.amount >= D2.amount) && (D1.color < D2.color); } void EditProduct::to100Fermentables(int row) { if (product->fermentables.at(row).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, 10, pWidget); } else { ui->fermentablesTable->removeCellWidget(row, 10); } } bool EditProduct::block_fermentable(int stage, int added) { if (stage > PROD_STAGE_PACKAGE) return true; if (stage > PROD_STAGE_TERTIARY && added < FERMENTABLE_ADDED_BOTTLE) return true; if (stage > PROD_STAGE_PRIMARY && added < FERMENTABLE_ADDED_LAGERING) return true; if (stage > PROD_STAGE_BREW && added < FERMENTABLE_ADDED_FERMENTATION) return true; return false; } void EditProduct::refreshFermentables() { QString w; QWidget* pWidget; QHBoxLayout* pLayout; QTableWidgetItem *item; std::sort(product->fermentables.begin(), product->fermentables.end(), ferment_sort_test); const QStringList labels({tr("Supplier"), tr("Fermentable"), tr("EBC"), tr("Type"), tr("Graintype"), tr("When"), tr("Yield"), tr("Amount"), tr("Stock"), tr("Procent"), tr("100%"), tr("Delete"), tr("Edit") }); ui->fermentablesTable->setColumnCount(13); ui->fermentablesTable->setColumnWidth(0, 140); /* Supplier */ ui->fermentablesTable->setColumnWidth(1, 220); /* Fermentable */ ui->fermentablesTable->setColumnWidth(2, 45); /* Color */ ui->fermentablesTable->setColumnWidth(3, 75); /* Type */ ui->fermentablesTable->setColumnWidth(4, 75); /* Graintype */ ui->fermentablesTable->setColumnWidth(5, 77); /* Added */ ui->fermentablesTable->setColumnWidth(6, 60); /* Yield */ ui->fermentablesTable->setColumnWidth(7, 80); /* Amount */ ui->fermentablesTable->setColumnWidth(8, 80); /* Stock */ ui->fermentablesTable->setColumnWidth(9, 60); /* Procent */ ui->fermentablesTable->setColumnWidth(10, 50); /* 100% */ ui->fermentablesTable->setColumnWidth(11, 80); /* Delete */ ui->fermentablesTable->setColumnWidth(12, 80); /* Edit */ ui->fermentablesTable->setHorizontalHeaderLabels(labels); ui->fermentablesTable->verticalHeader()->hide(); ui->fermentablesTable->setRowCount(product->fermentables.size()); for (int i = 0; i < product->fermentables.size(); i++) { ui->fermentablesTable->setItem(i, 0, new QTableWidgetItem(product->fermentables.at(i).supplier)); ui->fermentablesTable->setItem(i, 1, new QTableWidgetItem(product->fermentables.at(i).name)); w = QString("%1").arg(product->fermentables.at(i).color, 1, 'f', 0, '0'); item = new QTableWidgetItem(w); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 2, item); item = new QTableWidgetItem(QCoreApplication::translate("FermentableType", g_fermentable_types[product->fermentables.at(i).type])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 3, item); item = new QTableWidgetItem(QCoreApplication::translate("FermentableGraintype", g_fermentable_graintypes[product->fermentables.at(i).graintype])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 4, item); item = new QTableWidgetItem(QCoreApplication::translate("FermentableAdded", g_fermentable_added[product->fermentables.at(i).added])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 5, item); item = new QTableWidgetItem(QString("%1%").arg(product->fermentables.at(i).yield, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 6, item); item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables.at(i).amount, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(i, 7, item); if (block_fermentable(product->stage, product->fermentables.at(i).added)) { item = new QTableWidgetItem(QString("")); } else { item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables.at(i).inventory, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (product->fermentables.at(i).inventory < product->fermentables.at(i).amount) item->setForeground(QBrush(QColor(Qt::red))); } ui->fermentablesTable->setItem(i, 8, item); if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) { item = new QTableWidgetItem(QString("%1%").arg(product->fermentables.at(i).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, 9, item); to100Fermentables(i); /* Add the Delete and Edit row buttons if allowed. */ if (product->fermentables.at(i).added >= FERMENTABLE_ADDED_BOTTLE) { item = new QTableWidgetItem(""); item->setToolTip(tr("Edit this from the package tab")); ui->fermentablesTable->setItem(i, 11, item); item = new QTableWidgetItem(""); item->setToolTip(tr("Edit this from the package tab")); ui->fermentablesTable->setItem(i, 12, item); } else if (block_fermentable(product->stage, product->fermentables.at(i).added)) { item = new QTableWidgetItem(""); item->setToolTip(tr("Fermentable already used")); ui->fermentablesTable->setItem(i, 11, item); item = new QTableWidgetItem(""); item->setToolTip(tr("Fermentable already used")); ui->fermentablesTable->setItem(i, 12, item); } else { 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(deleteFermentRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_dele); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->fermentablesTable->setCellWidget(i, 11, 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(editFermentRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_edit); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->fermentablesTable->setCellWidget(i, 12, pWidget); } } } void EditProduct::calcFermentables() { int i; double psugar = 0, pcara = 0, d, s = 0, x, cw, 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 product lintner 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 double bv = 0.925; // Beer loss efficiency double sr = 0.95; // Mash and sparge efficiency qDebug() << "calcFermentables()"; /* * Get average mashtemp and mashtime from the Mash schedule. * It is possible that the schedule is not (yet) present. */ if (product->mashs.size() > 0) { for (i = 0; i < product->mashs.size(); i++) { if (product->mashs.at(i).step_type == 0) // Infusion mashinfuse += product->mashs.at(i).step_infuse_amount; if (product->mashs.at(i).step_temp <= 75 && product->mashs.at(i).step_temp >= 60) { // Ignore mashout and low temperatures. double timem = product->mashs.at(i).step_time; if (i > 0) timem += product->mashs.at(i).ramp_time; mashtime += timem; mashtemp += timem * product->mashs.at(i).step_temp; } } mashtemp = mashtemp / mashtime; mvol = mashinfuse; } /* * Pellets 2.67 ml/gram (plugs, cryo). * Leaf 6.01 ml/gram */ product->boil_absorb = product->ferment_absorb = 0; if (product->hops.size() > 0) { for (i = 0; i < product->hops.size(); i++) { if (product->hops.at(i).useat == HOP_USEAT_FWH || product->hops.at(i).useat == HOP_USEAT_BOIL || product->hops.at(i).useat == HOP_USEAT_AROMA || product->hops.at(i).useat == HOP_USEAT_WHIRLPOOL) { if (product->hops.at(i).form == HOP_FORMS_PELLET) { product->boil_absorb += my_ha_pellet * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_PLUG) { product->boil_absorb += my_ha_plug * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_LEAF) { product->boil_absorb += my_ha_leaf * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_LEAF_WET) { product->boil_absorb += my_ha_wethop * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_CRYO) { product->boil_absorb += my_ha_t45 * product->hops.at(i).amount; } } else if (product->hops.at(i).useat == HOP_USEAT_DRY_HOP) { if (product->hops.at(i).form == HOP_FORMS_PELLET) { product->ferment_absorb += my_ha_pellet * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_PLUG) { product->ferment_absorb += my_ha_plug * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_LEAF) { product->ferment_absorb += my_ha_leaf * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_LEAF_WET) { product->ferment_absorb += my_ha_wethop * product->hops.at(i).amount; } else if (product->hops.at(i).form == HOP_FORMS_CRYO) { product->ferment_absorb += my_ha_t45 * product->hops.at(i).amount; } } } } ui->boil_absorpShow->setValue(product->boil_absorb); ui->ferment_absorpShow->setValue(product->ferment_absorb); const QSignalBlocker blocker1(ui->est_ogEdit); const QSignalBlocker blocker2(ui->est_og2Edit); product->fermentables_use100 = false; if (product->fermentables.size() < 1) { qDebug() << " no fermentables, return."; product->est_og = 0.980; ui->est_ogEdit->setValue(0.980); ui->est_og2Edit->setValue(0.980); ui->est_og4Edit->setValue(0.980); ui->est_ogShow->setValue(0.980); product->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); product->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); product->est_abv = 0; ui->calEdit->setValue(0); product->mashs_kg = 0; ui->mash_kgEdit->setValue(0); return; } product->fermentables_ok = true; product->mashs_kg = 0; for (i = 0; i < product->fermentables.size(); i++) { if (product->fermentables.at(i).adjust_to_total_100 && product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) product->fermentables_use100 = true; if (product->fermentables.at(i).type == FERMENTABLE_TYPE_SUGAR && product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) psugar += product->fermentables.at(i).percentage; if (product->fermentables.at(i).graintype == FERMENTABLE_GRAINTYPE_CRYSTAL && product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) pcara += product->fermentables.at(i).percentage; d = product->fermentables.at(i).amount * (product->fermentables.at(i).yield / 100) * (1 - product->fermentables.at(i).moisture / 100); if (product->fermentables.at(i).added == FERMENTABLE_ADDED_MASH) { if (mvol > 0) { // If mash volume is known mvol += product->fermentables.at(i).amount * product->fermentables.at(i).moisture / 100; s += d; } d = product->efficiency / 100 * d; sugarsm += d; product->mashs_kg += product->fermentables.at(i).amount; } if (product->fermentables.at(i).added == FERMENTABLE_ADDED_MASH || product->fermentables.at(i).added == FERMENTABLE_ADDED_BOIL) sugarsf += d; if (product->fermentables.at(i).added == FERMENTABLE_ADDED_FERMENTATION || product->fermentables.at(i).added == FERMENTABLE_ADDED_LAGERING) { x = (product->fermentables.at(i).yield / 100) * (1 - product->fermentables.at(i).moisture / 100); addedS += product->fermentables.at(i).amount * x; addedmass += product->fermentables.at(i).amount; vol += (x * sugardensity + (1 - x) * 1) * product->fermentables.at(i).amount; } if (product->fermentables.at(i).added == FERMENTABLE_ADDED_MASH && (product->fermentables.at(i).type == FERMENTABLE_TYPE_GRAIN || product->fermentables.at(i).type == FERMENTABLE_TYPE_ADJUCT)) { lintner += product->fermentables.at(i).diastatic_power * product->fermentables.at(i).amount; } if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) { colort += product->fermentables.at(i).amount * Utils::ebc_to_srm(product->fermentables.at(i).color); colorh += product->fermentables.at(i).amount * product->fermentables.at(i).color * Utils::get_kt(product->fermentables.at(i).color); colorn += (product->fermentables.at(i).percentage / 100) * product->fermentables.at(i).color; // For 8.6 Pt wort. } /* Check supplies */ if ((((product->inventory_reduced <= PROD_STAGE_BREW) && (product->fermentables.at(i).added <= FERMENTABLE_ADDED_BOIL)) || ((product->inventory_reduced <= PROD_STAGE_PRIMARY) && (product->fermentables.at(i).added == FERMENTABLE_ADDED_FERMENTATION)) || ((product->inventory_reduced <= PROD_STAGE_TERTIARY) && (product->fermentables.at(i).added == FERMENTABLE_ADDED_LAGERING)) || ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->fermentables.at(i).added == FERMENTABLE_ADDED_BOTTLE)) || ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->fermentables.at(i).added == FERMENTABLE_ADDED_KEGS))) && product->fermentables.at(i).inventory < product->fermentables.at(i).amount) { product->fermentables_ok = false; } } #ifdef DEBUG_FERMENTABLES qDebug() << " adjust to 100" << product->fermentables_use100; qDebug() << " supplies" << product->fermentables_ok; qDebug() << " colort" << colort << "colorh" << colorh << "colorn" << colorn; qDebug() << " psugar" << psugar << "pcara" << pcara << "mvol" << mvol; qDebug() << " sugarsf" << sugarsf << "sugarsm" << sugarsm; #endif double v = s / sugardensity + mvol; s = 1000 * s / (v * 10); //deg. Plato product->est_mash_sg = Utils::plato_to_sg(s); ui->brew_mashsgShow->setValue(product->est_mash_sg); /* Estimate total recipe OG */ product->est_og = Utils::estimate_sg(sugarsf + addedS, product->batch_size); #ifdef DEBUG_FERMENTABLES qDebug() << " OG" << ui->est_ogEdit->value() << product->est_og; #endif if (product->stage > PROD_STAGE_BREW) { ui->est_ogLabel->setText(tr("Final OG:")); ui->est_ogEdit->setValue(product->og); ui->est_ogShow->setValue(product->og); } else { ui->est_ogEdit->setValue(product->est_og); ui->est_ogShow->setValue(product->est_og); } ui->est_og2Edit->setValue(product->est_og); ui->est_og4Edit->setValue(product->est_og); /* Estimate SG in kettle after boil */ product->est_og3 = Utils::estimate_sg(sugarsf, product->batch_size); ui->brew_aboilsgShow->setValue(product->est_og3); /* Estimate SG in kettle before boil */ product->preboil_sg = Utils::estimate_sg(sugarsm, product->boil_size); ui->brew_preboilsgShow->setValue(product->preboil_sg); #ifdef DEBUG_FERMENTABLES qDebug() << " preboil SG" << product->preboil_sg; #endif /* * Recalculate volumes */ double aboil_volume = product->batch_size; if (product->brew_aboil_volume > 0) aboil_volume = product->brew_aboil_volume / 1.04; // Volume @ 20 degrees. if (product->brew_fermenter_tcloss == 0) { product->brew_fermenter_tcloss = product->eq_trub_loss; ui->brew_trublossEdit->setValue(product->brew_fermenter_tcloss); } product->brew_fermenter_volume = aboil_volume - product->brew_fermenter_tcloss + product->brew_fermenter_extrawater; ui->brew_tofermentEdit->setValue(product->brew_fermenter_volume); /* Calculate SG in fermenter */ double ogx = product->brew_aboil_sg; if (ogx < 1.002) ogx = product->est_og3; double topw = product->brew_fermenter_extrawater; if (product->brew_fermenter_volume > 0) { double sug = Utils::sg_to_plato(ogx) * product->brew_fermenter_volume * ogx / 100; //kg of sugar in sug += addedS; //kg if ((product->brew_fermenter_volume * ogx + addedmass) > 0) { double pt = 100 * sug / (product->brew_fermenter_volume * ogx + addedmass + topw); product->og = product->brew_fermenter_sg = round(Utils::plato_to_sg(pt) * 10000) / 10000.0; ui->brew_fermentsgShow->setValue(product->brew_fermenter_sg); // color if (product->color_method == 4) { // Naudts product->brew_fermenter_color = round(((pt / 8.6) * colorn) + (product->boil_time / 60)); } else if (product->color_method == 3) { // Hans Halberstadt product->brew_fermenter_color = round((4.46 * bv * sr) / (aboil_volume + topw) * colorh); } else { cw = colort / (aboil_volume + topw) * 8.34436; product->brew_fermenter_color = Utils::kw_to_ebc(product->color_method, cw); } ui->brew_fermentcolorShow->setValue(product->brew_fermenter_color); ui->brew_fermentcolorShow->setStyleSheet(Utils::ebc_to_style(product->brew_fermenter_color)); } /* * After all calculations including hop absorption, correct the real volume in the fermenter. */ if ((product->boil_absorb > 0) && (product->boil_absorb < product->brew_fermenter_volume)) { product->brew_fermenter_volume -= product->boil_absorb; ui->brew_tofermentEdit->setValue(product->brew_fermenter_volume); } /* * Correct maximum package volume if needed. */ ui->pack_volumeEdit->setMaximum(product->brew_fermenter_volume); if (product->package_volume > product->brew_fermenter_volume) { product->package_volume = product->brew_fermenter_volume; ui->pack_volumeEdit->setValue(product->package_volume); } } else { // Negative volume product->brew_fermenter_sg = product->brew_fermenter_color = 0; ui->brew_fermentsgShow->setValue(0); ui->brew_fermentcolorShow->setStyleSheet(0); ui->brew_fermentcolorShow->setValue(0); } /* * Color of the wort */ if (product->color_method == 4) { // Naudts color = round(((Utils::sg_to_plato(product->est_og) / 8.6) * colorn) + (product->boil_time / 60)); } else if (product->color_method == 3) { // Hans Halberstadt color = round((4.46 * bv * sr) / product->batch_size * colorh); } else { cw = colort / product->batch_size * 8.34436; color = Utils::kw_to_ebc(product->color_method, cw); #ifdef DEBUG_FERMENTABLES qDebug() << " oud EBC" << color << "new EBC" << Utils::kw_to_newebc(product->color_method, cw) << "SRM" << Utils::kw_to_srm(product->color_method, cw); #endif } #ifdef DEBUG_FERMENTABLES qDebug() << " color" << ui->est_colorEdit->value() << color << product->est_color; #endif product->est_color = color; ui->est_color2Edit->setValue(color); ui->est_color2Edit->setStyleSheet(Utils::ebc_to_style(color)); if (product->stage > PROD_STAGE_BREW) { ui->est_colorLabel->setText(tr("Final EBC:")); ui->est_colorEdit->setValue(product->brew_fermenter_color); ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(product->brew_fermenter_color)); ui->est_colorShow->setValue(product->brew_fermenter_color); ui->pack_finalcolorLabel->setText(tr("Final EBC:")); } else { ui->est_colorEdit->setValue(color); ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(color)); ui->est_colorShow->setValue(color); } if (round(product->mashs_kg / product->eq_mash_max * 100) > 120) ui->perc_mashShow->setValue(120); else ui->perc_mashShow->setValue(round(product->mashs_kg / product->eq_mash_max * 100)); ui->mash_kgEdit->setValue(product->mashs_kg); ui->perc_sugarsShow->setValue(round(psugar)); ui->perc_caraShow->setValue(round(pcara)); if (product->mashs_kg > 0) { #ifdef DEBUG_FERMENTABLES qDebug() << " lintner" << lintner << " mashkg" << product->mashs_kg << "final" << round(lintner / product->mashs_kg); #endif ui->lintnerShow->setValue(round(lintner / product->mashs_kg)); } else { #ifdef DEBUG_FERMENTABLES qDebug() << " lintner N/A"; #endif ui->lintnerShow->setValue(0); } /* * Calculate the apparant attenuation. */ double svg = 0; double initcells = 0; bool sta1 = false; product->yeasts_ok = true; if (product->yeasts.size() > 0) { for (i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).use == 0) { // Used in primary if (product->yeasts.at(i).attenuation > svg) svg = product->yeasts.at(i).attenuation; // Take the highest if multiple yeasts. if (product->yeasts.at(i).sta1) sta1 = true; } if (product->yeasts.at(i).form == 0) initcells += (product->yeasts.at(i).cells / 1000000000) * product->yeasts.at(i).amount * (product->starter_viability / 100); else initcells += (product->yeasts.at(i).cells / 1000000) * product->yeasts.at(i).amount * (product->starter_viability / 100); // TODO: brett or others in secondary. if ((((product->inventory_reduced <= PROD_STAGE_PRIMARY) && (product->yeasts.at(i).use == 0)) || // Primary ((product->inventory_reduced <= PROD_STAGE_SECONDARY) && (product->yeasts.at(i).use == 1)) || // Secondary ((product->inventory_reduced <= PROD_STAGE_TERTIARY) && (product->yeasts.at(i).use == 2)) || // Tertiary ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->yeasts.at(i).use == 3))) && // Bottle (product->yeasts.at(i).inventory < product->yeasts.at(i).amount)) { product->yeasts_ok = false; } } #ifdef DEBUG_FERMENTABLES qDebug() << " est SVG" << svg; #endif } if (svg == 0) svg = 77.0; ui->est_svgEdit->setValue(svg); if (product->mashs_kg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0) product->est_fg = Utils::estimate_fg(psugar, pcara, mashinfuse / product->mashs_kg, mashtime, mashtemp, svg, product->est_og, sta1); else product->est_fg = Utils::estimate_fg(psugar, pcara, 0, 0, 0, svg, product->est_og, sta1); qDebug() << " est FG" << ui->est_fgEdit->value() << product->est_fg; product->est_abv = Utils::abvol(product->est_og, product->est_fg); #ifdef DEBUG_FERMENTABLES qDebug() << " est ABV" << ui->est_abvEdit->value() << product->est_abv; #endif if (product->stage > PROD_STAGE_TERTIARY) { ui->est_fgLabel->setText(tr("Final FG:")); ui->est_fgEdit->setValue(product->fg); ui->est_fgShow->setValue(product->fg); ui->est_abvLabel->setText(tr("Final ABV:")); double abv = Utils::abvol(product->og, product->fg); ui->est_abvEdit->setValue(abv); ui->est_abvShow->setValue(abv); } else { ui->est_fgEdit->setValue(product->est_fg); ui->est_fgShow->setValue(product->est_fg); ui->est_abvEdit->setValue(product->est_abv); ui->est_abvShow->setValue(product->est_abv); } ui->est_fg3Edit->setValue(product->est_fg); ui->est_abv2Edit->setValue(product->est_abv); /* * Calculate kilocalories/liter. Formula from brouwhulp. * Take the alcohol and sugar parts and then combine. */ double alc, sug; if (product->stage > PROD_STAGE_TERTIARY) { alc = 1881.22 * product->fg * (product->og - product->fg) / (1.775 - product->og); sug = 3550 * product->fg * (0.1808 * product->og + 0.8192 * product->fg - 1.0004); } else { alc = 1881.22 * product->est_fg * (product->est_og - product->est_fg) / (1.775 - product->est_og); sug = 3550 * product->est_fg * (0.1808 * product->est_og + 0.8192 * product->est_fg - 1.0004); } ui->calEdit->setValue(round((alc + sug) / (12 * 0.0295735296))); } void EditProduct::calcFermentablesFromOG(double og) { qDebug() << "calcFermentablesFromOG" << og; int i; double totmass = 0; double tot = 0; double d, amount; double efficiency = product->efficiency; double sug = Utils::sg_to_plato(og) * product->batch_size * og / 100.0; // total amount of sugars in kg. for (i = 0; i < product->fermentables.size(); i++) { if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) { d = product->fermentables.at(i).percentage / 100.0 * (product->fermentables.at(i).yield / 100.0) * (1 - product->fermentables.at(i).moisture / 100.0); if (product->fermentables.at(i).added == FERMENTABLE_ADDED_MASH) d = efficiency / 100.0 * d; tot += d; } } if (tot) totmass = round((sug / tot) * 1000.0) / 1000.0; if (totmass) { for (i = 0; i < product->fermentables.size(); i++) { amount = round(product->fermentables.at(i).percentage * 10.0 * totmass) / 1000.0; product->fermentables[i].amount = amount; } } } void EditProduct::ferment_perc_mash_valueChanged(int value) { if (value < 90) { ui->perc_mashShow->setStyleSheet(bar_green); } else { double s1 = 90.0 / value; if (value < 100) { ui->perc_mashShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, " "stop: 0 green, stop: %1 green, stop: %2 orange, stop: 1 orange" ");}").arg(s1 - 0.00001).arg(s1)); } else { double s2 = 100.0 / value; ui->perc_mashShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, " "stop: 0 green, stop: %1 green, stop: %2 orange, stop: %3 orange, stop: %4 red, stop: 1 red" ");}").arg(s1 - 0.00003).arg(s1 - 0.00002).arg(s2 - 0.00001).arg(s2)); } } } void EditProduct::ferment_perc_sugars_valueChanged(int value) { if (value < 20) ui->perc_sugarsShow->setStyleSheet(bar_green); else { double s1 = 20.0 / value; ui->perc_sugarsShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, " "stop: 0 green, stop: %1 green, stop: %2 red, stop: 1 red);}").arg(s1 - 0.00001).arg(s1)); } } void EditProduct::ferment_perc_cara_valueChanged(int value) { if (value < 25) ui->perc_caraShow->setStyleSheet(bar_green); else { double s1 = 25.0 / value; ui->perc_caraShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, " "stop: 0 green, stop: %1 green, stop: %2 red, stop: 1 red);}").arg(s1 - 0.00001).arg(s1)); } } void EditProduct::ferment_lintner_valueChanged(int value) { /* * Calculate the color stop positions */ if (value < 30) { ui->lintnerShow->setStyleSheet(bar_red); } else { double s1 = 30.0 / value; if (value < 40) { ui->lintnerShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, " "stop: 0 red, stop: %1 red, stop: %2 orange, stop: 1 orange);}").arg(s1 - 0.00001).arg(s1)); } else { double s2 = 40.0 / value; ui->lintnerShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, " "stop: 0 red, stop: %1 red, stop: %2 orange, stop: %3 orange, stop: %4 green, stop: 1 green" ");}").arg(s1 - 0.00003).arg(s1 - 0.00002).arg(s2 - 0.00001).arg(s2)); } } } void EditProduct::addFermentRow_clicked() { Fermentables newf; qDebug() << "Add fermentable row"; for (int i = 0; i < product->fermentables.size(); i++) { if (product->fermentables.at(i).amount == 0 && product->fermentables.at(i).color == 0) return; // Add only one at a time. } newf.name = "Select one"; newf.origin = ""; newf.supplier = ""; newf.amount = 0; newf.cost = 0; newf.type = FERMENTABLE_TYPE_GRAIN; newf.yield = 0; newf.color = 0; newf.coarse_fine_diff = 0; newf.moisture = 0; newf.diastatic_power = 0; newf.protein = 0; newf.dissolved_protein = 0; newf.max_in_batch = 100; newf.graintype = FERMENTABLE_GRAINTYPE_BASE; newf.added = FERMENTABLE_ADDED_MASH; newf.recommend_mash = true; newf.add_after_boil = false; newf.adjust_to_total_100 = false; newf.percentage = 0; newf.di_ph = 0; newf.acid_to_ph_57 = 0; product->fermentables.append(newf); emit refreshAll(); } void EditProduct::deleteFermentRow_clicked() { if (product->locked) return; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); int row = pb->objectName().toInt(); if (product->fermentables.size() < 1) return; int rc = QMessageBox::warning(this, tr("Delete fermentable"), tr("Delete %1").arg(product->fermentables.at(row).name), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (rc == QMessageBox::No) return; product->fermentables.removeAt(row); /* * Recalculate the percentages on the rows left. */ double total = 0; for (int i = 0; i < product->fermentables.size(); i++) if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).amount; for (int i = 0; i < product->fermentables.size(); i++) if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) product->fermentables[i].percentage = product->fermentables.at(i).amount / total * 100; is_changed(); emit refreshAll(); } void EditProduct::ferment_amount_changed(double val) { QTableWidgetItem *item; double total = 0, perc; if (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).added < FERMENTABLE_ADDED_BOTTLE) return; qDebug() << "ferment_amount_changed()" << product->fermentables_row << val; product->fermentables[product->fermentables_row].amount = val; item = new QTableWidgetItem(QString("%1 Kg").arg(val, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 7, item); for (int i = 0; i < product->fermentables.size(); i++) if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).amount; /* * Recalculate the percentages */ for (int i = 0; i < product->fermentables.size(); i++) { if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) { perc = product->fermentables.at(i).amount / total * 100; product->fermentables[i].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 == product->fermentables_row) this->pctEdit->setValue(perc); } } is_changed(); } void EditProduct::ferment_pct_changed(double val) { QTableWidgetItem *item; double total = 0, row100 = -1; if (! product->fermentables_use100) return; qDebug() << "ferment_pct_changed()" << product->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 < product->fermentables.size(); i++) { if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).amount; if (product->fermentables.at(i).adjust_to_total_100) row100 = i; } double oldperc = product->fermentables.at(product->fermentables_row).percentage; double diffp = val - oldperc; double diffw = (diffp / 100) * total; #ifdef DEBUG_FERMENTABLES qDebug() << "row100" << row100 << "total" << total << "diff kg" << diffw << "diff %" << diffp; #endif product->fermentables[product->fermentables_row].percentage += diffp; product->fermentables[product->fermentables_row].amount += diffw; product->fermentables[row100].percentage -= diffp; product->fermentables[row100].amount -= diffw; item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables[product->fermentables_row].amount, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 7, item); this->famountEdit->setValue(product->fermentables[product->fermentables_row].amount); item = new QTableWidgetItem(QString("%1%").arg(product->fermentables[product->fermentables_row].percentage, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 8, item); item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables[row100].amount, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(row100, 7, item); item = new QTableWidgetItem(QString("%1%").arg(product->fermentables[row100].percentage, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(row100, 8, item); is_changed(); } void EditProduct::ferment_to100_changed(bool val) { qDebug() << "ferment_to100_changed()" << product->fermentables_row << val << product->fermentables_use100; if (product->fermentables.at(product->fermentables_row).added >= FERMENTABLE_ADDED_BOTTLE) { const QSignalBlocker blocker1(to100Edit); product->fermentables[product->fermentables_row].adjust_to_total_100 = false; to100Edit->setChecked(false); return; } /* * 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 (! product->fermentables_use100 && val) { /* Scenario 1. */ product->fermentables_use100 = true; product->fermentables[product->fermentables_row].adjust_to_total_100 = true; pctEdit->setReadOnly(false); famountEdit->setReadOnly(true); } else if (product->fermentables_use100 && product->fermentables[product->fermentables_row].adjust_to_total_100 && ! val) { /* Scenario 2. */ product->fermentables[product->fermentables_row].adjust_to_total_100 = false; product->fermentables_use100 = false; pctEdit->setReadOnly(true); famountEdit->setReadOnly(false); } else if (product->fermentables_use100 && ! product->fermentables[product->fermentables_row].adjust_to_total_100 && val) { /* Scenario 3. */ for (int i = 0; i < product->fermentables.size(); i++) { product->fermentables[i].adjust_to_total_100 = false; } product->fermentables[product->fermentables_row].adjust_to_total_100 = true; } else { qWarning() << "ferment_to100_changed(" << val << ") bug triggered"; return; } for (int i = 0; i < product->fermentables.size(); i++) { to100Fermentables(i); } is_changed(); } void EditProduct::ferment_select_changed(int val) { QSqlQuery query; bool instock = finstockEdit->isChecked(); QString w; QTableWidgetItem *item; if (val < 1) return; qDebug() << "ferment_select_changed()" << product->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,inventory 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(); } /* * Replace the fermentable record contents */ product->fermentables[product->fermentables_row].name = query.value(0).toString(); product->fermentables[product->fermentables_row].origin = query.value(1).toString(); product->fermentables[product->fermentables_row].supplier = query.value(2).toString(); product->fermentables[product->fermentables_row].cost = query.value(3).toDouble(); product->fermentables[product->fermentables_row].type = query.value(4).toInt(); product->fermentables[product->fermentables_row].yield = query.value(5).toDouble(); product->fermentables[product->fermentables_row].color = query.value(6).toDouble(); product->fermentables[product->fermentables_row].coarse_fine_diff = query.value(7).toDouble(); product->fermentables[product->fermentables_row].moisture = query.value(8).toDouble(); product->fermentables[product->fermentables_row].diastatic_power = query.value(9).toDouble(); product->fermentables[product->fermentables_row].protein = query.value(10).toDouble(); product->fermentables[product->fermentables_row].dissolved_protein = query.value(11).toDouble(); product->fermentables[product->fermentables_row].max_in_batch = query.value(12).toDouble(); product->fermentables[product->fermentables_row].graintype = query.value(13).toInt(); product->fermentables[product->fermentables_row].recommend_mash = query.value(14).toInt() ? true:false; product->fermentables[product->fermentables_row].add_after_boil = query.value(15).toInt() ? true:false; product->fermentables[product->fermentables_row].di_ph = query.value(16).toDouble(); product->fermentables[product->fermentables_row].acid_to_ph_57 = query.value(17).toDouble(); product->fermentables[product->fermentables_row].inventory = query.value(18).toDouble(); /* * Update the visible fields */ fnameEdit->setText(product->fermentables.at(product->fermentables_row).name); fsupplierEdit->setText(product->fermentables.at(product->fermentables_row).supplier); fmaxEdit->setValue(product->fermentables.at(product->fermentables_row).max_in_batch); ui->fermentablesTable->setItem(product->fermentables_row, 0, new QTableWidgetItem(product->fermentables.at(product->fermentables_row).supplier)); ui->fermentablesTable->setItem(product->fermentables_row, 1, new QTableWidgetItem(product->fermentables.at(product->fermentables_row).name)); w = QString("%1").arg(product->fermentables.at(product->fermentables_row).color, 1, 'f', 0, '0'); item = new QTableWidgetItem(w); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 2, item); item = new QTableWidgetItem(QCoreApplication::translate("FermentableType", g_fermentable_types[product->fermentables.at(product->fermentables_row).type])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 3, item); item = new QTableWidgetItem(QCoreApplication::translate("FermentableGraintype", g_fermentable_graintypes[product->fermentables.at(product->fermentables_row).graintype])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 4, item); item = new QTableWidgetItem(QString("%1%").arg(product->fermentables.at(product->fermentables_row).yield, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 6, item); item = new QTableWidgetItem(QString("%1 Kg").arg(product->fermentables.at(product->fermentables_row).inventory, 4, 'f', 3, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (product->fermentables.at(product->fermentables_row).inventory < product->fermentables.at(product->fermentables_row).amount) item->setForeground(QBrush(QColor(Qt::red))); ui->fermentablesTable->setItem(product->fermentables_row, 8, item); calcFermentables(); is_changed(); } void EditProduct::ferment_instock_changed(bool val) { QSqlQuery query; qDebug() << "ferment_instock_changed()" << product->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 EditProduct::ferment_added_changed(int val) { qDebug() << "ferment_added_changed()" << product->fermentables_row << val; product->fermentables[product->fermentables_row].added = val; QTableWidgetItem *item = new QTableWidgetItem(QCoreApplication::translate("FermentableAdded", g_fermentable_added[val])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->fermentablesTable->setItem(product->fermentables_row, 5, item); famountEdit->setReadOnly(product->fermentables_use100 && product->fermentables.at(product->fermentables_row).added < FERMENTABLE_ADDED_BOTTLE); pctEdit->setReadOnly(! (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).added < FERMENTABLE_ADDED_BOTTLE)); double total = 0; for (int i = 0; i < product->fermentables.size(); i++) if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).amount; for (int i = 0; i < product->fermentables.size(); i++) if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) product->fermentables[i].percentage = product->fermentables.at(i).amount / total * 100; is_changed(); emit refreshAll(); } void EditProduct::editFermentRow_clicked() { QSqlQuery query; if (product->locked) return; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); product->fermentables_row = pb->objectName().toInt(); qDebug() << "Edit fermentable row" << product->fermentables_row; Fermentables backup = product->fermentables.at(product->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(product->fermentables.at(product->fermentables_row).name); fnameEdit->setGeometry(QRect(160, 10, 511, 23)); fnameEdit->setReadOnly(true); fsupplierEdit = new QLineEdit(dialog); fsupplierEdit->setObjectName(QString::fromUtf8("fsupplierEdit")); fsupplierEdit->setText(product->fermentables.at(product->fermentables_row).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(product->fermentables_use100 && product->fermentables.at(product->fermentables_row).added < 4); famountEdit->setMaximum(100000.0); famountEdit->setSingleStep(0.0010); famountEdit->setValue(product->fermentables.at(product->fermentables_row).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 (product->fermentables_use100 && product->fermentables.at(product->fermentables_row).added < FERMENTABLE_ADDED_BOTTLE) { if (product->fermentables.at(product->fermentables_row).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(product->fermentables.at(product->fermentables_row).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->setCurrentIndex(product->fermentables.at(product->fermentables_row).added); to100Edit = new QCheckBox(dialog); to100Edit->setObjectName(QString::fromUtf8("to100Edit")); to100Edit->setGeometry(QRect(160, 160, 85, 21)); to100Edit->setChecked(product->fermentables.at(product->fermentables_row).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(product->fermentables.at(product->fermentables_row).max_in_batch); ferment_instock_changed(true); connect(fselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::ferment_select_changed); connect(famountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::ferment_amount_changed); connect(pctEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::ferment_pct_changed); connect(faddedEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::ferment_added_changed); connect(to100Edit, &QCheckBox::stateChanged, this, &EditProduct::ferment_to100_changed); connect(finstockEdit, &QCheckBox::stateChanged, this, &EditProduct::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"; product->fermentables[product->fermentables_row] = backup; /* * Recalculate the percentages */ double total = 0; for (int i = 0; i < product->fermentables.size(); i++) if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) // Only before bottle/kegging total += product->fermentables.at(i).amount; product->fermentables_use100 = false; for (int i = 0; i < product->fermentables.size(); i++) { if (product->fermentables.at(i).adjust_to_total_100) product->fermentables_use100 = true; if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE) { product->fermentables[i].percentage = product->fermentables.at(i).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(); }