Bitcoin Core  24.99.0
P2P Digital Currency
peertablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2021 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/guiconstants.h>
8 #include <qt/guiutil.h>
9 
10 #include <interfaces/node.h>
11 
12 #include <utility>
13 
14 #include <QList>
15 #include <QTimer>
16 
18  QAbstractTableModel(parent),
19  m_node(node),
20  timer(nullptr)
21 {
22  // set up timer for auto refresh
23  timer = new QTimer(this);
24  connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
25  timer->setInterval(MODEL_UPDATE_DELAY);
26 
27  // load initial data
28  refresh();
29 }
30 
32 
34 {
35  timer->start();
36 }
37 
39 {
40  timer->stop();
41 }
42 
43 int PeerTableModel::rowCount(const QModelIndex& parent) const
44 {
45  if (parent.isValid()) {
46  return 0;
47  }
48  return m_peers_data.size();
49 }
50 
51 int PeerTableModel::columnCount(const QModelIndex& parent) const
52 {
53  if (parent.isValid()) {
54  return 0;
55  }
56  return columns.length();
57 }
58 
59 QVariant PeerTableModel::data(const QModelIndex& index, int role) const
60 {
61  if(!index.isValid())
62  return QVariant();
63 
64  CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
65 
66  const auto column = static_cast<ColumnIndex>(index.column());
67  if (role == Qt::DisplayRole) {
68  switch (column) {
69  case NetNodeId:
70  return (qint64)rec->nodeStats.nodeid;
71  case Age:
73  case Address:
74  return QString::fromStdString(rec->nodeStats.m_addr_name);
75  case Direction:
76  return QString(rec->nodeStats.fInbound ?
77  //: An Inbound Connection from a Peer.
78  tr("Inbound") :
79  //: An Outbound Connection to a Peer.
80  tr("Outbound"));
81  case ConnectionType:
82  return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /*prepend_direction=*/false);
83  case Network:
85  case Ping:
87  case Sent:
89  case Received:
91  case Subversion:
92  return QString::fromStdString(rec->nodeStats.cleanSubVer);
93  } // no default case, so the compiler can warn about missing cases
94  assert(false);
95  } else if (role == Qt::TextAlignmentRole) {
96  switch (column) {
97  case NetNodeId:
98  case Age:
99  return QVariant(Qt::AlignRight | Qt::AlignVCenter);
100  case Address:
101  return {};
102  case Direction:
103  case ConnectionType:
104  case Network:
105  return QVariant(Qt::AlignCenter);
106  case Ping:
107  case Sent:
108  case Received:
109  return QVariant(Qt::AlignRight | Qt::AlignVCenter);
110  case Subversion:
111  return {};
112  } // no default case, so the compiler can warn about missing cases
113  assert(false);
114  } else if (role == StatsRole) {
115  return QVariant::fromValue(rec);
116  }
117 
118  return QVariant();
119 }
120 
121 QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
122 {
123  if(orientation == Qt::Horizontal)
124  {
125  if(role == Qt::DisplayRole && section < columns.size())
126  {
127  return columns[section];
128  }
129  }
130  return QVariant();
131 }
132 
133 Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
134 {
135  if (!index.isValid()) return Qt::NoItemFlags;
136 
137  Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
138  return retval;
139 }
140 
141 QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const
142 {
143  Q_UNUSED(parent);
144 
145  if (0 <= row && row < rowCount() && 0 <= column && column < columnCount()) {
146  return createIndex(row, column, const_cast<CNodeCombinedStats*>(&m_peers_data[row]));
147  }
148 
149  return QModelIndex();
150 }
151 
153 {
154  interfaces::Node::NodesStats nodes_stats;
155  m_node.getNodesStats(nodes_stats);
156  decltype(m_peers_data) new_peers_data;
157  new_peers_data.reserve(nodes_stats.size());
158  for (const auto& node_stats : nodes_stats) {
159  const CNodeCombinedStats stats{std::get<0>(node_stats), std::get<2>(node_stats), std::get<1>(node_stats)};
160  new_peers_data.append(stats);
161  }
162 
163  // Handle peer addition or removal as suggested in Qt Docs. See:
164  // - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows
165  // - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models
166  // We take advantage of the fact that the std::vector returned
167  // by interfaces::Node::getNodesStats is sorted by nodeid.
168  for (int i = 0; i < m_peers_data.size();) {
169  if (i < new_peers_data.size() && m_peers_data.at(i).nodeStats.nodeid == new_peers_data.at(i).nodeStats.nodeid) {
170  ++i;
171  continue;
172  }
173  // A peer has been removed from the table.
174  beginRemoveRows(QModelIndex(), i, i);
175  m_peers_data.erase(m_peers_data.begin() + i);
176  endRemoveRows();
177  }
178 
179  if (m_peers_data.size() < new_peers_data.size()) {
180  // Some peers have been added to the end of the table.
181  beginInsertRows(QModelIndex(), m_peers_data.size(), new_peers_data.size() - 1);
182  m_peers_data.swap(new_peers_data);
183  endInsertRows();
184  } else {
185  m_peers_data.swap(new_peers_data);
186  }
187 
188  const auto top_left = index(0, 0);
189  const auto bottom_right = index(rowCount() - 1, columnCount() - 1);
190  Q_EMIT dataChanged(top_left, bottom_right);
191 }
node::NodeContext m_node
Definition: bitcoin-gui.cpp:37
uint64_t nRecvBytes
Definition: net.h:206
bool fInbound
Definition: net.h:200
uint64_t nSendBytes
Definition: net.h:204
ConnectionType m_conn_type
Definition: net.h:220
std::chrono::microseconds m_min_ping_time
Definition: net.h:210
std::chrono::seconds m_connected
Definition: net.h:195
std::string m_addr_name
Definition: net.h:197
Network m_network
Definition: net.h:218
NodeId nodeid
Definition: net.h:190
std::string cleanSubVer
Definition: net.h:199
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
interfaces::Node & m_node
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QList< CNodeCombinedStats > m_peers_data
Internal peer data structure.
const QStringList columns
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
PeerTableModel(interfaces::Node &node, QObject *parent)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
std::vector< std::tuple< CNodeStats, bool, CNodeStateStats > > NodesStats
Get stats for connected nodes.
Definition: node.h:129
virtual bool getNodesStats(NodesStats &stats)=0
static constexpr auto MODEL_UPDATE_DELAY
Definition: guiconstants.h:14
QString NetworkToQString(Network net)
Convert enum Network to QString.
Definition: guiutil.cpp:670
QString formatBytes(uint64_t bytes)
Definition: guiutil.cpp:803
QString formatPingTime(std::chrono::microseconds ping_time)
Format a CNodeStats.m_last_ping_time into a user-readable string or display N/A, if 0.
Definition: guiutil.cpp:754
QString ConnectionTypeToQString(ConnectionType conn_type, bool prepend_direction)
Convert enum ConnectionType to QString.
Definition: guiutil.cpp:685
QString FormatPeerAge(std::chrono::seconds time_connected)
Convert peer connection time to a QString denominated in the most relevant unit.
Definition: guiutil.cpp:730
Definition: init.h:25
CNodeStats nodeStats
assert(!tx.IsCoinBase())