From 656f52585564365f7fdaf3cb70453e8bc4dc0c89 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 13 Apr 2022 00:54:47 +0200 Subject: [PATCH] Merge bitcoin-core/gui#543: peers-tab: add connection duration column to tableview 51708c4516cb9d52e84dc8850d93f556dda1a75b gui: peersWidget - ResizeToContents Age and IP/Netmask columns (randymcmillan) 209301a442512579d57f79c82417dc7c496248b6 gui: add Age column to peers tab (randymcmillan) 127de22c5fb396e1670d2a911faf7a9adc9241e2 gui: add FormatPeerAge() utility helper (Jon Atack) Pull request description: This change adds an "Age" column to the peers table view, which displays the duration of each peer's connection. ACKs for top commit: jonatack: re-ACK 51708c4516cb9d52e84dc8850d93f556dda1a75b Jamewood: > re-ACK 51708c4 shaavan: reACK 51708c4516cb9d52e84dc8850d93f556dda1a75b hebasto: ACK 51708c4516cb9d52e84dc8850d93f556dda1a75b, I have reviewed the code and it looks OK, I agree it can be merged. Tree-SHA512: 27323f7080ec0d3fcdbf1b190fba1cd2d7406840ab6607c221cf8af950db9134e22721cc5a88f4fc4f390d8b05e98bc4b7521661a31fadad9e2c6c6390e71788 --- src/qt/guiutil.cpp | 12 ++++++++++++ src/qt/guiutil.h | 3 +++ src/qt/peertablemodel.cpp | 3 +++ src/qt/peertablemodel.h | 4 ++++ src/qt/peertablesortproxy.cpp | 2 ++ src/qt/rpcconsole.cpp | 2 ++ 6 files changed, 26 insertions(+) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 14bcc39eed..40f74f73e7 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -89,6 +89,8 @@ void ForceActivation(); #endif +using namespace std::chrono_literals; + namespace GUIUtil { static RecursiveMutex cs_css; @@ -1729,6 +1731,16 @@ QString formatDurationStr(std::chrono::seconds dur) return str_list.join(" "); } +QString FormatPeerAge(std::chrono::seconds time_connected) +{ + const auto time_now{GetTime()}; + const auto age{time_now - time_connected}; + if (age >= 24h) return QObject::tr("%1 d").arg(age / 24h); + if (age >= 1h) return QObject::tr("%1 h").arg(age / 1h); + if (age >= 1min) return QObject::tr("%1 m").arg(age / 1min); + return QObject::tr("%1 s").arg(age / 1s); +} + QString formatServicesStr(quint64 mask) { QStringList strList; diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 8f3cb7df71..3507043262 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -420,6 +420,9 @@ namespace GUIUtil /** Convert seconds into a QString with days, hours, mins, secs */ QString formatDurationStr(std::chrono::seconds dur); + /** Convert peer connection time to a QString denominated in the most relevant unit. */ + QString FormatPeerAge(std::chrono::seconds time_connected); + /** Format CNodeStats.nServices bitmask into a user-readable string */ QString formatServicesStr(quint64 mask); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index ecd305a77d..182ff17b55 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -71,6 +71,8 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const switch (column) { case NetNodeId: return (qint64)rec->nodeStats.nodeid; + case Age: + return GUIUtil::FormatPeerAge(rec->nodeStats.m_connected); case Address: // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection return QString::fromStdString((rec->nodeStats.fInbound ? "↓ " : "↑ ") + rec->nodeStats.m_addr_name); @@ -91,6 +93,7 @@ QVariant PeerTableModel::data(const QModelIndex& index, int role) const } else if (role == Qt::TextAlignmentRole) { switch (column) { case NetNodeId: + case Age: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case Address: return {}; diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 0ff1b5dba7..cf101149fd 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -47,6 +47,7 @@ public: enum ColumnIndex { NetNodeId = 0, + Age, Address, ConnectionType, Network, @@ -84,6 +85,9 @@ private: /*: Title of Peers Table column which contains a unique number used to identify a connection. */ tr("Peer"), + /*: Title of Peers Table column which indicates the duration (length of time) + since the peer connection started. */ + tr("Age"), /*: Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer. */ tr("Address"), diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp index ad966fbcab..6d716366fa 100644 --- a/src/qt/peertablesortproxy.cpp +++ b/src/qt/peertablesortproxy.cpp @@ -24,6 +24,8 @@ bool PeerTableSortProxy::lessThan(const QModelIndex& left_index, const QModelInd switch (static_cast(left_index.column())) { case PeerTableModel::NetNodeId: return left_stats.nodeid < right_stats.nodeid; + case PeerTableModel::Age: + return left_stats.m_connected > right_stats.m_connected; case PeerTableModel::Address: return left_stats.m_addr_name.compare(right_stats.m_addr_name) < 0; case PeerTableModel::ConnectionType: diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 084a65ff68..cd9f2bddcd 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -713,6 +713,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); } + ui->peerWidget->horizontalHeader()->setSectionResizeMode(PeerTableModel::Age, QHeaderView::ResizeToContents); ui->peerWidget->horizontalHeader()->setStretchLastSection(true); ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); @@ -745,6 +746,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH); ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); } + ui->banlistWidget->horizontalHeader()->setSectionResizeMode(BanTableModel::Address, QHeaderView::ResizeToContents); ui->banlistWidget->horizontalHeader()->setStretchLastSection(true); // create ban table context menu