2015-12-13 14:51:43 +01:00
|
|
|
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
2016-12-20 14:26:45 +01:00
|
|
|
// Copyright (c) 2014-2017 The Dash Core developers
|
2014-12-13 05:09:33 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2013-11-04 16:20:43 +01:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
#include "rpcconsole.h"
|
2015-08-18 19:24:10 +02:00
|
|
|
#include "ui_debugwindow.h"
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2015-06-23 21:10:42 +02:00
|
|
|
#include "bantablemodel.h"
|
2012-04-09 21:07:25 +02:00
|
|
|
#include "clientmodel.h"
|
|
|
|
#include "guiutil.h"
|
2015-07-28 15:20:14 +02:00
|
|
|
#include "platformstyle.h"
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2014-06-04 12:06:18 +02:00
|
|
|
#include "chainparams.h"
|
2017-07-03 15:13:34 +02:00
|
|
|
#include "rpc/server.h"
|
|
|
|
#include "rpc/client.h"
|
2014-06-03 14:42:20 +02:00
|
|
|
#include "util.h"
|
2013-04-13 07:13:08 +02:00
|
|
|
|
|
|
|
#include <openssl/crypto.h>
|
2014-09-05 13:18:35 +02:00
|
|
|
|
2015-09-04 16:11:34 +02:00
|
|
|
#include <univalue.h>
|
2014-08-20 21:15:16 +02:00
|
|
|
|
2014-06-05 07:00:16 +02:00
|
|
|
#ifdef ENABLE_WALLET
|
2014-06-04 22:00:59 +02:00
|
|
|
#include <db_cxx.h>
|
2014-06-05 07:00:16 +02:00
|
|
|
#endif
|
2014-06-04 22:00:59 +02:00
|
|
|
|
2015-10-25 20:54:46 +01:00
|
|
|
#include <QDir>
|
2012-04-09 21:07:25 +02:00
|
|
|
#include <QKeyEvent>
|
2015-06-01 15:32:25 +02:00
|
|
|
#include <QMenu>
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <QScrollBar>
|
2015-07-29 14:34:14 +02:00
|
|
|
#include <QSignalMapper>
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <QThread>
|
|
|
|
#include <QTime>
|
2015-08-28 16:46:20 +02:00
|
|
|
#include <QTimer>
|
2016-02-27 04:57:12 +01:00
|
|
|
#include <QStringList>
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2013-05-31 14:02:24 +02:00
|
|
|
#if QT_VERSION < 0x050000
|
2012-05-12 12:30:07 +02:00
|
|
|
#include <QUrl>
|
2013-05-31 14:02:24 +02:00
|
|
|
#endif
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2012-08-31 09:43:40 +02:00
|
|
|
// TODO: add a scrollback limit, as there is currently none
|
2012-04-09 21:07:25 +02:00
|
|
|
// TODO: make it possible to filter out categories (esp debug messages when implemented)
|
|
|
|
// TODO: receive errors and debug messages through ClientModel
|
|
|
|
|
|
|
|
const int CONSOLE_HISTORY = 50;
|
2012-05-12 12:30:07 +02:00
|
|
|
const QSize ICON_SIZE(24, 24);
|
|
|
|
|
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
|
|
|
const TrafficGraphData::GraphRange INITIAL_TRAFFIC_GRAPH_SETTING = TrafficGraphData::Range_30m;
|
2013-08-22 18:09:32 +02:00
|
|
|
|
2015-05-28 23:09:14 +02:00
|
|
|
// Repair parameters
|
|
|
|
const QString SALVAGEWALLET("-salvagewallet");
|
|
|
|
const QString RESCAN("-rescan");
|
|
|
|
const QString ZAPTXES1("-zapwallettxes=1");
|
|
|
|
const QString ZAPTXES2("-zapwallettxes=2");
|
|
|
|
const QString UPGRADEWALLET("-upgradewallet");
|
|
|
|
const QString REINDEX("-reindex");
|
|
|
|
|
2012-05-12 12:30:07 +02:00
|
|
|
const struct {
|
|
|
|
const char *url;
|
|
|
|
const char *source;
|
|
|
|
} ICON_MAPPING[] = {
|
2015-09-16 05:29:57 +02:00
|
|
|
{"cmd-request", "tx_input"},
|
|
|
|
{"cmd-reply", "tx_output"},
|
|
|
|
{"cmd-error", "tx_output"},
|
|
|
|
{"misc", "tx_inout"},
|
2012-05-12 12:30:07 +02:00
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
/* Object for executing console RPC commands in a separate thread.
|
|
|
|
*/
|
2013-01-23 21:51:02 +01:00
|
|
|
class RPCExecutor : public QObject
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
2013-01-23 21:51:02 +01:00
|
|
|
|
2015-07-14 13:59:05 +02:00
|
|
|
public Q_SLOTS:
|
2012-04-09 21:07:25 +02:00
|
|
|
void request(const QString &command);
|
2013-01-23 21:51:02 +01:00
|
|
|
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_SIGNALS:
|
2012-04-09 21:07:25 +02:00
|
|
|
void reply(int category, const QString &command);
|
|
|
|
};
|
|
|
|
|
2015-08-28 16:46:20 +02:00
|
|
|
/** Class for handling RPC timers
|
|
|
|
* (used for e.g. re-locking the wallet after a timeout)
|
|
|
|
*/
|
|
|
|
class QtRPCTimerBase: public QObject, public RPCTimerBase
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
QtRPCTimerBase(boost::function<void(void)>& func, int64_t millis):
|
|
|
|
func(func)
|
|
|
|
{
|
|
|
|
timer.setSingleShot(true);
|
|
|
|
connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
|
|
|
timer.start(millis);
|
|
|
|
}
|
|
|
|
~QtRPCTimerBase() {}
|
|
|
|
private Q_SLOTS:
|
|
|
|
void timeout() { func(); }
|
|
|
|
private:
|
|
|
|
QTimer timer;
|
|
|
|
boost::function<void(void)> func;
|
|
|
|
};
|
|
|
|
|
|
|
|
class QtRPCTimerInterface: public RPCTimerInterface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
~QtRPCTimerInterface() {}
|
|
|
|
const char *Name() { return "Qt"; }
|
|
|
|
RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
|
|
|
|
{
|
|
|
|
return new QtRPCTimerBase(func, millis);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
#include "rpcconsole.moc"
|
|
|
|
|
2012-08-30 21:42:18 +02:00
|
|
|
/**
|
|
|
|
* Split shell command line into a list of arguments. Aims to emulate \c bash and friends.
|
2012-08-30 21:42:18 +02:00
|
|
|
*
|
2012-08-30 21:42:18 +02:00
|
|
|
* - Arguments are delimited with whitespace
|
|
|
|
* - Extra whitespace at the beginning and end and between arguments will be ignored
|
2012-08-30 21:42:18 +02:00
|
|
|
* - Text can be "double" or 'single' quoted
|
|
|
|
* - The backslash \c \ is used as escape character
|
2012-08-30 21:42:18 +02:00
|
|
|
* - Outside quotes, any character can be escaped
|
2012-08-30 21:42:18 +02:00
|
|
|
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
|
|
|
|
* - Within single quotes, no escaping is possible and no special interpretation takes place
|
2012-08-30 21:42:18 +02:00
|
|
|
*
|
|
|
|
* @param[out] args Parsed arguments will be appended to this list
|
|
|
|
* @param[in] strCommand Command line to split
|
|
|
|
*/
|
|
|
|
bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2012-08-30 21:42:18 +02:00
|
|
|
enum CmdParseState
|
|
|
|
{
|
|
|
|
STATE_EATING_SPACES,
|
|
|
|
STATE_ARGUMENT,
|
|
|
|
STATE_SINGLEQUOTED,
|
|
|
|
STATE_DOUBLEQUOTED,
|
|
|
|
STATE_ESCAPE_OUTER,
|
|
|
|
STATE_ESCAPE_DOUBLEQUOTED
|
|
|
|
} state = STATE_EATING_SPACES;
|
|
|
|
std::string curarg;
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_FOREACH(char ch, strCommand)
|
2012-08-30 21:42:18 +02:00
|
|
|
{
|
|
|
|
switch(state)
|
2012-05-12 18:14:29 +02:00
|
|
|
{
|
2012-08-30 21:42:18 +02:00
|
|
|
case STATE_ARGUMENT: // In or after argument
|
|
|
|
case STATE_EATING_SPACES: // Handle runs of whitespace
|
2012-08-30 21:42:18 +02:00
|
|
|
switch(ch)
|
|
|
|
{
|
|
|
|
case '"': state = STATE_DOUBLEQUOTED; break;
|
|
|
|
case '\'': state = STATE_SINGLEQUOTED; break;
|
|
|
|
case '\\': state = STATE_ESCAPE_OUTER; break;
|
|
|
|
case ' ': case '\n': case '\t':
|
|
|
|
if(state == STATE_ARGUMENT) // Space ends argument
|
|
|
|
{
|
|
|
|
args.push_back(curarg);
|
|
|
|
curarg.clear();
|
|
|
|
}
|
|
|
|
state = STATE_EATING_SPACES;
|
|
|
|
break;
|
|
|
|
default: curarg += ch; state = STATE_ARGUMENT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_SINGLEQUOTED: // Single-quoted string
|
|
|
|
switch(ch)
|
|
|
|
{
|
|
|
|
case '\'': state = STATE_ARGUMENT; break;
|
|
|
|
default: curarg += ch;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_DOUBLEQUOTED: // Double-quoted string
|
|
|
|
switch(ch)
|
|
|
|
{
|
|
|
|
case '"': state = STATE_ARGUMENT; break;
|
|
|
|
case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
|
|
|
|
default: curarg += ch;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_ESCAPE_OUTER: // '\' outside quotes
|
|
|
|
curarg += ch; state = STATE_ARGUMENT;
|
|
|
|
break;
|
|
|
|
case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
|
2012-08-30 21:42:18 +02:00
|
|
|
if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
|
2012-08-30 21:42:18 +02:00
|
|
|
curarg += ch; state = STATE_DOUBLEQUOTED;
|
|
|
|
break;
|
2012-05-12 18:14:29 +02:00
|
|
|
}
|
|
|
|
}
|
2012-08-30 21:42:18 +02:00
|
|
|
switch(state) // final state
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2012-08-30 21:42:18 +02:00
|
|
|
case STATE_EATING_SPACES:
|
|
|
|
return true;
|
|
|
|
case STATE_ARGUMENT:
|
|
|
|
args.push_back(curarg);
|
|
|
|
return true;
|
|
|
|
default: // ERROR to end in one of the other states
|
|
|
|
return false;
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
2012-08-30 21:42:18 +02:00
|
|
|
}
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2012-08-30 21:42:18 +02:00
|
|
|
void RPCExecutor::request(const QString &command)
|
|
|
|
{
|
|
|
|
std::vector<std::string> args;
|
|
|
|
if(!parseCommandLine(args, command.toStdString()))
|
|
|
|
{
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
|
2012-08-30 21:42:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(args.empty())
|
|
|
|
return; // Nothing to do
|
2012-08-31 17:40:13 +02:00
|
|
|
try
|
|
|
|
{
|
2012-04-09 21:07:25 +02:00
|
|
|
std::string strPrint;
|
2012-08-30 21:42:18 +02:00
|
|
|
// Convert argument list to JSON objects in method-dependent way,
|
|
|
|
// and pass it along with the method name to the dispatcher.
|
2014-08-20 21:15:16 +02:00
|
|
|
UniValue result = tableRPC.execute(
|
2012-08-30 21:42:18 +02:00
|
|
|
args[0],
|
|
|
|
RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
|
2012-04-09 21:07:25 +02:00
|
|
|
|
|
|
|
// Format result reply
|
2014-08-20 21:15:16 +02:00
|
|
|
if (result.isNull())
|
2012-04-09 21:07:25 +02:00
|
|
|
strPrint = "";
|
2014-08-20 21:15:16 +02:00
|
|
|
else if (result.isStr())
|
2012-04-09 21:07:25 +02:00
|
|
|
strPrint = result.get_str();
|
|
|
|
else
|
2014-08-20 21:15:16 +02:00
|
|
|
strPrint = result.write(2);
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
2014-08-20 21:15:16 +02:00
|
|
|
catch (UniValue& objError)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2012-08-31 17:40:13 +02:00
|
|
|
try // Nice formatting for standard-format error
|
|
|
|
{
|
|
|
|
int code = find_value(objError, "code").get_int();
|
|
|
|
std::string message = find_value(objError, "message").get_str();
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
|
2012-08-31 17:40:13 +02:00
|
|
|
}
|
2014-12-07 13:29:06 +01:00
|
|
|
catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
|
2012-08-30 21:42:18 +02:00
|
|
|
{ // Show raw JSON object
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
|
2012-08-31 17:40:13 +02:00
|
|
|
}
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
2014-12-07 13:29:06 +01:00
|
|
|
catch (const std::exception& e)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-28 15:20:14 +02:00
|
|
|
RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
|
2014-11-10 16:41:57 +01:00
|
|
|
QWidget(parent),
|
2012-04-09 21:07:25 +02:00
|
|
|
ui(new Ui::RPCConsole),
|
2013-04-02 11:24:10 +02:00
|
|
|
clientModel(0),
|
2014-06-04 12:06:18 +02:00
|
|
|
historyPtr(0),
|
2015-06-01 15:32:25 +02:00
|
|
|
cachedNodeid(-1),
|
2015-07-29 14:34:14 +02:00
|
|
|
platformStyle(platformStyle),
|
2015-06-20 20:55:21 +02:00
|
|
|
peersTableContextMenu(0),
|
|
|
|
banTableContextMenu(0)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
2013-07-13 13:14:23 +02:00
|
|
|
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
|
2015-09-12 23:42:04 +02:00
|
|
|
QString theme = GUIUtil::getThemeName();
|
2015-07-28 15:20:14 +02:00
|
|
|
if (platformStyle->getImagesOnButtons()) {
|
2016-02-02 16:28:56 +01:00
|
|
|
ui->openDebugLogfileButton->setIcon(QIcon(":/icons/" + theme + "/export"));
|
2015-07-28 15:20:14 +02:00
|
|
|
}
|
2015-09-05 22:54:11 +02:00
|
|
|
// Needed on Mac also
|
2015-09-12 23:42:04 +02:00
|
|
|
ui->clearButton->setIcon(QIcon(":/icons/" + theme + "/remove"));
|
2015-09-05 22:54:11 +02:00
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
// Install event filter for up and down arrow
|
|
|
|
ui->lineEdit->installEventFilter(this);
|
2012-09-09 20:07:22 +02:00
|
|
|
ui->messagesWidget->installEventFilter(this);
|
2012-04-09 21:07:25 +02:00
|
|
|
|
|
|
|
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
2013-11-08 08:13:08 +01:00
|
|
|
connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear()));
|
2015-05-23 13:28:33 +02:00
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
// Wallet Repair Buttons
|
2017-03-15 00:56:09 +01:00
|
|
|
// connect(ui->btn_salvagewallet, SIGNAL(clicked()), this, SLOT(walletSalvage()));
|
|
|
|
// Disable salvage option in GUI, it's way too powerful and can lead to funds loss
|
|
|
|
ui->btn_salvagewallet->setEnabled(false);
|
2015-05-28 23:09:14 +02:00
|
|
|
connect(ui->btn_rescan, SIGNAL(clicked()), this, SLOT(walletRescan()));
|
|
|
|
connect(ui->btn_zapwallettxes1, SIGNAL(clicked()), this, SLOT(walletZaptxes1()));
|
|
|
|
connect(ui->btn_zapwallettxes2, SIGNAL(clicked()), this, SLOT(walletZaptxes2()));
|
|
|
|
connect(ui->btn_upgradewallet, SIGNAL(clicked()), this, SLOT(walletUpgrade()));
|
|
|
|
connect(ui->btn_reindex, SIGNAL(clicked()), this, SLOT(walletReindex()));
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2014-06-04 22:00:59 +02:00
|
|
|
// set library version labels
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0));
|
2015-10-25 20:54:46 +01:00
|
|
|
std::string walletPath = GetDataDir().string();
|
2015-10-25 21:45:08 +01:00
|
|
|
walletPath += QDir::separator().toLatin1() + GetArg("-wallet", "wallet.dat");
|
2015-10-25 21:28:18 +01:00
|
|
|
ui->wallet_path->setText(QString::fromStdString(walletPath));
|
2014-06-04 22:00:59 +02:00
|
|
|
#else
|
|
|
|
ui->label_berkeleyDBVersion->hide();
|
|
|
|
ui->berkeleyDBVersion->hide();
|
|
|
|
#endif
|
2015-08-28 16:46:20 +02:00
|
|
|
// Register RPC timer interface
|
|
|
|
rpcTimerInterface = new QtRPCTimerInterface();
|
|
|
|
RPCRegisterTimerInterface(rpcTimerInterface);
|
2012-06-14 19:18:30 +02:00
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
startExecutor();
|
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
|
|
|
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_SETTING);
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2014-06-04 12:06:18 +02:00
|
|
|
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
|
2012-04-09 21:07:25 +02:00
|
|
|
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
RPCConsole::~RPCConsole()
|
|
|
|
{
|
2013-07-13 13:14:23 +02:00
|
|
|
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT stopExecutor();
|
2015-08-28 16:46:20 +02:00
|
|
|
RPCUnregisterTimerInterface(rpcTimerInterface);
|
|
|
|
delete rpcTimerInterface;
|
2012-04-09 21:07:25 +02:00
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
|
|
|
|
{
|
2012-09-09 20:07:22 +02:00
|
|
|
if(event->type() == QEvent::KeyPress) // Special key handling
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2012-09-09 20:07:22 +02:00
|
|
|
QKeyEvent *keyevt = static_cast<QKeyEvent*>(event);
|
|
|
|
int key = keyevt->key();
|
|
|
|
Qt::KeyboardModifiers mod = keyevt->modifiers();
|
|
|
|
switch(key)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2012-09-09 20:07:22 +02:00
|
|
|
case Qt::Key_Up: if(obj == ui->lineEdit) { browseHistory(-1); return true; } break;
|
|
|
|
case Qt::Key_Down: if(obj == ui->lineEdit) { browseHistory(1); return true; } break;
|
|
|
|
case Qt::Key_PageUp: /* pass paging keys to messages widget */
|
|
|
|
case Qt::Key_PageDown:
|
|
|
|
if(obj == ui->lineEdit)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
2012-09-09 20:07:22 +02:00
|
|
|
QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
2016-05-31 06:56:58 +02:00
|
|
|
case Qt::Key_Return:
|
|
|
|
case Qt::Key_Enter:
|
|
|
|
// forward these events to lineEdit
|
|
|
|
if(obj == autoCompleter->popup()) {
|
|
|
|
QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
2012-09-09 20:07:22 +02:00
|
|
|
default:
|
|
|
|
// Typing in messages widget brings focus to line edit, and redirects key there
|
|
|
|
// Exclude most combinations and keys that emit no text, except paste shortcuts
|
|
|
|
if(obj == ui->messagesWidget && (
|
|
|
|
(!mod && !keyevt->text().isEmpty() && key != Qt::Key_Tab) ||
|
|
|
|
((mod & Qt::ControlModifier) && key == Qt::Key_V) ||
|
|
|
|
((mod & Qt::ShiftModifier) && key == Qt::Key_Insert)))
|
|
|
|
{
|
|
|
|
ui->lineEdit->setFocus();
|
|
|
|
QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
|
|
|
|
return true;
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-10 16:41:57 +01:00
|
|
|
return QWidget::eventFilter(obj, event);
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::setClientModel(ClientModel *model)
|
|
|
|
{
|
2013-08-22 18:09:32 +02:00
|
|
|
clientModel = model;
|
|
|
|
ui->trafficGraph->setClientModel(model);
|
2015-06-26 10:23:51 +02:00
|
|
|
if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) {
|
2013-06-03 14:10:14 +02:00
|
|
|
// Keep up to date with client
|
|
|
|
setNumConnections(model->getNumConnections());
|
2012-04-09 21:07:25 +02:00
|
|
|
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
2013-06-03 14:10:14 +02:00
|
|
|
|
2015-11-27 18:22:18 +01:00
|
|
|
setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL));
|
|
|
|
connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
|
2012-04-09 21:07:25 +02:00
|
|
|
|
2015-02-24 14:24:42 +01:00
|
|
|
setMasternodeCount(model->getMasternodeCountString());
|
|
|
|
connect(model, SIGNAL(strMasternodesChanged(QString)), this, SLOT(setMasternodeCount(QString)));
|
|
|
|
|
2013-08-22 18:09:32 +02:00
|
|
|
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
|
|
|
|
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
|
|
|
|
|
2015-11-09 11:45:07 +01:00
|
|
|
connect(model, SIGNAL(mempoolSizeChanged(long,size_t)), this, SLOT(setMempoolSize(long,size_t)));
|
|
|
|
|
2014-05-23 19:09:59 +02:00
|
|
|
// set up peer table
|
|
|
|
ui->peerWidget->setModel(model->getPeerTableModel());
|
|
|
|
ui->peerWidget->verticalHeader()->hide();
|
|
|
|
ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
|
|
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
2015-06-01 15:32:25 +02:00
|
|
|
ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
2014-05-23 19:09:59 +02:00
|
|
|
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
|
2014-06-04 12:06:18 +02:00
|
|
|
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
|
|
|
|
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
|
2015-06-20 21:48:10 +02:00
|
|
|
ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
|
2015-06-20 20:27:03 +02:00
|
|
|
|
2015-06-26 14:55:52 +02:00
|
|
|
// create peer table context menu actions
|
|
|
|
QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
|
2015-07-03 08:55:22 +02:00
|
|
|
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);
|
2015-06-26 14:55:52 +02:00
|
|
|
|
|
|
|
// create peer table context menu
|
2015-06-20 20:55:21 +02:00
|
|
|
peersTableContextMenu = new QMenu();
|
|
|
|
peersTableContextMenu->addAction(disconnectAction);
|
|
|
|
peersTableContextMenu->addAction(banAction1h);
|
|
|
|
peersTableContextMenu->addAction(banAction24h);
|
|
|
|
peersTableContextMenu->addAction(banAction7d);
|
|
|
|
peersTableContextMenu->addAction(banAction365d);
|
2015-06-01 15:32:25 +02:00
|
|
|
|
2015-06-23 21:10:42 +02:00
|
|
|
// 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.
|
2015-06-19 13:24:34 +02:00
|
|
|
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()));
|
2015-06-23 21:10:42 +02:00
|
|
|
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(banSelectedNode(int)));
|
2015-06-19 13:24:34 +02:00
|
|
|
|
2015-06-26 14:55:52 +02:00
|
|
|
// peer table context menu signals
|
|
|
|
connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPeersTableContextMenu(const QPoint&)));
|
|
|
|
connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode()));
|
|
|
|
|
|
|
|
// peer table signal handling - update peer details when selecting new node
|
2014-06-04 12:06:18 +02:00
|
|
|
connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
|
2015-06-26 14:55:52 +02:00
|
|
|
this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
|
|
|
|
// peer table signal handling - update peer details when new nodes are added to the model
|
2014-05-23 19:09:59 +02:00
|
|
|
connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged()));
|
|
|
|
|
2015-06-20 20:55:21 +02:00
|
|
|
// 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);
|
2015-06-26 14:55:52 +02:00
|
|
|
ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH);
|
|
|
|
ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
|
2015-06-20 21:48:10 +02:00
|
|
|
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
|
2015-06-20 20:55:21 +02:00
|
|
|
|
2015-06-26 10:23:51 +02:00
|
|
|
// create ban table context menu action
|
2015-06-23 21:10:42 +02:00
|
|
|
QAction* unbanAction = new QAction(tr("&Unban Node"), this);
|
2015-06-26 10:23:51 +02:00
|
|
|
|
|
|
|
// create ban table context menu
|
2015-06-20 20:55:21 +02:00
|
|
|
banTableContextMenu = new QMenu();
|
|
|
|
banTableContextMenu->addAction(unbanAction);
|
|
|
|
|
2015-06-26 10:23:51 +02:00
|
|
|
// ban table context menu signals
|
2015-06-20 20:55:21 +02:00
|
|
|
connect(ui->banlistWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showBanTableContextMenu(const QPoint&)));
|
|
|
|
connect(unbanAction, SIGNAL(triggered()), this, SLOT(unbanSelectedNode()));
|
|
|
|
|
2015-06-26 10:23:51 +02:00
|
|
|
// 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();
|
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
// Provide initial values
|
|
|
|
ui->clientVersion->setText(model->formatFullVersion());
|
2015-08-06 15:40:50 +02:00
|
|
|
ui->clientUserAgent->setText(model->formatSubVersion());
|
2012-04-09 21:07:25 +02:00
|
|
|
ui->clientName->setText(model->clientName());
|
|
|
|
ui->buildDate->setText(model->formatBuildDate());
|
2012-05-21 23:05:54 +02:00
|
|
|
ui->startupTime->setText(model->formatClientStartupTime());
|
2014-06-11 12:23:49 +02:00
|
|
|
ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
|
2016-02-27 04:57:12 +01:00
|
|
|
|
|
|
|
//Setup autocomplete and attach it
|
|
|
|
QStringList wordList;
|
|
|
|
std::vector<std::string> commandList = tableRPC.listCommands();
|
|
|
|
for (size_t i = 0; i < commandList.size(); ++i)
|
|
|
|
{
|
|
|
|
wordList << commandList[i].c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
autoCompleter = new QCompleter(wordList, this);
|
|
|
|
ui->lineEdit->setCompleter(autoCompleter);
|
2016-05-31 06:56:58 +02:00
|
|
|
autoCompleter->popup()->installEventFilter(this);
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 12:30:07 +02:00
|
|
|
static QString categoryClass(int category)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
|
|
|
switch(category)
|
|
|
|
{
|
2012-05-12 12:30:07 +02:00
|
|
|
case RPCConsole::CMD_REQUEST: return "cmd-request"; break;
|
|
|
|
case RPCConsole::CMD_REPLY: return "cmd-reply"; break;
|
|
|
|
case RPCConsole::CMD_ERROR: return "cmd-error"; break;
|
|
|
|
default: return "misc";
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Restart wallet with "-salvagewallet" */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::walletSalvage()
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-28 23:09:14 +02:00
|
|
|
buildParameterlist(SALVAGEWALLET);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Restart wallet with "-rescan" */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::walletRescan()
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-28 23:09:14 +02:00
|
|
|
buildParameterlist(RESCAN);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Restart wallet with "-zapwallettxes=1" */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::walletZaptxes1()
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-28 23:09:14 +02:00
|
|
|
buildParameterlist(ZAPTXES1);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Restart wallet with "-zapwallettxes=2" */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::walletZaptxes2()
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-28 23:09:14 +02:00
|
|
|
buildParameterlist(ZAPTXES2);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Restart wallet with "-upgradewallet" */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::walletUpgrade()
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-28 23:09:14 +02:00
|
|
|
buildParameterlist(UPGRADEWALLET);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Restart wallet with "-reindex" */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::walletReindex()
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-28 23:09:14 +02:00
|
|
|
buildParameterlist(REINDEX);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
/** Build command-line parameter list for restart */
|
2015-05-28 23:09:14 +02:00
|
|
|
void RPCConsole::buildParameterlist(QString arg)
|
2015-05-23 13:28:33 +02:00
|
|
|
{
|
2015-05-25 18:29:11 +02:00
|
|
|
// Get command-line arguments and remove the application name
|
|
|
|
QStringList args = QApplication::arguments();
|
|
|
|
args.removeFirst();
|
2015-05-28 23:09:14 +02:00
|
|
|
|
|
|
|
// Remove existing repair-options
|
|
|
|
args.removeAll(SALVAGEWALLET);
|
|
|
|
args.removeAll(RESCAN);
|
|
|
|
args.removeAll(ZAPTXES1);
|
|
|
|
args.removeAll(ZAPTXES2);
|
|
|
|
args.removeAll(UPGRADEWALLET);
|
|
|
|
args.removeAll(REINDEX);
|
|
|
|
|
2015-05-28 23:14:09 +02:00
|
|
|
// Append repair parameter to command line.
|
2015-05-25 18:29:11 +02:00
|
|
|
args.append(arg);
|
2015-05-28 23:09:14 +02:00
|
|
|
|
2015-05-25 18:29:11 +02:00
|
|
|
// Send command-line arguments to BitcoinGUI::handleRestart()
|
2016-02-02 16:28:56 +01:00
|
|
|
Q_EMIT handleRestart(args);
|
2015-05-23 13:28:33 +02:00
|
|
|
}
|
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
void RPCConsole::clear()
|
|
|
|
{
|
|
|
|
ui->messagesWidget->clear();
|
2012-08-31 09:43:40 +02:00
|
|
|
history.clear();
|
|
|
|
historyPtr = 0;
|
2012-04-09 21:07:25 +02:00
|
|
|
ui->lineEdit->clear();
|
|
|
|
ui->lineEdit->setFocus();
|
|
|
|
|
2012-05-12 12:30:07 +02:00
|
|
|
// Add smoothly scaled icon images.
|
|
|
|
// (when using width/height on an img, Qt uses nearest instead of linear interpolation)
|
2015-09-16 05:29:57 +02:00
|
|
|
QString iconPath = ":/icons/" + GUIUtil::getThemeName() + "/";
|
|
|
|
QString iconName = "";
|
|
|
|
|
2012-05-12 12:30:07 +02:00
|
|
|
for(int i=0; ICON_MAPPING[i].url; ++i)
|
|
|
|
{
|
2015-09-16 05:29:57 +02:00
|
|
|
iconName = ICON_MAPPING[i].source;
|
2012-05-12 12:30:07 +02:00
|
|
|
ui->messagesWidget->document()->addResource(
|
|
|
|
QTextDocument::ImageResource,
|
|
|
|
QUrl(ICON_MAPPING[i].url),
|
2015-09-16 05:29:57 +02:00
|
|
|
QImage(iconPath + iconName).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
2012-05-12 12:30:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set default style sheet
|
2015-10-22 13:33:58 +02:00
|
|
|
QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
|
2015-11-03 11:58:04 +01:00
|
|
|
// Try to make fixed font adequately large on different OS
|
2016-01-17 17:55:53 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
QString ptSize = QString("%1pt").arg(QFontInfo(QFont()).pointSize() * 10 / 8);
|
|
|
|
#else
|
2015-11-03 11:58:04 +01:00
|
|
|
QString ptSize = QString("%1pt").arg(QFontInfo(QFont()).pointSize() * 8.5 / 9);
|
2016-01-17 17:55:53 +01:00
|
|
|
#endif
|
2012-05-12 12:30:07 +02:00
|
|
|
ui->messagesWidget->document()->setDefaultStyleSheet(
|
2015-10-22 13:33:58 +02:00
|
|
|
QString(
|
2012-05-12 12:30:07 +02:00
|
|
|
"table { }"
|
|
|
|
"td.time { color: #808080; padding-top: 3px; } "
|
2015-10-22 13:33:58 +02:00
|
|
|
"td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
|
2012-05-12 12:30:07 +02:00
|
|
|
"td.cmd-request { color: #006060; } "
|
|
|
|
"td.cmd-error { color: red; } "
|
|
|
|
"b { color: #006060; } "
|
2015-10-22 13:33:58 +02:00
|
|
|
).arg(fixedFontInfo.family(), ptSize)
|
|
|
|
);
|
2012-05-12 12:30:07 +02:00
|
|
|
|
2016-02-02 16:28:56 +01:00
|
|
|
message(CMD_REPLY, (tr("Welcome to the Dash Core RPC console.") + "<br>" +
|
2012-05-16 15:34:29 +02:00
|
|
|
tr("Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.") + "<br>" +
|
|
|
|
tr("Type <b>help</b> for an overview of available commands.")), true);
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
|
2014-11-10 16:41:57 +01:00
|
|
|
void RPCConsole::keyPressEvent(QKeyEvent *event)
|
2014-03-18 14:51:28 +01:00
|
|
|
{
|
2014-11-10 16:41:57 +01:00
|
|
|
if(windowType() != Qt::Widget && event->key() == Qt::Key_Escape)
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
2014-03-18 14:51:28 +01:00
|
|
|
}
|
|
|
|
|
2012-05-12 12:30:07 +02:00
|
|
|
void RPCConsole::message(int category, const QString &message, bool html)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
|
|
|
QTime time = QTime::currentTime();
|
2012-05-12 12:30:07 +02:00
|
|
|
QString timeString = time.toString();
|
|
|
|
QString out;
|
|
|
|
out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
|
|
|
|
out += "<td class=\"icon\" width=\"32\"><img src=\"" + categoryClass(category) + "\"></td>";
|
|
|
|
out += "<td class=\"message " + categoryClass(category) + "\" valign=\"middle\">";
|
|
|
|
if(html)
|
|
|
|
out += message;
|
|
|
|
else
|
2015-10-22 13:33:58 +02:00
|
|
|
out += GUIUtil::HtmlEscape(message, false);
|
2012-05-12 12:30:07 +02:00
|
|
|
out += "</td></tr></table>";
|
|
|
|
ui->messagesWidget->append(out);
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::setNumConnections(int count)
|
|
|
|
{
|
2014-02-16 19:48:27 +01:00
|
|
|
if (!clientModel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString connections = QString::number(count) + " (";
|
|
|
|
connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / ";
|
|
|
|
connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")";
|
|
|
|
|
|
|
|
ui->numberOfConnections->setText(connections);
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
|
2015-11-27 18:22:18 +01:00
|
|
|
void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
|
2012-04-09 21:07:25 +02:00
|
|
|
{
|
|
|
|
ui->numberOfBlocks->setText(QString::number(count));
|
2015-02-09 11:19:01 +01:00
|
|
|
ui->lastBlockTime->setText(blockDate.toString());
|
2015-02-24 14:24:42 +01:00
|
|
|
}
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2015-02-24 14:24:42 +01:00
|
|
|
void RPCConsole::setMasternodeCount(const QString &strMasternodes)
|
|
|
|
{
|
|
|
|
ui->masternodeCount->setText(strMasternodes);
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
|
2015-11-09 11:45:07 +01:00
|
|
|
void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
|
|
|
|
{
|
|
|
|
ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));
|
|
|
|
|
|
|
|
if (dynUsage < 1000000)
|
|
|
|
ui->mempoolSize->setText(QString::number(dynUsage/1000.0, 'f', 2) + " KB");
|
|
|
|
else
|
|
|
|
ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB");
|
|
|
|
}
|
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
void RPCConsole::on_lineEdit_returnPressed()
|
|
|
|
{
|
|
|
|
QString cmd = ui->lineEdit->text();
|
|
|
|
ui->lineEdit->clear();
|
|
|
|
|
|
|
|
if(!cmd.isEmpty())
|
|
|
|
{
|
|
|
|
message(CMD_REQUEST, cmd);
|
2015-07-14 13:59:05 +02:00
|
|
|
Q_EMIT cmdRequest(cmd);
|
2015-03-25 10:16:46 +01:00
|
|
|
// Remove command, if already in history
|
|
|
|
history.removeOne(cmd);
|
2012-04-09 21:07:25 +02:00
|
|
|
// Append command to history
|
|
|
|
history.append(cmd);
|
|
|
|
// Enforce maximum history size
|
|
|
|
while(history.size() > CONSOLE_HISTORY)
|
|
|
|
history.removeFirst();
|
|
|
|
// Set pointer to end of history
|
|
|
|
historyPtr = history.size();
|
2012-05-14 18:17:12 +02:00
|
|
|
// Scroll console view to end
|
|
|
|
scrollToEnd();
|
2012-04-09 21:07:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::browseHistory(int offset)
|
|
|
|
{
|
|
|
|
historyPtr += offset;
|
|
|
|
if(historyPtr < 0)
|
|
|
|
historyPtr = 0;
|
|
|
|
if(historyPtr > history.size())
|
|
|
|
historyPtr = history.size();
|
|
|
|
QString cmd;
|
|
|
|
if(historyPtr < history.size())
|
|
|
|
cmd = history.at(historyPtr);
|
|
|
|
ui->lineEdit->setText(cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::startExecutor()
|
|
|
|
{
|
2013-04-02 11:24:10 +02:00
|
|
|
QThread *thread = new QThread;
|
2012-04-09 21:07:25 +02:00
|
|
|
RPCExecutor *executor = new RPCExecutor();
|
|
|
|
executor->moveToThread(thread);
|
|
|
|
|
|
|
|
// Replies from executor object must go to this object
|
|
|
|
connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
|
|
|
|
// Requests from this object must go to executor
|
|
|
|
connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
|
2013-04-02 11:24:10 +02:00
|
|
|
|
2012-04-09 21:07:25 +02:00
|
|
|
// On stopExecutor signal
|
|
|
|
// - queue executor for deletion (in execution thread)
|
|
|
|
// - quit the Qt event loop in the execution thread
|
|
|
|
connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
|
|
|
|
connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
|
|
|
|
// Queue the thread for deletion (in this thread) when it is finished
|
|
|
|
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
|
|
|
|
|
|
|
// Default implementation of QThread::run() simply spins up an event loop in the thread,
|
|
|
|
// which is what we want.
|
|
|
|
thread->start();
|
|
|
|
}
|
|
|
|
|
2012-05-09 17:12:05 +02:00
|
|
|
void RPCConsole::on_tabWidget_currentChanged(int index)
|
|
|
|
{
|
2015-06-06 10:38:15 +02:00
|
|
|
if (ui->tabWidget->widget(index) == ui->tab_console)
|
2012-05-09 17:12:05 +02:00
|
|
|
ui->lineEdit->setFocus();
|
2015-06-06 10:38:15 +02:00
|
|
|
else if (ui->tabWidget->widget(index) != ui->tab_peers)
|
|
|
|
clearSelectedNode();
|
2012-05-09 17:12:05 +02:00
|
|
|
}
|
2012-05-09 22:07:00 +02:00
|
|
|
|
|
|
|
void RPCConsole::on_openDebugLogfileButton_clicked()
|
|
|
|
{
|
|
|
|
GUIUtil::openDebugLogfile();
|
|
|
|
}
|
2012-05-14 18:17:12 +02:00
|
|
|
|
|
|
|
void RPCConsole::scrollToEnd()
|
|
|
|
{
|
|
|
|
QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
|
|
|
|
scrollbar->setValue(scrollbar->maximum());
|
|
|
|
}
|
2012-05-20 15:49:17 +02:00
|
|
|
|
2013-08-22 18:09:32 +02:00
|
|
|
void RPCConsole::on_sldGraphRange_valueChanged(int value)
|
|
|
|
{
|
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
|
|
|
setTrafficGraphRange(static_cast<TrafficGraphData::GraphRange>(value));
|
2013-08-22 18:09:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString RPCConsole::FormatBytes(quint64 bytes)
|
|
|
|
{
|
|
|
|
if(bytes < 1024)
|
|
|
|
return QString(tr("%1 B")).arg(bytes);
|
|
|
|
if(bytes < 1024 * 1024)
|
|
|
|
return QString(tr("%1 KB")).arg(bytes / 1024);
|
|
|
|
if(bytes < 1024 * 1024 * 1024)
|
|
|
|
return QString(tr("%1 MB")).arg(bytes / 1024 / 1024);
|
|
|
|
|
|
|
|
return QString(tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
|
|
|
|
}
|
|
|
|
|
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
|
|
|
void RPCConsole::setTrafficGraphRange(TrafficGraphData::GraphRange range)
|
2013-08-22 18:09:32 +02:00
|
|
|
{
|
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
|
|
|
ui->trafficGraph->setGraphRangeMins(range);
|
|
|
|
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(TrafficGraphData::RangeMinutes[range] * 60));
|
2013-08-22 18:09:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
|
|
|
|
{
|
|
|
|
ui->lblBytesIn->setText(FormatBytes(totalBytesIn));
|
|
|
|
ui->lblBytesOut->setText(FormatBytes(totalBytesOut));
|
|
|
|
}
|
2015-01-16 10:55:24 +01:00
|
|
|
|
2014-05-23 19:09:59 +02:00
|
|
|
void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
|
|
|
|
{
|
2014-06-03 14:42:20 +02:00
|
|
|
Q_UNUSED(deselected);
|
|
|
|
|
2015-06-26 14:55:52 +02:00
|
|
|
if (!clientModel || !clientModel->getPeerTableModel() || selected.indexes().isEmpty())
|
2014-05-23 19:09:59 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row());
|
|
|
|
if (stats)
|
|
|
|
updateNodeDetail(stats);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::peerLayoutChanged()
|
|
|
|
{
|
2015-06-26 14:55:52 +02:00
|
|
|
if (!clientModel || !clientModel->getPeerTableModel())
|
2014-06-04 12:06:18 +02:00
|
|
|
return;
|
|
|
|
|
2014-05-23 19:09:59 +02:00
|
|
|
const CNodeCombinedStats *stats = NULL;
|
2014-06-04 12:06:18 +02:00
|
|
|
bool fUnselect = false;
|
|
|
|
bool fReselect = false;
|
2014-05-23 19:09:59 +02:00
|
|
|
|
2014-06-04 12:06:18 +02:00
|
|
|
if (cachedNodeid == -1) // no node selected yet
|
2014-05-23 19:09:59 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
// find the currently selected row
|
2015-06-06 10:38:15 +02:00
|
|
|
int selectedRow = -1;
|
2014-05-23 19:09:59 +02:00
|
|
|
QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
|
2015-06-06 10:38:15 +02:00
|
|
|
if (!selectedModelIndex.isEmpty()) {
|
2014-05-23 19:09:59 +02:00
|
|
|
selectedRow = selectedModelIndex.first().row();
|
2015-06-06 10:38:15 +02:00
|
|
|
}
|
2014-05-23 19:09:59 +02:00
|
|
|
|
|
|
|
// check if our detail node has a row in the table (it may not necessarily
|
|
|
|
// be at selectedRow since its position can change after a layout change)
|
2014-06-04 12:06:18 +02:00
|
|
|
int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeid);
|
2014-05-23 19:09:59 +02:00
|
|
|
|
|
|
|
if (detailNodeRow < 0)
|
|
|
|
{
|
2015-08-09 01:17:27 +02:00
|
|
|
// detail node disappeared from table (node disconnected)
|
2014-05-23 19:09:59 +02:00
|
|
|
fUnselect = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (detailNodeRow != selectedRow)
|
|
|
|
{
|
|
|
|
// detail node moved position
|
|
|
|
fUnselect = true;
|
|
|
|
fReselect = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get fresh stats on the detail node.
|
|
|
|
stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
|
|
|
|
}
|
|
|
|
|
2015-06-06 10:38:15 +02:00
|
|
|
if (fUnselect && selectedRow >= 0) {
|
|
|
|
clearSelectedNode();
|
2014-05-23 19:09:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fReselect)
|
|
|
|
{
|
|
|
|
ui->peerWidget->selectRow(detailNodeRow);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stats)
|
|
|
|
updateNodeDetail(stats);
|
|
|
|
}
|
|
|
|
|
2014-06-04 12:06:18 +02:00
|
|
|
void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
|
2014-05-23 19:09:59 +02:00
|
|
|
{
|
2014-06-04 12:06:18 +02:00
|
|
|
// Update cached nodeid
|
|
|
|
cachedNodeid = stats->nodeStats.nodeid;
|
2014-05-23 19:09:59 +02:00
|
|
|
|
|
|
|
// update the detail ui with latest node information
|
2015-06-01 09:09:51 +02:00
|
|
|
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
|
|
|
|
peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
|
2014-06-04 12:06:18 +02:00
|
|
|
if (!stats->nodeStats.addrLocal.empty())
|
|
|
|
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
|
|
|
|
ui->peerHeading->setText(peerAddrDetails);
|
|
|
|
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
|
|
|
|
ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastSend) : tr("never"));
|
|
|
|
ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nLastRecv) : tr("never"));
|
|
|
|
ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes));
|
|
|
|
ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
|
|
|
|
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected));
|
|
|
|
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
|
2015-06-01 09:09:51 +02:00
|
|
|
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
|
2014-12-15 11:07:55 +01:00
|
|
|
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
|
2015-06-01 09:09:51 +02:00
|
|
|
ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
|
2014-06-04 12:06:18 +02:00
|
|
|
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
|
|
|
|
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
|
2015-06-01 09:09:51 +02:00
|
|
|
ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
|
|
|
|
ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No"));
|
2014-06-04 12:06:18 +02:00
|
|
|
|
|
|
|
// This check fails for example if the lock was busy and
|
|
|
|
// nodeStateStats couldn't be fetched.
|
|
|
|
if (stats->fNodeStateStatsAvailable) {
|
|
|
|
// Ban score is init to 0
|
|
|
|
ui->peerBanScore->setText(QString("%1").arg(stats->nodeStateStats.nMisbehavior));
|
|
|
|
|
|
|
|
// Sync height is init to -1
|
|
|
|
if (stats->nodeStateStats.nSyncHeight > -1)
|
|
|
|
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
|
|
|
|
else
|
|
|
|
ui->peerSyncHeight->setText(tr("Unknown"));
|
2015-06-01 09:09:51 +02:00
|
|
|
|
|
|
|
// Common height is init to -1
|
|
|
|
if (stats->nodeStateStats.nCommonHeight > -1)
|
|
|
|
ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
|
|
|
|
else
|
|
|
|
ui->peerCommonHeight->setText(tr("Unknown"));
|
2014-06-04 12:06:18 +02:00
|
|
|
}
|
2014-07-13 06:27:29 +02:00
|
|
|
|
2014-06-04 12:06:18 +02:00
|
|
|
ui->detailWidget->show();
|
2014-07-13 06:27:29 +02:00
|
|
|
}
|
|
|
|
|
2014-05-23 19:09:59 +02:00
|
|
|
void RPCConsole::resizeEvent(QResizeEvent *event)
|
|
|
|
{
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::showEvent(QShowEvent *event)
|
|
|
|
{
|
|
|
|
QWidget::showEvent(event);
|
|
|
|
|
2015-06-26 14:55:52 +02:00
|
|
|
if (!clientModel || !clientModel->getPeerTableModel())
|
2014-06-04 12:06:18 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
// start PeerTableModel auto refresh
|
|
|
|
clientModel->getPeerTableModel()->startAutoRefresh();
|
2014-05-23 19:09:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::hideEvent(QHideEvent *event)
|
|
|
|
{
|
|
|
|
QWidget::hideEvent(event);
|
|
|
|
|
2015-06-26 14:55:52 +02:00
|
|
|
if (!clientModel || !clientModel->getPeerTableModel())
|
2014-07-13 06:27:29 +02:00
|
|
|
return;
|
|
|
|
|
2014-05-23 19:09:59 +02:00
|
|
|
// stop PeerTableModel auto refresh
|
|
|
|
clientModel->getPeerTableModel()->stopAutoRefresh();
|
|
|
|
}
|
2015-04-11 06:14:18 +02:00
|
|
|
|
2015-06-20 20:55:21 +02:00
|
|
|
void RPCConsole::showPeersTableContextMenu(const QPoint& point)
|
2015-06-01 15:32:25 +02:00
|
|
|
{
|
|
|
|
QModelIndex index = ui->peerWidget->indexAt(point);
|
|
|
|
if (index.isValid())
|
2015-06-20 20:55:21 +02:00
|
|
|
peersTableContextMenu->exec(QCursor::pos());
|
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::showBanTableContextMenu(const QPoint& point)
|
|
|
|
{
|
|
|
|
QModelIndex index = ui->banlistWidget->indexAt(point);
|
|
|
|
if (index.isValid())
|
|
|
|
banTableContextMenu->exec(QCursor::pos());
|
2015-06-01 15:32:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RPCConsole::disconnectSelectedNode()
|
|
|
|
{
|
|
|
|
// Get currently selected peer address
|
|
|
|
QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
|
|
|
|
// Find the node, disconnect it and clear the selected node
|
|
|
|
if (CNode *bannedNode = FindNode(strNode.toStdString())) {
|
2015-06-19 16:32:22 +02:00
|
|
|
bannedNode->fDisconnect = true;
|
2015-06-06 10:38:15 +02:00
|
|
|
clearSelectedNode();
|
2015-06-01 15:32:25 +02:00
|
|
|
}
|
|
|
|
}
|
2015-06-06 10:38:15 +02:00
|
|
|
|
2015-06-19 13:24:34 +02:00
|
|
|
void RPCConsole::banSelectedNode(int bantime)
|
|
|
|
{
|
2015-06-26 10:23:51 +02:00
|
|
|
if (!clientModel)
|
|
|
|
return;
|
|
|
|
|
2015-06-19 13:24:34 +02:00
|
|
|
// 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);
|
|
|
|
|
2015-07-03 08:35:14 +02:00
|
|
|
CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
|
2015-06-21 10:44:48 +02:00
|
|
|
bannedNode->fDisconnect = true;
|
2015-09-20 10:42:35 +02:00
|
|
|
DumpBanlist();
|
2015-06-21 10:44:48 +02:00
|
|
|
|
2015-06-19 13:24:34 +02:00
|
|
|
clearSelectedNode();
|
2015-06-26 10:23:51 +02:00
|
|
|
clientModel->getBanTableModel()->refresh();
|
2015-06-19 13:24:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-20 20:55:21 +02:00
|
|
|
void RPCConsole::unbanSelectedNode()
|
|
|
|
{
|
2015-06-26 10:23:51 +02:00
|
|
|
if (!clientModel)
|
|
|
|
return;
|
|
|
|
|
2015-06-20 21:48:10 +02:00
|
|
|
// Get currently selected ban address
|
2015-06-20 20:55:21 +02:00
|
|
|
QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address);
|
|
|
|
CSubNet possibleSubnet(strNode.toStdString());
|
|
|
|
|
|
|
|
if (possibleSubnet.IsValid())
|
|
|
|
{
|
|
|
|
CNode::Unban(possibleSubnet);
|
2015-09-20 10:42:35 +02:00
|
|
|
DumpBanlist();
|
2015-06-26 10:23:51 +02:00
|
|
|
clientModel->getBanTableModel()->refresh();
|
2015-06-20 20:55:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-06 10:38:15 +02:00
|
|
|
void RPCConsole::clearSelectedNode()
|
|
|
|
{
|
|
|
|
ui->peerWidget->selectionModel()->clearSelection();
|
|
|
|
cachedNodeid = -1;
|
|
|
|
ui->detailWidget->hide();
|
|
|
|
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
|
|
|
|
}
|
2015-06-20 21:48:10 +02:00
|
|
|
|
|
|
|
void RPCConsole::showOrHideBanTableIfRequired()
|
|
|
|
{
|
2015-06-21 10:44:48 +02:00
|
|
|
if (!clientModel)
|
|
|
|
return;
|
2015-06-23 21:10:42 +02:00
|
|
|
|
2015-06-20 21:48:10 +02:00
|
|
|
bool visible = clientModel->getBanTableModel()->shouldShow();
|
|
|
|
ui->banlistWidget->setVisible(visible);
|
|
|
|
ui->banHeading->setVisible(visible);
|
2015-10-22 13:33:58 +02:00
|
|
|
}
|
2015-11-12 12:59:26 +01:00
|
|
|
|
|
|
|
void RPCConsole::setTabFocus(enum TabTypes tabType)
|
|
|
|
{
|
|
|
|
ui->tabWidget->setCurrentIndex(tabType);
|
|
|
|
}
|