From 412445afb52973eaef11875b286885761501f1ea Mon Sep 17 00:00:00 2001 From: "W. J. van der Laan" Date: Wed, 26 May 2021 15:01:14 +0200 Subject: [PATCH 01/11] Merge bitcoin-core/gui#313: qt: Optimize string concatenation by default a02c970eb001b456d74ddc30750fe8b55348ddac qt, refactor: Revert explicit including QStringBuilder (Hennadii Stepanov) 3fd3a0fc87a81d42755246830124833e9ca3f0a9 qt, build: Optimize string concatenation (Hennadii Stepanov) Pull request description: From [Qt docs](https://doc.qt.io/qt-5/qstring.html#more-efficient-string-construction): > ... multiple uses of the \[`QString`\] '+' operator usually means multiple memory allocations. When concatenating n substrings, where n > 2, there can be as many as n - 1 calls to the memory allocator. With this PR > ... the '+' will automatically be performed as the `QStringBuilder` '%' everywhere. The change in the `src/Makefile.qt.include` file does not justify submitting this PR into the main repo, IMHO. ACKs for top commit: laanwj: Code review ACK a02c970eb001b456d74ddc30750fe8b55348ddac Talkless: utACK a02c970eb001b456d74ddc30750fe8b55348ddac, built successfully on Debian Sid with Qt 5.15.2, but did not check if any displayed strings are "wrong" after refactoring. jarolrod: ACK a02c970eb001b456d74ddc30750fe8b55348ddac Tree-SHA512: cbb476ee96f27c3bd6e125efab74d8bf24bbdb4c30576b3feea45e203405f3bf5b497dd7d3e11361fc825fcbf4b893b152921a9efdeaf73b42d1865d85f0ae84 --- src/Makefile.qt.include | 2 +- src/qt/bitcoin.cpp | 9 ++++----- src/qt/guiutil.cpp | 3 +-- src/qt/optionsmodel.cpp | 3 ++- src/qt/overviewpage.cpp | 2 +- src/qt/peertablemodel.cpp | 2 +- src/qt/recentrequeststablemodel.cpp | 9 ++++++++- src/qt/test/wallettests.cpp | 2 +- src/qt/transactiondesc.cpp | 9 ++++++--- src/qt/transactiontablemodel.cpp | 6 ++++-- 10 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index c9efbe6504..a97956c48d 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -364,7 +364,7 @@ RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png) BITCOIN_RC = qt/res/dash-qt-res.rc -BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS +BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index fc66231389..52bd0767b3 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -492,8 +491,8 @@ void BitcoinApplication::handleRunawayException(const QString &message) { QMessageBox::critical( nullptr, tr("Runaway exception"), - tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) % - QLatin1String("

") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); + tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) + + QLatin1String("

") + GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); ::exit(EXIT_FAILURE); } @@ -503,8 +502,8 @@ void BitcoinApplication::handleNonFatalException(const QString& message) QMessageBox::warning( nullptr, tr("Internal error"), tr("An internal error occurred. %1 will attempt to continue safely. This is " - "an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) % - QLatin1String("

") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); + "an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) + + QLatin1String("

") + GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); } WId BitcoinApplication::getMainWinId() const diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index a67efe2552..649b009f25 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -69,7 +69,6 @@ #include #include #include -#include #include // for Qt::mightBeRichText #include #include @@ -1931,7 +1930,7 @@ QString MakeHtmlLink(const QString& source, const QString& link) { return QString(source).replace( link, - QLatin1String("") % link % QLatin1String("")); + QLatin1String("") + link + QLatin1String("")); } void PrintSlotException( diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index fb07fd662e..1758b95dbf 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -26,6 +26,7 @@ #endif #include +#include #include #include @@ -381,7 +382,7 @@ static ProxySetting GetProxySetting(QSettings &settings, const QString &name) static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_port) { - settings.setValue(name, ip_port.ip + ":" + ip_port.port); + settings.setValue(name, QString{ip_port.ip + QLatin1Char(':') + ip_port.port}); } static const QString GetDefaultProxyAddress() diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 16c2a5dfae..115ce523f7 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -469,7 +469,7 @@ void OverviewPage::updateCoinJoinProgress() ui->coinJoinProgress->setValue(progress); - QString strToolPip = ("" + tr("Overall progress") + ": %1%
" + + QString strToolPip = QString("" + tr("Overall progress") + ": %1%
" + tr("Denominated") + ": %2%
" + tr("Partially mixed") + ": %3%
" + tr("Mixed") + ": %4%
" + diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 1dfc195390..05a2d4239a 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -115,7 +115,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const return (qint64)rec->nodeStats.nodeid; case Address: // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection - return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.m_addr_name); + return QString::fromStdString((rec->nodeStats.fInbound ? "↓ " : "↑ ") + rec->nodeStats.m_addr_name); case ConnectionType: return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /* prepend_direction */ false); case Network: diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 5c9623f9ff..c28fef6490 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -17,6 +17,9 @@ #include +#include +#include + RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) { @@ -126,7 +129,11 @@ void RecentRequestsTableModel::updateAmountColumnTitle() /** Gets title for amount column including current display unit if optionsModel reference available. */ QString RecentRequestsTableModel::getAmountTitle() { - return (this->walletModel->getOptionsModel() != nullptr) ? tr("Requested") + " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : ""; + if (!walletModel->getOptionsModel()) return {}; + return tr("Requested") + + QLatin1String(" (") + + BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + + QLatin1Char(')'); } QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 15140e9645..3a8b297037 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -201,7 +201,7 @@ void TestGUI(interfaces::Node& node) QCOMPARE(uri.count("amount=0.00000001"), 2); QCOMPARE(receiveRequestDialog->QObject::findChild("amount_tag")->text(), QString("Amount:")); - QCOMPARE(receiveRequestDialog->QObject::findChild("amount_content")->text(), QString("0.00000001 ") + BitcoinUnits::name(unit)); + QCOMPARE(receiveRequestDialog->QObject::findChild("amount_content")->text(), QString::fromStdString("0.00000001 ") + BitcoinUnits::name(unit)); QCOMPARE(uri.count("label=TEST_LABEL_1"), 2); QCOMPARE(receiveRequestDialog->QObject::findChild("label_tag")->text(), QString("Label:")); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 0e89ffe556..2f90ca679f 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -26,6 +26,8 @@ #include #include +#include + QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks) { if (!status.is_final) @@ -44,19 +46,20 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i bool fChainLocked = status.is_chainlocked; if (nDepth == 0) { - strTxStatus = tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + (status.is_abandoned ? ", "+tr("abandoned") : ""); + const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()}; + strTxStatus = tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + abandoned; } else if (!fChainLocked && nDepth < 6) { strTxStatus = tr("%1/unconfirmed").arg(nDepth); } else { strTxStatus = tr("%1 confirmations").arg(nDepth); if (fChainLocked) { - strTxStatus += ", " + tr("locked via ChainLocks"); + strTxStatus += QLatin1String(", ") + tr("locked via ChainLocks"); return strTxStatus; } } if (status.is_islocked) { - strTxStatus += ", " + tr("verified via InstantSend"); + strTxStatus += QLatin1String(", ") + tr("verified via InstantSend"); } return strTxStatus; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 20ac423b1c..0a7b0066c3 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -466,9 +468,9 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const { QString watchAddress; - if (tooltip) { + if (tooltip && wtx->involvesWatchAddress) { // Mark transactions involving watch-only addresses by adding " (watch-only)" - watchAddress = wtx->involvesWatchAddress ? QString(" (") + tr("watch-only") + QString(")") : ""; + watchAddress = QLatin1String(" (") + tr("watch-only") + QLatin1Char(')'); } switch(wtx->type) From c858325d409ac851eb708b4be6b160f9c8420841 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 27 May 2021 15:26:58 +0300 Subject: [PATCH 02/11] Merge bitcoin-core/gui#346: English translations update df4c81fda490e556775f6006f3d4f7d54f61073b English translations update (Hennadii Stepanov) bfb53ddda9a31bbeb8697e65ff9987e61dac136f scripted-diff: Fix ellipsis after pr20773 (Hennadii Stepanov) Pull request description: Update for Transifex. After changing translator comments in #332 this update will show if Transifex triggers strings to be re-translated. ACKs for top commit: laanwj: ACK df4c81fda490e556775f6006f3d4f7d54f61073b jarolrod: ACK df4c81fda490e556775f6006f3d4f7d54f61073b Tree-SHA512: 1e54812bc04db6ae39e0b4d735b220ed8730a9941b17a0a2d09e21bcdd08e829adba86c35cf43c9be5e492ccb13e53a90149fcd7d6c0f5fdd022b978a1ff785c --- src/wallet/load.cpp | 2 +- src/wallet/wallet.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index f5091b3794..6e53e7ea10 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -112,7 +112,7 @@ bool LoadWallets(interfaces::Chain& chain, interfaces::CoinJoin::Loader& coinjoi if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) { continue; } - chain.initMessage(_("Loading wallet...").translated); + chain.initMessage(_("Loading wallet…").translated); std::shared_ptr pwallet = database ? CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), options.create_flags, error_string, warnings) : nullptr; if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n"))); if (!pwallet) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 14ba64998d..fbe833a627 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -238,7 +238,7 @@ std::shared_ptr LoadWalletInternal(interfaces::Chain& chain, interfaces return nullptr; } - chain.initMessage(_("Loading wallet...").translated); + chain.initMessage(_("Loading wallet…").translated); std::shared_ptr wallet = CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), options.create_flags, error, warnings); if (!wallet) { error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error; @@ -304,7 +304,7 @@ std::shared_ptr CreateWallet(interfaces::Chain& chain, interfaces::Coin } // Make the wallet - chain.initMessage(_("Loading wallet...").translated); + chain.initMessage(_("Loading wallet…").translated); std::shared_ptr wallet = CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), wallet_creation_flags, error, warnings); if (!wallet) { error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error; From 69a1305978a65978feae17e1a5715b4b70f82e91 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 31 May 2021 19:34:28 +0300 Subject: [PATCH 03/11] Merge bitcoin-core/gui#309: Add access to the Peers tab from the network icon d29ea72393ac1d9b32a6976062e9c9fb75876295 gui: Add access to the Peers tab from the network icon (Hennadii Stepanov) Pull request description: This PR add a small context menu to the network activity icon that provides an access to the Peers tab: ![gui-network-icon](https://user-images.githubusercontent.com/32963518/116794314-d64b9b80-aad4-11eb-89ca-7f75c7442ba8.gif) Closes #93. ACKs for top commit: Sjors: re-ACK d29ea72393ac1d9b32a6976062e9c9fb75876295 kristapsk: re-ACK d29ea72393ac1d9b32a6976062e9c9fb75876295 promag: Code review ACK d29ea72393ac1d9b32a6976062e9c9fb75876295. Tree-SHA512: dd871415fe514a19c6a22100d58f31954d9e55b80585d5a3f26e17a8d51dadf912441786fc0d23beabd812f1b501658fec1dbe345cd41beae5832a8eda890f77 --- src/qt/bitcoingui.cpp | 37 +++++++++++++++++++++++++++++++------ src/qt/bitcoingui.h | 6 ++++-- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 5191b1d17d..cc8af5afc9 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -211,8 +212,6 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const NetworkStyle* networkStyle, // Subscribe to notifications from core subscribeToCoreSignals(); - // Jump to peers tab by clicking on connections icon - connect(labelConnectionsIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showPeers); connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked, [this] { openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK); }); @@ -812,8 +811,11 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH } // Keep up to date with client - updateNetworkState(); + setNetworkActive(m_node.getNetworkActive()); setNumConnections(_clientModel->getNumConnections()); + connect(labelConnectionsIcon, &GUIUtil::ClickableLabel::clicked, [this] { + GUIUtil::PopupMenu(m_network_context_menu, QCursor::pos()); + }); connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections); connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive); @@ -1270,14 +1272,21 @@ void BitcoinGUI::updateNetworkState() nCountPrev = count; fNetworkActivePrev = fNetworkActive; + QString tooltip; if (fNetworkActive) { - labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Dash network", "", count)); + //: A substring of the tooltip. + tooltip = tr("%n active connection(s) to Dash network", "", count); } else { - labelConnectionsIcon->setToolTip(tr("Network activity disabled")); + tooltip = tr("Network activity disabled"); icon = "connect_4"; color = GUIUtil::ThemedColor::RED; } + // Don't word-wrap this (fixed-width) tooltip + tooltip = QLatin1String("") + tooltip + QLatin1String("
") + + //: A substring of the tooltip. "More actions" are available via the context menu. + tr("Click for more actions.") + QLatin1String("
"); + if (fNetworkActive && count == 0) { startConnectingAnimation(); } @@ -1285,6 +1294,7 @@ void BitcoinGUI::updateNetworkState() stopConnectingAnimation(); labelConnectionsIcon->setPixmap(GUIUtil::getIcon(icon, color).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); } + labelConnectionsIcon->setToolTip(tooltip); } void BitcoinGUI::setNumConnections(int count) @@ -1292,9 +1302,24 @@ void BitcoinGUI::setNumConnections(int count) updateNetworkState(); } -void BitcoinGUI::setNetworkActive(bool networkActive) +void BitcoinGUI::setNetworkActive(bool network_active) { updateNetworkState(); + m_network_context_menu->clear(); + m_network_context_menu->addAction( + //: A context menu item. The "Peers tab" is an element of the "Node window". + tr("Show Peers tab"), + [this] { + rpcConsole->setTabFocus(RPCConsole::TabTypes::PEERS); + showDebugWindow(); + }); + m_network_context_menu->addAction( + network_active ? + //: A context menu item. + tr("Disable network activity") : + //: A context menu item. The network activity was disabled previously. + tr("Enable network activity"), + [this, new_state = !network_active] { m_node.setNetworkActive(new_state); }); } void BitcoinGUI::updateHeadersSyncProgressLabel() diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 5831ed3715..7b86531fbe 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,6 @@ class QAction; class QButtonGroup; class QComboBox; class QDateTime; -class QMenu; class QProgressBar; class QProgressDialog; class QToolButton; @@ -190,6 +190,8 @@ private: ModalOverlay* modalOverlay = nullptr; QButtonGroup* tabGroup = nullptr; + QMenu* m_network_context_menu = new QMenu(this); + #ifdef Q_OS_MAC CAppNapInhibitor* m_app_nap_inhibitor = nullptr; #endif @@ -264,7 +266,7 @@ public Q_SLOTS: /** Set number of connections shown in the UI */ void setNumConnections(int count); /** Set network state shown in the UI */ - void setNetworkActive(bool networkActive); + void setNetworkActive(bool network_active); /** Get restart command-line parameters and request restart */ void handleRestart(QStringList args); /** Set number of blocks and last block date shown in the UI */ From 19310646e0953f179ffaa9ebd6f0b29305b549fd Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 31 May 2021 23:41:04 +0300 Subject: [PATCH 04/11] Merge bitcoin-core/gui#331: Make RPC console welcome message translation-friendly 0f3d955a38fe59a4e8cc4bf9f4442e6e1fd8bcbb qt: Make RPC console welcome message translation-friendly (Hennadii Stepanov) Pull request description: The best practice is do not split a translatable multi-line message into single lines. This helps translators to follow the context. ACKs for top commit: jarolrod: re-ACK 0f3d955a38fe59a4e8cc4bf9f4442e6e1fd8bcbb Tree-SHA512: 30911ff3a972a7787804bb8b27d0b77bfff15939bb478c199261866bfb55d9acd12ab4d44b8b9fc1d4898222cabc4007cc897f9b65728924d121f31e914c44ac --- src/qt/rpcconsole.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 969fd9af22..204e11dafd 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -936,23 +936,29 @@ void RPCConsole::clear(bool keep_prompt) ).arg(consoleFontSize) ); - message(CMD_REPLY, - tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + - "
" + - tr("Use up and down arrows to navigate history, and %1 to clear screen.") - .arg("" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "") + - "
" + - tr("Use %1 and %2 to increase or decrease the font size.") - .arg("" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "") - .arg("" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "") + - "
" + - tr("Type %1 for an overview of available commands.").arg("help") + - "
" + - tr("For more information on using this console type %1.").arg("help-console") + - "

" + - 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.") + - "
", - true); + static const QString welcome_message = + /*: RPC console welcome message. + Placeholders %7 and %8 are style tags for the warning content, and + they are not space separated from the rest of the text intentionally. */ + tr("Welcome to the %1 RPC console.\n" + "Use up and down arrows to navigate history, and %2 to clear screen.\n" + "Use %3 and %4 to increase or decrease the font size.\n" + "Type %5 for an overview of available commands.\n" + "For more information on using this console, type %6.\n" + "\n" + "%7WARNING: 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.%8") + .arg(PACKAGE_NAME, + "" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "", + "" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "", + "" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "", + "help", + "help-console", + "", + ""); + + message(CMD_REPLY, welcome_message, true); } void RPCConsole::keyPressEvent(QKeyEvent *event) From 5a0d524506acfc7907bf3bf3649ff6bd2f191fea Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 1 Jun 2021 03:25:23 +0300 Subject: [PATCH 05/11] Merge bitcoin-core/gui#123: rpc: Do not accept command while executing another one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 38eb37c0bd29b4cb825de905e8eec87636a5221b qt, rpc: Do not accept command while executing another one (Hennadii Stepanov) 0c32b9c5273a4933bda90aa9eb9b7eace6dcaa14 qt, rpc: Accept stop RPC even another command is executing (Hennadii Stepanov) ccf790287c53edbc7b18983e07f520823436c003 qt, rpc, refactor: Return early in RPCConsole::on_lineEdit_returnPressed (Hennadii Stepanov) 5b9c8c9cdd8e12d2e477840df9d6ab809a613c12 qt, rpc: Add "Executing…" message (Hennadii Stepanov) Pull request description: On master (3f512f3d563954547061ee743648b57a900cbe04) it is possible to enter another command while the current command is still being executed. That makes a mess in the output. With this PR: ![Screenshot from 2020-10-29 20-48-55](https://user-images.githubusercontent.com/32963518/97619690-329c0880-1a29-11eb-9f5b-6ae3c02c13b2.png) Some previous context: https://github.com/bitcoin-core/gui/pull/59#issuecomment-715275185 --- It is still possible to enter and execute the `stop` command any time. ACKs for top commit: jarolrod: ACK 38eb37c promag: Tested ACK 38eb37c0bd29b4cb825de905e8eec87636a5221b. Tree-SHA512: 2b37a4b6838bf586b1b5c878192106721f713caeb6252514a6540356aab898986396e0777e73891d331b1be797a4926c20d3f9f38ba2c984ea90d55b0c34f664 --- src/qt/rpcconsole.cpp | 106 +++++++++++++++++++++++---------------- src/qt/rpcconsole.h | 1 + src/qt/test/apptests.cpp | 2 +- 3 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 204e11dafd..5f9e5c11e3 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1080,57 +1080,71 @@ void RPCConsole::showPage(int index) void RPCConsole::on_lineEdit_returnPressed() { - QString cmd = ui->lineEdit->text(); + QString cmd = ui->lineEdit->text().trimmed(); - 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; + if (cmd.isEmpty()) { + return; + } + + 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(); + // A special case allows to request shutdown even a long-running command is executed. + if (cmd == QLatin1String("stop")) { + std::string dummy; + RPCExecuteCommandLine(m_node, dummy, cmd.toStdString()); + return; + } - cmdBeforeBrowsing = QString(); + if (m_is_executing) { + return; + } + + ui->lineEdit->clear(); #ifdef ENABLE_WALLET - WalletModel* wallet_model = ui->WalletSelector->currentData().value(); + WalletModel* wallet_model = ui->WalletSelector->currentData().value(); - 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; + 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")); } -#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(); + m_last_wallet_model = wallet_model; } +#endif // ENABLE_WALLET + + message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); + //: A console message indicating an entered command is currently being executed. + message(CMD_REPLY, tr("Executing…")); + m_is_executing = true; + 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) @@ -1160,7 +1174,13 @@ void RPCConsole::startExecutor() executor->moveToThread(&thread); // Replies from executor object must go to this object - connect(executor, &RPCExecutor::reply, this, qOverload(&RPCConsole::message)); + connect(executor, &RPCExecutor::reply, this, [this](int category, const QString& command) { + // Remove "Executing…" message. + ui->messagesWidget->undo(); + message(category, command); + scrollToEnd(); + m_is_executing = false; + }); // Requests from this object must go to executor connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 7cbb36c20f..397de092f0 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -189,6 +189,7 @@ private: QCompleter *autoCompleter = nullptr; QThread thread; WalletModel* m_last_wallet_model{nullptr}; + bool m_is_executing{false}; /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 547ff05565..872099a1bd 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -41,7 +41,7 @@ void TestRpcCommand(RPCConsole* console) QTest::keyClicks(lineEdit, "getblockchaininfo"); QTest::keyClick(lineEdit, Qt::Key_Return); QVERIFY(mw_spy.wait(1000)); - QCOMPARE(mw_spy.count(), 2); + QCOMPARE(mw_spy.count(), 4); QString output = messagesWidget->toPlainText(); UniValue value; value.read(output.right(output.size() - output.indexOf("{")).toStdString()); From f4fccd31cb1879b9772b98e730bb499c25298af5 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 5 Jun 2021 21:48:53 +0300 Subject: [PATCH 06/11] Merge bitcoin-core/gui#329: Make console buttons look clickable 8b419b5163d41c0caef7b9fa6d3008b73917e8ee qt: make console buttons look clickable (Jarol Rodriguez) Pull request description: On master, for macOS, the console buttons' hitboxes are quite small. This makes clicking on the button with your mouse a little more tedious than it should be. The Issue is related to recent versions of Qt (>5.9.8) not playing so nice on macOS when there are "incorrect" `width` and `height` values set for a `QPushButton` (here is another example: https://github.com/bitcoin-core/gui/pull/319#pullrequestreview-652907740). This fixes this small hitbox issue by converting the buttons from `QPushButton` to `QToolButton`, which in turn makes the buttons look explicitly clickable. This approach was chosen as it helps us avoid having to play around with `width` and `height` values until we find values that play nice with macOS and look good on Linux & Windows. Also, `QToolButton` is an appropriate class for these buttons. Per [Qt Docs](https://doc.qt.io/qt-5/qtoolbutton.html#details): > A tool button is a special button that provides quick-access to specific commands or options. As opposed to a normal command button, a tool button usually doesn't show a text label, but shows an icon instead. Since we are changing the type of the buttons, we need to change the respective actions connection logic in `rpcconsole`. Instead of plugging in `QToolButton`, we abstract it to the base class: `QAbstractButton`. per [Qt Dev Notes](https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Developer-Notes-for-Qt-Code#inherited-signals-and-slot) > Use base class functions as this makes the code more general, e.g., use QAbstractButton::clicked instead of QPushButton::clicked. While here, we also update the size of the icons to `22x22` to be consistent with other tool buttons. **macOS: Master vs PR:** | Master | PR | | ----------- | ----------- | | ![master-ss-macos](https://user-images.githubusercontent.com/23396902/118339460-e9079c80-b4e6-11eb-864b-d394aca5df61.png) | ![pr-ss-macos](https://user-images.githubusercontent.com/23396902/118339468-ec9b2380-b4e6-11eb-9a9e-30620216750e.png) | **Linux: Master vs PR:** | Master | PR | | ----------- | ----------- | | ![master-ss-linux](https://user-images.githubusercontent.com/23396902/118339520-13595a00-b4e7-11eb-86d0-96dd1264c198.png) | ![pr-ss-linux](https://user-images.githubusercontent.com/23396902/118339533-1c4a2b80-b4e7-11eb-8d7f-f733d999c8fd.png) | ACKs for top commit: hebasto: ACK 8b419b5163d41c0caef7b9fa6d3008b73917e8ee, tested on Linux Mint 20.1 (Qt 5.12.8). promag: Tested ACK 8b419b5163d41c0caef7b9fa6d3008b73917e8ee on macOS Big Sur M1, this drops only relevant usages to `flat` buttons. Tree-SHA512: 3f3cdcbe83398136a1d1ee8fc2835be8681f2ed39e79db1e939cab6a00a779f528343d54992807a845cc84d9ef13591affb7a6dbca9e5753a2b8665b0af4d611 --- src/qt/rpcconsole.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 5f9e5c11e3..fd1ea9fdd2 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -37,6 +37,7 @@ #include #endif +#include #include #include #include @@ -547,9 +548,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags ui->lineEdit->setMaxLength(16 * 1024 * 1024); ui->messagesWidget->installEventFilter(this); - connect(ui->clearButton, &QPushButton::clicked, [this] { clear(); }); - connect(ui->fontBiggerButton, &QPushButton::clicked, this, &RPCConsole::fontBigger); - connect(ui->fontSmallerButton, &QPushButton::clicked, this, &RPCConsole::fontSmaller); + connect(ui->clearButton, &QAbstractButton::clicked, [this] { clear(); }); + connect(ui->fontBiggerButton, &QAbstractButton::clicked, this, &RPCConsole::fontBigger); + connect(ui->fontSmallerButton, &QAbstractButton::clicked, this, &RPCConsole::fontSmaller); connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear); // disable the wallet selector by default From 3be79a9ed9623b7579ec296e0118c153cd9f2d4c Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 5 Jun 2021 22:59:30 +0300 Subject: [PATCH 07/11] Merge bitcoin-core/gui#256: Save/restore column sizes of the tables in the Peers tab fb1b1e0f3eae32b087347889ed7502b7f2c48549 qt: Save/restore column sizes of the tables in the Peers tab (Hennadii Stepanov) Pull request description: ACKs for top commit: jonatack: ACK fb1b1e0f3eae32b087347889ed7502b7f2c48549 code review, debug-built and tested jarolrod: ACK fb1b1e0f3eae32b087347889ed7502b7f2c48549 Tree-SHA512: f93495ecd13e4202aba61b407fffbeec855f5b0c1cc027197c78edddd7d11c87ebdb0fcb1daac242f0407323b31f4e7e0313bd76113a5241e4c868a8829af20a --- src/qt/rpcconsole.cpp | 27 ++++++++++++++++++++++----- src/qt/rpcconsole.h | 5 ++++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index fd1ea9fdd2..6759671616 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -505,6 +505,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags ui->splitter->restoreState(settings.value("RPCConsoleWidgetPeersTabSplitterSizes").toByteArray()); } + m_peer_widget_header_state = settings.value("PeersTabPeerHeaderState").toByteArray(); + m_banlist_widget_header_state = settings.value("PeersTabBanlistHeaderState").toByteArray(); + constexpr QChar nonbreaking_hyphen(8209); const std::vector CONNECTION_TYPE_DOC{ //: Explanatory text for an inbound peer connection. @@ -610,6 +613,9 @@ RPCConsole::~RPCConsole() settings.setValue("RPCConsoleWidgetPeersTabSplitterSizes", ui->splitter->saveState()); } + settings.setValue("PeersTabPeerHeaderState", m_peer_widget_header_state); + settings.setValue("PeersTabBanlistHeaderState", m_banlist_widget_header_state); + m_node.rpcUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete pageButtons; @@ -701,9 +707,12 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ 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); + + if (!ui->peerWidget->horizontalHeader()->restoreState(m_peer_widget_header_state)) { + 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); ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); @@ -726,8 +735,11 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ 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); + + if (!ui->banlistWidget->horizontalHeader()->restoreState(m_banlist_widget_header_state)) { + 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 @@ -1357,6 +1369,11 @@ void RPCConsole::showEvent(QShowEvent *event) void RPCConsole::hideEvent(QHideEvent *event) { + // It is too late to call QHeaderView::saveState() in ~RPCConsole(), as all of + // the columns of QTableView child widgets will have zero width at that moment. + m_peer_widget_header_state = ui->peerWidget->horizontalHeader()->saveState(); + m_banlist_widget_header_state = ui->banlistWidget->horizontalHeader()->saveState(); + QWidget::hideEvent(event); if (!clientModel || !clientModel->getPeerTableModel()) diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 397de092f0..9fd94324fe 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -12,9 +12,10 @@ #include #include -#include +#include #include #include +#include class ClientModel; class RPCTimerInterface; @@ -190,6 +191,8 @@ private: QThread thread; WalletModel* m_last_wallet_model{nullptr}; bool m_is_executing{false}; + QByteArray m_peer_widget_header_state; + QByteArray m_banlist_widget_header_state; /** Update UI with latest network info from model. */ void updateNetworkState(); From 7d9ce32562837a9ae9f63e7ed37c9fb24cd60c0b Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 6 Jun 2021 01:00:39 +0300 Subject: [PATCH 08/11] Merge bitcoin-core/gui#29: refactor: Optimize signal-slot connections logic 62cb8d98d27e7f316f01f177f35ad0ed6f8cd9ce qt: Drop BitcoinGUI* WalletFrame data member (Hennadii Stepanov) f73e5c972ab096e0f80cb9e753fa221d17313358 qt: Move CreateWalletActivity connection from WalletFrame to BitcoinGUI (Hennadii Stepanov) 20e2e24e90d782219e853ef0676ac66dc6a9de6a qt: Move WalletView connections from WalletFrame to BitcoinGUI (Hennadii Stepanov) Pull request description: This PR: - implements an idea from https://github.com/bitcoin/bitcoin/pull/17937#issuecomment-575991765 - simplifies `WalletFrame` class interface - as a side effect, removes `bitcoingui` -> `walletframe` -> `bitcoingui` circular dependency - is an alternative to https://github.com/bitcoin/bitcoin/pull/17500 ACKs for top commit: promag: Tested ACK 62cb8d98d27e7f316f01f177f35ad0ed6f8cd9ce on macos 11.2.3 with depends build. jarolrod: ACK 62cb8d98d27e7f316f01f177f35ad0ed6f8cd9ce Tree-SHA512: 633b526a8499ba9ab4b16928daf4de4f6d610284bb9fa51891cad35300a03bde740df3466a71b46e87a62121330fcc9e606eac7666ea5e45fa6d5785b60dcbbd --- src/qt/bitcoingui.cpp | 22 +++++++++++++++++- src/qt/walletframe.cpp | 31 ++++--------------------- src/qt/walletframe.h | 8 +++---- test/lint/lint-circular-dependencies.sh | 1 - 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index cc8af5afc9..687063b53a 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -115,6 +115,11 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const NetworkStyle* networkStyle, connect(walletFrame, &WalletFrame::message, [this](const QString& title, const QString& message, unsigned int style) { this->message(title, message, style); }); + connect(walletFrame, &WalletFrame::createWalletButtonClicked, [this] { + auto activity = new CreateWalletActivity(getWalletController(), this); + connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater); + activity->create(); + }); } else #endif // ENABLE_WALLET { @@ -913,7 +918,10 @@ WalletController* BitcoinGUI::getWalletController() void BitcoinGUI::addWallet(WalletModel* walletModel) { if (!walletFrame) return; - if (!walletFrame->addWallet(walletModel)) return; + + WalletView* wallet_view = new WalletView(walletFrame); + if (!walletFrame->addWallet(walletModel, wallet_view)) return; + rpcConsole->addWallet(walletModel); if (m_wallet_selector->count() == 0) { setWalletActionsEnabled(true); @@ -922,6 +930,18 @@ void BitcoinGUI::addWallet(WalletModel* walletModel) } const QString display_name = walletModel->getDisplayName(); m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); + + connect(wallet_view, &WalletView::outOfSyncWarningClicked, walletFrame, &WalletFrame::outOfSyncWarningClicked); + connect(wallet_view, &WalletView::transactionClicked, this, &BitcoinGUI::gotoHistoryPage); + connect(wallet_view, &WalletView::coinsSent, this, &BitcoinGUI::gotoHistoryPage); + connect(wallet_view, &WalletView::message, [this](const QString& title, const QString& message, unsigned int style) { + this->message(title, message, style); + }); + connect(wallet_view, &WalletView::encryptionStatusChanged, this, &BitcoinGUI::updateWalletStatus); + connect(wallet_view, &WalletView::incomingTransaction, this, &BitcoinGUI::incomingTransaction); + connect(wallet_view, &WalletView::hdEnabledStatusChanged, this, &BitcoinGUI::updateWalletStatus); + connect(this, &BitcoinGUI::setPrivacy, wallet_view, &WalletView::setPrivacy); + wallet_view->setPrivacy(isPrivacyModeActivated()); } void BitcoinGUI::removeWallet(WalletModel* walletModel) diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index bc313e2f33..2edd154e7a 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -7,14 +7,11 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -30,9 +27,8 @@ #include #include -WalletFrame::WalletFrame(BitcoinGUI* _gui) - : QFrame(_gui), - gui(_gui), +WalletFrame::WalletFrame(QWidget* parent) + : QFrame(parent), m_size_hint(OverviewPage{nullptr}.sizeHint()) { // Leave HBox hook for adding a list view later @@ -53,11 +49,7 @@ WalletFrame::WalletFrame(BitcoinGUI* _gui) // A button for create wallet dialog QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack); - connect(create_wallet_button, &QPushButton::clicked, [this] { - auto activity = new CreateWalletActivity(gui->getWalletController(), this); - connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater); - activity->create(); - }); + connect(create_wallet_button, &QPushButton::clicked, this, &WalletFrame::createWalletButtonClicked); no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop); no_wallet_group->setLayout(no_wallet_layout); @@ -86,17 +78,15 @@ void WalletFrame::setClientModel(ClientModel *_clientModel) } } -bool WalletFrame::addWallet(WalletModel *walletModel) +bool WalletFrame::addWallet(WalletModel* walletModel, WalletView* walletView) { - if (!gui || !clientModel || !walletModel) return false; + if (!clientModel || !walletModel) return false; if (mapWalletViews.count(walletModel) > 0) return false; - WalletView* walletView = new WalletView(this); walletView->setClientModel(clientModel); walletView->setWalletModel(walletModel); walletView->showOutOfSyncWarning(bOutOfSync); - walletView->setPrivacy(gui->isPrivacyModeActivated()); WalletView* current_wallet_view = currentWalletView(); if (current_wallet_view) { @@ -108,17 +98,6 @@ bool WalletFrame::addWallet(WalletModel *walletModel) walletStack->addWidget(walletView); mapWalletViews[walletModel] = walletView; - connect(walletView, &WalletView::outOfSyncWarningClicked, this, &WalletFrame::outOfSyncWarningClicked); - connect(walletView, &WalletView::transactionClicked, gui, &BitcoinGUI::gotoHistoryPage); - connect(walletView, &WalletView::coinsSent, gui, &BitcoinGUI::gotoHistoryPage); - connect(walletView, &WalletView::message, [this](const QString& title, const QString& message, unsigned int style) { - gui->message(title, message, style); - }); - connect(walletView, &WalletView::encryptionStatusChanged, gui, &BitcoinGUI::updateWalletStatus); - connect(walletView, &WalletView::incomingTransaction, gui, &BitcoinGUI::incomingTransaction); - connect(walletView, &WalletView::hdEnabledStatusChanged, gui, &BitcoinGUI::updateWalletStatus); - connect(gui, &BitcoinGUI::setPrivacy, walletView, &WalletView::setPrivacy); - return true; } diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 8764448457..1bed80dc41 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -9,7 +9,6 @@ #include #include -class BitcoinGUI; class ClientModel; class SendCoinsRecipient; class WalletModel; @@ -33,12 +32,12 @@ class WalletFrame : public QFrame Q_OBJECT public: - explicit WalletFrame(BitcoinGUI* _gui = nullptr); + explicit WalletFrame(QWidget* parent); ~WalletFrame(); void setClientModel(ClientModel *clientModel); - bool addWallet(WalletModel *walletModel); + bool addWallet(WalletModel* walletModel, WalletView* walletView); void setCurrentWallet(WalletModel* wallet_model); void removeWallet(WalletModel* wallet_model); void removeAllWallets(); @@ -54,9 +53,10 @@ Q_SIGNALS: /** Notify that the user has requested more information about the out-of-sync warning */ void requestedSyncWarningInfo(); + void createWalletButtonClicked(); + private: QStackedWidget *walletStack; - BitcoinGUI *gui; ClientModel *clientModel; QMap mapWalletViews; QGroupBox* no_wallet_group; diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 603f79baf9..836d1de04a 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -16,7 +16,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "index/coinstatsindex -> node/coinstats -> index/coinstatsindex" "policy/fees -> txmempool -> policy/fees" "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel" - "qt/bitcoingui -> qt/walletframe -> qt/bitcoingui" "qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel" "qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel" "txmempool -> validation -> txmempool" From 9ca2aad0b37031f8a75b68a8a4b559afc1aa98ed Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 7 Jun 2021 22:10:17 +0300 Subject: [PATCH 09/11] Merge bitcoin-core/gui#164: Handle peer addition/removal in a right way ecbd91153875c8cdd5b92b840afc116f65e457fb qt: Handle peer addition/removal in a right way (Hennadii Stepanov) 1b66f6e556631a1a2d89aefba70a79894bd14fcd qt: Drop PeerTablePriv class (Hennadii Stepanov) efb7e5aa962d4a4047061996bbb50b6da4592cbc qt, refactor: Use default arguments for overridden functions (Hennadii Stepanov) Pull request description: This PR makes `PeerTableModel` handle a peer addition/removal in a right way. See: - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models Fixes #160. Fixes #191. ACKs for top commit: jarolrod: re-ACK ecbd911 promag: reACK ecbd91153875c8cdd5b92b840afc116f65e457fb just improvements to the comment since last review. Tree-SHA512: 074935d67f78561724218e8b33822e2de16749f873c29054926b720ffcd642f08249a222b563983cf65a9b716290aa14e2372c47fc04e5f401f759db25ca710f --- src/qt/peertablemodel.cpp | 97 ++++++++++++++++++--------------------- src/qt/peertablemodel.h | 21 +++++---- src/qt/rpcconsole.cpp | 2 +- 3 files changed, 58 insertions(+), 62 deletions(-) diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 05a2d4239a..ecd305a77d 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -14,53 +14,11 @@ #include #include -// private implementation -class PeerTablePriv -{ -public: - /** Local cache of peer information */ - QList cachedNodeStats; - - /** Pull a full list of peers from vNodes into our cache */ - void refreshPeers(interfaces::Node& node) - { - cachedNodeStats.clear(); - - interfaces::Node::NodesStats nodes_stats; - node.getNodesStats(nodes_stats); - cachedNodeStats.reserve(nodes_stats.size()); - - for (const auto& node_stats : nodes_stats) - { - CNodeCombinedStats stats; - stats.nodeStats = std::get<0>(node_stats); - stats.fNodeStateStatsAvailable = std::get<1>(node_stats); - stats.nodeStateStats = std::get<2>(node_stats); - cachedNodeStats.append(stats); - } - } - - int size() const - { - return cachedNodeStats.size(); - } - - CNodeCombinedStats *index(int idx) - { - if (idx >= 0 && idx < cachedNodeStats.size()) - return &cachedNodeStats[idx]; - - return nullptr; - } -}; - PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) : QAbstractTableModel(parent), m_node(node), timer(nullptr) { - priv.reset(new PeerTablePriv()); - // set up timer for auto refresh timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh); @@ -85,15 +43,15 @@ void PeerTableModel::stopAutoRefresh() timer->stop(); } -int PeerTableModel::rowCount(const QModelIndex &parent) const +int PeerTableModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) { return 0; } - return priv->size(); + return m_peers_data.size(); } -int PeerTableModel::columnCount(const QModelIndex &parent) const +int PeerTableModel::columnCount(const QModelIndex& parent) const { if (parent.isValid()) { return 0; @@ -101,7 +59,7 @@ int PeerTableModel::columnCount(const QModelIndex &parent) const return columns.length(); } -QVariant PeerTableModel::data(const QModelIndex &index, int role) const +QVariant PeerTableModel::data(const QModelIndex& index, int role) const { if(!index.isValid()) return QVariant(); @@ -174,19 +132,52 @@ Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const return retval; } -QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent) const +QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const { Q_UNUSED(parent); - CNodeCombinedStats *data = priv->index(row); - if (data) - return createIndex(row, column, data); + if (0 <= row && row < rowCount() && 0 <= column && column < columnCount()) { + return createIndex(row, column, const_cast(&m_peers_data[row])); + } + return QModelIndex(); } void PeerTableModel::refresh() { - Q_EMIT layoutAboutToBeChanged(); - priv->refreshPeers(m_node); - Q_EMIT layoutChanged(); + interfaces::Node::NodesStats nodes_stats; + m_node.getNodesStats(nodes_stats); + decltype(m_peers_data) new_peers_data; + new_peers_data.reserve(nodes_stats.size()); + for (const auto& node_stats : nodes_stats) { + const CNodeCombinedStats stats{std::get<0>(node_stats), std::get<2>(node_stats), std::get<1>(node_stats)}; + new_peers_data.append(stats); + } + + // Handle peer addition or removal as suggested in Qt Docs. See: + // - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows + // - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models + // We take advantage of the fact that the std::vector returned + // by interfaces::Node::getNodesStats is sorted by nodeid. + for (int i = 0; i < m_peers_data.size();) { + if (i < new_peers_data.size() && m_peers_data.at(i).nodeStats.nodeid == new_peers_data.at(i).nodeStats.nodeid) { + ++i; + continue; + } + // A peer has been removed from the table. + beginRemoveRows(QModelIndex(), i, i); + m_peers_data.erase(m_peers_data.begin() + i); + endRemoveRows(); + } + + if (m_peers_data.size() < new_peers_data.size()) { + // Some peers have been added to the end of the table. + beginInsertRows(QModelIndex(), m_peers_data.size(), new_peers_data.size() - 1); + m_peers_data.swap(new_peers_data); + endInsertRows(); + } else { + m_peers_data.swap(new_peers_data); + } + + Q_EMIT changed(); } diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 3d195342f1..0ff1b5dba7 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -8,10 +8,11 @@ #include // For CNodeStateStats #include -#include - #include +#include +#include #include +#include class PeerTablePriv; @@ -61,18 +62,23 @@ public: /** @name Methods overridden from QAbstractTableModel @{*/ - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - QModelIndex index(int row, int column, const QModelIndex &parent) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; /*@}*/ public Q_SLOTS: void refresh(); +Q_SIGNALS: + void changed(); + private: + //! Internal peer data structure. + QList m_peers_data{}; interfaces::Node& m_node; const QStringList columns{ /*: Title of Peers Table column which contains a @@ -99,7 +105,6 @@ private: /*: Title of Peers Table column which contains the peer's User Agent string. */ tr("User Agent")}; - std::unique_ptr priv; QTimer *timer; }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 6759671616..b9c68c9c43 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -727,7 +727,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // peer table signal handling - update peer details when selecting new node connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget); - connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::updateDetailWidget); + connect(model->getPeerTableModel(), &PeerTableModel::changed, this, &RPCConsole::updateDetailWidget); // set up ban table ui->banlistWidget->setModel(model->getBanTableModel()); From fc900a8aea56a5cf3582bd6e29aeb5ca5d7f3a30 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 12 Jun 2021 13:58:19 +0300 Subject: [PATCH 10/11] Merge bitcoin-core/gui#333: refactor: Signal-slot connections cleanup f507681baa406046c9c3d44be39e99124a2d6e5f qt: Connect WalletView signal to BitcoinGUI slot directly (Hennadii Stepanov) bd50ff9290ea9ec8b482db11314a6fd658373f23 qt: Drop redundant OverviewPage::handleOutOfSyncWarningClicks slot (Hennadii Stepanov) 793f19599b6d9009c2fb11e4c07e0872ff00defe qt: Drop redundant WalletView::requestedSyncWarningInfo slot (Hennadii Stepanov) Pull request description: This PR: - removes slots whose only job is to emit a signal, since we can use the signal as a slot - connects the`WalletView::outOfSyncWarningClicked` signal to the `BitcoinGUI::showModalOverlay` slot directly, and removes intermediate `WalletFrame` slot and signal - split from #29 This PR does not change behavior. ACKs for top commit: Talkless: tACK f507681baa406046c9c3d44be39e99124a2d6e5f, tested on Debian Sid with Qt 5.15.2, no any behavioral changes noticed. promag: Code review ACK f507681baa406046c9c3d44be39e99124a2d6e5f. Tree-SHA512: cd636a7e61881b2cbee84d5425d2107a8e39683b8eb32d79dc9ea942db55d5c1979be2f70da1660eaee5de622d10ed5a92f11fc2351de21b84324b10b23d0c96 --- src/qt/bitcoingui.cpp | 7 +------ src/qt/overviewpage.cpp | 5 ----- src/qt/overviewpage.h | 1 - src/qt/walletframe.cpp | 5 ----- src/qt/walletframe.h | 4 ---- src/qt/walletview.cpp | 7 +------ src/qt/walletview.h | 4 ---- 7 files changed, 2 insertions(+), 31 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 687063b53a..875e0084a1 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -224,11 +224,6 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const NetworkStyle* networkStyle, modalOverlay = new ModalOverlay(enableWallet, this->centralWidget()); connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showModalOverlay); connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this, &BitcoinGUI::showModalOverlay); -#ifdef ENABLE_WALLET - if(enableWallet) { - connect(walletFrame, &WalletFrame::requestedSyncWarningInfo, this, &BitcoinGUI::showModalOverlay); - } -#endif #ifdef Q_OS_MAC m_app_nap_inhibitor = new CAppNapInhibitor; @@ -931,7 +926,7 @@ void BitcoinGUI::addWallet(WalletModel* walletModel) const QString display_name = walletModel->getDisplayName(); m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); - connect(wallet_view, &WalletView::outOfSyncWarningClicked, walletFrame, &WalletFrame::outOfSyncWarningClicked); + connect(wallet_view, &WalletView::outOfSyncWarningClicked, this, &BitcoinGUI::showModalOverlay); connect(wallet_view, &WalletView::transactionClicked, this, &BitcoinGUI::gotoHistoryPage); connect(wallet_view, &WalletView::coinsSent, this, &BitcoinGUI::gotoHistoryPage); connect(wallet_view, &WalletView::message, [this](const QString& title, const QString& message, unsigned int style) { diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 115ce523f7..30b238d4db 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -199,11 +199,6 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index) Q_EMIT transactionClicked(filter->mapToSource(index)); } -void OverviewPage::handleOutOfSyncWarningClicks() -{ - Q_EMIT outOfSyncWarningClicked(); -} - void OverviewPage::setPrivacy(bool privacy) { m_privacy = privacy; diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 41af14cb8c..f922e8ff74 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -70,7 +70,6 @@ private Q_SLOTS: void handleTransactionClicked(const QModelIndex &index); void updateAlerts(const QString &warnings); void updateWatchOnlyLabels(bool showWatchOnly); - void handleOutOfSyncWarningClicks(); }; #endif // BITCOIN_QT_OVERVIEWPAGE_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 2edd154e7a..0148003e20 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -343,8 +343,3 @@ WalletModel* WalletFrame::currentWalletModel() const WalletView* wallet_view = currentWalletView(); return wallet_view ? wallet_view->getWalletModel() : nullptr; } - -void WalletFrame::outOfSyncWarningClicked() -{ - Q_EMIT requestedSyncWarningInfo(); -} diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 1bed80dc41..4b76dc40ec 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -50,8 +50,6 @@ public: Q_SIGNALS: void message(const QString& title, const QString& message, unsigned int style); - /** Notify that the user has requested more information about the out-of-sync warning */ - void requestedSyncWarningInfo(); void createWalletButtonClicked(); @@ -110,8 +108,6 @@ public Q_SLOTS: void usedSendingAddresses(); /** Show used receiving addresses */ void usedReceivingAddresses(); - /** Pass on signal over requested out-of-sync-warning information */ - void outOfSyncWarningClicked(); }; #endif // BITCOIN_QT_WALLETFRAME_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 48605227e7..6869854ced 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -100,7 +100,7 @@ WalletView::WalletView(QWidget* parent) : connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked); // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page connect(overviewPage, &OverviewPage::transactionClicked, transactionView, qOverload(&TransactionView::focusTransaction)); - connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo); + connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::outOfSyncWarningClicked); connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); @@ -408,11 +408,6 @@ void WalletView::showProgress(const QString &title, int nProgress) } } -void WalletView::requestedSyncWarningInfo() -{ - Q_EMIT outOfSyncWarningClicked(); -} - /** Update wallet with the sum of the selected transactions */ void WalletView::trxAmount(QString amount) { diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 0b3b32dbc1..8886de7ecb 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -122,10 +122,6 @@ public Q_SLOTS: /** Show progress dialog e.g. for rescan */ void showProgress(const QString &title, int nProgress); - /** User has requested more information about the out of sync state */ - void requestedSyncWarningInfo(); - - /** Update selected DASH amount from transactionview */ void trxAmount(QString amount); Q_SIGNALS: From 6431f71b3a16339d8a88f3ac123cd9a6a057ae42 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 5 Aug 2021 09:46:26 +0300 Subject: [PATCH 11/11] Merge bitcoin-core/gui#393: Fix regression in "Encrypt Wallet" menu item d54d94959869b0c363939163b99ba0475751dcb6 qt: Fix regression in "Encrypt Wallet" menu item (Hennadii Stepanov) Pull request description: Fix #392. Adding a new item to the `m_wallet_selector` must follow the establishment of a connection between the `WalletView::encryptionStatusChanged` signal and the `BitcoinGUI::updateWalletStatus` slot. This was a regression introduced in https://github.com/bitcoin/bitcoin/commit/20e2e24e90d782219e853ef0676ac66dc6a9de6a (#29). --- An _encrypted_ wallet being auto-loaded at the GUI startup: - on master (eaf09bda4ab21f79f89822d2c6fa3d7a3ce57b0d) ![Screenshot from 2021-08-03 22-38-49](https://user-images.githubusercontent.com/32963518/128075837-cdbb2047-5327-43ea-b2d5-2dcdef67cdc0.png) - with this PR ![Screenshot from 2021-08-03 22-34-58](https://user-images.githubusercontent.com/32963518/128075572-cb727652-ad44-4b85-bf64-edcd19f9dea1.png) ACKs for top commit: achow101: ACK d54d94959869b0c363939163b99ba0475751dcb6 jarolrod: ACK d54d94959869b0c363939163b99ba0475751dcb6 Tree-SHA512: 669615ec8e1517c2f4cdf59bd11a7c85be793ba0dda112361cf95e6c2f0636215fed331d26a86dc9b779a49defae1b248232f98dab449584376c111c288e87bb --- src/qt/bitcoingui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 875e0084a1..98ba9297da 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -923,8 +923,6 @@ void BitcoinGUI::addWallet(WalletModel* walletModel) } else if (m_wallet_selector->count() == 1) { m_wallet_selector_action->setVisible(true); } - const QString display_name = walletModel->getDisplayName(); - m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); connect(wallet_view, &WalletView::outOfSyncWarningClicked, this, &BitcoinGUI::showModalOverlay); connect(wallet_view, &WalletView::transactionClicked, this, &BitcoinGUI::gotoHistoryPage); @@ -937,6 +935,8 @@ void BitcoinGUI::addWallet(WalletModel* walletModel) connect(wallet_view, &WalletView::hdEnabledStatusChanged, this, &BitcoinGUI::updateWalletStatus); connect(this, &BitcoinGUI::setPrivacy, wallet_view, &WalletView::setPrivacy); wallet_view->setPrivacy(isPrivacyModeActivated()); + const QString display_name = walletModel->getDisplayName(); + m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); } void BitcoinGUI::removeWallet(WalletModel* walletModel)