From ad204df1a9077327ab1142fbc9bf41369c1a73d1 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sat, 20 Jun 2015 20:27:03 +0200 Subject: [PATCH] [Qt] add banlist table below peers table --- src/Makefile.qt.include | 3 + src/qt/bantablemodel.cpp | 192 +++++++++++++++++++++++++++++++++++++ src/qt/bantablemodel.h | 66 +++++++++++++ src/qt/clientmodel.cpp | 13 +++ src/qt/clientmodel.h | 4 + src/qt/forms/rpcconsole.ui | 94 ++++++++++++++++-- src/qt/rpcconsole.cpp | 13 +++ 7 files changed, 375 insertions(+), 10 deletions(-) create mode 100644 src/qt/bantablemodel.cpp create mode 100644 src/qt/bantablemodel.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 3e8eda178..480bd9dc8 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 000000000..3b71769ef --- /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 +#include +#include + +#include +#include + +// private implementation +class BanTablePriv +{ +public: + /** Local cache of peer information */ + QList 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 banMap; + CNode::GetBanned(banMap); + + cachedBanlist.clear(); +#if QT_VERSION >= 0x040700 + cachedBanlist.reserve(banMap.size()); +#endif + std::map::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(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::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 000000000..ef7a26e3c --- /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 +#include + +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 97d671156..62c35130f 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 ca2da3dde..627bdf862 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -9,6 +9,7 @@ #include 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 e8d9a958a..39230aee6 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -713,17 +713,91 @@ - - - Qt::ScrollBarAsNeeded + + + 0 - - true - - - false - - + + + + Qt::ScrollBarAsNeeded + + + true + + + false + + + + + + + + 0 + 0 + + + + + 300 + 32 + + + + + 16777215 + 32 + + + + + 14 + + + + IBeamCursor + + + Banned peers + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Qt::ScrollBarAsNeeded + + + true + + + false + + + + diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 2a94312be..c6e70697f 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(); } }