diff -r 54b5abd46958 -r 6d3ba9c44f95 src/ProdOnTree.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ProdOnTree.cpp Sat May 21 21:40:57 2022 +0200 @@ -0,0 +1,431 @@ +/** + * ProdOnTree.cpp is part of bmsapp. + * + * 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 . + */ +#include "ProdOnTree.h" +#include "MainWindow.h" +#include "EditProduct.h" +#include "config.h" +#include "Utils.h" + + +ProdOnTree::ProdOnTree(QWidget *parent) : QDialog(parent) +{ + qDebug() << "ProdOnTree start"; + + gridLayout = new QGridLayout(this); + gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + treeWidget = new QTreeWidget(this); + treeWidget->setObjectName(QString::fromUtf8("treeWidget")); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(treeWidget->sizePolicy().hasHeightForWidth()); + treeWidget->setSizePolicy(sizePolicy); + gridLayout->addWidget(treeWidget, 0, 0, 1, 1); + + recipeBox = new QGroupBox(this); + recipeBox->setObjectName(QString::fromUtf8("recipeBox")); + QSizePolicy sizePolicy3(QSizePolicy::Preferred, QSizePolicy::Expanding); + sizePolicy3.setHorizontalStretch(0); + sizePolicy3.setVerticalStretch(0); + sizePolicy3.setHeightForWidth(recipeBox->sizePolicy().hasHeightForWidth()); + recipeBox->setSizePolicy(sizePolicy3); + recipeBox->setMinimumSize(QSize(500, 0)); + + volumeLabel = new QLabel(recipeBox); + volumeLabel->setObjectName(QString::fromUtf8("volumeLabel")); + volumeLabel->setGeometry(QRect(100, 30, 141, 20)); + volumeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + volumeLabel->setText(tr("Brew volume:")); + efficiencyLabel = new QLabel(recipeBox); + efficiencyLabel->setObjectName(QString::fromUtf8("efficiencyLabel")); + efficiencyLabel->setGeometry(QRect(100, 120, 141, 20)); + efficiencyLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + efficiencyLabel->setText(tr("Brewhouse efficiency:")); + boilvolumeLabel = new QLabel(recipeBox); + boilvolumeLabel->setObjectName(QString::fromUtf8("boilvolumeLabel")); + boilvolumeLabel->setGeometry(QRect(100, 60, 141, 20)); + boilvolumeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + boilvolumeLabel->setText(tr("Boil volume:")); + boiltimeLabel = new QLabel(recipeBox); + boiltimeLabel->setObjectName(QString::fromUtf8("boiltimeLabel")); + boiltimeLabel->setGeometry(QRect(100, 90, 141, 20)); + boiltimeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + boiltimeLabel->setText(tr("Boil time:")); + ogLabel = new QLabel(recipeBox); + ogLabel->setObjectName(QString::fromUtf8("ogLabel")); + ogLabel->setGeometry(QRect(100, 150, 141, 20)); + ogLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ogLabel->setText(tr("Original gravity:")); + fgLabel = new QLabel(recipeBox); + fgLabel->setObjectName(QString::fromUtf8("fgLabel")); + fgLabel->setGeometry(QRect(100, 180, 141, 20)); + fgLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + fgLabel->setText(tr("Final gravity:")); + abvLabel = new QLabel(recipeBox); + abvLabel->setObjectName(QString::fromUtf8("abvLabel")); + abvLabel->setGeometry(QRect(100, 210, 141, 20)); + abvLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + abvLabel->setText(tr("Alcohol by Volume:")); + co2Label = new QLabel(recipeBox); + co2Label->setObjectName(QString::fromUtf8("co2Label")); + co2Label->setGeometry(QRect(100, 240, 141, 20)); + co2Label->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + co2Label->setText(tr("CO2 Volume:")); + colorLabel = new QLabel(recipeBox); + colorLabel->setObjectName(QString::fromUtf8("colorLabel")); + colorLabel->setGeometry(QRect(100, 270, 141, 20)); + colorLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + colorLabel->setText(tr("Color EBC:")); + colormethodLabel = new QLabel(recipeBox); + colormethodLabel->setObjectName(QString::fromUtf8("colormethodLabel")); + colormethodLabel->setGeometry(QRect(100, 300, 141, 20)); + colormethodLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + colormethodLabel->setText(tr("Color method:")); + ibuLabel = new QLabel(recipeBox); + ibuLabel->setObjectName(QString::fromUtf8("ibuLabel")); + ibuLabel->setGeometry(QRect(100, 330, 141, 20)); + ibuLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ibuLabel->setText(tr("Bitterness IBU:")); + ibumethodLabel = new QLabel(recipeBox); + ibumethodLabel->setObjectName(QString::fromUtf8("ibumethodLabel")); + ibumethodLabel->setGeometry(QRect(100, 360, 141, 20)); + ibumethodLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ibumethodLabel->setText(tr("Bitterness method:")); + remarksLabel = new QLabel(recipeBox); + remarksLabel->setObjectName(QString::fromUtf8("remarksLabel")); + remarksLabel->setGeometry(QRect(30, 390, 101, 20)); + remarksLabel->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter); + remarksLabel->setText(tr("Remarks:")); + + volumeEdit = new QDoubleSpinBox(recipeBox); + volumeEdit->setObjectName(QString::fromUtf8("volumeEdit")); + volumeEdit->setGeometry(QRect(260, 30, 111, 24)); + volumeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + volumeEdit->setReadOnly(true); + volumeEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + volumeEdit->setDecimals(1); + volumeEdit->setMaximum(100000.000000000000000); + volumeEdit->setSuffix(tr(" L")); + boilvolumeEdit = new QDoubleSpinBox(recipeBox); + boilvolumeEdit->setObjectName(QString::fromUtf8("boilvolumeEdit")); + boilvolumeEdit->setGeometry(QRect(260, 60, 111, 24)); + boilvolumeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + boilvolumeEdit->setReadOnly(true); + boilvolumeEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + boilvolumeEdit->setDecimals(1); + boilvolumeEdit->setMaximum(100000.000000000000000); + boilvolumeEdit->setSuffix(tr(" L")); + efficiencyEdit = new QDoubleSpinBox(recipeBox); + efficiencyEdit->setObjectName(QString::fromUtf8("efficiencyEdit")); + efficiencyEdit->setGeometry(QRect(260, 120, 111, 24)); + efficiencyEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + efficiencyEdit->setReadOnly(true); + efficiencyEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + efficiencyEdit->setDecimals(1); + efficiencyEdit->setMaximum(100.000000000000000); + efficiencyEdit->setSuffix(tr(" %")); + ogEdit = new QDoubleSpinBox(recipeBox); + ogEdit->setObjectName(QString::fromUtf8("ogEdit")); + ogEdit->setGeometry(QRect(260, 150, 111, 24)); + ogEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ogEdit->setReadOnly(true); + ogEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + ogEdit->setDecimals(3); + ogEdit->setMaximum(1.200000000000000); + fgEdit = new QDoubleSpinBox(recipeBox); + fgEdit->setObjectName(QString::fromUtf8("fgEdit")); + fgEdit->setGeometry(QRect(260, 180, 111, 24)); + fgEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + fgEdit->setReadOnly(true); + fgEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + fgEdit->setDecimals(3); + fgEdit->setMaximum(1.200000000000000); + abvEdit = new QDoubleSpinBox(recipeBox); + abvEdit->setObjectName(QString::fromUtf8("abvEdit")); + abvEdit->setGeometry(QRect(260, 210, 111, 24)); + abvEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + abvEdit->setReadOnly(true); + abvEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + abvEdit->setDecimals(1); + abvEdit->setMaximum(100.000000000000000); + abvEdit->setSuffix(tr(" %")); + co2Edit = new QDoubleSpinBox(recipeBox); + co2Edit->setObjectName(QString::fromUtf8("co2Edit")); + co2Edit->setGeometry(QRect(260, 240, 111, 24)); + co2Edit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + co2Edit->setReadOnly(true); + co2Edit->setButtonSymbols(QAbstractSpinBox::NoButtons); + co2Edit->setDecimals(2); + co2Edit->setMaximum(100.000000000000000); + boiltimeEdit = new QSpinBox(recipeBox); + boiltimeEdit->setObjectName(QString::fromUtf8("boiltimeEdit")); + boiltimeEdit->setGeometry(QRect(260, 90, 111, 24)); + boiltimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + boiltimeEdit->setReadOnly(true); + boiltimeEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + boiltimeEdit->setMaximum(1440); + boiltimeEdit->setSuffix(tr(" min")); + colorEdit = new QSpinBox(recipeBox); + colorEdit->setObjectName(QString::fromUtf8("colorEdit")); + colorEdit->setGeometry(QRect(260, 270, 111, 24)); + colorEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + colorEdit->setReadOnly(true); + colorEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + colorEdit->setMaximum(1440); + ibuEdit = new QSpinBox(recipeBox); + ibuEdit->setObjectName(QString::fromUtf8("ibuEdit")); + ibuEdit->setGeometry(QRect(260, 330, 111, 24)); + ibuEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + ibuEdit->setReadOnly(true); + ibuEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); + ibuEdit->setMaximum(1440); + remarksEdit = new QPlainTextEdit(recipeBox); + remarksEdit->setObjectName(QString::fromUtf8("remarksEdit")); + remarksEdit->setGeometry(QRect(30, 410, 441, 111)); + remarksEdit->setReadOnly(true); + colormethodEdit = new QLineEdit(recipeBox); + colormethodEdit->setObjectName(QString::fromUtf8("colormethodEdit")); + colormethodEdit->setGeometry(QRect(260, 300, 113, 23)); + colormethodEdit->setReadOnly(true); + ibumethodEdit = new QLineEdit(recipeBox); + ibumethodEdit->setObjectName(QString::fromUtf8("ibumethodEdit")); + ibumethodEdit->setGeometry(QRect(260, 360, 113, 23)); + ibumethodEdit->setReadOnly(true); + + gridLayout->addWidget(recipeBox, 0, 1, 2, 1); + + groupBox = new QGroupBox(this); + groupBox->setObjectName(QString::fromUtf8("groupBox")); + groupBox->setEnabled(true); + groupBox->setFlat(false); + horizontalLayout = new QHBoxLayout(groupBox); + horizontalLayout->setSpacing(6); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + horizontalLayout->setContentsMargins(0, 0, 0, 0); + + quitButton = new QPushButton(groupBox); + quitButton->setObjectName(QString::fromUtf8("quitButton")); + quitButton->setMinimumSize(QSize(80, 24)); + quitButton->setText(tr("Quit")); + QIcon icon; + icon.addFile(QString::fromUtf8(":icons/silk/door_out.png"), QSize(), QIcon::Normal, QIcon::Off); + quitButton->setIcon(icon); + horizontalLayout->addWidget(quitButton, 0, Qt::AlignLeft); + + openButton = new QPushButton(groupBox); + openButton->setObjectName(QString::fromUtf8("openButton")); + openButton->setMinimumSize(QSize(80, 24)); + openButton->setText(tr("Open")); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":icons/silk/cup_go.png"), QSize(), QIcon::Normal, QIcon::Off); + openButton->setIcon(icon1); + horizontalLayout->addWidget(openButton, 0, Qt::AlignRight); + + gridLayout->addWidget(groupBox, 1, 0, 1, 1); + + record = -2; + connect(quitButton, SIGNAL(clicked()), parent, SLOT(fromProdOnTree())); + connect(openButton, SIGNAL(clicked()), this, SLOT(on_openButton_clicked())); + connect(this, SIGNAL(setStatus(QString)), parent, SLOT(statusMsg(QString))); + + treeWidget->setColumnCount(4); + treeWidget->setHeaderLabels({ tr("Guide"), tr("Group"), tr("Style"), tr("Product") }); + treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + treeWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + + connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(on_item_clicked(QTreeWidgetItem*, int))); + connect(treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(on_item_doubleclicked(QTreeWidgetItem*, int))); + + emit refreshTable(); +} + + +void ProdOnTree::refreshTable() +{ + QTreeWidgetItem *st_guide, *st_group, *st_name, *name; + + qDebug() << "ProdOnTree reload"; + + treeWidget->clear(); + + QSqlQuery query0; + query0.prepare("SELECT DISTINCT st_guide FROM products WHERE stage='11' ORDER BY st_guide"); + query0.exec(); + while (query0.next()) { + st_guide = new QTreeWidgetItem( QStringList( { query0.value(0).toString() } )); + treeWidget->addTopLevelItem( st_guide ); + st_guide->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); + + QSqlQuery query1; + query1.prepare("SELECT DISTINCT st_letter FROM products WHERE stage='11' AND st_guide=:guide ORDER BY st_letter"); + query1.bindValue(":guide", query0.value(0).toString()); + query1.exec(); + while (query1.next()) { + st_group = new QTreeWidgetItem(QStringList({ "", query1.value(0).toString() })); + st_group->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); + st_guide->addChild( st_group ); + + QSqlQuery query2; + query2.prepare("SELECT DISTINCT st_name FROM products WHERE stage='11' AND st_guide=:guide AND st_letter=:group ORDER BY st_name"); + query2.bindValue(":guide", query0.value(0).toString()); + query2.bindValue(":group", query1.value(0).toString()); + query2.exec(); + while (query2.next()) { + st_name = new QTreeWidgetItem(QStringList({ "", "", query2.value(0).toString() })); + st_name->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); + st_group->addChild( st_name ); + + QSqlQuery query3; + query3.prepare("SELECT name,record,code FROM products WHERE stage='11' AND st_guide=:guide AND st_letter=:group AND st_name=:name " + "ORDER BY code,name"); + query3.bindValue(":guide", query0.value(0).toString()); + query3.bindValue(":group", query1.value(0).toString()); + query3.bindValue(":name", query2.value(0).toString()); + query3.exec(); + while (query3.next()) { + name = new QTreeWidgetItem(QStringList({ "", "", "", + query3.value(2).toString() + " - " + query3.value(0).toString(), query3.value(1).toString() })); + st_name->addChild( name ); + } + } + treeWidget->expandItem(st_group); + } + treeWidget->expandItem(st_guide); + } + + QSqlQuery query("SELECT record FROM products WHERE stage='11'"); + emit setStatus(QString(tr("Total items: %1")).arg(query.size())); + + showRecipe(); +} + + +void ProdOnTree::showRecipe() +{ + QString w; + + qDebug() << "showRecipe" << record; + + const QStringList c_method({"Morey", "Mosher", "Daniels", "Halberstadt", "Naudts" }); + const QStringList i_method({"Tinseth", "Rager", "Daniels" }); + + /* + * If no recipe is "pre" selected, return. + */ + if (record < 1) { + recipeBox->setEnabled(false); + return; + } + + /* + * Fill in basic details of the selected recipe. + */ + QSqlQuery query; + query.prepare("SELECT batch_size,boil_size,boil_time,efficiency,est_og,est_fg,est_abv,est_color,color_method,est_ibu,ibu_method,est_carb,notes,name " + "FROM products WHERE record=:record"); + query.bindValue(":record", record); + query.exec(); + if (query.size() == 1) { + query.first(); + volumeEdit->setValue(query.value(0).toDouble()); + boilvolumeEdit->setValue(query.value(1).toDouble()); + boiltimeEdit->setValue(query.value(2).toInt()); + efficiencyEdit->setValue(query.value(3).toDouble()); + ogEdit->setValue(query.value(4).toDouble()); + fgEdit->setValue(query.value(5).toDouble()); + abvEdit->setValue(query.value(6).toInt()); + colorEdit->setValue(query.value(7).toInt()); + colorEdit->setStyleSheet(Utils::ebc_to_style(query.value(7).toInt())); + colormethodEdit->setText(c_method[query.value(8).toInt()]); + ibuEdit->setValue(query.value(9).toInt()); + ibumethodEdit->setText(i_method[query.value(10).toInt()]); + co2Edit->setValue(query.value(11).toDouble()); + remarksEdit->setPlainText(query.value(12).toString()); + recipeBox->setTitle(query.value(13).toString()); + recipeBox->setEnabled(true); + } else { + qDebug() << "Error getting product record" << record; + } +} + + +ProdOnTree::~ProdOnTree() {} + + +void ProdOnTree::edit(int recno) +{ + EditProduct dialog(recno, this); + /* Signal from editor if a refresh is needed */ + connect(&dialog, SIGNAL(entry_changed()), this, SLOT(refreshTable())); + dialog.setModal(true); + dialog.exec(); +} + + +void ProdOnTree::on_openButton_clicked() +{ + if (record > 0) + edit(record); +} + + +void ProdOnTree::on_item_clicked(QTreeWidgetItem *item, int col) +{ + record = -2; // Invalid + + if (col == 0) { + if (item->isExpanded()) { + treeWidget->collapseItem(item); + } else { + treeWidget->expandItem(item); + } + } else if (col == 1) { + if (item->isExpanded()) { + treeWidget->collapseItem(item); + } else { + treeWidget->expandItem(item); + } + } else if (col == 2 && item->text(2).length()) { + if (item->isExpanded()) { + item->setExpanded(false); + } else { + item->setExpanded(true); + } + } else if (col == 3) { + /* + * if a recipe name is selected then: + * item column 3 contains the recipe name, + * item column 4 contains the recipe record number. + */ + if (item->text(4).toInt() > 0) { + if (record != item->text(4).toInt()) { + record = item->text(4).toInt(); + showRecipe(); + } + } + } +} + + +void ProdOnTree::on_item_doubleclicked(QTreeWidgetItem *item, int col) +{ + if ((col == 3) && (item->text(4).toInt() > 0)) { + edit(item->text(4).toInt()); + } +} + +