Skip to content

Commit 85a2229

Browse files
committed
Merge pull request #1269 from laanwj/2012_05_consoleimprovements
UI console improvements
2 parents 839c4e7 + ae744c8 commit 85a2229

File tree

3 files changed

+79
-99
lines changed

3 files changed

+79
-99
lines changed

src/qt/forms/rpcconsole.ui

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>706</width>
10-
<height>382</height>
10+
<height>446</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -327,30 +327,22 @@
327327
<number>3</number>
328328
</property>
329329
<item>
330-
<widget class="QTableWidget" name="messagesWidget">
330+
<widget class="QTextEdit" name="messagesWidget">
331331
<property name="minimumSize">
332332
<size>
333333
<width>0</width>
334334
<height>100</height>
335335
</size>
336336
</property>
337-
<property name="tabKeyNavigation">
338-
<bool>false</bool>
337+
<property name="readOnly">
338+
<bool>true</bool>
339339
</property>
340-
<property name="selectionBehavior">
341-
<enum>QAbstractItemView::SelectRows</enum>
340+
<property name="tabKeyNavigation" stdset="0">
341+
<bool>false</bool>
342342
</property>
343-
<property name="columnCount">
343+
<property name="columnCount" stdset="0">
344344
<number>2</number>
345345
</property>
346-
<attribute name="horizontalHeaderVisible">
347-
<bool>false</bool>
348-
</attribute>
349-
<attribute name="verticalHeaderVisible">
350-
<bool>false</bool>
351-
</attribute>
352-
<column/>
353-
<column/>
354346
</widget>
355347
</item>
356348
<item>

src/qt/rpcconsole.cpp

Lines changed: 71 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <QThread>
1111
#include <QTextEdit>
1212
#include <QKeyEvent>
13+
#include <QUrl>
1314

1415
#include <boost/tokenizer.hpp>
1516

@@ -19,6 +20,19 @@
1920
const int CONSOLE_SCROLLBACK = 50;
2021
const int CONSOLE_HISTORY = 50;
2122

23+
const QSize ICON_SIZE(24, 24);
24+
25+
const struct {
26+
const char *url;
27+
const char *source;
28+
} ICON_MAPPING[] = {
29+
{"cmd-request", ":/icons/tx_input"},
30+
{"cmd-reply", ":/icons/tx_output"},
31+
{"cmd-error", ":/icons/tx_output"},
32+
{"misc", ":/icons/tx_inout"},
33+
{NULL, NULL}
34+
};
35+
2236
/* Object for executing console RPC commands in a separate thread.
2337
*/
2438
class RPCExecutor: public QObject
@@ -41,19 +55,26 @@ void RPCExecutor::start()
4155
void RPCExecutor::request(const QString &command)
4256
{
4357
// Parse shell-like command line into separate arguments
44-
boost::escaped_list_separator<char> els('\\',' ','\"');
45-
std::string strCommand = command.toStdString();
46-
boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);
47-
4858
std::string strMethod;
4959
std::vector<std::string> strParams;
50-
int n = 0;
51-
for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
60+
try {
61+
boost::escaped_list_separator<char> els('\\',' ','\"');
62+
std::string strCommand = command.toStdString();
63+
boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els);
64+
65+
int n = 0;
66+
for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n)
67+
{
68+
if(n == 0) // First parameter is the command
69+
strMethod = *beg;
70+
else
71+
strParams.push_back(*beg);
72+
}
73+
}
74+
catch(boost::escaped_list_error &e)
5275
{
53-
if(n == 0) // First parameter is the command
54-
strMethod = *beg;
55-
else
56-
strParams.push_back(*beg);
76+
emit reply(RPCConsole::CMD_ERROR, QString("Parse error"));
77+
return;
5778
}
5879

5980
try {
@@ -83,12 +104,9 @@ void RPCExecutor::request(const QString &command)
83104
RPCConsole::RPCConsole(QWidget *parent) :
84105
QDialog(parent),
85106
ui(new Ui::RPCConsole),
86-
firstLayout(true),
87107
historyPtr(0)
88108
{
89109
ui->setupUi(this);
90-
ui->messagesWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch);
91-
ui->messagesWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
92110

93111
#ifndef WIN32
94112
// Show Debug logfile label and Open button only for Windows
@@ -99,13 +117,6 @@ RPCConsole::RPCConsole(QWidget *parent) :
99117
// Install event filter for up and down arrow
100118
ui->lineEdit->installEventFilter(this);
101119

102-
// Add "Copy message" to context menu explicitly
103-
QAction *copyMessageAction = new QAction(tr("&Copy"), this);
104-
copyMessageAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_C));
105-
copyMessageAction->setShortcutContext(Qt::WidgetShortcut);
106-
connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
107-
ui->messagesWidget->addAction(copyMessageAction);
108-
109120
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
110121
connect(ui->openDebugLogfileButton, SIGNAL(clicked()), this, SLOT(on_openDebugLogfileButton_clicked()));
111122

@@ -159,68 +170,62 @@ void RPCConsole::setClientModel(ClientModel *model)
159170
}
160171
}
161172

162-
static QColor categoryColor(int category)
173+
static QString categoryClass(int category)
163174
{
164175
switch(category)
165176
{
166-
case RPCConsole::MC_ERROR: return QColor(255,0,0); break;
167-
case RPCConsole::MC_DEBUG: return QColor(192,192,192); break;
168-
case RPCConsole::CMD_REQUEST: return QColor(128,128,128); break;
169-
case RPCConsole::CMD_REPLY: return QColor(128,255,128); break;
170-
case RPCConsole::CMD_ERROR: return QColor(255,128,128); break;
171-
default: return QColor(0,0,0);
177+
case RPCConsole::CMD_REQUEST: return "cmd-request"; break;
178+
case RPCConsole::CMD_REPLY: return "cmd-reply"; break;
179+
case RPCConsole::CMD_ERROR: return "cmd-error"; break;
180+
default: return "misc";
172181
}
173182
}
174183

175184
void RPCConsole::clear()
176185
{
177186
ui->messagesWidget->clear();
178-
ui->messagesWidget->setRowCount(0);
179187
ui->lineEdit->clear();
180188
ui->lineEdit->setFocus();
181189

182-
message(CMD_REPLY, tr("Welcome to the bitcoin RPC console.")+"\n"+
183-
tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.")+"\n"+
184-
tr("Type \"help\" for an overview of available commands."));
190+
// Add smoothly scaled icon images.
191+
// (when using width/height on an img, Qt uses nearest instead of linear interpolation)
192+
for(int i=0; ICON_MAPPING[i].url; ++i)
193+
{
194+
ui->messagesWidget->document()->addResource(
195+
QTextDocument::ImageResource,
196+
QUrl(ICON_MAPPING[i].url),
197+
QImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
198+
}
199+
200+
// Set default style sheet
201+
ui->messagesWidget->document()->setDefaultStyleSheet(
202+
"table { }"
203+
"td.time { color: #808080; padding-top: 3px; } "
204+
"td.message { font-family: Monospace; font-size: 12px; } "
205+
"td.cmd-request { color: #006060; } "
206+
"td.cmd-error { color: red; } "
207+
"b { color: #006060; } "
208+
);
209+
210+
message(CMD_REPLY, tr("Welcome to the Bitcoin RPC console.<br>"
211+
"Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.<br>"
212+
"Type <b>help</b> for an overview of available commands."), true);
185213
}
186214

187-
void RPCConsole::message(int category, const QString &message)
215+
void RPCConsole::message(int category, const QString &message, bool html)
188216
{
189-
// Add row to messages widget
190-
int row = ui->messagesWidget->rowCount();
191-
ui->messagesWidget->setRowCount(row+1);
192-
193217
QTime time = QTime::currentTime();
194-
QTableWidgetItem *newTime = new QTableWidgetItem(time.toString());
195-
newTime->setData(Qt::DecorationRole, categoryColor(category));
196-
newTime->setForeground(QColor(128,128,128));
197-
newTime->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
198-
199-
int numLines = message.count("\n") + 1;
200-
// As Qt doesn't like very tall cells (they break scrolling) keep only short messages in
201-
// the cell text, longer messages trigger a display widget with scroll bar
202-
if(numLines < 5)
203-
{
204-
QTableWidgetItem *newItem = new QTableWidgetItem(message);
205-
newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); // make non-editable
206-
if(category == CMD_ERROR) // Coloring error messages in red
207-
newItem->setForeground(QColor(255,16,16));
208-
ui->messagesWidget->setItem(row, 1, newItem);
209-
} else {
210-
QTextEdit *newWidget = new QTextEdit;
211-
newWidget->setText(message);
212-
newWidget->setMaximumHeight(100);
213-
newWidget->setReadOnly(true);
214-
ui->messagesWidget->setCellWidget(row, 1, newWidget);
215-
}
216-
217-
ui->messagesWidget->setItem(row, 0, newTime);
218-
ui->messagesWidget->resizeRowToContents(row);
219-
// Preserve only limited scrollback buffer
220-
while(ui->messagesWidget->rowCount() > CONSOLE_SCROLLBACK)
221-
ui->messagesWidget->removeRow(0);
222-
// Scroll to bottom after table is updated
223-
QTimer::singleShot(0, ui->messagesWidget, SLOT(scrollToBottom()));
218+
QString timeString = time.toString();
219+
QString out;
220+
out += "<table><tr><td class=\"time\" width=\"65\">" + timeString + "</td>";
221+
out += "<td class=\"icon\" width=\"32\"><img src=\"" + categoryClass(category) + "\"></td>";
222+
out += "<td class=\"message " + categoryClass(category) + "\" valign=\"middle\">";
223+
if(html)
224+
out += message;
225+
else
226+
out += GUIUtil::HtmlEscape(message, true);
227+
out += "</td></tr></table>";
228+
ui->messagesWidget->append(out);
224229
}
225230

226231
void RPCConsole::setNumConnections(int count)
@@ -298,24 +303,10 @@ void RPCConsole::startExecutor()
298303
thread->start();
299304
}
300305

301-
void RPCConsole::copyMessage()
302-
{
303-
GUIUtil::copyEntryData(ui->messagesWidget, 1, Qt::EditRole);
304-
}
305-
306306
void RPCConsole::on_tabWidget_currentChanged(int index)
307307
{
308308
if(ui->tabWidget->widget(index) == ui->tab_console)
309309
{
310-
if(firstLayout)
311-
{
312-
// Work around QTableWidget issue:
313-
// Call resizeRowsToContents on first Layout request with widget visible,
314-
// to make sure multiline messages that were added before the console was shown
315-
// have the right height.
316-
firstLayout = false;
317-
ui->messagesWidget->resizeRowsToContents();
318-
}
319310
ui->lineEdit->setFocus();
320311
}
321312
}

src/qt/rpcconsole.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,13 @@ private slots:
3737

3838
public slots:
3939
void clear();
40-
void message(int category, const QString &message);
40+
void message(int category, const QString &message, bool html = false);
4141
/** Set number of connections shown in the UI */
4242
void setNumConnections(int count);
4343
/** Set number of blocks shown in the UI */
4444
void setNumBlocks(int count);
4545
/** Go forward or back in history */
4646
void browseHistory(int offset);
47-
/** Copy currently selected message to clipboard */
48-
void copyMessage();
4947

5048
signals:
5149
// For RPC command executor
@@ -55,7 +53,6 @@ public slots:
5553
private:
5654
Ui::RPCConsole *ui;
5755
ClientModel *clientModel;
58-
bool firstLayout;
5956
QStringList history;
6057
int historyPtr;
6158

0 commit comments

Comments
 (0)