bantablemodel.cpp raw
1 // Copyright (c) 2011-present 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 <qt/bantablemodel.h>
6
7 #include <interfaces/node.h>
8 #include <net_types.h>
9
10 #include <utility>
11
12 #include <QDateTime>
13 #include <QList>
14 #include <QLocale>
15 #include <QModelIndex>
16 #include <QVariant>
17
18 bool BannedNodeLessThan::operator()(const CCombinedBan& left, const CCombinedBan& right) const
19 {
20 const CCombinedBan* pLeft = &left;
21 const CCombinedBan* pRight = &right;
22
23 if (order == Qt::DescendingOrder)
24 std::swap(pLeft, pRight);
25
26 switch (static_cast<BanTableModel::ColumnIndex>(column)) {
27 case BanTableModel::Address:
28 return pLeft->subnet.ToString().compare(pRight->subnet.ToString()) < 0;
29 case BanTableModel::Bantime:
30 return pLeft->banEntry.nBanUntil < pRight->banEntry.nBanUntil;
31 } // no default case, so the compiler can warn about missing cases
32 assert(false);
33 }
34
35 // private implementation
36 class BanTablePriv
37 {
38 public:
39 /** Local cache of peer information */
40 QList<CCombinedBan> cachedBanlist;
41 /** Column to sort nodes by (default to unsorted) */
42 int sortColumn{-1};
43 /** Order (ascending or descending) to sort nodes by */
44 Qt::SortOrder sortOrder;
45
46 /** Pull a full list of banned nodes from interfaces::Node into our cache */
47 void refreshBanlist(interfaces::Node& node)
48 {
49 banmap_t banMap;
50 node.getBanned(banMap);
51
52 cachedBanlist.clear();
53 cachedBanlist.reserve(banMap.size());
54 for (const auto& entry : banMap)
55 {
56 CCombinedBan banEntry;
57 banEntry.subnet = entry.first;
58 banEntry.banEntry = entry.second;
59 cachedBanlist.append(banEntry);
60 }
61
62 if (sortColumn >= 0)
63 // sort cachedBanlist (use stable sort to prevent rows jumping around unnecessarily)
64 std::stable_sort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder));
65 }
66
67 int size() const
68 {
69 return cachedBanlist.size();
70 }
71
72 CCombinedBan *index(int idx)
73 {
74 if (idx >= 0 && idx < cachedBanlist.size())
75 return &cachedBanlist[idx];
76
77 return nullptr;
78 }
79 };
80
81 BanTableModel::BanTableModel(interfaces::Node& node, QObject* parent) :
82 QAbstractTableModel(parent),
83 m_node(node)
84 {
85 columns << tr("IP/Netmask") << tr("Banned Until");
86 priv.reset(new BanTablePriv());
87
88 // load initial data
89 refresh();
90 }
91
92 BanTableModel::~BanTableModel() = default;
93
94 int BanTableModel::rowCount(const QModelIndex &parent) const
95 {
96 if (parent.isValid()) {
97 return 0;
98 }
99 return priv->size();
100 }
101
102 int BanTableModel::columnCount(const QModelIndex &parent) const
103 {
104 if (parent.isValid()) {
105 return 0;
106 }
107 return columns.length();
108 }
109
110 QVariant BanTableModel::data(const QModelIndex &index, int role) const
111 {
112 if(!index.isValid())
113 return QVariant();
114
115 CCombinedBan *rec = static_cast<CCombinedBan*>(index.internalPointer());
116
117 const auto column = static_cast<ColumnIndex>(index.column());
118 if (role == Qt::DisplayRole) {
119 switch (column) {
120 case Address:
121 return QString::fromStdString(rec->subnet.ToString());
122 case Bantime:
123 QDateTime date = QDateTime::fromMSecsSinceEpoch(0);
124 date = date.addSecs(rec->banEntry.nBanUntil);
125 return QLocale::system().toString(date, QLocale::LongFormat);
126 } // no default case, so the compiler can warn about missing cases
127 assert(false);
128 }
129
130 return QVariant();
131 }
132
133 QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int role) const
134 {
135 if(orientation == Qt::Horizontal)
136 {
137 if(role == Qt::DisplayRole && section < columns.size())
138 {
139 return columns[section];
140 }
141 }
142 return QVariant();
143 }
144
145 Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const
146 {
147 if (!index.isValid()) return Qt::NoItemFlags;
148
149 Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
150 return retval;
151 }
152
153 QModelIndex BanTableModel::index(int row, int column, const QModelIndex &parent) const
154 {
155 Q_UNUSED(parent);
156 CCombinedBan *data = priv->index(row);
157
158 if (data)
159 return createIndex(row, column, data);
160 return QModelIndex();
161 }
162
163 void BanTableModel::refresh()
164 {
165 Q_EMIT layoutAboutToBeChanged();
166 priv->refreshBanlist(m_node);
167 Q_EMIT layoutChanged();
168 }
169
170 void BanTableModel::sort(int column, Qt::SortOrder order)
171 {
172 priv->sortColumn = column;
173 priv->sortOrder = order;
174 refresh();
175 }
176
177 bool BanTableModel::shouldShow()
178 {
179 return priv->size() > 0;
180 }
181
182 bool BanTableModel::unban(const QModelIndex& index)
183 {
184 CCombinedBan* ban{static_cast<CCombinedBan*>(index.internalPointer())};
185 return ban != nullptr && m_node.unban(ban->subnet);
186 }
187