1 // Copyright (c) 2011-2013 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.
5 #include "peertablemodel.h"
7 #include "clientmodel.h"
8 #include "guiconstants.h"
18 bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
20 const CNodeStats *pLeft = &(left.nodeStats);
21 const CNodeStats *pRight = &(right.nodeStats);
23 if (order == Qt::DescendingOrder)
24 std::swap(pLeft, pRight);
28 case PeerTableModel::Address:
29 return pLeft->addrName.compare(pRight->addrName) < 0;
30 case PeerTableModel::Subversion:
31 return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
32 case PeerTableModel::Ping:
33 return pLeft->dPingTime < pRight->dPingTime;
39 // private implementation
43 /** Local cache of peer information */
44 QList<CNodeCombinedStats> cachedNodeStats;
45 /** Column to sort nodes by */
47 /** Order (ascending or descending) to sort nodes by */
48 Qt::SortOrder sortOrder;
49 /** Index of rows by node ID */
50 std::map<NodeId, int> mapNodeRows;
52 /** Pull a full list of peers from vNodes into our cache */
56 TRY_LOCK(cs_vNodes, lockNodes);
59 // skip the refresh if we can't immediately get the lock
62 cachedNodeStats.clear();
63 #if QT_VERSION >= 0x040700
64 cachedNodeStats.reserve(vNodes.size());
66 BOOST_FOREACH(CNode* pnode, vNodes)
68 CNodeCombinedStats stats;
69 stats.nodeStateStats.nMisbehavior = 0;
70 stats.nodeStateStats.nSyncHeight = -1;
71 stats.fNodeStateStatsAvailable = false;
72 pnode->copyStats(stats.nodeStats);
73 cachedNodeStats.append(stats);
77 // Try to retrieve the CNodeStateStats for each node.
79 TRY_LOCK(cs_main, lockMain);
82 BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
83 stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats);
88 // sort cacheNodeStats (use stable sort to prevent rows jumping around unneceesarily)
89 qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
94 BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
95 mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
100 return cachedNodeStats.size();
103 CNodeCombinedStats *index(int idx)
105 if(idx >= 0 && idx < cachedNodeStats.size()) {
106 return &cachedNodeStats[idx];
113 PeerTableModel::PeerTableModel(ClientModel *parent) :
114 QAbstractTableModel(parent),
118 columns << tr("Address/Hostname") << tr("User Agent") << tr("Ping Time");
119 priv = new PeerTablePriv();
120 // default to unsorted
121 priv->sortColumn = -1;
123 // set up timer for auto refresh
124 timer = new QTimer();
125 connect(timer, SIGNAL(timeout()), SLOT(refresh()));
126 timer->setInterval(MODEL_UPDATE_DELAY);
132 void PeerTableModel::startAutoRefresh()
137 void PeerTableModel::stopAutoRefresh()
142 int PeerTableModel::rowCount(const QModelIndex &parent) const
148 int PeerTableModel::columnCount(const QModelIndex &parent) const
151 return columns.length();;
154 QVariant PeerTableModel::data(const QModelIndex &index, int role) const
159 CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
161 if (role == Qt::DisplayRole) {
162 switch(index.column())
165 return QString::fromStdString(rec->nodeStats.addrName);
167 return QString::fromStdString(rec->nodeStats.cleanSubVer);
169 return GUIUtil::formatPingTime(rec->nodeStats.dPingTime);
171 } else if (role == Qt::TextAlignmentRole) {
172 if (index.column() == Ping)
173 return (int)(Qt::AlignRight | Qt::AlignVCenter);
179 QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
181 if(orientation == Qt::Horizontal)
183 if(role == Qt::DisplayRole && section < columns.size())
185 return columns[section];
191 Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
196 Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
200 QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
203 CNodeCombinedStats *data = priv->index(row);
207 return createIndex(row, column, data);
211 return QModelIndex();
215 const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
217 return priv->index(idx);
220 void PeerTableModel::refresh()
222 emit layoutAboutToBeChanged();
223 priv->refreshPeers();
224 emit layoutChanged();
227 int PeerTableModel::getRowByNodeId(NodeId nodeid)
229 std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
230 if (it == priv->mapNodeRows.end())
236 void PeerTableModel::sort(int column, Qt::SortOrder order)
238 priv->sortColumn = column;
239 priv->sortOrder = order;