diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoinrpc.cpp | 2 | ||||
-rw-r--r-- | src/init.cpp | 12 | ||||
-rw-r--r-- | src/makefile.unix | 15 | ||||
-rw-r--r-- | src/net.cpp | 44 | ||||
-rw-r--r-- | src/net.h | 3 | ||||
-rw-r--r-- | src/netbase.cpp | 16 | ||||
-rw-r--r-- | src/qt/forms/askpassphrasedialog.ui | 3 | ||||
-rw-r--r-- | src/qt/forms/rpcconsole.ui | 22 | ||||
-rw-r--r-- | src/qt/forms/transactiondescdialog.ui | 4 | ||||
-rw-r--r-- | src/qt/rpcconsole.cpp | 151 | ||||
-rw-r--r-- | src/qt/rpcconsole.h | 5 |
11 files changed, 135 insertions, 142 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index df3c190b38..e058978ebf 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -2447,7 +2447,7 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe strMessageRet = ""; // Read status - int nProto; + int nProto = 0; int nStatus = ReadHTTPStatus(stream, nProto); // Read header diff --git a/src/init.cpp b/src/init.cpp index fe07ed7275..d253c3b7a6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -192,7 +192,7 @@ bool AppInit2(int argc, char* argv[]) " -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" + " -proxy=<ip:port> \t " + _("Connect through socks proxy") + "\n" + " -socks=<n> \t " + _("Select the version of socks proxy to use (4 or 5, 5 is default)") + "\n" + - " -noproxy=<net> \t " + _("Do not use proxy for connections to network net (ipv4 or ipv6)") + "\n" + + " -noproxy=<net> \t " + _("Do not use proxy for connections to network <net> (IPv4 or IPv6)") + "\n" + " -dns \t " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" + " -proxydns \t " + _("Pass DNS requests to (SOCKS5) proxy") + "\n" + " -port=<port> \t\t " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" + @@ -201,7 +201,7 @@ bool AppInit2(int argc, char* argv[]) " -connect=<ip> \t\t " + _("Connect only to the specified node") + "\n" + " -seednode=<ip> \t\t " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" + " -externalip=<ip> \t " + _("Specify your own public address") + "\n" + - " -blocknet=<net> \t " + _("Do not connect to addresses in network net (ipv4, ipv6)") + "\n" + + " -blocknet=<net> \t " + _("Do not connect to addresses in network <net> (IPv4 or IPv6)") + "\n" + " -discover \t " + _("Try to discover public IP address (default: 1)") + "\n" + " -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" + " -listen \t " + _("Accept connections from outside (default: 1)") + "\n" + @@ -611,14 +611,14 @@ bool AppInit2(int argc, char* argv[]) std::string strError; if (mapArgs.count("-bind")) { BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) { - fBound |= Bind(CService(strBind, GetDefaultPort(), false)); + fBound |= Bind(CService(strBind, GetListenPort(), false)); } } else { struct in_addr inaddr_any; inaddr_any.s_addr = INADDR_ANY; - fBound |= Bind(CService(inaddr_any, GetDefaultPort())); + fBound |= Bind(CService(inaddr_any, GetListenPort())); #ifdef USE_IPV6 - fBound |= Bind(CService(in6addr_any, GetDefaultPort())); + fBound |= Bind(CService(in6addr_any, GetListenPort())); #endif } if (!fBound) @@ -628,7 +628,7 @@ bool AppInit2(int argc, char* argv[]) if (mapArgs.count("-externalip")) { BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) - AddLocal(CNetAddr(strAddr, fNameLookup), LOCAL_MANUAL); + AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); } if (mapArgs.count("-paytxfee")) diff --git a/src/makefile.unix b/src/makefile.unix index ad0a82df50..b1cc89d0cb 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -82,8 +82,11 @@ LIBS+= \ DEBUGFLAGS=-g -CXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ - $(DEBUGFLAGS) $(DEFS) $(HARDENING) + +# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only +# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. +xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ + $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) OBJS= \ obj/version.o \ @@ -121,26 +124,26 @@ version.cpp: obj/build.h DEFS += -DHAVE_BUILD_INFO obj/%.o: %.cpp - $(CXX) -c $(CXXFLAGS) -MMD -o $@ $< + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ rm -f $(@:%.o=%.d) bitcoind: $(OBJS:obj/%=obj/%) - $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + $(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) obj-test/%.o: test/%.cpp - $(CXX) -c $(TESTDEFS) $(CXXFLAGS) -MMD -o $@ $< + $(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -o $@ $< @cp $(@:%.o=%.d) $(@:%.o=%.P); \ sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ rm -f $(@:%.o=%.d) test_bitcoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) - $(CXX) $(CXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(LDFLAGS) $(LIBS) + $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(LDFLAGS) $(LIBS) clean: -rm -f bitcoind test_bitcoin diff --git a/src/net.cpp b/src/net.cpp index f12afb78e6..c8cb17091f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -38,6 +38,10 @@ void ThreadDNSAddressSeed2(void* parg); bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); +struct LocalServiceInfo { + int nScore; + int nPort; +}; // // Global state variables @@ -46,7 +50,7 @@ bool fClient = false; static bool fUseUPnP = false; uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); static CCriticalSection cs_mapLocalHost; -static map<CService, int> mapLocalHost; +static map<CNetAddr, LocalServiceInfo> mapLocalHost; static bool vfReachable[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {}; static CNode* pnodeLocalHost = NULL; @@ -98,23 +102,23 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer) if (fUseProxy || mapArgs.count("-connect") || fNoListen) return false; - int nBestCount = -1; + int nBestScore = -1; int nBestReachability = -1; { LOCK(cs_mapLocalHost); - for (map<CService, int>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) + for (map<CNetAddr, LocalServiceInfo>::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) { - int nCount = (*it).second; + int nScore = (*it).second.nScore; int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); - if (nReachability > nBestReachability || (nReachability == nBestReachability && nCount > nBestCount)) + if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) { - addr = (*it).first; + addr = CService((*it).first, (*it).second.nPort); nBestReachability = nReachability; - nBestCount = nCount; + nBestScore = nScore; } } } - return nBestCount >= 0; + return nBestScore >= 0; } // get best local address for a particular peer as a CAddress @@ -211,7 +215,12 @@ bool AddLocal(const CService& addr, int nScore) { LOCK(cs_mapLocalHost); - mapLocalHost[addr] = std::max(nScore, mapLocalHost[addr]) + (mapLocalHost.count(addr) ? 1 : 0); + bool fAlready = mapLocalHost.count(addr) > 0; + LocalServiceInfo &info = mapLocalHost[addr]; + if (!fAlready || nScore >= info.nScore) { + info.nScore = nScore; + info.nPort = addr.GetPort() + (fAlready ? 1 : 0); + } enum Network net = addr.GetNetwork(); vfReachable[net] = true; if (net == NET_IPV6) vfReachable[NET_IPV4] = true; @@ -222,11 +231,9 @@ bool AddLocal(const CService& addr, int nScore) return true; } -bool AddLocal(const CNetAddr& addr, int nScore, int port) +bool AddLocal(const CNetAddr &addr, int nScore) { - if (port == -1) - port = GetListenPort(); - return AddLocal(CService(addr, port), nScore); + return AddLocal(CService(addr, GetListenPort()), nScore); } /** Make a particular network entirely off-limits (no automatic connects to it) */ @@ -249,7 +256,7 @@ bool SeenLocal(const CService& addr) LOCK(cs_mapLocalHost); if (mapLocalHost.count(addr) == 0) return false; - mapLocalHost[addr]++; + mapLocalHost[addr].nScore++; } AdvertizeLocal(); @@ -1796,7 +1803,7 @@ void static Discover() struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr); CNetAddr addr(s4->sin_addr); if (AddLocal(addr, LOCAL_IF)) - printf("ipv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); + printf("IPv4 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); } #ifdef USE_IPV6 else if (ifa->ifa_addr->sa_family == AF_INET6) @@ -1804,7 +1811,7 @@ void static Discover() struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr); CNetAddr addr(s6->sin6_addr); if (AddLocal(addr, LOCAL_IF)) - printf("ipv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); + printf("IPv6 %s: %s\n", ifa->ifa_name, addr.ToString().c_str()); } #endif } @@ -1887,8 +1894,9 @@ bool StopNode() fShutdown = true; nTransactionsUpdated++; int64 nStart = GetTime(); - for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) - semOutbound->post(); + if (semOutbound) + for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) + semOutbound->post(); do { int nThreadsRunning = 0; @@ -38,6 +38,7 @@ CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CService& ip); CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0); void MapPort(bool fMapPort); +unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string())); void StartNode(void* parg); bool StopNode(); @@ -58,7 +59,7 @@ enum void SetLimited(enum Network net, bool fLimited = true); bool IsLimited(const CNetAddr& addr); bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); -bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE, int port = -1); +bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); diff --git a/src/netbase.cpp b/src/netbase.cpp index ebf823e899..2131bdf75b 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -11,6 +11,7 @@ #endif #include "strlcpy.h" +#include <boost/algorithm/string/case_conv.hpp> // for to_lower() using namespace std; @@ -27,6 +28,7 @@ static bool vfNoProxy[NET_MAX] = {}; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; enum Network ParseNetwork(std::string net) { + boost::to_lower(net); if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; if (net == "tor") return NET_TOR; @@ -464,12 +466,14 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest int port = portDefault; size_t colon = strDest.find_last_of(':'); - char *endp = NULL; - int n = strtol(pszDest + colon + 1, &endp, 10); - if (endp && *endp == 0 && n >= 0) { - strDest = strDest.substr(0, colon); - if (n > 0 && n < 0x10000) - port = n; + if (colon != strDest.npos) { + char *endp = NULL; + int n = strtol(pszDest + colon + 1, &endp, 10); + if (endp && *endp == 0 && n >= 0) { + strDest = strDest.substr(0, colon); + if (n > 0 && n < 0x10000) + port = n; + } } if (strDest[0] == '[' && strDest[strDest.size()-1] == ']') strDest = strDest.substr(1, strDest.size()-2); diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui index 1383af7a70..e4d86f7cf9 100644 --- a/src/qt/forms/askpassphrasedialog.ui +++ b/src/qt/forms/askpassphrasedialog.ui @@ -28,9 +28,6 @@ <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QLabel" name="warningLabel"> - <property name="text"> - <string>TextLabel</string> - </property> <property name="textFormat"> <enum>Qt::RichText</enum> </property> 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 @@ <x>0</x> <y>0</y> <width>706</width> - <height>382</height> + <height>446</height> </rect> </property> <property name="windowTitle"> @@ -327,30 +327,22 @@ <number>3</number> </property> <item> - <widget class="QTableWidget" name="messagesWidget"> + <widget class="QTextEdit" name="messagesWidget"> <property name="minimumSize"> <size> <width>0</width> <height>100</height> </size> </property> - <property name="tabKeyNavigation"> - <bool>false</bool> + <property name="readOnly"> + <bool>true</bool> </property> - <property name="selectionBehavior"> - <enum>QAbstractItemView::SelectRows</enum> + <property name="tabKeyNavigation" stdset="0"> + <bool>false</bool> </property> - <property name="columnCount"> + <property name="columnCount" stdset="0"> <number>2</number> </property> - <attribute name="horizontalHeaderVisible"> - <bool>false</bool> - </attribute> - <attribute name="verticalHeaderVisible"> - <bool>false</bool> - </attribute> - <column/> - <column/> </widget> </item> <item> diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui index 9a9f6db158..039cb082cc 100644 --- a/src/qt/forms/transactiondescdialog.ui +++ b/src/qt/forms/transactiondescdialog.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>300</height> + <width>600</width> + <height>250</height> </rect> </property> <property name="windowTitle"> diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 5a035888ed..33b09952b7 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -10,6 +10,7 @@ #include <QThread> #include <QTextEdit> #include <QKeyEvent> +#include <QUrl> #include <boost/tokenizer.hpp> @@ -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 @@ -41,19 +55,26 @@ void RPCExecutor::start() void RPCExecutor::request(const QString &command) { // Parse shell-like command line into separate arguments - boost::escaped_list_separator<char> els('\\',' ','\"'); - std::string strCommand = command.toStdString(); - boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els); - std::string strMethod; std::vector<std::string> strParams; - int n = 0; - for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n) + try { + boost::escaped_list_separator<char> els('\\',' ','\"'); + std::string strCommand = command.toStdString(); + boost::tokenizer<boost::escaped_list_separator<char> > tok(strCommand, els); + + int n = 0; + for(boost::tokenizer<boost::escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end();++beg,++n) + { + if(n == 0) // First parameter is the command + strMethod = *beg; + else + strParams.push_back(*beg); + } + } + catch(boost::escaped_list_error &e) { - if(n == 0) // First parameter is the command - strMethod = *beg; - else - strParams.push_back(*beg); + emit reply(RPCConsole::CMD_ERROR, QString("Parse error")); + return; } try { @@ -83,12 +104,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 +117,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 +170,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.<br>" + "Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.<br>" + "Type <b>help</b> 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 += "<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 + out += GUIUtil::HtmlEscape(message, true); + out += "</td></tr></table>"; + ui->messagesWidget->append(out); } void RPCConsole::setNumConnections(int count) @@ -298,24 +303,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; |