aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schnelli <jonas.schnelli@include7.ch>2015-06-20 20:27:03 +0200
committerJonas Schnelli <jonas.schnelli@include7.ch>2015-09-16 16:50:19 +0200
commitad204df1a9077327ab1142fbc9bf41369c1a73d1 (patch)
tree40bf9432ae40956dcb6990814832e6b8ceca0158
parent50f090884ccd29e439720aeb83fcd293fae34921 (diff)
[Qt] add banlist table below peers table
-rw-r--r--src/Makefile.qt.include3
-rw-r--r--src/qt/bantablemodel.cpp192
-rw-r--r--src/qt/bantablemodel.h66
-rw-r--r--src/qt/clientmodel.cpp13
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/forms/rpcconsole.ui94
-rw-r--r--src/qt/rpcconsole.cpp13
7 files changed, 375 insertions, 10 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 3e8eda1782..480bd9dc8a 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -97,6 +97,7 @@ QT_MOC_CPP = \
qt/moc_addressbookpage.cpp \
qt/moc_addresstablemodel.cpp \
qt/moc_askpassphrasedialog.cpp \
+ qt/moc_bantablemodel.cpp \
qt/moc_bitcoinaddressvalidator.cpp \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoingui.cpp \
@@ -162,6 +163,7 @@ BITCOIN_QT_H = \
qt/addressbookpage.h \
qt/addresstablemodel.h \
qt/askpassphrasedialog.h \
+ qt/bantablemodel.h \
qt/bitcoinaddressvalidator.h \
qt/bitcoinamountfield.h \
qt/bitcoingui.h \
@@ -260,6 +262,7 @@ RES_ICONS = \
qt/res/icons/verify.png
BITCOIN_QT_CPP = \
+ qt/bantablemodel.cpp \
qt/bitcoinaddressvalidator.cpp \
qt/bitcoinamountfield.cpp \
qt/bitcoingui.cpp \
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
new file mode 100644
index 0000000000..3b71769ef3
--- /dev/null
+++ b/src/qt/bantablemodel.cpp
@@ -0,0 +1,192 @@
+// Copyright (c) 2011-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bantablemodel.h"
+
+#include "clientmodel.h"
+#include "guiconstants.h"
+#include "guiutil.h"
+
+#include "net.h"
+#include "sync.h"
+#include "utiltime.h"
+
+#include <QDebug>
+#include <QList>
+#include <QTimer>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/c_local_time_adjustor.hpp>
+
+// private implementation
+class BanTablePriv
+{
+public:
+ /** Local cache of peer information */
+ QList<CCombinedBan> cachedBanlist;
+ /** Column to sort nodes by */
+ int sortColumn;
+ /** Order (ascending or descending) to sort nodes by */
+ Qt::SortOrder sortOrder;
+
+ /** Pull a full list of banned nodes from CNode into our cache */
+ void refreshBanlist()
+ {
+ std::map<CSubNet, int64_t> banMap;
+ CNode::GetBanned(banMap);
+
+ cachedBanlist.clear();
+#if QT_VERSION >= 0x040700
+ cachedBanlist.reserve(banMap.size());
+#endif
+ std::map<CSubNet, int64_t>::iterator iter;
+ for (iter = banMap.begin(); iter != banMap.end(); ++iter) {
+ CCombinedBan banEntry;
+ banEntry.subnet = iter->first;
+ banEntry.bantil = iter->second;
+ cachedBanlist.append(banEntry);
+ }
+ }
+
+ int size()
+ {
+ return cachedBanlist.size();
+ }
+
+ CCombinedBan *index(int idx)
+ {
+ if(idx >= 0 && idx < cachedBanlist.size()) {
+ return &cachedBanlist[idx];
+ } else {
+ return 0;
+ }
+ }
+};
+
+BanTableModel::BanTableModel(ClientModel *parent) :
+ QAbstractTableModel(parent),
+ clientModel(parent),
+ timer(0)
+{
+ columns << tr("IP/Netmask") << tr("Banned Until");
+ priv = new BanTablePriv();
+ // default to unsorted
+ priv->sortColumn = -1;
+
+ // set up timer for auto refresh
+ timer = new QTimer();
+ connect(timer, SIGNAL(timeout()), SLOT(refresh()));
+ timer->setInterval(MODEL_UPDATE_DELAY);
+
+ // load initial data
+ refresh();
+}
+
+void BanTableModel::startAutoRefresh()
+{
+ timer->start();
+}
+
+void BanTableModel::stopAutoRefresh()
+{
+ timer->stop();
+}
+
+int BanTableModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return priv->size();
+}
+
+int BanTableModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return columns.length();;
+}
+
+QVariant BanTableModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid())
+ return QVariant();
+
+ CCombinedBan *rec = static_cast<CCombinedBan*>(index.internalPointer());
+
+ if (role == Qt::DisplayRole) {
+ switch(index.column())
+ {
+ case Address:
+ return QString::fromStdString(rec->subnet.ToString());
+ case Bantime:
+ //show time in users local timezone, not 64bit compatible!
+ //TODO find a way to support 64bit timestamps
+ boost::posix_time::ptime pt1 = boost::posix_time::from_time_t(rec->bantil);
+ boost::posix_time::ptime pt2 = boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local(pt1);
+ std::stringstream ss;
+ ss << pt2;
+ return QString::fromStdString(ss.str());
+ }
+ } else if (role == Qt::TextAlignmentRole) {
+ if (index.column() == Bantime)
+ return (int)(Qt::AlignRight | Qt::AlignVCenter);
+ }
+
+ return QVariant();
+}
+
+QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole && section < columns.size())
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const
+{
+ if(!index.isValid())
+ return 0;
+
+ Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ return retval;
+}
+
+QModelIndex BanTableModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ CCombinedBan *data = priv->index(row);
+
+ if (data)
+ {
+ return createIndex(row, column, data);
+ }
+ else
+ {
+ return QModelIndex();
+ }
+}
+
+void BanTableModel::refresh()
+{
+ emit layoutAboutToBeChanged();
+ priv->refreshBanlist();
+ emit layoutChanged();
+}
+
+void BanTableModel::sort(int column, Qt::SortOrder order)
+{
+ priv->sortColumn = column;
+ priv->sortOrder = order;
+ refresh();
+}
+
+bool BanTableModel::shouldShow()
+{
+ if (priv->size() > 0)
+ return true;
+ return false;
+} \ No newline at end of file
diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h
new file mode 100644
index 0000000000..ef7a26e3c6
--- /dev/null
+++ b/src/qt/bantablemodel.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2011-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_BANTABLEMODEL_H
+#define BITCOIN_QT_BANTABLEMODEL_H
+
+#include "main.h"
+#include "net.h"
+
+#include <QAbstractTableModel>
+#include <QStringList>
+
+class ClientModel;
+class BanTablePriv;
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+QT_END_NAMESPACE
+
+struct CCombinedBan {
+ CSubNet subnet;
+ int64_t bantil;
+};
+
+/**
+ Qt model providing information about connected peers, similar to the
+ "getpeerinfo" RPC call. Used by the rpc console UI.
+ */
+class BanTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit BanTableModel(ClientModel *parent = 0);
+ void startAutoRefresh();
+ void stopAutoRefresh();
+
+ enum ColumnIndex {
+ Address = 0,
+ Bantime = 1,
+ };
+
+ /** @name Methods overridden from QAbstractTableModel
+ @{*/
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ void sort(int column, Qt::SortOrder order);
+ bool shouldShow();
+ /*@}*/
+
+public slots:
+ void refresh();
+
+private:
+ ClientModel *clientModel;
+ QStringList columns;
+ BanTablePriv *priv;
+ QTimer *timer;
+};
+
+#endif // BITCOIN_QT_BANTABLEMODEL_H
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 97d6711560..62c35130f8 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -4,6 +4,7 @@
#include "clientmodel.h"
+#include "bantablemodel.h"
#include "guiconstants.h"
#include "peertablemodel.h"
@@ -26,6 +27,7 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent),
optionsModel(optionsModel),
peerTableModel(0),
+ banTableModel(0),
cachedNumBlocks(0),
cachedBlockDate(QDateTime()),
cachedReindexing(0),
@@ -33,6 +35,7 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
pollTimer(0)
{
peerTableModel = new PeerTableModel(this);
+ banTableModel = new BanTableModel(this);
pollTimer = new QTimer(this);
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
pollTimer->start(MODEL_UPDATE_DELAY);
@@ -176,6 +179,11 @@ PeerTableModel *ClientModel::getPeerTableModel()
return peerTableModel;
}
+BanTableModel *ClientModel::getBanTableModel()
+{
+ return banTableModel;
+}
+
QString ClientModel::formatFullVersion() const
{
return QString::fromStdString(FormatFullVersion());
@@ -206,6 +214,11 @@ QString ClientModel::formatClientStartupTime() const
return QDateTime::fromTime_t(nClientStartupTime).toString();
}
+void ClientModel::updateBanlist()
+{
+ banTableModel->refresh();
+}
+
// Handlers for core signals
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
{
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index ca2da3dde0..627bdf862d 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -9,6 +9,7 @@
#include <QDateTime>
class AddressTableModel;
+class BanTableModel;
class OptionsModel;
class PeerTableModel;
class TransactionTableModel;
@@ -44,6 +45,7 @@ public:
OptionsModel *getOptionsModel();
PeerTableModel *getPeerTableModel();
+ BanTableModel *getBanTableModel();
//! Return number of connections, default is in- and outbound (total)
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
@@ -72,6 +74,7 @@ public:
private:
OptionsModel *optionsModel;
PeerTableModel *peerTableModel;
+ BanTableModel *banTableModel;
int cachedNumBlocks;
QDateTime cachedBlockDate;
@@ -99,6 +102,7 @@ public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
void updateAlert(const QString &hash, int status);
+ void updateBanlist();
};
#endif // BITCOIN_QT_CLIENTMODEL_H
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index e8d9a958ad..39230aee6f 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -713,17 +713,91 @@
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" rowspan="2">
- <widget class="QTableView" name="peerWidget">
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
- </property>
- <property name="sortingEnabled">
- <bool>true</bool>
+ <layout class="QVBoxLayout" name="verticalLayout_101">
+ <property name="spacing">
+ <number>0</number>
</property>
- <attribute name="horizontalHeaderHighlightSections">
- <bool>false</bool>
- </attribute>
- </widget>
+ <item>
+ <widget class="QTableView" name="peerWidget">
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAsNeeded</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="banHeading">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>14</pointsize>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>Banned peers</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="banlistWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAsNeeded</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
</item>
<item row="0" column="1">
<widget class="QLabel" name="peerHeading">
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 2a94312be0..c6e70697fb 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -8,6 +8,7 @@
#include "clientmodel.h"
#include "guiutil.h"
#include "platformstyle.h"
+#include "bantablemodel.h"
#include "chainparams.h"
#include "rpcserver.h"
@@ -351,6 +352,9 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
+ // set up ban table
+ ui->banlistWidget->setModel(model->getBanTableModel());
+
// create context menu actions
QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
QAction* banAction1h = new QAction(tr("&Ban Node for 1 hour"), this);
@@ -395,6 +399,12 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->buildDate->setText(model->formatBuildDate());
ui->startupTime->setText(model->formatClientStartupTime());
ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
+
+ if (!clientModel->getBanTableModel()->shouldShow())
+ {
+ ui->banlistWidget->hide();
+ ui->banHeading->hide();
+ }
}
}
@@ -766,6 +776,9 @@ void RPCConsole::banSelectedNode(int bantime)
CNode::Ban(CNetAddr(addr), bantime);
bannedNode->CloseSocketDisconnect();
clearSelectedNode();
+ ui->banlistWidget->setVisible(true);
+ ui->banHeading->setVisible(true);
+ clientModel->updateBanlist();
}
}