aboutsummaryrefslogtreecommitdiff
path: root/src/qt/rpcconsole.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/rpcconsole.cpp')
-rw-r--r--src/qt/rpcconsole.cpp152
1 files changed, 132 insertions, 20 deletions
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index ec18ea8f71..9603a26c6e 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -5,9 +5,11 @@
#include "rpcconsole.h"
#include "ui_rpcconsole.h"
+#include "bantablemodel.h"
#include "clientmodel.h"
#include "guiutil.h"
#include "platformstyle.h"
+#include "bantablemodel.h"
#include "chainparams.h"
#include "rpcserver.h"
@@ -25,6 +27,7 @@
#include <QKeyEvent>
#include <QMenu>
#include <QScrollBar>
+#include <QSignalMapper>
#include <QThread>
#include <QTime>
#include <QTimer>
@@ -240,8 +243,9 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
clientModel(0),
historyPtr(0),
cachedNodeid(-1),
- contextMenu(0),
- platformStyle(platformStyle)
+ platformStyle(platformStyle),
+ peersTableContextMenu(0),
+ banTableContextMenu(0)
{
ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
@@ -328,8 +332,7 @@ void RPCConsole::setClientModel(ClientModel *model)
{
clientModel = model;
ui->trafficGraph->setClientModel(model);
- if(model)
- {
+ if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) {
// Keep up to date with client
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
@@ -350,23 +353,75 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
+ ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
- // create context menu actions
+ // create peer table context menu actions
QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
-
- // create context menu
- contextMenu = new QMenu();
- contextMenu->addAction(disconnectAction);
-
- // context menu signals
- connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu(const QPoint&)));
+ QAction* banAction1h = new QAction(tr("Ban Node for") + " " + tr("1 &hour"), this);
+ QAction* banAction24h = new QAction(tr("Ban Node for") + " " + tr("1 &day"), this);
+ QAction* banAction7d = new QAction(tr("Ban Node for") + " " + tr("1 &week"), this);
+ QAction* banAction365d = new QAction(tr("Ban Node for") + " " + tr("1 &year"), this);
+
+ // create peer table context menu
+ peersTableContextMenu = new QMenu();
+ peersTableContextMenu->addAction(disconnectAction);
+ peersTableContextMenu->addAction(banAction1h);
+ peersTableContextMenu->addAction(banAction24h);
+ peersTableContextMenu->addAction(banAction7d);
+ peersTableContextMenu->addAction(banAction365d);
+
+ // Add a signal mapping to allow dynamic context menu arguments.
+ // We need to use int (instead of int64_t), because signal mapper only supports
+ // int or objects, which is okay because max bantime (1 year) is < int_max.
+ QSignalMapper* signalMapper = new QSignalMapper(this);
+ signalMapper->setMapping(banAction1h, 60*60);
+ signalMapper->setMapping(banAction24h, 60*60*24);
+ signalMapper->setMapping(banAction7d, 60*60*24*7);
+ signalMapper->setMapping(banAction365d, 60*60*24*365);
+ connect(banAction1h, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(banAction24h, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(banAction7d, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(banAction365d, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(banSelectedNode(int)));
+
+ // peer table context menu signals
+ connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPeersTableContextMenu(const QPoint&)));
connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode()));
- // connect the peerWidget selection model to our peerSelected() handler
+ // peer table signal handling - update peer details when selecting new node
connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
- this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
+ this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
+ // peer table signal handling - update peer details when new nodes are added to the model
connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged()));
+ // set up ban table
+ ui->banlistWidget->setModel(model->getBanTableModel());
+ ui->banlistWidget->verticalHeader()->hide();
+ ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+ ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH);
+ ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
+ ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
+
+ // create ban table context menu action
+ QAction* unbanAction = new QAction(tr("&Unban Node"), this);
+
+ // create ban table context menu
+ banTableContextMenu = new QMenu();
+ banTableContextMenu->addAction(unbanAction);
+
+ // ban table context menu signals
+ connect(ui->banlistWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showBanTableContextMenu(const QPoint&)));
+ connect(unbanAction, SIGNAL(triggered()), this, SLOT(unbanSelectedNode()));
+
+ // ban table signal handling - clear peer details when clicking a peer in the ban table
+ connect(ui->banlistWidget, SIGNAL(clicked(const QModelIndex&)), this, SLOT(clearSelectedNode()));
+ // ban table signal handling - ensure ban table is shown or hidden (if empty)
+ connect(model->getBanTableModel(), SIGNAL(layoutChanged()), this, SLOT(showOrHideBanTableIfRequired()));
+ showOrHideBanTableIfRequired();
+
// Provide initial values
ui->clientVersion->setText(model->formatFullVersion());
ui->clientUserAgent->setText(model->formatSubVersion());
@@ -576,7 +631,7 @@ void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelecti
{
Q_UNUSED(deselected);
- if (!clientModel || selected.indexes().isEmpty())
+ if (!clientModel || !clientModel->getPeerTableModel() || selected.indexes().isEmpty())
return;
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row());
@@ -586,7 +641,7 @@ void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelecti
void RPCConsole::peerLayoutChanged()
{
- if (!clientModel)
+ if (!clientModel || !clientModel->getPeerTableModel())
return;
const CNodeCombinedStats *stats = NULL;
@@ -695,7 +750,7 @@ void RPCConsole::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
- if (!clientModel)
+ if (!clientModel || !clientModel->getPeerTableModel())
return;
// start PeerTableModel auto refresh
@@ -706,18 +761,25 @@ void RPCConsole::hideEvent(QHideEvent *event)
{
QWidget::hideEvent(event);
- if (!clientModel)
+ if (!clientModel || !clientModel->getPeerTableModel())
return;
// stop PeerTableModel auto refresh
clientModel->getPeerTableModel()->stopAutoRefresh();
}
-void RPCConsole::showMenu(const QPoint& point)
+void RPCConsole::showPeersTableContextMenu(const QPoint& point)
{
QModelIndex index = ui->peerWidget->indexAt(point);
if (index.isValid())
- contextMenu->exec(QCursor::pos());
+ peersTableContextMenu->exec(QCursor::pos());
+}
+
+void RPCConsole::showBanTableContextMenu(const QPoint& point)
+{
+ QModelIndex index = ui->banlistWidget->indexAt(point);
+ if (index.isValid())
+ banTableContextMenu->exec(QCursor::pos());
}
void RPCConsole::disconnectSelectedNode()
@@ -731,6 +793,46 @@ void RPCConsole::disconnectSelectedNode()
}
}
+void RPCConsole::banSelectedNode(int bantime)
+{
+ if (!clientModel)
+ return;
+
+ // Get currently selected peer address
+ QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ // Find possible nodes, ban it and clear the selected node
+ if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ std::string nStr = strNode.toStdString();
+ std::string addr;
+ int port = 0;
+ SplitHostPort(nStr, port, addr);
+
+ CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
+ bannedNode->fDisconnect = true;
+ DumpBanlist();
+
+ clearSelectedNode();
+ clientModel->getBanTableModel()->refresh();
+ }
+}
+
+void RPCConsole::unbanSelectedNode()
+{
+ if (!clientModel)
+ return;
+
+ // Get currently selected ban address
+ QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address);
+ CSubNet possibleSubnet(strNode.toStdString());
+
+ if (possibleSubnet.IsValid())
+ {
+ CNode::Unban(possibleSubnet);
+ DumpBanlist();
+ clientModel->getBanTableModel()->refresh();
+ }
+}
+
void RPCConsole::clearSelectedNode()
{
ui->peerWidget->selectionModel()->clearSelection();
@@ -738,3 +840,13 @@ void RPCConsole::clearSelectedNode()
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}
+
+void RPCConsole::showOrHideBanTableIfRequired()
+{
+ if (!clientModel)
+ return;
+
+ bool visible = clientModel->getBanTableModel()->shouldShow();
+ ui->banlistWidget->setVisible(visible);
+ ui->banHeading->setVisible(visible);
+} \ No newline at end of file