From c6aa86afc2fe8995bcb1036c9879f85ef335e295 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 12 May 2012 12:30:07 +0200 Subject: Convert RPC console to QTextEdit instead of QTableView * This allows copy/pasting whole or partial messages * Handle output more consistently in console * No more scrollbars-in-scrollbars: by setting per-pixel scrolling on the table, cells can have any height * Decorations for "request" and "reply" are changed to the txin and txout icons instead of colored squares --- src/qt/forms/rpcconsole.ui | 22 +++----- src/qt/rpcconsole.cpp | 124 ++++++++++++++++++++------------------------- src/qt/rpcconsole.h | 5 +- 3 files changed, 62 insertions(+), 89 deletions(-) diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index e8f01ff2f5..cded274792 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -7,7 +7,7 @@ 0 0 706 - 382 + 446 @@ -327,30 +327,22 @@ 3 - + 0 100 - - false + + true - - QAbstractItemView::SelectRows + + false - + 2 - - false - - - false - - - diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 5a035888ed..0f78288542 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -19,6 +20,19 @@ const int CONSOLE_SCROLLBACK = 50; const int CONSOLE_HISTORY = 50; +const QSize ICON_SIZE(24, 24); + +const struct { + const char *url; + const char *source; +} ICON_MAPPING[] = { + {"cmd-request", ":/icons/tx_input"}, + {"cmd-reply", ":/icons/tx_output"}, + {"cmd-error", ":/icons/tx_output"}, + {"misc", ":/icons/tx_inout"}, + {NULL, NULL} +}; + /* Object for executing console RPC commands in a separate thread. */ class RPCExecutor: public QObject @@ -83,12 +97,9 @@ void RPCExecutor::request(const QString &command) RPCConsole::RPCConsole(QWidget *parent) : QDialog(parent), ui(new Ui::RPCConsole), - firstLayout(true), historyPtr(0) { ui->setupUi(this); - ui->messagesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch); - ui->messagesWidget->setContextMenuPolicy(Qt::ActionsContextMenu); #ifndef WIN32 // Show Debug logfile label and Open button only for Windows @@ -99,13 +110,6 @@ RPCConsole::RPCConsole(QWidget *parent) : // Install event filter for up and down arrow ui->lineEdit->installEventFilter(this); - // Add "Copy message" to context menu explicitly - QAction *copyMessageAction = new QAction(tr("&Copy"), this); - copyMessageAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C)); - copyMessageAction->setShortcutContext(Qt::WidgetShortcut); - connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage())); - ui->messagesWidget->addAction(copyMessageAction); - connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); connect(ui->openDebugLogfileButton, SIGNAL(clicked()), this, SLOT(on_openDebugLogfileButton_clicked())); @@ -159,68 +163,62 @@ void RPCConsole::setClientModel(ClientModel *model) } } -static QColor categoryColor(int category) +static QString categoryClass(int category) { switch(category) { - case RPCConsole::MC_ERROR: return QColor(255,0,0); break; - case RPCConsole::MC_DEBUG: return QColor(192,192,192); break; - case RPCConsole::CMD_REQUEST: return QColor(128,128,128); break; - case RPCConsole::CMD_REPLY: return QColor(128,255,128); break; - case RPCConsole::CMD_ERROR: return QColor(255,128,128); break; - default: return QColor(0,0,0); + 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"; } } void RPCConsole::clear() { ui->messagesWidget->clear(); - ui->messagesWidget->setRowCount(0); ui->lineEdit->clear(); ui->lineEdit->setFocus(); - message(CMD_REPLY, tr("Welcome to the bitcoin RPC console.")+"\n"+ - tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.")+"\n"+ - tr("Type \"help\" for an overview of available commands.")); + // Add smoothly scaled icon images. + // (when using width/height on an img, Qt uses nearest instead of linear interpolation) + for(int i=0; ICON_MAPPING[i].url; ++i) + { + ui->messagesWidget->document()->addResource( + QTextDocument::ImageResource, + QUrl(ICON_MAPPING[i].url), + QImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + + // Set default style sheet + ui->messagesWidget->document()->setDefaultStyleSheet( + "table { }" + "td.time { color: #808080; padding-top: 3px; } " + "td.message { font-family: Monospace; font-size: 12px; } " + "td.cmd-request { color: #006060; } " + "td.cmd-error { color: red; } " + "b { color: #006060; } " + ); + + message(CMD_REPLY, tr("Welcome to the Bitcoin RPC console.
" + "Use up and down arrows to navigate history, and Ctrl-L to clear screen.
" + "Type help for an overview of available commands."), true); } -void RPCConsole::message(int category, const QString &message) +void RPCConsole::message(int category, const QString &message, bool html) { - // Add row to messages widget - int row = ui->messagesWidget->rowCount(); - ui->messagesWidget->setRowCount(row+1); - QTime time = QTime::currentTime(); - QTableWidgetItem *newTime = new QTableWidgetItem(time.toString()); - newTime->setData(Qt::DecorationRole, categoryColor(category)); - newTime->setForeground(QColor(128,128,128)); - newTime->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable - - int numLines = message.count("\n") + 1; - // As Qt doesn't like very tall cells (they break scrolling) keep only short messages in - // the cell text, longer messages trigger a display widget with scroll bar - if(numLines < 5) - { - QTableWidgetItem *newItem = new QTableWidgetItem(message); - newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable - if(category == CMD_ERROR) // Coloring error messages in red - newItem->setForeground(QColor(255,16,16)); - ui->messagesWidget->setItem(row, 1, newItem); - } else { - QTextEdit *newWidget = new QTextEdit; - newWidget->setText(message); - newWidget->setMaximumHeight(100); - newWidget->setReadOnly(true); - ui->messagesWidget->setCellWidget(row, 1, newWidget); - } - - ui->messagesWidget->setItem(row, 0, newTime); - ui->messagesWidget->resizeRowToContents(row); - // Preserve only limited scrollback buffer - while(ui->messagesWidget->rowCount() > CONSOLE_SCROLLBACK) - ui->messagesWidget->removeRow(0); - // Scroll to bottom after table is updated - QTimer::singleShot(0, ui->messagesWidget, SLOT(scrollToBottom())); + QString timeString = time.toString(); + QString out; + out += ""; + out += ""; + out += "
" + timeString + ""; + if(html) + out += message; + else + out += GUIUtil::HtmlEscape(message, true); + out += "
"; + ui->messagesWidget->append(out); } void RPCConsole::setNumConnections(int count) @@ -298,24 +296,10 @@ void RPCConsole::startExecutor() thread->start(); } -void RPCConsole::copyMessage() -{ - GUIUtil::copyEntryData(ui->messagesWidget, 1, Qt::EditRole); -} - void RPCConsole::on_tabWidget_currentChanged(int index) { if(ui->tabWidget->widget(index) == ui->tab_console) { - if(firstLayout) - { - // Work around QTableWidget issue: - // Call resizeRowsToContents on first Layout request with widget visible, - // to make sure multiline messages that were added before the console was shown - // have the right height. - firstLayout = false; - ui->messagesWidget->resizeRowsToContents(); - } ui->lineEdit->setFocus(); } } diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 30948eaad2..9c4fab497e 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -37,15 +37,13 @@ private slots: public slots: void clear(); - void message(int category, const QString &message); + void message(int category, const QString &message, bool html = false); /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set number of blocks shown in the UI */ void setNumBlocks(int count); /** Go forward or back in history */ void browseHistory(int offset); - /** Copy currently selected message to clipboard */ - void copyMessage(); signals: // For RPC command executor @@ -55,7 +53,6 @@ signals: private: Ui::RPCConsole *ui; ClientModel *clientModel; - bool firstLayout; QStringList history; int historyPtr; -- cgit v1.2.3