1414#include < QList>
1515#include < QTimer>
1616
17- // private implementation
18- class PeerTablePriv
19- {
20- public:
21- /* * Local cache of peer information */
22- QList<CNodeCombinedStats> cachedNodeStats;
23-
24- /* * Pull a full list of peers from vNodes into our cache */
25- void refreshPeers (interfaces::Node& node)
26- {
27- cachedNodeStats.clear ();
28-
29- interfaces::Node::NodesStats nodes_stats;
30- node.getNodesStats (nodes_stats);
31- cachedNodeStats.reserve (nodes_stats.size ());
32- for (const auto & node_stats : nodes_stats)
33- {
34- CNodeCombinedStats stats;
35- stats.nodeStats = std::get<0 >(node_stats);
36- stats.fNodeStateStatsAvailable = std::get<1 >(node_stats);
37- stats.nodeStateStats = std::get<2 >(node_stats);
38- cachedNodeStats.append (stats);
39- }
40- }
41-
42- int size () const
43- {
44- return cachedNodeStats.size ();
45- }
46-
47- CNodeCombinedStats *index (int idx)
48- {
49- if (idx >= 0 && idx < cachedNodeStats.size ())
50- return &cachedNodeStats[idx];
51-
52- return nullptr ;
53- }
54- };
55-
5617PeerTableModel::PeerTableModel (interfaces::Node& node, QObject* parent) :
5718 QAbstractTableModel(parent),
5819 m_node(node),
5920 timer(nullptr )
6021{
61- priv.reset (new PeerTablePriv ());
62-
6322 // set up timer for auto refresh
6423 timer = new QTimer (this );
6524 connect (timer, &QTimer::timeout, this , &PeerTableModel::refresh);
@@ -84,23 +43,23 @@ void PeerTableModel::stopAutoRefresh()
8443 timer->stop ();
8544}
8645
87- int PeerTableModel::rowCount (const QModelIndex & parent) const
46+ int PeerTableModel::rowCount (const QModelIndex& parent) const
8847{
8948 if (parent.isValid ()) {
9049 return 0 ;
9150 }
92- return priv-> size ();
51+ return m_peers_data. size ();
9352}
9453
95- int PeerTableModel::columnCount (const QModelIndex & parent) const
54+ int PeerTableModel::columnCount (const QModelIndex& parent) const
9655{
9756 if (parent.isValid ()) {
9857 return 0 ;
9958 }
10059 return columns.length ();
10160}
10261
103- QVariant PeerTableModel::data (const QModelIndex & index, int role) const
62+ QVariant PeerTableModel::data (const QModelIndex& index, int role) const
10463{
10564 if (!index.isValid ())
10665 return QVariant ();
@@ -173,19 +132,52 @@ Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
173132 return retval;
174133}
175134
176- QModelIndex PeerTableModel::index (int row, int column, const QModelIndex & parent) const
135+ QModelIndex PeerTableModel::index (int row, int column, const QModelIndex& parent) const
177136{
178137 Q_UNUSED (parent);
179- CNodeCombinedStats *data = priv->index (row);
180138
181- if (data)
182- return createIndex (row, column, data);
139+ if (0 <= row && row < rowCount () && 0 <= column && column < columnCount ()) {
140+ return createIndex (row, column, const_cast <CNodeCombinedStats*>(&m_peers_data[row]));
141+ }
142+
183143 return QModelIndex ();
184144}
185145
186146void PeerTableModel::refresh ()
187147{
188- Q_EMIT layoutAboutToBeChanged ();
189- priv->refreshPeers (m_node);
190- Q_EMIT layoutChanged ();
148+ interfaces::Node::NodesStats nodes_stats;
149+ m_node.getNodesStats (nodes_stats);
150+ decltype (m_peers_data) new_peers_data;
151+ new_peers_data.reserve (nodes_stats.size ());
152+ for (const auto & node_stats : nodes_stats) {
153+ const CNodeCombinedStats stats{std::get<0 >(node_stats), std::get<2 >(node_stats), std::get<1 >(node_stats)};
154+ new_peers_data.append (stats);
155+ }
156+
157+ // Handle peer addition or removal as suggested in Qt Docs. See:
158+ // - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows
159+ // - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models
160+ // We take advantage of the fact that the std::vector returned
161+ // by interfaces::Node::getNodesStats is sorted by nodeid.
162+ for (int i = 0 ; i < m_peers_data.size ();) {
163+ if (i < new_peers_data.size () && m_peers_data.at (i).nodeStats .nodeid == new_peers_data.at (i).nodeStats .nodeid ) {
164+ ++i;
165+ continue ;
166+ }
167+ // A peer has been removed from the table.
168+ beginRemoveRows (QModelIndex (), i, i);
169+ m_peers_data.erase (m_peers_data.begin () + i);
170+ endRemoveRows ();
171+ }
172+
173+ if (m_peers_data.size () < new_peers_data.size ()) {
174+ // Some peers have been added to the end of the table.
175+ beginInsertRows (QModelIndex (), m_peers_data.size (), new_peers_data.size () - 1 );
176+ m_peers_data.swap (new_peers_data);
177+ endInsertRows ();
178+ } else {
179+ m_peers_data.swap (new_peers_data);
180+ }
181+
182+ Q_EMIT changed ();
191183}
0 commit comments