src/EditProductTab6.cpp

Thu, 18 Aug 2022 20:34:15 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Thu, 18 Aug 2022 20:34:15 +0200
changeset 401
583148eb6e01
parent 395
7212b980a527
child 454
2dfead81c72f
permissions
-rw-r--r--

Init est_carb field for new products.

/**
 * 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;

    qDebug() << "refreshYeasts" << product->yeasts.size();
    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("Amount"), tr("Stock"), tr("Delete"), tr("Edit") });

    ui->yeastsTable->setColumnCount(13);
    ui->yeastsTable->setColumnWidth(0, 200);	/* Yeast	*/
    ui->yeastsTable->setColumnWidth(1, 115);	/* Laboratory	*/
    ui->yeastsTable->setColumnWidth(2,  80);	/* Code		*/
    ui->yeastsTable->setColumnWidth(3,  80);	/* Type		*/
    ui->yeastsTable->setColumnWidth(4,  80);	/* 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,  80);	/* Amount	*/
    ui->yeastsTable->setColumnWidth(10, 80);	/* Stock	*/
    ui->yeastsTable->setColumnWidth(11, 80);	/* Delete	*/
    ui->yeastsTable->setColumnWidth(12, 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).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, 9, 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, 10, item);

	if (block_yeast(product->stage, product->yeasts.at(i).use)) {
	    ui->yeastsTable->removeCellWidget(i, 11);     /* to remove the unneeded button */
            item = new QTableWidgetItem("");
            item->setToolTip(tr("Yeast already used"));
            ui->yeastsTable->setItem(i, 11, item);
            ui->yeastsTable->removeCellWidget(i, 12);
            item = new QTableWidgetItem("");
            item->setToolTip(tr("Yeast already used"));
            ui->yeastsTable->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(deleteYeastRow_clicked()));
            pLayout = new QHBoxLayout(pWidget);
            pLayout->addWidget(btn_dele);
            pLayout->setContentsMargins(5, 0, 5, 0);
            pWidget->setLayout(pLayout);
            ui->yeastsTable->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(editYeastRow_clicked()));
            pLayout = new QHBoxLayout(pWidget);
            pLayout->addWidget(btn_edit);
            pLayout->setContentsMargins(5, 0, 5, 0);
            pWidget->setLayout(pLayout);
            ui->yeastsTable->setCellWidget(i, 12, 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()";
    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_chiller_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":"");

     		qDebug() << "  need" << yeast_grams << "grams, gr/hl:" << yeast_gr_hl << "pitch:" << pitch_gr_hl;
		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;
		}

		qDebug() << "  pitchrate:" << product->yeast_pitchrate << "needed:" << needed << "initcells:" << initcells << "starter" << maybe_starter;
	    }
	    break;
	}
    }

    if (maybe_starter != product->starter_enable) {
	product->starter_enable = maybe_starter;
	qDebug() << "  Set starter enable" << maybe_starter;
	is_changed();
    }

    if (product->starter_enable) {
	qDebug() << "  Starter calculate..";

	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;
    qDebug() << "  calcStep(" << svol << "," << stype << "," << start << ") irate" << irate
	     << "ncells" << res.ncells << "totcells" << res.totcells << "growf" << res.growf;
    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.
	 */
	qDebug() << "  calcSteps() auto";

	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;

	    tcells = result.totcells;
	    if (result.totcells > needed)	// Hit the target
		return;
	}

    } else {
	/*
	 * Recalculate the starter.
	 */
	qDebug() << "  calcSteps() recalculate";

	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];
	    	}
	    }
	}
    }
}


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;
	    }
	}
    }
    qDebug() << "calcViability vpm:" << vpm << "max:" << max;

    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);
    qDebug() << "age" << timeDiff << "degrade" << degrade << "base" << base ;
}


void EditProduct::yeast_prod_date_changed(QDate val)
{
    product->yeast_prod_date = ui->productionEdit->nullDate();
    qDebug() << "yeast_prod_date_changed" << val << product->yeast_prod_date;
    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)
{
    qDebug() << "yeast_method_changed" << val;
    product->starter_type = val;
    calcYeast();
    is_changed();
}


void EditProduct::yeast_starter_sg_changed(double val)
{
    qDebug() << "yeast_starter_sg_changed" << val;
    product->starter_sg = val;
    calcYeast();
    is_changed();
}


void EditProduct::yeast_pitchrate_button_clicked()
{
}


void EditProduct::yeast_starter_edit_clicked()
{
    QToolButton *pb = qobject_cast<QToolButton *>(QObject::sender());
    int row = pb->objectName().toInt();
    qDebug() << "yeast_starter_edit_clicked" << row;

    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) {
        qDebug() << "reject";
    } else {
	product->prop_type[row] = typeEdit->currentIndex();
	product->prop_volume[row] = volEdit->value();
	qDebug() << "accept";
        calcYeast();
	is_changed();
    }

    disconnect(buttonBox, nullptr, nullptr, nullptr);
}


void EditProduct::addYeastRow_clicked()
{
    Yeasts newy;

    qDebug() << "Add yeast row";

    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();
    qDebug() << "Delete yeast row" << row << product->yeasts.size();

    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);
    is_changed();
    emit refreshAll();
}


void EditProduct::yeast_amount_changed(double val)
{
    QTableWidgetItem *item;

    qDebug() << "yeast_amount_changed()" << product->yeasts_row << val;

    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;

    qDebug() << "yeast_select_changed()" << product->yeasts_row << val << instock;

    /*
     * 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();
    }
    qDebug() << "found" << query.value(0).toString() << query.value(2).toString();

    /*
     * Replace the yeast record contents
     */
    product->yeasts[product->yeasts_row].name = query.value(0).toString();
    product->yeasts[product->yeasts_row].laboratory = query.value(1).toString();
    product->yeasts[product->yeasts_row].product_id = query.value(2).toString();
    product->yeasts[product->yeasts_row].type = query.value(3).toInt();
    product->yeasts[product->yeasts_row].form = query.value(4).toInt();
    product->yeasts[product->yeasts_row].min_temperature = query.value(5).toDouble();
    product->yeasts[product->yeasts_row].max_temperature = query.value(6).toDouble();
    product->yeasts[product->yeasts_row].flocculation = query.value(7).toInt();
    product->yeasts[product->yeasts_row].attenuation = query.value(8).toDouble();
    product->yeasts[product->yeasts_row].cells = query.value(9).toDouble();
    product->yeasts[product->yeasts_row].tolerance = query.value(10).toDouble();
    product->yeasts[product->yeasts_row].sta1 = query.value(11).toInt() ? true:false;
    product->yeasts[product->yeasts_row].bacteria = query.value(12).toInt() ? true:false;
    product->yeasts[product->yeasts_row].harvest_top = query.value(13).toInt() ? true:false;
    product->yeasts[product->yeasts_row].harvest_time = query.value(14).toInt();
    product->yeasts[product->yeasts_row].pitch_temperature = query.value(15).toDouble();
    product->yeasts[product->yeasts_row].pofpos = query.value(16).toInt() ? true:false;
    product->yeasts[product->yeasts_row].zymocide = query.value(17).toInt();
    product->yeasts[product->yeasts_row].gr_hl_lo = query.value(18).toInt();
    product->yeasts[product->yeasts_row].sg_lo = query.value(19).toDouble();
    product->yeasts[product->yeasts_row].gr_hl_hi = query.value(20).toInt();
    product->yeasts[product->yeasts_row].sg_hi = query.value(21).toDouble();
    product->yeasts[product->yeasts_row].cost = query.value(22).toDouble();
    product->yeasts[product->yeasts_row].inventory = query.value(23).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);

    //calcYeast();
    is_changed();
    emit refreshAll();
}


void EditProduct::yeast_instock_changed(bool val)
{
    QSqlQuery query;

    qDebug() << "yeast_instock_changed()" << product->yeasts_row << val;

    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)
{
    qDebug() << "yeast_useat_changed()" << product->yeasts_row << val;

    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();
    qDebug() << "Edit yeast row" << product->yeasts_row;
    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) {
        qDebug() << "reject and rollback";
        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;
	}
    }
}

mercurial