Mon, 11 Apr 2022 20:45:22 +0200
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
127 | 1 | /** |
2 | * EditRecipe.cpp is part of bmsapp. | |
3 | * | |
4 | * Tab 3, hops | |
5 | * | |
6 | * bmsapp is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 3 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * bmsapp is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | ||
21 | ||
22 | bool EditRecipe::hop_sort_test(const Hops &D1, const Hops &D2) | |
23 | { | |
24 | if (D1.h_useat > D2.h_useat) | |
25 | return false; | |
26 | if (D1.h_useat < D2.h_useat) | |
27 | return true; | |
28 | /* Same useat moments, test time. */ | |
29 | if (D1.h_time < D2.h_time) | |
30 | return false; | |
31 | if (D1.h_time > D2.h_time) | |
32 | return true; | |
33 | /* Finally consider the amounts */ | |
34 | return (D1.h_amount > D2.h_amount); | |
35 | } | |
36 | ||
37 | ||
38 | void EditRecipe::refreshHops() | |
39 | { | |
40 | QString w; | |
41 | QWidget* pWidget; | |
42 | QHBoxLayout* pLayout; | |
43 | QTableWidgetItem *item; | |
44 | ||
45 | qDebug() << "refreshHops" << recipe->hops.size(); | |
46 | std::sort(recipe->hops.begin(), recipe->hops.end(), hop_sort_test); | |
47 | ||
48 | /* | |
49 | * During filling the table turn off the cellChanged signal because every cell that is filled | |
50 | * triggers the cellChanged signal. The QTableWidget has no better signal to use. | |
51 | */ | |
52 | this->ignoreChanges = true; | |
53 | ||
54 | const QStringList labels({tr("Origin"), tr("Hop"), tr("Type"), tr("Form"), tr("Alpha"), tr("Use at"), tr("Time"), | |
55 | tr("IBU"), tr("Amount"), tr("Delete"), tr("Edit") }); | |
56 | ||
57 | ui->hopsTable->setColumnCount(11); | |
58 | ui->hopsTable->setColumnWidth(0, 150); /* Origin */ | |
59 | ui->hopsTable->setColumnWidth(1, 225); /* Hop */ | |
60 | ui->hopsTable->setColumnWidth(2, 75); /* Type */ | |
61 | ui->hopsTable->setColumnWidth(3, 75); /* Form */ | |
62 | ui->hopsTable->setColumnWidth(4, 75); /* Alpha% */ | |
63 | ui->hopsTable->setColumnWidth(5, 75); /* Added */ | |
64 | ui->hopsTable->setColumnWidth(6, 75); /* Time */ | |
65 | ui->hopsTable->setColumnWidth(7, 60); /* IBU */ | |
66 | ui->hopsTable->setColumnWidth(8, 75); /* Amount */ | |
67 | ui->hopsTable->setColumnWidth(9, 80); /* Delete */ | |
68 | ui->hopsTable->setColumnWidth(10, 80); /* Edit */ | |
69 | ui->hopsTable->setHorizontalHeaderLabels(labels); | |
70 | ui->hopsTable->verticalHeader()->hide(); | |
71 | ui->hopsTable->setRowCount(recipe->hops.size()); | |
72 | ||
73 | for (int i = 0; i < recipe->hops.size(); i++) { | |
74 | ||
75 | ui->hopsTable->setItem(i, 0, new QTableWidgetItem(recipe->hops.at(i).h_origin)); | |
76 | ui->hopsTable->setItem(i, 1, new QTableWidgetItem(recipe->hops.at(i).h_name)); | |
77 | ||
78 | item = new QTableWidgetItem(h_types[recipe->hops.at(i).h_type]); | |
79 | item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); | |
80 | ui->hopsTable->setItem(i, 2, item); | |
81 | ||
82 | item = new QTableWidgetItem(h_forms[recipe->hops.at(i).h_form]); | |
83 | item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); | |
84 | ui->hopsTable->setItem(i, 3, item); | |
85 | ||
86 | item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(i).h_alpha, 2, 'f', 1, '0')); | |
87 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
88 | ui->hopsTable->setItem(i, 4, item); | |
89 | ||
90 | item = new QTableWidgetItem(h_useat[recipe->hops.at(i).h_useat]); | |
91 | item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); | |
92 | ui->hopsTable->setItem(i, 5, item); | |
93 | ||
94 | if (recipe->hops.at(i).h_useat == 2 || recipe->hops.at(i).h_useat == 4) { // Boil or whirlpool | |
95 | item = new QTableWidgetItem(QString("%1 min.").arg(recipe->hops.at(i).h_time, 1, 'f', 0, '0')); | |
96 | } else if (recipe->hops.at(i).h_useat == 5) { // Dry-hop | |
97 | item = new QTableWidgetItem(QString("%1 days.").arg(recipe->hops.at(i).h_time / 1440, 1, 'f', 0, '0')); | |
98 | } else { | |
99 | item = new QTableWidgetItem(QString("")); | |
100 | } | |
101 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
102 | ui->hopsTable->setItem(i, 6, item); | |
103 | ||
104 | double ibu = Utils::toIBU(recipe->hops.at(i).h_useat, recipe->hops.at(i).h_form, recipe->preboil_sg, recipe->batch_size, recipe->hops.at(i).h_amount, | |
105 | recipe->hops.at(i).h_time, recipe->hops.at(i).h_alpha, recipe->ibu_method, 0, recipe->hops.at(i).h_time, 0); | |
106 | item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); | |
107 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
108 | ui->hopsTable->setItem(i, 7, item); | |
109 | ||
110 | if (recipe->hops.at(i).h_amount < 1.0) { | |
111 | item = new QTableWidgetItem(QString("%1 gr").arg(recipe->hops.at(i).h_amount * 1000.0, 2, 'f', 1, '0')); | |
112 | } else { | |
113 | item = new QTableWidgetItem(QString("%1 kg").arg(recipe->hops.at(i).h_amount, 4, 'f', 3, '0')); | |
114 | } | |
115 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
116 | ui->hopsTable->setItem(i, 8, item); | |
117 | ||
118 | /* Add the Delete row button */ | |
119 | pWidget = new QWidget(); | |
120 | QPushButton* btn_dele = new QPushButton(); | |
121 | btn_dele->setObjectName(QString("%1").arg(i)); /* Send row with the button */ | |
122 | btn_dele->setText(tr("Delete")); | |
123 | connect(btn_dele, SIGNAL(clicked()), this, SLOT(on_deleteHopRow_clicked())); | |
124 | pLayout = new QHBoxLayout(pWidget); | |
125 | pLayout->addWidget(btn_dele); | |
126 | pLayout->setContentsMargins(5, 0, 5, 0); | |
127 | pWidget->setLayout(pLayout); | |
128 | ui->hopsTable->setCellWidget(i, 9, pWidget); | |
129 | ||
130 | pWidget = new QWidget(); | |
131 | QPushButton* btn_edit = new QPushButton(); | |
132 | btn_edit->setObjectName(QString("%1").arg(i)); /* Send row with the button */ | |
133 | btn_edit->setText(tr("Edit")); | |
134 | connect(btn_edit, SIGNAL(clicked()), this, SLOT(on_editHopRow_clicked())); | |
135 | pLayout = new QHBoxLayout(pWidget); | |
136 | pLayout->addWidget(btn_edit); | |
137 | pLayout->setContentsMargins(5, 0, 5, 0); | |
138 | pWidget->setLayout(pLayout); | |
139 | ui->hopsTable->setCellWidget(i, 10, pWidget); | |
140 | } | |
141 | this->ignoreChanges = false; | |
142 | } | |
143 | ||
144 | ||
145 | void EditRecipe::on_Flavour_valueChanged(int value) | |
146 | { | |
147 | if (value < 20) { | |
148 | ui->hop_tasteShow->setStyleSheet(bar_20); | |
149 | ui->hop_tasteShow->setFormat(tr("Very low")); | |
150 | } else if (value < 40) { | |
151 | ui->hop_tasteShow->setStyleSheet(bar_40); | |
152 | ui->hop_tasteShow->setFormat(tr("Low")); | |
153 | } else if (value < 60) { | |
154 | ui->hop_tasteShow->setStyleSheet(bar_60); | |
155 | ui->hop_tasteShow->setFormat(tr("Moderate")); | |
156 | } else if (value < 80) { | |
157 | ui->hop_tasteShow->setStyleSheet(bar_80); | |
158 | ui->hop_tasteShow->setFormat(tr("High")); | |
159 | } else { | |
160 | ui->hop_tasteShow->setStyleSheet(bar_100); | |
161 | ui->hop_tasteShow->setFormat(tr("Very high")); | |
162 | } | |
163 | } | |
164 | ||
165 | ||
166 | void EditRecipe::on_Aroma_valueChanged(int value) | |
167 | { | |
168 | if (value < 20) { | |
169 | ui->hop_aromaShow->setStyleSheet(bar_20); | |
170 | ui->hop_aromaShow->setFormat(tr("Very low")); | |
171 | } else if (value < 40) { | |
172 | ui->hop_aromaShow->setStyleSheet(bar_40); | |
173 | ui->hop_aromaShow->setFormat(tr("Low")); | |
174 | } else if (value < 60) { | |
175 | ui->hop_aromaShow->setStyleSheet(bar_60); | |
176 | ui->hop_aromaShow->setFormat(tr("Moderate")); | |
177 | } else if (value < 80) { | |
178 | ui->hop_aromaShow->setStyleSheet(bar_80); | |
179 | ui->hop_aromaShow->setFormat(tr("High")); | |
180 | } else { | |
181 | ui->hop_aromaShow->setStyleSheet(bar_100); | |
182 | ui->hop_aromaShow->setFormat(tr("Very high")); | |
183 | } | |
184 | } | |
185 | ||
186 | ||
187 | void EditRecipe::calcIBUs() | |
188 | { | |
189 | double hop_flavour = 0, hop_aroma = 0, ibus = 0; | |
190 | ||
191 | for (int i = 0; i < recipe->hops.size(); i++) { | |
192 | ||
193 | ibus += Utils::toIBU(recipe->hops.at(i).h_useat, recipe->hops.at(i).h_form, recipe->preboil_sg, recipe->batch_size, recipe->hops.at(i).h_amount, | |
194 | recipe->hops.at(i).h_time, recipe->hops.at(i).h_alpha, recipe->ibu_method, 0, recipe->hops.at(i).h_time, 0); | |
195 | hop_flavour += Utils::hopFlavourContribution(recipe->hops.at(i).h_time, recipe->batch_size, recipe->hops.at(i).h_useat, recipe->hops.at(i).h_amount); | |
196 | hop_aroma += Utils::hopAromaContribution(recipe->hops.at(i).h_time, recipe->batch_size, recipe->hops.at(i).h_useat, recipe->hops.at(i).h_amount); | |
197 | } | |
198 | ||
199 | hop_flavour = round(hop_flavour * 1000.0 / 5.0) / 10; | |
200 | hop_aroma = round(hop_aroma * 1000.0 / 6.0) / 10; | |
201 | if (hop_flavour > 100) | |
202 | hop_flavour = 100; | |
203 | if (hop_aroma > 100) | |
204 | hop_aroma = 100; | |
205 | qDebug() << "ibu" << recipe->est_ibu << ibus << "flavour" << hop_flavour << "aroma" << hop_aroma; | |
206 | ||
207 | recipe->est_ibu = ibus; | |
208 | ui->est_ibuEdit->setValue(recipe->est_ibu); | |
209 | ui->est_ibu2Edit->setValue(recipe->est_ibu); | |
210 | ui->hop_tasteShow->setValue(hop_flavour); | |
211 | ui->hop_aromaShow->setValue(hop_aroma); | |
212 | } | |
213 | ||
214 | ||
215 | void EditRecipe::on_addHopRow_clicked() | |
216 | { | |
217 | Hops newh; | |
218 | ||
219 | qDebug() << "Add hop row"; | |
220 | ||
221 | for (int i = 0; i < recipe->hops.size(); i++) { | |
222 | if (recipe->hops.at(i).h_amount == 0 && recipe->hops.at(i).h_alpha == 0) | |
223 | return; // Add only one at a time. | |
224 | } | |
225 | ||
129
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
226 | newh.h_name = "Select one"; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
227 | newh.h_origin = ""; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
228 | newh.h_amount = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
229 | newh.h_cost = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
230 | newh.h_type = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
231 | newh.h_form = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
232 | newh.h_useat = 2; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
233 | newh.h_time = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
234 | newh.h_alpha = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
235 | newh.h_beta = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
236 | newh.h_hsi = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
237 | newh.h_humulene = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
238 | newh.h_caryophyllene = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
239 | newh.h_cohumulone = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
240 | newh.h_myrcene = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
241 | newh.h_total_oil = 0; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
242 | |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
243 | recipe->hops.append(newh); |
127 | 244 | emit refreshAll(); |
245 | } | |
246 | ||
247 | ||
248 | void EditRecipe::on_deleteHopRow_clicked() | |
249 | { | |
250 | QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); | |
251 | int row = pb->objectName().toInt(); | |
252 | qDebug() << "Delete hop row" << row << recipe->hops.size(); | |
253 | ||
254 | if (recipe->hops.size() < 1) | |
255 | return; | |
256 | ||
257 | int rc = QMessageBox::warning(this, tr("Delete hop"), tr("Delete %1").arg(recipe->hops.at(row).h_name), | |
258 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | |
259 | if (rc == QMessageBox::No) | |
260 | return; | |
261 | ||
129
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
262 | this->ignoreChanges = true; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
263 | recipe->hops.removeAt(row); |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
264 | this->ignoreChanges = false; |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
265 | is_changed(); |
a9c19eaab018
Blocked hop table edit. Implemented add and delete hop rows. Started the ui of the water tab.
Michiel Broek <mbroek@mbse.eu>
parents:
127
diff
changeset
|
266 | emit refreshAll(); |
127 | 267 | } |
268 | ||
269 | ||
270 | void EditRecipe::hop_amount_changed(double val) | |
271 | { | |
272 | QTableWidgetItem *item; | |
273 | ||
274 | qDebug() << "hop_amount_changed()" << recipe->hops_row << val; | |
275 | this->ignoreChanges = true; | |
276 | ||
277 | recipe->hops[recipe->hops_row].h_amount = val / 1000.0; | |
278 | item = new QTableWidgetItem(QString("%1 gr").arg(val, 2, 'f', 1, '0')); | |
279 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
280 | ui->hopsTable->setItem(recipe->hops_row, 8, item); | |
281 | ||
282 | double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, | |
283 | recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, | |
284 | recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); | |
285 | ||
286 | ibuEdit->setValue(ibu); | |
287 | item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); | |
288 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
289 | ui->hopsTable->setItem(recipe->hops_row, 7, item); | |
290 | ||
291 | this->ignoreChanges = false; | |
292 | calcIBUs(); | |
293 | is_changed(); | |
294 | } | |
295 | ||
296 | ||
297 | void EditRecipe::hop_time_changed(int val) | |
298 | { | |
299 | QTableWidgetItem *item; | |
300 | ||
301 | qDebug() << "hop_time_changed()" << recipe->hops_row << val; | |
302 | ||
303 | this->ignoreChanges = true; | |
304 | recipe->hops[recipe->hops_row].h_time = val; | |
305 | ||
306 | if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) { // Boil or whirlpool | |
307 | item = new QTableWidgetItem(QString("%1 min.").arg(val, 1, 'f', 0, '0')); | |
308 | } else if (recipe->hops.at(recipe->hops_row).h_useat == 5) { // Dry-hop | |
309 | item = new QTableWidgetItem(QString("%1 days.").arg(val / 1440, 1, 'f', 0, '0')); | |
310 | } else { | |
311 | item = new QTableWidgetItem(QString("")); | |
312 | } | |
313 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
314 | ui->hopsTable->setItem(recipe->hops_row, 6, item); | |
315 | ||
316 | double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, | |
317 | recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, | |
318 | recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); | |
319 | ||
320 | ibuEdit->setValue(ibu); | |
321 | item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); | |
322 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
323 | ui->hopsTable->setItem(recipe->hops_row, 7, item); | |
324 | ||
325 | this->ignoreChanges = false; | |
326 | calcIBUs(); | |
327 | is_changed(); | |
328 | } | |
329 | ||
330 | ||
331 | void EditRecipe::hop_select_changed(int val) | |
332 | { | |
333 | QSqlQuery query; | |
334 | bool instock = hinstockEdit->isChecked(); | |
335 | QString w; | |
336 | QTableWidgetItem *item; | |
337 | ||
338 | if (val < 1) | |
339 | return; | |
340 | ||
341 | qDebug() << "hop_select_changed()" << recipe->fermentables_row << val << instock; | |
342 | ||
343 | /* | |
344 | * Search the hop pointed by the index and instock flag. | |
345 | */ | |
346 | QString sql = "SELECT name,origin,alpha,beta,humulene,caryophyllene,cohumulone,myrcene,hsi,total_oil,type,form,cost FROM inventory_hops "; | |
347 | if (instock) | |
348 | sql.append("WHERE inventory > 0 "); | |
349 | sql.append("ORDER BY origin,name"); | |
350 | query.prepare(sql); | |
351 | query.exec(); | |
352 | query.first(); | |
353 | for (int i = 0; i < (val - 1); i++) { | |
354 | query.next(); | |
355 | } | |
356 | qDebug() << "found" << query.value(1).toString() << query.value(0).toString(); | |
357 | ||
358 | /* | |
359 | * Replace the hop record contents | |
360 | */ | |
361 | this->ignoreChanges = true; | |
362 | recipe->hops[recipe->hops_row].h_name = query.value(0).toString(); | |
363 | recipe->hops[recipe->hops_row].h_origin = query.value(1).toString(); | |
364 | recipe->hops[recipe->hops_row].h_alpha = query.value(2).toDouble(); | |
365 | recipe->hops[recipe->hops_row].h_beta = query.value(3).toDouble(); | |
366 | recipe->hops[recipe->hops_row].h_humulene = query.value(4).toDouble(); | |
367 | recipe->hops[recipe->hops_row].h_caryophyllene = query.value(5).toDouble(); | |
368 | recipe->hops[recipe->hops_row].h_cohumulone = query.value(6).toDouble(); | |
369 | recipe->hops[recipe->hops_row].h_myrcene = query.value(7).toDouble(); | |
370 | recipe->hops[recipe->hops_row].h_hsi = query.value(8).toDouble(); | |
371 | recipe->hops[recipe->hops_row].h_total_oil = query.value(9).toDouble(); | |
372 | recipe->hops[recipe->hops_row].h_type = query.value(10).toInt(); | |
373 | recipe->hops[recipe->hops_row].h_form = query.value(11).toInt(); | |
374 | recipe->hops[recipe->hops_row].h_cost = query.value(12).toDouble(); | |
375 | ||
376 | /* | |
377 | * Update the visible fields | |
378 | */ | |
379 | hnameEdit->setText(recipe->hops.at(recipe->hops_row).h_name); | |
380 | horiginEdit->setText(recipe->hops.at(recipe->hops_row).h_origin); | |
381 | ||
382 | double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, | |
383 | recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, | |
384 | recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); | |
385 | ibuEdit->setValue(ibu); | |
386 | ||
387 | ui->hopsTable->setItem(recipe->hops_row, 0, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).h_origin)); | |
388 | ui->hopsTable->setItem(recipe->hops_row, 1, new QTableWidgetItem(recipe->hops.at(recipe->hops_row).h_name)); | |
389 | ||
390 | item = new QTableWidgetItem(h_types[recipe->hops.at(recipe->hops_row).h_type]); | |
391 | item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); | |
392 | ui->hopsTable->setItem(recipe->hops_row, 2, item); | |
393 | ||
394 | item = new QTableWidgetItem(h_forms[recipe->hops.at(recipe->hops_row).h_form]); | |
395 | item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); | |
396 | ui->hopsTable->setItem(recipe->hops_row, 3, item); | |
397 | ||
398 | item = new QTableWidgetItem(QString("%1%").arg(recipe->hops.at(recipe->hops_row).h_alpha, 2, 'f', 1, '0')); | |
399 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
400 | ui->hopsTable->setItem(recipe->hops_row, 4, item); | |
401 | ||
402 | item = new QTableWidgetItem(QString("%1").arg(ibu, 2, 'f', 1, '0')); | |
403 | item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); | |
404 | ui->hopsTable->setItem(recipe->hops_row, 7, item); | |
405 | ||
406 | this->ignoreChanges = false; | |
407 | calcIBUs(); | |
408 | is_changed(); | |
409 | } | |
410 | ||
411 | ||
412 | void EditRecipe::hop_instock_changed(bool val) | |
413 | { | |
414 | QSqlQuery query; | |
415 | ||
416 | qDebug() << "hop_instock_changed()" << recipe->hops_row << val; | |
417 | ||
418 | this->hselectEdit->setCurrentIndex(-1); | |
419 | this->hselectEdit->clear(); | |
420 | QString sql = "SELECT origin,name,alpha,inventory FROM inventory_hops "; | |
421 | if (val) | |
422 | sql.append("WHERE inventory > 0 "); | |
423 | sql.append("ORDER BY origin,name"); | |
424 | query.prepare(sql); | |
425 | query.exec(); | |
426 | query.first(); | |
427 | this->hselectEdit->addItem(""); // Start with empty value | |
428 | for (int i = 0; i < query.size(); i++) { | |
429 | this->hselectEdit->addItem(query.value(0).toString()+" - "+query.value(1).toString()+" ("+query.value(2).toString()+"%) "+ | |
430 | QString("%1 gr").arg(query.value(3).toDouble() * 1000.0, 2, 'f', 1, '0')); | |
431 | query.next(); | |
432 | } | |
433 | } | |
434 | ||
435 | ||
436 | void EditRecipe::hop_useat_changed(int val) | |
437 | { | |
438 | qDebug() << "hop_useat_changed()" << recipe->hops_row << val; | |
439 | ||
440 | this->ignoreChanges = true; | |
441 | recipe->hops[recipe->hops_row].h_useat = val; | |
442 | QTableWidgetItem *item = new QTableWidgetItem(h_useat[val]); | |
443 | item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); | |
444 | ui->hopsTable->setItem(recipe->hops_row, 5, item); | |
445 | ||
446 | if (val == 2 || val == 4) { // Boil or whirlpool | |
447 | htimeLabel->setText(tr("Time in minutes:")); | |
448 | htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time); | |
449 | htimeEdit->setReadOnly(false); | |
450 | } else if (val == 5) { // Dry-hop | |
451 | htimeLabel->setText(tr("Time in days:")); | |
452 | htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time / 1440); | |
453 | htimeEdit->setReadOnly(false); | |
454 | } else { | |
455 | htimeLabel->setText(""); | |
456 | htimeEdit->setValue(0); | |
457 | htimeEdit->setReadOnly(true); | |
458 | } | |
459 | ||
460 | this->ignoreChanges = false; | |
461 | is_changed(); | |
462 | emit refreshAll(); | |
463 | } | |
464 | ||
465 | ||
466 | void EditRecipe::on_editHopRow_clicked() | |
467 | { | |
468 | QSqlQuery query; | |
469 | ||
470 | QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); | |
471 | recipe->hops_row = pb->objectName().toInt(); | |
472 | qDebug() << "Edit hop row" << recipe->hops_row; | |
473 | Hops backup = recipe->hops.at(recipe->hops_row); | |
474 | ||
475 | QDialog* dialog = new QDialog(this); | |
476 | dialog->resize(738, 260); | |
477 | QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); | |
478 | buttonBox->setObjectName(QString::fromUtf8("buttonBox")); | |
479 | buttonBox->setGeometry(QRect(30, 210, 671, 32)); | |
480 | buttonBox->setLayoutDirection(Qt::LeftToRight); | |
481 | buttonBox->setOrientation(Qt::Horizontal); | |
482 | buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); | |
483 | buttonBox->setCenterButtons(true); | |
484 | QLabel *nameLabel = new QLabel(dialog); | |
485 | nameLabel->setObjectName(QString::fromUtf8("nameLabel")); | |
486 | nameLabel->setText(tr("Current hop:")); | |
487 | nameLabel->setGeometry(QRect(10, 10, 141, 20)); | |
488 | nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
489 | QLabel *originLabel = new QLabel(dialog); | |
490 | originLabel->setObjectName(QString::fromUtf8("originLabel")); | |
491 | originLabel->setText(tr("Origin:")); | |
492 | originLabel->setGeometry(QRect(10, 40, 141, 20)); | |
493 | originLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
494 | QLabel *amountLabel = new QLabel(dialog); | |
495 | amountLabel->setObjectName(QString::fromUtf8("amountLabel")); | |
496 | amountLabel->setText(tr("Amount in gr:")); | |
497 | amountLabel->setGeometry(QRect(10, 100, 141, 20)); | |
498 | amountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
499 | htimeLabel = new QLabel(dialog); | |
500 | htimeLabel->setObjectName(QString::fromUtf8("htimeLabel")); | |
501 | if (recipe->hops.at(recipe->hops_row).h_useat == 5) // Dry-hop | |
502 | htimeLabel->setText(tr("Time in days:")); | |
503 | else if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) // Boil or whirlpool | |
504 | htimeLabel->setText(tr("Time in minutes:")); | |
505 | else | |
506 | htimeLabel->setText(""); | |
507 | ||
508 | htimeLabel->setGeometry(QRect(10, 130, 141, 20)); | |
509 | htimeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
510 | QLabel *useatLabel = new QLabel(dialog); | |
511 | useatLabel->setObjectName(QString::fromUtf8("useatLabel")); | |
512 | useatLabel->setText(tr("Use at:")); | |
513 | useatLabel->setGeometry(QRect(10, 160, 141, 20)); | |
514 | useatLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
515 | QLabel *selectLabel = new QLabel(dialog); | |
516 | selectLabel->setObjectName(QString::fromUtf8("selectLabel")); | |
517 | selectLabel->setText(tr("Select hop:")); | |
518 | selectLabel->setGeometry(QRect(10, 70, 141, 20)); | |
519 | selectLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
520 | QLabel *instockLabel = new QLabel(dialog); | |
521 | instockLabel->setObjectName(QString::fromUtf8("instockLabel")); | |
522 | instockLabel->setText(tr("In stock:")); | |
523 | instockLabel->setGeometry(QRect(525, 70, 121, 20)); | |
524 | instockLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
525 | QLabel *ibuLabel = new QLabel(dialog); | |
526 | ibuLabel->setObjectName(QString::fromUtf8("maxLabel")); | |
527 | ibuLabel->setText(tr("Bitterness IBU:")); | |
528 | ibuLabel->setGeometry(QRect(420, 130, 121, 20)); | |
529 | ibuLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
530 | ||
531 | hselectEdit = new QComboBox(dialog); | |
532 | hselectEdit->setObjectName(QString::fromUtf8("selectEdit")); | |
533 | hselectEdit->setGeometry(QRect(160, 70, 371, 23)); | |
534 | ||
535 | hnameEdit = new QLineEdit(dialog); | |
536 | hnameEdit->setObjectName(QString::fromUtf8("hnameEdit")); | |
537 | hnameEdit->setText(recipe->hops.at(recipe->hops_row).h_name); | |
538 | hnameEdit->setGeometry(QRect(160, 10, 511, 23)); | |
539 | hnameEdit->setReadOnly(true); | |
540 | horiginEdit = new QLineEdit(dialog); | |
541 | horiginEdit->setObjectName(QString::fromUtf8("horiginEdit")); | |
542 | horiginEdit->setText(recipe->hops.at(recipe->hops_row).h_origin); | |
543 | horiginEdit->setGeometry(QRect(160, 40, 511, 23)); | |
544 | horiginEdit->setReadOnly(true); | |
545 | hamountEdit = new QDoubleSpinBox(dialog); | |
546 | hamountEdit->setObjectName(QString::fromUtf8("hamountEdit")); | |
547 | hamountEdit->setGeometry(QRect(160, 100, 121, 24)); | |
548 | hamountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
549 | hamountEdit->setAccelerated(true); | |
550 | hamountEdit->setDecimals(1); | |
551 | hamountEdit->setMaximum(1000000.0); | |
552 | hamountEdit->setSingleStep(0.5); | |
553 | hamountEdit->setValue(recipe->hops.at(recipe->hops_row).h_amount * 1000.0); | |
554 | htimeEdit = new QSpinBox(dialog); | |
555 | htimeEdit->setObjectName(QString::fromUtf8("htimeEdit")); | |
556 | htimeEdit->setGeometry(QRect(160, 130, 121, 24)); | |
557 | htimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
558 | htimeEdit->setAccelerated(true); | |
559 | htimeEdit->setMaximum(10000.0); | |
560 | if (recipe->hops.at(recipe->hops_row).h_useat == 2 || recipe->hops.at(recipe->hops_row).h_useat == 4) { // Boil or whirlpool | |
561 | htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time); | |
562 | htimeEdit->setReadOnly(false); | |
563 | } else if (recipe->hops.at(recipe->hops_row).h_useat == 5){ // Dry-hop | |
564 | htimeEdit->setValue(recipe->hops.at(recipe->hops_row).h_time / 1440); | |
565 | htimeEdit->setReadOnly(false); | |
566 | } else { | |
567 | htimeEdit->setReadOnly(true); | |
568 | } | |
569 | useatEdit = new QComboBox(dialog); | |
570 | useatEdit->setObjectName(QString::fromUtf8("useatEdit")); | |
571 | useatEdit->setGeometry(QRect(160, 160, 161, 23)); | |
572 | useatEdit->addItem(tr("Mash")); | |
573 | useatEdit->addItem(tr("First wort")); | |
574 | useatEdit->addItem(tr("Boil")); | |
575 | useatEdit->addItem(tr("Aroma")); | |
576 | useatEdit->addItem(tr("Whirlpool")); | |
577 | useatEdit->addItem(tr("Dry hop")); | |
578 | useatEdit->setCurrentIndex(recipe->hops.at(recipe->hops_row).h_useat); | |
579 | ||
580 | hinstockEdit = new QCheckBox(dialog); | |
581 | hinstockEdit->setObjectName(QString::fromUtf8("hinstockEdit")); | |
582 | hinstockEdit->setGeometry(QRect(655, 70, 85, 21)); | |
583 | hinstockEdit->setChecked(true); | |
584 | ||
585 | ibuEdit = new QDoubleSpinBox(dialog); | |
586 | ibuEdit->setObjectName(QString::fromUtf8("ibuEdit")); | |
587 | ibuEdit->setGeometry(QRect(550, 130, 121, 24)); | |
588 | ibuEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); | |
589 | ibuEdit->setReadOnly(true); | |
590 | ibuEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); | |
591 | ibuEdit->setDecimals(1); | |
592 | double ibu = Utils::toIBU(recipe->hops.at(recipe->hops_row).h_useat, recipe->hops.at(recipe->hops_row).h_form, recipe->preboil_sg, | |
593 | recipe->batch_size, recipe->hops.at(recipe->hops_row).h_amount, recipe->hops.at(recipe->hops_row).h_time, | |
594 | recipe->hops.at(recipe->hops_row).h_alpha, recipe->ibu_method, 0, recipe->hops.at(recipe->hops_row).h_time, 0); | |
595 | ibuEdit->setValue(ibu); | |
596 | ||
597 | hop_instock_changed(true); | |
598 | ||
599 | connect(hselectEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_select_changed); | |
600 | connect(hamountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::hop_amount_changed); | |
601 | connect(htimeEdit, QOverload<int>::of(&QSpinBox::valueChanged), this, &EditRecipe::hop_time_changed); | |
602 | connect(useatEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditRecipe::hop_useat_changed); | |
603 | connect(hinstockEdit, &QCheckBox::stateChanged, this, &EditRecipe::hop_instock_changed); | |
604 | connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); | |
605 | connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); | |
606 | ||
607 | dialog->setModal(true); | |
608 | dialog->exec(); | |
609 | if (dialog->result() == QDialog::Rejected) { | |
610 | qDebug() << "reject and rollback"; | |
611 | recipe->hops[recipe->hops_row] = backup; | |
612 | } else { | |
613 | /* Clear time if hop is not used for boil, whirlpool or dry-hop. */ | |
614 | if (! (recipe->hops.at(recipe->hops_row).h_useat == 2 || | |
615 | recipe->hops.at(recipe->hops_row).h_useat == 4 || | |
616 | recipe->hops.at(recipe->hops_row).h_useat == 5)) { | |
617 | if (recipe->hops.at(recipe->hops_row).h_time) { | |
618 | recipe->hops[recipe->hops_row].h_time = 0; | |
619 | is_changed(); | |
620 | } | |
621 | } | |
622 | } | |
623 | ||
624 | disconnect(hselectEdit, nullptr, nullptr, nullptr); | |
625 | disconnect(hamountEdit, nullptr, nullptr, nullptr); | |
626 | disconnect(htimeEdit, nullptr, nullptr, nullptr); | |
627 | disconnect(useatEdit, nullptr, nullptr, nullptr); | |
628 | disconnect(hinstockEdit, nullptr, nullptr, nullptr); | |
629 | disconnect(buttonBox, nullptr, nullptr, nullptr); | |
630 | ||
631 | emit refreshAll(); | |
632 | } | |
633 | ||
634 |