diff options
Diffstat (limited to 'src/qt/rpcconsole.cpp')
-rw-r--r-- | src/qt/rpcconsole.cpp | 152 |
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 |