PIVX Core  5.6.99
P2P Digital Currency
peertablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2013 The Bitcoin developers
2 // Copyright (c) 2017-2020 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "peertablemodel.h"
7 
8 #include "clientmodel.h"
9 #include "guiconstants.h"
10 #include "guiutil.h"
11 #include "net.h"
12 #include "sync.h"
13 #include "validation.h" // cs_main
14 
15 #include <algorithm>
16 
17 #include <QDebug>
18 #include <QList>
19 #include <QTimer>
20 
21 bool NodeLessThan::operator()(const CNodeCombinedStats& left, const CNodeCombinedStats& right) const
22 {
23  const CNodeStats* pLeft = &(left.nodeStats);
24  const CNodeStats* pRight = &(right.nodeStats);
25 
26  if (order == Qt::DescendingOrder)
27  std::swap(pLeft, pRight);
28 
29  switch(column) {
31  return pLeft->nodeid < pRight->nodeid;
33  return pLeft->addrName.compare(pRight->addrName) < 0;
35  return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
37  return pLeft->dPingTime < pRight->dPingTime;
38  }
39 
40  return false;
41 }
42 
43 // private implementation
45 {
46 public:
48  QList<CNodeCombinedStats> cachedNodeStats;
52  Qt::SortOrder sortOrder;
54  std::map<NodeId, int> mapNodeRows;
55 
57  void refreshPeers()
58  {
59  {
60  cachedNodeStats.clear();
61  std::vector<CNodeStats> vstats;
62  if(g_connman)
63  g_connman->GetNodeStats(vstats);
64  cachedNodeStats.reserve(vstats.size());
65  for (const CNodeStats& nodestats : vstats) {
66  CNodeCombinedStats stats;
67  stats.nodeStateStats.nMisbehavior = 0;
68  stats.nodeStateStats.nSyncHeight = -1;
69  stats.nodeStateStats.nCommonHeight = -1;
70  stats.fNodeStateStatsAvailable = false;
71  stats.nodeStats = nodestats;
72  cachedNodeStats.append(stats);
73  }
74  }
75 
76  // Try to retrieve the CNodeStateStats for each node.
77  {
78  TRY_LOCK(cs_main, lockMain);
79  if (lockMain) {
80  for (CNodeCombinedStats& stats : cachedNodeStats)
81  stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats);
82  }
83  }
84 
85  if (sortColumn >= 0)
86  // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
87  std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
88 
89  // build index map
90  mapNodeRows.clear();
91  int row = 0;
92  for (const CNodeCombinedStats& stats : cachedNodeStats)
93  mapNodeRows.emplace(stats.nodeStats.nodeid, row++);
94  }
95 
96  int size()
97  {
98  return cachedNodeStats.size();
99  }
100 
102  {
103  if (idx >= 0 && idx < cachedNodeStats.size()) {
104  return &cachedNodeStats[idx];
105  } else {
106  return 0;
107  }
108  }
109 };
110 
111 PeerTableModel::PeerTableModel(ClientModel* parent) : QAbstractTableModel(parent),
112  clientModel(parent),
113  timer(0)
114 {
115  columns << tr("NodeID") << tr("Address/Hostname") << tr("Version") << tr("Ping Time");
116  priv = new PeerTablePriv();
117  // default to unsorted
118  priv->sortColumn = -1;
119 
120  // set up timer for auto refresh
121  timer = new QTimer();
122  connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
123  timer->setInterval(MODEL_UPDATE_DELAY);
124 
125  // load initial data
126  refresh();
127 }
128 
130 {
131  timer->start();
132 }
133 
135 {
136  timer->stop();
137 }
138 
139 int PeerTableModel::rowCount(const QModelIndex& parent) const
140 {
141  Q_UNUSED(parent);
142  return priv->size();
143 }
144 
145 int PeerTableModel::columnCount(const QModelIndex& parent) const
146 {
147  Q_UNUSED(parent);
148  return columns.length();
149  ;
150 }
151 
152 QVariant PeerTableModel::data(const QModelIndex& index, int role) const
153 {
154  if (!index.isValid())
155  return QVariant();
156 
157  CNodeCombinedStats* rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
158 
159  if (role == Qt::DisplayRole) {
160  switch(index.column()) {
161  case NetNodeId:
162  return rec->nodeStats.nodeid;
163  case Address:
164  return QString::fromStdString(rec->nodeStats.addrName);
165  case Subversion:
166  return QString::fromStdString(rec->nodeStats.cleanSubVer);
167  case Ping:
169  }
170  } else if (role == Qt::TextAlignmentRole) {
171  if (index.column() == Ping)
172  return (int)(Qt::AlignRight | Qt::AlignVCenter);
173  }
174 
175  return QVariant();
176 }
177 
178 QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
179 {
180  if (orientation == Qt::Horizontal) {
181  if (role == Qt::DisplayRole && section < columns.size()) {
182  return columns[section];
183  }
184  }
185  return QVariant();
186 }
187 
188 Qt::ItemFlags PeerTableModel::flags(const QModelIndex& index) const
189 {
190  if (!index.isValid())
191  return Qt::NoItemFlags;
192 
193  Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
194  return retval;
195 }
196 
197 QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const
198 {
199  Q_UNUSED(parent);
201 
202  if (data) {
203  return createIndex(row, column, data);
204  } else {
205  return QModelIndex();
206  }
207 }
208 
210 {
211  return priv->index(idx);
212 }
213 
215 {
216  Q_EMIT layoutAboutToBeChanged();
217  priv->refreshPeers();
218  Q_EMIT layoutChanged();
219 }
220 
222 {
223  std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
224  if (it == priv->mapNodeRows.end())
225  return -1;
226 
227  return it->second;
228 }
229 
230 void PeerTableModel::sort(int column, Qt::SortOrder order)
231 {
232  priv->sortColumn = column;
233  priv->sortOrder = order;
234  refresh();
235 }
std::string addrName
Definition: net.h:594
double dPingTime
Definition: net.h:605
NodeId nodeid
Definition: net.h:588
std::string cleanSubVer
Definition: net.h:596
Model for PIVX network client.
Definition: clientmodel.h:50
bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
Qt::SortOrder order
QModelIndex index(int row, int column, const QModelIndex &parent) const
QVariant data(const QModelIndex &index, int role) const
int rowCount(const QModelIndex &parent) const
QStringList columns
PeerTableModel(ClientModel *parent=0)
const CNodeCombinedStats * getNodeStats(int idx)
int getRowByNodeId(NodeId nodeid)
PeerTablePriv * priv
QVariant headerData(int section, Qt::Orientation orientation, int role) const
void sort(int column, Qt::SortOrder order)
Qt::ItemFlags flags(const QModelIndex &index) const
int columnCount(const QModelIndex &parent) const
void refreshPeers()
Pull a full list of peers from vNodes into our cache.
int sortColumn
Column to sort nodes by.
CNodeCombinedStats * index(int idx)
QList< CNodeCombinedStats > cachedNodeStats
Local cache of peer information.
Qt::SortOrder sortOrder
Order (ascending or descending) to sort nodes by.
std::map< NodeId, int > mapNodeRows
Index of rows by node ID.
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
QString formatPingTime(double dPingTime)
Definition: guiutil.cpp:734
int NodeId
Definition: net.h:109
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
Get statistics from node state.
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
CNodeStateStats nodeStateStats
CNodeStats nodeStats
#define TRY_LOCK(cs, name)
Definition: sync.h:224