|
1 /** |
|
2 * EditProduct.cpp is part of bmsapp. |
|
3 * |
|
4 * tab 7, mash. |
|
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 void EditProduct::refreshMashs() |
|
22 { |
|
23 QString w; |
|
24 QWidget* pWidget; |
|
25 QHBoxLayout* pLayout; |
|
26 QTableWidgetItem *item; |
|
27 QIcon down_icon, up_icon; |
|
28 |
|
29 qDebug() << "refreshMashs" << product->mashs.size(); |
|
30 |
|
31 down_icon.addFile(QString::fromUtf8(":/icons/silk/bullet_arrow_down.png"), QSize(), QIcon::Normal, QIcon::Off); |
|
32 up_icon.addFile(QString::fromUtf8(":/icons/silk/bullet_arrow_up.png"), QSize(), QIcon::Normal, QIcon::Off); |
|
33 |
|
34 const QStringList labels({tr("Step name"), tr("Type"), tr("Start"), tr("End"), tr("Rest"), tr("Ramp"), |
|
35 tr("Inf/dec"), tr("Inf/dec"), tr("Volume"), tr("W/G ratio"), "", "", tr("Delete"), tr("Edit") }); |
|
36 |
|
37 ui->mashsTable->setColumnCount(14); |
|
38 ui->mashsTable->setColumnWidth(0, 189); /* Step name */ |
|
39 ui->mashsTable->setColumnWidth(1, 100); /* Type */ |
|
40 ui->mashsTable->setColumnWidth(2, 70); /* Start temp */ |
|
41 ui->mashsTable->setColumnWidth(3, 70); /* End temp */ |
|
42 ui->mashsTable->setColumnWidth(4, 70); /* Rest time */ |
|
43 ui->mashsTable->setColumnWidth(5, 70); /* Ramp time */ |
|
44 ui->mashsTable->setColumnWidth(6, 70); /* Infusion vol */ |
|
45 ui->mashsTable->setColumnWidth(7, 70); /* Infusion tmp */ |
|
46 ui->mashsTable->setColumnWidth(8, 70); /* Volume */ |
|
47 ui->mashsTable->setColumnWidth(9, 80); /* W/G ratio */ |
|
48 ui->mashsTable->setColumnWidth(10, 30); /* Up button */ |
|
49 ui->mashsTable->setColumnWidth(11, 30); /* Down button */ |
|
50 ui->mashsTable->setColumnWidth(12, 80); /* Delete */ |
|
51 ui->mashsTable->setColumnWidth(13, 80); /* Edit */ |
|
52 ui->mashsTable->setHorizontalHeaderLabels(labels); |
|
53 ui->mashsTable->verticalHeader()->hide(); |
|
54 ui->mashsTable->setRowCount(product->mashs.size()); |
|
55 |
|
56 for (int i = 0; i < product->mashs.size(); i++) { |
|
57 |
|
58 ui->mashsTable->setItem(i, 0, new QTableWidgetItem(product->mashs.at(i).step_name)); |
|
59 |
|
60 item = new QTableWidgetItem(step_types[product->mashs.at(i).step_type]); |
|
61 item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter); |
|
62 ui->mashsTable->setItem(i, 1, item); |
|
63 |
|
64 item = new QTableWidgetItem(QString("%1 °C").arg(product->mashs.at(i).step_temp, 2, 'f', 1, '0')); |
|
65 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
66 ui->mashsTable->setItem(i, 2, item); |
|
67 |
|
68 item = new QTableWidgetItem(QString("%1 °C").arg(product->mashs.at(i).end_temp, 2, 'f', 1, '0')); |
|
69 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
70 ui->mashsTable->setItem(i, 3, item); |
|
71 |
|
72 item = new QTableWidgetItem(QString("%1 min").arg(product->mashs.at(i).step_time, 1, 'f', 0, '0')); |
|
73 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
74 ui->mashsTable->setItem(i, 4, item); |
|
75 |
|
76 item = new QTableWidgetItem(QString("%1 min").arg(product->mashs.at(i).ramp_time, 1, 'f', 0, '0')); |
|
77 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
78 ui->mashsTable->setItem(i, 5, item); |
|
79 |
|
80 if (product->mashs.at(i).step_infuse_amount > 0) { |
|
81 item = new QTableWidgetItem(QString("%1 L").arg(product->mashs.at(i).step_infuse_amount, 2, 'f', 1, '0')); |
|
82 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
83 ui->mashsTable->setItem(i, 6, item); |
|
84 item = new QTableWidgetItem(QString("%1 °C").arg(product->mashs.at(i).step_infuse_temp, 3, 'f', 2, '0')); |
|
85 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
86 ui->mashsTable->setItem(i, 7, item); |
|
87 } else { |
|
88 ui->mashsTable->removeCellWidget(i, 6); |
|
89 ui->mashsTable->removeCellWidget(i, 7); |
|
90 } |
|
91 |
|
92 item = new QTableWidgetItem(QString("%1 L").arg(product->mashs.at(i).step_volume, 2, 'f', 1, '0')); |
|
93 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
94 ui->mashsTable->setItem(i, 8, item); |
|
95 |
|
96 item = new QTableWidgetItem(QString("%1 L/kg").arg(product->mashs.at(i).step_wg_ratio, 3, 'f', 2, '0')); |
|
97 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
98 ui->mashsTable->setItem(i, 9, item); |
|
99 |
|
100 if (i > 0) { |
|
101 pWidget = new QWidget(); |
|
102 QPushButton* btn_up = new QPushButton(); |
|
103 btn_up->setObjectName(QString("%1").arg(i)); /* Send row with the button */ |
|
104 btn_up->setIcon(up_icon); |
|
105 connect(btn_up, SIGNAL(clicked()), this, SLOT(upMashRow_clicked())); |
|
106 pLayout = new QHBoxLayout(pWidget); |
|
107 pLayout->addWidget(btn_up); |
|
108 pLayout->setContentsMargins(5, 0, 5, 0); |
|
109 pWidget->setLayout(pLayout); |
|
110 ui->mashsTable->setCellWidget(i, 10, pWidget); |
|
111 } else { |
|
112 ui->mashsTable->removeCellWidget(i, 10); |
|
113 } |
|
114 |
|
115 if (i < (product->mashs.size() - 1)) { |
|
116 pWidget = new QWidget(); |
|
117 QPushButton* btn_down = new QPushButton(); |
|
118 btn_down->setObjectName(QString("%1").arg(i)); /* Send row with the button */ |
|
119 btn_down->setIcon(down_icon); |
|
120 connect(btn_down, SIGNAL(clicked()), this, SLOT(downMashRow_clicked())); |
|
121 pLayout = new QHBoxLayout(pWidget); |
|
122 pLayout->addWidget(btn_down); |
|
123 pLayout->setContentsMargins(5, 0, 5, 0); |
|
124 pWidget->setLayout(pLayout); |
|
125 ui->mashsTable->setCellWidget(i, 11, pWidget); |
|
126 } else { |
|
127 ui->mashsTable->removeCellWidget(i, 11); |
|
128 } |
|
129 |
|
130 pWidget = new QWidget(); |
|
131 QPushButton* btn_dele = new QPushButton(); |
|
132 btn_dele->setObjectName(QString("%1").arg(i)); /* Send row with the button */ |
|
133 btn_dele->setText(tr("Delete")); |
|
134 connect(btn_dele, SIGNAL(clicked()), this, SLOT(deleteMashRow_clicked())); |
|
135 pLayout = new QHBoxLayout(pWidget); |
|
136 pLayout->addWidget(btn_dele); |
|
137 pLayout->setContentsMargins(5, 0, 5, 0); |
|
138 pWidget->setLayout(pLayout); |
|
139 ui->mashsTable->setCellWidget(i, 12, pWidget); |
|
140 |
|
141 pWidget = new QWidget(); |
|
142 QPushButton* btn_edit = new QPushButton(); |
|
143 btn_edit->setObjectName(QString("%1").arg(i)); /* Send row with the button */ |
|
144 btn_edit->setText(tr("Edit")); |
|
145 connect(btn_edit, SIGNAL(clicked()), this, SLOT(editMashRow_clicked())); |
|
146 pLayout = new QHBoxLayout(pWidget); |
|
147 pLayout->addWidget(btn_edit); |
|
148 pLayout->setContentsMargins(5, 0, 5, 0); |
|
149 pWidget->setLayout(pLayout); |
|
150 ui->mashsTable->setCellWidget(i, 13, pWidget); |
|
151 } |
|
152 } |
|
153 |
|
154 |
|
155 double EditProduct::infusionVol(double step_infused, double step_mashkg, double infuse_temp, double step_temp, double last_temp) |
|
156 { |
|
157 double a = last_temp * (equip_tun_weight * equip_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); |
|
158 double b = step_temp * (equip_tun_weight * equip_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); |
|
159 double vol = round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)) * 100.0) / 100.0; |
|
160 |
|
161 if (vol < 0) |
|
162 vol = 0; |
|
163 qDebug() << " infusionVol(" << step_infused << "," << step_mashkg << "," << infuse_temp <<"," << step_temp << "," << last_temp << "):" << vol; |
|
164 return vol; |
|
165 } |
|
166 |
|
167 |
|
168 double EditProduct::decoctionVol(double step_volume, double step_temp, double prev_temp) |
|
169 { |
|
170 double a = (equip_tun_weight * equip_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); |
|
171 double b = SpecificHeatWater * (99 - step_temp); |
|
172 double vol = 0; |
|
173 |
|
174 if (b > 0) |
|
175 vol = round((a / b) * 1000000.0) / 1000000.0; |
|
176 qDebug() << " decoctionVol(" << step_volume << "," << step_temp << "," << prev_temp << "):" << vol; |
|
177 return vol; |
|
178 } |
|
179 |
|
180 |
|
181 void EditProduct::calcMash() |
|
182 { |
|
183 double infused = 0, vol, a, b, temp; |
|
184 int i, j, n; |
|
185 double lasttemp = 18.0; |
|
186 double graintemp = 18.0; |
|
187 double tuntemp = 18.0; |
|
188 |
|
189 product->mashs_time = 0; |
|
190 |
|
191 if (product->mashs.size() && product->mashs_kg > 0) { |
|
192 qDebug() << "calcMash()"; |
|
193 |
|
194 for (i = 0; i < product->mashs.size(); i++) { |
|
195 if (product->mashs.at(i).step_type == 0) { // Infusion |
|
196 if (i == 0) { |
|
197 // First mash step, temperature from the mashtun and malt. |
|
198 n = 20; // tun is preheated. |
|
199 tuntemp = product->mashs.at(i).step_temp; |
|
200 for (j = 0; j < n; j++) { |
|
201 a = product->mashs_kg * graintemp * SpecificHeatMalt + equip_tun_weight * tuntemp * equip_tun_specific_heat; |
|
202 b = product->mashs[i].step_temp * |
|
203 (equip_tun_weight * equip_tun_specific_heat + |
|
204 product->mashs.at(i).step_infuse_amount * SpecificHeatWater + |
|
205 product->mashs_kg * SpecificHeatMalt) - |
|
206 SlakingHeat * product->mashs_kg; |
|
207 if (product->mashs.at(i).step_infuse_amount > 0) { |
|
208 temp = (b - a) / (product->mashs.at(i).step_infuse_amount * SpecificHeatWater); |
|
209 } else { |
|
210 temp = 99; |
|
211 } |
|
212 tuntemp += (temp - tuntemp) / 2; |
|
213 product->mashs[i].step_infuse_temp = round(temp * 1000000.0) / 1000000.0; |
|
214 } |
|
215 qDebug() << " init infuse temp:" << product->mashs.at(i).step_infuse_temp; |
|
216 } else { |
|
217 // Calculate amount of infusion water. |
|
218 product->mashs[i].step_infuse_amount = |
|
219 infusionVol(infused, product->mashs_kg, product->mashs.at(i).step_infuse_temp, product->mashs.at(i).step_temp, lasttemp); |
|
220 qDebug() << i << " vol:" << product->mashs.at(i).step_infuse_amount << "temp:" << product->mashs.at(i).step_infuse_temp; |
|
221 } |
|
222 infused += product->mashs.at(i).step_infuse_amount; |
|
223 } else if (product->mashs.at(i).step_type == 1) { // Temperature |
|
224 if (i > 0) |
|
225 product->mashs[i].step_infuse_amount = 0; |
|
226 product->mashs[i].step_infuse_temp = 0; |
|
227 } else if (product->mashs.at(i).step_type == 2) { // Decoction |
|
228 product->mashs[i].step_infuse_amount = decoctionVol(infused, product->mashs.at(i).step_temp, lasttemp); |
|
229 product->mashs[i].step_infuse_temp = 99; |
|
230 } |
|
231 product->mashs[i].step_volume = infused; |
|
232 //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; |
|
233 lasttemp = product->mashs.at(i).step_temp; |
|
234 product->mashs_time += product->mashs.at(i).step_time; |
|
235 if (i > 0) |
|
236 product->mashs_time += product->mashs.at(i).ramp_time; |
|
237 product->mashs[i].step_wg_ratio = round((infused / product->mashs_kg) * 1000000.0) / 1000000.0; |
|
238 } |
|
239 } |
|
240 |
|
241 /* Show the calculated total mash time. */ |
|
242 ui->mash_timeEdit->setText(QString("%1:%2").arg(product->mashs_time / 60).arg(product->mashs_time % 60, 2, 'f', 0, '0')); |
|
243 } |
|
244 |
|
245 |
|
246 void EditProduct::addMashRow_clicked() |
|
247 { |
|
248 Mashs newm; |
|
249 |
|
250 for (int i = 0; i < product->mashs.size(); i++) { |
|
251 if (product->mashs.at(i).step_time == 0) |
|
252 return; // Add only one at a time. |
|
253 } |
|
254 |
|
255 newm.step_name = "Name me"; |
|
256 newm.step_temp = newm.end_temp = 67.0; |
|
257 newm.step_time = 20; |
|
258 newm.ramp_time = 10; |
|
259 if (product->mashs.size()) { |
|
260 newm.step_volume = product->mashs.at(product->mashs.size() - 1).step_volume; |
|
261 newm.step_wg_ratio = product->mashs.at(product->mashs.size() - 1).step_wg_ratio; |
|
262 newm.step_type = product->mashs.at(product->mashs.size() - 1).step_type; |
|
263 } else { |
|
264 newm.step_volume = 0; |
|
265 newm.step_wg_ratio = 0; |
|
266 newm.step_type = 1; |
|
267 } |
|
268 newm.step_infuse_amount = newm.step_infuse_temp = 0; |
|
269 |
|
270 product->mashs.append(newm); |
|
271 is_changed(); |
|
272 emit refreshAll(); |
|
273 } |
|
274 |
|
275 |
|
276 void EditProduct::deleteMashRow_clicked() |
|
277 { |
|
278 if (product->locked || product->mashs.size() < 1) |
|
279 return; |
|
280 |
|
281 QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); |
|
282 int row = pb->objectName().toInt(); |
|
283 qDebug() << "Delete mash row" << row << product->mashs.size(); |
|
284 |
|
285 int rc = QMessageBox::warning(this, tr("Delete mash step"), tr("Delete %1").arg(product->mashs.at(row).step_name), |
|
286 QMessageBox::Yes | QMessageBox::No, QMessageBox::No); |
|
287 if (rc == QMessageBox::No) |
|
288 return; |
|
289 |
|
290 product->mashs.removeAt(row); |
|
291 is_changed(); |
|
292 emit refreshAll(); |
|
293 } |
|
294 |
|
295 |
|
296 void EditProduct::upMashRow_clicked() |
|
297 { |
|
298 if (product->locked || product->mashs.size() < 1) |
|
299 return; |
|
300 |
|
301 QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); |
|
302 int row = pb->objectName().toInt(); |
|
303 qDebug() << "Move up mash row" << row << product->mashs.size(); |
|
304 |
|
305 Mashs temp; |
|
306 temp = product->mashs[row - 1]; |
|
307 product->mashs[row - 1] = product->mashs[row]; |
|
308 product->mashs[row] = temp; |
|
309 is_changed(); |
|
310 emit refreshAll(); |
|
311 } |
|
312 |
|
313 |
|
314 void EditProduct::downMashRow_clicked() |
|
315 { |
|
316 if (product->locked || product->mashs.size() < 1) |
|
317 return; |
|
318 |
|
319 QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); |
|
320 int row = pb->objectName().toInt(); |
|
321 qDebug() << "Move down mash row" << row << product->mashs.size(); |
|
322 |
|
323 Mashs temp; |
|
324 temp = product->mashs[row + 1]; |
|
325 product->mashs[row + 1] = product->mashs[row]; |
|
326 product->mashs[row] = temp; |
|
327 is_changed(); |
|
328 emit refreshAll(); |
|
329 } |
|
330 |
|
331 |
|
332 void EditProduct::step_name_changed(QString val) |
|
333 { |
|
334 product->mashs[product->mashs_row].step_name = val; |
|
335 ui->mashsTable->setItem(product->mashs_row, 0, new QTableWidgetItem(val)); |
|
336 is_changed(); |
|
337 } |
|
338 |
|
339 |
|
340 void EditProduct::step_type_changed(int val) |
|
341 { |
|
342 qDebug() << "step_type_changed" << product->mashs_row << val; |
|
343 |
|
344 product->mashs[product->mashs_row].step_type = val; |
|
345 ivolLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
346 stepivolEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
347 itmpLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
348 stepitmpEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
349 is_changed(); |
|
350 emit refreshAll(); |
|
351 } |
|
352 |
|
353 |
|
354 void EditProduct::step_temp_changed(double val) |
|
355 { |
|
356 qDebug() << "step_temp_changed" << product->mashs_row << val; |
|
357 product->mashs[product->mashs_row].step_temp = val; |
|
358 QTableWidgetItem *item = new QTableWidgetItem(QString("%1 °C").arg(val, 2, 'f', 1, '0')); |
|
359 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
360 ui->mashsTable->setItem(product->mashs_row, 2, item); |
|
361 is_changed(); |
|
362 emit refreshAll(); |
|
363 } |
|
364 |
|
365 |
|
366 void EditProduct::end_temp_changed(double val) |
|
367 { |
|
368 qDebug() << "end_temp_changed" << product->mashs_row << val; |
|
369 product->mashs[product->mashs_row].end_temp = val; |
|
370 QTableWidgetItem *item = new QTableWidgetItem(QString("%1 °C").arg(val, 2, 'f', 1, '0')); |
|
371 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
372 ui->mashsTable->setItem(product->mashs_row, 3, item); |
|
373 is_changed(); |
|
374 emit refreshAll(); |
|
375 } |
|
376 |
|
377 |
|
378 void EditProduct::step_time_changed(double val) |
|
379 { |
|
380 qDebug() << "step_time_changed" << product->mashs_row << val; |
|
381 product->mashs[product->mashs_row].step_time = val; |
|
382 QTableWidgetItem *item = new QTableWidgetItem(QString("%1 min").arg(val, 1, 'f', 0, '0')); |
|
383 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
384 ui->mashsTable->setItem(product->mashs_row, 4, item); |
|
385 is_changed(); |
|
386 emit refreshAll(); |
|
387 } |
|
388 |
|
389 |
|
390 void EditProduct::ramp_time_changed(double val) |
|
391 { |
|
392 qDebug() << "ramp_time_changed" << product->mashs_row << val; |
|
393 product->mashs[product->mashs_row].ramp_time = val; |
|
394 QTableWidgetItem *item = new QTableWidgetItem(QString("%1 min").arg(val, 1, 'f', 0, '0')); |
|
395 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
396 ui->mashsTable->setItem(product->mashs_row, 5, item); |
|
397 is_changed(); |
|
398 emit refreshAll(); |
|
399 } |
|
400 |
|
401 |
|
402 void EditProduct::infuse_changed(double val) |
|
403 { |
|
404 qDebug() << "infuse_changed" << product->mashs_row << val; |
|
405 product->mashs[product->mashs_row].step_infuse_amount = val; |
|
406 QTableWidgetItem *item = new QTableWidgetItem(QString("%1 L").arg(val, 1, 'f', 0, '0')); |
|
407 item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); |
|
408 ui->mashsTable->setItem(product->mashs_row, 6, item); |
|
409 |
|
410 /* |
|
411 * Recalculate water volumes |
|
412 */ |
|
413 double volume = 0; |
|
414 for (int i = 0; i < product->mashs.size(); i++) { |
|
415 if (product->mashs.at(i).step_type == 0) { |
|
416 volume += product->mashs.at(i).step_infuse_amount; |
|
417 } |
|
418 product->mashs[i].step_volume = volume; |
|
419 } |
|
420 product->w1_amount = volume - product->w2_amount; |
|
421 product->wg_amount = volume; |
|
422 ui->w1_volEdit->setValue(product->w1_amount); |
|
423 |
|
424 is_changed(); |
|
425 emit refreshAll(); |
|
426 } |
|
427 |
|
428 |
|
429 void EditProduct::editMashRow_clicked() |
|
430 { |
|
431 QSqlQuery query; |
|
432 |
|
433 if (product->locked) |
|
434 return; |
|
435 |
|
436 QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender()); |
|
437 product->mashs_row = pb->objectName().toInt(); |
|
438 qDebug() << "Edit mash row" << product->mashs_row; |
|
439 Mashs backup = product->mashs.at(product->mashs_row); |
|
440 |
|
441 QDialog* dialog = new QDialog(this); |
|
442 dialog->resize(738, 230); |
|
443 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); |
|
444 buttonBox->setObjectName(QString::fromUtf8("buttonBox")); |
|
445 buttonBox->setGeometry(QRect(30, 180, 671, 32)); |
|
446 buttonBox->setLayoutDirection(Qt::LeftToRight); |
|
447 buttonBox->setOrientation(Qt::Horizontal); |
|
448 buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); |
|
449 buttonBox->setCenterButtons(true); |
|
450 |
|
451 QLabel *nameLabel = new QLabel(dialog); |
|
452 nameLabel->setObjectName(QString::fromUtf8("nameLabel")); |
|
453 nameLabel->setText(tr("Step name:")); |
|
454 nameLabel->setGeometry(QRect(10, 10, 141, 20)); |
|
455 nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
456 stepnameEdit = new QLineEdit(dialog); |
|
457 stepnameEdit->setObjectName(QString::fromUtf8("stepnameEdit")); |
|
458 stepnameEdit->setText(product->mashs.at(product->mashs_row).step_name); |
|
459 stepnameEdit->setGeometry(QRect(160, 10, 511, 23)); |
|
460 |
|
461 QLabel *typeLabel = new QLabel(dialog); |
|
462 typeLabel->setObjectName(QString::fromUtf8("typeLabel")); |
|
463 typeLabel->setText(tr("Step type:")); |
|
464 typeLabel->setGeometry(QRect(10, 40, 141, 20)); |
|
465 typeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
466 QComboBox *typeEdit = new QComboBox(dialog); |
|
467 typeEdit->setObjectName(QString::fromUtf8("typeEdit")); |
|
468 typeEdit->setGeometry(QRect(160, 40, 161, 23)); |
|
469 typeEdit->addItem(tr("Infusion")); |
|
470 typeEdit->addItem(tr("Temperature")); |
|
471 typeEdit->addItem(tr("Decoction")); |
|
472 typeEdit->setCurrentIndex(product->mashs.at(product->mashs_row).step_type); |
|
473 |
|
474 QLabel *tempLabel = new QLabel(dialog); |
|
475 tempLabel->setObjectName(QString::fromUtf8("tempLabel")); |
|
476 tempLabel->setText(tr("Step start temp:")); |
|
477 tempLabel->setGeometry(QRect(10, 70, 141, 20)); |
|
478 tempLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
479 steptempEdit = new QDoubleSpinBox(dialog); |
|
480 steptempEdit->setObjectName(QString::fromUtf8("steptempEdit")); |
|
481 steptempEdit->setGeometry(QRect(160, 70, 121, 24)); |
|
482 steptempEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
483 steptempEdit->setDecimals(1); |
|
484 steptempEdit->setValue(product->mashs.at(product->mashs_row).step_temp); |
|
485 |
|
486 QLabel *endLabel = new QLabel(dialog); |
|
487 endLabel->setObjectName(QString::fromUtf8("endLabel")); |
|
488 endLabel->setText(tr("Step end temp:")); |
|
489 endLabel->setGeometry(QRect(360, 70, 141, 20)); |
|
490 endLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
491 endtempEdit = new QDoubleSpinBox(dialog); |
|
492 endtempEdit->setObjectName(QString::fromUtf8("endtempEdit")); |
|
493 endtempEdit->setGeometry(QRect(510, 70, 121, 24)); |
|
494 endtempEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
495 endtempEdit->setDecimals(1); |
|
496 endtempEdit->setValue(product->mashs.at(product->mashs_row).end_temp); |
|
497 |
|
498 QLabel *timeLabel = new QLabel(dialog); |
|
499 timeLabel->setObjectName(QString::fromUtf8("timeLabel")); |
|
500 timeLabel->setText(tr("Step rest time:")); |
|
501 timeLabel->setGeometry(QRect(10, 100, 141, 20)); |
|
502 timeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
503 steptimeEdit = new QDoubleSpinBox(dialog); |
|
504 steptimeEdit->setObjectName(QString::fromUtf8("steptimeEdit")); |
|
505 steptimeEdit->setGeometry(QRect(160, 100, 121, 24)); |
|
506 steptimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
507 steptimeEdit->setDecimals(0); |
|
508 steptimeEdit->setValue(product->mashs.at(product->mashs_row).step_time); |
|
509 |
|
510 QLabel *rampLabel = new QLabel(dialog); |
|
511 rampLabel->setObjectName(QString::fromUtf8("rampLabel")); |
|
512 rampLabel->setText(tr("Step ramp time:")); |
|
513 rampLabel->setGeometry(QRect(360, 100, 141, 20)); |
|
514 rampLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
515 ramptimeEdit = new QDoubleSpinBox(dialog); |
|
516 ramptimeEdit->setObjectName(QString::fromUtf8("ramptimeEdit")); |
|
517 ramptimeEdit->setGeometry(QRect(510, 100, 121, 24)); |
|
518 ramptimeEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
519 ramptimeEdit->setDecimals(0); |
|
520 ramptimeEdit->setValue(product->mashs.at(product->mashs_row).ramp_time); |
|
521 |
|
522 /* |
|
523 * Only used for Infusion steps. |
|
524 */ |
|
525 ivolLabel = new QLabel(dialog); |
|
526 ivolLabel->setObjectName(QString::fromUtf8("ivolLabel")); |
|
527 ivolLabel->setText(tr("Infusion volume:")); |
|
528 ivolLabel->setGeometry(QRect(10, 130, 141, 20)); |
|
529 ivolLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
530 ivolLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
531 stepivolEdit = new QDoubleSpinBox(dialog); |
|
532 stepivolEdit->setObjectName(QString::fromUtf8("stepivolEdit")); |
|
533 stepivolEdit->setGeometry(QRect(160, 130, 121, 24)); |
|
534 stepivolEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
535 stepivolEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
536 stepivolEdit->setDecimals(1); |
|
537 stepivolEdit->setAccelerated(true); |
|
538 stepivolEdit->setMaximum(100000.0); |
|
539 stepivolEdit->setSingleStep(0.5); |
|
540 stepivolEdit->setValue(product->mashs.at(product->mashs_row).step_infuse_amount); |
|
541 |
|
542 itmpLabel = new QLabel(dialog); |
|
543 itmpLabel->setObjectName(QString::fromUtf8("itmpLabel")); |
|
544 itmpLabel->setText(tr("Infusion Temperature:")); |
|
545 itmpLabel->setGeometry(QRect(360, 130, 141, 20)); |
|
546 itmpLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
547 itmpLabel->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
548 stepitmpEdit = new QDoubleSpinBox(dialog); |
|
549 stepitmpEdit->setObjectName(QString::fromUtf8("stepitmpEdit")); |
|
550 stepitmpEdit->setGeometry(QRect(510, 130, 121, 24)); |
|
551 stepitmpEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); |
|
552 stepitmpEdit->setVisible(product->mashs.at(product->mashs_row).step_type == 0); |
|
553 stepitmpEdit->setDecimals(1); |
|
554 stepitmpEdit->setReadOnly(true); |
|
555 stepitmpEdit->setButtonSymbols(QAbstractSpinBox::NoButtons); |
|
556 stepitmpEdit->setValue(product->mashs.at(product->mashs_row).step_infuse_temp); |
|
557 |
|
558 connect(stepnameEdit, &QLineEdit::textEdited, this, &EditProduct::step_name_changed); |
|
559 connect(typeEdit, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &EditProduct::step_type_changed); |
|
560 connect(steptempEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::step_temp_changed); |
|
561 connect(endtempEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::end_temp_changed); |
|
562 connect(steptimeEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::step_time_changed); |
|
563 connect(ramptimeEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::ramp_time_changed); |
|
564 connect(stepivolEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditProduct::infuse_changed); |
|
565 connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); |
|
566 connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); |
|
567 |
|
568 dialog->setModal(true); |
|
569 dialog->exec(); |
|
570 if (dialog->result() == QDialog::Rejected) { |
|
571 qDebug() << "reject and rollback"; |
|
572 product->mashs[product->mashs_row] = backup; |
|
573 /* Rollback water volumes too */ |
|
574 double volume = 0; |
|
575 for (int i = 0; i < product->mashs.size(); i++) { |
|
576 if (product->mashs.at(i).step_type == 0) { |
|
577 volume += product->mashs.at(i).step_infuse_amount; |
|
578 } |
|
579 product->mashs[i].step_volume = volume; |
|
580 } |
|
581 product->w1_amount = volume - product->w2_amount; |
|
582 product->wg_amount = volume; |
|
583 ui->w1_volEdit->setValue(product->w1_amount); |
|
584 } |
|
585 |
|
586 disconnect(stepnameEdit, nullptr, nullptr, nullptr); |
|
587 disconnect(steptempEdit, nullptr, nullptr, nullptr); |
|
588 disconnect(endtempEdit, nullptr, nullptr, nullptr); |
|
589 disconnect(steptimeEdit, nullptr, nullptr, nullptr); |
|
590 disconnect(ramptimeEdit, nullptr, nullptr, nullptr); |
|
591 disconnect(stepivolEdit, nullptr, nullptr, nullptr); |
|
592 disconnect(buttonBox, nullptr, nullptr, nullptr); |
|
593 |
|
594 emit refreshAll(); |
|
595 } |
|
596 |
|
597 |
|
598 void EditProduct::mash_name_changed(QString name) |
|
599 { |
|
600 qDebug() << "mash_name_changed" << name; |
|
601 product->mash_name = name; |
|
602 is_changed(); |
|
603 } |
|
604 |
|
605 |
|
606 void EditProduct::mash_select_changed(int val) |
|
607 { |
|
608 QSqlQuery query; |
|
609 int i; |
|
610 |
|
611 qDebug() << "mash_select_changed" << val; |
|
612 |
|
613 const QSignalBlocker blocker1(ui->mash_nameEdit); |
|
614 query.prepare("SELECT name,steps FROM profile_mash ORDER BY name"); |
|
615 query.exec(); |
|
616 query.first(); |
|
617 for (i = 0; i < (val -1); i++) { |
|
618 query.next(); |
|
619 } |
|
620 |
|
621 product->mash_name = query.value(0).toString(); |
|
622 ui->mash_nameEdit->setText(product->mash_name); |
|
623 |
|
624 QJsonParseError parseError; |
|
625 const auto& json = query.value(1).toString(); |
|
626 if (!json.trimmed().isEmpty()) { |
|
627 const auto& formattedJson = QString("%1").arg(json); |
|
628 QJsonDocument newsteps = QJsonDocument::fromJson(formattedJson.toUtf8(), &parseError); |
|
629 |
|
630 if (parseError.error != QJsonParseError::NoError) { |
|
631 qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset; |
|
632 } else { |
|
633 /* |
|
634 * Got the json data in the steps array, replace the product steps. |
|
635 */ |
|
636 double infuse = 0; |
|
637 if (product->mashs.size()) { |
|
638 infuse = product->mashs.at(0).step_infuse_amount; |
|
639 product->mashs.clear(); |
|
640 ui->mashsTable->clear(); |
|
641 } |
|
642 if (newsteps.isArray()) { |
|
643 for (i = 0; i < newsteps.array().size(); i++) { |
|
644 QJsonObject obj = newsteps.array().at(i).toObject(); |
|
645 Mashs m; |
|
646 m.step_name = obj["step_name"].toString(); |
|
647 if (obj["step_type"].isString()) |
|
648 m.step_type = QString(obj["step_type"].toString()).toInt(); |
|
649 else |
|
650 m.step_type = obj["step_type"].toInt(); |
|
651 m.step_volume = 0; |
|
652 m.step_infuse_amount = 0; |
|
653 m.step_infuse_temp = 0; |
|
654 if (obj["step_temp"].isString()) |
|
655 m.step_temp = QString(obj["step_temp"].toString()).toDouble(); |
|
656 else |
|
657 m.step_temp = obj["step_temp"].toDouble(); |
|
658 if (obj["step_time"].isString()) |
|
659 m.step_time = QString(obj["step_time"].toString()).toDouble(); |
|
660 else |
|
661 m.step_time = obj["step_time"].toDouble(); |
|
662 if (obj["ramp_time"].isString()) |
|
663 m.ramp_time = QString(obj["ramp_time"].toString()).toDouble(); |
|
664 else |
|
665 m.ramp_time = obj["ramp_time"].toDouble(); |
|
666 if (obj["end_temp"].isString()) |
|
667 m.end_temp = QString(obj["end_temp"].toString()).toDouble(); |
|
668 else |
|
669 m.end_temp = obj["end_temp"].toDouble(); |
|
670 m.step_wg_ratio = 0; |
|
671 product->mashs.append(m); |
|
672 } |
|
673 } |
|
674 if (product->mashs.at(0).step_type == 0) |
|
675 product->mashs[0].step_infuse_amount = infuse; // Restore saved initial infusion |
|
676 } |
|
677 } |
|
678 is_changed(); |
|
679 emit refreshAll(); |
|
680 } |
|
681 |
|
682 |