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 "peertablemodel.h"
7 #include "clientmodel.h"
8 #include "guiconstants.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
;
41 // private implementation
45 /** Local cache of peer information */
46 QList
<CNodeCombinedStats
> cachedNodeStats
;
47 /** Column to sort nodes by */
49 /** Order (ascending or descending) to sort nodes by */
50 Qt::SortOrder sortOrder
;
51 /** Index of rows by node ID */
52 std::map
<NodeId
, int> mapNodeRows
;
54 /** Pull a full list of peers from vNodes into our cache */
58 cachedNodeStats
.clear();
59 std::vector
<CNodeStats
> vstats
;
61 g_connman
->GetNodeStats(vstats
);
62 #if QT_VERSION >= 0x040700
63 cachedNodeStats
.reserve(vstats
.size());
65 for (const CNodeStats
& nodestats
: vstats
)
67 CNodeCombinedStats stats
;
68 stats
.nodeStateStats
.nMisbehavior
= 0;
69 stats
.nodeStateStats
.nSyncHeight
= -1;
70 stats
.nodeStateStats
.nCommonHeight
= -1;
71 stats
.fNodeStateStatsAvailable
= false;
72 stats
.nodeStats
= nodestats
;
73 cachedNodeStats
.append(stats
);
77 // Try to retrieve the CNodeStateStats for each node.
79 TRY_LOCK(cs_main
, lockMain
);
82 for (CNodeCombinedStats
&stats
: cachedNodeStats
)
83 stats
.fNodeStateStatsAvailable
= GetNodeStateStats(stats
.nodeStats
.nodeid
, stats
.nodeStateStats
);
88 // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
89 qStableSort(cachedNodeStats
.begin(), cachedNodeStats
.end(), NodeLessThan(sortColumn
, sortOrder
));
94 for (const 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
];
112 PeerTableModel::PeerTableModel(ClientModel
*parent
) :
113 QAbstractTableModel(parent
),
117 columns
<< tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping");
118 priv
.reset(new PeerTablePriv());
119 // default to unsorted
120 priv
->sortColumn
= -1;
122 // set up timer for auto refresh
123 timer
= new QTimer(this);
124 connect(timer
, SIGNAL(timeout()), SLOT(refresh()));
125 timer
->setInterval(MODEL_UPDATE_DELAY
);
131 PeerTableModel::~PeerTableModel()
133 // Intentionally left empty
136 void PeerTableModel::startAutoRefresh()
141 void PeerTableModel::stopAutoRefresh()
146 int PeerTableModel::rowCount(const QModelIndex
&parent
) const
152 int PeerTableModel::columnCount(const QModelIndex
&parent
) const
155 return columns
.length();
158 QVariant
PeerTableModel::data(const QModelIndex
&index
, int role
) const
163 CNodeCombinedStats
*rec
= static_cast<CNodeCombinedStats
*>(index
.internalPointer());
165 if (role
== Qt::DisplayRole
) {
166 switch(index
.column())
169 return (qint64
)rec
->nodeStats
.nodeid
;
171 return QString::fromStdString(rec
->nodeStats
.addrName
);
173 return QString::fromStdString(rec
->nodeStats
.cleanSubVer
);
175 return GUIUtil::formatPingTime(rec
->nodeStats
.dMinPing
);
177 } else if (role
== Qt::TextAlignmentRole
) {
178 if (index
.column() == Ping
)
179 return (QVariant
)(Qt::AlignRight
| Qt::AlignVCenter
);
185 QVariant
PeerTableModel::headerData(int section
, Qt::Orientation orientation
, int role
) const
187 if(orientation
== Qt::Horizontal
)
189 if(role
== Qt::DisplayRole
&& section
< columns
.size())
191 return columns
[section
];
197 Qt::ItemFlags
PeerTableModel::flags(const QModelIndex
&index
) const
202 Qt::ItemFlags retval
= Qt::ItemIsSelectable
| Qt::ItemIsEnabled
;
206 QModelIndex
PeerTableModel::index(int row
, int column
, const QModelIndex
&parent
) const
209 CNodeCombinedStats
*data
= priv
->index(row
);
212 return createIndex(row
, column
, data
);
213 return QModelIndex();
216 const CNodeCombinedStats
*PeerTableModel::getNodeStats(int idx
)
218 return priv
->index(idx
);
221 void PeerTableModel::refresh()
223 Q_EMIT
layoutAboutToBeChanged();
224 priv
->refreshPeers();
225 Q_EMIT
layoutChanged();
228 int PeerTableModel::getRowByNodeId(NodeId nodeid
)
230 std::map
<NodeId
, int>::iterator it
= priv
->mapNodeRows
.find(nodeid
);
231 if (it
== priv
->mapNodeRows
.end())
237 void PeerTableModel::sort(int column
, Qt::SortOrder order
)
239 priv
->sortColumn
= column
;
240 priv
->sortOrder
= order
;