src/EditRecipeTab3.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 376
81ae1b4e25db
child 454
2dfead81c72f
permissions
-rw-r--r--

Init est_carb field for new products.

/**
 * EditRecipe.cpp is part of bmsapp.
 *
 * Tab 3, hops
 *
 * bmsapp is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bmsapp is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */



bool EditRecipe::hop_sort_test(const Hops &D1, const Hops &D2)
{
    if (D1.useat > D2.useat)
	return false;
    if (D1.useat < D2.useat)
	return true;
    /* Same useat moments, test time. */
    if (D1.time < D2.time)
	return false;
    if (D1.time > D2.time)
	return true;
    /* Finally consider the amounts */
    return (D1.amount > D2.amount);
}


void EditRecipe::refreshHops()
{
    QString w;
    QWidget* pWidget;
    QHBoxLayout* pLayout;
    QTableWidgetItem *item;

    qDebug() << "refreshHops" << recipe->hops.size();
    std::sort(recipe->hops.begin(), recipe->hops.end(), hop_sort_test);

    const QStringList labels({tr("Origin"), tr("Hop"), tr("Type"), tr("Form"), tr("Alpha"), tr("Use at"), tr("Time"),
                              tr("IBU"), tr("Amount"), tr("Delete"), tr("Edit") });

    ui->hopsTable->setColumnCount(11);
    ui->hopsTable->setColumnWidth(0, 150);     /* Origin	*/
    ui->hopsTable->setColumnWidth(1, 225);     /* Hop		*/
    ui->hopsTable->setColumnWidth(2,  84);     /* Type		*/
    ui->hopsTable->setColumnWidth(3,  84);     /* Form          */
    ui->hopsTable->setColumnWidth(4,  75);     /* Alpha%	*/
    ui->hopsTable->setColumnWidth(5,  75);     /* Added         */
    ui->hopsTable->setColumnWidth(6,  75);     /* Time		*/
    ui->hopsTable->setColumnWidth(7,  60);     /* IBU		*/
    ui->hopsTable->setColumnWidth(8,  90);     /* Amount	*/
    ui->hopsTable->setColumnWidth(9,  80);     /* Delete        */
    ui->hopsTable->setColumnWidth(10, 80);     /* Edit          */
    ui->hopsTable->setHorizontalHeaderLabels(labels);
    ui->hopsTable->verticalHeader()->hide();
    ui->hopsTable->setRowCount(recipe->hops.size());

    for (int i = 0; i < recipe->hops.size(); i++) {

	ui->hopsTable->setItem(i, 0, new QTableWidgetItem(recipe->hops.at(i).origin));
	ui->hopsTable->setItem(i, 1, new QTableWidgetItem(recipe->hops.at(i).name));

    	item = new QTableWidgetItem(QCoreApplication::translate("HopTypes", g_hop_types[recipe->hops.at(i).type]));
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 2, item);

	item = new QTableWidgetItem(QCoreApplication::translate("HopForm", g_hop_forms[recipe->hops.at(i).form]));
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 3, item);

	item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(i).alpha, 2, 'f', 1, '0'));
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 4, item);

	item = new QTableWidgetItem(QCoreApplication::translate("HopUse", g_hop_useat[recipe->hops.at(i).useat]));
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 5, item);

	if (recipe->hops.at(i).useat == 2 || recipe->hops.at(i).useat == 4) {	// Boil or whirlpool
	    item = new QTableWidgetItem(QString("%1 min.").arg(recipe->hops.at(i).time, 1, 'f', 0, '0'));
	} else if (recipe->hops.at(i).useat == 5) {					// Dry-hop
	    item = new QTableWidgetItem(QString("%1 days.").arg(recipe->hops.at(i).time / 1440, 1, 'f', 0, '0'));
	} else {
	    item = new QTableWidgetItem(QString(""));
	}
	item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 6, item);

	double ibu = Utils::toIBU(recipe->hops.at(i).useat, recipe->hops.at(i).form, recipe->preboil_sg, recipe->est_og,
			   recipe->batch_size, recipe->hops.at(i).amount,
	                   recipe->hops.at(i).time, recipe->hops.at(i).alpha, recipe->ibu_method, 0, recipe->hops.at(i).time,
			   0, recipe->boil_time, 0, 0, 0, recipe->hops.at(i).utilisation, recipe->hops.at(i).bu_factor);
	item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0'));
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 7, item);

	if (recipe->hops.at(i).amount < 1.0) {
	    item = new QTableWidgetItem(QString("%1 gr").arg(recipe->hops.at(i).amount * 1000.0, 2, 'f', 1, '0'));
	} else {
	    item = new QTableWidgetItem(QString("%1 kg").arg(recipe->hops.at(i).amount, 4, 'f', 3, '0'));
	}
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->hopsTable->setItem(i, 8, item);

	/* Add the Delete row button */
        pWidget = new QWidget();
        QPushButton* btn_dele = new QPushButton();
        btn_dele->setObjectName(QString("%1").arg(i));  /* Send row with the button */
        btn_dele->setText(tr("Delete"));
        connect(btn_dele, SIGNAL(clicked()), this, SLOT(deleteHopRow_clicked()));
        pLayout = new QHBoxLayout(pWidget);
        pLayout->addWidget(btn_dele);
        pLayout->setContentsMargins(5, 0, 5, 0);
        pWidget->setLayout(pLayout);
        ui->hopsTable->setCellWidget(i, 9, pWidget);

        pWidget = new QWidget();
        QPushButton* btn_edit = new QPushButton();
        btn_edit->setObjectName(QString("%1").arg(i));  /* Send row with the button */
        btn_edit->setText(tr("Edit"));
        connect(btn_edit, SIGNAL(clicked()), this, SLOT(editHopRow_clicked()));
        pLayout = new QHBoxLayout(pWidget);
        pLayout->addWidget(btn_edit);
        pLayout->setContentsMargins(5, 0, 5, 0);
        pWidget->setLayout(pLayout);
        ui->hopsTable->setCellWidget(i, 10, pWidget);
    }
}


void EditRecipe::hop_Flavour_valueChanged(int value)
{
    if (value < 20) {
        ui->hop_tasteShow->setStyleSheet(bar_20);
        ui->hop_tasteShow->setFormat(tr("Very low"));
    } else {
        double s1 = 20.0 / value;
        if (value < 40) {
            ui->hop_tasteShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                  "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #008C00, stop: 1 #008C00);}").arg(s1).arg(s1));
            ui->hop_tasteShow->setFormat(tr("Low"));
        } else {
            double s2 = 40.0 / value;
            if (value < 60) {
                ui->hop_tasteShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                  "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #006C00, stop: %3 #006C00, stop: %4 #008C00, stop: 1 #008C00"
                  ");}").arg(s1).arg(s1).arg(s2).arg(s2));
                ui->hop_tasteShow->setFormat(tr("Moderate"));
            } else {
                double s3 = 60.0 / value;
                if (value < 80) {
                    ui->hop_tasteShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                      "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #006C00, stop: %3 #006C00, stop: %4 #008C00, stop: %5 #008C00, "
                      "stop: %6 #00AC00, stop: 1 #00AC00"
                      ");}").arg(s1).arg(s1).arg(s2).arg(s2).arg(s3).arg(s3));
                    ui->hop_tasteShow->setFormat(tr("High"));
                } else {
                    double s4 = 80.0 / value;
                    ui->hop_tasteShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                      "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #006C00, stop: %3 #006C00, stop: %4 #008C00, stop: %5 #008C00, "
                      "stop: %6 #00AC00, stop: %7 #00AC00, stop: %8 #00CC00, stop: 1 #00CC00"
                      ");}").arg(s1).arg(s1).arg(s2).arg(s2).arg(s3).arg(s3).arg(s4).arg(s4));
                    ui->hop_tasteShow->setFormat(tr("Very high"));
                }
            }
        }
    }
}


void EditRecipe::hop_Aroma_valueChanged(int value)
{
    if (value < 20) {
        ui->hop_aromaShow->setStyleSheet(bar_20);
        ui->hop_aromaShow->setFormat(tr("Very low"));
    } else {
        double s1 = 20.0 / value;
        if (value < 40) {
            ui->hop_aromaShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                  "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #008C00, stop: 1 #008C00);}").arg(s1).arg(s1));
            ui->hop_aromaShow->setFormat(tr("Low"));
        } else {
            double s2 = 40.0 / value;
            if (value < 60) {
                ui->hop_aromaShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                  "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #006C00, stop: %3 #006C00, stop: %4 #008C00, stop: 1 #008C00"
                  ");}").arg(s1).arg(s1).arg(s2).arg(s2));
                ui->hop_aromaShow->setFormat(tr("Moderate"));
            } else {
                double s3 = 60.0 / value;
                if (value < 80) {
                    ui->hop_aromaShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                      "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #006C00, stop: %3 #006C00, stop: %4 #008C00, stop: %5 #008C00, "
                      "stop: %6 #00AC00, stop: 1 #00AC00"
                      ");}").arg(s1).arg(s1).arg(s2).arg(s2).arg(s3).arg(s3));
                    ui->hop_aromaShow->setFormat(tr("High"));
                } else {
                    double s4 = 80.0 / value;
                    ui->hop_aromaShow->setStyleSheet(QString("QProgressBar::chunk {background-color: qlineargradient(x0: 0, x2: 1, "
                      "stop: 0 #004D00, stop: %1 #004D00, stop: %2 #006C00, stop: %3 #006C00, stop: %4 #008C00, stop: %5 #008C00, "
                      "stop: %6 #00AC00, stop: %7 #00AC00, stop: %8 #00CC00, stop: 1 #00CC00"
                      ");}").arg(s1).arg(s1).arg(s2).arg(s2).arg(s3).arg(s3).arg(s4).arg(s4));
                    ui->hop_aromaShow->setFormat(tr("Very high"));
                }
            }
        }
    }
}


void EditRecipe::calcIBUs()
{
    double hop_flavour = 0, hop_aroma = 0, ibus = 0;

    for (int i = 0; i < recipe->hops.size(); i++) {

	ibus += Utils::toIBU(recipe->hops.at(i).useat, recipe->hops.at(i).form, recipe->preboil_sg, recipe->est_og, recipe->batch_size,
			   recipe->hops.at(i).amount,
                           recipe->hops.at(i).time, recipe->hops.at(i).alpha, recipe->ibu_method, 0, recipe->hops.at(i).time,
			   0, recipe->boil_time, 0, 0, 0, recipe->hops.at(i).utilisation, recipe->hops.at(i).bu_factor);
	hop_flavour += Utils::hopFlavourContribution(recipe->hops.at(i).time, recipe->batch_size, recipe->hops.at(i).useat,
				recipe->hops.at(i).amount, recipe->hops.at(i).form);
        hop_aroma += Utils::hopAromaContribution(recipe->hops.at(i).time, recipe->batch_size, recipe->hops.at(i).useat,
				recipe->hops.at(i).amount, recipe->hops.at(i).form);
    }

    hop_flavour = round(hop_flavour * 1000.0 / 5.0) / 10;
    hop_aroma = round(hop_aroma * 1000.0 / 6.0) / 10;
    if (hop_flavour > 100)
        hop_flavour = 100;
    if (hop_aroma > 100)
        hop_aroma = 100;
    qDebug() << "ibu" << recipe->est_ibu << ibus << "flavour" << hop_flavour << "aroma" << hop_aroma << "method" << recipe->ibu_method;

    recipe->est_ibu = ibus;
    ui->est_ibuEdit->setValue(recipe->est_ibu);
    ui->est_ibu2Edit->setValue(recipe->est_ibu);
    ui->est_ibuShow->setValue(recipe->est_ibu);
    ui->hop_tasteShow->setValue(hop_flavour);
    ui->hop_aromaShow->setValue(hop_aroma);
}


void EditRecipe::addHopRow_clicked()
{
    Hops newh;

    qDebug() << "Add hop row";

    for (int i = 0; i < recipe->hops.size(); i++) {
        if (recipe->hops.at(i).amount == 0 && recipe->hops.at(i).alpha == 0)
            return;     // Add only one at a time.
    }

    newh.name = "Select one";
    newh.origin = "";
    newh.amount = 0;
    newh.cost = 0;
    newh.type = 0;
    newh.form = 0;
    newh.useat = 2;
    newh.time = 0;
    newh.alpha = 0;
    newh.beta = 0;
    newh.hsi = 0;
    newh.humulene = 0;
    newh.caryophyllene = 0;
    newh.cohumulone = 0;
    newh.myrcene = 0;
    newh.total_oil = 0;
    newh.utilisation = 20;
    newh.bu_factor = 1;

    recipe->hops.append(newh);
    emit refreshAll();
}


void EditRecipe::deleteHopRow_clicked()
{
    if (recipe->locked || recipe->hops.size() < 1)
	return;

    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
    int row = pb->objectName().toInt();
    qDebug() << "Delete hop row" << row << recipe->hops.size();

    int rc = QMessageBox::warning(this, tr("Delete hop"), tr("Delete %1").arg(recipe->hops.at(row).name),
                    QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
    if (rc == QMessageBox::No)
        return;

    recipe->hops.removeAt(row);
    is_changed();
    emit refreshAll();
}


void EditRecipe::hop_amount_changed(double val)
{
    QTableWidgetItem *item;

    recipe->hops[recipe->hops_row].amount = val / 1000.0;
    item = new QTableWidgetItem(QString("%1 gr").arg(val, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 8, item);

    double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).useat, recipe->hops.at(recipe->hops_row).form, recipe->preboil_sg, recipe->est_og,
                              recipe->batch_size, recipe->hops.at(recipe->hops_row).amount, recipe->hops.at(recipe->hops_row).time,
                              recipe->hops.at(recipe->hops_row).alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).time,
			      0, recipe->boil_time, 0, 0, 0, recipe->hops.at(recipe->hops_row).utilisation, recipe->hops.at(recipe->hops_row).bu_factor);

    ibuEdit->setValue(ibu);
    item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 7, item);

    calcIBUs();
    is_changed();
}


void EditRecipe::hop_alpha_changed(double val)
{
    QTableWidgetItem *item;

    recipe->hops[recipe->hops_row].alpha = val;
    item = new QTableWidgetItem(QString("%1%").arg(val, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 4, item);

    double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).useat, recipe->hops.at(recipe->hops_row).form, recipe->preboil_sg, recipe->est_og,
                              recipe->batch_size, recipe->hops.at(recipe->hops_row).amount, recipe->hops.at(recipe->hops_row).time,
                              recipe->hops.at(recipe->hops_row).alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).time,
                              0, recipe->boil_time, 0, 0, 0, recipe->hops.at(recipe->hops_row).utilisation, recipe->hops.at(recipe->hops_row).bu_factor);

    ibuEdit->setValue(ibu);
    item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 7, item);

    calcIBUs();
    is_changed();
}


void EditRecipe::hop_time_changed(int val)
{
    QTableWidgetItem *item;

    if (recipe->hops.at(recipe->hops_row).useat == 2 || recipe->hops.at(recipe->hops_row).useat == 4) {       // Boil or whirlpool
        item = new QTableWidgetItem(QString("%1 min.").arg(val, 1, 'f', 0, '0'));
	recipe->hops[recipe->hops_row].time = val;
    } else if (recipe->hops.at(recipe->hops_row).useat == 5) {                                   // Dry-hop
        item = new QTableWidgetItem(QString("%1 days.").arg(val, 1, 'f', 0, '0'));
	recipe->hops[recipe->hops_row].time = val * 1440;
    } else {
        item = new QTableWidgetItem(QString(""));
	recipe->hops[recipe->hops_row].time = val;
    }
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 6, item);

    double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).useat, recipe->hops.at(recipe->hops_row).form, recipe->preboil_sg, recipe->est_og,
                              recipe->batch_size, recipe->hops.at(recipe->hops_row).amount, recipe->hops.at(recipe->hops_row).time,
 			      recipe->hops.at(recipe->hops_row).alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).time,
			      0, recipe->boil_time, 0, 0, 0, recipe->hops.at(recipe->hops_row).utilisation, recipe->hops.at(recipe->hops_row).bu_factor);

    ibuEdit->setValue(ibu);
    item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 7, item);

    calcIBUs();
    is_changed();
}


void EditRecipe::hop_select_changed(int val)
{
    QSqlQuery query;
    bool instock = hinstockEdit->isChecked();
    QString w;
    QTableWidgetItem *item;

    if (val < 1)
        return;

    /*
     * Search the hop pointed by the index and instock flag.
     */
    QString sql = "SELECT * FROM inventory_hops ";
    if (instock)
        sql.append("WHERE inventory > 0 ");
    sql.append("ORDER BY origin,name");
    query.prepare(sql);
    query.exec();
    query.first();
    for (int i = 0; i < (val - 1); i++) {
        query.next();
    }

    /*
     * Replace the hop record contents
     */
    recipe->hops[recipe->hops_row].name = query.value("name").toString();
    recipe->hops[recipe->hops_row].origin = query.value("origin").toString();
    recipe->hops[recipe->hops_row].alpha = query.value("alpha").toDouble();
    recipe->hops[recipe->hops_row].beta = query.value("beta").toDouble();
    recipe->hops[recipe->hops_row].humulene = query.value("humulene").toDouble();
    recipe->hops[recipe->hops_row].caryophyllene = query.value("caryophyllene").toDouble();
    recipe->hops[recipe->hops_row].cohumulone = query.value("cohumulone").toDouble();
    recipe->hops[recipe->hops_row].myrcene = query.value("myrcene").toDouble();
    recipe->hops[recipe->hops_row].hsi = query.value("hsi").toDouble();
    recipe->hops[recipe->hops_row].total_oil = query.value("total_oil").toDouble();
    recipe->hops[recipe->hops_row].type = query.value("type").toInt();
    recipe->hops[recipe->hops_row].form = query.value("form").toInt();
    recipe->hops[recipe->hops_row].cost = query.value("cost").toDouble();
    recipe->hops[recipe->hops_row].utilisation = query.value("utilisation").toDouble();
    recipe->hops[recipe->hops_row].bu_factor = query.value("bu_factor").toDouble();

    /*
     * Update the visible fields
     */
    hnameEdit->setText(recipe->hops.at(recipe->hops_row).name);
    horiginEdit->setText(recipe->hops.at(recipe->hops_row).origin);

    double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).useat, recipe->hops.at(recipe->hops_row).form, recipe->preboil_sg, recipe->est_og,
		              recipe->batch_size, recipe->hops.at(recipe->hops_row).amount, recipe->hops.at(recipe->hops_row).time,
			      recipe->hops.at(recipe->hops_row).alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).time,
			      0, recipe->boil_time, 0, 0, 0, recipe->hops.at(recipe->hops_row).utilisation, recipe->hops.at(recipe->hops_row).bu_factor);
    ibuEdit->setValue(ibu);

    ui->hopsTable->setItem(recipe->hops_row, 0, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).origin));
    ui->hopsTable->setItem(recipe->hops_row, 1, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).name));

    QString hoptype = QCoreApplication::translate("HopTypes", g_hop_types[recipe->hops.at(recipe->hops_row).type]);
    item = new QTableWidgetItem(hoptype);
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 2, item);

    item = new QTableWidgetItem(QCoreApplication::translate("HopForm", g_hop_forms[recipe->hops.at(recipe->hops_row).form]));
    //item = new QTableWidgetItem(hop_forms[recipe->hops.at(recipe->hops_row).form]);
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 3, item);

    item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(recipe->hops_row).alpha, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 4, item);

    item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 7, item);

    calcIBUs();
    is_changed();
}


void EditRecipe::hop_instock_changed(bool val)
{
    QSqlQuery query;

    this->hselectEdit->setCurrentIndex(-1);
    this->hselectEdit->clear();
    QString sql = "SELECT origin,name,alpha,inventory FROM inventory_hops ";
    if (val)
        sql.append("WHERE inventory > 0 ");
    sql.append("ORDER BY origin,name");
    query.prepare(sql);
    query.exec();
    query.first();
    this->hselectEdit->addItem("");      // Start with empty value
    for (int i = 0; i < query.size(); i++) {
        this->hselectEdit->addItem(query.value(0).toString()+" - "+query.value(1).toString()+" ("+query.value(2).toString()+"%) "+
                        QString("%1 gr").arg(query.value(3).toDouble() * 1000.0, 2, 'f', 1, '0'));
        query.next();
    }
}


void EditRecipe::hop_useat_changed(int val)
{
    recipe->hops[recipe->hops_row].useat = val;
    QTableWidgetItem *item = new QTableWidgetItem(QCoreApplication::translate("HopUse", g_hop_useat[val]));
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 5, item);

    if (val == 2 || val == 4) {	// Boil or whirlpool
	htimeLabel->setText(tr("Time in minutes:"));
        htimeEdit->setValue(recipe->hops.at(recipe->hops_row).time);
	htimeEdit->setReadOnly(false);
    } else if (val == 5) {	// Dry-hop
        htimeLabel->setText(tr("Time in days:"));
	htimeEdit->setValue(recipe->hops.at(recipe->hops_row).time / 1440);
	htimeEdit->setReadOnly(false);
    } else {
        htimeLabel->setText("");
	htimeEdit->setValue(0);
	htimeEdit->setReadOnly(true);
    }

    is_changed();
    emit refreshAll();
}


void EditRecipe::hop_form_changed(int val)
{
    recipe->hops[recipe->hops_row].form = val;
    QTableWidgetItem *item = new QTableWidgetItem(QCoreApplication::translate("HopForm", g_hop_forms[val]));
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 3, item);

    double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).useat, recipe->hops.at(recipe->hops_row).form, recipe->preboil_sg, recipe->est_og,
                              recipe->batch_size, recipe->hops.at(recipe->hops_row).amount, recipe->hops.at(recipe->hops_row).time,
                              recipe->hops.at(recipe->hops_row).alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).time,
                              0, recipe->boil_time, 0, 0, 0, recipe->hops.at(recipe->hops_row).utilisation, recipe->hops.at(recipe->hops_row).bu_factor);

    ibuEdit->setValue(ibu);
    item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->hopsTable->setItem(recipe->hops_row, 7, item);

    is_changed();
    emit refreshAll();
}


void EditRecipe::editHopRow_clicked()
{
    QSqlQuery query;

    if (recipe->locked)
	return;

    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
    recipe->hops_row = pb->objectName().toInt();
    qDebug() << "Edit hop row" << recipe->hops_row;
    Hops backup = recipe->hops.at(recipe->hops_row);

    QDialog* dialog = new QDialog(this);
    dialog->resize(738, 260);
    QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
    buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
    buttonBox->setGeometry(QRect(30, 210, 671, 32));
    buttonBox->setLayoutDirection(Qt::LeftToRight);
    buttonBox->setOrientation(Qt::Horizontal);
    buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    buttonBox->setCenterButtons(true);
    QLabel *nameLabel = new QLabel(dialog);
    nameLabel->setObjectName(QString::fromUtf8("nameLabel"));
    nameLabel->setText(tr("Current hop:"));
    nameLabel->setGeometry(QRect(10, 10, 141, 20));
    nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *originLabel = new QLabel(dialog);
    originLabel->setObjectName(QString::fromUtf8("originLabel"));
    originLabel->setText(tr("Origin:"));
    originLabel->setGeometry(QRect(10, 40, 141, 20));
    originLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *amountLabel = new QLabel(dialog);
    amountLabel->setObjectName(QString::fromUtf8("amountLabel"));
    amountLabel->setText(tr("Amount in gr:"));
    amountLabel->setGeometry(QRect(10, 100, 141, 20));
    amountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *alphaLabel = new QLabel(dialog);
    alphaLabel->setObjectName(QString::fromUtf8("alphaLabel"));
    alphaLabel->setText(tr("Alpha percent:"));
    alphaLabel->setGeometry(QRect(420, 100, 121, 20));
    alphaLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    htimeLabel = new QLabel(dialog);
    htimeLabel->setObjectName(QString::fromUtf8("htimeLabel"));
    if (recipe->hops.at(recipe->hops_row).useat == 5)		// Dry-hop
	htimeLabel->setText(tr("Time in days:"));
    else if (recipe->hops.at(recipe->hops_row).useat == 2 || recipe->hops.at(recipe->hops_row).useat == 4)	// Boil or whirlpool
    	htimeLabel->setText(tr("Time in minutes:"));
    else
	htimeLabel->setText("");

    htimeLabel->setGeometry(QRect(10, 130, 141, 20));
    htimeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *useatLabel = new QLabel(dialog);
    useatLabel->setObjectName(QString::fromUtf8("useatLabel"));
    useatLabel->setText(tr("Use at:"));
    useatLabel->setGeometry(QRect(10, 160, 141, 20));
    useatLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *formLabel = new QLabel(dialog);
    formLabel->setObjectName(QString::fromUtf8("formLabel"));
    formLabel->setText(tr("Hop form:"));
    formLabel->setGeometry(QRect(380, 160, 121, 20));
    formLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *selectLabel = new QLabel(dialog);
    selectLabel->setObjectName(QString::fromUtf8("selectLabel"));
    selectLabel->setText(tr("Select hop:"));
    selectLabel->setGeometry(QRect(10, 70, 141, 20));
    selectLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *instockLabel = new QLabel(dialog);
    instockLabel->setObjectName(QString::fromUtf8("instockLabel"));
    instockLabel->setText(tr("In stock:"));
    instockLabel->setGeometry(QRect(525, 70, 121, 20));
    instockLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *ibuLabel = new QLabel(dialog);
    ibuLabel->setObjectName(QString::fromUtf8("maxLabel"));
    ibuLabel->setText(tr("Bitterness IBU:"));
    ibuLabel->setGeometry(QRect(420, 130, 121, 20));
    ibuLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

    hselectEdit = new QComboBox(dialog);
    hselectEdit->setObjectName(QString::fromUtf8("selectEdit"));
    hselectEdit->setGeometry(QRect(160, 70, 371, 23));

    hnameEdit = new QLineEdit(dialog);
    hnameEdit->setObjectName(QString::fromUtf8("hnameEdit"));
    hnameEdit->setText(recipe->hops.at(recipe->hops_row).name);
    hnameEdit->setGeometry(QRect(160, 10, 511, 23));
    hnameEdit->setReadOnly(true);
    horiginEdit = new QLineEdit(dialog);
    horiginEdit->setObjectName(QString::fromUtf8("horiginEdit"));
    horiginEdit->setText(recipe->hops.at(recipe->hops_row).origin);
    horiginEdit->setGeometry(QRect(160, 40, 511, 23));
    horiginEdit->setReadOnly(true);
    hamountEdit = new QDoubleSpinBox(dialog);
    hamountEdit->setObjectName(QString::fromUtf8("hamountEdit"));
    hamountEdit->setGeometry(QRect(160, 100, 121, 24));
    hamountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    hamountEdit->setAccelerated(true);
    hamountEdit->setDecimals(1);
    hamountEdit->setMaximum(1000000.0);
    hamountEdit->setSingleStep(0.5);
    hamountEdit->setValue(recipe->hops.at(recipe->hops_row).amount * 1000.0);
    halphaEdit = new QDoubleSpinBox(dialog);
    halphaEdit->setObjectName(QString::fromUtf8("halphaEdit"));
    halphaEdit->setGeometry(QRect(550, 100, 121, 24));
    halphaEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    halphaEdit->setAccelerated(true);
    halphaEdit->setDecimals(1);
    halphaEdit->setMaximum(100.0);
    halphaEdit->setSingleStep(0.1);
    halphaEdit->setValue(recipe->hops.at(recipe->hops_row).alpha);
    htimeEdit = new QSpinBox(dialog);
    htimeEdit->setObjectName(QString::fromUtf8("htimeEdit"));
    htimeEdit->setGeometry(QRect(160, 130, 121, 24));
    htimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    htimeEdit->setAccelerated(true);
    htimeEdit->setMaximum(10000.0);
    if (recipe->hops.at(recipe->hops_row).useat == 2 || recipe->hops.at(recipe->hops_row).useat == 4) {	// Boil or whirlpool
	htimeEdit->setValue(recipe->hops.at(recipe->hops_row).time);
	htimeEdit->setReadOnly(false);
    } else if (recipe->hops.at(recipe->hops_row).useat == 5){	// Dry-hop
	htimeEdit->setValue(recipe->hops.at(recipe->hops_row).time / 1440);
	htimeEdit->setReadOnly(false);
    } else {
	htimeEdit->setReadOnly(true);
    }
    useatEdit = new QComboBox(dialog);
    useatEdit->setObjectName(QString::fromUtf8("useatEdit"));
    useatEdit->setGeometry(QRect(160, 160, 161, 23));
    useatEdit->addItem(tr("Mash"));
    useatEdit->addItem(tr("First wort"));
    useatEdit->addItem(tr("Boil"));
    useatEdit->addItem(tr("Aroma"));
    useatEdit->addItem(tr("Whirlpool"));
    useatEdit->addItem(tr("Dry hop"));
    useatEdit->addItem(tr("Bottling"));
    useatEdit->setCurrentIndex(recipe->hops.at(recipe->hops_row).useat);

    hformEdit = new QComboBox(dialog);
    hformEdit->setObjectName(QString::fromUtf8("formEdit"));
    hformEdit->setGeometry(QRect(510, 160, 161, 23));
    hformEdit->addItem(tr("Pellet"));
    hformEdit->addItem(tr("Plug"));
    hformEdit->addItem(tr("Leaf"));
    hformEdit->addItem(tr("Wet leaf"));
    hformEdit->addItem(tr("Cryo"));
    hformEdit->addItem(tr("Extract"));
    hformEdit->setCurrentIndex(recipe->hops.at(recipe->hops_row).form);

    hinstockEdit = new QCheckBox(dialog);
    hinstockEdit->setObjectName(QString::fromUtf8("hinstockEdit"));
    hinstockEdit->setGeometry(QRect(655, 70, 85, 21));
    hinstockEdit->setChecked(true);

    ibuEdit = new QDoubleSpinBox(dialog);
    ibuEdit->setObjectName(QString::fromUtf8("ibuEdit"));
    ibuEdit->setGeometry(QRect(550, 130, 121, 24));
    ibuEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    ibuEdit->setReadOnly(true);
    ibuEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    ibuEdit->setDecimals(1);
    double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).useat, recipe->hops.at(recipe->hops_row).form, recipe->preboil_sg, recipe->est_og,
                              recipe->batch_size, recipe->hops.at(recipe->hops_row).amount, recipe->hops.at(recipe->hops_row).time,
                              recipe->hops.at(recipe->hops_row).alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).time,
			      0, recipe->boil_time, 0, 0, 0, recipe->hops.at(recipe->hops_row).utilisation, recipe->hops.at(recipe->hops_row).bu_factor);
    ibuEdit->setValue(ibu);

    hop_instock_changed(true);

    connect(hselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_select_changed);
    connect(hamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::hop_amount_changed);
    connect(halphaEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::hop_alpha_changed);
    connect(htimeEdit, QOverload<int>::of(&QSpinBox::valueChanged), this, &EditRecipe::hop_time_changed);
    connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_useat_changed);
    connect(hformEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_form_changed);
    connect(hinstockEdit, &QCheckBox::stateChanged, this, &EditRecipe::hop_instock_changed);
    connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
    connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));

    dialog->setModal(true);
    dialog->exec();
    if (dialog->result() == QDialog::Rejected) {
        qDebug() << "reject and rollback";
        recipe->hops[recipe->hops_row] = backup;
    } else {
	/* Clear time if hop is not used for boil, whirlpool or dry-hop. */
	if (! (recipe->hops.at(recipe->hops_row).useat == 2 ||
	       recipe->hops.at(recipe->hops_row).useat == 4 ||
	       recipe->hops.at(recipe->hops_row).useat == 5)) {
	    if (recipe->hops.at(recipe->hops_row).time) {
		recipe->hops[recipe->hops_row].time = 0;
		is_changed();
	    }
	}
    }

    disconnect(hselectEdit, nullptr, nullptr, nullptr);
    disconnect(hamountEdit, nullptr, nullptr, nullptr);
    disconnect(halphaEdit, nullptr, nullptr, nullptr);
    disconnect(htimeEdit, nullptr, nullptr, nullptr);
    disconnect(useatEdit, nullptr, nullptr, nullptr);
    disconnect(hformEdit, nullptr, nullptr, nullptr);
    disconnect(hinstockEdit, nullptr, nullptr, nullptr);
    disconnect(buttonBox, nullptr, nullptr, nullptr);

    emit refreshAll();
}


void EditRecipe::adjustHops(double factor)
{
    double amount;

    if (recipe->hops.size() == 0)
	return;

    for (int i = 0; i < recipe->hops.size(); i++) {
	amount = recipe->hops.at(i).amount * factor;
	recipe->hops[i].amount = amount;
    }
}

mercurial