--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EditProductTab7.cpp Thu Apr 28 22:49:13 2022 +0200 @@ -0,0 +1,682 @@ +/** + * EditProduct.cpp is part of bmsapp. + * + * tab 7, mash. + * + * 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/>. + */ + + +void EditProduct::refreshMashs() +{ + QString w; + QWidget* pWidget; + QHBoxLayout* pLayout; + QTableWidgetItem *item; + QIcon down_icon, up_icon; + + qDebug() << "refreshMashs" << product->mashs.size(); + + down_icon.addFile(QString::fromUtf8(":/icons/silk/bullet_arrow_down.png"), QSize(), QIcon::Normal, QIcon::Off); + up_icon.addFile(QString::fromUtf8(":/icons/silk/bullet_arrow_up.png"), QSize(), QIcon::Normal, QIcon::Off); + + const QStringList labels({tr("Step name"), tr("Type"), tr("Start"), tr("End"), tr("Rest"), tr("Ramp"), + tr("Inf/dec"), tr("Inf/dec"), tr("Volume"), tr("W/G ratio"), "", "", tr("Delete"), tr("Edit") }); + + ui->mashsTable->setColumnCount(14); + ui->mashsTable->setColumnWidth(0, 189); /* Step name */ + ui->mashsTable->setColumnWidth(1, 100); /* Type */ + ui->mashsTable->setColumnWidth(2, 70); /* Start temp */ + ui->mashsTable->setColumnWidth(3, 70); /* End temp */ + ui->mashsTable->setColumnWidth(4, 70); /* Rest time */ + ui->mashsTable->setColumnWidth(5, 70); /* Ramp time */ + ui->mashsTable->setColumnWidth(6, 70); /* Infusion vol */ + ui->mashsTable->setColumnWidth(7, 70); /* Infusion tmp */ + ui->mashsTable->setColumnWidth(8, 70); /* Volume */ + ui->mashsTable->setColumnWidth(9, 80); /* W/G ratio */ + ui->mashsTable->setColumnWidth(10, 30); /* Up button */ + ui->mashsTable->setColumnWidth(11, 30); /* Down button */ + ui->mashsTable->setColumnWidth(12, 80); /* Delete */ + ui->mashsTable->setColumnWidth(13, 80); /* Edit */ + ui->mashsTable->setHorizontalHeaderLabels(labels); + ui->mashsTable->verticalHeader()->hide(); + ui->mashsTable->setRowCount(product->mashs.size()); + + for (int i = 0; i < product->mashs.size(); i++) { + + ui->mashsTable->setItem(i, 0, new QTableWidgetItem(product->mashs.at(i).step_name)); + + item = new QTableWidgetItem(step_types[product->mashs.at(i).step_type]); + item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 1, item); + + item = new QTableWidgetItem(QString("%1 °C").arg(product->mashs.at(i).step_temp, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 2, item); + + item = new QTableWidgetItem(QString("%1 °C").arg(product->mashs.at(i).end_temp, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 3, item); + + item = new QTableWidgetItem(QString("%1 min").arg(product->mashs.at(i).step_time, 1, 'f', 0, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 4, item); + + item = new QTableWidgetItem(QString("%1 min").arg(product->mashs.at(i).ramp_time, 1, 'f', 0, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 5, item); + + if (product->mashs.at(i).step_infuse_amount > 0) { + item = new QTableWidgetItem(QString("%1 L").arg(product->mashs.at(i).step_infuse_amount, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 6, item); + item = new QTableWidgetItem(QString("%1 °C").arg(product->mashs.at(i).step_infuse_temp, 3, 'f', 2, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 7, item); + } else { + ui->mashsTable->removeCellWidget(i, 6); + ui->mashsTable->removeCellWidget(i, 7); + } + + item = new QTableWidgetItem(QString("%1 L").arg(product->mashs.at(i).step_volume, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 8, item); + + item = new QTableWidgetItem(QString("%1 L/kg").arg(product->mashs.at(i).step_wg_ratio, 3, 'f', 2, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(i, 9, item); + + if (i > 0) { + pWidget = new QWidget(); + QPushButton* btn_up = new QPushButton(); + btn_up->setObjectName(QString("%1").arg(i)); /* Send row with the button */ + btn_up->setIcon(up_icon); + connect(btn_up, SIGNAL(clicked()), this, SLOT(upMashRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_up); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->mashsTable->setCellWidget(i, 10, pWidget); + } else { + ui->mashsTable->removeCellWidget(i, 10); + } + + if (i < (product->mashs.size() - 1)) { + pWidget = new QWidget(); + QPushButton* btn_down = new QPushButton(); + btn_down->setObjectName(QString("%1").arg(i)); /* Send row with the button */ + btn_down->setIcon(down_icon); + connect(btn_down, SIGNAL(clicked()), this, SLOT(downMashRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_down); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->mashsTable->setCellWidget(i, 11, pWidget); + } else { + ui->mashsTable->removeCellWidget(i, 11); + } + + 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(deleteMashRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_dele); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->mashsTable->setCellWidget(i, 12, pWidget); + + pWidget = new QWidget(); + QPushButton* btn_edit = new QPushButton(); + btn_edit->setObjectName(QString("%1").arg(i)); /* Send row with the button */ + btn_edit->setText(tr("Edit")); + connect(btn_edit, SIGNAL(clicked()), this, SLOT(editMashRow_clicked())); + pLayout = new QHBoxLayout(pWidget); + pLayout->addWidget(btn_edit); + pLayout->setContentsMargins(5, 0, 5, 0); + pWidget->setLayout(pLayout); + ui->mashsTable->setCellWidget(i, 13, pWidget); + } +} + + +double EditProduct::infusionVol(double step_infused, double step_mashkg, double infuse_temp, double step_temp, double last_temp) +{ + double a = last_temp * (equip_tun_weight * equip_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + double b = step_temp * (equip_tun_weight * equip_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + double vol = round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)) * 100.0) / 100.0; + + if (vol < 0) + vol = 0; + qDebug() << " infusionVol(" << step_infused << "," << step_mashkg << "," << infuse_temp <<"," << step_temp << "," << last_temp << "):" << vol; + return vol; +} + + +double EditProduct::decoctionVol(double step_volume, double step_temp, double prev_temp) +{ + double a = (equip_tun_weight * equip_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); + double b = SpecificHeatWater * (99 - step_temp); + double vol = 0; + + if (b > 0) + vol = round((a / b) * 1000000.0) / 1000000.0; + qDebug() << " decoctionVol(" << step_volume << "," << step_temp << "," << prev_temp << "):" << vol; + return vol; +} + + +void EditProduct::calcMash() +{ + double infused = 0, vol, a, b, temp; + int i, j, n; + double lasttemp = 18.0; + double graintemp = 18.0; + double tuntemp = 18.0; + + product->mashs_time = 0; + + if (product->mashs.size() && product->mashs_kg > 0) { + qDebug() << "calcMash()"; + + for (i = 0; i < product->mashs.size(); i++) { + if (product->mashs.at(i).step_type == 0) { // Infusion + if (i == 0) { + // First mash step, temperature from the mashtun and malt. + n = 20; // tun is preheated. + tuntemp = product->mashs.at(i).step_temp; + for (j = 0; j < n; j++) { + a = product->mashs_kg * graintemp * SpecificHeatMalt + equip_tun_weight * tuntemp * equip_tun_specific_heat; + b = product->mashs[i].step_temp * + (equip_tun_weight * equip_tun_specific_heat + + product->mashs.at(i).step_infuse_amount * SpecificHeatWater + + product->mashs_kg * SpecificHeatMalt) - + SlakingHeat * product->mashs_kg; + if (product->mashs.at(i).step_infuse_amount > 0) { + temp = (b - a) / (product->mashs.at(i).step_infuse_amount * SpecificHeatWater); + } else { + temp = 99; + } + tuntemp += (temp - tuntemp) / 2; + product->mashs[i].step_infuse_temp = round(temp * 1000000.0) / 1000000.0; + } + qDebug() << " init infuse temp:" << product->mashs.at(i).step_infuse_temp; + } else { + // Calculate amount of infusion water. + product->mashs[i].step_infuse_amount = + infusionVol(infused, product->mashs_kg, product->mashs.at(i).step_infuse_temp, product->mashs.at(i).step_temp, lasttemp); + qDebug() << i << " vol:" << product->mashs.at(i).step_infuse_amount << "temp:" << product->mashs.at(i).step_infuse_temp; + } + infused += product->mashs.at(i).step_infuse_amount; + } else if (product->mashs.at(i).step_type == 1) { // Temperature + if (i > 0) + product->mashs[i].step_infuse_amount = 0; + product->mashs[i].step_infuse_temp = 0; + } else if (product->mashs.at(i).step_type == 2) { // Decoction + product->mashs[i].step_infuse_amount = decoctionVol(infused, product->mashs.at(i).step_temp, lasttemp); + product->mashs[i].step_infuse_temp = 99; + } + product->mashs[i].step_volume = infused; + //qDebug() << i << " type:" << product->mashs.at(i).step_type << "volume:" << product->mashs.at(i).step_infuse_amount << "temp:" << product->mashs.at(i).step_infuse_temp; + lasttemp = product->mashs.at(i).step_temp; + product->mashs_time += product->mashs.at(i).step_time; + if (i > 0) + product->mashs_time += product->mashs.at(i).ramp_time; + product->mashs[i].step_wg_ratio = round((infused / product->mashs_kg) * 1000000.0) / 1000000.0; + } + } + + /* Show the calculated total mash time. */ + ui->mash_timeEdit->setText(QString("%1:%2").arg(product->mashs_time / 60).arg(product->mashs_time % 60, 2, 'f', 0, '0')); +} + + +void EditProduct::addMashRow_clicked() +{ + Mashs newm; + + for (int i = 0; i < product->mashs.size(); i++) { + if (product->mashs.at(i).step_time == 0) + return; // Add only one at a time. + } + + newm.step_name = "Name me"; + newm.step_temp = newm.end_temp = 67.0; + newm.step_time = 20; + newm.ramp_time = 10; + if (product->mashs.size()) { + newm.step_volume = product->mashs.at(product->mashs.size() - 1).step_volume; + newm.step_wg_ratio = product->mashs.at(product->mashs.size() - 1).step_wg_ratio; + newm.step_type = product->mashs.at(product->mashs.size() - 1).step_type; + } else { + newm.step_volume = 0; + newm.step_wg_ratio = 0; + newm.step_type = 1; + } + newm.step_infuse_amount = newm.step_infuse_temp = 0; + + product->mashs.append(newm); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::deleteMashRow_clicked() +{ + if (product->locked || product->mashs.size() < 1) + return; + + QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); + int row = pb->objectName().toInt(); + qDebug() << "Delete mash row" << row << product->mashs.size(); + + int rc = QMessageBox::warning(this, tr("Delete mash step"), tr("Delete %1").arg(product->mashs.at(row).step_name), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (rc == QMessageBox::No) + return; + + product->mashs.removeAt(row); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::upMashRow_clicked() +{ + if (product->locked || product->mashs.size() < 1) + return; + + QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); + int row = pb->objectName().toInt(); + qDebug() << "Move up mash row" << row << product->mashs.size(); + + Mashs temp; + temp = product->mashs[row - 1]; + product->mashs[row - 1] = product->mashs[row]; + product->mashs[row] = temp; + is_changed(); + emit refreshAll(); +} + + +void EditProduct::downMashRow_clicked() +{ + if (product->locked || product->mashs.size() < 1) + return; + + QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); + int row = pb->objectName().toInt(); + qDebug() << "Move down mash row" << row << product->mashs.size(); + + Mashs temp; + temp = product->mashs[row + 1]; + product->mashs[row + 1] = product->mashs[row]; + product->mashs[row] = temp; + is_changed(); + emit refreshAll(); +} + + +void EditProduct::step_name_changed(QString val) +{ + product->mashs[product->mashs_row].step_name = val; + ui->mashsTable->setItem(product->mashs_row, 0, new QTableWidgetItem(val)); + is_changed(); +} + + +void EditProduct::step_type_changed(int val) +{ + qDebug() << "step_type_changed" << product->mashs_row << val; + + product->mashs[product->mashs_row].step_type = val; + ivolLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + stepivolEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + itmpLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + stepitmpEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::step_temp_changed(double val) +{ + qDebug() << "step_temp_changed" << product->mashs_row << val; + product->mashs[product->mashs_row].step_temp = val; + QTableWidgetItem *item = new QTableWidgetItem(QString("%1 °C").arg(val, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(product->mashs_row, 2, item); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::end_temp_changed(double val) +{ + qDebug() << "end_temp_changed" << product->mashs_row << val; + product->mashs[product->mashs_row].end_temp = val; + QTableWidgetItem *item = new QTableWidgetItem(QString("%1 °C").arg(val, 2, 'f', 1, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(product->mashs_row, 3, item); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::step_time_changed(double val) +{ + qDebug() << "step_time_changed" << product->mashs_row << val; + product->mashs[product->mashs_row].step_time = val; + QTableWidgetItem *item = new QTableWidgetItem(QString("%1 min").arg(val, 1, 'f', 0, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(product->mashs_row, 4, item); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::ramp_time_changed(double val) +{ + qDebug() << "ramp_time_changed" << product->mashs_row << val; + product->mashs[product->mashs_row].ramp_time = val; + QTableWidgetItem *item = new QTableWidgetItem(QString("%1 min").arg(val, 1, 'f', 0, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(product->mashs_row, 5, item); + is_changed(); + emit refreshAll(); +} + + +void EditProduct::infuse_changed(double val) +{ + qDebug() << "infuse_changed" << product->mashs_row << val; + product->mashs[product->mashs_row].step_infuse_amount = val; + QTableWidgetItem *item = new QTableWidgetItem(QString("%1 L").arg(val, 1, 'f', 0, '0')); + item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); + ui->mashsTable->setItem(product->mashs_row, 6, item); + + /* + * Recalculate water volumes + */ + double volume = 0; + for (int i = 0; i < product->mashs.size(); i++) { + if (product->mashs.at(i).step_type == 0) { + volume += product->mashs.at(i).step_infuse_amount; + } + product->mashs[i].step_volume = volume; + } + product->w1_amount = volume - product->w2_amount; + product->wg_amount = volume; + ui->w1_volEdit->setValue(product->w1_amount); + + is_changed(); + emit refreshAll(); +} + + +void EditProduct::editMashRow_clicked() +{ + QSqlQuery query; + + if (product->locked) + return; + + QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); + product->mashs_row = pb->objectName().toInt(); + qDebug() << "Edit mash row" << product->mashs_row; + Mashs backup = product->mashs.at(product->mashs_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("Step name:")); + nameLabel->setGeometry(QRect(10, 10, 141, 20)); + nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + stepnameEdit = new QLineEdit(dialog); + stepnameEdit->setObjectName(QString::fromUtf8("stepnameEdit")); + stepnameEdit->setText(product->mashs.at(product->mashs_row).step_name); + stepnameEdit->setGeometry(QRect(160, 10, 511, 23)); + + QLabel *typeLabel = new QLabel(dialog); + typeLabel->setObjectName(QString::fromUtf8("typeLabel")); + typeLabel->setText(tr("Step type:")); + typeLabel->setGeometry(QRect(10, 40, 141, 20)); + typeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + QComboBox *typeEdit = new QComboBox(dialog); + typeEdit->setObjectName(QString::fromUtf8("typeEdit")); + typeEdit->setGeometry(QRect(160, 40, 161, 23)); + typeEdit->addItem(tr("Infusion")); + typeEdit->addItem(tr("Temperature")); + typeEdit->addItem(tr("Decoction")); + typeEdit->setCurrentIndex(product->mashs.at(product->mashs_row).step_type); + + QLabel *tempLabel = new QLabel(dialog); + tempLabel->setObjectName(QString::fromUtf8("tempLabel")); + tempLabel->setText(tr("Step start temp:")); + tempLabel->setGeometry(QRect(10, 70, 141, 20)); + tempLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + steptempEdit = new QDoubleSpinBox(dialog); + steptempEdit->setObjectName(QString::fromUtf8("steptempEdit")); + steptempEdit->setGeometry(QRect(160, 70, 121, 24)); + steptempEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + steptempEdit->setDecimals(1); + steptempEdit->setValue(product->mashs.at(product->mashs_row).step_temp); + + QLabel *endLabel = new QLabel(dialog); + endLabel->setObjectName(QString::fromUtf8("endLabel")); + endLabel->setText(tr("Step end temp:")); + endLabel->setGeometry(QRect(360, 70, 141, 20)); + endLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + endtempEdit = new QDoubleSpinBox(dialog); + endtempEdit->setObjectName(QString::fromUtf8("endtempEdit")); + endtempEdit->setGeometry(QRect(510, 70, 121, 24)); + endtempEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + endtempEdit->setDecimals(1); + endtempEdit->setValue(product->mashs.at(product->mashs_row).end_temp); + + QLabel *timeLabel = new QLabel(dialog); + timeLabel->setObjectName(QString::fromUtf8("timeLabel")); + timeLabel->setText(tr("Step rest time:")); + timeLabel->setGeometry(QRect(10, 100, 141, 20)); + timeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + steptimeEdit = new QDoubleSpinBox(dialog); + steptimeEdit->setObjectName(QString::fromUtf8("steptimeEdit")); + steptimeEdit->setGeometry(QRect(160, 100, 121, 24)); + steptimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + steptimeEdit->setDecimals(0); + steptimeEdit->setValue(product->mashs.at(product->mashs_row).step_time); + + QLabel *rampLabel = new QLabel(dialog); + rampLabel->setObjectName(QString::fromUtf8("rampLabel")); + rampLabel->setText(tr("Step ramp time:")); + rampLabel->setGeometry(QRect(360, 100, 141, 20)); + rampLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ramptimeEdit = new QDoubleSpinBox(dialog); + ramptimeEdit->setObjectName(QString::fromUtf8("ramptimeEdit")); + ramptimeEdit->setGeometry(QRect(510, 100, 121, 24)); + ramptimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ramptimeEdit->setDecimals(0); + ramptimeEdit->setValue(product->mashs.at(product->mashs_row).ramp_time); + + /* + * Only used for Infusion steps. + */ + ivolLabel = new QLabel(dialog); + ivolLabel->setObjectName(QString::fromUtf8("ivolLabel")); + ivolLabel->setText(tr("Infusion volume:")); + ivolLabel->setGeometry(QRect(10, 130, 141, 20)); + ivolLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ivolLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + stepivolEdit = new QDoubleSpinBox(dialog); + stepivolEdit->setObjectName(QString::fromUtf8("stepivolEdit")); + stepivolEdit->setGeometry(QRect(160, 130, 121, 24)); + stepivolEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + stepivolEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + stepivolEdit->setDecimals(1); + stepivolEdit->setAccelerated(true); + stepivolEdit->setMaximum(100000.0); + stepivolEdit->setSingleStep(0.5); + stepivolEdit->setValue(product->mashs.at(product->mashs_row).step_infuse_amount); + + itmpLabel = new QLabel(dialog); + itmpLabel->setObjectName(QString::fromUtf8("itmpLabel")); + itmpLabel->setText(tr("Infusion Temperature:")); + itmpLabel->setGeometry(QRect(360, 130, 141, 20)); + itmpLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + itmpLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + stepitmpEdit = new QDoubleSpinBox(dialog); + stepitmpEdit->setObjectName(QString::fromUtf8("stepitmpEdit")); + stepitmpEdit->setGeometry(QRect(510, 130, 121, 24)); + stepitmpEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + stepitmpEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); + stepitmpEdit->setDecimals(1); + stepitmpEdit->setReadOnly(true); + stepitmpEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + stepitmpEdit->setValue(product->mashs.at(product->mashs_row).step_infuse_temp); + + connect(stepnameEdit, &QLineEdit::textEdited, this, &EditProduct::step_name_changed); + connect(typeEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::step_type_changed); + connect(steptempEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::step_temp_changed); + connect(endtempEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::end_temp_changed); + connect(steptimeEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::step_time_changed); + connect(ramptimeEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::ramp_time_changed); + connect(stepivolEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::infuse_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->mashs[product->mashs_row] = backup; + /* Rollback water volumes too */ + double volume = 0; + for (int i = 0; i < product->mashs.size(); i++) { + if (product->mashs.at(i).step_type == 0) { + volume += product->mashs.at(i).step_infuse_amount; + } + product->mashs[i].step_volume = volume; + } + product->w1_amount = volume - product->w2_amount; + product->wg_amount = volume; + ui->w1_volEdit->setValue(product->w1_amount); + } + + disconnect(stepnameEdit, nullptr, nullptr, nullptr); + disconnect(steptempEdit, nullptr, nullptr, nullptr); + disconnect(endtempEdit, nullptr, nullptr, nullptr); + disconnect(steptimeEdit, nullptr, nullptr, nullptr); + disconnect(ramptimeEdit, nullptr, nullptr, nullptr); + disconnect(stepivolEdit, nullptr, nullptr, nullptr); + disconnect(buttonBox, nullptr, nullptr, nullptr); + + emit refreshAll(); +} + + +void EditProduct::mash_name_changed(QString name) +{ + qDebug() << "mash_name_changed" << name; + product->mash_name = name; + is_changed(); +} + + +void EditProduct::mash_select_changed(int val) +{ + QSqlQuery query; + int i; + + qDebug() << "mash_select_changed" << val; + + const QSignalBlocker blocker1(ui->mash_nameEdit); + query.prepare("SELECT name,steps FROM profile_mash ORDER BY name"); + query.exec(); + query.first(); + for (i = 0; i < (val -1); i++) { + query.next(); + } + + product->mash_name = query.value(0).toString(); + ui->mash_nameEdit->setText(product->mash_name); + + QJsonParseError parseError; + const auto& json = query.value(1).toString(); + if (!json.trimmed().isEmpty()) { + const auto& formattedJson = QString("%1").arg(json); + QJsonDocument newsteps = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); + + if (parseError.error != QJsonParseError::NoError) { + qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset; + } else { + /* + * Got the json data in the steps array, replace the product steps. + */ + double infuse = 0; + if (product->mashs.size()) { + infuse = product->mashs.at(0).step_infuse_amount; + product->mashs.clear(); + ui->mashsTable->clear(); + } + if (newsteps.isArray()) { + for (i = 0; i < newsteps.array().size(); i++) { + QJsonObject obj = newsteps.array().at(i).toObject(); + Mashs m; + m.step_name = obj["step_name"].toString(); + if (obj["step_type"].isString()) + m.step_type = QString(obj["step_type"].toString()).toInt(); + else + m.step_type = obj["step_type"].toInt(); + m.step_volume = 0; + m.step_infuse_amount = 0; + m.step_infuse_temp = 0; + if (obj["step_temp"].isString()) + m.step_temp = QString(obj["step_temp"].toString()).toDouble(); + else + m.step_temp = obj["step_temp"].toDouble(); + if (obj["step_time"].isString()) + m.step_time = QString(obj["step_time"].toString()).toDouble(); + else + m.step_time = obj["step_time"].toDouble(); + if (obj["ramp_time"].isString()) + m.ramp_time = QString(obj["ramp_time"].toString()).toDouble(); + else + m.ramp_time = obj["ramp_time"].toDouble(); + if (obj["end_temp"].isString()) + m.end_temp = QString(obj["end_temp"].toString()).toDouble(); + else + m.end_temp = obj["end_temp"].toDouble(); + m.step_wg_ratio = 0; + product->mashs.append(m); + } + } + if (product->mashs.at(0).step_type == 0) + product->mashs[0].step_infuse_amount = infuse; // Restore saved initial infusion + } + } + is_changed(); + emit refreshAll(); +} + +