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