1 // Copyright (c) 2011-2016 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 <qt/peertablemodel.h>
7 #include <qt/clientmodel.h>
8 #include <qt/guiconstants.h>
9 #include <qt/guiutil.h>
11 #include <validation.h> // for cs_main
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::NetNodeId
:
29 return pLeft
->nodeid
< pRight
->nodeid
;
30 case PeerTableModel::Address
:
31 return pLeft
->addrName
.compare(pRight
->addrName
) < 0;
32 case PeerTableModel::Subversion
:
33 return pLeft
->cleanSubVer
.compare(pRight
->cleanSubVer
) < 0;
34 case PeerTableModel::Ping
:
35 return pLeft
->dMinPing
< pRight
->dMinPing
;
36 case PeerTableModel::Sent
:
37 return pLeft
->nSendBytes
< pRight
->nSendBytes
;
38 case PeerTableModel::Received
:
39 return pLeft
->nRecvBytes
< pRight
->nRecvBytes
;
45 // private implementation
49 /** Local cache of peer information */
50 QList
<CNodeCombinedStats
> cachedNodeStats
;
51 /** Column to sort nodes by */
53 /** Order (ascending or descending) to sort nodes by */
54 Qt::SortOrder sortOrder
;
55 /** Index of rows by node ID */
56 std::map
<NodeId
, int> mapNodeRows
;
58 /** Pull a full list of peers from vNodes into our cache */
62 cachedNodeStats
.clear();
63 std::vector
<CNodeStats
> vstats
;
65 g_connman
->GetNodeStats(vstats
);
66 #if QT_VERSION >= 0x040700
67 cachedNodeStats
.reserve(vstats
.size());
69 for (const CNodeStats
& nodestats
: vstats
)
71 CNodeCombinedStats stats
;
72 stats
.nodeStateStats
.nMisbehavior
= 0;
73 stats
.nodeStateStats
.nSyncHeight
= -1;
74 stats
.nodeStateStats
.nCommonHeight
= -1;
75 stats
.fNodeStateStatsAvailable
= false;
76 stats
.nodeStats
= nodestats
;
77 cachedNodeStats
.append(stats
);
81 // Try to retrieve the CNodeStateStats for each node.
83 TRY_LOCK(cs_main
, lockMain
);
86 for (CNodeCombinedStats
&stats
: cachedNodeStats
)
87 stats
.fNodeStateStatsAvailable
= GetNodeStateStats(stats
.nodeStats
.nodeid
, stats
.nodeStateStats
);
92 // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
93 qStableSort(cachedNodeStats
.begin(), cachedNodeStats
.end(), NodeLessThan(sortColumn
, sortOrder
));
98 for (const CNodeCombinedStats
& stats
: cachedNodeStats
)
99 mapNodeRows
.insert(std::pair
<NodeId
, int>(stats
.nodeStats
.nodeid
, row
++));
104 return cachedNodeStats
.size();
107 CNodeCombinedStats
*index(int idx
)
109 if (idx
>= 0 && idx
< cachedNodeStats
.size())
110 return &cachedNodeStats
[idx
];
116 PeerTableModel::PeerTableModel(ClientModel
*parent
) :
117 QAbstractTableModel(parent
),
121 columns
<< tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
122 priv
.reset(new PeerTablePriv());
123 // default to unsorted
124 priv
->sortColumn
= -1;
126 // set up timer for auto refresh
127 timer
= new QTimer(this);
128 connect(timer
, SIGNAL(timeout()), SLOT(refresh()));
129 timer
->setInterval(MODEL_UPDATE_DELAY
);
135 PeerTableModel::~PeerTableModel()
137 // Intentionally left empty
140 void PeerTableModel::startAutoRefresh()
145 void PeerTableModel::stopAutoRefresh()
150 int PeerTableModel::rowCount(const QModelIndex
&parent
) const
156 int PeerTableModel::columnCount(const QModelIndex
&parent
) const
159 return columns
.length();
162 QVariant
PeerTableModel::data(const QModelIndex
&index
, int role
) const
167 CNodeCombinedStats
*rec
= static_cast<CNodeCombinedStats
*>(index
.internalPointer());
169 if (role
== Qt::DisplayRole
) {
170 switch(index
.column())
173 return (qint64
)rec
->nodeStats
.nodeid
;
175 return QString::fromStdString(rec
->nodeStats
.addrName
);
177 return QString::fromStdString(rec
->nodeStats
.cleanSubVer
);
179 return GUIUtil::formatPingTime(rec
->nodeStats
.dMinPing
);
181 return GUIUtil::formatBytes(rec
->nodeStats
.nSendBytes
);
183 return GUIUtil::formatBytes(rec
->nodeStats
.nRecvBytes
);
185 } else if (role
== Qt::TextAlignmentRole
) {
186 switch (index
.column()) {
190 return QVariant(Qt::AlignRight
| Qt::AlignVCenter
);
199 QVariant
PeerTableModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
201 if(orientation
== Qt::Horizontal
)
203 if(role
== Qt::DisplayRole
&& section
< columns
.size())
205 return columns
[section
];
211 Qt::ItemFlags
PeerTableModel::flags(const QModelIndex
&index
) const
216 Qt::ItemFlags retval
= Qt::ItemIsSelectable
| Qt::ItemIsEnabled
;
220 QModelIndex
PeerTableModel::index(int row
, int column
, const QModelIndex
&parent
) const
223 CNodeCombinedStats
*data
= priv
->index(row
);
226 return createIndex(row
, column
, data
);
227 return QModelIndex();
230 const CNodeCombinedStats
*PeerTableModel::getNodeStats(int idx
)
232 return priv
->index(idx
);
235 void PeerTableModel::refresh()
237 Q_EMIT
layoutAboutToBeChanged();
238 priv
->refreshPeers();
239 Q_EMIT
layoutChanged();
242 int PeerTableModel::getRowByNodeId(NodeId nodeid
)
244 std::map
<NodeId
, int>::iterator it
= priv
->mapNodeRows
.find(nodeid
);
245 if (it
== priv
->mapNodeRows
.end())
251 void PeerTableModel::sort(int column
, Qt::SortOrder order
)
253 priv
->sortColumn
= column
;
254 priv
->sortOrder
= order
;