Fabcoin Core  0.16.2
P2P Digital Currency
peertablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2017 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.
4 
5 #include <peertablemodel.h>
6 
7 #include <clientmodel.h>
8 #include <guiconstants.h>
9 #include <guiutil.h>
10 
11 #include <validation.h> // for cs_main
12 #include <sync.h>
13 
14 #include <QDebug>
15 #include <QList>
16 #include <QTimer>
17 
18 bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
19 {
20  const CNodeStats *pLeft = &(left.nodeStats);
21  const CNodeStats *pRight = &(right.nodeStats);
22 
23  if (order == Qt::DescendingOrder)
24  std::swap(pLeft, pRight);
25 
26  switch(column)
27  {
29  return pLeft->nodeid < pRight->nodeid;
31  return pLeft->addrName.compare(pRight->addrName) < 0;
33  return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
35  return pLeft->dMinPing < pRight->dMinPing;
36  }
37 
38  return false;
39 }
40 
41 // private implementation
43 {
44 public:
46  QList<CNodeCombinedStats> cachedNodeStats;
50  Qt::SortOrder sortOrder;
52  std::map<NodeId, int> mapNodeRows;
53 
55  void refreshPeers()
56  {
57  {
58  cachedNodeStats.clear();
59  std::vector<CNodeStats> vstats;
60  if(g_connman)
61  g_connman->GetNodeStats(vstats);
62 #if QT_VERSION >= 0x040700
63  cachedNodeStats.reserve(vstats.size());
64 #endif
65  for (const CNodeStats& nodestats : vstats)
66  {
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);
74  }
75  }
76 
77  // Try to retrieve the CNodeStateStats for each node.
78  {
79  TRY_LOCK(cs_main, lockMain);
80  if (lockMain)
81  {
82  for (CNodeCombinedStats &stats : cachedNodeStats)
83  stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats);
84  }
85  }
86 
87  if (sortColumn >= 0)
88  // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
89  qStableSort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
90 
91  // build index map
92  mapNodeRows.clear();
93  int row = 0;
94  for (const CNodeCombinedStats& stats : cachedNodeStats)
95  mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
96  }
97 
98  int size() const
99  {
100  return cachedNodeStats.size();
101  }
102 
104  {
105  if (idx >= 0 && idx < cachedNodeStats.size())
106  return &cachedNodeStats[idx];
107 
108  return 0;
109  }
110 };
111 
113  QAbstractTableModel(parent),
114  clientModel(parent),
115  timer(0)
116 {
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;
121 
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);
126 
127  // load initial data
128  refresh();
129 }
130 
132 {
133  // Intentionally left empty
134 }
135 
137 {
138  timer->start();
139 }
140 
142 {
143  timer->stop();
144 }
145 
146 int PeerTableModel::rowCount(const QModelIndex &parent) const
147 {
148  Q_UNUSED(parent);
149  return priv->size();
150 }
151 
152 int PeerTableModel::columnCount(const QModelIndex &parent) const
153 {
154  Q_UNUSED(parent);
155  return columns.length();
156 }
157 
158 QVariant PeerTableModel::data(const QModelIndex &index, int role) const
159 {
160  if(!index.isValid())
161  return QVariant();
162 
163  CNodeCombinedStats *rec = static_cast<CNodeCombinedStats*>(index.internalPointer());
164 
165  if (role == Qt::DisplayRole) {
166  switch(index.column())
167  {
168  case NetNodeId:
169  return (qint64)rec->nodeStats.nodeid;
170  case Address:
171  return QString::fromStdString(rec->nodeStats.addrName);
172  case Subversion:
173  return QString::fromStdString(rec->nodeStats.cleanSubVer);
174  case Ping:
176  }
177  } else if (role == Qt::TextAlignmentRole) {
178  if (index.column() == Ping)
179  return (QVariant)(Qt::AlignRight | Qt::AlignVCenter);
180  }
181 
182  return QVariant();
183 }
184 
185 QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, int role) const
186 {
187  if(orientation == Qt::Horizontal)
188  {
189  if(role == Qt::DisplayRole && section < columns.size())
190  {
191  return columns[section];
192  }
193  }
194  return QVariant();
195 }
196 
197 Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
198 {
199  if(!index.isValid())
200  return 0;
201 
202  Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
203  return retval;
204 }
205 
206 QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const
207 {
208  Q_UNUSED(parent);
209  CNodeCombinedStats *data = priv->index(row);
210 
211  if (data)
212  return createIndex(row, column, data);
213  return QModelIndex();
214 }
215 
217 {
218  return priv->index(idx);
219 }
220 
222 {
223  Q_EMIT layoutAboutToBeChanged();
224  priv->refreshPeers();
225  Q_EMIT layoutChanged();
226 }
227 
229 {
230  std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
231  if (it == priv->mapNodeRows.end())
232  return -1;
233 
234  return it->second;
235 }
236 
237 void PeerTableModel::sort(int column, Qt::SortOrder order)
238 {
239  priv->sortColumn = column;
240  priv->sortOrder = order;
241  refresh();
242 }
int getRowByNodeId(NodeId nodeid)
int rowCount(const QModelIndex &parent) const
CNodeStateStats nodeStateStats
#define TRY_LOCK(cs, name)
Definition: sync.h:177
int columnCount(const QModelIndex &parent) const
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
Definition: Interface.h:284
void refreshPeers()
Pull a full list of peers from vNodes into our cache.
int sortColumn
Column to sort nodes by.
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
Get statistics from node state.
CCriticalSection cs_main
Definition: validation.cpp:77
QStringList columns
CNodeCombinedStats * index(int idx)
std::string cleanSubVer
Definition: net.h:531
NodeLessThan(int nColumn, Qt::SortOrder fOrder)
Qt::SortOrder order
CNodeStats nodeStats
Qt::SortOrder sortOrder
Order (ascending or descending) to sort nodes by.
int size() const
QVariant headerData(int section, Qt::Orientation orientation, int role) const
QList< CNodeCombinedStats > cachedNodeStats
Local cache of peer information.
std::unique_ptr< PeerTablePriv > priv
Qt::ItemFlags flags(const QModelIndex &index) const
std::string addrName
Definition: net.h:529
int64_t NodeId
Definition: net.h:93
const CNodeCombinedStats * getNodeStats(int idx)
bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
Model for Fabcoin network client.
Definition: clientmodel.h:38
QString formatPingTime(double dPingTime)
Definition: guiutil.cpp:932
std::map< NodeId, int > mapNodeRows
Index of rows by node ID.
QVariant data(const QModelIndex &index, int role) const
QModelIndex index(int row, int column, const QModelIndex &parent) const
double dMinPing
Definition: net.h:542
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:75
void sort(int column, Qt::SortOrder order)
PeerTableModel(ClientModel *parent=0)
NodeId nodeid
Definition: net.h:522