Added monitor nodes overview

Mon, 27 Jun 2022 21:12:19 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 27 Jun 2022 21:12:19 +0200
changeset 310
bdaac24b86ed
parent 309
8678a0731737
child 311
449116c083bd

Added monitor nodes overview

CMakeLists.txt file | annotate | diff | comparison | revisions
src/MainWindow.cpp file | annotate | diff | comparison | revisions
src/MainWindow.h file | annotate | diff | comparison | revisions
src/MonCO2meters.cpp file | annotate | diff | comparison | revisions
src/MonCO2meters.h file | annotate | diff | comparison | revisions
src/MonFermenters.cpp file | annotate | diff | comparison | revisions
src/MonFermenters.h file | annotate | diff | comparison | revisions
src/MonNodes.cpp file | annotate | diff | comparison | revisions
src/MonNodes.h file | annotate | diff | comparison | revisions
src/MoniSpindels.cpp file | annotate | diff | comparison | revisions
src/MoniSpindels.h file | annotate | diff | comparison | revisions
ui/MainWindow.ui file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Mon Jun 27 11:50:18 2022 +0200
+++ b/CMakeLists.txt	Mon Jun 27 21:12:19 2022 +0200
@@ -165,6 +165,10 @@
     ${SRCDIR}/ProdOnCode.cpp
     ${SRCDIR}/ProdOnDate.cpp
     ${SRCDIR}/ProdOnTree.cpp
+    ${SRCDIR}/MonNodes.cpp
+    ${SRCDIR}/MonFermenters.cpp
+    ${SRCDIR}/MonCO2meters.cpp
+    ${SRCDIR}/MoniSpindels.cpp
     ${SRCDIR}/EditProduct.cpp
     ${SRCDIR}/ImportXML.cpp
     ${SRCDIR}/Setup.cpp
@@ -210,6 +214,10 @@
     ${SRCDIR}/ProdOnCode.h
     ${SRCDIR}/ProdOnDate.h
     ${SRCDIR}/ProdOnTree.h
+    ${SRCDIR}/MonNodes.h
+    ${SRCDIR}/MonFermenters.h
+    ${SRCDIR}/MonCO2meters.h
+    ${SRCDIR}/MoniSpindels.h
     ${SRCDIR}/EditProduct.h
     ${SRCDIR}/ImportXML.h
     ${SRCDIR}/Setup.h
--- a/src/MainWindow.cpp	Mon Jun 27 11:50:18 2022 +0200
+++ b/src/MainWindow.cpp	Mon Jun 27 21:12:19 2022 +0200
@@ -33,6 +33,10 @@
 #include "ProfileMashs.h"
 #include "ProfileStyles.h"
 #include "ProfileFerments.h"
+#include "MonNodes.h"
+#include "MonFermenters.h"
+#include "MonCO2meters.h"
+#include "MoniSpindels.h"
 #include "ImportXML.h"
 #include "Setup.h"
 #include "PrinterDialog.h"
@@ -115,7 +119,6 @@
 }
 
 
-
 void MainWindow::loadSetup()
 {
     /*
@@ -237,21 +240,28 @@
      * Two maingroups, nodes and devices.
      * Node message are detected by the group_id object.
      * Device messages are detected by the device object.
+     *
+     * Messages can be connected to client widgets so we can emit messages to them.
      */
     QString device = jsonMessage.object()["device"].toString();
     QString group_id = jsonMessage.object()["group_id"].toString();
     if (device != "") {
 	if (device == "fermenters") {
-	    qDebug() << "found fermenter";
+	    //qDebug() << "found fermenter" << jsonMessage.object()["node"].toString()+"/"+jsonMessage.object()["unit"].toString();
+	    emit updateFermenters(jsonMessage.object()["node"].toString()+"/"+jsonMessage.object()["unit"].toString());
 	} else if (device == "co2meters") {
-	    qDebug() << "found co2meter";
+	    //qDebug() << "found co2meter" << jsonMessage.object()["node"].toString()+"/"+jsonMessage.object()["unit"].toString();
+	    emit updateCO2meters(jsonMessage.object()["node"].toString()+"/"+jsonMessage.object()["unit"].toString());
 	} else if (device == "ispindels") {
-	    qDebug() << "found iSpindel";
+	    qDebug() << "found iSpindel" << jsonMessage.object()["node"].toString()+"/"+jsonMessage.object()["unit"].toString();
+	    emit updateiSpindels(jsonMessage.object()["node"].toString()+"/"+jsonMessage.object()["unit"].toString());
 	} else {
 	    qDebug() << "unknown device" << device;
 	}
     } else if (group_id != "") {
-	qDebug() << "node" << jsonMessage.object()["node"].toString();
+	emit updateNodes(jsonMessage.object()["node"].toString());
+//    } else if (jsonMessage.object()["ping"].toString() != "") {
+//	qDebug() << "ping" << jsonMessage;
     } else {
 	qDebug() << "unknown WS message" << message;
     }
@@ -393,6 +403,90 @@
 }
 
 
+void MainWindow::fromMonNodes()
+{
+    ui->mainStack->setCurrentIndex(-1);
+    ui->mainStack->removeWidget(MonNodesWindow);
+    delete MonNodesWindow;
+    setWindowTitle( QString("BMSapp - %1").arg(VERSIONSTRING) );
+    ui->menuBar->setVisible(true);
+}
+
+
+void MainWindow::on_actionMon_Nodes_triggered()
+{
+    MonNodesWindow = new MonNodes(this);
+    int index = ui->mainStack->count();
+    ui->mainStack->addWidget(MonNodesWindow);
+    ui->mainStack->setCurrentIndex(index);
+    setWindowTitle( QString("BMSapp - %1 - Monitor Nodes").arg(VERSIONSTRING));
+    ui->menuBar->setVisible(false);
+}
+
+
+void MainWindow::fromMonFermenters()
+{
+    ui->mainStack->setCurrentIndex(-1);
+    ui->mainStack->removeWidget(MonFermentersWindow);
+    delete MonFermentersWindow;
+    setWindowTitle( QString("BMSapp - %1").arg(VERSIONSTRING) );
+    ui->menuBar->setVisible(true);
+}
+
+
+void MainWindow::on_actionMon_Fermenters_triggered()
+{
+    MonFermentersWindow = new MonFermenters(this);
+    int index = ui->mainStack->count();
+    ui->mainStack->addWidget(MonFermentersWindow);
+    ui->mainStack->setCurrentIndex(index);
+    setWindowTitle( QString("BMSapp - %1 - Monitor Fermenters").arg(VERSIONSTRING));
+//    ui->menuBar->setVisible(false);
+}
+
+
+void MainWindow::fromMonCO2meters()
+{
+    ui->mainStack->setCurrentIndex(-1);
+    ui->mainStack->removeWidget(MonCO2metersWindow);
+    delete MonCO2metersWindow;
+    setWindowTitle( QString("BMSapp - %1").arg(VERSIONSTRING) );
+    ui->menuBar->setVisible(true);
+}
+
+
+void MainWindow::on_actionMon_CO2meters_triggered()
+{
+    MonCO2metersWindow = new MonCO2meters(this);
+    int index = ui->mainStack->count();
+    ui->mainStack->addWidget(MonCO2metersWindow);
+    ui->mainStack->setCurrentIndex(index);
+    setWindowTitle( QString("BMSapp - %1 - Monitor CO2meters").arg(VERSIONSTRING));
+//    ui->menuBar->setVisible(false);
+}
+
+
+void MainWindow::fromMoniSpindels()
+{
+    ui->mainStack->setCurrentIndex(-1);
+    ui->mainStack->removeWidget(MoniSpindelsWindow);
+    delete MoniSpindelsWindow;
+    setWindowTitle( QString("BMSapp - %1").arg(VERSIONSTRING) );
+    ui->menuBar->setVisible(true);
+}
+
+
+void MainWindow::on_actionMon_iSpindels_triggered()
+{
+    MoniSpindelsWindow = new MoniSpindels(this);
+    int index = ui->mainStack->count();
+    ui->mainStack->addWidget(MoniSpindelsWindow);
+    ui->mainStack->setCurrentIndex(index);
+    setWindowTitle( QString("BMSapp - %1 - Monitor iSpindels").arg(VERSIONSTRING));
+//    ui->menuBar->setVisible(false);
+}
+
+
 void MainWindow::fromRecipesTree()
 {
     ui->mainStack->setCurrentIndex(-1);
--- a/src/MainWindow.h	Mon Jun 27 11:50:18 2022 +0200
+++ b/src/MainWindow.h	Mon Jun 27 21:12:19 2022 +0200
@@ -18,6 +18,10 @@
 #include "ProfileMashs.h"
 #include "ProfileStyles.h"
 #include "ProfileFerments.h"
+#include "MonNodes.h"
+#include "MonFermenters.h"
+#include "MonCO2meters.h"
+#include "MoniSpindels.h"
 #include "ImportXML.h"
 #include "Setup.h"
 
@@ -124,12 +128,26 @@
     ProfileMashs *ProfileMashsWindow;
     ProfileStyles *ProfileStylesWindow;
     ProfileFerments *ProfileFermentsWindow;
+    MonNodes *MonNodesWindow;
+    MonFermenters *MonFermentersWindow;
+    MonCO2meters *MonCO2metersWindow;
+    MoniSpindels *MoniSpindelsWindow;
     ImportXML *ImportXMLWindow;
     Setup *SetupWindow;
 
+signals:
+    void updateNodes(QString);
+    void updateFermenters(QString);
+    void updateCO2meters(QString);
+    void updateiSpindels(QString);
+
 private slots:
     void on_actionImport_XML_triggered();
     void on_actionExit_triggered();
+    void on_actionMon_Nodes_triggered();
+    void on_actionMon_Fermenters_triggered();
+    void on_actionMon_CO2meters_triggered();
+    void on_actionMon_iSpindels_triggered();
     void on_actionProd_inprod_triggered();
     void on_actionOn_Name_triggered();
     void on_actionOn_Code_triggered();
@@ -154,6 +172,10 @@
 
 public slots:
     void fromImportXML();
+    void fromMonNodes();
+    void fromMonFermenters();
+    void fromMonCO2meters();
+    void fromMoniSpindels();
     void fromRecipesTree();
     void fromInventorySuppliers();
     void fromInventoryFermentables();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MonCO2meters.cpp	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,149 @@
+/**
+ * MonCO2meters.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 "MonCO2meters.h"
+#include "EditSupplier.h"
+#include "MainWindow.h"
+#include "config.h"
+
+
+
+/*
+ * Build the table and buttons on the mainscreen.
+ * Don't use a ui file, do it dynamicly.
+ */
+MonCO2meters::MonCO2meters(QWidget *parent) : QDialog(parent)
+{
+    qDebug() << "MonCO2meters start";
+
+    gridLayout = new QGridLayout(this);
+    gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
+    tableSuppliers = new QTableWidget(this);
+    tableSuppliers->setObjectName(QString::fromUtf8("tableSuppliers"));
+    tableSuppliers->setEnabled(true);
+    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+    sizePolicy.setHorizontalStretch(0);
+    sizePolicy.setVerticalStretch(0);
+    sizePolicy.setHeightForWidth(tableSuppliers->sizePolicy().hasHeightForWidth());
+    tableSuppliers->setSizePolicy(sizePolicy);
+    tableSuppliers->setMinimumSize(QSize(1054, 0));
+    gridLayout->addWidget(tableSuppliers, 0, 0, 1, 1);
+
+    groupBox = new QGroupBox(this);
+    groupBox->setObjectName(QString::fromUtf8("groupBox"));
+    groupBox->setEnabled(true);
+    groupBox->setFlat(false);
+    horizontalLayout = new QHBoxLayout(groupBox);
+    horizontalLayout->setSpacing(6);
+    horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
+    horizontalLayout->setContentsMargins(0, 0, 0, 0);
+    quitButton = new QPushButton(groupBox);
+    quitButton->setObjectName(QString::fromUtf8("quitButton"));
+    quitButton->setMinimumSize(QSize(80, 24));
+    quitButton->setText(tr("Quit"));
+    QIcon icon;
+    icon.addFile(QString::fromUtf8(":icons/silk/door_out.png"), QSize(), QIcon::Normal, QIcon::Off);
+    quitButton->setIcon(icon);
+    horizontalLayout->addWidget(quitButton, 0, Qt::AlignLeft);
+
+    insertButton = new QPushButton(groupBox);
+    insertButton->setObjectName(QString::fromUtf8("insertButton"));
+    insertButton->setMinimumSize(QSize(80, 24));
+    insertButton->setText(tr("New"));
+    QIcon icon1;
+    icon1.addFile(QString::fromUtf8(":icons/silk/table_row_insert.png"), QSize(), QIcon::Normal, QIcon::Off);
+    insertButton->setIcon(icon1);
+    horizontalLayout->addWidget(insertButton, 0, Qt::AlignRight);
+    gridLayout->addWidget(groupBox, 1, 0, 1, 1);
+
+    connect(quitButton, SIGNAL(clicked()), parent, SLOT(fromMonCO2meters()));
+    connect(insertButton, SIGNAL(clicked()), this, SLOT(on_insertButton_clicked()));
+    connect(this, SIGNAL(setStatus(QString)), parent, SLOT(statusMsg(QString)));
+    emit refreshTable();
+}
+
+
+void MonCO2meters::refreshTable()
+{
+    qDebug() << "MonCO2meters reload";
+
+    //    query.exec("SELECT record,node,alias,online FROM mon_co2meters ORDER BY node,alias");
+    QSqlQuery query("SELECT * FROM inventory_suppliers ORDER BY name");
+    const QStringList labels({tr("Name"), tr("Address"), tr("City"), tr("Country"), tr("Phone"), tr("Edit")});
+
+    this->tableSuppliers->setColumnCount(6);
+    this->tableSuppliers->setColumnWidth(0, 250);	/* Name		*/
+    this->tableSuppliers->setColumnWidth(1, 250);	/* Address	*/
+    this->tableSuppliers->setColumnWidth(2, 200);	/* City		*/
+    this->tableSuppliers->setColumnWidth(3, 120);	/* Country	*/
+    this->tableSuppliers->setColumnWidth(4, 120);	/* Phone	*/
+    this->tableSuppliers->setColumnWidth(5, 90);	/* Edit button	*/
+    this->tableSuppliers->setRowCount(query.size());
+    this->tableSuppliers->setHorizontalHeaderLabels(labels);
+    this->tableSuppliers->verticalHeader()->hide();
+    /* Set the widget size to 1054 x 575 in the ui. */
+
+    query.first();
+    for (int ridx = 0 ; ridx < query.size() ; ridx++ ) {
+	this->tableSuppliers->setItem(ridx, 0, new QTableWidgetItem(query.value(1).toString()));
+	this->tableSuppliers->setItem(ridx, 1, new QTableWidgetItem(query.value(2).toString()));
+	this->tableSuppliers->setItem(ridx, 2, new QTableWidgetItem(query.value(3).toString()));
+	this->tableSuppliers->setItem(ridx, 3, new QTableWidgetItem(query.value(5).toString()));
+	this->tableSuppliers->setItem(ridx, 4, new QTableWidgetItem(query.value(8).toString()));
+
+	/* Add the Edit button */
+	QWidget* 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()));
+	QHBoxLayout* pLayout = new QHBoxLayout(pWidget);
+	pLayout->addWidget(btn_edit);
+	pLayout->setContentsMargins(5, 0, 5, 0);
+	pWidget->setLayout(pLayout);
+	this->tableSuppliers->setCellWidget(ridx, 5, pWidget);
+	query.next();
+    }
+    emit setStatus(QString(tr("Total items: %1")).arg(query.size()));
+}
+
+
+MonCO2meters::~MonCO2meters() {}
+
+
+void MonCO2meters::edit(int recno)
+{
+    EditSupplier 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 MonCO2meters::on_editButton_clicked()
+{
+    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
+    int recno = pb->objectName().toInt();
+    edit(recno);
+}
+
+
+void MonCO2meters::on_insertButton_clicked()
+{
+    edit(-1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MonCO2meters.h	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,43 @@
+#ifndef _MONCO2METERS_H
+#define _MONCO2METERS_H
+
+#include <QDialog>
+#include <QtWidgets/QGridLayout>
+#include <QtWidgets/QGroupBox>
+#include <QtWidgets/QHBoxLayout>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QTableWidget>
+
+namespace Ui {
+class MonCO2meters;
+}
+
+class MonCO2meters : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit MonCO2meters(QWidget *parent = nullptr);
+    ~MonCO2meters();
+
+signals:
+    void setStatus(QString);
+
+private slots:
+    void on_insertButton_clicked();
+    void on_editButton_clicked();
+    void refreshTable(void);
+
+private:
+    QGridLayout *gridLayout;
+    QTableWidget *tableSuppliers;
+    QGroupBox *groupBox;
+    QHBoxLayout *horizontalLayout;
+    QPushButton *quitButton;
+    QPushButton *insertButton;
+
+    void edit(int recno);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MonFermenters.cpp	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,150 @@
+/**
+ * MonFermenters.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 "MonFermenters.h"
+#include "EditSupplier.h"
+#include "MainWindow.h"
+#include "config.h"
+
+
+
+/*
+ * Build the table and buttons on the mainscreen.
+ * Don't use a ui file, do it dynamicly.
+ */
+MonFermenters::MonFermenters(QWidget *parent) : QDialog(parent)
+{
+    qDebug() << "MonFermenters start";
+
+    gridLayout = new QGridLayout(this);
+    gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
+    tableSuppliers = new QTableWidget(this);
+    tableSuppliers->setObjectName(QString::fromUtf8("tableSuppliers"));
+    tableSuppliers->setEnabled(true);
+    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+    sizePolicy.setHorizontalStretch(0);
+    sizePolicy.setVerticalStretch(0);
+    sizePolicy.setHeightForWidth(tableSuppliers->sizePolicy().hasHeightForWidth());
+    tableSuppliers->setSizePolicy(sizePolicy);
+    tableSuppliers->setMinimumSize(QSize(1054, 0));
+    gridLayout->addWidget(tableSuppliers, 0, 0, 1, 1);
+
+    groupBox = new QGroupBox(this);
+    groupBox->setObjectName(QString::fromUtf8("groupBox"));
+    groupBox->setEnabled(true);
+    groupBox->setFlat(false);
+    horizontalLayout = new QHBoxLayout(groupBox);
+    horizontalLayout->setSpacing(6);
+    horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
+    horizontalLayout->setContentsMargins(0, 0, 0, 0);
+    quitButton = new QPushButton(groupBox);
+    quitButton->setObjectName(QString::fromUtf8("quitButton"));
+    quitButton->setMinimumSize(QSize(80, 24));
+    quitButton->setText(tr("Quit"));
+    QIcon icon;
+    icon.addFile(QString::fromUtf8(":icons/silk/door_out.png"), QSize(), QIcon::Normal, QIcon::Off);
+    quitButton->setIcon(icon);
+    horizontalLayout->addWidget(quitButton, 0, Qt::AlignLeft);
+
+    insertButton = new QPushButton(groupBox);
+    insertButton->setObjectName(QString::fromUtf8("insertButton"));
+    insertButton->setMinimumSize(QSize(80, 24));
+    insertButton->setText(tr("New"));
+    QIcon icon1;
+    icon1.addFile(QString::fromUtf8(":icons/silk/table_row_insert.png"), QSize(), QIcon::Normal, QIcon::Off);
+    insertButton->setIcon(icon1);
+    horizontalLayout->addWidget(insertButton, 0, Qt::AlignRight);
+    gridLayout->addWidget(groupBox, 1, 0, 1, 1);
+
+    connect(quitButton, SIGNAL(clicked()), parent, SLOT(fromMonFermenters()));
+    connect(insertButton, SIGNAL(clicked()), this, SLOT(on_insertButton_clicked()));
+    connect(this, SIGNAL(setStatus(QString)), parent, SLOT(statusMsg(QString)));
+    emit refreshTable();
+}
+
+
+void MonFermenters::refreshTable()
+{
+    qDebug() << "MonFermenters reload";
+
+    //    query.exec("SELECT record,node,alias,online FROM mon_fermenters ORDER BY node,alias");
+    //
+    QSqlQuery query("SELECT * FROM inventory_suppliers ORDER BY name");
+    const QStringList labels({tr("Name"), tr("Address"), tr("City"), tr("Country"), tr("Phone"), tr("Edit")});
+
+    this->tableSuppliers->setColumnCount(6);
+    this->tableSuppliers->setColumnWidth(0, 250);	/* Name		*/
+    this->tableSuppliers->setColumnWidth(1, 250);	/* Address	*/
+    this->tableSuppliers->setColumnWidth(2, 200);	/* City		*/
+    this->tableSuppliers->setColumnWidth(3, 120);	/* Country	*/
+    this->tableSuppliers->setColumnWidth(4, 120);	/* Phone	*/
+    this->tableSuppliers->setColumnWidth(5, 90);	/* Edit button	*/
+    this->tableSuppliers->setRowCount(query.size());
+    this->tableSuppliers->setHorizontalHeaderLabels(labels);
+    this->tableSuppliers->verticalHeader()->hide();
+    /* Set the widget size to 1054 x 575 in the ui. */
+
+    query.first();
+    for (int ridx = 0 ; ridx < query.size() ; ridx++ ) {
+	this->tableSuppliers->setItem(ridx, 0, new QTableWidgetItem(query.value(1).toString()));
+	this->tableSuppliers->setItem(ridx, 1, new QTableWidgetItem(query.value(2).toString()));
+	this->tableSuppliers->setItem(ridx, 2, new QTableWidgetItem(query.value(3).toString()));
+	this->tableSuppliers->setItem(ridx, 3, new QTableWidgetItem(query.value(5).toString()));
+	this->tableSuppliers->setItem(ridx, 4, new QTableWidgetItem(query.value(8).toString()));
+
+	/* Add the Edit button */
+	QWidget* 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()));
+	QHBoxLayout* pLayout = new QHBoxLayout(pWidget);
+	pLayout->addWidget(btn_edit);
+	pLayout->setContentsMargins(5, 0, 5, 0);
+	pWidget->setLayout(pLayout);
+	this->tableSuppliers->setCellWidget(ridx, 5, pWidget);
+	query.next();
+    }
+    emit setStatus(QString(tr("Total items: %1")).arg(query.size()));
+}
+
+
+MonFermenters::~MonFermenters() {}
+
+
+void MonFermenters::edit(int recno)
+{
+    EditSupplier 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 MonFermenters::on_editButton_clicked()
+{
+    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
+    int recno = pb->objectName().toInt();
+    edit(recno);
+}
+
+
+void MonFermenters::on_insertButton_clicked()
+{
+    edit(-1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MonFermenters.h	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,43 @@
+#ifndef _MONFERMENTERS_H
+#define _MONFERMENTERS_H
+
+#include <QDialog>
+#include <QtWidgets/QGridLayout>
+#include <QtWidgets/QGroupBox>
+#include <QtWidgets/QHBoxLayout>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QTableWidget>
+
+namespace Ui {
+class MonFermenters;
+}
+
+class MonFermenters : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit MonFermenters(QWidget *parent = nullptr);
+    ~MonFermenters();
+
+signals:
+    void setStatus(QString);
+
+private slots:
+    void on_insertButton_clicked();
+    void on_editButton_clicked();
+    void refreshTable(void);
+
+private:
+    QGridLayout *gridLayout;
+    QTableWidget *tableSuppliers;
+    QGroupBox *groupBox;
+    QHBoxLayout *horizontalLayout;
+    QPushButton *quitButton;
+    QPushButton *insertButton;
+
+    void edit(int recno);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MonNodes.cpp	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,163 @@
+/**
+ * MonNodes.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 "MonNodes.h"
+#include "EditSupplier.h"
+#include "MainWindow.h"
+#include "config.h"
+
+
+
+/*
+ * Build the table and buttons on the mainscreen.
+ * Don't use a ui file, do it dynamicly.
+ */
+MonNodes::MonNodes(QWidget *parent) : QDialog(parent)
+{
+    qDebug() << "MonNodes start";
+
+    gridLayout = new QGridLayout(this);
+    gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
+    tableNodes = new QTableWidget(this);
+    tableNodes->setObjectName(QString::fromUtf8("tableNodes"));
+    tableNodes->setEnabled(true);
+    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+    sizePolicy.setHorizontalStretch(0);
+    sizePolicy.setVerticalStretch(0);
+    sizePolicy.setHeightForWidth(tableNodes->sizePolicy().hasHeightForWidth());
+    tableNodes->setSizePolicy(sizePolicy);
+    tableNodes->setMinimumSize(QSize(974, 0));
+    gridLayout->addWidget(tableNodes, 0, 0, 1, 1);
+
+    groupBox = new QGroupBox(this);
+    groupBox->setObjectName(QString::fromUtf8("groupBox"));
+    groupBox->setEnabled(true);
+    groupBox->setFlat(false);
+    horizontalLayout = new QHBoxLayout(groupBox);
+    horizontalLayout->setSpacing(6);
+    horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
+    horizontalLayout->setContentsMargins(0, 0, 0, 0);
+    quitButton = new QPushButton(groupBox);
+    quitButton->setObjectName(QString::fromUtf8("quitButton"));
+    quitButton->setMinimumSize(QSize(80, 24));
+    quitButton->setText(tr("Quit"));
+    QIcon icon;
+    icon.addFile(QString::fromUtf8(":icons/silk/door_out.png"), QSize(), QIcon::Normal, QIcon::Off);
+    quitButton->setIcon(icon);
+    horizontalLayout->addWidget(quitButton, 0, Qt::AlignCenter);
+    gridLayout->addWidget(groupBox, 1, 0, 1, 1);
+
+    connect(quitButton, SIGNAL(clicked()), parent, SLOT(fromMonNodes()));
+    connect(this, SIGNAL(setStatus(QString)), parent, SLOT(statusMsg(QString)));
+    connect(parent, SIGNAL(updateNodes(QString)), this, SLOT(refreshNodes(QString)));
+    emit refreshTable();
+}
+
+
+void MonNodes::refreshTable()
+{
+    QTableWidgetItem *item;
+
+    qDebug() << "MonNodes reload";
+
+    QSqlQuery query("SELECT record,node,online,group_id,lastseen,net_address,up_interval FROM mon_nodes ORDER BY node");
+    const QStringList labels({tr("Node"), tr("Status"), tr("Group"), tr("Last seen"), tr("Address"), tr("Interval"), tr("Edit")});
+
+    this->tableNodes->setColumnCount(7);
+    this->tableNodes->setColumnWidth(0, 200);	/* Node		*/
+    this->tableNodes->setColumnWidth(1, 100);	/* Status	*/
+    this->tableNodes->setColumnWidth(2, 150);	/* Group	*/
+    this->tableNodes->setColumnWidth(3, 200);	/* Last seen	*/
+    this->tableNodes->setColumnWidth(4, 120);	/* Address	*/
+    this->tableNodes->setColumnWidth(5,  90);	/* Interval	*/
+    this->tableNodes->setColumnWidth(6,  90);	/* Edit button	*/
+    this->tableNodes->setRowCount(query.size());
+    this->tableNodes->setHorizontalHeaderLabels(labels);
+    this->tableNodes->verticalHeader()->hide();
+    /* Set the widget size to 1054 x 575 in the ui. */
+
+    query.first();
+    for (int i = 0 ; i < query.size() ; i++ ) {
+	this->tableNodes->setItem(i, 0, new QTableWidgetItem(query.value("node").toString()));
+
+	if (query.value("online").toInt()) {
+	    item = new QTableWidgetItem(QString("Ok"));
+	} else {
+	    item = new QTableWidgetItem(QString("Offline"));
+	    item->setForeground(QBrush(QColor(Qt::red)));
+	}
+	item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
+	this->tableNodes->setItem(i, 1, item);
+
+	item = new QTableWidgetItem(query.value("group_id").toString());
+	item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
+	this->tableNodes->setItem(i, 2, item);
+
+	item = new QTableWidgetItem(query.value("lastseen").toDateTime().toString("dd MMM yyyy HH:mm:ss"));
+	item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
+	this->tableNodes->setItem(i, 3, item);
+
+	this->tableNodes->setItem(i, 4, new QTableWidgetItem(query.value("net_address").toString()));
+
+	item = new QTableWidgetItem(query.value("up_interval").toString());
+	item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
+	this->tableNodes->setItem(i, 5, item);
+
+	/* Add the Edit button */
+	QWidget* pWidget = new QWidget();
+	QPushButton* btn_edit = new QPushButton();
+	btn_edit->setObjectName(QString("%1").arg(query.value("record").toString()));	/* Send record with the button */
+	btn_edit->setText(tr("Details"));
+	connect(btn_edit, SIGNAL(clicked()), this, SLOT(on_editButton_clicked()));
+	QHBoxLayout* pLayout = new QHBoxLayout(pWidget);
+	pLayout->addWidget(btn_edit);
+	pLayout->setContentsMargins(5, 0, 5, 0);
+	pWidget->setLayout(pLayout);
+	this->tableNodes->setCellWidget(i, 6, pWidget);
+	query.next();
+    }
+    emit setStatus(QString(tr("Total items: %1")).arg(query.size()));
+}
+
+
+MonNodes::~MonNodes() {}
+
+
+void MonNodes::refreshNodes(QString node)
+{
+    qDebug() << "refreshNodes" << node;
+    emit refreshTable();
+}
+
+
+void MonNodes::edit(int recno)
+{
+//    EditSupplier 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 MonNodes::on_editButton_clicked()
+{
+    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
+    int recno = pb->objectName().toInt();
+    edit(recno);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MonNodes.h	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,44 @@
+#ifndef _MONNODES_H
+#define _MONNODES_H
+
+#include <QDialog>
+#include <QtWidgets/QGridLayout>
+#include <QtWidgets/QGroupBox>
+#include <QtWidgets/QHBoxLayout>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QTableWidget>
+
+namespace Ui {
+class MonNodes;
+}
+
+class MonNodes : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit MonNodes(QWidget *parent = nullptr);
+    ~MonNodes();
+
+signals:
+    void setStatus(QString);
+
+private slots:
+    void on_editButton_clicked();
+    void refreshTable(void);
+
+public slots:
+    void refreshNodes(QString);
+
+private:
+    QGridLayout *gridLayout;
+    QTableWidget *tableNodes;
+    QGroupBox *groupBox;
+    QHBoxLayout *horizontalLayout;
+    QPushButton *quitButton;
+
+    void edit(int recno);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MoniSpindels.cpp	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,149 @@
+/**
+ * MoniSpindels.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 "MoniSpindels.h"
+#include "EditSupplier.h"
+#include "MainWindow.h"
+#include "config.h"
+
+
+
+/*
+ * Build the table and buttons on the mainscreen.
+ * Don't use a ui file, do it dynamicly.
+ */
+MoniSpindels::MoniSpindels(QWidget *parent) : QDialog(parent)
+{
+    qDebug() << "MoniSpindels start";
+
+    gridLayout = new QGridLayout(this);
+    gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
+    tableSuppliers = new QTableWidget(this);
+    tableSuppliers->setObjectName(QString::fromUtf8("tableSuppliers"));
+    tableSuppliers->setEnabled(true);
+    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+    sizePolicy.setHorizontalStretch(0);
+    sizePolicy.setVerticalStretch(0);
+    sizePolicy.setHeightForWidth(tableSuppliers->sizePolicy().hasHeightForWidth());
+    tableSuppliers->setSizePolicy(sizePolicy);
+    tableSuppliers->setMinimumSize(QSize(1054, 0));
+    gridLayout->addWidget(tableSuppliers, 0, 0, 1, 1);
+
+    groupBox = new QGroupBox(this);
+    groupBox->setObjectName(QString::fromUtf8("groupBox"));
+    groupBox->setEnabled(true);
+    groupBox->setFlat(false);
+    horizontalLayout = new QHBoxLayout(groupBox);
+    horizontalLayout->setSpacing(6);
+    horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
+    horizontalLayout->setContentsMargins(0, 0, 0, 0);
+    quitButton = new QPushButton(groupBox);
+    quitButton->setObjectName(QString::fromUtf8("quitButton"));
+    quitButton->setMinimumSize(QSize(80, 24));
+    quitButton->setText(tr("Quit"));
+    QIcon icon;
+    icon.addFile(QString::fromUtf8(":icons/silk/door_out.png"), QSize(), QIcon::Normal, QIcon::Off);
+    quitButton->setIcon(icon);
+    horizontalLayout->addWidget(quitButton, 0, Qt::AlignLeft);
+
+    insertButton = new QPushButton(groupBox);
+    insertButton->setObjectName(QString::fromUtf8("insertButton"));
+    insertButton->setMinimumSize(QSize(80, 24));
+    insertButton->setText(tr("New"));
+    QIcon icon1;
+    icon1.addFile(QString::fromUtf8(":icons/silk/table_row_insert.png"), QSize(), QIcon::Normal, QIcon::Off);
+    insertButton->setIcon(icon1);
+    horizontalLayout->addWidget(insertButton, 0, Qt::AlignRight);
+    gridLayout->addWidget(groupBox, 1, 0, 1, 1);
+
+    connect(quitButton, SIGNAL(clicked()), parent, SLOT(fromMoniSpindels()));
+    connect(insertButton, SIGNAL(clicked()), this, SLOT(on_insertButton_clicked()));
+    connect(this, SIGNAL(setStatus(QString)), parent, SLOT(statusMsg(QString)));
+    emit refreshTable();
+}
+
+
+void MoniSpindels::refreshTable()
+{
+    qDebug() << "MoniSpindels reload";
+
+    //    query.exec("SELECT record,alias,online FROM mon_ispindels ORDER BY alias");
+    QSqlQuery query("SELECT * FROM inventory_suppliers ORDER BY name");
+    const QStringList labels({tr("Name"), tr("Address"), tr("City"), tr("Country"), tr("Phone"), tr("Edit")});
+
+    this->tableSuppliers->setColumnCount(6);
+    this->tableSuppliers->setColumnWidth(0, 250);	/* Name		*/
+    this->tableSuppliers->setColumnWidth(1, 250);	/* Address	*/
+    this->tableSuppliers->setColumnWidth(2, 200);	/* City		*/
+    this->tableSuppliers->setColumnWidth(3, 120);	/* Country	*/
+    this->tableSuppliers->setColumnWidth(4, 120);	/* Phone	*/
+    this->tableSuppliers->setColumnWidth(5, 90);	/* Edit button	*/
+    this->tableSuppliers->setRowCount(query.size());
+    this->tableSuppliers->setHorizontalHeaderLabels(labels);
+    this->tableSuppliers->verticalHeader()->hide();
+    /* Set the widget size to 1054 x 575 in the ui. */
+
+    query.first();
+    for (int ridx = 0 ; ridx < query.size() ; ridx++ ) {
+	this->tableSuppliers->setItem(ridx, 0, new QTableWidgetItem(query.value(1).toString()));
+	this->tableSuppliers->setItem(ridx, 1, new QTableWidgetItem(query.value(2).toString()));
+	this->tableSuppliers->setItem(ridx, 2, new QTableWidgetItem(query.value(3).toString()));
+	this->tableSuppliers->setItem(ridx, 3, new QTableWidgetItem(query.value(5).toString()));
+	this->tableSuppliers->setItem(ridx, 4, new QTableWidgetItem(query.value(8).toString()));
+
+	/* Add the Edit button */
+	QWidget* 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()));
+	QHBoxLayout* pLayout = new QHBoxLayout(pWidget);
+	pLayout->addWidget(btn_edit);
+	pLayout->setContentsMargins(5, 0, 5, 0);
+	pWidget->setLayout(pLayout);
+	this->tableSuppliers->setCellWidget(ridx, 5, pWidget);
+	query.next();
+    }
+    emit setStatus(QString(tr("Total items: %1")).arg(query.size()));
+}
+
+
+MoniSpindels::~MoniSpindels() {}
+
+
+void MoniSpindels::edit(int recno)
+{
+    EditSupplier 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 MoniSpindels::on_editButton_clicked()
+{
+    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
+    int recno = pb->objectName().toInt();
+    edit(recno);
+}
+
+
+void MoniSpindels::on_insertButton_clicked()
+{
+    edit(-1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/MoniSpindels.h	Mon Jun 27 21:12:19 2022 +0200
@@ -0,0 +1,43 @@
+#ifndef _MONISPINDELS_H
+#define _MONISPINDELS_H
+
+#include <QDialog>
+#include <QtWidgets/QGridLayout>
+#include <QtWidgets/QGroupBox>
+#include <QtWidgets/QHBoxLayout>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QTableWidget>
+
+namespace Ui {
+class MoniSpindels;
+}
+
+class MoniSpindels : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit MoniSpindels(QWidget *parent = nullptr);
+    ~MoniSpindels();
+
+signals:
+    void setStatus(QString);
+
+private slots:
+    void on_insertButton_clicked();
+    void on_editButton_clicked();
+    void refreshTable(void);
+
+private:
+    QGridLayout *gridLayout;
+    QTableWidget *tableSuppliers;
+    QGroupBox *groupBox;
+    QHBoxLayout *horizontalLayout;
+    QPushButton *quitButton;
+    QPushButton *insertButton;
+
+    void edit(int recno);
+};
+
+#endif
--- a/ui/MainWindow.ui	Mon Jun 27 11:50:18 2022 +0200
+++ b/ui/MainWindow.ui	Mon Jun 27 21:12:19 2022 +0200
@@ -87,47 +87,12 @@
     <property name="title">
      <string>Monitor</string>
     </property>
-    <widget class="QMenu" name="menuSystems">
-     <property name="title">
-      <string>Systems</string>
-     </property>
-     <property name="icon">
-      <iconset resource="../resources/icons.qrc">
-       <normaloff>:/icons/silk/computer.png</normaloff>:/icons/silk/computer.png</iconset>
-     </property>
-    </widget>
-    <widget class="QMenu" name="menuFermenters">
-     <property name="title">
-      <string>Fermenters</string>
-     </property>
-     <property name="icon">
-      <iconset resource="../resources/icons.qrc">
-       <normaloff>:/icons/bms/fridge.png</normaloff>:/icons/bms/fridge.png</iconset>
-     </property>
-    </widget>
-    <widget class="QMenu" name="menuCO2_Meters">
-     <property name="title">
-      <string>CO2 Meters</string>
-     </property>
-     <property name="icon">
-      <iconset resource="../resources/icons.qrc">
-       <normaloff>:/icons/bms/beerbottle.png</normaloff>:/icons/bms/beerbottle.png</iconset>
-     </property>
-    </widget>
-    <widget class="QMenu" name="menuiSpindels">
-     <property name="title">
-      <string>iSpindels</string>
-     </property>
-     <property name="icon">
-      <iconset resource="../resources/icons.qrc">
-       <normaloff>:/icons/bms/fermenter.png</normaloff>:/icons/bms/fermenter.png</iconset>
-     </property>
-    </widget>
-    <addaction name="menuSystems"/>
+    <addaction name="separator"/>
+    <addaction name="actionMon_Nodes"/>
     <addaction name="separator"/>
-    <addaction name="menuFermenters"/>
-    <addaction name="menuCO2_Meters"/>
-    <addaction name="menuiSpindels"/>
+    <addaction name="actionMon_Fermenters"/>
+    <addaction name="actionMon_CO2meters"/>
+    <addaction name="actionMon_iSpindels"/>
    </widget>
    <widget class="QMenu" name="menuProducts">
     <property name="title">
@@ -449,6 +414,47 @@
     <string>ll</string>
    </property>
   </action>
+  <action name="actionNodes">
+   <property name="text">
+    <string>Nodes</string>
+   </property>
+  </action>
+  <action name="actionMon_Nodes">
+   <property name="icon">
+    <iconset resource="../resources/icons.qrc">
+     <normaloff>:/icons/bms/network-idle.png</normaloff>:/icons/bms/network-idle.png</iconset>
+   </property>
+   <property name="text">
+    <string>Nodes</string>
+   </property>
+  </action>
+  <action name="actionMon_Fermenters">
+   <property name="icon">
+    <iconset resource="../resources/icons.qrc">
+     <normaloff>:/icons/bms/fridge.png</normaloff>:/icons/bms/fridge.png</iconset>
+   </property>
+   <property name="text">
+    <string>Fermenters</string>
+   </property>
+  </action>
+  <action name="actionMon_CO2meters">
+   <property name="icon">
+    <iconset resource="../resources/icons.qrc">
+     <normaloff>:/icons/bms/beerbottle.png</normaloff>:/icons/bms/beerbottle.png</iconset>
+   </property>
+   <property name="text">
+    <string>Carbonation</string>
+   </property>
+  </action>
+  <action name="actionMon_iSpindels">
+   <property name="icon">
+    <iconset resource="../resources/icons.qrc">
+     <normaloff>:/icons/bms/fermenter.png</normaloff>:/icons/bms/fermenter.png</iconset>
+   </property>
+   <property name="text">
+    <string>iSpindels</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources>

mercurial