Fri, 20 Jan 2023 16:44:08 +0100
Added more buttons to the images tab. Load images from the database and display thumbnails added. Added support for jpeg files. Rename pictures in the database to .png. Added temporary images_list, images_count and images_current variables to the product record.
/** * EditProduct.cpp is part of bmsapp. * * tab 6, yeasts. * * 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 yeaste 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::yeast_sort_test(const Yeasts &D1, const Yeasts &D2) { if (D1.use > D2.use) return false; if (D1.use < D2.use) return true; return (D1.amount > D2.amount); } bool EditProduct::block_yeast(int stage, int use) { if (stage > PROD_STAGE_PRIMARY && use < YEAST_USE_SECONDARY) return true; if (stage > PROD_STAGE_SECONDARY && use < YEAST_USE_TERTIARY) return true; if (stage > PROD_STAGE_TERTIARY && use < YEAST_USE_BOTTLE) return true; if (stage > PROD_STAGE_PACKAGE) return true; return false; } void EditProduct::refreshYeasts() { QString w; QWidget* pWidget; QHBoxLayout* pLayout; QTableWidgetItem *item; std::sort(product->yeasts.begin(), product->yeasts.end(), yeast_sort_test); const QStringList labels({tr("Yeast"), tr("Laboratory"), tr("Code"), tr("Type"), tr("Use for"), tr("Min."), tr("Max."), tr("Tol."), tr("Attn."), tr("STA"), tr("Amount"), tr("Stock"), tr("Delete"), tr("Edit") }); ui->yeastsTable->setColumnCount(14); ui->yeastsTable->setColumnWidth(0, 200); /* Yeast */ ui->yeastsTable->setColumnWidth(1, 115); /* Laboratory */ ui->yeastsTable->setColumnWidth(2, 80); /* Code */ ui->yeastsTable->setColumnWidth(3, 75); /* Type */ ui->yeastsTable->setColumnWidth(4, 75); /* Usage */ ui->yeastsTable->setColumnWidth(5, 50); /* Min. */ ui->yeastsTable->setColumnWidth(6, 50); /* Max. */ ui->yeastsTable->setColumnWidth(7, 50); /* Tolerance */ ui->yeastsTable->setColumnWidth(8, 50); /* Attenuation */ ui->yeastsTable->setColumnWidth(9, 40); /* STA1 gen */ ui->yeastsTable->setColumnWidth(10, 80); /* Amount */ ui->yeastsTable->setColumnWidth(11, 80); /* Stock */ ui->yeastsTable->setColumnWidth(12, 80); /* Delete */ ui->yeastsTable->setColumnWidth(13, 80); /* Edit */ ui->yeastsTable->setHorizontalHeaderLabels(labels); ui->yeastsTable->verticalHeader()->hide(); ui->yeastsTable->setRowCount(product->yeasts.size()); for (int i = 0; i < product->yeasts.size(); i++) { ui->yeastsTable->setItem(i, 0, new QTableWidgetItem(product->yeasts.at(i).name)); ui->yeastsTable->setItem(i, 1, new QTableWidgetItem(product->yeasts.at(i).laboratory)); ui->yeastsTable->setItem(i, 2, new QTableWidgetItem(product->yeasts.at(i).product_id)); item = new QTableWidgetItem(QCoreApplication::translate("YeastForm", g_yeast_forms[product->yeasts.at(i).form])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 3, item); item = new QTableWidgetItem(QCoreApplication::translate("YeastUse", g_yeast_use[product->yeasts.at(i).use])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 4, item); item = new QTableWidgetItem(QString("%1°C").arg(product->yeasts.at(i).min_temperature, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 5, item); item = new QTableWidgetItem(QString("%1°C").arg(product->yeasts.at(i).max_temperature, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 6, item); item = new QTableWidgetItem(QString("%1%").arg(product->yeasts.at(i).tolerance, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 7, item); item = new QTableWidgetItem(QString("%1%").arg(product->yeasts.at(i).attenuation, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 8, item); if (product->yeasts.at(i).use != YEAST_USE_BOTTLE && product->yeasts.at(i).sta1) { 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->yeastsTable->setCellWidget(i, 9, pWidget); } else { ui->yeastsTable->removeCellWidget(i, 9); } if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) item = new QTableWidgetItem(QString("%1 pack").arg(product->yeasts.at(i).amount, 1, 'f', 0, '0')); else if (product->yeasts.at(i).form == YEAST_FORMS_DRY || product->yeasts.at(i).form == YEAST_FORMS_DRIED) item = new QTableWidgetItem(QString("%1 gr").arg(product->yeasts.at(i).amount * 1000.0, 3, 'f', 2, '0')); else item = new QTableWidgetItem(QString("%1 ml").arg(product->yeasts.at(i).amount * 1000.0, 3, 'f', 2, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(i, 10, item); if (block_yeast(product->stage, product->yeasts.at(i).use)) { item = new QTableWidgetItem(QString("")); } else { if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) item = new QTableWidgetItem(QString("%1 pack").arg(product->yeasts.at(i).inventory, 1, 'f', 0, '0')); else if (product->yeasts.at(i).form == YEAST_FORMS_DRY || product->yeasts.at(i).form == YEAST_FORMS_DRIED) item = new QTableWidgetItem(QString("%1 gr").arg(product->yeasts.at(i).inventory * 1000.0, 3, 'f', 2, '0')); else item = new QTableWidgetItem(QString("%1 ml").arg(product->yeasts.at(i).inventory * 1000.0, 3, 'f', 2, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (product->yeasts.at(i).inventory < product->yeasts.at(i).amount) item->setForeground(QBrush(QColor(Qt::red))); } ui->yeastsTable->setItem(i, 11, item); if (block_yeast(product->stage, product->yeasts.at(i).use)) { ui->yeastsTable->removeCellWidget(i, 12); /* to remove the unneeded button */ item = new QTableWidgetItem(""); item->setToolTip(tr("Yeast already used")); ui->yeastsTable->setItem(i, 12, item); ui->yeastsTable->removeCellWidget(i, 13); item = new QTableWidgetItem(""); item->setToolTip(tr("Yeast already used")); ui->yeastsTable->setItem(i, 13, 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(deleteYeastRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_dele); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->yeastsTable->setCellWidget(i, 12, 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(editYeastRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_edit); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->yeastsTable->setCellWidget(i, 13, pWidget); } } } void EditProduct::initYeast() { ui->est_og4Edit->setValue(product->est_og); ui->est_fg3Edit->setValue(product->est_fg); ui->est_abv2Edit->setValue(product->est_abv); ui->productionEdit->setDate(product->yeast_prod_date); ui->conditionShow->setValue(product->starter_viability); ui->startersgEdit->setValue(product->starter_sg); ui->pitchrateEdit->setValue(product->yeast_pitchrate); ui->yeastsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); for (int i = 0; i < 3; i++) { ui->stmethodEdit->addItem(QCoreApplication::translate("YeastStarter", g_yeast_starter[i])); } ui->stmethodEdit->setCurrentIndex(product->starter_type); } /* * Calculate the needed yeast for this batch. */ void EditProduct::calcYeast() { double sg = product->brew_fermenter_sg; double use_cells; double needed = 0; double initcells = 0; bool maybe_starter = false; qDebug() << "calcYeast()"; qDebug() << " " << product->prop_volume[0] << product->prop_volume[1] << product->prop_volume[2] << product->prop_volume[3]; ui->yeastProcedure->setCurrentIndex(0); if (sg <= 1.0001 && product->fg > 1.000) sg = product->fg; else if (sg <= 1.0001) sg = product->est_og; double plato = Utils::sg_to_plato(sg); double volume = product->brew_fermenter_volume; if (volume > 0) { if (product->brew_fermenter_extrawater > 0) volume += product->brew_fermenter_extrawater; } else { volume = product->batch_size - product->eq_trub_loss; } if (product->yeasts.size() == 0) return; // No yeast in product. calcViability(); for (int i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).use == YEAST_USE_PRIMARY) { // Primary if (product->yeasts.at(i).form == YEAST_FORMS_DRY) { /* * Dry yeast, build the formule with the yeast parameters. * Based on https://www.lallemandbrewing.com/en/canada/brewers-corner/brewing-tools/pitching-rate-calculator/ */ ui->yeastProcedure->setCurrentIndex(2); ui->lo_gr_hlEdit->setValue(product->yeasts.at(i).gr_hl_lo); ui->hi_gr_hlEdit->setValue(product->yeasts.at(i).gr_hl_hi); ui->lo_sgEdit->setValue(product->yeasts.at(i).sg_lo); ui->hi_sgEdit->setValue(product->yeasts.at(i).sg_hi); double og = product->yeasts.at(i).sg_lo; double f1 = product->yeasts.at(i).gr_hl_lo / 100.0; double f2 = round(f1 / 5 * 1000000.0) / 1000000.0; double multiplier = (sg <= og) ? f1 : (f1 + f2 * (sg - og) / 0.008); qDebug() << " sg:" << sg << "og:" << og << "f1:" << f1 << "f2:" << f2 << "multiplier:" << multiplier; double yeast_grams = round(volume * multiplier * 100.0) / product->starter_viability; double yeast_gr_hl = round((yeast_grams / (volume * 0.01)) * 100.0) / 100.0; double pitch_gr_hl = round(((product->yeasts.at(i).amount * 1000.0) / (volume * 0.01)) * 100.0) / 100.0; ui->dry_needShow->setValue(yeast_grams); ui->dry_pitchrateShow->setValue(yeast_gr_hl); ui->pitch_grShow->setValue(pitch_gr_hl); ui->pitch_grShow->setStyleSheet((pitch_gr_hl < yeast_gr_hl) ? "background-color: red":""); #ifdef DEBUG_YEAST qDebug() << " need" << yeast_grams << "grams, gr/hl:" << yeast_gr_hl << "pitch:" << pitch_gr_hl; #endif return; } else { /* * Liquid, slant, culture etc. * pitchrate see https://www.brewersfriend.com/yeast-pitch-rate-and-starter-calculator/ * and http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ */ ui->yeastProcedure->setCurrentIndex(1); if (product->yeast_pitchrate == 0) { /* * No pitchrate yet, do a educated guess .. */ if (product->yeasts.at(i).type == YEAST_TYPES_LAGER) { product->yeast_pitchrate = 1.5; if (sg > 1.060) product->yeast_pitchrate = 2.0; } else if (product->yeasts.at(i).type == YEAST_TYPES_KVEIK) { // Real Kveik product->yeast_pitchrate = 0.075; } else { product->yeast_pitchrate = 0.75; if (sg > 1.060) product->yeast_pitchrate = 1.0; } is_changed(); ui->pitchrateEdit->setValue(product->yeast_pitchrate); } initcells = (product->yeasts.at(i).cells / 1000000) * product->yeasts.at(i).amount * (product->starter_viability / 100.0); if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) initcells = (product->yeasts.at(i).cells / 1000000000) * product->yeasts.at(i).amount * (product->starter_viability / 100.0); needed = round(product->yeast_pitchrate * volume * plato * 10.0) / 10.0; ui->neededShow->setValue(needed); if (needed > initcells) { maybe_starter = true; } #ifdef DEBUG_YEAST qDebug() << " pitchrate:" << product->yeast_pitchrate << "needed:" << needed << "initcells:" << initcells << "starter" << maybe_starter; #endif } break; } } if (maybe_starter != product->starter_enable) { if (product->starter_enable && !maybe_starter) { #ifdef DEBUG_YEAST qDebug() << " Clear obsolete starter"; #endif for (int i = 0; i < 4; i++) { product->prop_volume[i] = 0; product->prop_type[i] = 0; } } product->starter_enable = maybe_starter; #ifdef DEBUG_YEAST qDebug() << " Set starter enable" << maybe_starter; #endif is_changed(); } if (product->starter_enable) { #ifdef DEBUG_YEAST qDebug() << " Starter calculate.."; #endif const QStringList labels({tr("Method"), tr("Volume"), tr("Inj. factor"), tr("New cells"), tr("Total cells"), tr("Grow factor"), "" }); ui->starterTable->show(); ui->starterTable->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->starterTable->clear(); ui->starterTable->setColumnCount(7); ui->starterTable->setRowCount(0); ui->starterTable->setColumnWidth(0, 130); /* Method */ ui->starterTable->setColumnWidth(1, 90); /* Volume */ ui->starterTable->setColumnWidth(2, 90); /* Inj. factor */ ui->starterTable->setColumnWidth(3, 90); /* New cells */ ui->starterTable->setColumnWidth(4, 90); /* Total cells */ ui->starterTable->setColumnWidth(5, 90); /* Grow factor */ ui->starterTable->setColumnWidth(6, 30); /* Edit button */ ui->starterTable->setHorizontalHeaderLabels(labels); calcSteps(product->starter_type, initcells, needed); } else { ui->starterTable->hide(); } calcBU(); } /* * http://braukaiser.com/blog/blog/2012/11/03/estimating-yeast-growth/ * * stype: 0=stirred, 1=shaken, 2=simple * totcells: initial cells * egrams: gram extract */ double EditProduct::getGrowthRate(int stype, double totcells, double egrams) { /* Cells per grams extract (B/g) */ double cpe = totcells / egrams; if (cpe > 3.5) return 0; // no growth if (stype == STARTERS_SIMPLE) return 0.4; // simple starter if (stype == STARTERS_SHAKEN) return 0.62; // shaken starter if (cpe <= 1.4) // stirred starter return 1.4; return 2.33 - (.67 * cpe); }; StepResult EditProduct::calcStep(double svol, int stype, double start) { StepResult res; double gperpoint = 2.72715; //number of grams of extract per point of starter gravity per liter double irate = round(start / svol * 10000.0) / 10.0; double egrams = (product->starter_sg - 1) * svol * gperpoint; double grate = getGrowthRate(stype, start, egrams); double ncells = round(egrams * grate * 10.0) / 10.0; double totcells = ncells + start; res.svol = svol; res.irate = irate; res.ncells = ncells; res.totcells = totcells; res.growf = round((ncells / start) * 100.0) / 100.0; #ifdef DEBUG_YEAST qDebug() << " calcStep(" << svol << "," << stype << "," << start << ") irate" << irate << "ncells" << res.ncells << "totcells" << res.totcells << "growf" << res.growf; #endif return res; } /* * Calculate all starter steps. * stype: final starter type: 0 = stirred, 1 = shaked, 2 = simple. * start: initial cells in billions * needed: needed cells in billions * * result: all values updated. */ void EditProduct::calcSteps(int stype, double start, double needed) { int i, step, svol; int lasti = 0; /* Erlenmeyer sizes */ const int uvols[] { 20, 40, 60, 80, 100, 150, 200, 250, 375, 500, 625, 750, 875, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000 }; int mvols = sizeof(uvols); StepResult result; QTableWidgetItem *item; QWidget* pWidget; QHBoxLayout* pLayout; double tcells = start; QIcon iconT; iconT.addFile(QString::fromUtf8(":/icons/silk/pencil.png"), QSize(), QIcon::Normal, QIcon::Off); if ((product->prop_volume[0] + product->prop_volume[1] + product->prop_volume[2] + product->prop_volume[3]) == 0) { /* * Auto calculate the starter. */ #ifdef DEBUG_YEAST qDebug() << " calcSteps() auto"; #endif if (start > needed) return; for (step = 1; step < 5; step++) { qDebug() << " step" << step; for (i = lasti; i <= mvols; i++) { lasti = i; svol = uvols[lasti]; result = calcStep(svol, stype, tcells); if (result.irate < 25) { // inocculation rate too low, backup one step and break out. lasti = i - 1; svol = uvols[lasti]; result = calcStep(svol, stype, tcells); break; } if (result.totcells > needed || i == mvols) { // hit the target or loops done break; } } ui->starterTable->setRowCount(step); item = new QTableWidgetItem(QCoreApplication::translate("YeastStarter", g_yeast_starter[stype])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->starterTable->setItem(step -1, 0, item); item = new QTableWidgetItem(QString("%1").arg(result.svol / 1000.0, 4, 'f', 3, '0')); // To liters item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->starterTable->setItem(step -1, 1, item); item = new QTableWidgetItem(QString("%1").arg(result.irate, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if ((result.irate < 25) || (result.irate > 100)) item->setForeground(QBrush(QColor(Qt::red))); ui->starterTable->setItem(step -1, 2, item); item = new QTableWidgetItem(QString("%1").arg(result.ncells, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->starterTable->setItem(step -1, 3, item); item = new QTableWidgetItem(QString("%1").arg(result.totcells, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); item->setForeground(QBrush(QColor((result.totcells > needed) ? Qt::green:Qt::red))); ui->starterTable->setItem(step -1, 4, item); item = new QTableWidgetItem(QString("%1").arg(result.growf, 3, 'f', 2, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (result.growf < 1) item->setForeground(QBrush(QColor(Qt::red))); if ((stype > 0) && (result.growf > 3)) item->setForeground(QBrush(QColor(Qt::red))); ui->starterTable->setItem(step -1, 5, item); pWidget = new QWidget(); QToolButton* btn_edit = new QToolButton(); btn_edit->setObjectName(QString("%1").arg(step - 1)); /* Send row with the button */ btn_edit->setIcon(iconT); connect(btn_edit, SIGNAL(clicked()), this, SLOT(yeast_starter_edit_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_edit); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->starterTable->setCellWidget(step -1, 6, pWidget); product->prop_type[step -1] = product->starter_type; product->prop_volume[step -1] = result.svol / 1000.0; #ifdef DEBUG_YEAST qDebug() << " step" << step << "type" << product->prop_type[step -1] << "vol" << product->prop_volume[step -1]; #endif tcells = result.totcells; if (result.totcells > needed) // Hit the target return; } } else { /* * Recalculate the starter. */ #ifdef DEBUG_YEAST qDebug() << " calcSteps() recalculate"; #endif for (step = 0; step < 4; step++) { if (product->prop_volume[step] > 0) { result = calcStep(product->prop_volume[step] * 1000, product->prop_type[step], tcells); ui->starterTable->setRowCount(step + 1); item = new QTableWidgetItem(QCoreApplication::translate("YeastStarter", g_yeast_starter[product->prop_type[step]])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->starterTable->setItem(step, 0, item); item = new QTableWidgetItem(QString("%1").arg(result.svol / 1000.0, 4, 'f', 3, '0')); // To liters item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->starterTable->setItem(step, 1, item); item = new QTableWidgetItem(QString("%1").arg(result.irate, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if ((result.irate < 25) || (result.irate > 100)) item->setForeground(QBrush(QColor(Qt::red))); ui->starterTable->setItem(step, 2, item); item = new QTableWidgetItem(QString("%1").arg(result.ncells, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->starterTable->setItem(step, 3, item); item = new QTableWidgetItem(QString("%1").arg(result.totcells, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); item->setForeground(QBrush(QColor((result.totcells > needed) ? Qt::green:Qt::red))); ui->starterTable->setItem(step, 4, item); item = new QTableWidgetItem(QString("%1").arg(result.growf, 3, 'f', 2, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (result.growf < 1) item->setForeground(QBrush(QColor(Qt::red))); if ((stype > 0) && (result.growf > 3)) item->setForeground(QBrush(QColor(Qt::red))); ui->starterTable->setItem(step, 5, item); pWidget = new QWidget(); QToolButton* btn_edit = new QToolButton(); btn_edit->setObjectName(QString("%1").arg(step)); /* Send row with the button */ btn_edit->setIcon(iconT); connect(btn_edit, SIGNAL(clicked()), this, SLOT(yeast_starter_edit_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_edit); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->starterTable->setCellWidget(step, 6, pWidget); tcells = result.totcells; if (result.totcells > needed) { // Hit the target for (int i = step + 1; i < 4; i++) { product->prop_volume[i] = 0; product->prop_type[i] = 0; } return; } else if ((step < 3) && (product->prop_volume[step + 1] == 0)) { // Extra step needed, start with the same size. product->prop_volume[step + 1] = product->prop_volume[step]; product->prop_type[step + 1] = product->prop_type[step]; } #ifdef DEBUG_YEAST qDebug() << " step" << step << "type" << product->prop_type[step] << "vol" << product->prop_volume[step]; #endif } } } } void EditProduct::calcViability() { double vpm = 1.00; double max = 100; for (int i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).use == YEAST_USE_PRIMARY) { if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) { vpm = 0.80; max = 97; if (product->yeasts.at(i).laboratory == "White Labs") { // PurePitch vpm = 0.95; max = 100; } } else if (product->yeasts.at(i).form == YEAST_FORMS_DRY) { vpm = 0.998; max = 100; } else if (product->yeasts.at(i).form == YEAST_FORMS_DRIED) { // dried kveik vpm = 0.92; max = 100; } else { // Slant, Culture, Frozen, Bottle vpm = 0.99; max = 97; } } } #ifdef DEBUG_YEAST qDebug() << "calcViability vpm:" << vpm << "max:" << max; #endif double base = max; /* * Calculate time days before today. If the date is cleared, * the result is 0 days. Dates in the future are ignored. */ int timeDiff = product->yeast_prod_date.daysTo(QDate::currentDate()); if (timeDiff < 0) timeDiff == 0; double degrade = 1 - ((1 - vpm) / 30.41); // viability degradation per day. for (int i = 0; i < timeDiff; i++) { base = base * degrade; } if (base > max) base = max; base = round(base); product->starter_viability = base; ui->conditionShow->setValue(product->starter_viability); #ifdef DEBUG_YEAST qDebug() << "age" << timeDiff << "degrade" << degrade << "base" << base ; #endif } void EditProduct::yeast_prod_date_changed(QDate val) { product->yeast_prod_date = ui->productionEdit->nullDate(); calcViability(); calcYeast(); is_changed(); } void EditProduct::yeast_prod_date_clear() { product->yeast_prod_date = QDate(); ui->productionEdit->setDate(QDate()); } void EditProduct::yeast_prod_date_today() { product->yeast_prod_date = QDate::currentDate(); ui->productionEdit->setDate(QDate::currentDate()); } void EditProduct::yeast_method_changed(int val) { #ifdef DEBUG_YEAST qDebug() << "yeast_method_changed" << val; #endif product->starter_type = val; calcYeast(); is_changed(); } void EditProduct::yeast_starter_sg_changed(double val) { #ifdef DEBUG_YEAST qDebug() << "yeast_starter_sg_changed" << val; #endif product->starter_sg = val; calcYeast(); is_changed(); } void EditProduct::pitchindex_changed(int val) { #ifdef DEBUG_YEAST qDebug() << "pitchindex_changed" << val; #endif product->pitch_pitchindex = val; } void EditProduct::pitchrate_changed(double val) { #ifdef DEBUG_YEAST qDebug() << "pitchrate_changed" << val; #endif product->yeast_pitchrate = val; calcYeast(); is_changed(); } void EditProduct::yeast_pitchrate_button_clicked() { #ifdef DEBUG_YEAST qDebug() << "yeast_pitchrate_button_clicked"; #endif product->pitch_pitchindex = 1; QDialog* dialog = new QDialog(this); dialog->resize(420, 110); dialog->setWindowTitle(tr("BMSapp - Pitchrate")); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setObjectName(QString::fromUtf8("buttonBox")); buttonBox->setGeometry(QRect(30, 60, 360, 32)); buttonBox->setLayoutDirection(Qt::LeftToRight); buttonBox->setOrientation(Qt::Horizontal); buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); buttonBox->setCenterButtons(true); QLabel *typeLabel = new QLabel(dialog); typeLabel->setObjectName(QString::fromUtf8("typeLabel")); typeLabel->setText(tr("Beer pitch type:")); typeLabel->setGeometry(QRect(10, 20, 195, 20)); typeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QComboBox *typeEdit = new QComboBox(dialog); typeEdit->setObjectName(QString::fromUtf8("typeEdit")); typeEdit->setGeometry(QRect(215, 20, 185, 23)); typeEdit->setIconSize(QSize(0, 0)); typeEdit->addItem(tr("0.075 Real Kveik")); typeEdit->addItem(tr("0.75 Ale, upto 1.060")); typeEdit->addItem(tr("1.0 Ale, above 1.060")); typeEdit->addItem(tr("1.5 Lager, upto 1.060")); typeEdit->addItem(tr("2.0 Lager, above 1.060")); typeEdit->setCurrentIndex(product->pitch_pitchindex); connect(typeEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::pitchindex_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) { switch (product->pitch_pitchindex) { case 0: product->yeast_pitchrate = 0.075; break; case 1: product->yeast_pitchrate = 0.75; break; case 2: product->yeast_pitchrate = 1.0; break; case 3: product->yeast_pitchrate = 1.5; break; case 4: product->yeast_pitchrate = 2.0; break; } ui->pitchrateEdit->setValue(product->yeast_pitchrate); /* Will automatic call calcYeast() and is_changed() */ } disconnect(typeEdit, nullptr, nullptr, nullptr); disconnect(buttonBox, nullptr, nullptr, nullptr); } void EditProduct::yeast_retry_button_clicked() { #ifdef DEBUG_YEAST qDebug() << "yeast_retry_button_clicked"; #endif int rc = QMessageBox::warning(this, tr("Retry starter"), tr("Retry to automatic create starter steps"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (rc == QMessageBox::No) return; for (int i = 0; i < 4; i++) { product->prop_volume[i] = 0; product->prop_type[i] = product->starter_type; } calcYeast(); is_changed(); } void EditProduct::yeast_starter_edit_clicked() { QToolButton *pb = qobject_cast<QToolButton *>(QObject::sender()); int row = pb->objectName().toInt(); #ifdef DEBUG_YEAST qDebug() << "yeast_starter_edit_clicked" << row; #endif QDialog* dialog = new QDialog(this); dialog->resize(338, 140); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setObjectName(QString::fromUtf8("buttonBox")); buttonBox->setGeometry(QRect(30, 90, 271, 32)); buttonBox->setLayoutDirection(Qt::LeftToRight); buttonBox->setOrientation(Qt::Horizontal); buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); buttonBox->setCenterButtons(true); QLabel *typeLabel = new QLabel(dialog); typeLabel->setObjectName(QString::fromUtf8("typeLabel")); typeLabel->setText(tr("Start step type:")); typeLabel->setGeometry(QRect(10, 10, 141, 20)); typeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *volLabel = new QLabel(dialog); volLabel->setObjectName(QString::fromUtf8("volLabel")); volLabel->setText(tr("Starter step volume:")); volLabel->setGeometry(QRect(10, 40, 141, 20)); volLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QComboBox *typeEdit = new QComboBox(dialog); typeEdit->setObjectName(QString::fromUtf8("typeEdit")); typeEdit->setGeometry(QRect(160, 10, 121, 23)); typeEdit->addItem(tr("Stirred")); typeEdit->addItem(tr("Shaken")); typeEdit->addItem(tr("Simple")); typeEdit->setCurrentIndex(product->prop_type[row]); QDoubleSpinBox *volEdit = new QDoubleSpinBox(dialog); volEdit->setObjectName(QString::fromUtf8("volEdit")); volEdit->setGeometry(QRect(160, 40, 121, 24)); volEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); volEdit->setAccelerated(true); volEdit->setDecimals(3); volEdit->setSingleStep(0.01); volEdit->setValue(product->prop_volume[row]); volEdit->setMaximum(5); connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); dialog->setModal(true); dialog->exec(); if (dialog->result() != QDialog::Rejected) { product->prop_type[row] = typeEdit->currentIndex(); product->prop_volume[row] = volEdit->value(); calcYeast(); is_changed(); } disconnect(buttonBox, nullptr, nullptr, nullptr); } void EditProduct::addYeastRow_clicked() { Yeasts newy; #ifdef DEBUG_YEAST qDebug() << "Add yeast row"; #endif for (int i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).amount == 0) return; // Add only one at a time. } newy.name = "Select one"; newy.laboratory = ""; newy.product_id = ""; newy.amount = 0; newy.type = YEAST_TYPES_ALE; newy.form = YEAST_FORMS_LIQUID; newy.min_temperature = 0; newy.max_temperature = 0; newy.flocculation = 0; newy.attenuation = 0; newy.cells = 0; newy.tolerance = 0; newy.inventory = 0; newy.use = YEAST_USE_PRIMARY; newy.sta1 = false; newy.bacteria = false; newy.harvest_top = false; newy.harvest_time = 0; newy.pitch_temperature = 0; newy.pofpos = false; newy.zymocide = 0; newy.gr_hl_lo = 0; newy.sg_lo = 0; newy.gr_hl_hi = 0; newy.sg_hi = 0; newy.cost = 0; product->yeasts.append(newy); emit refreshAll(); } void EditProduct::deleteYeastRow_clicked() { if (product->locked || product->yeasts.size() < 1) return; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); int row = pb->objectName().toInt(); #ifdef DEBUG_YEAST qDebug() << "Delete yeast row" << row << product->yeasts.size(); #endif int rc = QMessageBox::warning(this, tr("Delete yeast"), tr("Delete %1").arg(product->yeasts.at(row).name), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (rc == QMessageBox::No) return; product->yeasts.removeAt(row); bool primary = false; for (int i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).use == YEAST_USE_PRIMARY) primary = true; } if (! primary) { #ifdef DEBUG_YEAST qDebug() << " Clear starter (if any)"; #endif for (int i = 0; i < 4; i++) product->prop_volume[i] = 0; } is_changed(); emit refreshAll(); } void EditProduct::yeast_amount_changed(double val) { QTableWidgetItem *item; #ifdef DEBUG_YEAST qDebug() << "yeast_amount_changed()" << product->yeasts_row << val; #endif if (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_LIQUID) { product->yeasts[product->yeasts_row].amount = val; item = new QTableWidgetItem(QString("%1 pack").arg(val, 1, 'f', 0, '0')); } else if ((product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRY) || (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRIED)) { product->yeasts[product->yeasts_row].amount = val / 1000.0; item = new QTableWidgetItem(QString("%1 gr").arg(val, 3, 'f', 2, '0')); } else { product->yeasts[product->yeasts_row].amount = val / 1000.0; item = new QTableWidgetItem(QString("%1 ml").arg(val, 3, 'f', 2, '0')); } item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 9, item); calcYeast(); is_changed(); } void EditProduct::yeast_select_changed(int val) { QSqlQuery query; bool instock = yinstockEdit->isChecked(); QString w; QTableWidgetItem *item; int oldform = product->yeasts.at(product->yeasts_row).form; if (val < 1) return; #ifdef DEBUG_YEAST qDebug() << "yeast_select_changed()" << product->yeasts_row << val << instock; #endif /* * Search the yeast pointed by the index and instock flag. */ QString sql = "SELECT name,laboratory,product_id,type,form,min_temperature,max_temperature,flocculation,attenuation," "cells,tolerance,sta1,bacteria,harvest_top,harvest_time,pitch_temperature,pofpos,zymocide," "gr_hl_lo,sg_lo,gr_hl_hi,sg_hi,cost,inventory FROM inventory_yeasts "; if (instock) sql.append("WHERE inventory > 0 "); sql.append("ORDER BY laboratory,product_id,name"); query.prepare(sql); query.exec(); query.first(); for (int i = 0; i < (val - 1); i++) { query.next(); } #ifdef DEBUG_YEAST qDebug() << "found" << query.value("name").toString() << query.value("product_id").toString(); #endif /* * Replace the yeast record contents */ product->yeasts[product->yeasts_row].name = query.value("name").toString(); product->yeasts[product->yeasts_row].laboratory = query.value("laboratory").toString(); product->yeasts[product->yeasts_row].product_id = query.value("product_id").toString(); product->yeasts[product->yeasts_row].type = query.value("type").toInt(); product->yeasts[product->yeasts_row].form = query.value("form").toInt(); product->yeasts[product->yeasts_row].min_temperature = query.value("min_temperature").toDouble(); product->yeasts[product->yeasts_row].max_temperature = query.value("max_temperature").toDouble(); product->yeasts[product->yeasts_row].flocculation = query.value("flocculation").toInt(); product->yeasts[product->yeasts_row].attenuation = query.value("attenuation").toDouble(); product->yeasts[product->yeasts_row].cells = query.value("cells").toDouble(); product->yeasts[product->yeasts_row].tolerance = query.value("tolerance").toDouble(); product->yeasts[product->yeasts_row].sta1 = query.value("sta1").toInt() ? true:false; product->yeasts[product->yeasts_row].bacteria = query.value("bacteria").toInt() ? true:false; product->yeasts[product->yeasts_row].harvest_top = query.value("harvest_top").toInt() ? true:false; product->yeasts[product->yeasts_row].harvest_time = query.value("harvest_time").toInt(); product->yeasts[product->yeasts_row].pitch_temperature = query.value("pitch_temperature").toDouble(); product->yeasts[product->yeasts_row].pofpos = query.value("pofpos").toInt() ? true:false; product->yeasts[product->yeasts_row].zymocide = query.value("zymocide").toInt(); product->yeasts[product->yeasts_row].gr_hl_lo = query.value("gr_hl_lo").toInt(); product->yeasts[product->yeasts_row].sg_lo = query.value("sg_lo").toDouble(); product->yeasts[product->yeasts_row].gr_hl_hi = query.value("gr_hl_hi").toInt(); product->yeasts[product->yeasts_row].sg_hi = query.value("sg_hi").toDouble(); product->yeasts[product->yeasts_row].cost = query.value("cost").toDouble(); product->yeasts[product->yeasts_row].inventory = query.value("inventory").toDouble(); /* * Update the visible fields */ const QSignalBlocker blocker1(yamountEdit); ynameEdit->setText(product->yeasts.at(product->yeasts_row).name); ylaboratoryEdit->setText(product->yeasts.at(product->yeasts_row).laboratory); yproduct_idEdit->setText(product->yeasts.at(product->yeasts_row).product_id); if (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_LIQUID) { if (oldform != YEAST_FORMS_LIQUID) product->yeasts[product->yeasts_row].amount = 1; yamountEdit->setValue(product->yeasts[product->yeasts_row].amount); yamountEdit->setDecimals(0); yamountEdit->setSingleStep(1.0); yamountLabel->setText(tr("Total packs:")); } else if ((product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRY) || (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRIED)) { if (oldform == YEAST_FORMS_LIQUID) product->yeasts[product->yeasts_row].amount = 0.01; yamountEdit->setValue(product->yeasts[product->yeasts_row].amount * 1000.0); yamountEdit->setDecimals(1); yamountEdit->setSingleStep(0.5); yamountLabel->setText(tr("Amount in gr:")); } else { if (oldform == YEAST_FORMS_LIQUID) product->yeasts[product->yeasts_row].amount = 0.01; yamountEdit->setValue(product->yeasts[product->yeasts_row].amount * 1000.0); yamountEdit->setDecimals(1); yamountEdit->setSingleStep(0.5); yamountLabel->setText(tr("Amount in ml:")); } ui->yeastsTable->setItem(product->yeasts_row, 0, new QTableWidgetItem(product->yeasts.at(product->yeasts_row).name)); ui->yeastsTable->setItem(product->yeasts_row, 1, new QTableWidgetItem(product->yeasts.at(product->yeasts_row).laboratory)); ui->yeastsTable->setItem(product->yeasts_row, 2, new QTableWidgetItem(product->yeasts.at(product->yeasts_row).product_id)); item = new QTableWidgetItem(QCoreApplication::translate("YeastForm", g_yeast_forms[product->yeasts.at(product->yeasts_row).form])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 3, item); item = new QTableWidgetItem(QString("%1").arg(product->yeasts.at(product->yeasts_row).min_temperature, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 5, item); item = new QTableWidgetItem(QString("%1").arg(product->yeasts.at(product->yeasts_row).max_temperature, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 6, item); item = new QTableWidgetItem(QString("%1").arg(product->yeasts.at(product->yeasts_row).tolerance, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 7, item); item = new QTableWidgetItem(QString("%1").arg(product->yeasts.at(product->yeasts_row).attenuation, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 8, item); if (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_LIQUID) item = new QTableWidgetItem(QString("%1 pack").arg(product->yeasts.at(product->yeasts_row).amount, 1, 'f', 0, '0')); else if (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRY || product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRIED) item = new QTableWidgetItem(QString("%1 gr").arg(product->yeasts.at(product->yeasts_row).amount * 1000.0, 3, 'f', 2, '0')); else item = new QTableWidgetItem(QString("%1 ml").arg(product->yeasts.at(product->yeasts_row).amount * 1000.0, 3, 'f', 2, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 9, item); /* * If there is no need for a starter, wipe it. */ bool maybe_starter = false; for (int i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).use == YEAST_USE_PRIMARY && ! ((product->yeasts.at(i).form == YEAST_FORMS_DRY) || (product->yeasts.at(i).form == YEAST_FORMS_DRIED))) maybe_starter = true; } if (! maybe_starter) { #ifdef DEBUG_YEAST qDebug() << " Clear starter (if any)"; #endif for (int i = 0; i < 4; i++) product->prop_volume[i] = 0; } is_changed(); emit refreshAll(); } void EditProduct::yeast_instock_changed(bool val) { QSqlQuery query; #ifdef DEBUG_YEAST qDebug() << "yeast_instock_changed()" << product->yeasts_row << val; #endif this->yselectEdit->setCurrentIndex(-1); this->yselectEdit->clear(); QString sql = "SELECT name,laboratory,product_id,inventory FROM inventory_yeasts "; if (val) sql.append("WHERE inventory > 0 "); sql.append("ORDER BY laboratory,product_id,name"); query.prepare(sql); query.exec(); query.first(); this->yselectEdit->addItem(""); // Start with empty value for (int i = 0; i < query.size(); i++) { this->yselectEdit->addItem(query.value(1).toString()+" - "+query.value(2).toString()+" "+query.value(0).toString() + QString(" (%1 gr)").arg(query.value(3).toDouble() * 1000.0, 2, 'f', 1, '0')); query.next(); } } void EditProduct::yeast_useat_changed(int val) { #ifdef DEBUG_YEAST qDebug() << "yeast_useat_changed()" << product->yeasts_row << val; #endif product->yeasts[product->yeasts_row].use = val; QTableWidgetItem *item = new QTableWidgetItem(QCoreApplication::translate("YeastUse", g_yeast_use[val])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->yeastsTable->setItem(product->yeasts_row, 5, item); is_changed(); emit refreshAll(); } void EditProduct::editYeastRow_clicked() { QSqlQuery query; if (product->locked) return; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); product->yeasts_row = pb->objectName().toInt(); #ifdef DEBUG_YEAST qDebug() << "Edit yeast row" << product->yeasts_row; #endif Yeasts backup = product->yeasts.at(product->yeasts_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("Yeast name:")); nameLabel->setGeometry(QRect(10, 10, 141, 20)); nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *laboratoryLabel = new QLabel(dialog); laboratoryLabel->setObjectName(QString::fromUtf8("laboratoryLabel")); laboratoryLabel->setText(tr("Laboratory:")); laboratoryLabel->setGeometry(QRect(10, 40, 141, 20)); laboratoryLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *product_idLabel = new QLabel(dialog); product_idLabel->setObjectName(QString::fromUtf8("product_idLabel")); product_idLabel->setText(tr("Laboratory:")); product_idLabel->setGeometry(QRect(10, 70, 141, 20)); product_idLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLabel *selectLabel = new QLabel(dialog); selectLabel->setObjectName(QString::fromUtf8("selectLabel")); selectLabel->setText(tr("Select yeast:")); selectLabel->setGeometry(QRect(10,100, 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,100, 121, 20)); instockLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); yamountLabel = new QLabel(dialog); yamountLabel->setObjectName(QString::fromUtf8("amountLabel")); if (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_LIQUID) yamountLabel->setText(tr("Total packs:")); else if ((product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRY) || (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRIED)) yamountLabel->setText(tr("Amount in gr:")); else yamountLabel->setText(tr("Amount in ml:")); yamountLabel->setGeometry(QRect(10, 130, 141, 20)); yamountLabel->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); ynameEdit = new QLineEdit(dialog); ynameEdit->setObjectName(QString::fromUtf8("ynameEdit")); ynameEdit->setText(product->yeasts.at(product->yeasts_row).name); ynameEdit->setGeometry(QRect(160, 10, 511, 23)); ynameEdit->setReadOnly(true); ylaboratoryEdit = new QLineEdit(dialog); ylaboratoryEdit->setObjectName(QString::fromUtf8("ylaboratoryEdit")); ylaboratoryEdit->setText(product->yeasts.at(product->yeasts_row).laboratory); ylaboratoryEdit->setGeometry(QRect(160, 40, 511, 23)); ylaboratoryEdit->setReadOnly(true); yproduct_idEdit = new QLineEdit(dialog); yproduct_idEdit->setObjectName(QString::fromUtf8("yproduct_idEdit")); yproduct_idEdit->setText(product->yeasts.at(product->yeasts_row).product_id); yproduct_idEdit->setGeometry(QRect(160, 70, 511, 23)); yproduct_idEdit->setReadOnly(true); yselectEdit = new QComboBox(dialog); yselectEdit->setObjectName(QString::fromUtf8("selectEdit")); yselectEdit->setGeometry(QRect(160,100, 371, 23)); yinstockEdit = new QCheckBox(dialog); yinstockEdit->setObjectName(QString::fromUtf8("yinstockEdit")); yinstockEdit->setGeometry(QRect(655,100, 85, 21)); yinstockEdit->setChecked(true); yamountEdit = new QDoubleSpinBox(dialog); yamountEdit->setObjectName(QString::fromUtf8("yamountEdit")); yamountEdit->setGeometry(QRect(160, 130, 121, 24)); yamountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); yamountEdit->setAccelerated(true); yamountEdit->setMaximum(10000.0); if (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_LIQUID) { yamountEdit->setDecimals(0); yamountEdit->setSingleStep(1.0); yamountEdit->setValue(product->yeasts.at(product->yeasts_row).amount); } else if ((product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRY) || (product->yeasts.at(product->yeasts_row).form == YEAST_FORMS_DRIED)) { yamountEdit->setDecimals(1); yamountEdit->setSingleStep(0.5); yamountEdit->setValue(product->yeasts.at(product->yeasts_row).amount * 1000.0); } else { yamountEdit->setDecimals(1); yamountEdit->setSingleStep(0.5); yamountEdit->setValue(product->yeasts.at(product->yeasts_row).amount * 1000.0); } yamountEdit->setMaximum(1000000000.0); useatEdit = new QComboBox(dialog); useatEdit->setObjectName(QString::fromUtf8("useatEdit")); useatEdit->setGeometry(QRect(160, 160, 161, 23)); useatEdit->addItem(tr("Primary")); useatEdit->addItem(tr("Secondary")); useatEdit->addItem(tr("Tertiary")); useatEdit->addItem(tr("Bottle")); useatEdit->setCurrentIndex(product->yeasts.at(product->yeasts_row).use); yeast_instock_changed(true); connect(yselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::yeast_select_changed); connect(yamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::yeast_amount_changed); connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::yeast_useat_changed); connect(yinstockEdit, &QCheckBox::stateChanged, this, &EditProduct::yeast_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) { #ifdef DEBUG_YEAST qDebug() << "reject and rollback"; #endif product->yeasts[product->yeasts_row] = backup; } else { } disconnect(yselectEdit, nullptr, nullptr, nullptr); disconnect(yamountEdit, nullptr, nullptr, nullptr); disconnect(useatEdit, nullptr, nullptr, nullptr); disconnect(yinstockEdit, nullptr, nullptr, nullptr); disconnect(buttonBox, nullptr, nullptr, nullptr); emit refreshAll(); } void EditProduct::adjustYeasts(double factor) { double amount; if (product->yeasts.size() == 0) return; for (int i = 0; i < product->yeasts.size(); i++) { if (product->yeasts.at(i).form == YEAST_FORMS_DRY) { // Only adjust dry yeast amount = product->yeasts.at(i).amount * factor; product->yeasts[i].amount = amount; } } }