Mon, 30 Jan 2023 17:05:13 +0100
Added yeastpack editor. Expanded the database upgrade. On startup, recount the yeastpack used fields.
/** * EditProduct.cpp is part of bmsapp. * * Tab 4, 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 EditProduct::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); } bool EditProduct::block_hop(int stage, int useat) { if (stage > PROD_STAGE_BREW && useat < HOP_USEAT_DRY_HOP) return true; return false; } void EditProduct::refreshHops() { QString w; QWidget* pWidget; QHBoxLayout* pLayout; QTableWidgetItem *item; std::sort(product->hops.begin(), product->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("Stock"), tr("Delete"), tr("Edit") }); ui->hopsTable->setColumnCount(12); ui->hopsTable->setColumnWidth(0, 150); /* Origin */ ui->hopsTable->setColumnWidth(1, 245); /* Hop */ ui->hopsTable->setColumnWidth(2, 74); /* Type */ ui->hopsTable->setColumnWidth(3, 84); /* Form */ ui->hopsTable->setColumnWidth(4, 55); /* Alpha% */ ui->hopsTable->setColumnWidth(5, 75); /* Added */ ui->hopsTable->setColumnWidth(6, 65); /* Time */ ui->hopsTable->setColumnWidth(7, 50); /* IBU */ ui->hopsTable->setColumnWidth(8, 80); /* Amount */ ui->hopsTable->setColumnWidth(9, 80); /* Stock */ ui->hopsTable->setColumnWidth(10, 80); /* Delete */ ui->hopsTable->setColumnWidth(11, 80); /* Edit */ ui->hopsTable->setHorizontalHeaderLabels(labels); ui->hopsTable->verticalHeader()->hide(); ui->hopsTable->setRowCount(product->hops.size()); for (int i = 0; i < product->hops.size(); i++) { ui->hopsTable->setItem(i, 0, new QTableWidgetItem(product->hops.at(i).origin)); ui->hopsTable->setItem(i, 1, new QTableWidgetItem(product->hops.at(i).name)); item = new QTableWidgetItem(QCoreApplication::translate("HopTypes", g_hop_types[product->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[product->hops.at(i).form])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->hopsTable->setItem(i, 3, item); item = new QTableWidgetItem(QString("%1%").arg(product->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[product->hops.at(i).useat])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->hopsTable->setItem(i, 5, item); if (product->hops.at(i).useat == 2 || product->hops.at(i).useat == 4) { // Boil or whirlpool item = new QTableWidgetItem(QString("%1 min.").arg(product->hops.at(i).time, 1, 'f', 0, '0')); } else if (product->hops.at(i).useat == 5) { // Dry-hop item = new QTableWidgetItem(QString("%1 days.").arg(product->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(product->hops.at(i).useat, product->hops.at(i).form, product->preboil_sg, product->est_og3, product->batch_size, product->hops.at(i).amount, product->hops.at(i).time, product->hops.at(i).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(i).utilisation, product->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 (product->hops.at(i).amount < 1.0) { item = new QTableWidgetItem(QString("%1 gr").arg(product->hops.at(i).amount * 1000.0, 2, 'f', 1, '0')); } else { item = new QTableWidgetItem(QString("%1 kg").arg(product->hops.at(i).amount, 4, 'f', 3, '0')); } item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->hopsTable->setItem(i, 8, item); if (block_hop(product->stage, product->hops.at(i).useat)) { item = new QTableWidgetItem(QString("")); } else { if (product->hops.at(i).inventory < 1.0) { item = new QTableWidgetItem(QString("%1 gr").arg(product->hops.at(i).inventory * 1000.0, 2, 'f', 1, '0')); } else { item = new QTableWidgetItem(QString("%1 kg").arg(product->hops.at(i).inventory, 4, 'f', 3, '0')); } item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (product->hops.at(i).inventory < product->hops.at(i).amount) item->setForeground(QBrush(QColor(Qt::red))); } ui->hopsTable->setItem(i, 9, item); /* Add the Delete row button */ if (block_hop(product->stage, product->hops.at(i).useat)) { item = new QTableWidgetItem(""); item->setToolTip(tr("Hop already used")); ui->hopsTable->setItem(i, 10, item); item = new QTableWidgetItem(""); item->setToolTip(tr("Hop already used")); ui->hopsTable->setItem(i, 11, 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(deleteHopRow_clicked())); pLayout = new QHBoxLayout(pWidget); pLayout->addWidget(btn_dele); pLayout->setContentsMargins(5, 0, 5, 0); pWidget->setLayout(pLayout); ui->hopsTable->setCellWidget(i, 10, 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, 11, pWidget); } } } void EditProduct::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 EditProduct::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 EditProduct::calcIBUs() { double hop_flavour = 0, hop_aroma = 0, ibus = 0, ferm_ibus = 0; product->hops_ok = true; for (int i = 0; i < product->hops.size(); i++) { ibus += Utils::toIBU(product->hops.at(i).useat, product->hops.at(i).form, product->preboil_sg, product->est_og3, product->batch_size, product->hops.at(i).amount, product->hops.at(i).time, product->hops.at(i).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(i).utilisation, product->hops.at(i).bu_factor); if (product->stage > PROD_STAGE_BREW) ferm_ibus += Utils::toIBU(product->hops.at(i).useat, product->hops.at(i).form, product->brew_preboil_sg, product->brew_fermenter_sg, product->brew_fermenter_volume + product->brew_fermenter_tcloss + product->boil_absorb, product->hops.at(i).amount, product->hops.at(i).time, product->hops.at(i).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(i).utilisation, product->hops.at(i).bu_factor); else ferm_ibus += Utils::toIBU(product->hops.at(i).useat, product->hops.at(i).form, product->preboil_sg, product->est_og3, product->brew_fermenter_volume + product->brew_fermenter_tcloss + product->boil_absorb, product->hops.at(i).amount, product->hops.at(i).time, product->hops.at(i).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(i).utilisation, product->hops.at(i).bu_factor); hop_flavour += Utils::hopFlavourContribution(product->hops.at(i).time, product->batch_size, product->hops.at(i).useat, product->hops.at(i).amount, product->hops.at(i).form); hop_aroma += Utils::hopAromaContribution(product->hops.at(i).time, product->batch_size, product->hops.at(i).useat, product->hops.at(i).amount, product->hops.at(i).form); if ((((product->inventory_reduced <= PROD_STAGE_BREW) && (product->hops.at(i).useat <= HOP_USEAT_WHIRLPOOL)) || ((product->inventory_reduced <= PROD_STAGE_PACKAGE) && (product->hops.at(i).useat == HOP_USEAT_DRY_HOP))) && (product->hops.at(i).inventory < product->hops.at(i).amount)) product->hops_ok = false; } 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" << product->est_ibu << ibus << "flavour" << hop_flavour << "aroma" << hop_aroma << "method" << product->ibu_method << "fermenter" << ferm_ibus << "supplies" << product->hops_ok; product->est_ibu = ibus; product->brew_fermenter_ibu = ferm_ibus; if (product->stage > PROD_STAGE_BREW) { ui->est_ibuLabel->setText(tr("Final IBU:")); ui->est_ibuEdit->setValue(product->brew_fermenter_ibu); ui->est_ibuShow->setValue(product->brew_fermenter_ibu); } else { ui->est_ibuEdit->setValue(product->est_ibu); ui->est_ibuShow->setValue(product->est_ibu); } ui->est_ibu2Edit->setValue(product->est_ibu); ui->brew_fermentibuShow->setValue(product->brew_fermenter_ibu); ui->hop_tasteShow->setValue(hop_flavour); ui->hop_aromaShow->setValue(hop_aroma); } void EditProduct::addHopRow_clicked() { Hops newh; qDebug() << "Add hop row"; for (int i = 0; i < product->hops.size(); i++) { if (product->hops.at(i).amount == 0 && product->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 = HOP_TYPE_BITTERING; newh.form = HOP_FORMS_PELLET; newh.useat = HOP_USEAT_BOIL; 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.inventory = 0; newh.utilisation = my_ut_pellet; newh.bu_factor = 1; product->hops.append(newh); emit refreshAll(); } void EditProduct::deleteHopRow_clicked() { if (product->locked || product->hops.size() < 1) return; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); int row = pb->objectName().toInt(); qDebug() << "Delete hop row" << row << product->hops.size(); int rc = QMessageBox::warning(this, tr("Delete hop"), tr("Delete %1").arg(product->hops.at(row).name), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (rc == QMessageBox::No) return; product->hops.removeAt(row); is_changed(); emit refreshAll(); } void EditProduct::hop_amount_changed(double val) { QTableWidgetItem *item; qDebug() << "hop_amount_changed()" << product->hops_row << val; product->hops[product->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(product->hops_row, 8, item); double ibu = Utils::toIBU(product->hops.at(product->hops_row).useat, product->hops.at(product->hops_row).form, product->preboil_sg, product->est_og3, product->batch_size, product->hops.at(product->hops_row).amount, product->hops.at(product->hops_row).time, product->hops.at(product->hops_row).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(product->hops_row).utilisation, product->hops.at(product->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(product->hops_row, 7, item); calcIBUs(); is_changed(); } void EditProduct::hop_time_changed(int val) { QTableWidgetItem *item; qDebug() << "hop_time_changed()" << product->hops_row << val; if (product->hops.at(product->hops_row).useat == HOP_USEAT_BOIL || product->hops.at(product->hops_row).useat == HOP_USEAT_WHIRLPOOL) { item = new QTableWidgetItem(QString("%1 min.").arg(val, 1, 'f', 0, '0')); product->hops[product->hops_row].time = val; } else if (product->hops.at(product->hops_row).useat == HOP_USEAT_DRY_HOP) { item = new QTableWidgetItem(QString("%1 days.").arg(val, 1, 'f', 0, '0')); product->hops[product->hops_row].time = val * 1440; } else { item = new QTableWidgetItem(QString("")); product->hops[product->hops_row].time = val; } item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->hopsTable->setItem(product->hops_row, 6, item); double ibu = Utils::toIBU(product->hops.at(product->hops_row).useat, product->hops.at(product->hops_row).form, product->preboil_sg, product->est_og3, product->batch_size, product->hops.at(product->hops_row).amount, product->hops.at(product->hops_row).time, product->hops.at(product->hops_row).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(product->hops_row).utilisation, product->hops.at(product->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(product->hops_row, 7, item); calcIBUs(); is_changed(); } void EditProduct::hop_select_changed(int val) { QSqlQuery query; bool instock = hinstockEdit->isChecked(); QString w; QTableWidgetItem *item; if (val < 1) return; qDebug() << "hop_select_changed()" << product->fermentables_row << val << instock; /* * 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 */ product->hops[product->hops_row].name = query.value("name").toString(); product->hops[product->hops_row].origin = query.value("origin").toString(); product->hops[product->hops_row].alpha = query.value("alpha").toDouble(); product->hops[product->hops_row].beta = query.value("beta").toDouble(); product->hops[product->hops_row].humulene = query.value("humulene").toDouble(); product->hops[product->hops_row].caryophyllene = query.value("caryophyllene").toDouble(); product->hops[product->hops_row].cohumulone = query.value("cohumulone").toDouble(); product->hops[product->hops_row].myrcene = query.value("myrcene").toDouble(); product->hops[product->hops_row].hsi = query.value("hsi").toDouble(); product->hops[product->hops_row].total_oil = query.value("total_oil").toDouble(); product->hops[product->hops_row].type = query.value("type").toInt(); product->hops[product->hops_row].form = query.value("form").toInt(); product->hops[product->hops_row].cost = query.value("cost").toDouble(); product->hops[product->hops_row].inventory = query.value("inventory").toDouble(); product->hops[product->hops_row].utilisation = query.value("utilisation").toDouble(); product->hops[product->hops_row].bu_factor = query.value("bu_factor").toDouble(); /* * Update the visible fields */ hnameEdit->setText(product->hops.at(product->hops_row).name); horiginEdit->setText(product->hops.at(product->hops_row).origin); double ibu = Utils::toIBU(product->hops.at(product->hops_row).useat, product->hops.at(product->hops_row).form, product->preboil_sg, product->est_og3, product->batch_size, product->hops.at(product->hops_row).amount, product->hops.at(product->hops_row).time, product->hops.at(product->hops_row).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(product->hops_row).utilisation, product->hops.at(product->hops_row).bu_factor); ibuEdit->setValue(ibu); ui->hopsTable->setItem(product->hops_row, 0, new QTableWidgetItem(product->hops.at(product->hops_row).origin)); ui->hopsTable->setItem(product->hops_row, 1, new QTableWidgetItem(product->hops.at(product->hops_row).name)); QString hoptype = QCoreApplication::translate("HopTypes", g_hop_types[product->hops.at(product->hops_row).type]); item = new QTableWidgetItem(hoptype); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->hopsTable->setItem(product->hops_row, 2, item); item = new QTableWidgetItem(QCoreApplication::translate("HopForm", g_hop_forms[product->hops.at(product->hops_row).form])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->hopsTable->setItem(product->hops_row, 3, item); item = new QTableWidgetItem(QString("%1%").arg(product->hops.at(product->hops_row).alpha, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->hopsTable->setItem(product->hops_row, 4, item); item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); ui->hopsTable->setItem(product->hops_row, 7, item); if (product->hops.at(product->hops_row).inventory < 1.0) { item = new QTableWidgetItem(QString("%1 gr").arg(product->hops.at(product->hops_row).inventory * 1000.0, 2, 'f', 1, '0')); } else { item = new QTableWidgetItem(QString("%1 kg").arg(product->hops.at(product->hops_row).inventory, 4, 'f', 3, '0')); } item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); if (product->hops.at(product->hops_row).inventory < product->hops.at(product->hops_row).amount) item->setForeground(QBrush(QColor(Qt::red))); ui->hopsTable->setItem(product->hops_row, 9, item); calcIBUs(); is_changed(); } void EditProduct::hop_instock_changed(bool val) { QSqlQuery query; qDebug() << "hop_instock_changed()" << product->hops_row << val; 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 EditProduct::hop_useat_changed(int val) { qDebug() << "hop_useat_changed()" << product->hops_row << val; product->hops[product->hops_row].useat = val; QTableWidgetItem *item = new QTableWidgetItem(QCoreApplication::translate("HopUse", g_hop_useat[val])); item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); ui->hopsTable->setItem(product->hops_row, 5, item); if (val == HOP_USEAT_BOIL || val == HOP_USEAT_WHIRLPOOL) { htimeLabel->setText(tr("Time in minutes:")); htimeEdit->setValue(product->hops.at(product->hops_row).time); htimeLabel->show(); htimeEdit->show(); } else if (val == HOP_USEAT_DRY_HOP) { htimeLabel->setText(tr("Time in days:")); htimeEdit->setValue(product->hops.at(product->hops_row).time / 1440); htimeLabel->show(); htimeEdit->show(); } else { htimeEdit->setValue(0); htimeLabel->hide(); htimeEdit->hide(); } is_changed(); emit refreshAll(); } void EditProduct::editHopRow_clicked() { QSqlQuery query; if (product->locked) return; QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); product->hops_row = pb->objectName().toInt(); qDebug() << "Edit hop row" << product->hops_row; Hops backup = product->hops.at(product->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); htimeLabel = new QLabel(dialog); htimeLabel->setObjectName(QString::fromUtf8("htimeLabel")); if (product->hops.at(product->hops_row).useat == HOP_USEAT_DRY_HOP) htimeLabel->setText(tr("Time in days:")); else htimeLabel->setText(tr("Time in minutes:")); 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 *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(product->hops.at(product->hops_row).name); hnameEdit->setGeometry(QRect(160, 10, 511, 23)); hnameEdit->setReadOnly(true); horiginEdit = new QLineEdit(dialog); horiginEdit->setObjectName(QString::fromUtf8("horiginEdit")); horiginEdit->setText(product->hops.at(product->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(product->hops.at(product->hops_row).amount * 1000.0); 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 (product->hops.at(product->hops_row).useat == HOP_USEAT_BOIL || product->hops.at(product->hops_row).useat == HOP_USEAT_WHIRLPOOL) { htimeEdit->setValue(product->hops.at(product->hops_row).time); htimeLabel->show(); htimeEdit->show(); } else if (product->hops.at(product->hops_row).useat == HOP_USEAT_DRY_HOP) { htimeEdit->setValue(product->hops.at(product->hops_row).time / 1440); htimeLabel->show(); htimeEdit->show(); } else { htimeLabel->hide(); htimeEdit->hide(); } useatEdit = new QComboBox(dialog); useatEdit->setObjectName(QString::fromUtf8("useatEdit")); useatEdit->setGeometry(QRect(160, 160, 161, 23)); for (int i = 0; i < 7; i++) useatEdit->addItem(QCoreApplication::translate("HopUse", g_hop_useat[i])); useatEdit->setCurrentIndex(product->hops.at(product->hops_row).useat); 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(product->hops.at(product->hops_row).useat, product->hops.at(product->hops_row).form, product->preboil_sg, product->est_og3, product->batch_size, product->hops.at(product->hops_row).amount, product->hops.at(product->hops_row).time, product->hops.at(product->hops_row).alpha, product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6, product->boil_time, product->brew_cooling_method, product->eq_chiller_to79, product->eq_chiller_lpm, product->hops.at(product->hops_row).utilisation, product->hops.at(product->hops_row).bu_factor); ibuEdit->setValue(ibu); hop_instock_changed(true); connect(hselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::hop_select_changed); connect(hamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::hop_amount_changed); connect(htimeEdit, QOverload<int>::of(&QSpinBox::valueChanged), this, &EditProduct::hop_time_changed); connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::hop_useat_changed); connect(hinstockEdit, &QCheckBox::stateChanged, this, &EditProduct::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"; product->hops[product->hops_row] = backup; } else { /* Clear time if hop is not used for boil, whirlpool or dry-hop. */ if (! (product->hops.at(product->hops_row).useat == HOP_USEAT_BOIL || product->hops.at(product->hops_row).useat == HOP_USEAT_WHIRLPOOL || product->hops.at(product->hops_row).useat == HOP_USEAT_DRY_HOP)) { if (product->hops.at(product->hops_row).time) { product->hops[product->hops_row].time = 0; is_changed(); } } } disconnect(hselectEdit, nullptr, nullptr, nullptr); disconnect(hamountEdit, nullptr, nullptr, nullptr); disconnect(htimeEdit, nullptr, nullptr, nullptr); disconnect(useatEdit, nullptr, nullptr, nullptr); disconnect(hinstockEdit, nullptr, nullptr, nullptr); disconnect(buttonBox, nullptr, nullptr, nullptr); emit refreshAll(); } void EditProduct::adjustHops(double factor) { double amount; if (product->hops.size() == 0) return; for (int i = 0; i < product->hops.size(); i++) { amount = product->hops.at(i).amount * factor; product->hops[i].amount = amount; } }