Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711521
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
126 KB
Subscribers
None
View Options
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 745da3014..c25952cd8 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1,1489 +1,1508 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RPCConsole</class>
<widget class="QWidget" name="RPCConsole">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>740</width>
<height>430</height>
</rect>
</property>
<property name="windowTitle">
<string>Debug window</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_alerts">
+ <property name="visible">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>3</number>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_info">
<attribute name="title">
<string>&Information</string>
</attribute>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
<property name="horizontalSpacing">
<number>12</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>General</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Client version</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLabel" name="clientVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelClientUserAgent">
<property name="text">
<string>User Agent</string>
</property>
<property name="indent">
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLabel" name="clientUserAgent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_berkeleyDBVersion">
<property name="text">
<string>Using BerkeleyDB version</string>
</property>
<property name="indent">
<number>10</number>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLabel" name="berkeleyDBVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Datadir</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QLabel" name="dataDir">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="toolTip">
<string>To specify a non-default location of the data directory use the '%1' option.</string>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Blocksdir</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="QLabel" name="blocksDir">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="toolTip">
<string>To specify a non-default location of the blocks directory use the '%1' option.</string>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
<item row="6" column="1" colspan="2">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="labelNetwork">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Network</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="8" column="1" colspan="2">
<widget class="QLabel" name="networkName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Block chain</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
<item row="11" column="1" colspan="2">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="labelLastBlockTime">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
<item row="12" column="1" colspan="2">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="labelMempoolTitle">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Memory Pool</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="labelNumberOfTransactions">
<property name="text">
<string>Current number of transactions</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QLabel" name="mempoolNumberTxs">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="labelMemoryUsage">
<property name="text">
<string>Memory usage</string>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="mempoolSize">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="2" rowspan="3">
<layout class="QVBoxLayout" name="verticalLayoutDebugButton">
<property name="spacing">
<number>3</number>
</property>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="labelDebugLogfile">
<property name="text">
<string>Debug log file</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openDebugLogfileButton">
<property name="toolTip">
<string>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</string>
</property>
<property name="text">
<string>&Open</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="16" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_console">
<attribute name="title">
<string>&Console</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="WalletSelectorLabel">
<property name="text">
<string>Wallet: </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="WalletSelector">
<item>
<property name="text">
<string>(none)</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="fontSmallerButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="toolTip">
<string>Decrease font size</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/fontsmaller</normaloff>:/icons/fontsmaller</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>16</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fontBiggerButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Increase font size</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/fontbigger</normaloff>:/icons/fontbigger</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>16</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Clear console</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="shortcut">
<string notr="true">Ctrl+L</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTextEdit" name="messagesWidget">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="tabKeyNavigation" stdset="0">
<bool>false</bool>
</property>
<property name="columnCount" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutPrompt">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QPushButton" name="promptIcon">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximumSize">
<size>
<width>16</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/prompticon</normaloff>
<disabledoff>:/icons/prompticon</disabledoff>:/icons/prompticon</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="placeholderText">
<string/>
</property>
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_nettraffic">
<attribute name="title">
<string>&Network Traffic</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="TrafficGraphWidget" name="trafficGraph" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSlider" name="sldGraphRange">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>288</number>
</property>
<property name="pageStep">
<number>12</number>
</property>
<property name="value">
<number>6</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblGraphRange">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClearTrafficGraph">
<property name="text">
<string>&Reset</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Totals</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="Line" name="line">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>255</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>255</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>255</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16">
<property name="text">
<string>Received</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblBytesIn">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="Line" name="line_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>10</width>
<height>0</height>
</size>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="Light">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_17">
<property name="text">
<string>Sent</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblBytesOut">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>407</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_peers">
<attribute name="title">
<string>&Peers</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" rowspan="2">
<layout class="QVBoxLayout" name="verticalLayout_101">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QTableView" name="peerWidget">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QLabel" name="banHeading">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>Banned peers</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="banlistWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QLabel" name="peerHeading">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>32</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>Select a peer to view detailed information.</string>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="detailWidget" native="true">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_30">
<property name="text">
<string>Whitelisted</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="peerWhitelisted">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Direction</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="peerDirection">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="peerVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>User Agent</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="peerSubversion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Services</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="peerServices">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Starting Block</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="peerHeight">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Synced Headers</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QLabel" name="peerSyncHeight">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_25">
<property name="text">
<string>Synced Blocks</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="peerCommonHeight">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Ban Score</string>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QLabel" name="peerBanScore">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Connection Time</string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QLabel" name="peerConnTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Last Send</string>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QLabel" name="peerLastSend">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Last Receive</string>
</property>
</widget>
</item>
<item row="11" column="2">
<widget class="QLabel" name="peerLastRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Sent</string>
</property>
</widget>
</item>
<item row="12" column="2">
<widget class="QLabel" name="peerBytesSent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Received</string>
</property>
</widget>
</item>
<item row="13" column="2">
<widget class="QLabel" name="peerBytesRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Ping Time</string>
</property>
</widget>
</item>
<item row="14" column="2">
<widget class="QLabel" name="peerPingTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="peerPingWaitLabel">
<property name="toolTip">
<string>The duration of a currently outstanding ping.</string>
</property>
<property name="text">
<string>Ping Wait</string>
</property>
</widget>
</item>
<item row="15" column="2">
<widget class="QLabel" name="peerPingWait">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="peerMinPingLabel">
<property name="text">
<string>Min Ping</string>
</property>
</widget>
</item>
<item row="16" column="2">
<widget class="QLabel" name="peerMinPing">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
<item row="17" column="2">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="18" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TrafficGraphWidget</class>
<extends>QWidget</extends>
<header>qt/trafficgraphwidget.h</header>
<container>1</container>
<slots>
<slot>clear()</slot>
</slots>
</customwidget>
</customwidgets>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index f0dd59fb5..c85eb4eb1 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -1,319 +1,319 @@
// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <qt/forms/ui_overviewpage.h>
#include <qt/overviewpage.h>
#include <qt/bitcoinunits.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/transactionfilterproxy.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
#include <QAbstractItemDelegate>
#include <QPainter>
#define DECORATION_SIZE 54
#define NUM_ITEMS 5
Q_DECLARE_METATYPE(interfaces::WalletBalances)
class TxViewDelegate : public QAbstractItemDelegate {
Q_OBJECT
public:
explicit TxViewDelegate(const PlatformStyle *_platformStyle,
QObject *parent = nullptr)
: QAbstractItemDelegate(parent), unit(BitcoinUnits::BCH),
platformStyle(_platformStyle) {}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const {
painter->save();
QIcon icon = qvariant_cast<QIcon>(
index.data(TransactionTableModel::RawDecorationRole));
QRect mainRect = option.rect;
QRect decorationRect(mainRect.topLeft(),
QSize(DECORATION_SIZE, DECORATION_SIZE));
int xspace = DECORATION_SIZE + 8;
int ypad = 6;
int halfheight = (mainRect.height() - 2 * ypad) / 2;
QRect amountRect(mainRect.left() + xspace, mainRect.top() + ypad,
mainRect.width() - xspace, halfheight);
QRect addressRect(mainRect.left() + xspace,
mainRect.top() + ypad + halfheight,
mainRect.width() - xspace, halfheight);
icon = platformStyle->SingleColorIcon(icon);
icon.paint(painter, decorationRect);
QDateTime date =
index.data(TransactionTableModel::DateRole).toDateTime();
QString address = index.data(Qt::DisplayRole).toString();
Amount amount(
int64_t(
index.data(TransactionTableModel::AmountRole).toLongLong()) *
SATOSHI);
bool confirmed =
index.data(TransactionTableModel::ConfirmedRole).toBool();
QVariant value = index.data(Qt::ForegroundRole);
QColor foreground = option.palette.color(QPalette::Text);
if (value.canConvert<QBrush>()) {
QBrush brush = qvariant_cast<QBrush>(value);
foreground = brush.color();
}
painter->setPen(foreground);
QRect boundingRect;
painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter,
address, &boundingRect);
if (index.data(TransactionTableModel::WatchonlyRole).toBool()) {
QIcon iconWatchonly = qvariant_cast<QIcon>(
index.data(TransactionTableModel::WatchonlyDecorationRole));
QRect watchonlyRect(boundingRect.right() + 5,
mainRect.top() + ypad + halfheight, 16,
halfheight);
iconWatchonly.paint(painter, watchonlyRect);
}
if (amount < Amount::zero()) {
foreground = COLOR_NEGATIVE;
} else if (!confirmed) {
foreground = COLOR_UNCONFIRMED;
} else {
foreground = option.palette.color(QPalette::Text);
}
painter->setPen(foreground);
QString amountText = BitcoinUnits::formatWithUnit(
unit, amount, true, BitcoinUnits::separatorAlways);
if (!confirmed) {
amountText = QString("[") + amountText + QString("]");
}
painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter,
amountText);
painter->setPen(option.palette.color(QPalette::Text));
painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter,
GUIUtil::dateTimeStr(date));
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const {
return QSize(DECORATION_SIZE, DECORATION_SIZE);
}
int unit;
const PlatformStyle *platformStyle;
};
#include <qt/overviewpage.moc>
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
: QWidget(parent), ui(new Ui::OverviewPage), clientModel(nullptr),
walletModel(nullptr),
txdelegate(new TxViewDelegate(platformStyle, this)) {
ui->setupUi(this);
m_balances.balance = -SATOSHI;
// use a SingleColorIcon for the "out of sync warning" icon
QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
// also set the disabled icon because we are using a disabled QPushButton to
// work around missing HiDPI support of QLabel
// (https://bugreports.qt.io/browse/QTBUG-42503)
icon.addPixmap(icon.pixmap(QSize(64, 64), QIcon::Normal), QIcon::Disabled);
ui->labelTransactionsStatus->setIcon(icon);
ui->labelWalletStatus->setIcon(icon);
// Recent transactions
ui->listTransactions->setItemDelegate(txdelegate);
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
connect(ui->listTransactions, &QListView::clicked, this,
&OverviewPage::handleTransactionClicked);
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
connect(ui->labelWalletStatus, &QPushButton::clicked, this,
&OverviewPage::handleOutOfSyncWarningClicks);
connect(ui->labelTransactionsStatus, &QPushButton::clicked, this,
&OverviewPage::handleOutOfSyncWarningClicks);
}
void OverviewPage::handleTransactionClicked(const QModelIndex &index) {
if (filter) {
Q_EMIT transactionClicked(filter->mapToSource(index));
}
}
void OverviewPage::handleOutOfSyncWarningClicks() {
Q_EMIT outOfSyncWarningClicked();
}
OverviewPage::~OverviewPage() {
delete ui;
}
void OverviewPage::setBalance(const interfaces::WalletBalances &balances) {
int unit = walletModel->getOptionsModel()->getDisplayUnit();
m_balances = balances;
if (walletModel->privateKeysDisabled()) {
ui->labelBalance->setText(
BitcoinUnits::formatWithUnit(unit, balances.watch_only_balance,
false, BitcoinUnits::separatorAlways));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(
unit, balances.unconfirmed_watch_only_balance, false,
BitcoinUnits::separatorAlways));
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(
unit, balances.immature_watch_only_balance, false,
BitcoinUnits::separatorAlways));
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(
unit,
balances.watch_only_balance +
balances.unconfirmed_watch_only_balance +
balances.immature_watch_only_balance,
false, BitcoinUnits::separatorAlways));
} else {
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(
unit, balances.balance, false, BitcoinUnits::separatorAlways));
ui->labelUnconfirmed->setText(
BitcoinUnits::formatWithUnit(unit, balances.unconfirmed_balance,
false, BitcoinUnits::separatorAlways));
ui->labelImmature->setText(
BitcoinUnits::formatWithUnit(unit, balances.immature_balance, false,
BitcoinUnits::separatorAlways));
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(
unit,
balances.balance + balances.unconfirmed_balance +
balances.immature_balance,
false, BitcoinUnits::separatorAlways));
ui->labelWatchAvailable->setText(
BitcoinUnits::formatWithUnit(unit, balances.watch_only_balance,
false, BitcoinUnits::separatorAlways));
ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit(
unit, balances.unconfirmed_watch_only_balance, false,
BitcoinUnits::separatorAlways));
ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit(
unit, balances.immature_watch_only_balance, false,
BitcoinUnits::separatorAlways));
ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit(
unit,
balances.watch_only_balance +
balances.unconfirmed_watch_only_balance +
balances.immature_watch_only_balance,
false, BitcoinUnits::separatorAlways));
}
// only show immature (newly mined) balance if it's non-zero, so as not to
// complicate things for the non-mining users
bool showImmature = balances.immature_balance != Amount::zero();
bool showWatchOnlyImmature =
balances.immature_watch_only_balance != Amount::zero();
// for symmetry reasons also show immature label when the watch-only one is
// shown
ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
// show watch-only immature balance
ui->labelWatchImmature->setVisible(!walletModel->privateKeysDisabled() &&
showWatchOnlyImmature);
}
// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly) {
// show spendable label (only when watch-only is active)
ui->labelSpendable->setVisible(showWatchOnly);
// show watch-only label
ui->labelWatchonly->setVisible(showWatchOnly);
// show watch-only balance separator line
ui->lineWatchBalance->setVisible(showWatchOnly);
// show watch-only available balance
ui->labelWatchAvailable->setVisible(showWatchOnly);
// show watch-only pending balance
ui->labelWatchPending->setVisible(showWatchOnly);
// show watch-only total balance
ui->labelWatchTotal->setVisible(showWatchOnly);
if (!showWatchOnly) {
ui->labelWatchImmature->hide();
}
}
void OverviewPage::setClientModel(ClientModel *model) {
this->clientModel = model;
if (model) {
- // Show warning if this is a prerelease version
+ // Show warning, for example if this is a prerelease version
connect(model, &ClientModel::alertsChanged, this,
&OverviewPage::updateAlerts);
updateAlerts(model->getStatusBarWarnings());
}
}
void OverviewPage::setWalletModel(WalletModel *model) {
this->walletModel = model;
if (model && model->getOptionsModel()) {
// Set up transaction list
filter.reset(new TransactionFilterProxy());
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
ui->listTransactions->setModel(filter.get());
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
interfaces::Wallet &wallet = model->wallet();
interfaces::WalletBalances balances = wallet.getBalances();
setBalance(balances);
connect(model, &WalletModel::balanceChanged, this,
&OverviewPage::setBalance);
connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged,
this, &OverviewPage::updateDisplayUnit);
updateWatchOnlyLabels(wallet.haveWatchOnly() &&
!model->privateKeysDisabled());
connect(model, &WalletModel::notifyWatchonlyChanged,
[this](bool showWatchOnly) {
updateWatchOnlyLabels(showWatchOnly &&
!walletModel->privateKeysDisabled());
});
}
// update the display unit, to not use the default ("BCH")
updateDisplayUnit();
}
void OverviewPage::updateDisplayUnit() {
if (walletModel && walletModel->getOptionsModel()) {
if (m_balances.balance != -SATOSHI) {
setBalance(m_balances);
}
// Update txdelegate->unit with the current unit
txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
ui->listTransactions->update();
}
}
void OverviewPage::updateAlerts(const QString &warnings) {
this->ui->labelAlerts->setVisible(!warnings.isEmpty());
this->ui->labelAlerts->setText(warnings);
}
void OverviewPage::showOutOfSyncWarning(bool fShow) {
ui->labelWalletStatus->setVisible(fShow);
ui->labelTransactionsStatus->setVisible(fShow);
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 1176fdcd5..e65e7b884 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1,1455 +1,1472 @@
// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <qt/rpcconsole.h>
#include <chainparams.h>
#include <config.h>
#include <interfaces/node.h>
#include <netbase.h>
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
#include <qt/forms/ui_debugwindow.h>
#include <qt/platformstyle.h>
#include <qt/walletmodel.h>
#include <rpc/client.h>
#include <rpc/server.h>
#include <util/strencodings.h>
#include <util/system.h>
#ifdef ENABLE_WALLET
#include <wallet/wallet.h>
#include <db_cxx.h>
#endif
#include <univalue.h>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QScreen>
#include <QScrollBar>
#include <QSettings>
#include <QStringList>
#include <QTime>
#include <QTimer>
// TODO: add a scrollback limit, as there is currently none
// 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;
const int INITIAL_TRAFFIC_GRAPH_MINS = 30;
const QSize FONT_RANGE(4, 40);
const char fontSizeSettingsKey[] = "consoleFontSize";
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"},
{nullptr, nullptr}};
namespace {
// don't add private key handling cmd's to the history
const QStringList historyFilter = QStringList() << "importprivkey"
<< "importmulti"
<< "sethdseed"
<< "signmessagewithprivkey"
<< "signrawtransactionwithkey"
<< "walletpassphrase"
<< "walletpassphrasechange"
<< "encryptwallet";
} // namespace
/* Object for executing console RPC commands in a separate thread.
*/
class RPCExecutor : public QObject {
Q_OBJECT
public:
explicit RPCExecutor(interfaces::Node &node) : m_node(node) {}
public Q_SLOTS:
void request(const QString &command, const WalletModel *wallet_model);
Q_SIGNALS:
void reply(int category, const QString &command);
private:
interfaces::Node &m_node;
};
/** 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(std::function<void()> &_func, int64_t millis) : func(_func) {
timer.setSingleShot(true);
connect(&timer, &QTimer::timeout, [this] { func(); });
timer.start(millis);
}
~QtRPCTimerBase() {}
private:
QTimer timer;
std::function<void()> func;
};
class QtRPCTimerInterface : public RPCTimerInterface {
public:
~QtRPCTimerInterface() {}
const char *Name() override { return "Qt"; }
RPCTimerBase *NewTimer(std::function<void()> &func,
int64_t millis) override {
return new QtRPCTimerBase(func, millis);
}
};
#include <qt/rpcconsole.moc>
/**
* Split shell command line into a list of arguments and optionally execute the
* command(s).
* Aims to emulate \c bash and friends.
*
* - Command nesting is possible with parenthesis; for example:
* validateaddress(getnewaddress())
* - Arguments are delimited with whitespace or comma
* - Extra whitespace at the beginning and end and between arguments will be
* ignored
* - Text can be "double" or 'single' quoted
* - The backslash \c \ is used as escape character
* - Outside quotes, any character can be escaped
* - 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
*
* @param[in] node optional node to execute command on
* @param[out] strResult stringified result from the executed command(chain)
* @param[in] strCommand Command line to split
* @param[in] fExecute set true if you want the command to be executed
* @param[out] pstrFilteredOut Command line, filtered to remove any sensitive
* data
*/
bool RPCConsole::RPCParseCommandLine(interfaces::Node *node,
std::string &strResult,
const std::string &strCommand,
const bool fExecute,
std::string *const pstrFilteredOut,
const WalletModel *wallet_model) {
std::vector<std::vector<std::string>> stack;
stack.push_back(std::vector<std::string>());
enum CmdParseState {
STATE_EATING_SPACES,
STATE_EATING_SPACES_IN_ARG,
STATE_EATING_SPACES_IN_BRACKETS,
STATE_ARGUMENT,
STATE_SINGLEQUOTED,
STATE_DOUBLEQUOTED,
STATE_ESCAPE_OUTER,
STATE_ESCAPE_DOUBLEQUOTED,
STATE_COMMAND_EXECUTED,
STATE_COMMAND_EXECUTED_INNER
} state = STATE_EATING_SPACES;
std::string curarg;
UniValue lastResult;
unsigned nDepthInsideSensitive = 0;
size_t filter_begin_pos = 0, chpos;
std::vector<std::pair<size_t, size_t>> filter_ranges;
auto add_to_current_stack = [&](const std::string &strArg) {
if (stack.back().empty() && (!nDepthInsideSensitive) &&
historyFilter.contains(QString::fromStdString(strArg),
Qt::CaseInsensitive)) {
nDepthInsideSensitive = 1;
filter_begin_pos = chpos;
}
// Make sure stack is not empty before adding something
if (stack.empty()) {
stack.push_back(std::vector<std::string>());
}
stack.back().push_back(strArg);
};
auto close_out_params = [&]() {
if (nDepthInsideSensitive) {
if (!--nDepthInsideSensitive) {
assert(filter_begin_pos);
filter_ranges.push_back(
std::make_pair(filter_begin_pos, chpos));
filter_begin_pos = 0;
}
}
stack.pop_back();
};
std::string strCommandTerminated = strCommand;
if (strCommandTerminated.back() != '\n') {
strCommandTerminated += "\n";
}
for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos) {
char ch = strCommandTerminated[chpos];
switch (state) {
case STATE_COMMAND_EXECUTED_INNER:
case STATE_COMMAND_EXECUTED: {
bool breakParsing = true;
switch (ch) {
case '[':
curarg.clear();
state = STATE_COMMAND_EXECUTED_INNER;
break;
default:
if (state == STATE_COMMAND_EXECUTED_INNER) {
if (ch != ']') {
// append char to the current argument (which is
// also used for the query command)
curarg += ch;
break;
}
if (curarg.size() && fExecute) {
// if we have a value query, query arrays with
// index and objects with a string key
UniValue subelement;
if (lastResult.isArray()) {
for (char argch : curarg) {
if (!IsDigit(argch)) {
throw std::runtime_error(
"Invalid result query");
}
}
subelement =
lastResult[atoi(curarg.c_str())];
} else if (lastResult.isObject()) {
subelement = find_value(lastResult, curarg);
} else {
// no array or object: abort
throw std::runtime_error(
"Invalid result query");
}
lastResult = subelement;
}
state = STATE_COMMAND_EXECUTED;
break;
}
// don't break parsing when the char is required for the
// next argument
breakParsing = false;
// pop the stack and return the result to the current
// command arguments
close_out_params();
// don't stringify the json in case of a string to avoid
// doublequotes
if (lastResult.isStr()) {
curarg = lastResult.get_str();
} else {
curarg = lastResult.write(2);
}
// if we have a non empty result, use it as stack
// argument otherwise as general result
if (curarg.size()) {
if (stack.size()) {
add_to_current_stack(curarg);
} else {
strResult = curarg;
}
}
curarg.clear();
// assume eating space state
state = STATE_EATING_SPACES;
}
if (breakParsing) {
break;
}
}
// FALLTHROUGH
case STATE_ARGUMENT: // In or after argument
case STATE_EATING_SPACES_IN_ARG:
case STATE_EATING_SPACES_IN_BRACKETS:
case STATE_EATING_SPACES: // Handle runs of whitespace
switch (ch) {
case '"':
state = STATE_DOUBLEQUOTED;
break;
case '\'':
state = STATE_SINGLEQUOTED;
break;
case '\\':
state = STATE_ESCAPE_OUTER;
break;
case '(':
case ')':
case '\n':
if (state == STATE_EATING_SPACES_IN_ARG) {
throw std::runtime_error("Invalid Syntax");
}
if (state == STATE_ARGUMENT) {
if (ch == '(' && stack.size() &&
stack.back().size() > 0) {
if (nDepthInsideSensitive) {
++nDepthInsideSensitive;
}
stack.push_back(std::vector<std::string>());
}
// don't allow commands after executed commands on
// baselevel
if (!stack.size()) {
throw std::runtime_error("Invalid Syntax");
}
add_to_current_stack(curarg);
curarg.clear();
state = STATE_EATING_SPACES_IN_BRACKETS;
}
if ((ch == ')' || ch == '\n') && stack.size() > 0) {
if (fExecute) {
// Convert argument list to JSON objects in
// method-dependent way, and pass it along with
// the method name to the dispatcher.
UniValue params = RPCConvertValues(
stack.back()[0],
std::vector<std::string>(
stack.back().begin() + 1,
stack.back().end()));
std::string method = stack.back()[0];
std::string uri;
#ifdef ENABLE_WALLET
if (wallet_model) {
QByteArray encodedName =
QUrl::toPercentEncoding(
wallet_model->getWalletName());
uri = "/wallet/" +
std::string(encodedName.constData(),
encodedName.length());
}
#endif
GlobalConfig config;
assert(node);
lastResult = node->executeRpc(config, method,
params, uri);
}
state = STATE_COMMAND_EXECUTED;
curarg.clear();
}
break;
case ' ':
case ',':
case '\t':
if (state == STATE_EATING_SPACES_IN_ARG &&
curarg.empty() && ch == ',') {
throw std::runtime_error("Invalid Syntax");
} else if (state == STATE_ARGUMENT) {
// Space ends argument
add_to_current_stack(curarg);
curarg.clear();
}
if ((state == STATE_EATING_SPACES_IN_BRACKETS ||
state == STATE_ARGUMENT) &&
ch == ',') {
state = STATE_EATING_SPACES_IN_ARG;
break;
}
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
if (ch != '"' && ch != '\\') {
// keep '\' for everything but the quote and '\' itself
curarg += '\\';
}
curarg += ch;
state = STATE_DOUBLEQUOTED;
break;
}
}
if (pstrFilteredOut) {
if (STATE_COMMAND_EXECUTED == state) {
assert(!stack.empty());
close_out_params();
}
*pstrFilteredOut = strCommand;
for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) {
pstrFilteredOut->replace(i->first, i->second - i->first, "(…)");
}
}
// final state
switch (state) {
case STATE_COMMAND_EXECUTED:
if (lastResult.isStr()) {
strResult = lastResult.get_str();
} else {
strResult = lastResult.write(2);
}
// FALLTHROUGH
case STATE_ARGUMENT:
case STATE_EATING_SPACES:
return true;
default: // ERROR to end in one of the other states
return false;
}
}
void RPCExecutor::request(const QString &command,
const WalletModel *wallet_model) {
try {
std::string result;
std::string executableCommand = command.toStdString() + "\n";
// Catch the console-only-help command before RPC call is executed and
// reply with help text as-if a RPC reply.
if (executableCommand == "help-console\n") {
Q_EMIT reply(
RPCConsole::CMD_REPLY,
QString(("\n"
"This console accepts RPC commands using the standard "
"syntax.\n"
" example: getblockhash 0\n\n"
"This console can also accept RPC commands using "
"parenthesized syntax.\n"
" example: getblockhash(0)\n\n"
"Commands may be nested when specified with the "
"parenthesized syntax.\n"
" example: getblock(getblockhash(0) 1)\n\n"
"A space or a comma can be used to delimit arguments "
"for either syntax.\n"
" example: getblockhash 0\n"
" getblockhash,0\n\n"
"Named results can be queried with a non-quoted key "
"string in brackets.\n"
" example: getblock(getblockhash(0) true)[tx]\n\n"
"Results without keys can be queried using an integer "
"in brackets.\n"
" example: "
"getblock(getblockhash(0),true)[tx][0]\n\n")));
return;
}
if (!RPCConsole::RPCExecuteCommandLine(
m_node, result, executableCommand, nullptr, wallet_model)) {
Q_EMIT reply(RPCConsole::CMD_ERROR,
QString("Parse error: unbalanced ' or \""));
return;
}
Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
} catch (UniValue &objError) {
// Nice formatting for standard-format error
try {
int code = find_value(objError, "code").get_int();
std::string message = find_value(objError, "message").get_str();
Q_EMIT reply(RPCConsole::CMD_ERROR,
QString::fromStdString(message) + " (code " +
QString::number(code) + ")");
} catch (const std::runtime_error &) {
// raised when converting to invalid type, i.e. missing code or
// message. Show raw JSON object.
Q_EMIT reply(RPCConsole::CMD_ERROR,
QString::fromStdString(objError.write()));
}
} catch (const std::exception &e) {
Q_EMIT reply(RPCConsole::CMD_ERROR,
QString("Error: ") + QString::fromStdString(e.what()));
}
}
RPCConsole::RPCConsole(interfaces::Node &node,
const PlatformStyle *_platformStyle, QWidget *parent)
: QWidget(parent), m_node(node), ui(new Ui::RPCConsole),
platformStyle(_platformStyle) {
ui->setupUi(this);
QSettings settings;
if (!restoreGeometry(
settings.value("RPCConsoleWindowGeometry").toByteArray())) {
// Restore failed (perhaps missing setting), center the window
move(QGuiApplication::primaryScreen()->availableGeometry().center() -
frameGeometry().center());
}
QChar nonbreaking_hyphen(8209);
ui->dataDir->setToolTip(
ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(
QString(nonbreaking_hyphen) + "blocksdir"));
ui->openDebugLogfileButton->setToolTip(
ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
if (platformStyle->getImagesOnButtons()) {
ui->openDebugLogfileButton->setIcon(
platformStyle->SingleColorIcon(":/icons/export"));
}
ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
ui->fontBiggerButton->setIcon(
platformStyle->SingleColorIcon(":/icons/fontbigger"));
ui->fontSmallerButton->setIcon(
platformStyle->SingleColorIcon(":/icons/fontsmaller"));
// Install event filter for up and down arrow
ui->lineEdit->installEventFilter(this);
ui->messagesWidget->installEventFilter(this);
connect(ui->clearButton, &QPushButton::clicked, this, &RPCConsole::clear);
connect(ui->fontBiggerButton, &QPushButton::clicked, this,
&RPCConsole::fontBigger);
connect(ui->fontSmallerButton, &QPushButton::clicked, this,
&RPCConsole::fontSmaller);
connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph,
&TrafficGraphWidget::clear);
// disable the wallet selector by default
ui->WalletSelector->setVisible(false);
ui->WalletSelectorLabel->setVisible(false);
// set library version labels
#ifdef ENABLE_WALLET
ui->berkeleyDBVersion->setText(DbEnv::version(nullptr, nullptr, nullptr));
#else
ui->label_berkeleyDBVersion->hide();
ui->berkeleyDBVersion->hide();
#endif
// Register RPC timer interface
rpcTimerInterface = new QtRPCTimerInterface();
// avoid accidentally overwriting an existing, non QTThread
// based timer interface
m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface);
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
consoleFontSize =
settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize())
.toInt();
clear();
}
RPCConsole::~RPCConsole() {
QSettings settings;
settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
m_node.rpcUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
}
bool RPCConsole::eventFilter(QObject *obj, QEvent *event) {
// Special key handling
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyevt = static_cast<QKeyEvent *>(event);
int key = keyevt->key();
Qt::KeyboardModifiers mod = keyevt->modifiers();
switch (key) {
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) {
QApplication::postEvent(ui->messagesWidget,
new QKeyEvent(*keyevt));
return true;
}
break;
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;
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;
}
}
}
return QWidget::eventFilter(obj, event);
}
void RPCConsole::setClientModel(ClientModel *model) {
clientModel = model;
+
+ bool wallet_enabled{false};
+#ifdef ENABLE_WALLET
+ wallet_enabled = WalletModel::isWalletEnabled();
+#endif // ENABLE_WALLET
+ if (model && !wallet_enabled) {
+ // Show warning, for example if this is a prerelease version
+ connect(model, &ClientModel::alertsChanged, this,
+ &RPCConsole::updateAlerts);
+ updateAlerts(model->getStatusBarWarnings());
+ }
+
ui->trafficGraph->setClientModel(model);
if (model && clientModel->getPeerTableModel() &&
clientModel->getBanTableModel()) {
// Keep up to date with client
setNumConnections(model->getNumConnections());
connect(model, &ClientModel::numConnectionsChanged, this,
&RPCConsole::setNumConnections);
interfaces::Node &node = clientModel->node();
setNumBlocks(node.getNumBlocks(),
QDateTime::fromTime_t(node.getLastBlockTime()),
node.getVerificationProgress(), false);
connect(model, &ClientModel::numBlocksChanged, this,
&RPCConsole::setNumBlocks);
updateNetworkState();
connect(model, &ClientModel::networkActiveChanged, this,
&RPCConsole::setNetworkActive);
updateTrafficStats(node.getTotalBytesRecv(), node.getTotalBytesSent());
connect(model, &ClientModel::bytesChanged, this,
&RPCConsole::updateTrafficStats);
connect(model, &ClientModel::mempoolSizeChanged, this,
&RPCConsole::setMempoolSize);
// 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::ExtendedSelection);
ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->peerWidget->setColumnWidth(PeerTableModel::Address,
ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion,
SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
// create peer table context menu actions
QAction *disconnectAction = new QAction(tr("&Disconnect"), this);
QAction *banAction1h =
new QAction(tr("Ban for") + " " + tr("1 &hour"), this);
QAction *banAction24h =
new QAction(tr("Ban for") + " " + tr("1 &day"), this);
QAction *banAction7d =
new QAction(tr("Ban for") + " " + tr("1 &week"), this);
QAction *banAction365d =
new QAction(tr("Ban for") + " " + tr("1 &year"), this);
// create peer table context menu
peersTableContextMenu = new QMenu(this);
peersTableContextMenu->addAction(disconnectAction);
peersTableContextMenu->addAction(banAction1h);
peersTableContextMenu->addAction(banAction24h);
peersTableContextMenu->addAction(banAction7d);
peersTableContextMenu->addAction(banAction365d);
connect(banAction1h, &QAction::triggered,
[this] { banSelectedNode(60 * 60); });
connect(banAction24h, &QAction::triggered,
[this] { banSelectedNode(60 * 60 * 24); });
connect(banAction7d, &QAction::triggered,
[this] { banSelectedNode(60 * 60 * 24 * 7); });
connect(banAction365d, &QAction::triggered,
[this] { banSelectedNode(60 * 60 * 24 * 365); });
// peer table context menu signals
connect(ui->peerWidget, &QTableView::customContextMenuRequested, this,
&RPCConsole::showPeersTableContextMenu);
connect(disconnectAction, &QAction::triggered, this,
&RPCConsole::disconnectSelectedNode);
// peer table signal handling - update peer details when selecting new
// node
connect(ui->peerWidget->selectionModel(),
&QItemSelectionModel::selectionChanged, this,
&RPCConsole::peerSelected);
// peer table signal handling - update peer details when new nodes are
// added to the model
connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged,
this, &RPCConsole::peerLayoutChanged);
// peer table signal handling - cache selected node ids
connect(model->getPeerTableModel(),
&PeerTableModel::layoutAboutToBeChanged, this,
&RPCConsole::peerLayoutAboutToChange);
// 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);
ui->banlistWidget->setColumnWidth(BanTableModel::Address,
BANSUBNET_COLUMN_WIDTH);
ui->banlistWidget->setColumnWidth(BanTableModel::Bantime,
BANTIME_COLUMN_WIDTH);
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
// create ban table context menu action
QAction *unbanAction = new QAction(tr("&Unban"), this);
// create ban table context menu
banTableContextMenu = new QMenu(this);
banTableContextMenu->addAction(unbanAction);
// ban table context menu signals
connect(ui->banlistWidget, &QTableView::customContextMenuRequested,
this, &RPCConsole::showBanTableContextMenu);
connect(unbanAction, &QAction::triggered, this,
&RPCConsole::unbanSelectedNode);
// ban table signal handling - clear peer details when clicking a peer
// in the ban table
connect(ui->banlistWidget, &QTableView::clicked, this,
&RPCConsole::clearSelectedNode);
// ban table signal handling - ensure ban table is shown or hidden (if
// empty)
connect(model->getBanTableModel(), &BanTableModel::layoutChanged, this,
&RPCConsole::showOrHideBanTableIfRequired);
showOrHideBanTableIfRequired();
// Provide initial values
ui->clientVersion->setText(model->formatFullVersion());
ui->clientUserAgent->setText(model->formatSubVersion());
ui->dataDir->setText(model->dataDir());
ui->blocksDir->setText(model->blocksDir());
ui->startupTime->setText(model->formatClientStartupTime());
ui->networkName->setText(
QString::fromStdString(Params().NetworkIDString()));
// Setup autocomplete and attach it
QStringList wordList;
std::vector<std::string> commandList = m_node.listRpcCommands();
for (size_t i = 0; i < commandList.size(); ++i) {
wordList << commandList[i].c_str();
wordList << ("help " + commandList[i]).c_str();
}
wordList << "help-console";
wordList.sort();
autoCompleter = new QCompleter(wordList, this);
autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
// ui->lineEdit is initially disabled because running commands is only
// possible from now on.
ui->lineEdit->setEnabled(true);
ui->lineEdit->setCompleter(autoCompleter);
autoCompleter->popup()->installEventFilter(this);
// Start thread to execute RPC commands.
startExecutor();
}
if (!model) {
// Client model is being set to 0, this means shutdown() is about to be
// called.
thread.quit();
thread.wait();
}
}
#ifdef ENABLE_WALLET
void RPCConsole::addWallet(WalletModel *const walletModel) {
// use name for text and wallet model for internal data object (to allow to
// move to a wallet id later)
ui->WalletSelector->addItem(walletModel->getDisplayName(),
QVariant::fromValue(walletModel));
if (ui->WalletSelector->count() == 2 && !isVisible()) {
// First wallet added, set to default so long as the window isn't
// presently visible (and potentially in use)
ui->WalletSelector->setCurrentIndex(1);
}
if (ui->WalletSelector->count() > 2) {
ui->WalletSelector->setVisible(true);
ui->WalletSelectorLabel->setVisible(true);
}
}
void RPCConsole::removeWallet(WalletModel *const walletModel) {
ui->WalletSelector->removeItem(
ui->WalletSelector->findData(QVariant::fromValue(walletModel)));
if (ui->WalletSelector->count() == 2) {
ui->WalletSelector->setVisible(false);
ui->WalletSelectorLabel->setVisible(false);
}
}
#endif
static QString categoryClass(int category) {
switch (category) {
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::fontBigger() {
setFontSize(consoleFontSize + 1);
}
void RPCConsole::fontSmaller() {
setFontSize(consoleFontSize - 1);
}
void RPCConsole::setFontSize(int newSize) {
QSettings settings;
// don't allow an insane font size
if (newSize < FONT_RANGE.width() || newSize > FONT_RANGE.height()) {
return;
}
// temp. store the console content
QString str = ui->messagesWidget->toHtml();
// replace font tags size in current content
str.replace(QString("font-size:%1pt").arg(consoleFontSize),
QString("font-size:%1pt").arg(newSize));
// store the new font size
consoleFontSize = newSize;
settings.setValue(fontSizeSettingsKey, consoleFontSize);
// clear console (reset icon sizes, default stylesheet) and re-add the
// content
float oldPosFactor = 1.0 /
ui->messagesWidget->verticalScrollBar()->maximum() *
ui->messagesWidget->verticalScrollBar()->value();
clear(false);
ui->messagesWidget->setHtml(str);
ui->messagesWidget->verticalScrollBar()->setValue(
oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
}
void RPCConsole::clear(bool clearHistory) {
ui->messagesWidget->clear();
if (clearHistory) {
history.clear();
historyPtr = 0;
}
ui->lineEdit->clear();
ui->lineEdit->setFocus();
// 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),
platformStyle->SingleColorImage(ICON_MAPPING[i].source)
.scaled(QSize(consoleFontSize * 2, consoleFontSize * 2),
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Set default style sheet
QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
ui->messagesWidget->document()->setDefaultStyleSheet(
QString("table { }"
"td.time { color: #808080; font-size: %2; padding-top: 3px; } "
"td.message { font-family: %1; font-size: %2; "
"white-space:pre-wrap; } "
"td.cmd-request { color: #006060; } "
"td.cmd-error { color: red; } "
".secwarning { color: red; }"
"b { color: #006060; } ")
.arg(fixedFontInfo.family(), QString("%1pt").arg(consoleFontSize)));
#ifdef Q_OS_MAC
QString clsKey = "(⌘)-L";
#else
QString clsKey = "Ctrl-L";
#endif
message(CMD_REPLY,
(tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + "<br>" +
tr("Use up and down arrows to navigate history, and "
"%1 to clear screen.")
.arg("<b>" + clsKey + "</b>") +
"<br>" +
tr("Type %1 for an overview of available commands.")
.arg("<b>help</b>") +
"<br>" +
tr("For more information on using this console type %1.")
.arg("<b>help-console</b>") +
"<br><span class=\"secwarning\"><br>" +
tr("WARNING: Scammers have been active, telling users to type "
"commands here, stealing their wallet contents. Do not use "
"this console without fully understanding the ramifications "
"of a command.") +
"</span>"),
true);
}
void RPCConsole::keyPressEvent(QKeyEvent *event) {
if (windowType() != Qt::Widget && event->key() == Qt::Key_Escape) {
close();
}
}
void RPCConsole::message(int category, const QString &message, bool html) {
QTime time = QTime::currentTime();
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, false);
}
out += "</td></tr></table>";
ui->messagesWidget->append(out);
}
void RPCConsole::updateNetworkState() {
QString connections =
QString::number(clientModel->getNumConnections()) + " (";
connections += tr("In:") + " " +
QString::number(clientModel->getNumConnections(
ClientModel::CONNECTIONS_IN)) +
" / ";
connections += tr("Out:") + " " +
QString::number(clientModel->getNumConnections(
ClientModel::CONNECTIONS_OUT)) +
")";
if (!clientModel->node().getNetworkActive()) {
connections += " (" + tr("Network activity disabled") + ")";
}
ui->numberOfConnections->setText(connections);
}
void RPCConsole::setNumConnections(int count) {
if (!clientModel) {
return;
}
updateNetworkState();
}
void RPCConsole::setNetworkActive(bool networkActive) {
updateNetworkState();
}
void RPCConsole::setNumBlocks(int count, const QDateTime &blockDate,
double nVerificationProgress, bool headers) {
if (!headers) {
ui->numberOfBlocks->setText(QString::number(count));
ui->lastBlockTime->setText(blockDate.toString());
}
}
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");
}
}
void RPCConsole::on_lineEdit_returnPressed() {
QString cmd = ui->lineEdit->text();
if (!cmd.isEmpty()) {
std::string strFilteredCmd;
try {
std::string dummy;
if (!RPCParseCommandLine(nullptr, dummy, cmd.toStdString(), false,
&strFilteredCmd)) {
// Failed to parse command, so we cannot even filter it for the
// history
throw std::runtime_error("Invalid command line");
}
} catch (const std::exception &e) {
QMessageBox::critical(this, "Error",
QString("Error: ") +
QString::fromStdString(e.what()));
return;
}
ui->lineEdit->clear();
cmdBeforeBrowsing = QString();
#ifdef ENABLE_WALLET
WalletModel *wallet_model{nullptr};
const int wallet_index = ui->WalletSelector->currentIndex();
if (wallet_index > 0) {
wallet_model = ui->WalletSelector->itemData(wallet_index)
.value<WalletModel *>();
}
if (m_last_wallet_model != wallet_model) {
if (wallet_model) {
message(CMD_REQUEST, tr("Executing command using \"%1\" wallet")
.arg(wallet_model->getWalletName()));
} else {
message(CMD_REQUEST,
tr("Executing command without any wallet"));
}
m_last_wallet_model = wallet_model;
}
#endif
message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
Q_EMIT cmdRequest(cmd, m_last_wallet_model);
cmd = QString::fromStdString(strFilteredCmd);
// Remove command, if already in history
history.removeOne(cmd);
// 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();
// Scroll console view to end
scrollToEnd();
}
}
void RPCConsole::browseHistory(int offset) {
// store current text when start browsing through the history
if (historyPtr == history.size()) {
cmdBeforeBrowsing = ui->lineEdit->text();
}
historyPtr += offset;
if (historyPtr < 0) {
historyPtr = 0;
}
if (historyPtr > history.size()) {
historyPtr = history.size();
}
QString cmd;
if (historyPtr < history.size()) {
cmd = history.at(historyPtr);
} else if (!cmdBeforeBrowsing.isNull()) {
cmd = cmdBeforeBrowsing;
}
ui->lineEdit->setText(cmd);
}
void RPCConsole::startExecutor() {
RPCExecutor *executor = new RPCExecutor(m_node);
executor->moveToThread(&thread);
// Replies from executor object must go to this object
connect(executor, &RPCExecutor::reply, this,
static_cast<void (RPCConsole::*)(int, const QString &)>(
&RPCConsole::message));
// Requests from this object must go to executor
connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
// Make sure executor object is deleted in its own thread
connect(&thread, &QThread::finished, executor, &RPCExecutor::deleteLater);
// Default implementation of QThread::run() simply spins up an event loop in
// the thread, which is what we want.
thread.start();
}
void RPCConsole::on_tabWidget_currentChanged(int index) {
if (ui->tabWidget->widget(index) == ui->tab_console) {
ui->lineEdit->setFocus();
} else if (ui->tabWidget->widget(index) != ui->tab_peers) {
clearSelectedNode();
}
}
void RPCConsole::on_openDebugLogfileButton_clicked() {
GUIUtil::openDebugLogfile();
}
void RPCConsole::scrollToEnd() {
QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar();
scrollbar->setValue(scrollbar->maximum());
}
void RPCConsole::on_sldGraphRange_valueChanged(int value) {
const int multiplier = 5; // each position on the slider represents 5 min
int mins = value * multiplier;
setTrafficGraphRange(mins);
}
void RPCConsole::setTrafficGraphRange(int mins) {
ui->trafficGraph->setGraphRangeMins(mins);
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(mins * 60));
}
void RPCConsole::updateTrafficStats(quint64 totalBytesIn,
quint64 totalBytesOut) {
ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
}
void RPCConsole::peerSelected(const QItemSelection &selected,
const QItemSelection &deselected) {
Q_UNUSED(deselected);
if (!clientModel || !clientModel->getPeerTableModel() ||
selected.indexes().isEmpty()) {
return;
}
const CNodeCombinedStats *stats =
clientModel->getPeerTableModel()->getNodeStats(
selected.indexes().first().row());
if (stats) {
updateNodeDetail(stats);
}
}
void RPCConsole::peerLayoutAboutToChange() {
QModelIndexList selected =
ui->peerWidget->selectionModel()->selectedIndexes();
cachedNodeids.clear();
for (int i = 0; i < selected.size(); i++) {
const CNodeCombinedStats *stats =
clientModel->getPeerTableModel()->getNodeStats(
selected.at(i).row());
cachedNodeids.append(stats->nodeStats.nodeid);
}
}
void RPCConsole::peerLayoutChanged() {
if (!clientModel || !clientModel->getPeerTableModel()) {
return;
}
const CNodeCombinedStats *stats = nullptr;
bool fUnselect = false;
bool fReselect = false;
// no node selected yet
if (cachedNodeids.empty()) {
return;
}
// find the currently selected row
int selectedRow = -1;
QModelIndexList selectedModelIndex =
ui->peerWidget->selectionModel()->selectedIndexes();
if (!selectedModelIndex.isEmpty()) {
selectedRow = selectedModelIndex.first().row();
}
// 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)
int detailNodeRow =
clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.first());
if (detailNodeRow < 0) {
// detail node disappeared from table (node disconnected)
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);
}
if (fUnselect && selectedRow >= 0) {
clearSelectedNode();
}
if (fReselect) {
for (int i = 0; i < cachedNodeids.size(); i++) {
ui->peerWidget->selectRow(
clientModel->getPeerTableModel()->getRowByNodeId(
cachedNodeids.at(i)));
}
}
if (stats) {
updateNodeDetail(stats);
}
}
void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) {
// update the detail ui with latest node information
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) +
" ");
peerAddrDetails +=
tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
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(GetSystemTimeInSeconds() -
stats->nodeStats.nLastSend)
: tr("never"));
ui->peerLastRecv->setText(
stats->nodeStats.nLastRecv
? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() -
stats->nodeStats.nLastRecv)
: tr("never"));
ui->peerBytesSent->setText(
GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
ui->peerBytesRecv->setText(
GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
ui->peerConnTime->setText(GUIUtil::formatDurationStr(
GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(
GUIUtil::formatPingTime(stats->nodeStats.m_ping_usec));
ui->peerPingWait->setText(
GUIUtil::formatPingTime(stats->nodeStats.m_ping_wait_usec));
ui->peerMinPing->setText(
GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_usec));
ui->timeoffset->setText(
GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
ui->peerVersion->setText(
QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
ui->peerSubversion->setText(
QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound")
: tr("Outbound"));
ui->peerHeight->setText(
QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
ui->peerWhitelisted->setText(
stats->nodeStats.m_legacyWhitelisted ? tr("Yes") : tr("No"));
// 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"));
}
// 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"));
}
}
ui->detailWidget->show();
}
void RPCConsole::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
}
void RPCConsole::showEvent(QShowEvent *event) {
QWidget::showEvent(event);
if (!clientModel || !clientModel->getPeerTableModel()) {
return;
}
// start PeerTableModel auto refresh
clientModel->getPeerTableModel()->startAutoRefresh();
}
void RPCConsole::hideEvent(QHideEvent *event) {
QWidget::hideEvent(event);
if (!clientModel || !clientModel->getPeerTableModel()) {
return;
}
// stop PeerTableModel auto refresh
clientModel->getPeerTableModel()->stopAutoRefresh();
}
void RPCConsole::showPeersTableContextMenu(const QPoint &point) {
QModelIndex index = ui->peerWidget->indexAt(point);
if (index.isValid()) {
peersTableContextMenu->exec(QCursor::pos());
}
}
void RPCConsole::showBanTableContextMenu(const QPoint &point) {
QModelIndex index = ui->banlistWidget->indexAt(point);
if (index.isValid()) {
banTableContextMenu->exec(QCursor::pos());
}
}
void RPCConsole::disconnectSelectedNode() {
// Get selected peer addresses
QList<QModelIndex> nodes =
GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
for (int i = 0; i < nodes.count(); i++) {
// Get currently selected peer address
NodeId id = nodes.at(i).data().toLongLong();
// Find the node, disconnect it and clear the selected node
if (m_node.disconnect(id)) {
clearSelectedNode();
}
}
}
void RPCConsole::banSelectedNode(int bantime) {
if (!clientModel) {
return;
}
// Get selected peer addresses
QList<QModelIndex> nodes =
GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
for (int i = 0; i < nodes.count(); i++) {
// Get currently selected peer address
NodeId id = nodes.at(i).data().toLongLong();
// Get currently selected peer address
int detailNodeRow =
clientModel->getPeerTableModel()->getRowByNodeId(id);
if (detailNodeRow < 0) {
return;
}
// Find possible nodes, ban it and clear the selected node
const CNodeCombinedStats *stats =
clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
if (stats) {
m_node.ban(stats->nodeStats.addr, bantime);
m_node.disconnect(stats->nodeStats.addr);
}
}
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
}
void RPCConsole::unbanSelectedNode() {
if (!clientModel) {
return;
}
// Get selected ban addresses
QList<QModelIndex> nodes =
GUIUtil::getEntryData(ui->banlistWidget, BanTableModel::Address);
for (int i = 0; i < nodes.count(); i++) {
// Get currently selected ban address
QString strNode = nodes.at(i).data().toString();
CSubNet possibleSubnet;
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
if (possibleSubnet.IsValid() && m_node.unban(possibleSubnet)) {
clientModel->getBanTableModel()->refresh();
}
}
}
void RPCConsole::clearSelectedNode() {
ui->peerWidget->selectionModel()->clearSelection();
cachedNodeids.clear();
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}
void RPCConsole::showOrHideBanTableIfRequired() {
if (!clientModel) {
return;
}
bool visible = clientModel->getBanTableModel()->shouldShow();
ui->banlistWidget->setVisible(visible);
ui->banHeading->setVisible(visible);
}
void RPCConsole::setTabFocus(enum TabTypes tabType) {
ui->tabWidget->setCurrentIndex(tabType);
}
QString RPCConsole::tabTitle(TabTypes tab_type) const {
return ui->tabWidget->tabText(tab_type);
}
+
+void RPCConsole::updateAlerts(const QString &warnings) {
+ this->ui->label_alerts->setVisible(!warnings.isEmpty());
+ this->ui->label_alerts->setText(warnings);
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 9fceaf6c9..02a7ee5bc 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -1,181 +1,184 @@
// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_QT_RPCCONSOLE_H
#define BITCOIN_QT_RPCCONSOLE_H
#include <qt/guiutil.h>
#include <qt/peertablemodel.h>
#include <net.h>
#include <QCompleter>
#include <QThread>
#include <QWidget>
class ClientModel;
class PlatformStyle;
class RPCTimerInterface;
class WalletModel;
namespace interfaces {
class Node;
}
namespace Ui {
class RPCConsole;
}
QT_BEGIN_NAMESPACE
class QMenu;
class QItemSelection;
QT_END_NAMESPACE
/** Local Bitcoin RPC console. */
class RPCConsole : public QWidget {
Q_OBJECT
public:
explicit RPCConsole(interfaces::Node &node,
const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
static bool
RPCParseCommandLine(interfaces::Node *node, std::string &strResult,
const std::string &strCommand, bool fExecute,
std::string *const pstrFilteredOut = nullptr,
const WalletModel *wallet_model = nullptr);
static bool
RPCExecuteCommandLine(interfaces::Node &node, std::string &strResult,
const std::string &strCommand,
std::string *const pstrFilteredOut = nullptr,
const WalletModel *wallet_model = nullptr) {
return RPCParseCommandLine(&node, strResult, strCommand, true,
pstrFilteredOut, wallet_model);
}
void setClientModel(ClientModel *model);
void addWallet(WalletModel *const walletModel);
void removeWallet(WalletModel *const walletModel);
enum MessageClass { MC_ERROR, MC_DEBUG, CMD_REQUEST, CMD_REPLY, CMD_ERROR };
enum TabTypes {
TAB_INFO = 0,
TAB_CONSOLE = 1,
TAB_GRAPH = 2,
TAB_PEERS = 3
};
std::vector<TabTypes> tabs() const {
return {TAB_INFO, TAB_CONSOLE, TAB_GRAPH, TAB_PEERS};
}
QString tabTitle(TabTypes tab_type) const;
protected:
virtual bool eventFilter(QObject *obj, QEvent *event) override;
void keyPressEvent(QKeyEvent *) override;
private Q_SLOTS:
void on_lineEdit_returnPressed();
void on_tabWidget_currentChanged(int index);
/** open the debug.log from the current datadir */
void on_openDebugLogfileButton_clicked();
/** change the time range of the network traffic graph */
void on_sldGraphRange_valueChanged(int value);
/** update traffic statistics */
void updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut);
void resizeEvent(QResizeEvent *event) override;
void showEvent(QShowEvent *event) override;
void hideEvent(QHideEvent *event) override;
/** Show custom context menu on Peers tab */
void showPeersTableContextMenu(const QPoint &point);
/** Show custom context menu on Bans tab */
void showBanTableContextMenu(const QPoint &point);
/** Hides ban table if no bans are present */
void showOrHideBanTableIfRequired();
/** clear the selected node */
void clearSelectedNode();
public Q_SLOTS:
void clear(bool clearHistory = true);
void fontBigger();
void fontSmaller();
void setFontSize(int newSize);
/** Append the message to the message widget */
void message(int category, const QString &msg) {
message(category, msg, false);
}
void message(int category, const QString &message, bool html);
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set network state shown in the UI */
void setNetworkActive(bool networkActive);
/** Set number of blocks and last block date shown in the UI */
void setNumBlocks(int count, const QDateTime &blockDate,
double nVerificationProgress, bool headers);
/** Set size (number of transactions and memory usage) of the mempool in the
* UI */
void setMempoolSize(long numberOfTxs, size_t dynUsage);
/** Go forward or back in history */
void browseHistory(int offset);
/** Scroll console view to end */
void scrollToEnd();
/** Handle selection of peer in peers list */
void peerSelected(const QItemSelection &selected,
const QItemSelection &deselected);
/** Handle selection caching before update */
void peerLayoutAboutToChange();
/** Handle updated peer information */
void peerLayoutChanged();
/** Disconnect a selected node on the Peers tab */
void disconnectSelectedNode();
/** Ban a selected node on the Peers tab */
void banSelectedNode(int bantime);
/** Unban a selected node on the Bans tab */
void unbanSelectedNode();
/** set which tab has the focus (is visible) */
void setTabFocus(enum TabTypes tabType);
Q_SIGNALS:
// For RPC command executor
void cmdRequest(const QString &command, const WalletModel *wallet_model);
private:
void startExecutor();
void setTrafficGraphRange(int mins);
/** show detailed information on ui about selected node */
void updateNodeDetail(const CNodeCombinedStats *stats);
enum ColumnWidths {
ADDRESS_COLUMN_WIDTH = 200,
SUBVERSION_COLUMN_WIDTH = 150,
PING_COLUMN_WIDTH = 80,
BANSUBNET_COLUMN_WIDTH = 200,
BANTIME_COLUMN_WIDTH = 250
};
interfaces::Node &m_node;
Ui::RPCConsole *const ui;
ClientModel *clientModel = nullptr;
QStringList history;
int historyPtr = 0;
QString cmdBeforeBrowsing;
QList<NodeId> cachedNodeids;
const PlatformStyle *const platformStyle;
RPCTimerInterface *rpcTimerInterface = nullptr;
QMenu *peersTableContextMenu = nullptr;
QMenu *banTableContextMenu = nullptr;
int consoleFontSize = 0;
QCompleter *autoCompleter = nullptr;
QThread thread;
WalletModel *m_last_wallet_model{nullptr};
/** Update UI with latest network info from model. */
void updateNetworkState();
+
+private Q_SLOTS:
+ void updateAlerts(const QString &warnings);
};
#endif // BITCOIN_QT_RPCCONSOLE_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Apr 27, 12:33 (20 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573553
Default Alt Text
(126 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment