From 856738db2b63dbfb284ea2b47d0995d605bb47fc Mon Sep 17 00:00:00 2001
From: Evgenii Tagiltsev <tagiltsev.ebgenii@gmail.com>
Date: Thu, 1 Aug 2019 18:35:33 +0200
Subject: [PATCH] [*] changed description panel

---
 .../DapChainNodeNetworkExplorer.cpp           | 182 +++++++++---------
 .../DapChainNodeNetworkExplorer.h             | 144 ++++++--------
 .../DapChainNodeNetworkModel.cpp              |  81 +++++++-
 KelvinDashboardGUI/DapChainNodeNetworkModel.h |  25 ++-
 KelvinDashboardGUI/DapServiceController.cpp   |   1 +
 KelvinDashboardGUI/DapServiceController.h     |   4 +-
 .../DapUiQmlWidgetNodeNetworkExplorer.qml     | 139 +++++++------
 libKelvinDashboardCommon/DapNodeType.h        |  32 +++
 .../libKelvinDashboardCommon.pri              |   3 +-
 9 files changed, 355 insertions(+), 256 deletions(-)
 create mode 100644 libKelvinDashboardCommon/DapNodeType.h

diff --git a/KelvinDashboardGUI/DapChainNodeNetworkExplorer.cpp b/KelvinDashboardGUI/DapChainNodeNetworkExplorer.cpp
index 272c0d877..b7ca254c2 100644
--- a/KelvinDashboardGUI/DapChainNodeNetworkExplorer.cpp
+++ b/KelvinDashboardGUI/DapChainNodeNetworkExplorer.cpp
@@ -1,18 +1,19 @@
-#include "DapChainNodeNetworkExplorer.h"
+#include "DapChainNodeNetworkExplorer.h"
 
-//  TEST
-//#define VIRTUAL_COLUMN_NUMBER   5
-//-----------------------------------
-
-//#define DESCRIPTION_NODE            QString("Address: %1\nAlias: %2\nIPv4: %3")
 #define DEFAULT_NODE_COLOR_HOVER    QColor("#FF0000")
 #define DEFAULT_NODE_COLOR          QColor("#000000")
+#define DEFAULT_NODE_COLOR_OFFLINE  QColor("#FF0000")
+#define DEFAULT_NODE_COLOR_ONLINE   QColor("#00FF00")
+#define DEFAULT_NODE_COLOR_SELECTED QColor("#0000FF")
 #define DEFAULT_NODE_SIZE           50
 #define DEFAULT_WIDTH_LINE          3
 
 DapChainNodeNetworkExplorer::DapChainNodeNetworkExplorer(QQuickItem *parent) :
     QQuickPaintedItem(parent),
     m_model(nullptr),
+    m_colorOnline(DEFAULT_NODE_COLOR_ONLINE),
+    m_colorOffline(DEFAULT_NODE_COLOR_OFFLINE),
+    m_colorSelect(DEFAULT_NODE_COLOR_SELECTED),
     m_colorNormal(DEFAULT_NODE_COLOR),
     m_colorFocused(DEFAULT_NODE_COLOR_HOVER),
     m_widthLine(DEFAULT_WIDTH_LINE),
@@ -26,24 +27,26 @@ void DapChainNodeNetworkExplorer::mousePressEvent(QMouseEvent* event)
 {
     QQuickPaintedItem::mousePressEvent(event);
 
-    for(auto Node = m_nodeMap.begin(); Node != m_nodeMap.end(); Node++)
+    emit selectNodeChanged();
+
+    if(m_currentSelectedNode.second != nullptr)
     {
-        if (Node.value().State == DapNodeState::Selected)
-        {
-            Node.value().State = DapNodeState::Normal;
-            emit selectNodeChanged();
-        }
+        m_currentSelectedNode.second->State = Normal;
+        m_currentSelectedNode.second = nullptr;
+    }
 
-        if(Node.value().State == DapNodeState::Focused)
+    for(auto node = m_nodeMap.begin(); node != m_nodeMap.end(); node++)
+    {
+        if(node.value().State == DapNodeState::Focused)
         {
-            DapNodeData* nodeData = &Node.value();
+            DapNodeGui* nodeData = &node.value();
             nodeData->State = DapNodeState::Selected;
-            m_currentSelectedNode = Node.key();
-            emit selectNode(Node.key());
+            m_currentSelectedNode = QPair<QString, DapNodeGui*>(node.key(), nodeData);
+            emit selectNode();
+            update();
+            return;
         }
     }
-
-    update();
 }
 
 void DapChainNodeNetworkExplorer::wheelEvent(QWheelEvent* event)
@@ -65,22 +68,18 @@ void DapChainNodeNetworkExplorer::hoverMoveEvent(QHoverEvent* event)
 {
     QQuickPaintedItem::hoverMoveEvent(event);
 
-    for(auto Node = m_nodeMap.begin(); Node != m_nodeMap.end(); Node++)
+    for(auto node = m_nodeMap.begin(); node != m_nodeMap.end(); node++)
     {
-        DapNodeData* nodeData = &Node.value();
-        if(nodeData->Rect.contains(event->pos()))
+        DapNodeGui* nodeDataGui = &node.value();
+        if(nodeDataGui->Rect.contains(event->pos()) && nodeDataGui->State != Selected)
         {
-            if(nodeData->State == DapNodeState::Selected) return;
-            nodeData->State = DapNodeState::Focused;
+            nodeDataGui->State = DapNodeState::Focused;
             break;
         }
-        else
+        else if(nodeDataGui->State == DapNodeState::Focused)
         {
-            if(nodeData->State == DapNodeState::Focused)
-            {
-                nodeData->State = DapNodeState::Normal;
-                break;
-            }
+            nodeDataGui->State = DapNodeState::Normal;
+            break;
         }
     }
 
@@ -90,51 +89,46 @@ void DapChainNodeNetworkExplorer::hoverMoveEvent(QHoverEvent* event)
 void DapChainNodeNetworkExplorer::paint(QPainter* painter)
 {
     if(m_model == nullptr) return;
-    QString address;
-    const DapNodeData* activatedNode = nullptr;
+    QString focusedNode = QString();
+    QPen penNormal(QBrush(m_colorNormal), m_widthLine);
+    QPen penOnline(QBrush(m_colorOnline), m_widthLine);
+    QPen penOffline(QBrush(m_colorOffline), m_widthLine);
+    QPen penFocused(QBrush(m_colorFocused), m_widthLine);
+    QPen penSelected(QBrush(m_colorSelect), m_widthLine);
 
-    QPen pen(QBrush(m_colorNormal), m_widthLine);
-    painter->setPen(pen);
     painter->setBrush(QBrush("#FFFFFF"));
-
     for(auto node = m_nodeMap.constBegin(); node != m_nodeMap.constEnd(); node++)
     {
-        const DapNodeData* nodeData = &node.value();
+        const DapNodeGui* nodeDataGui = &node.value();
+        const DapNodeData* nodeData = m_model->getNodeData(node.key());
         for(int i = 0; i < nodeData->Link.count(); i++)
-            painter->drawLine(nodeData->Rect.center(), nodeData->Link.at(i)->Rect.center());
-
-        if(nodeData->State == DapNodeState::Focused)
         {
-            address = node.key();
-            activatedNode = nodeData;
-            continue;
+            if(nodeData->Status) painter->setPen(penOnline);
+            else painter->setPen(penOffline);
+            painter->drawLine(nodeDataGui->Rect.center(), m_nodeMap[nodeData->Link.at(i)].Rect.center());
         }
-        else if (nodeData->State == DapNodeState::Selected)
+
+        if(nodeDataGui->State == Focused)
         {
-            QPen penSelected(QBrush("#0000FF"), m_widthLine);
-            painter->setPen(penSelected);
-            painter->drawEllipse(nodeData->Rect);
-            painter->setPen(pen);
-            continue;
+            painter->setPen(penFocused);
+            focusedNode = node.key();
         }
+        else if(nodeDataGui->State == Selected) painter->setPen(penSelected);
+        else painter->setPen(penNormal);
 
-        painter->drawEllipse(nodeData->Rect);
+        painter->drawEllipse(nodeDataGui->Rect);
     }
 
-    if(activatedNode != nullptr)
+    if(!focusedNode.isEmpty())
     {
-        QPen penActivated(QBrush(m_colorFocused), m_widthLine);
         QPen penWhite(QBrush("#FFFFFF"), m_widthLine);
-        QRect rect(activatedNode->Rect.center(), QSize(200, 15));
-
-        painter->setPen(penActivated);
-        painter->drawEllipse(activatedNode->Rect);
+        QRect rect(m_nodeMap[focusedNode].Rect.center(), QSize(200, 15));
+        const DapNodeData* nodeData = m_model->getNodeData(focusedNode);
 
         painter->setPen(penWhite);
         painter->drawRect(rect);
-
-        painter->setPen(pen);
-        painter->drawText(rect, activatedNode->Alias);
+        painter->setPen(penNormal);
+        painter->drawText(rect, nodeData->Alias);
     }
 }
 
@@ -163,40 +157,47 @@ DapChainNodeNetworkModel* DapChainNodeNetworkExplorer::getModel() const
     return m_model;
 }
 
-
 int DapChainNodeNetworkExplorer::getSelectedNodePosX() const
 {
-    if(m_nodeMap.contains(m_currentSelectedNode))
-       return m_nodeMap[m_currentSelectedNode].Rect.center().x();
-
+    if(m_currentSelectedNode.second != nullptr)
+        return m_currentSelectedNode.second->Rect.center().x();
     return -1;
 }
 
 int DapChainNodeNetworkExplorer::getSelectedNodePosY() const
 {
-    if(m_nodeMap.contains(m_currentSelectedNode))
-       return m_nodeMap[m_currentSelectedNode].Rect.center().y();
-
+    if(m_currentSelectedNode.second != nullptr)
+        return m_currentSelectedNode.second->Rect.center().y();
     return -1;
 }
 
 QString DapChainNodeNetworkExplorer::getSelectedNodeAddress() const
 {
-    return m_currentSelectedNode;
+    if(m_currentSelectedNode.second != nullptr)
+        return m_currentSelectedNode.first;
+    return QString();
 }
 
 QString DapChainNodeNetworkExplorer::getSelectedNodeAlias() const
 {
-    if(m_nodeMap.contains(m_currentSelectedNode))
-       return m_nodeMap[m_currentSelectedNode].Alias;
+    if(m_currentSelectedNode.second != nullptr)
+    {
+        const DapNodeData* nodeData = m_model->getNodeData(m_currentSelectedNode.first);
+        if(nodeData != nullptr)
+            return nodeData->Alias;
+    }
 
     return QString();
 }
 
 QString DapChainNodeNetworkExplorer::getSelectedNodeIpv4() const
 {
-    if(m_nodeMap.contains(m_currentSelectedNode))
-       return m_nodeMap[m_currentSelectedNode].AddressIpv4.toString();
+    if(m_currentSelectedNode.second != nullptr)
+    {
+        const DapNodeData* nodeData = m_model->getNodeData(m_currentSelectedNode.first);
+        if(nodeData != nullptr)
+            return nodeData->Ipv4;
+    }
 
     return QString();
 }
@@ -250,16 +251,21 @@ void DapChainNodeNetworkExplorer::setModel(DapChainNodeNetworkModel* aModel)
 {
     if (m_model == aModel) return;
     m_model = aModel;
-    connect(m_model, SIGNAL(dataChanged(QVariant)), this, SLOT(proccessCreateGraph()));
+    QObject::connect(m_model, SIGNAL(changeNodeNetwork()), this, SLOT(proccessCreateGraph()));
+    QObject::connect(m_model, SIGNAL(changeStatusNode(QString, bool)), this, SLOT(update()));
     proccessCreateGraph();
     emit modelChanged(m_model);
 }
 
-void DapChainNodeNetworkExplorer::setCurrentNodeStatus(const DapNodeStatus& aNodeStatus)
+QString DapChainNodeNetworkExplorer::getAddressByPos(const int aX, const int aY)
 {
-    qDebug() << "changed node status" << m_currentSelectedNode << (int)aNodeStatus;
-    if(m_nodeMap.contains(m_currentSelectedNode))
-        m_nodeMap[m_currentSelectedNode].Status = aNodeStatus;
+    for(auto node = m_nodeMap.constBegin(); node != m_nodeMap.constEnd(); node++)
+    {
+        if(node->Rect.contains(aX, aY))
+            return node.key();
+    }
+
+    return QString();
 }
 
 void DapChainNodeNetworkExplorer::setColorOnline(const QColor& aColorOnline)
@@ -292,33 +298,19 @@ void DapChainNodeNetworkExplorer::setColorSelect(const QColor& aColorSelect)
 void DapChainNodeNetworkExplorer::proccessCreateGraph()
 {
     if(m_model == nullptr) return;
-    QVariant m_data = m_model->getData();
 
-    QMap<QString, QVariant> dataMap = m_data.toMap();
+    const DapNodeMap* const nodeMap = m_model->getDataMap();
     int pointX = m_sizeNode;
-    int heightConten = dataMap.count() * m_sizeNode;
-
-    QList<QString> addressList = dataMap.keys();
-    foreach(auto address, addressList)
-        m_nodeMap[address] = DapNodeData();
-
-    for(auto node = m_nodeMap.begin(); node != m_nodeMap.end(); node++)
+    int heightConten = nodeMap->count() * m_sizeNode;
+    for (auto node = nodeMap->constBegin(); node != nodeMap->constEnd(); node++)
     {
-        DapNodeData* nodeData = &node.value();
-        QStringList nodeDataList = dataMap[node.key()].toStringList();
-        nodeData->Cell = nodeDataList.at(0).toUInt();
-        nodeData->AddressIpv4 = QHostAddress(nodeDataList.at(1));
-        nodeData->Alias = nodeDataList.at(2);
-
-        if(nodeDataList.at(3).toUInt() > 0)
-        {
-            for(int i = 4; i < nodeDataList.count(); i++)
-                nodeData->Link.append(&m_nodeMap[nodeDataList.at(i)]);
-        }
+        DapNodeGui nodeData;
 
         int posY = (qrand() % ((heightConten + 1) - m_sizeNode) + m_sizeNode);
-        nodeData->Rect = QRect(pointX, posY, m_sizeNode, m_sizeNode);
+        nodeData.Rect = QRect(pointX, posY, m_sizeNode, m_sizeNode);
         pointX += m_sizeNode * 2;
+
+        m_nodeMap[node.key()] = nodeData;
     }
 
     setSize(QSize(pointX + m_sizeNode * 2, heightConten + m_sizeNode * 2));
diff --git a/KelvinDashboardGUI/DapChainNodeNetworkExplorer.h b/KelvinDashboardGUI/DapChainNodeNetworkExplorer.h
index 67dbc48e7..18793f483 100644
--- a/KelvinDashboardGUI/DapChainNodeNetworkExplorer.h
+++ b/KelvinDashboardGUI/DapChainNodeNetworkExplorer.h
@@ -3,61 +3,21 @@
 
 #include <QQuickPaintedItem>
 #include <QPainter>
-#include <QHostAddress>
 #include <QVariant>
 #include <QToolTip>
 
 #include "DapChainNodeNetworkModel.h"
-
-enum class DapNodeState {
-    Normal,
-    Focused,
-    Selected
-};
-
-enum DapNodeStatus {
-    Offline,
-    Online
-};
-
-struct DapNodeData {
-    quint32 Cell;
-    QHostAddress AddressIpv4;
-    QString Alias;
-    QVector<DapNodeData*> Link;
-    QRect Rect;
-    DapNodeState State;
-    DapNodeStatus Status;
-
-    DapNodeData()
-    {
-        State = DapNodeState::Normal;
-        Status = DapNodeStatus::Offline;
-        Link = QVector<DapNodeData*>();
-    }
-
-    DapNodeData& operator << (DapNodeData& AData)
-    {
-        Link.append(&AData);
-        return *this;
-    }
-
-    DapNodeData& operator = (const DapNodeData& AData) {
-        Cell = AData.Cell;
-        Alias = AData.Alias;
-        AddressIpv4 = AData.AddressIpv4;
-        Rect = AData.Rect;
-        Link = AData.Link;
-        State = AData.State;
-        Status = AData.Status;
-        return *this;
-    }
-};
-
+#include "DapNodeType.h"
+
+/*!
+ * \brief The DapChainNodeNetworkExplorer class
+ * \details Class paiting DapKelvin map
+ * \warning To use this class it requers to send DapChainNodeNetworkModel model to slot setModel()
+ * \author Tagiltsev Evgenii
+ */
 class DapChainNodeNetworkExplorer : public QQuickPaintedItem
 {
     Q_OBJECT
-    Q_ENUM(DapNodeStatus)
     Q_PROPERTY(QColor colorSelect READ getColorSelect WRITE setColorSelect NOTIFY colorSelectChanged)
     Q_PROPERTY(QColor colorNormal READ getColorNormal WRITE setColorNormal NOTIFY colorNormalChanged)
     Q_PROPERTY(QColor colorFocused READ getColorFocused WRITE setColorFocused NOTIFY colorFocusedChanged)
@@ -67,18 +27,30 @@ class DapChainNodeNetworkExplorer : public QQuickPaintedItem
     Q_PROPERTY(int sizeNode READ getSizeNode WRITE setSizeNode NOTIFY sizeNodeChanged)
     Q_PROPERTY(DapChainNodeNetworkModel* model READ getModel WRITE setModel NOTIFY modelChanged)
 
+public:
+    enum DapNodeState {
+        Normal,
+        Focused,
+        Selected
+    };
+
+    struct DapNodeGui {
+        DapNodeState State;
+        QRect Rect;
+    };
+
 private:
-    QString m_currentSelectedNode;
     DapChainNodeNetworkModel* m_model;
-    QMap<QString /*Address*/, DapNodeData /*Data*/> m_nodeMap;
+    QMap<QString /*Address*/, DapNodeGui /*NodeDataGui*/> m_nodeMap;                //  node map for gui
+    QPair<QString /*Address*/, DapNodeGui* /*NodeDataGui*/> m_currentSelectedNode;  //  selected node
 
-    QColor m_colorOnline;
-    QColor m_colorOffline;
-    QColor m_colorSelect;
-    QColor m_colorNormal;
-    QColor m_colorFocused;
-    int m_widthLine;
-    int m_sizeNode;
+    QColor m_colorOnline;       //  Property color for online status
+    QColor m_colorOffline;      //  Property color for offline status
+    QColor m_colorSelect;       //  Property color for selected state
+    QColor m_colorNormal;       //  Property color for normal state
+    QColor m_colorFocused;      //  Property color for focused state
+    int m_widthLine;            //  Property width line for borders
+    int m_sizeNode;             //  Property lenght of square's side
 
 protected:
     void mousePressEvent(QMouseEvent* event);
@@ -87,38 +59,38 @@ protected:
 
 public:
     explicit DapChainNodeNetworkExplorer(QQuickItem *parent = nullptr);
-    void paint(QPainter* painter);
-    DapNodeStatus getNodeStatus() const;
-    QColor getColorOnline() const;
-    QColor getColorOffline() const;
-    QColor getColorSelect() const;
-    QColor getColorNormal() const;
-    QColor getColorFocused() const;
-    int getWidthLine() const;
-    int getSizeNode() const;
-
-    DapChainNodeNetworkModel* getModel() const;
-
-    Q_INVOKABLE void setCurrentNodeStatus(const DapNodeStatus& aNodeStatus);
-    Q_INVOKABLE int getSelectedNodePosX() const;
-    Q_INVOKABLE int getSelectedNodePosY() const;
-    Q_INVOKABLE QString getSelectedNodeAddress() const;
-    Q_INVOKABLE QString getSelectedNodeAlias() const;
-    Q_INVOKABLE QString getSelectedNodeIpv4() const;
+    void paint(QPainter* painter);                                      //!<    Overload method for paiting
+
+    QColor getColorOnline() const;                                      //!<    Get color for online nodes
+    QColor getColorOffline() const;                                     //!<    Get color for offline nodes
+    QColor getColorSelect() const;                                      //!<    Get color for selected node
+    QColor getColorNormal() const;                                      //!<    Get color for normal state for node
+    QColor getColorFocused() const;                                     //!<    Get color for focused node
+    int getWidthLine() const;                                           //!<    Get line width for borders
+    int getSizeNode() const;                                            //!<    Get lenght of square's side
+
+    DapChainNodeNetworkModel* getModel() const;                         //!<    Get model
+
+    Q_INVOKABLE int getSelectedNodePosX() const;                        //!<    Get X position for selected node
+    Q_INVOKABLE int getSelectedNodePosY() const;                        //!<    Get Y position for selected node
+    Q_INVOKABLE QString getSelectedNodeAddress() const;                 //!<    Get address for selected node
+    Q_INVOKABLE QString getSelectedNodeAlias() const;                   //!<    Get alias for selected node
+    Q_INVOKABLE QString getSelectedNodeIpv4() const;                    //!<    Get Ipv4 address for selected node
+    Q_INVOKABLE QString getAddressByPos(const int aX, const int aY);    //!<    Find node address by coordinate
 
 public slots:
-    void setColorSelect(const QColor& aColorSelect);
-    void setColorNormal(const QColor& aColorNormal);
-    void setColorFocused(const QColor& aColorActivated);
-    void setColorOnline(const QColor& aColorOnline);
-    void setColorOffline(const QColor& aColorOffline);
-    void setWidthLine(const int widthLine);
-    void setSizeNode(const int sizeNode);
+    void setColorSelect(const QColor& aColorSelect);                    //!<    Set color for selected node
+    void setColorNormal(const QColor& aColorNormal);                    //!<    Set color for normal state for node
+    void setColorFocused(const QColor& aColorActivated);                //!<    Set color for focused node
+    void setColorOnline(const QColor& aColorOnline);                    //!<    Set color for online nodes
+    void setColorOffline(const QColor& aColorOffline);                  //!<    Set color for offline nodes
+    void setWidthLine(const int widthLine);                             //!<    Set line width for borders
+    void setSizeNode(const int sizeNode);                               //!<    Set lenght of square's side
 
-    void setModel(DapChainNodeNetworkModel* aModel);
+    void setModel(DapChainNodeNetworkModel* aModel);                    //!<    Set model
 
 private slots:
-    void proccessCreateGraph();
+    void proccessCreateGraph();                                         //  Slot for repainting map if it was changed
 
 signals:
     void colorSelectChanged(QColor colorSelect);
@@ -130,8 +102,8 @@ signals:
     void sizeNodeChanged(int sizeNode);
     void modelChanged(DapChainNodeNetworkModel* model);
 
-    void selectNode(QString address);
-    void selectNodeChanged();
+    void selectNode();                                                  //!<    Signal selected node
+    void selectNodeChanged();                                           //!<    Signal deselect node
 };
 
 #endif // DAPCHAINNODENETWORKEXPLORER_H
diff --git a/KelvinDashboardGUI/DapChainNodeNetworkModel.cpp b/KelvinDashboardGUI/DapChainNodeNetworkModel.cpp
index fa573eabb..2f1e4d96b 100644
--- a/KelvinDashboardGUI/DapChainNodeNetworkModel.cpp
+++ b/KelvinDashboardGUI/DapChainNodeNetworkModel.cpp
@@ -1,8 +1,13 @@
 #include "DapChainNodeNetworkModel.h"
 #include <QDebug>
 
+#define DEFAULT_TIMER_MS 1000
+
 DapChainNodeNetworkModel::DapChainNodeNetworkModel(QObject *parent) : QObject(parent)
 {
+    m_timerRequest = new QTimer(this);
+    QObject::connect(m_timerRequest, SIGNAL(timeout()), this, SIGNAL(requestNodeNetwork()));
+    m_timerRequest->start(DEFAULT_TIMER_MS);
 }
 
 DapChainNodeNetworkModel& DapChainNodeNetworkModel::getInstance()
@@ -11,14 +16,78 @@ DapChainNodeNetworkModel& DapChainNodeNetworkModel::getInstance()
     return instance;
 }
 
-QVariant DapChainNodeNetworkModel::getData() const
+const DapNodeMap* DapChainNodeNetworkModel::getDataMap() const
 {
-    return m_data;
+    return &m_nodeMap;
 }
 
-void DapChainNodeNetworkModel::setData(const QVariant& AData)
+const DapNodeData* DapChainNodeNetworkModel::getNodeData(const QString& aAddress) const
 {
-    if (m_data == AData) return;
-    m_data = AData;
-    emit dataChanged(m_data);
+    const DapNodeData* nodeData = nullptr;
+    if(m_nodeMap.contains(aAddress))
+        nodeData = const_cast<const DapNodeData*>(&m_nodeMap.find(aAddress).value());
+
+    return nodeData;
+}
+
+bool DapChainNodeNetworkModel::isNodeOnline(const QString& aAddress) const
+{
+    if(m_nodeMap.contains(aAddress))
+        return m_nodeMap[aAddress].Status;
+
+    return false;
+}
+
+void DapChainNodeNetworkModel::setStatusNode(const QString& aAddress, const bool aIsOnline)
+{
+    if(m_nodeMap.contains(aAddress))
+    {
+        m_nodeMap[aAddress].Status = aIsOnline;
+        emit changeStatusNode(aAddress, aIsOnline);
+    }
+}
+
+void DapChainNodeNetworkModel::startRequest()
+{
+    if(m_timerRequest->isActive()) m_timerRequest->stop();
+    m_timerRequest->start();
+}
+
+void DapChainNodeNetworkModel::startRequest(const int aTimeout)
+{
+    if(m_timerRequest->isActive()) m_timerRequest->stop();
+    m_timerRequest->start(aTimeout);
+}
+
+void DapChainNodeNetworkModel::stopRequest()
+{
+    m_timerRequest->stop();
+}
+
+void DapChainNodeNetworkModel::setData(const QVariant& aData)
+{
+    if (m_data == aData) return;
+    m_data = aData;
+    QMap<QString, QVariant> dataMap = m_data.toMap();
+
+    QList<QString> addressList = dataMap.keys();
+    foreach(auto address, addressList)
+        m_nodeMap[address] = DapNodeData();
+
+    for(auto node = m_nodeMap.begin(); node != m_nodeMap.end(); node++)
+    {
+        DapNodeData* nodeData = &node.value();
+        QStringList nodeDataList = dataMap[node.key()].toStringList();
+        nodeData->Cell = nodeDataList.at(0).toUInt();
+        nodeData->Ipv4 = nodeDataList.at(1);
+        nodeData->Alias = nodeDataList.at(2);
+
+        if(nodeDataList.at(3).toUInt() > 0)
+        {
+            for(int i = 4; i < nodeDataList.count(); i++)
+                nodeData->Link.append(nodeDataList.at(i));
+        }
+    }
+
+    emit changeNodeNetwork();
 }
diff --git a/KelvinDashboardGUI/DapChainNodeNetworkModel.h b/KelvinDashboardGUI/DapChainNodeNetworkModel.h
index 52eb5bf90..b7458b0e0 100644
--- a/KelvinDashboardGUI/DapChainNodeNetworkModel.h
+++ b/KelvinDashboardGUI/DapChainNodeNetworkModel.h
@@ -2,28 +2,43 @@
 #define DAPCHAINNODENETWORKMODEL_H
 
 #include <QObject>
+#include <QTimer>
 #include <QHostAddress>
 #include <QVariant>
 
+#include "DapNodeType.h"
+
 class DapChainNodeNetworkModel : public QObject
 {
     Q_OBJECT
-    Q_PROPERTY(QVariant data READ getData WRITE setData NOTIFY dataChanged)
 
+private:
     QVariant m_data;
+    QTimer* m_timerRequest;
+
+protected:
+    DapNodeMap m_nodeMap;
 
 public:
     explicit DapChainNodeNetworkModel(QObject *parent = nullptr);
-    Q_INVOKABLE static DapChainNodeNetworkModel &getInstance();
+    const DapNodeMap* getDataMap() const;
+    const DapNodeData* getNodeData(const QString& aAddress) const;
 
-    QVariant getData() const;
+    Q_INVOKABLE static DapChainNodeNetworkModel &getInstance();
+    Q_INVOKABLE bool isNodeOnline(const QString& aAddress) const;
 
 public slots:
-    void setData(const QVariant& AData);
+    void setData(const QVariant& aData);
+    Q_INVOKABLE void setStatusNode(const QString& aAddress, const bool aIsOnline);
+    Q_INVOKABLE void startRequest();
+    Q_INVOKABLE void startRequest(const int aTimeout);
+    Q_INVOKABLE void stopRequest();
 
 signals:
+    void changeNodeNetwork();
+    void requestNodeNetwork();
+    void changeStatusNode(QString node, bool isOnline);
     void appendNode(QMap<QString, QVariant>);
-    void dataChanged(QVariant data);
 };
 
 #endif // DAPCHAINNODENETWORKMODEL_H
diff --git a/KelvinDashboardGUI/DapServiceController.cpp b/KelvinDashboardGUI/DapServiceController.cpp
index 36314a38a..839486122 100755
--- a/KelvinDashboardGUI/DapServiceController.cpp
+++ b/KelvinDashboardGUI/DapServiceController.cpp
@@ -53,6 +53,7 @@ void DapServiceController::init(DapServiceClient *apDapServiceClient)
 	connect(m_pDapCommandController, SIGNAL(sendNodeNetwork(QVariant)), this, SLOT(processGetNodeNetwork(QVariant)));
     connect(m_pDapCommandController, SIGNAL(onLogModel()), SLOT(get()));
 
+    connect(&DapChainNodeNetworkModel::getInstance(), SIGNAL(requestNodeNetwork()), this, SLOT(getNodeNetwork()));
 }
 
 QString DapServiceController::getBrand() const
diff --git a/KelvinDashboardGUI/DapServiceController.h b/KelvinDashboardGUI/DapServiceController.h
index acf44f5e2..12a3fa429 100755
--- a/KelvinDashboardGUI/DapServiceController.h
+++ b/KelvinDashboardGUI/DapServiceController.h
@@ -81,8 +81,6 @@ public:
 
     void getWalletInfo(const QString& asWalletName);
 
-    void getNodeNetwork();
-
 signals:
     /// The signal is emitted when the Brand company property changes.
     void brandChanged(const QString &brand);
@@ -116,6 +114,8 @@ private slots:
     void processGetNodeNetwork(const QVariant& aData);
 
 public slots:
+    void getNodeNetwork();
+
     void get();
     /// Get node logs.
     /// @param aiTimeStamp Timestamp start reading logging.
diff --git a/KelvinDashboardGUI/DapUiQmlWidgetNodeNetworkExplorer.qml b/KelvinDashboardGUI/DapUiQmlWidgetNodeNetworkExplorer.qml
index f015f1248..df9f7a4b9 100644
--- a/KelvinDashboardGUI/DapUiQmlWidgetNodeNetworkExplorer.qml
+++ b/KelvinDashboardGUI/DapUiQmlWidgetNodeNetworkExplorer.qml
@@ -5,6 +5,11 @@ import QtQuick.Layouts 1.12
 import NodeNetworkExplorer 1.0
 
 Page {
+    Rectangle {
+        anchors.fill: parent;
+        color: "#3b3353";
+    }
+
     RowLayout {
         anchors.fill: parent
         spacing: 2
@@ -23,9 +28,19 @@ Page {
                 scale: 0.6
                 transformOrigin: Item.TopLeft
                 model: dapNodeNetworkModel
+                colorOffline: "#eb4d4b"
+                colorOnline: "#6ab04c"
+                colorFocused: "#ff7979"
+                colorSelect: "#686de0"
                 onSelectNode: {
                     dapNodeNetworkMenu.x = getSelectedNodePosX();
                     dapNodeNetworkMenu.y = getSelectedNodePosY();
+
+                    if(dapNodeNetworkModel.isNodeOnline(getSelectedNodeAddress()))
+                        dapRadioButtonOnline.checked = true;
+                    else
+                        dapRadioButtonOffline.checked = true;
+
                     dapNodeNetworkMenu.visible = true;
                 }
                 onSelectNodeChanged: {
@@ -39,9 +54,9 @@ Page {
                         text: qsTr("Show detalies")
                         onTriggered: {
                             dapNodeNetworkDescription.visible = true;
-                            dapDescriptionAddress.text = dapGraphWidget.getSelectedNodeAddress();
-                            dapDescriptionAlias.text = dapGraphWidget.getSelectedNodeAlias();
-                            dapDescriptionIpv4.text = dapGraphWidget.getSelectedNodeIpv4();
+                            dapDescriptionModel.get(0).name = dapGraphWidget.getSelectedNodeAddress();
+                            dapDescriptionModel.get(1).name = dapGraphWidget.getSelectedNodeAlias();
+                            dapDescriptionModel.get(2).name = dapGraphWidget.getSelectedNodeIpv4();
                         }
                     }
 
@@ -62,63 +77,59 @@ Page {
             Layout.fillWidth: true
             Layout.fillHeight: true
             visible: false
-            border.color: "#F3F2F1"
-            border.width: 1
-
-             Column {
-                 anchors.fill: parent
-
-                 Text {
-                     anchors.horizontalCenter: parent.horizontalCenter
-                     topPadding: 20
-                     bottomPadding: 30
-                     font.pointSize: 24
-                     text: qsTr("Description")
-                 }
-
-                 Column {
-                     leftPadding: 30
-
-                     Text {
-                         text: qsTr("Address")
-                         font.pointSize: 13
-                     }
-
-                     Text {
-                         id: dapDescriptionAddress
-                         font.pointSize: 8
-                     }
-                 }
-
-
-                 Column {
-                     leftPadding: 30
-
-                     Text {
-                         text: qsTr("Alias")
-                         font.pointSize: 13
-                     }
-
-                     Text {
-                         id: dapDescriptionAlias
-                         font.pointSize: 8
-                     }
-                 }
-
-                 Column {
-                     leftPadding: 30
-
-                     Text {
-                         text: qsTr("Ipv4")
-                         font.pointSize: 13
-                     }
-
-                     Text {
-                         id:dapDescriptionIpv4
-                         font.pointSize: 8
-                     }
-                 }
-             }
+            color: "#eaecef"
+
+            ListModel {
+                id: dapDescriptionModel
+                ListElement { name: ""; category: "Address"; }
+                ListElement { name: ""; category: "Alias"; }
+                ListElement { name: ""; category: "Ipv4"; }
+            }
+
+            ListView {
+                anchors.fill: parent
+                model: dapDescriptionModel
+                delegate: Text {text: name; font.pixelSize: 18 }
+                section.property: "category"
+                section.criteria: ViewSection.FullString
+                section.delegate: dapCategory
+
+                header: Rectangle {
+                    width: parent.width
+                    height: rowContent.height
+                    RowLayout {
+                        id: rowContent
+                        Button {
+                            text: "X"
+                        }
+
+                        Text {
+                            Layout.rowSpan: 1
+                            verticalAlignment: Qt.AlignVCenter
+                            horizontalAlignment: Qt.AlignHCenter
+                            text: qsTr("Description")
+                        }
+                    }
+
+                }
+            }
+
+
+            Component {
+                id: dapCategory
+                Rectangle {
+                    width: dapNodeNetworkDescription.width
+                    height: childrenRect.height
+                    color: "#0000FF"
+
+                    Text {
+                        color: "#FFFFFF"
+                        text: section
+                        font.bold: true
+                        font.pixelSize: 20
+                    }
+                }
+            }
         }
     }
 
@@ -152,14 +163,20 @@ Page {
             }
 
             RadioButton {
+                id: dapRadioButtonOffline
                 Layout.alignment: Qt.AlignCenter
                 text: qsTr("Offline")
+                onToggled: {
+                    dapNodeNetworkModel.setStatusNode(dapGraphWidget.getSelectedNodeAddress(), false);
+                }
             }
 
             RadioButton {
+                id: dapRadioButtonOnline
                 Layout.alignment: Qt.AlignCenter
                 text: qsTr("Online")
-                onClicked: {
+                onToggled: {
+                    dapNodeNetworkModel.setStatusNode(dapGraphWidget.getSelectedNodeAddress(), true);
                 }
             }
 
diff --git a/libKelvinDashboardCommon/DapNodeType.h b/libKelvinDashboardCommon/DapNodeType.h
new file mode 100644
index 000000000..f3f05127f
--- /dev/null
+++ b/libKelvinDashboardCommon/DapNodeType.h
@@ -0,0 +1,32 @@
+#ifndef DAPNODETYPE_H
+#define DAPNODETYPE_H
+
+#include <QString>
+#include <QStringList>
+
+struct DapNodeData {
+    quint32 Cell;
+    QString Ipv4;
+    QString Alias;
+    QStringList Link;
+    bool Status;
+
+    DapNodeData()
+    {
+        Status = false;
+    }
+
+    DapNodeData& operator = (const DapNodeData& AData) {
+        Cell = AData.Cell;
+        Alias = AData.Alias;
+        Ipv4 = AData.Ipv4;
+        Link = AData.Link;
+        Status = AData.Status;
+        return *this;
+    }
+};
+
+typedef QMap<QString /*Address*/, DapNodeData /*Data*/> DapNodeMap;
+
+
+#endif // DAPNODETYPE_H
diff --git a/libKelvinDashboardCommon/libKelvinDashboardCommon.pri b/libKelvinDashboardCommon/libKelvinDashboardCommon.pri
index 0db2e7e16..6f2fbbbe1 100755
--- a/libKelvinDashboardCommon/libKelvinDashboardCommon.pri
+++ b/libKelvinDashboardCommon/libKelvinDashboardCommon.pri
@@ -25,4 +25,5 @@ HEADERS +=\
     $$PWD/DapSettingsCipher.h \
     $$PWD/DapLogMessage.h \
     $$PWD/DapLogModel.h \
-    $$PWD/DapChainWallet.h
+    $$PWD/DapChainWallet.h \
+    $$PWD/DapNodeType.h
-- 
GitLab