BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
peertablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2018 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <qt/peertablemodel.h>
6 
7 #include <qt/clientmodel.h>
8 #include <qt/guiconstants.h>
9 #include <qt/guiutil.h>
10 
11 #include <interfaces/node.h>
12 #include <validation.h> // for cs_main
13 #include <sync.h>
14 
15 #include <QDebug>
16 #include <QList>
17 #include <QTimer>
18 
19 bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
20 {
21  const CNodeStats *pLeft = &(left.nodeStats);
22  const CNodeStats *pRight = &(right.nodeStats);
23 
24  if (order == Qt::DescendingOrder)
25  std::swap(pLeft, pRight);
26 
27  switch(column)
28  {
30  return pLeft->nodeid < pRight->nodeid;
32  return pLeft->addrName.compare(pRight->addrName) < 0;
34  return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
36  return pLeft->dMinPing < pRight->dMinPing;
38  return pLeft->nSendBytes < pRight->nSendBytes;
40  return pLeft->nRecvBytes < pRight->nRecvBytes;
41  }
42 
43  return false;
44 }
45 
46 // private implementation
48 {
49 public:
51  QList<CNodeCombinedStats> cachedNodeStats;
55  Qt::SortOrder sortOrder;
57  std::map<NodeId, int> mapNodeRows;
58 
61  {
62  {
63  cachedNodeStats.clear();
64 
65  interfaces::Node::NodesStats nodes_stats;
66  node.getNodesStats(nodes_stats);
67  cachedNodeStats.reserve(nodes_stats.size());
68  for (const auto& node_stats : nodes_stats)
69  {
70  CNodeCombinedStats stats;
71  stats.nodeStats = std::get<0>(node_stats);
72  stats.fNodeStateStatsAvailable = std::get<1>(node_stats);
73  stats.nodeStateStats = std::get<2>(node_stats);
74  cachedNodeStats.append(stats);
75  }
76  }
77 
78  if (sortColumn >= 0)
79  // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
80  qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
81 
82  // build index map
83  mapNodeRows.clear();
84  int row = 0;
85  for (const CNodeCombinedStats& stats : cachedNodeStats)
86  mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
87  }
88 
89  int size() const
90  {
91  return cachedNodeStats.size();
92  }
93 
95  {
96  if (idx >= 0 && idx < cachedNodeStats.size())
97  return &cachedNodeStats[idx];
98 
99  return 0;
100  }
101 };
102 
104  QAbstractTableModel(parent),
105  m_node(node),
106  clientModel(parent),
107  timer(0)
108 {
109  columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
110  priv.reset(new PeerTablePriv());
111  // default to unsorted
112  priv->sortColumn = -1;
113 
114  // set up timer for auto refresh
115  timer = new QTimer(this);
116  connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
117  timer->setInterval(MODEL_UPDATE_DELAY);
118 
119  // load initial data
120  refresh();
121 }
122 
124 {
125  // Intentionally left empty
126 }
127 
129 {
130  timer->start();
131 }
132 
134 {
135  timer->stop();
136 }
137 
138 int PeerTableModel::rowCount(const QModelIndex &parent) const
139 {
140  Q_UNUSED(parent);
141  return priv->size();
142 }
143 
144 int PeerTableModel::columnCount(const QModelIndex &parent) const
145 {
146  Q_UNUSED(parent);
147  return columns.length();
148 }
149 
150 QVariant PeerTableModel::data(const QModelIndex &index, int role) const
151 {
152  if(!index.isValid())
153  return QVariant();
154 
155  CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
156 
157  if (role == Qt::DisplayRole) {
158  switch(index.column())
159  {
160  case NetNodeId:
161  return (qint64)rec->nodeStats.nodeid;
162  case Address:
163  // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
164  return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName);
165  case Subversion:
166  return QString::fromStdString(rec->nodeStats.cleanSubVer);
167  case Ping:
169  case Sent:
171  case Received:
173  }
174  } else if (role == Qt::TextAlignmentRole) {
175  switch (index.column()) {
176  case Ping:
177  case Sent:
178  case Received:
179  return QVariant(Qt::AlignRight | Qt::AlignVCenter);
180  default:
181  return QVariant();
182  }
183  }
184 
185  return QVariant();
186 }
187 
188 QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
189 {
190  if(orientation == Qt::Horizontal)
191  {
192  if(role == Qt::DisplayRole && section < columns.size())
193  {
194  return columns[section];
195  }
196  }
197  return QVariant();
198 }
199 
200 Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
201 {
202  if(!index.isValid())
203  return 0;
204 
205  Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
206  return retval;
207 }
208 
209 QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
210 {
211  Q_UNUSED(parent);
212  CNodeCombinedStats *data = priv->index(row);
213 
214  if (data)
215  return createIndex(row, column, data);
216  return QModelIndex();
217 }
218 
220 {
221  return priv->index(idx);
222 }
223 
225 {
226  Q_EMIT layoutAboutToBeChanged();
227  priv->refreshPeers(m_node);
228  Q_EMIT layoutChanged();
229 }
230 
232 {
233  std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
234  if (it == priv->mapNodeRows.end())
235  return -1;
236 
237  return it->second;
238 }
239 
240 void PeerTableModel::sort(int column, Qt::SortOrder order)
241 {
242  priv->sortColumn = column;
243  priv->sortOrder = order;
244  refresh();
245 }
void refreshPeers(interfaces::Node &node)
Pull a full list of peers from vNodes into our cache.
QVariant data(const QModelIndex &index, int role) const
std::vector< std::tuple< CNodeStats, bool, CNodeStateStats > > NodesStats
Get stats for connected nodes.
Definition: node.h:98
int getRowByNodeId(NodeId nodeid)
bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
CNodeStateStats nodeStateStats
int sortColumn
Column to sort nodes by.
QStringList columns
QString formatBytes(uint64_t bytes)
Definition: guiutil.cpp:878
CNodeCombinedStats * index(int idx)
std::string cleanSubVer
Definition: net.h:557
Qt::SortOrder order
Qt::ItemFlags flags(const QModelIndex &index) const
CNodeStats nodeStats
Qt::SortOrder sortOrder
Order (ascending or descending) to sort nodes by.
int columnCount(const QModelIndex &parent) const
interfaces::Node & m_node
PeerTableModel(interfaces::Node &node, ClientModel *parent=0)
QList< CNodeCombinedStats > cachedNodeStats
Local cache of peer information.
bool fInbound
Definition: net.h:558
std::unique_ptr< PeerTablePriv > priv
int size() const
uint64_t nRecvBytes
Definition: net.h:563
std::string addrName
Definition: net.h:555
int64_t NodeId
Definition: net.h:88
const CNodeCombinedStats * getNodeStats(int idx)
uint64_t nSendBytes
Definition: net.h:561
QModelIndex index(int row, int column, const QModelIndex &parent) const
Model for Bitcoin network client.
Definition: clientmodel.h:44
QString formatPingTime(double dPingTime)
Definition: guiutil.cpp:831
std::map< NodeId, int > mapNodeRows
Index of rows by node ID.
double dMinPing
Definition: net.h:568
virtual bool getNodesStats(NodesStats &stats)=0
void sort(int column, Qt::SortOrder order)
Top-level interface for a bitcoin node (bsha3d process).
Definition: node.h:35
int rowCount(const QModelIndex &parent) const
QVariant headerData(int section, Qt::Orientation orientation, int role) const
NodeId nodeid
Definition: net.h:548