aboutsummaryrefslogtreecommitdiff
path: root/src/qt/peertablemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/peertablemodel.cpp')
-rw-r--r--src/qt/peertablemodel.cpp198
1 files changed, 66 insertions, 132 deletions
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index bad81d894c..b324693692 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -11,103 +11,14 @@
#include <utility>
-#include <QDebug>
#include <QList>
#include <QTimer>
-bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
-{
- const CNodeStats *pLeft = &(left.nodeStats);
- const CNodeStats *pRight = &(right.nodeStats);
-
- if (order == Qt::DescendingOrder)
- std::swap(pLeft, pRight);
-
- switch(column)
- {
- case PeerTableModel::NetNodeId:
- return pLeft->nodeid < pRight->nodeid;
- case PeerTableModel::Address:
- return pLeft->addrName.compare(pRight->addrName) < 0;
- case PeerTableModel::Network:
- return pLeft->m_network < pRight->m_network;
- case PeerTableModel::Ping:
- return pLeft->m_min_ping_usec < pRight->m_min_ping_usec;
- case PeerTableModel::Sent:
- return pLeft->nSendBytes < pRight->nSendBytes;
- case PeerTableModel::Received:
- return pLeft->nRecvBytes < pRight->nRecvBytes;
- case PeerTableModel::Subversion:
- return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
- }
-
- return false;
-}
-
-// private implementation
-class PeerTablePriv
-{
-public:
- /** Local cache of peer information */
- QList<CNodeCombinedStats> cachedNodeStats;
- /** Column to sort nodes by (default to unsorted) */
- int sortColumn{-1};
- /** Order (ascending or descending) to sort nodes by */
- Qt::SortOrder sortOrder;
- /** Index of rows by node ID */
- std::map<NodeId, int> mapNodeRows;
-
- /** Pull a full list of peers from vNodes into our cache */
- void refreshPeers(interfaces::Node& node)
- {
- {
- cachedNodeStats.clear();
-
- interfaces::Node::NodesStats nodes_stats;
- node.getNodesStats(nodes_stats);
- cachedNodeStats.reserve(nodes_stats.size());
- for (const auto& node_stats : nodes_stats)
- {
- CNodeCombinedStats stats;
- stats.nodeStats = std::get<0>(node_stats);
- stats.fNodeStateStatsAvailable = std::get<1>(node_stats);
- stats.nodeStateStats = std::get<2>(node_stats);
- cachedNodeStats.append(stats);
- }
- }
-
- if (sortColumn >= 0)
- // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
- std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
-
- // build index map
- mapNodeRows.clear();
- int row = 0;
- for (const CNodeCombinedStats& stats : cachedNodeStats)
- mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
- }
-
- int size() const
- {
- return cachedNodeStats.size();
- }
-
- CNodeCombinedStats *index(int idx)
- {
- if (idx >= 0 && idx < cachedNodeStats.size())
- return &cachedNodeStats[idx];
-
- return nullptr;
- }
-};
-
PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
QAbstractTableModel(parent),
m_node(node),
timer(nullptr)
{
- priv.reset(new PeerTablePriv());
-
// set up timer for auto refresh
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
@@ -132,15 +43,15 @@ void PeerTableModel::stopAutoRefresh()
timer->stop();
}
-int PeerTableModel::rowCount(const QModelIndex &parent) const
+int PeerTableModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;
}
- return priv->size();
+ return m_peers_data.size();
}
-int PeerTableModel::columnCount(const QModelIndex &parent) const
+int PeerTableModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid()) {
return 0;
@@ -148,48 +59,54 @@ int PeerTableModel::columnCount(const QModelIndex &parent) const
return columns.length();
}
-QVariant PeerTableModel::data(const QModelIndex &index, int role) const
+QVariant PeerTableModel::data(const QModelIndex& index, int role) const
{
if(!index.isValid())
return QVariant();
CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
+ const auto column = static_cast<ColumnIndex>(index.column());
if (role == Qt::DisplayRole) {
- switch(index.column())
- {
+ switch (column) {
case NetNodeId:
return (qint64)rec->nodeStats.nodeid;
case Address:
// prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
- return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName);
+ return QString::fromStdString((rec->nodeStats.fInbound ? "↓ " : "↑ ") + rec->nodeStats.addrName);
+ case ConnectionType:
+ return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /* prepend_direction */ false);
case Network:
return GUIUtil::NetworkToQString(rec->nodeStats.m_network);
case Ping:
- return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec);
+ return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_time);
case Sent:
return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
case Received:
return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
case Subversion:
return QString::fromStdString(rec->nodeStats.cleanSubVer);
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
} else if (role == Qt::TextAlignmentRole) {
- switch (index.column()) {
- case Network:
- return QVariant(Qt::AlignCenter);
- case Ping:
- case Sent:
- case Received:
- return QVariant(Qt::AlignRight | Qt::AlignVCenter);
- default:
- return QVariant();
- }
+ switch (column) {
+ case NetNodeId:
+ return QVariant(Qt::AlignRight | Qt::AlignVCenter);
+ case Address:
+ return {};
+ case ConnectionType:
+ case Network:
+ return QVariant(Qt::AlignCenter);
+ case Ping:
+ case Sent:
+ case Received:
+ return QVariant(Qt::AlignRight | Qt::AlignVCenter);
+ case Subversion:
+ return {};
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
} else if (role == StatsRole) {
- switch (index.column()) {
- case NetNodeId: return QVariant::fromValue(rec);
- default: return QVariant();
- }
+ return QVariant::fromValue(rec);
}
return QVariant();
@@ -215,35 +132,52 @@ Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
return retval;
}
-QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
+QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const
{
Q_UNUSED(parent);
- CNodeCombinedStats *data = priv->index(row);
- if (data)
- return createIndex(row, column, data);
+ if (0 <= row && row < rowCount() && 0 <= column && column < columnCount()) {
+ return createIndex(row, column, const_cast<CNodeCombinedStats*>(&m_peers_data[row]));
+ }
+
return QModelIndex();
}
void PeerTableModel::refresh()
{
- Q_EMIT layoutAboutToBeChanged();
- priv->refreshPeers(m_node);
- Q_EMIT layoutChanged();
-}
+ interfaces::Node::NodesStats nodes_stats;
+ m_node.getNodesStats(nodes_stats);
+ decltype(m_peers_data) new_peers_data;
+ new_peers_data.reserve(nodes_stats.size());
+ for (const auto& node_stats : nodes_stats) {
+ const CNodeCombinedStats stats{std::get<0>(node_stats), std::get<2>(node_stats), std::get<1>(node_stats)};
+ new_peers_data.append(stats);
+ }
-int PeerTableModel::getRowByNodeId(NodeId nodeid)
-{
- std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
- if (it == priv->mapNodeRows.end())
- return -1;
+ // Handle peer addition or removal as suggested in Qt Docs. See:
+ // - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows
+ // - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models
+ // We take advantage of the fact that the std::vector returned
+ // by interfaces::Node::getNodesStats is sorted by nodeid.
+ for (int i = 0; i < m_peers_data.size();) {
+ if (i < new_peers_data.size() && m_peers_data.at(i).nodeStats.nodeid == new_peers_data.at(i).nodeStats.nodeid) {
+ ++i;
+ continue;
+ }
+ // A peer has been removed from the table.
+ beginRemoveRows(QModelIndex(), i, i);
+ m_peers_data.erase(m_peers_data.begin() + i);
+ endRemoveRows();
+ }
- return it->second;
-}
+ if (m_peers_data.size() < new_peers_data.size()) {
+ // Some peers have been added to the end of the table.
+ beginInsertRows(QModelIndex(), m_peers_data.size(), new_peers_data.size() - 1);
+ m_peers_data.swap(new_peers_data);
+ endInsertRows();
+ } else {
+ m_peers_data.swap(new_peers_data);
+ }
-void PeerTableModel::sort(int column, Qt::SortOrder order)
-{
- priv->sortColumn = column;
- priv->sortOrder = order;
- refresh();
+ Q_EMIT changed();
}