Added profile water table and editor.

Sun, 06 Mar 2022 15:31:40 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 06 Mar 2022 15:31:40 +0100
changeset 48
ddd1171ecda5
parent 47
160e4b407a7d
child 49
29cf6e350063

Added profile water table and editor.

CMakeLists.txt file | annotate | diff | comparison | revisions
src/EditProfileWater.cpp file | annotate | diff | comparison | revisions
src/EditProfileWater.h file | annotate | diff | comparison | revisions
src/MainWindow.cpp file | annotate | diff | comparison | revisions
src/MainWindow.h file | annotate | diff | comparison | revisions
src/ProfileWaters.cpp file | annotate | diff | comparison | revisions
src/ProfileWaters.h file | annotate | diff | comparison | revisions
ui/EditProfileWater.ui file | annotate | diff | comparison | revisions
ui/MainWindow.ui file | annotate | diff | comparison | revisions
ui/ProfileWaters.ui file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Sun Mar 06 12:00:07 2022 +0100
+++ b/CMakeLists.txt	Sun Mar 06 15:31:40 2022 +0100
@@ -115,6 +115,8 @@
     ${SRCDIR}/EditWater.cpp
     ${SRCDIR}/InventoryEquipments.cpp
     ${SRCDIR}/EditEquipment.cpp
+    ${SRCDIR}/ProfileWaters.cpp
+    ${SRCDIR}/EditProfileWater.cpp
     ${SRCDIR}/Setup.cpp
     ${SRCDIR}/Utils.cpp
     ${SRCDIR}/MainWindow.cpp
@@ -139,6 +141,8 @@
     ${SRCDIR}/EditWater.h
     ${SRCDIR}/InventoryEquipments.h
     ${SRCDIR}/EditEquipment.h
+    ${SRCDIR}/ProfileWaters.h
+    ${SRCDIR}/EditProfileWater.h
     ${SRCDIR}/Setup.h
     ${SRCDIR}/Utils.h
     ${SRCDIR}/MainWindow.h
@@ -162,6 +166,8 @@
     ${UIDIR}/EditWater.ui
     ${UIDIR}/InventoryEquipments.ui
     ${UIDIR}/EditEquipment.ui
+    ${UIDIR}/ProfileWaters.ui
+    ${UIDIR}/EditProfileWater.ui
     ${UIDIR}/Setup.ui
     ${UIDIR}/MainWindow.ui
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/EditProfileWater.cpp	Sun Mar 06 15:31:40 2022 +0100
@@ -0,0 +1,241 @@
+/**
+ * EditProfileWater.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 <http://www.gnu.org/licenses/>.
+ */
+#include "EditProfileWater.h"
+#include "../ui/ui_EditProfileWater.h"
+#include "bmsapp.h"
+
+
+EditProfileWater::EditProfileWater(int id, QWidget *parent) : QDialog(parent), ui(new Ui::EditProfileWater)
+{
+    QSqlQuery query;
+
+    qDebug() << "EditProfileWater record:" << id;
+    ui->setupUi(this);
+    this->recno = id;
+
+    WindowTitle();
+
+    if (id >= 0) {
+	query.prepare("SELECT * FROM profile_water WHERE record = :recno");
+	query.bindValue(":recno", id);
+	query.exec();
+	query.next();
+
+	ui->nameEdit->setText(query.value(1).toString());
+        ui->caEdit->setValue(query.value(2).toDouble());
+	ui->hcoEdit->setValue(query.value(3).toDouble());
+	ui->so4Edit->setValue(query.value(4).toDouble());
+	ui->clEdit->setValue(query.value(5).toDouble());
+	ui->naEdit->setValue(query.value(6).toDouble());
+	ui->mgEdit->setValue(query.value(7).toDouble());
+	ui->phEdit->setValue(query.value(8).toDouble());
+	ui->notesEdit->setPlainText(query.value(9).toString());
+	ui->alkalinityEdit->setValue(query.value(10).toDouble());
+    } else {
+	/* Set some defaults */
+	ui->phEdit->setValue(7.0);
+    }
+    WaterSet();
+    connect(ui->nameEdit, &QLineEdit::textChanged, this, &EditProfileWater::is_changed);
+    connect(ui->caEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::water_changed);
+    connect(ui->hcoEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::hco_changed);
+    connect(ui->so4Edit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::water_changed);
+    connect(ui->clEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::water_changed);
+    connect(ui->naEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::water_changed);
+    connect(ui->mgEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::water_changed);
+    connect(ui->phEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::water_changed);
+    connect(ui->alkalinityEdit, &QDoubleSpinBox::textChanged, this, &EditProfileWater::alkalinity_changed);
+    connect(ui->notesEdit, SIGNAL(textChanged()), this, SLOT(is_changed()));
+
+    ui->saveButton->setEnabled(false);
+    ui->deleteButton->setEnabled((id >= 0) ? true:false);
+}
+
+
+EditProfileWater::~EditProfileWater()
+{
+    qDebug() << "EditProfileWater done";
+    delete ui;
+    emit entry_changed();
+}
+
+
+/*
+ * Window header, mark any change with '**'
+ */
+void EditProfileWater::WindowTitle()
+{
+    QString txt;
+
+    if (this->recno < 0) {
+	txt = QString(tr("BMSapp - Add new brewing water"));
+    } else {
+	txt = QString(tr("BMSapp - Edit brewing water %1").arg(this->recno));
+    }
+
+    if (this->textIsChanged) {
+	txt.append((QString(" **")));
+    }
+    setWindowTitle(txt);
+}
+
+
+void EditProfileWater::on_saveButton_clicked()
+{
+    QSqlQuery query;
+
+    /* If there are errors in the form, show a message and do "return;" */
+    if (ui->nameEdit->text().length() < 2) {
+	QMessageBox::warning(this, tr("Edit Water"), tr("Name empty or too short."));
+	return;
+    }
+
+    if (this->textIsChanged) {
+    	if (this->recno == -1) {
+    	    query.prepare("INSERT INTO profile_water SET name=:name, calcium=:ca, "
+		"bicarbonate=:hco, sulfate=:so4, chloride=:cl, sodium=:na, magnesium=:mg, ph=:ph, notes=:notes, "
+		"total_alkalinity=:alkalinity, uuid = :uuid");
+    	} else {
+	    query.prepare("UPDATE profile_water SET name=:name, calcium=:ca, "
+		"bicarbonate=:hco, sulfate=:so4, chloride=:cl, sodium=:na, magnesium=:mg, ph=:ph, notes=:notes, "
+                "total_alkalinity=:alkalinity WHERE record = :recno");
+    	}
+	query.bindValue(":name", ui->nameEdit->text());
+	query.bindValue(":ca", QString("%1").arg(ui->caEdit->value(), 2, 'f', 1, '0'));
+	query.bindValue(":hco", QString("%1").arg(ui->hcoEdit->value(), 2, 'f', 1, '0'));
+	query.bindValue(":so4", QString("%1").arg(ui->so4Edit->value(), 2, 'f', 1, '0'));
+	query.bindValue(":cl", QString("%1").arg(ui->clEdit->value(), 2, 'f', 1, '0'));
+	query.bindValue(":na", QString("%1").arg(ui->naEdit->value(), 2, 'f', 1, '0'));
+	query.bindValue(":mg", QString("%1").arg(ui->mgEdit->value(), 2, 'f', 1, '0'));
+	query.bindValue(":ph", QString("%1").arg(ui->phEdit->value(), 3, 'f', 2, '0'));
+	query.bindValue(":notes", ui->notesEdit->toPlainText());
+	query.bindValue(":alkalinity", QString("%1").arg(ui->alkalinityEdit->value(), 2, 'f', 1, '0'));
+	if (this->recno == -1) {
+	    query.bindValue(":uuid", QUuid::createUuid().toString().mid(1, 36));
+	} else {
+	    query.bindValue(":recno", this->recno);
+	}
+	query.exec();
+	if (query.lastError().isValid()) {
+	    qDebug() << "EditProfileWater" << query.lastError();
+	    QMessageBox::warning(this, tr("Database error"),
+                        tr("MySQL error: %1\n%2\n%3")
+                        .arg(query.lastError().nativeErrorCode())
+                        .arg(query.lastError().driverText())
+                        .arg(query.lastError().databaseText()));
+	} else {
+	    qDebug() << "EditProfileWater Saved";
+	}
+    }
+
+    ui->saveButton->setEnabled(false);
+    this->textIsChanged = false;
+    WindowTitle();
+}
+
+
+void EditProfileWater::on_deleteButton_clicked()
+{
+    QSqlQuery query;
+
+    query.prepare("DELETE FROM profile_water WHERE record = :recno");
+    query.bindValue(":recno", this->recno);
+    query.exec();
+    if (query.lastError().isValid()) {
+	qDebug() << "EditProfileWater" << query.lastError();
+	QMessageBox::warning(this, tr("Database error"),
+                        tr("MySQL error: %1\n%2\n%3")
+                        .arg(query.lastError().nativeErrorCode())
+                        .arg(query.lastError().driverText())
+                        .arg(query.lastError().databaseText()));
+    } else {
+	qDebug() << "EditProfileWater Deleted" << this->recno;
+    }
+
+    this->close();
+    this->setResult(1);
+}
+
+
+void EditProfileWater::WaterSet()
+{
+    double cations, anions, balance;
+
+    cations = (ui->caEdit->value() / 20.039) + (ui->mgEdit->value() / 12.1525) + (ui->naEdit->value() / 22.989);
+    anions = (ui->hcoEdit->value() / 61.016) + (ui->so4Edit->value() / 48.031) + (ui->clEdit->value() / 35.4527);
+    balance = round((cations - anions) * 100) / 100;
+    ui->balanceEdit->setValue(balance);
+
+    if (balance <= 0.1 && balance >= -0.1) {
+	ui->balanceIcon->setPixmap(QPixmap(":icons/silk/tick.png"));
+    } else if (balance <= 0.5 && balance >= -0.5) {
+	ui->balanceIcon->setPixmap(QPixmap(":icons/silk/thumb_down.png"));
+    } else {
+	ui->balanceIcon->setPixmap(QPixmap(":icons/silk/error.png"));
+    }
+}
+
+
+void EditProfileWater::is_changed()
+{
+    ui->saveButton->setEnabled(true);
+    ui->deleteButton->setEnabled((this->recno >= 0) ? true:false);
+    this->textIsChanged = true;
+    WindowTitle();
+}
+
+
+void EditProfileWater::water_changed()
+{
+    WaterSet();
+    is_changed();
+}
+
+
+void EditProfileWater::hco_changed()
+{
+    ui->alkalinityEdit->setValue(ui->hcoEdit->value() * 50 / 61);
+    water_changed();
+}
+
+
+void EditProfileWater::alkalinity_changed()
+{
+    ui->hcoEdit->setValue(ui->alkalinityEdit->value() * 1.22);
+    water_changed();
+}
+
+
+void EditProfileWater::on_quitButton_clicked()
+{
+    if (this->textIsChanged) {
+	int rc = QMessageBox::warning(this, tr("Water changed"), tr("The water has been modified\n Save changes?"),
+                                QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save);
+        switch (rc) {
+            case QMessageBox::Save:
+                        on_saveButton_clicked();
+                        break;  /* Saved and then Quit */
+            case QMessageBox::Discard:
+                        break;  /* Quit without Save */
+            case QMessageBox::Cancel:
+                        return; /* Return to the editor page */
+        }
+    }
+
+    this->close();
+    this->setResult(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/EditProfileWater.h	Sun Mar 06 15:31:40 2022 +0100
@@ -0,0 +1,40 @@
+#ifndef _EDITPROFILEWATER_H
+#define _EDITPROFILEWATER_H
+
+#include <QDialog>
+
+
+namespace Ui {
+class EditProfileWater;
+}
+
+class EditProfileWater : public QDialog
+{
+    Q_OBJECT
+
+signals:
+    void entry_changed();
+
+public:
+    explicit EditProfileWater(int id, QWidget *parent = 0);
+    ~EditProfileWater();
+
+private slots:
+    void on_saveButton_clicked();
+    void on_quitButton_clicked();
+    void on_deleteButton_clicked();
+    void is_changed();
+    void water_changed();
+    void hco_changed();
+    void alkalinity_changed();
+
+private:
+    Ui::EditProfileWater *ui;
+    int recno;
+    bool textIsChanged = false;
+
+    void WindowTitle();
+    void WaterSet();
+};
+
+#endif
--- a/src/MainWindow.cpp	Sun Mar 06 12:00:07 2022 +0100
+++ b/src/MainWindow.cpp	Sun Mar 06 15:31:40 2022 +0100
@@ -23,6 +23,7 @@
 #include "InventoryMiscs.h"
 #include "InventoryWaters.h"
 #include "InventoryEquipments.h"
+#include "ProfileWaters.h"
 #include "Setup.h"
 #include "../ui/ui_MainWindow.h"
 #include "config.h"
@@ -183,6 +184,24 @@
 }
 
 
+void MainWindow::fromProfileWaters()
+{
+    qDebug() << Q_FUNC_INFO;
+    delete ProfileWatersWindow;
+    this->show();
+}
+
+
+void MainWindow::on_actionWater_profiles_triggered()
+{
+    qDebug() << Q_FUNC_INFO;
+    ProfileWatersWindow = new ProfileWaters(this);
+    QObject::connect(ProfileWatersWindow, SIGNAL(firstWindow()), this, SLOT(fromProfileWaters()));
+    this->hide();    // Close the main window
+    ProfileWatersWindow->show();  // Show a second window
+}
+
+
 void MainWindow::fromSetup()
 {
     qDebug() << Q_FUNC_INFO;
--- a/src/MainWindow.h	Sun Mar 06 12:00:07 2022 +0100
+++ b/src/MainWindow.h	Sun Mar 06 15:31:40 2022 +0100
@@ -8,6 +8,7 @@
 #include "InventoryMiscs.h"
 #include "InventoryWaters.h"
 #include "InventoryEquipments.h"
+#include "ProfileWaters.h"
 #include "Setup.h"
 
 #include <QMainWindow>
@@ -36,6 +37,7 @@
     void on_actionMiscs_triggered();
     void on_actionWaters_triggered();
     void on_actionEquipments_triggered();
+    void on_actionWater_profiles_triggered();
     void on_actionSetup_triggered();
     void on_actionAbout_triggered();
 
@@ -47,6 +49,7 @@
     void fromInventoryMiscs();
     void fromInventoryWaters();
     void fromInventoryEquipments();
+    void fromProfileWaters();
     void fromSetup();
 
 private:
@@ -60,6 +63,7 @@
     InventoryMiscs *InventoryMiscsWindow;
     InventoryWaters *InventoryWatersWindow;
     InventoryEquipments *InventoryEquipmentsWindow;
+    ProfileWaters * ProfileWatersWindow;
     Setup *SetupWindow;
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ProfileWaters.cpp	Sun Mar 06 15:31:40 2022 +0100
@@ -0,0 +1,163 @@
+/**
+ * ProfileWaters.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 <http://www.gnu.org/licenses/>.
+ */
+#include "ProfileWaters.h"
+#include "EditProfileWater.h"
+#include "../ui/ui_ProfileWaters.h"
+#include "config.h"
+#include "bmsapp.h"
+
+
+ProfileWaters::ProfileWaters(QWidget *parent) : QDialog(parent), ui(new Ui::ProfileWaters)
+{
+    qDebug() << "ProfileWaters start";
+
+    ui->setupUi(this);
+    emit refreshTable();
+
+    setWindowTitle( QString("BMSapp - %1 - Profile Waters").arg(VERSIONSTRING) );
+}
+
+
+void ProfileWaters::refreshTable()
+{
+    QString w;
+    QWidget* pWidget;
+    QLabel *label;
+    QHBoxLayout* pLayout;
+
+    qDebug() << "ProfileWaters reload";
+
+    QSqlQuery query("SELECT * FROM profile_water ORDER BY name");
+    const QStringList labels({tr("Name"), tr("Notes"), tr("Ca"), tr("Mg"), tr("Na"), tr("CaCO3"), tr("Cl"), tr("SO4"), tr("pH"), tr("Edit")});
+
+    ui->tableWaters->setColumnCount(10);
+    ui->tableWaters->setColumnWidth(0, 150);	/* Name		*/
+    ui->tableWaters->setColumnWidth(1, 375);	/* Notes	*/
+    ui->tableWaters->setColumnWidth(2,  75);	/* Ca		*/
+    ui->tableWaters->setColumnWidth(3,  75);	/* Mg		*/
+    ui->tableWaters->setColumnWidth(4,  75);	/* Na		*/
+    ui->tableWaters->setColumnWidth(5,  75);	/* CaCO3	*/
+    ui->tableWaters->setColumnWidth(6,  75);	/* Cl		*/
+    ui->tableWaters->setColumnWidth(7,  75);	/* SO4		*/
+    ui->tableWaters->setColumnWidth(8,  75);	/* pH		*/
+    ui->tableWaters->setColumnWidth(9,  80);	/* Edit button	*/
+    ui->tableWaters->setRowCount(query.size());
+    ui->tableWaters->setHorizontalHeaderLabels(labels);
+    ui->tableWaters->verticalHeader()->hide();
+    ui->tableWaters->setFixedSize(1130 + 24, 640);	/* Even if this is too large, it works */
+
+    QTableWidgetItem *rightitem = new QTableWidgetItem();
+    rightitem->setTextAlignment(Qt::AlignRight);
+
+    query.first();
+    for (int ridx = 0 ; ridx < query.size() ; ridx++ ) {
+	ui->tableWaters->setItem(ridx, 0, new QTableWidgetItem(query.value(1).toString()));	/* Name */
+	ui->tableWaters->setItem(ridx, 1, new QTableWidgetItem(query.value(9).toString()));	/* Notes */
+
+        w = QString("%1").arg(query.value(2).toDouble(), 2, 'f', 1, '0' );	/* Ca */
+        QTableWidgetItem *item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 2, item);
+
+	w = QString("%1").arg(query.value(7).toDouble(), 2, 'f', 1, '0' );      /* Mg */
+        item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 3, item);
+
+	w = QString("%1").arg(query.value(6).toDouble(), 2, 'f', 1, '0' );      /* Na */
+        item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 4, item);
+
+	w = QString("%1").arg(query.value(10).toDouble(), 2, 'f', 1, '0' );      /* CaCO3 */
+        item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 5, item);
+
+	w = QString("%1").arg(query.value(5).toDouble(), 2, 'f', 1, '0' );      /* Cl */
+        item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 6, item);
+
+	w = QString("%1").arg(query.value(4).toDouble(), 2, 'f', 1, '0' );      /* SO4 */
+        item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 7, item);
+
+	w = QString("%1").arg(query.value(8).toDouble(), 2, 'f', 1, '0' );      /* pH */
+        item = new QTableWidgetItem(w);
+        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
+        ui->tableWaters->setItem(ridx, 8, item);
+
+	/* Add the Edit button */
+	pWidget = new QWidget();
+	QPushButton* btn_edit = new QPushButton();
+	btn_edit->setObjectName(QString("%1").arg(query.value(0).toString()));	/* Send record with the button */
+	btn_edit->setText(tr("Edit"));
+	connect(btn_edit, SIGNAL(clicked()), this, SLOT(on_editButton_clicked()));
+	pLayout = new QHBoxLayout(pWidget);
+	pLayout->addWidget(btn_edit);
+	pLayout->setContentsMargins(5, 0, 5, 0);
+	pWidget->setLayout(pLayout);
+	ui->tableWaters->setCellWidget(ridx, 9, pWidget);
+	query.next();
+    }
+
+    setWindowTitle( QString("BMSapp - %1 - Profile Waters").arg(VERSIONSTRING) );
+}
+
+
+ProfileWaters::~ProfileWaters()
+{
+    qDebug() << "ProfileWaters done";
+    delete ui;
+}
+
+
+void ProfileWaters::edit(int recno)
+{
+    qDebug() << "ProfileWaters edit:" << recno;
+
+    EditProfileWater 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 ProfileWaters::on_editButton_clicked()
+{
+    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
+    int recno = pb->objectName().toInt();
+    qDebug() << Q_FUNC_INFO << recno;
+    edit(recno);
+}
+
+
+void ProfileWaters::on_insertButton_clicked()
+{
+    qDebug() << Q_FUNC_INFO;
+    edit(-1);
+}
+
+
+void ProfileWaters::on_quitButton_clicked()
+{
+    emit firstWindow();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ProfileWaters.h	Sun Mar 06 15:31:40 2022 +0100
@@ -0,0 +1,32 @@
+#ifndef _PROFILEWATERS_H
+#define _PROFILEWATERS_H
+
+#include <QDialog>
+
+namespace Ui {
+class ProfileWaters;
+}
+
+class ProfileWaters : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit ProfileWaters(QWidget *parent = nullptr);
+    ~ProfileWaters();
+
+signals:
+    void firstWindow();
+
+private slots:
+    void on_quitButton_clicked();
+    void on_insertButton_clicked();
+    void on_editButton_clicked();
+    void refreshTable(void);
+
+private:
+    Ui::ProfileWaters *ui;
+    void edit(int recno);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/EditProfileWater.ui	Sun Mar 06 15:31:40 2022 +0100
@@ -0,0 +1,567 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EditProfileWater</class>
+ <widget class="QDialog" name="EditProfileWater">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1024</width>
+    <height>560</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QWidget" name="topWidget" native="true">
+     <widget class="QLabel" name="nameLabel">
+      <property name="geometry">
+       <rect>
+        <x>30</x>
+        <y>10</y>
+        <width>121</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Name:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="notesLabel">
+      <property name="geometry">
+       <rect>
+        <x>30</x>
+        <y>40</y>
+        <width>121</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Notes:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLineEdit" name="nameEdit">
+      <property name="geometry">
+       <rect>
+        <x>160</x>
+        <y>10</y>
+        <width>691</width>
+        <height>23</height>
+       </rect>
+      </property>
+      <property name="maxLength">
+       <number>128</number>
+      </property>
+      <property name="placeholderText">
+       <string>Name of the brewing water</string>
+      </property>
+     </widget>
+     <widget class="QPlainTextEdit" name="notesEdit">
+      <property name="geometry">
+       <rect>
+        <x>160</x>
+        <y>40</y>
+        <width>691</width>
+        <height>81</height>
+       </rect>
+      </property>
+      <property name="placeholderText">
+       <string>Notes or the source of this water.</string>
+      </property>
+     </widget>
+     <widget class="QPushButton" name="quitButton">
+      <property name="geometry">
+       <rect>
+        <x>90</x>
+        <y>510</y>
+        <width>80</width>
+        <height>23</height>
+       </rect>
+      </property>
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="text">
+       <string>Quit</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>:icons/silk/door_out.png</normaloff>:icons/silk/door_out.png</iconset>
+      </property>
+     </widget>
+     <widget class="QPushButton" name="saveButton">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+      <property name="geometry">
+       <rect>
+        <x>850</x>
+        <y>510</y>
+        <width>80</width>
+        <height>23</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Save</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>:icons/silk/disk.png</normaloff>:icons/silk/disk.png</iconset>
+      </property>
+     </widget>
+     <widget class="QPushButton" name="deleteButton">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+      <property name="geometry">
+       <rect>
+        <x>463</x>
+        <y>510</y>
+        <width>80</width>
+        <height>23</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Delete</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>:icons/silk/delete.png</normaloff>:icons/silk/delete.png</iconset>
+      </property>
+     </widget>
+     <widget class="QLabel" name="caLabel">
+      <property name="geometry">
+       <rect>
+        <x>10</x>
+        <y>150</y>
+        <width>141</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Calcium (Ca) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="mgLabel">
+      <property name="geometry">
+       <rect>
+        <x>10</x>
+        <y>180</y>
+        <width>141</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Magnesium (Mg) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="naLabel">
+      <property name="geometry">
+       <rect>
+        <x>10</x>
+        <y>210</y>
+        <width>141</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Sodium (Na) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="phLabel">
+      <property name="geometry">
+       <rect>
+        <x>10</x>
+        <y>290</y>
+        <width>141</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Acid pH:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="caEdit">
+      <property name="geometry">
+       <rect>
+        <x>160</x>
+        <y>150</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="mgEdit">
+      <property name="geometry">
+       <rect>
+        <x>160</x>
+        <y>180</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="naEdit">
+      <property name="geometry">
+       <rect>
+        <x>160</x>
+        <y>210</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="phEdit">
+      <property name="geometry">
+       <rect>
+        <x>160</x>
+        <y>290</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.010000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="so4Edit">
+      <property name="geometry">
+       <rect>
+        <x>730</x>
+        <y>150</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="clEdit">
+      <property name="geometry">
+       <rect>
+        <x>730</x>
+        <y>180</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="hcoEdit">
+      <property name="geometry">
+       <rect>
+        <x>730</x>
+        <y>210</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="alkalinityEdit">
+      <property name="geometry">
+       <rect>
+        <x>730</x>
+        <y>240</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="accelerated">
+       <bool>true</bool>
+      </property>
+      <property name="decimals">
+       <number>1</number>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.100000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QDoubleSpinBox" name="balanceEdit">
+      <property name="geometry">
+       <rect>
+        <x>730</x>
+        <y>290</y>
+        <width>121</width>
+        <height>24</height>
+       </rect>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+      <property name="readOnly">
+       <bool>true</bool>
+      </property>
+      <property name="accelerated">
+       <bool>false</bool>
+      </property>
+      <property name="minimum">
+       <double>-100.000000000000000</double>
+      </property>
+      <property name="maximum">
+       <double>1000.000000000000000</double>
+      </property>
+      <property name="singleStep">
+       <double>0.010000000000000</double>
+      </property>
+      <property name="stepType">
+       <enum>QAbstractSpinBox::DefaultStepType</enum>
+      </property>
+     </widget>
+     <widget class="QLabel" name="so4Label">
+      <property name="geometry">
+       <rect>
+        <x>540</x>
+        <y>150</y>
+        <width>181</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Sulfate (SO4) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="clLabel">
+      <property name="geometry">
+       <rect>
+        <x>570</x>
+        <y>180</y>
+        <width>151</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Chloride (Cl) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="hcoLabel">
+      <property name="geometry">
+       <rect>
+        <x>530</x>
+        <y>210</y>
+        <width>191</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Bicarbonate (HCO3) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="alkalinityLabel">
+      <property name="geometry">
+       <rect>
+        <x>530</x>
+        <y>240</y>
+        <width>191</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Alkalinity (CaCO3) mg/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="balanceLabel">
+      <property name="geometry">
+       <rect>
+        <x>540</x>
+        <y>290</y>
+        <width>181</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Ion balance meq/L:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QLabel" name="balanceIcon">
+      <property name="geometry">
+       <rect>
+        <x>860</x>
+        <y>290</y>
+        <width>56</width>
+        <height>20</height>
+       </rect>
+      </property>
+      <property name="pixmap">
+       <pixmap resource="../../../../../../home/mbroek/MyProjects/bmsapp/resources/icons.qrc">:/icons/silk/tick.png</pixmap>
+      </property>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>nameEdit</tabstop>
+  <tabstop>notesEdit</tabstop>
+  <tabstop>quitButton</tabstop>
+  <tabstop>deleteButton</tabstop>
+  <tabstop>saveButton</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../../../../../../home/mbroek/MyProjects/bmsapp/resources/icons.qrc"/>
+ </resources>
+ <connections/>
+</ui>
--- a/ui/MainWindow.ui	Sun Mar 06 12:00:07 2022 +0100
+++ b/ui/MainWindow.ui	Sun Mar 06 15:31:40 2022 +0100
@@ -290,7 +290,7 @@
   </action>
   <action name="actionWater_profiles">
    <property name="enabled">
-    <bool>false</bool>
+    <bool>true</bool>
    </property>
    <property name="icon">
     <iconset>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/ProfileWaters.ui	Sun Mar 06 15:31:40 2022 +0100
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProfileWaters</class>
+ <widget class="QDialog" name="ProfileWaters">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1280</width>
+    <height>640</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QTableWidget" name="tableWaters">
+     <property name="enabled">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="enabled">
+      <bool>true</bool>
+     </property>
+     <property name="flat">
+      <bool>false</bool>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="spacing">
+       <number>6</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item alignment="Qt::AlignLeft">
+       <widget class="QPushButton" name="quitButton">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>80</width>
+          <height>24</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Quit</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normaloff>:icons/silk/door_out.png</normaloff>:icons/silk/door_out.png</iconset>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="insertButton">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>80</width>
+          <height>24</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>New</string>
+        </property>
+        <property name="icon">
+         <iconset>
+          <normaloff>:icons/silk/table_row_insert.png</normaloff>:icons/silk/table_row_insert.png</iconset>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../../../../../home/mbroek/MyProjects/bmsapp/resources/icons.qrc"/>
+ </resources>
+ <connections/>
+</ui>

mercurial