src/EditRecipeTab4.cpp

Wed, 20 Apr 2022 22:48:20 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 20 Apr 2022 22:48:20 +0200
changeset 150
fd568cc1dd0e
parent 140
6638609328c2
child 152
58e4ce7dd217
permissions
-rw-r--r--

Implemented the last widgets on the first tab and added the needed functions for them such as scaling the recipe. This is the last part of the recipe editor, now ready for testing.

/**
 * EditRecipe.cpp is part of bmsapp.
 *
 * tab 4, miscs.
 *
 * 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::misc_sort_test(const Miscs &D1, const Miscs &D2)
{
    if (D1.m_use_use > D2.m_use_use)
	return false;
    if (D1.m_use_use < D2.m_use_use)
	return true;
    if (D1.m_type > D2.m_type)
	return false;
    if (D1.m_type < D2.m_type)
	return true;
    return (D1.m_amount > D2.m_amount);
}


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

    qDebug() << "refreshMiscs" << recipe->miscs.size();
    std::sort(recipe->miscs.begin(), recipe->miscs.end(), misc_sort_test);

    /*
     * During filling the table turn off the cellChanged signal because every cell that is filled
     * triggers the cellChanged signal. The QTableWidget has no better signal to use.
     */
    this->ignoreChanges = true;

    const QStringList labels({tr("Ingredient"), tr("Type"), tr("Use at"), tr("Time"), tr("Amount"), tr("Delete"), tr("Edit") });

    ui->miscsTable->setColumnCount(7);
    ui->miscsTable->setColumnWidth(0, 300);	/* Ingredient	*/
    ui->miscsTable->setColumnWidth(1, 100);	/* Type		*/
    ui->miscsTable->setColumnWidth(2, 100);	/* Added	*/
    ui->miscsTable->setColumnWidth(3,  75);	/* Time		*/
    ui->miscsTable->setColumnWidth(4,  90);	/* Amount	*/
    ui->miscsTable->setColumnWidth(5,  80);	/* Delete	*/
    ui->miscsTable->setColumnWidth(6,  80);	/* Edit		*/
    ui->miscsTable->setHorizontalHeaderLabels(labels);
    ui->miscsTable->verticalHeader()->hide();
    ui->miscsTable->setRowCount(recipe->miscs.size());

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

	ui->miscsTable->setItem(i, 0, new QTableWidgetItem(recipe->miscs.at(i).m_name));

	item = new QTableWidgetItem(m_types[recipe->miscs.at(i).m_type]);
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->miscsTable->setItem(i, 1, item);

	item = new QTableWidgetItem(m_uses[recipe->miscs.at(i).m_use_use]);
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->miscsTable->setItem(i, 2, item);

	if (recipe->miscs.at(i).m_use_use == 2) {	// Boil
	    item = new QTableWidgetItem(QString("%1 min.").arg(recipe->miscs.at(i).m_time, 1, 'f', 0, '0'));
	} else if (recipe->miscs.at(i).m_use_use == 3 || recipe->miscs.at(i).m_use_use == 4) {	// Primary or secondary
	    item = new QTableWidgetItem(QString("%1 days.").arg(recipe->miscs.at(i).m_time / 1440, 1, 'f', 0, '0'));
	} else {
	    item = new QTableWidgetItem(QString(""));
	}
	item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->miscsTable->setItem(i, 3, item);

	if (recipe->miscs.at(i).m_amount_is_weight)
	    item = new QTableWidgetItem(QString("%1 gr").arg(recipe->miscs.at(i).m_amount * 1000.0, 3, 'f', 2, '0'));
	else
	    item = new QTableWidgetItem(QString("%1 ml").arg(recipe->miscs.at(i).m_amount * 1000.0, 3, 'f', 2, '0'));
	item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->miscsTable->setItem(i, 4, item);

	/*
	 * Add the Delete and Edit row buttons.
	 * Not for water agents, these are set on the water tab.
	 */
	if (recipe->miscs.at(i).m_type == 4) {
	    ui->miscsTable->removeCellWidget(i, 5);
	    ui->miscsTable->removeCellWidget(i, 6);
	} 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(deleteMiscRow_clicked()));
            pLayout = new QHBoxLayout(pWidget);
            pLayout->addWidget(btn_dele);
            pLayout->setContentsMargins(5, 0, 5, 0);
            pWidget->setLayout(pLayout);
            ui->miscsTable->setCellWidget(i, 5, 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(editMiscRow_clicked()));
            pLayout = new QHBoxLayout(pWidget);
            pLayout->addWidget(btn_edit);
            pLayout->setContentsMargins(5, 0, 5, 0);
            pWidget->setLayout(pLayout);
            ui->miscsTable->setCellWidget(i, 6, pWidget);
	}

	/*
	 * Update the water agents.
	 */
	if (recipe->miscs.at(i).m_type == 4) {
	    if (recipe->miscs.at(i).m_name == "CaCl2") {
		ui->bs_cacl2Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "CaSO4") {
		ui->bs_caso4Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "MgSO4") {
		ui->bs_mgso4Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "NaCl") {
		ui->bs_naclEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "MgCl2") {
		ui->bs_mgcl2Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "NaHCO3") {
		ui->bs_nahco3Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "CaCO3") {
		ui->bs_caco3Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "Melkzuur" || recipe->miscs.at(i).m_name == "Lactic") {
		recipe->wa_acid_name = 0;
		recipe->wa_acid_perc = my_acids.at(0).AcidPrc;
		ui->mw_acidPick->setCurrentIndex(0);
		ui->mw_acidpercEdit->setValue(my_acids.at(0).AcidPrc);
		ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "Zoutzuur" || recipe->miscs.at(i).m_name == "Hydrochloric") {
                recipe->wa_acid_name = 1;
                recipe->wa_acid_perc = my_acids.at(1).AcidPrc;
		ui->mw_acidPick->setCurrentIndex(1);
                ui->mw_acidpercEdit->setValue(my_acids.at(1).AcidPrc);
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "Fosforzuur" || recipe->miscs.at(i).m_name == "Phosphoric") {
                recipe->wa_acid_name = 2;
                recipe->wa_acid_perc = my_acids.at(2).AcidPrc;
		ui->mw_acidPick->setCurrentIndex(2);
                ui->mw_acidpercEdit->setValue(my_acids.at(2).AcidPrc);
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    } else if (recipe->miscs.at(i).m_name == "Zwavelzuur" || recipe->miscs.at(i).m_name == "Sulfuric") {
                recipe->wa_acid_name = 3;
                recipe->wa_acid_perc = my_acids.at(3).AcidPrc;
		ui->mw_acidPick->setCurrentIndex(3);
                ui->mw_acidpercEdit->setValue(my_acids.at(3).AcidPrc);
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
	    }
	}
    }
    this->ignoreChanges = false;
}


/*
 * Manipulate the memory array and update the miscs table.
 */
void EditRecipe::brewing_salt_sub(QString salt, double val)
{
    QTableWidgetItem *item;

    val = round(val * 100.0) / 100.0;
    if (val == 0) {
	/*
	 * Remove this salt if it is in the table.
	 */
	for (int i = 0; i < recipe->miscs.size(); i++) {
	    if (salt.contains(recipe->miscs.at(i).m_name)) {
		qDebug() << "  brewing_salt_sub delete" << salt;
		recipe->miscs.removeAt(i);
		refreshMiscs();
		return;
	    }
	}
	qDebug() << "  brewing_salt_sub delete error";
	return;
    }

    /*
     * First see if this salt is in the table.
     * If it is, update the amount.
     */
    for (int i = 0; i < recipe->miscs.size(); i++) {
	if (salt.contains(recipe->miscs.at(i).m_name)) {
	    recipe->miscs[i].m_amount = val / 1000.0;
	    if (recipe->miscs.at(i).m_amount_is_weight)
            	item = new QTableWidgetItem(QString("%1 gr").arg(val, 3, 'f', 2, '0'));
            else
	    	item = new QTableWidgetItem(QString("%1 ml").arg(val, 3, 'f', 2, '0'));
	    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
	    ui->miscsTable->setItem(i, 4, item);
	    return;
	}
    }

    /*
     * We need a new entry. Search in the database is tricky because
     * we are here with possible more names for the same salt. The
     * name can be like 'Lactic Melkzuur'. So we select only the
     * brewing salts and manually check their names.
     */
    QSqlQuery query("SELECT * FROM inventory_miscs WHERE type = 4");
    while (query.next()) {
	if (salt.contains(query.value(1).toString())) {
	    qDebug() << "  found it, append";
	    Miscs m;
	    m.m_name = query.value(1).toString();
            m.m_amount = val / 1000.0;
            m.m_type = query.value(2).toInt();
            m.m_use_use = query.value(3).toInt();
            m.m_time = query.value(4).toDouble();
            m.m_amount_is_weight = query.value(5).toInt() ? true:false;
            m.m_cost = query.value(10).toDouble();
            recipe->miscs.append(m);
	    refreshMiscs();
	    return;
	}
    }

    qDebug() << "brewing_salt_sub, nothing done." << salt << val;
}


/*
 * Edit brewing salt and recalculate.
 */
void EditRecipe::set_brewing_salt(QString salt, double val)
{
    if (this->ignoreChanges)
	return;

    val = round(val * 100.0) / 100.0;
    qDebug() << "set_brewing_salt" << salt << val;
    brewing_salt_sub(salt, val);
    calcWater();
    is_changed();
}


void EditRecipe::addMiscRow_clicked()
{
    Miscs newm;

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

    newm.m_name = "Select one";
    newm.m_amount = 0;
    newm.m_type = 0;
    newm.m_use_use = 0;
    newm.m_time = 0;
    newm.m_amount_is_weight = true;
    newm.m_cost = 0;
    recipe->miscs.append(newm);
    is_changed();
    emit refreshAll();
}


void EditRecipe::deleteMiscRow_clicked()
{
    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
    int row = pb->objectName().toInt();
    qDebug() << "Delete misc row" << row << recipe->miscs.size();

    if (recipe->miscs.size() < 1)
        return;

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

    this->ignoreChanges = true;
    recipe->miscs.removeAt(row);
    this->ignoreChanges = false;
    is_changed();
    emit refreshAll();
}


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

    qDebug() << "misc_amount_changed()" << recipe->miscs_row << val;
    this->ignoreChanges = true;

    recipe->miscs[recipe->miscs_row].m_amount = val / 1000.0;
    if (recipe->miscs.at(recipe->miscs_row).m_amount_is_weight) {
        item = new QTableWidgetItem(QString("%1 gr").arg(recipe->miscs.at(recipe->miscs_row).m_amount * 1000.0, 3, 'f', 2, '0'));
    } else {
        item = new QTableWidgetItem(QString("%1 ml").arg(recipe->miscs.at(recipe->miscs_row).m_amount * 1000.0, 3, 'f', 2, '0'));
    }
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 4, item);

    this->ignoreChanges = false;
    is_changed();
}


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

    qDebug() << "misc_time_changed()" << recipe->miscs_row << val;

    this->ignoreChanges = true;
    if (recipe->miscs.at(recipe->miscs_row).m_use_use == 2) {       // Boil
	recipe->miscs[recipe->miscs_row].m_time = val;
	item = new QTableWidgetItem(QString("%1 min.").arg(val, 1, 'f', 0, '0'));
    } else if (recipe->miscs.at(recipe->miscs_row).m_use_use == 3 || recipe->miscs.at(recipe->miscs_row).m_use_use == 4) {  // Primary or secondary
	recipe->miscs[recipe->miscs_row].m_time = val * 1440;
	item = new QTableWidgetItem(QString("%1 days.").arg(val, 1, 'f', 0, '0'));
    } else {
	item = new QTableWidgetItem(QString(""));
    }
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 3, item);

    this->ignoreChanges = false;
    is_changed();
}


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

    if (val < 1)
        return;

    qDebug() << "misc_select_changed()" << recipe->miscs_row << val << instock;

    /*
     * Search the misc ingredient pointed by the index and instock flag.
     */
    QString sql = "SELECT name,type,use_use,time,amount_is_weight,cost FROM inventory_miscs WHERE ";
    if (instock)
        sql.append("inventory > 0 AND ");
    sql.append("type != 4 ORDER BY name");
    qDebug() << sql;
    query.prepare(sql);
    query.exec();
    query.first();
    for (int i = 0; i < (val - 1); i++) {
        query.next();
    }
    qDebug() << "found" << query.value(0).toString();

    /*
     * Replace the misc record contents
     */
    this->ignoreChanges = true;
    recipe->miscs[recipe->miscs_row].m_name = query.value(0).toString();
    recipe->miscs[recipe->miscs_row].m_type = query.value(1).toInt();
    recipe->miscs[recipe->miscs_row].m_use_use = query.value(2).toInt();
    recipe->miscs[recipe->miscs_row].m_time = query.value(3).toDouble();
    recipe->miscs[recipe->miscs_row].m_amount_is_weight = query.value(4).toInt() ? true:false;
    recipe->miscs[recipe->miscs_row].m_cost = query.value(5).toDouble();

    /*
     * Update the visible fields
     */
    mnameEdit->setText(recipe->miscs.at(recipe->miscs_row).m_name);
    ui->miscsTable->setItem(recipe->miscs_row, 0, new QTableWidgetItem(recipe->miscs.at(recipe->miscs_row).m_name));

    item = new QTableWidgetItem(m_types[recipe->miscs.at(recipe->miscs_row).m_type]);
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 1, item);

    item = new QTableWidgetItem(m_uses[recipe->miscs.at(recipe->miscs_row).m_use_use]);
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 2, item);
    useatEdit->setCurrentIndex(recipe->miscs.at(recipe->miscs_row).m_use_use);

    if (recipe->miscs.at(recipe->miscs_row).m_use_use == 3 || recipe->miscs.at(recipe->miscs_row).m_use_use == 4) {     // Fermentation stages
        mtimeEdit->setValue(recipe->miscs.at(recipe->miscs_row).m_time / 1440);
        mtimeEdit->setReadOnly(false);
	mtimeLabel->setText(tr("Time in days:"));
	item = new QTableWidgetItem(QString("%1 days.").arg(recipe->miscs.at(recipe->miscs_row).m_time / 1440, 1, 'f', 0, '0'));
    } else if (recipe->miscs.at(recipe->miscs_row).m_use_use == 2) {    // Boil
        mtimeEdit->setValue(recipe->miscs.at(recipe->miscs_row).m_time);
        mtimeEdit->setReadOnly(false);
	mtimeLabel->setText(tr("Time in minutes:"));
	item = new QTableWidgetItem(QString("%1 min.").arg(recipe->miscs.at(recipe->miscs_row).m_time, 1, 'f', 0, '0'));
    } else {
        mtimeEdit->setReadOnly(true);
	mtimeLabel->setText("");
	item = new QTableWidgetItem(QString(""));
    }
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 3, item);

    if (recipe->miscs.at(recipe->miscs_row).m_amount_is_weight) {
	mamountLabel->setText(tr("Amount in gr:"));
	item = new QTableWidgetItem(QString("%1 gr").arg(recipe->miscs.at(recipe->miscs_row).m_amount * 1000.0, 3, 'f', 2, '0'));
    } else {
	mamountLabel->setText(tr("Amount in ml:"));
	item = new QTableWidgetItem(QString("%1 ml").arg(recipe->miscs.at(recipe->miscs_row).m_amount * 1000.0, 3, 'f', 2, '0'));
    }
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 4, item);

    this->ignoreChanges = false;
    is_changed();
    emit refreshAll();
}


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

    qDebug() << "misc_instock_changed()" << recipe->miscs_row << val;

    this->mselectEdit->setCurrentIndex(-1);
    this->mselectEdit->clear();
    QString sql = "SELECT name,type,amount_is_weight,inventory FROM inventory_miscs WHERE ";
    if (val)
        sql.append("inventory > 0 AND ");
    sql.append("type != 4 ORDER BY name");
    query.prepare(sql);
    query.exec();
    query.first();
    this->mselectEdit->addItem("");      // Start with empty value
    for (int i = 0; i < query.size(); i++) {
        this->mselectEdit->addItem(query.value(0).toString()+ " (" + m_types[query.value(1).toInt()] + ") " +
                        QString("%1 %2").arg(query.value(3).toDouble() * 1000.0, 3, 'f', 2, '0').arg(query.value(2).toInt()?"gr":"ml"));
        query.next();
    }
}


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

    qDebug() << "misc_useat_changed" << val;
    this->ignoreChanges = true;
    recipe->miscs[recipe->miscs_row].m_use_use = val;
    item = new QTableWidgetItem(m_uses[val]);
    item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 2, item);

    if (val == 3 || val == 4) {     // Fermentation stages
	recipe->miscs[recipe->miscs_row].m_time = mtimeEdit->value() * 1440;
        mtimeEdit->setReadOnly(false);
        mtimeLabel->setText(tr("Time in days:"));
        item = new QTableWidgetItem(QString("%1 days.").arg(recipe->miscs.at(recipe->miscs_row).m_time / 1440, 1, 'f', 0, '0'));
    } else if (val == 2) {    // Boil
	recipe->miscs[recipe->miscs_row].m_time = mtimeEdit->value();
        mtimeEdit->setReadOnly(false);
        mtimeLabel->setText(tr("Time in minutes:"));
        item = new QTableWidgetItem(QString("%1 min.").arg(recipe->miscs.at(recipe->miscs_row).m_time, 1, 'f', 0, '0'));
    } else {
	recipe->miscs[recipe->miscs_row].m_time = 0;
	mtimeEdit->setValue(0);
        mtimeEdit->setReadOnly(true);
        mtimeLabel->setText("");
        item = new QTableWidgetItem(QString(""));
    }
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->miscsTable->setItem(recipe->miscs_row, 3, item);

    this->ignoreChanges = false;
    is_changed();
}


void EditRecipe::editMiscRow_clicked()
{
    QSqlQuery query;

    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
    recipe->miscs_row = pb->objectName().toInt();
    qDebug() << "Edit misc row" << recipe->miscs_row;
    Miscs backup = recipe->miscs.at(recipe->miscs_row);

    QDialog* dialog = new QDialog(this);
    dialog->resize(738, 230);
    QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
    buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
    buttonBox->setGeometry(QRect(30, 180, 671, 32));
    buttonBox->setLayoutDirection(Qt::LeftToRight);
    buttonBox->setOrientation(Qt::Horizontal);
    buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    buttonBox->setCenterButtons(true);

    QLabel *nameLabel = new QLabel(dialog);
    nameLabel->setObjectName(QString::fromUtf8("nameLabel"));
    nameLabel->setText(tr("Current ingredient:"));
    nameLabel->setGeometry(QRect(10, 10, 141, 20));
    nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

    mamountLabel = new QLabel(dialog);
    mamountLabel->setObjectName(QString::fromUtf8("mamountLabel"));
    if (recipe->miscs.at(recipe->miscs_row).m_amount_is_weight)
    	mamountLabel->setText(tr("Amount in gr:"));
    else
	mamountLabel->setText(tr("Amount in ml:"));
    mamountLabel->setGeometry(QRect(10, 70, 141, 20));
    mamountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

    mtimeLabel = new QLabel(dialog);
    mtimeLabel->setObjectName(QString::fromUtf8("mtimeLabel"));
    if (recipe->miscs.at(recipe->miscs_row).m_use_use == 3 || recipe->miscs.at(recipe->miscs_row).m_use_use == 4)	// Fermentation stages
        mtimeLabel->setText(tr("Time in days:"));
    else if (recipe->miscs.at(recipe->miscs_row).m_use_use == 2)  // Boil
        mtimeLabel->setText(tr("Time in minutes:"));
    else
        mtimeLabel->setText("");
    mtimeLabel->setGeometry(QRect(10, 100, 141, 20));
    mtimeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

    QLabel *selectLabel = new QLabel(dialog);
    selectLabel->setObjectName(QString::fromUtf8("selectLabel"));
    selectLabel->setText(tr("Select ingredient:"));
    selectLabel->setGeometry(QRect(10, 40, 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, 40, 121, 20));
    instockLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

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

    mnameEdit = new QLineEdit(dialog);
    mnameEdit->setObjectName(QString::fromUtf8("mnameEdit"));
    mnameEdit->setText(recipe->miscs.at(recipe->miscs_row).m_name);
    mnameEdit->setGeometry(QRect(160, 10, 511, 23));
    mnameEdit->setReadOnly(true);

    mamountEdit = new QDoubleSpinBox(dialog);
    mamountEdit->setObjectName(QString::fromUtf8("mamountEdit"));
    mamountEdit->setGeometry(QRect(160, 70, 121, 24));
    mamountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    mamountEdit->setAccelerated(true);
    mamountEdit->setDecimals(2);
    mamountEdit->setMaximum(1000000.0);
    mamountEdit->setSingleStep(0.1);
    mamountEdit->setValue(recipe->miscs.at(recipe->miscs_row).m_amount * 1000.0);

    mtimeEdit = new QSpinBox(dialog);
    mtimeEdit->setObjectName(QString::fromUtf8("mtimeEdit"));
    mtimeEdit->setGeometry(QRect(160, 100, 121, 24));
    mtimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    mtimeEdit->setAccelerated(true);
    mtimeEdit->setMaximum(10000.0);
    if (recipe->miscs.at(recipe->miscs_row).m_use_use == 3 || recipe->miscs.at(recipe->miscs_row).m_use_use == 4) {	// Fermentation stages
	mtimeEdit->setValue(recipe->miscs.at(recipe->miscs_row).m_time / 1440);
        mtimeEdit->setReadOnly(false);
    } else if (recipe->miscs.at(recipe->miscs_row).m_use_use == 2) {	// Boil
	mtimeEdit->setValue(recipe->miscs.at(recipe->miscs_row).m_time);
        mtimeEdit->setReadOnly(false);
    } else {
	mtimeEdit->setReadOnly(true);
    }

    useatEdit = new QComboBox(dialog);
    useatEdit->setObjectName(QString::fromUtf8("useatEdit"));
    useatEdit->setGeometry(QRect(160, 130, 161, 23));
    useatEdit->addItem(tr("Starter"));
    useatEdit->addItem(tr("Mash"));
    useatEdit->addItem(tr("Boil"));
    useatEdit->addItem(tr("Primary"));
    useatEdit->addItem(tr("Secondary"));
    useatEdit->addItem(tr("Bottling"));
    useatEdit->setCurrentIndex(recipe->miscs.at(recipe->miscs_row).m_use_use);

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

    misc_instock_changed(true);

    connect(mselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::misc_select_changed);
    connect(mamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::misc_amount_changed);
    connect(mtimeEdit, QOverload<int>::of(&QSpinBox::valueChanged), this, &EditRecipe::misc_time_changed);
    connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::misc_useat_changed);
    connect(minstockEdit, &QCheckBox::stateChanged, this, &EditRecipe::misc_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->miscs[recipe->miscs_row] = backup;
    } else {
        /* Clear time if misc is not used for boil or fermentation. */
        if (! (recipe->miscs.at(recipe->miscs_row).m_use_use == 2 ||
               recipe->miscs.at(recipe->miscs_row).m_use_use == 3 ||
               recipe->miscs.at(recipe->miscs_row).m_use_use == 4)) {
            if (recipe->miscs.at(recipe->miscs_row).m_time) {
                recipe->miscs[recipe->miscs_row].m_time = 0;
                is_changed();
            }
        }
    }

    disconnect(mselectEdit, nullptr, nullptr, nullptr);
    disconnect(mamountEdit, nullptr, nullptr, nullptr);
    disconnect(mtimeEdit, nullptr, nullptr, nullptr);
    disconnect(useatEdit, nullptr, nullptr, nullptr);
    disconnect(minstockEdit, nullptr, nullptr, nullptr);
    disconnect(buttonBox, nullptr, nullptr, nullptr);

    emit refreshAll();
}


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

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

    this->ignoreChanges = true;
    for (int i = 0; i < recipe->miscs.size(); i++) {
	amount = recipe->miscs.at(i).m_amount * factor;
	recipe->miscs[i].m_amount = amount;

	/*
         * Update the water agents.
         */
        if (recipe->miscs.at(i).m_type == 4) {
            if (recipe->miscs.at(i).m_name == "CaCl2") {
                ui->bs_cacl2Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "CaSO4") {
                ui->bs_caso4Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "MgSO4") {
                ui->bs_mgso4Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "NaCl") {
                ui->bs_naclEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "MgCl2") {
                ui->bs_mgcl2Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "NaHCO3") {
                ui->bs_nahco3Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "CaCO3") {
                ui->bs_caco3Edit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "Melkzuur" || recipe->miscs.at(i).m_name == "Lactic") {
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "Zoutzuur" || recipe->miscs.at(i).m_name == "Hydrochloric") {
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "Fosforzuur" || recipe->miscs.at(i).m_name == "Phosphoric") {
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            } else if (recipe->miscs.at(i).m_name == "Zwavelzuur" || recipe->miscs.at(i).m_name == "Sulfuric") {
                ui->mw_acidvolEdit->setValue(recipe->miscs.at(i).m_amount * 1000.0);
            }
        }
    }
    this->ignoreChanges = false;
}

mercurial