From 1e585b1987b62b19d35cb0955f457fccdab2bff1 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:30:55 +0100 Subject: [PATCH 01/13] Merge bitcoin-core/gui#828: Rendering an amp characters in the wallet name for QMenu 8233ee41ab9648cd0c3bd78bc2a8d692a54d9ea0 gui: correct replacement of amp character in the wallet name for QMenu (Konstantin Akimov) Pull request description: In the current implementation Qt uses '&' as a signal to underscore letter and use it as a hot-key, which is not expected for case of wallet name. The [comment in the code](https://github.com/bitcoin/bitcoin/pull/30446/files#diff-2ecf8cbf369cf3d2f3d2b1cf5cfe4c1a647d63e11e2885d2fd0ac11fb5f7a804L402-L404) regarding the use of an "&" on a menu item is misleading. If a wallet name has an "&" in it, it is not supposed to be interpreted as a hot-key, but it should be shown as it is without replacing it to an underscore. See screenshots before & after: ![Screenshot_20240713_122454](https://github.com/user-attachments/assets/e36d6e4c-d872-4b4c-b55e-bcfde9881281) ![Screenshot_20240713_131304](https://github.com/user-attachments/assets/9484687d-0aea-4061-a461-5d187762a4b4) ACKs for top commit: hebasto: re-ACK 8233ee41ab9648cd0c3bd78bc2a8d692a54d9ea0. pablomartin4btc: tACK 8233ee41ab9648cd0c3bd78bc2a8d692a54d9ea0 BrandonOdiwuor: ACK 8233ee41ab9648cd0c3bd78bc2a8d692a54d9ea0. Tested on Ubuntu 22.04 using Qt version 5.15.3 Tree-SHA512: 918c2c05555d203a8b203794c138651d4a1691a05a858631d5a4664b78e150402d1ae4a02ee5181f63a5b22a09badca0a4ea14a626f45f8cbe557226c308b8c5 --- src/qt/bitcoingui.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index d0336e597c371..290ad7fe9f316 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -520,10 +520,9 @@ void BitcoinGUI::createActions() for (const std::pair& i : m_wallet_controller->listWalletDir()) { const std::string& path = i.first; QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); - // Menu items remove single &. Single & are shown when && is in - // the string, but only the first occurrence. So replace only - // the first & with &&. - name.replace(name.indexOf(QChar('&')), 1, QString("&&")); + // An single ampersand in the menu item's text sets a shortcut for this item. + // Single & are shown when && is in the string. So replace & with &&. + name.replace(QChar('&'), QString("&&")); QAction* action = m_open_wallet_menu->addAction(name); if (i.second) { From c36bb8e6fba143a0fbadb1599c5c5360de7c9181 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 13 Jul 2024 12:39:49 +0700 Subject: [PATCH 02/13] fix: use && in governance urls instead & --- src/qt/governancelist.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qt/governancelist.cpp b/src/qt/governancelist.cpp index c5e664edca49c..57fd41153e3ff 100644 --- a/src/qt/governancelist.cpp +++ b/src/qt/governancelist.cpp @@ -387,8 +387,11 @@ void GovernanceList::showProposalContextMenu(const QPoint& pos) return; } + QString proposal_url = proposal->url(); + proposal_url.replace(QChar('&'), QString("&&")); + // right click menu with option to open proposal url - QAction* openProposalUrl = new QAction(proposal->url(), this); + QAction* openProposalUrl = new QAction(proposal_url, this); proposalContextMenu->clear(); proposalContextMenu->addAction(openProposalUrl); connect(openProposalUrl, &QAction::triggered, proposal, &Proposal::openUrl); From 4f89c98dc40bf77ac8a9dffe75ed0d117ef91184 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 20 Apr 2021 23:11:41 +0300 Subject: [PATCH 03/13] Merge bitcoin-core/gui#263: Revamp context menus 16c157de3c316517e095994fa8d526253225a672 qt, refactor: Use better QMenu::addAction overloaded function (Hennadii Stepanov) 79311750b58d650d49a3f0edd59d31dd132ab8c0 qt: Do not assign Alt+ shortcuts to context menu actions (Hennadii Stepanov) 963e12058f3ca3cdaeefd9aa5a8305fa41afd1a0 qt: Drop menu separator that separates nothing (Hennadii Stepanov) 1398a6536c710368d9f1d0cf6e280fe63d07c9f0 qt, refactor: Make AddressBookPage::deleteAction a local variable (Hennadii Stepanov) Pull request description: This PR: 1. removes useless `Alt` + `` shortcuts from context menu items 2. replaces 3 lines of code with the only call of [`QMenu::addAction`](https://doc.qt.io/qt-5/qmenu.html#addAction-5) for each context menu item (it became possible since https://github.com/bitcoin/bitcoin/pull/21286 was merged) 3. makes other minor cleanups No behavior change. ACKs for top commit: kristapsk: ACK 16c157de3c316517e095994fa8d526253225a672 promag: Code review ACK 16c157de3c316517e095994fa8d526253225a672. Nice code cleanup that takes advantage of more recent Qt API. jarolrod: ACK 16c157de3c316517e095994fa8d526253225a672 Tree-SHA512: e5555fe957058cc67b351aaf9f09fe3635edb2d07a2223d3093913a25607ae538f0a2fde84c0b0cd43e7475b248949548eb4a5d4b21d8f7391fa2fa8541c04ff --- src/qt/addressbookpage.cpp | 36 ++++++++---------------- src/qt/addressbookpage.h | 1 - src/qt/bitcoingui.cpp | 7 ++--- src/qt/coincontroldialog.cpp | 28 ++++--------------- src/qt/qrimagewidget.cpp | 8 ++---- src/qt/receivecoinsdialog.cpp | 24 ++++------------ src/qt/rpcconsole.cpp | 33 ++++------------------ src/qt/transactionview.cpp | 52 ++++++++++------------------------- 8 files changed, 46 insertions(+), 143 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 6df4f7ebbf9fc..9f8510b605bc5 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -107,32 +107,20 @@ AddressBookPage::AddressBookPage(Mode _mode, Tabs _tab, QWidget* parent) : break; } - // Context menu actions - QAction *copyAddressAction = new QAction(tr("&Copy Address"), this); - QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); - QAction *editAction = new QAction(tr("&Edit"), this); - QAction *showAddressQRCodeAction = new QAction(tr("&Show address QR code"), this); - deleteAction = new QAction(ui->deleteAddress->text(), this); + // Build context menu + contextMenu = new QMenu(this); + contextMenu->addAction(tr("Copy Address"), this, &AddressBookPage::on_copyAddress_clicked); + contextMenu->addAction(tr("Copy Label"), this, &AddressBookPage::onCopyLabelAction); + contextMenu->addAction(tr("Edit"), this, &AddressBookPage::onEditAction); + [[maybe_unused]] QAction* qrAction = contextMenu->addAction(tr("Show address QR code"), this, &AddressBookPage::on_showAddressQRCode_clicked); #ifndef USE_QRCODE - showAddressQRCodeAction->setEnabled(false); + qrAction->setEnabled(false); #endif - // Build context menu - contextMenu = new QMenu(this); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(editAction); - if(tab == SendingTab) - contextMenu->addAction(deleteAction); - contextMenu->addSeparator(); - contextMenu->addAction(showAddressQRCodeAction); - - // Connect signals for context menu actions - connect(copyAddressAction, &QAction::triggered, this, &AddressBookPage::on_copyAddress_clicked); - connect(copyLabelAction, &QAction::triggered, this, &AddressBookPage::onCopyLabelAction); - connect(editAction, &QAction::triggered, this, &AddressBookPage::onEditAction); - connect(deleteAction, &QAction::triggered, this, &AddressBookPage::on_deleteAddress_clicked); - connect(showAddressQRCodeAction, &QAction::triggered, this, &AddressBookPage::on_showAddressQRCode_clicked); + if (tab == SendingTab) { + contextMenu->addAction(tr("Delete"), this, &AddressBookPage::on_deleteAddress_clicked); + } + connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu); connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept); @@ -267,13 +255,11 @@ void AddressBookPage::selectionChanged() // In sending tab, allow deletion of selection ui->deleteAddress->setEnabled(true); ui->deleteAddress->setVisible(true); - deleteAction->setEnabled(true); break; case ReceivingTab: // Deleting receiving addresses, however, is not allowed ui->deleteAddress->setEnabled(false); ui->deleteAddress->setVisible(false); - deleteAction->setEnabled(false); break; } ui->copyAddress->setEnabled(true); diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index b1d1a495f64ab..a354a8b08210f 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -54,7 +54,6 @@ public Q_SLOTS: QString returnValue; AddressBookSortFilterProxyModel *proxyModel; QMenu *contextMenu; - QAction *deleteAction; // to be able to explicitly disable it QString newAddressToSelect; private Q_SLOTS: diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 290ad7fe9f316..b6ae30d224ee4 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -2054,11 +2054,8 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) - { - QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this); - menuAction->setData(QVariant(u)); - menu->addAction(menuAction); + for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { + menu->addAction(BitcoinUnits::name(u))->setData(QVariant(u)); } connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection); } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 73cdc667866ab..9fd492cb97aa6 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -62,32 +62,16 @@ CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _m GUIUtil::disableMacFocusRect(this); - // context menu actions - QAction *copyAddressAction = new QAction(tr("Copy address"), this); - QAction *copyLabelAction = new QAction(tr("Copy label"), this); - QAction *copyAmountAction = new QAction(tr("Copy amount"), this); - copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this - lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this - unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this - // context menu contextMenu = new QMenu(this); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(copyAmountAction); - contextMenu->addAction(copyTransactionHashAction); + contextMenu->addAction(tr("Copy address"), this, &CoinControlDialog::copyAddress); + contextMenu->addAction(tr("Copy label"), this, &CoinControlDialog::copyLabel); + contextMenu->addAction(tr("Copy amount"), this, &CoinControlDialog::copyAmount); + copyTransactionHashAction = contextMenu->addAction(tr("Copy transaction ID"), this, &CoinControlDialog::copyTransactionHash); contextMenu->addSeparator(); - contextMenu->addAction(lockAction); - contextMenu->addAction(unlockAction); - - // context menu signals + lockAction = contextMenu->addAction(tr("Lock unspent"), this, &CoinControlDialog::lockCoin); + unlockAction = contextMenu->addAction(tr("Unlock unspent"), this, &CoinControlDialog::unlockCoin); connect(ui->treeWidget, &QWidget::customContextMenuRequested, this, &CoinControlDialog::showMenu); - connect(copyAddressAction, &QAction::triggered, this, &CoinControlDialog::copyAddress); - connect(copyLabelAction, &QAction::triggered, this, &CoinControlDialog::copyLabel); - connect(copyAmountAction, &QAction::triggered, this, &CoinControlDialog::copyAmount); - connect(copyTransactionHashAction, &QAction::triggered, this, &CoinControlDialog::copyTransactionHash); - connect(lockAction, &QAction::triggered, this, &CoinControlDialog::lockCoin); - connect(unlockAction, &QAction::triggered, this, &CoinControlDialog::unlockCoin); // clipboard actions QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index dbb4d8dc805a0..c3c6bd0eac7a7 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -27,12 +27,8 @@ QRImageWidget::QRImageWidget(QWidget *parent): QLabel(parent), contextMenu(nullptr) { contextMenu = new QMenu(this); - QAction *saveImageAction = new QAction(tr("&Save Image…"), this); - connect(saveImageAction, &QAction::triggered, this, &QRImageWidget::saveImage); - contextMenu->addAction(saveImageAction); - QAction *copyImageAction = new QAction(tr("&Copy Image"), this); - connect(copyImageAction, &QAction::triggered, this, &QRImageWidget::copyImage); - contextMenu->addAction(copyImageAction); + contextMenu->addAction(tr("Save Image…"), this, &QRImageWidget::saveImage); + contextMenu->addAction(tr("Copy Image"), this, &QRImageWidget::copyImage); } bool QRImageWidget::setQR(const QString& data, const QString& text) diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 5dcb2b66031f2..b7f2258291bc0 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -31,28 +31,14 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : ui->label_3}, GUIUtil::FontWeight::Normal, 15); GUIUtil::updateFonts(); - // context menu actions - QAction *copyURIAction = new QAction(tr("Copy URI"), this); - QAction* copyAddressAction = new QAction(tr("Copy address"), this); - copyLabelAction = new QAction(tr("Copy label"), this); - copyMessageAction = new QAction(tr("Copy message"), this); - copyAmountAction = new QAction(tr("Copy amount"), this); - // context menu contextMenu = new QMenu(this); - contextMenu->addAction(copyURIAction); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(copyMessageAction); - contextMenu->addAction(copyAmountAction); - - // context menu signals + contextMenu->addAction(tr("Copy URI"), this, &ReceiveCoinsDialog::copyURI); + contextMenu->addAction(tr("Copy address"), this, &ReceiveCoinsDialog::copyAddress); + copyLabelAction = contextMenu->addAction(tr("Copy label"), this, &ReceiveCoinsDialog::copyLabel); + copyMessageAction = contextMenu->addAction(tr("Copy message"), this, &ReceiveCoinsDialog::copyMessage); + copyAmountAction = contextMenu->addAction(tr("Copy amount"), this, &ReceiveCoinsDialog::copyAmount); connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu); - connect(copyURIAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyURI); - connect(copyAddressAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAddress); - connect(copyLabelAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyLabel); - connect(copyMessageAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyMessage); - connect(copyAmountAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAmount); connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear); } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ecd53638ed6b4..a42a0e9e2015a 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -705,29 +705,14 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ ui->peerWidget->horizontalHeader()->setStretchLastSection(true); ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); - // create peer table context menu actions - QAction* disconnectAction = new QAction(tr("&Disconnect"), this); - QAction* banAction1h = new QAction(ts.ban_for + " " + tr("1 &hour"), this); - QAction* banAction24h = new QAction(ts.ban_for + " " + tr("1 &day"), this); - QAction* banAction7d = new QAction(ts.ban_for + " " + tr("1 &week"), this); - QAction* banAction365d = new QAction(ts.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 + peersTableContextMenu->addAction(tr("Disconnect"), this, &RPCConsole::disconnectSelectedNode); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 hour"), [this] { banSelectedNode(60 * 60); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 day"), [this] { banSelectedNode(60 * 60 * 24); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 week"), [this] { banSelectedNode(60 * 60 * 24 * 7); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 year"), [this] { banSelectedNode(60 * 60 * 24 * 365); }); 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::updateDetailWidget); @@ -746,16 +731,10 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ 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 + banTableContextMenu->addAction(tr("Unban"), this, &RPCConsole::unbanSelectedNode); 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); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index b51361a64683e..f016ff872af33 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -145,36 +145,23 @@ TransactionView::TransactionView(QWidget* parent) : transactionView->setObjectName("transactionView"); - // Actions - abandonAction = new QAction(tr("Abandon transaction"), this); - resendAction = new QAction(tr("Resend transaction"), this); - copyAddressAction = new QAction(tr("Copy address"), this); - copyLabelAction = new QAction(tr("Copy label"), this); - QAction *copyAmountAction = new QAction(tr("Copy amount"), this); - QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); - QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this); - QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this); - QAction *editLabelAction = new QAction(tr("Edit address label"), this); - QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); - QAction *showAddressQRCodeAction = new QAction(tr("Show address QR code"), this); -#ifndef USE_QRCODE - showAddressQRCodeAction->setEnabled(false); -#endif - contextMenu = new QMenu(this); contextMenu->setObjectName("contextMenu"); - contextMenu->addAction(copyAddressAction); - contextMenu->addAction(copyLabelAction); - contextMenu->addAction(copyAmountAction); - contextMenu->addAction(copyTxIDAction); - contextMenu->addAction(copyTxHexAction); - contextMenu->addAction(copyTxPlainText); - contextMenu->addAction(showDetailsAction); - contextMenu->addAction(showAddressQRCodeAction); + copyAddressAction = contextMenu->addAction(tr("Copy address"), this, &TransactionView::copyAddress); + copyLabelAction = contextMenu->addAction(tr("Copy label"), this, &TransactionView::copyLabel); + contextMenu->addAction(tr("Copy amount"), this, &TransactionView::copyAmount); + contextMenu->addAction(tr("Copy transaction ID"), this, &TransactionView::copyTxID); + contextMenu->addAction(tr("Copy raw transaction"), this, &TransactionView::copyTxHex); + contextMenu->addAction(tr("Copy full transaction details"), this, &TransactionView::copyTxPlainText); + contextMenu->addAction(tr("Show transaction details"), this, &TransactionView::showDetails); contextMenu->addSeparator(); - contextMenu->addAction(abandonAction); - contextMenu->addAction(resendAction); - contextMenu->addAction(editLabelAction); + abandonAction = contextMenu->addAction(tr("Abandon transaction"), this, &TransactionView::abandonTx); + resendAction = contextMenu->addAction(tr("Resend transaction"), this, &TransactionView::resendTx); + contextMenu->addAction(tr("Edit address label"), this, &TransactionView::editLabel); + [[maybe_unused]] QAction* showAddressQRCodeAction = contextMenu->addAction(tr("Show address QR code"), this, &TransactionView::showAddressQRCode); +#ifndef USE_QRCODE + showAddressQRCodeAction->setEnabled(false); +#endif connect(dateWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseDate); connect(typeWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseType); @@ -188,17 +175,6 @@ TransactionView::TransactionView(QWidget* parent) : connect(transactionView, &QTableView::clicked, this, &TransactionView::computeSum); connect(transactionView, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu); - connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx); - connect(resendAction, &QAction::triggered, this, &TransactionView::resendTx); - connect(copyAddressAction, &QAction::triggered, this, &TransactionView::copyAddress); - connect(copyLabelAction, &QAction::triggered, this, &TransactionView::copyLabel); - connect(copyAmountAction, &QAction::triggered, this, &TransactionView::copyAmount); - connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID); - connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex); - connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText); - connect(editLabelAction, &QAction::triggered, this, &TransactionView::editLabel); - connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails); - connect(showAddressQRCodeAction, &QAction::triggered, this, &TransactionView::showAddressQRCode); // Double-clicking on a transaction on the transaction history page shows details connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails); } From 1cdd9fbdf5c0b732236d3b2dc164b2c7a6b1b188 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 13 Jul 2024 12:52:14 +0700 Subject: [PATCH 04/13] refactor: use new QAction style for governance list and masternode list --- src/qt/governancelist.cpp | 6 ++---- src/qt/masternodelist.cpp | 9 +++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/qt/governancelist.cpp b/src/qt/governancelist.cpp index 57fd41153e3ff..807157d8b6762 100644 --- a/src/qt/governancelist.cpp +++ b/src/qt/governancelist.cpp @@ -387,14 +387,12 @@ void GovernanceList::showProposalContextMenu(const QPoint& pos) return; } + // right click menu with option to open proposal url QString proposal_url = proposal->url(); proposal_url.replace(QChar('&'), QString("&&")); - // right click menu with option to open proposal url - QAction* openProposalUrl = new QAction(proposal_url, this); proposalContextMenu->clear(); - proposalContextMenu->addAction(openProposalUrl); - connect(openProposalUrl, &QAction::triggered, proposal, &Proposal::openUrl); + proposalContextMenu->addAction(proposal_url, proposal, &Proposal::openUrl); proposalContextMenu->exec(QCursor::pos()); } diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index 43ba572455df0..7b8cdb7fe1adf 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -81,15 +81,12 @@ MasternodeList::MasternodeList(QWidget* parent) : ui->checkBoxMyMasternodesOnly->setEnabled(false); - QAction* copyProTxHashAction = new QAction(tr("Copy ProTx Hash"), this); - QAction* copyCollateralOutpointAction = new QAction(tr("Copy Collateral Outpoint"), this); contextMenuDIP3 = new QMenu(this); - contextMenuDIP3->addAction(copyProTxHashAction); - contextMenuDIP3->addAction(copyCollateralOutpointAction); + contextMenuDIP3->addAction(tr("Copy ProTx Hash"), this, &MasternodeList::copyProTxHash_clicked); + contextMenuDIP3->addAction(tr("Copy Collateral Outpoint"), this, &MasternodeList::copyCollateralOutpoint_clicked); + connect(ui->tableWidgetMasternodesDIP3, &QTableWidget::customContextMenuRequested, this, &MasternodeList::showContextMenuDIP3); connect(ui->tableWidgetMasternodesDIP3, &QTableWidget::doubleClicked, this, &MasternodeList::extraInfoDIP3_clicked); - connect(copyProTxHashAction, &QAction::triggered, this, &MasternodeList::copyProTxHash_clicked); - connect(copyCollateralOutpointAction, &QAction::triggered, this, &MasternodeList::copyCollateralOutpoint_clicked); timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MasternodeList::updateDIP3ListScheduled); From b5fb5597069d0ea013622a11b08086e7ab7af94a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 28 Apr 2021 20:51:58 +0300 Subject: [PATCH 05/13] Merge bitcoin-core/gui#18: Add peertablesortproxy module 5a4a15d2b4456272fd8aa080195f40a09576ae01 qt, refactor: Drop no longer used PeerTableModel::getRowByNodeId func (Hennadii Stepanov) 9a9f180df0d51396fee2468681df6dd935b0248e qt, refactor: Drop no longer used PeerTableModel::sort function (Hennadii Stepanov) 778a64af209e4fa692a3aca8376ba1bd5e1af881 qt: Use PeerTableSortProxy for sorting peer table (Hennadii Stepanov) df2d165ba9e0acc53f36a326f68f57ad9c297872 qt: Add peertablesortproxy module (Hennadii Stepanov) Pull request description: The "Peers" table in the "Node" window does not hold multiple selection after sorting. This PR introduces a `QSortFilterProxyModel` subclass, that is a standard Qt [practice](https://doc.qt.io/qt-5/model-view-programming.html#custom-sorting-models) for such cases. Now the sorting code is encapsulated into the dedicated Qt class, and we do not need to maintain it. Fixes #283 (additionally). --- On **master** (7ae86b3c6845873ca96650fc69beb4ae5285c801): - rows are sorted by "Ping", and a selection is made ![Screenshot from 2020-11-28 22-53-11](https://user-images.githubusercontent.com/32963518/100525900-96eaed00-31cc-11eb-86e7-72ede3b8b33c.png) - rows are sorted by "NodeId", and the previous selection is _lost_ ![Screenshot from 2020-11-28 22-53-21](https://user-images.githubusercontent.com/32963518/100525904-9c483780-31cc-11eb-957c-06f53d7d31ab.png) With **this PR**: - rows are sorted by "Ping", and a selection is made ![Screenshot from 2020-11-28 22-39-41](https://user-images.githubusercontent.com/32963518/100525776-06aca800-31cc-11eb-8c4e-9c6566fe80fe.png) - rows are sorted by "NodeId", and the row are still selected ![Screenshot from 2020-11-28 22-39-53](https://user-images.githubusercontent.com/32963518/100525791-2348e000-31cc-11eb-8b78-716a5551d7ec.png) ACKs for top commit: jarolrod: re-ACK 5a4a15d2b4456272fd8aa080195f40a09576ae01, tested on macOS 11.2 Qt 5.15.2 after rebase promag: Tested ACK 5a4a15d2b4456272fd8aa080195f40a09576ae01. Tree-SHA512: f81c1385892fbf1a46ffb98b42094ca1cc97da52114bbbc94fedb553899b1f18c26a349e186bba6e27922a89426bd61e8bc88b1f7832512dbe211b5f834e076e --- src/Makefile.qt.include | 3 ++ src/qt/clientmodel.cpp | 10 +++++ src/qt/clientmodel.h | 3 ++ src/qt/peertablemodel.cpp | 69 +------------------------------- src/qt/peertablemodel.h | 14 ------- src/qt/peertablesortproxy.cpp | 43 ++++++++++++++++++++ src/qt/peertablesortproxy.h | 25 ++++++++++++ src/qt/rpcconsole.cpp | 75 +++-------------------------------- src/qt/rpcconsole.h | 4 -- 9 files changed, 91 insertions(+), 155 deletions(-) create mode 100644 src/qt/peertablesortproxy.cpp create mode 100644 src/qt/peertablesortproxy.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 885a0e5334006..de588ef74ba37 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -69,6 +69,7 @@ QT_MOC_CPP = \ qt/moc_optionsmodel.cpp \ qt/moc_overviewpage.cpp \ qt/moc_peertablemodel.cpp \ + qt/moc_peertablesortproxy.cpp \ qt/moc_paymentserver.cpp \ qt/moc_psbtoperationsdialog.cpp \ qt/moc_qrdialog.cpp \ @@ -146,6 +147,7 @@ BITCOIN_QT_H = \ qt/overviewpage.h \ qt/paymentserver.h \ qt/peertablemodel.h \ + qt/peertablesortproxy.h \ qt/psbtoperationsdialog.h \ qt/qrdialog.h \ qt/qrimagewidget.h \ @@ -227,6 +229,7 @@ BITCOIN_QT_BASE_CPP = \ qt/optionsdialog.cpp \ qt/optionsmodel.cpp \ qt/peertablemodel.cpp \ + qt/peertablesortproxy.cpp \ qt/qvalidatedlineedit.cpp \ qt/qvaluecombobox.cpp \ qt/rpcconsole.cpp \ diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 9ee3c43cf9462..a69599f28e59d 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -42,7 +43,11 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO { cachedBestHeaderHeight = -1; cachedBestHeaderTime = -1; + peerTableModel = new PeerTableModel(m_node, this); + m_peer_table_sort_proxy = new PeerTableSortProxy(this); + m_peer_table_sort_proxy->setSourceModel(peerTableModel); + banTableModel = new BanTableModel(m_node, this); mnListCached = std::make_shared(); @@ -219,6 +224,11 @@ PeerTableModel *ClientModel::getPeerTableModel() return peerTableModel; } +PeerTableSortProxy* ClientModel::peerTableSortProxy() +{ + return m_peer_table_sort_proxy; +} + BanTableModel *ClientModel::getBanTableModel() { return banTableModel; diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 46068ca264ef6..e5933ab9f84f8 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -20,6 +20,7 @@ class BanTableModel; class CBlockIndex; class OptionsModel; class PeerTableModel; +class PeerTableSortProxy; enum class SynchronizationState; QT_BEGIN_NAMESPACE @@ -58,6 +59,7 @@ class ClientModel : public QObject interfaces::CoinJoin::Options& coinJoinOptions() const { return m_node.coinJoinOptions(); } OptionsModel *getOptionsModel(); PeerTableModel *getPeerTableModel(); + PeerTableSortProxy* peerTableSortProxy(); BanTableModel *getBanTableModel(); //! Return number of connections, default is in- and outbound (total) @@ -109,6 +111,7 @@ class ClientModel : public QObject std::unique_ptr m_handler_notify_additional_data_sync_progess_changed; OptionsModel *optionsModel; PeerTableModel *peerTableModel; + PeerTableSortProxy* m_peer_table_sort_proxy{nullptr}; BanTableModel *banTableModel; //! A thread to interact with m_node asynchronously diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 5c60e25f8f9f9..1dfc1953908e1 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -11,56 +11,19 @@ #include -#include #include #include -bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const -{ - const CNodeStats *pLeft = &(left.nodeStats); - const CNodeStats *pRight = &(right.nodeStats); - - if (order == Qt::DescendingOrder) - std::swap(pLeft, pRight); - - switch (static_cast(column)) { - case PeerTableModel::NetNodeId: - return pLeft->nodeid < pRight->nodeid; - case PeerTableModel::Address: - return pLeft->m_addr_name.compare(pRight->m_addr_name) < 0; - case PeerTableModel::ConnectionType: - return pLeft->m_conn_type < pRight->m_conn_type; - case PeerTableModel::Network: - return pLeft->m_network < pRight->m_network; - case PeerTableModel::Ping: - return pLeft->m_min_ping_time < pRight->m_min_ping_time; - case PeerTableModel::Sent: - return pLeft->nSendBytes < pRight->nSendBytes; - case PeerTableModel::Received: - return pLeft->nRecvBytes < pRight->nRecvBytes; - case PeerTableModel::Subversion: - return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; - } // no default case, so the compiler can warn about missing cases - assert(false); -} - // private implementation class PeerTablePriv { public: /** Local cache of peer information */ QList cachedNodeStats; - /** Column to sort nodes by (default to unsorted) */ - int sortColumn{-1}; - /** Order (ascending or descending) to sort nodes by */ - Qt::SortOrder sortOrder; - /** Index of rows by node ID */ - std::map mapNodeRows; /** Pull a full list of peers from vNodes into our cache */ void refreshPeers(interfaces::Node& node) { - { cachedNodeStats.clear(); interfaces::Node::NodesStats nodes_stats; @@ -75,17 +38,6 @@ class PeerTablePriv stats.nodeStateStats = std::get<2>(node_stats); cachedNodeStats.append(stats); } - } - - if (sortColumn >= 0) - // sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily) - std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder)); - - // build index map - mapNodeRows.clear(); - int row = 0; - for (const CNodeCombinedStats& stats : cachedNodeStats) - mapNodeRows.insert(std::pair(stats.nodeStats.nodeid, row++)); } int size() const @@ -196,10 +148,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const } // no default case, so the compiler can warn about missing cases assert(false); } else if (role == StatsRole) { - switch (index.column()) { - case NetNodeId: return QVariant::fromValue(rec); - default: return QVariant(); - } + return QVariant::fromValue(rec); } return QVariant(); @@ -241,19 +190,3 @@ void PeerTableModel::refresh() priv->refreshPeers(m_node); Q_EMIT layoutChanged(); } - -int PeerTableModel::getRowByNodeId(NodeId nodeid) -{ - std::map::iterator it = priv->mapNodeRows.find(nodeid); - if (it == priv->mapNodeRows.end()) - return -1; - - return it->second; -} - -void PeerTableModel::sort(int column, Qt::SortOrder order) -{ - priv->sortColumn = column; - priv->sortOrder = order; - refresh(); -} diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 66228d609953e..3d195342f1966 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -30,18 +30,6 @@ struct CNodeCombinedStats { }; Q_DECLARE_METATYPE(CNodeCombinedStats*) -class NodeLessThan -{ -public: - NodeLessThan(int nColumn, Qt::SortOrder fOrder) : - column(nColumn), order(fOrder) {} - bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const; - -private: - int column; - Qt::SortOrder order; -}; - /** Qt model providing information about connected peers, similar to the "getpeerinfo" RPC call. Used by the rpc console UI. @@ -53,7 +41,6 @@ class PeerTableModel : public QAbstractTableModel public: explicit PeerTableModel(interfaces::Node& node, QObject* parent); ~PeerTableModel(); - int getRowByNodeId(NodeId nodeid); void startAutoRefresh(); void stopAutoRefresh(); @@ -80,7 +67,6 @@ class PeerTableModel : public QAbstractTableModel QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; - void sort(int column, Qt::SortOrder order) override; /*@}*/ public Q_SLOTS: diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp new file mode 100644 index 0000000000000..ad966fbcabb40 --- /dev/null +++ b/src/qt/peertablesortproxy.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2020 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 + +#include +#include + +#include +#include +#include + +PeerTableSortProxy::PeerTableSortProxy(QObject* parent) + : QSortFilterProxyModel(parent) +{ +} + +bool PeerTableSortProxy::lessThan(const QModelIndex& left_index, const QModelIndex& right_index) const +{ + const CNodeStats left_stats = Assert(sourceModel()->data(left_index, PeerTableModel::StatsRole).value())->nodeStats; + const CNodeStats right_stats = Assert(sourceModel()->data(right_index, PeerTableModel::StatsRole).value())->nodeStats; + + switch (static_cast(left_index.column())) { + case PeerTableModel::NetNodeId: + return left_stats.nodeid < right_stats.nodeid; + case PeerTableModel::Address: + return left_stats.m_addr_name.compare(right_stats.m_addr_name) < 0; + case PeerTableModel::ConnectionType: + return left_stats.m_conn_type < right_stats.m_conn_type; + case PeerTableModel::Network: + return left_stats.m_network < right_stats.m_network; + case PeerTableModel::Ping: + return left_stats.m_min_ping_time < right_stats.m_min_ping_time; + case PeerTableModel::Sent: + return left_stats.nSendBytes < right_stats.nSendBytes; + case PeerTableModel::Received: + return left_stats.nRecvBytes < right_stats.nRecvBytes; + case PeerTableModel::Subversion: + return left_stats.cleanSubVer.compare(right_stats.cleanSubVer) < 0; + } // no default case, so the compiler can warn about missing cases + assert(false); +} diff --git a/src/qt/peertablesortproxy.h b/src/qt/peertablesortproxy.h new file mode 100644 index 0000000000000..1879f6b400bc1 --- /dev/null +++ b/src/qt/peertablesortproxy.h @@ -0,0 +1,25 @@ +// Copyright (c) 2020 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_PEERTABLESORTPROXY_H +#define BITCOIN_QT_PEERTABLESORTPROXY_H + +#include + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class PeerTableSortProxy : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + explicit PeerTableSortProxy(QObject* parent = nullptr); + +protected: + bool lessThan(const QModelIndex& left_index, const QModelIndex& right_index) const override; +}; + +#endif // BITCOIN_QT_PEERTABLESORTPROXY_H diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a42a0e9e2015a..7d2acbde956c1 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -12,12 +12,13 @@ #include -#include -#include -#include #include #include #include +#include +#include +#include +#include #include #include #include @@ -694,7 +695,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // set up peer table - ui->peerWidget->setModel(model->getPeerTableModel()); + ui->peerWidget->setModel(model->peerTableSortProxy()); ui->peerWidget->verticalHeader()->hide(); ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -716,10 +717,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); - // 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); + connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::updateDetailWidget); // set up ban table ui->banlistWidget->setModel(model->getBanTableModel()); @@ -1198,67 +1196,6 @@ void RPCConsole::setTrafficGraphRange(TrafficGraphData::GraphRange range) ui->lblGraphRange->setText(GUIUtil::formatDurationStr(std::chrono::minutes{TrafficGraphData::RangeMinutes[range]})); } -void RPCConsole::peerLayoutAboutToChange() -{ - cachedNodeids.clear(); - for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) { - const auto stats = peer.data(PeerTableModel::StatsRole).value(); - cachedNodeids.append(stats->nodeStats.nodeid); - } -} - -void RPCConsole::peerLayoutChanged() -{ - if (!clientModel || !clientModel->getPeerTableModel()) - return; - - bool fUnselect = false; - bool fReselect = false; - - if (cachedNodeids.empty()) // no node selected yet - 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; - } - } - - if (fUnselect && selectedRow >= 0) { - clearSelectedNode(); - } - - if (fReselect) - { - for(int i = 0; i < cachedNodeids.size(); i++) - { - ui->peerWidget->selectRow(clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.at(i))); - } - } - - updateDetailWidget(); -} - void RPCConsole::updateDetailWidget() { const QList selected_peers = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 2834311ca5666..7cbb36c20f898 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -134,10 +134,6 @@ public Q_SLOTS: void browseHistory(int offset); /** Scroll console view to end */ void scrollToEnd(); - /** 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 */ From 1d56d207cdf0edca38303d154ff80e8652256c39 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 10 May 2021 23:39:09 +0300 Subject: [PATCH 06/13] Merge bitcoin-core/gui#257: refactor: Use template function qOverload in signal-slot connections cdbc2bd1f1c171848c1fef7f217afe140e1afb06 qt: Use template function qOverload in signal-slot connections (Hennadii Stepanov) Pull request description: A nice template function [`qOverload`](https://doc.qt.io/qt-5/qtglobal.html#qOverload) is available for us now (https://github.com/bitcoin/bitcoin/pull/20413, https://github.com/bitcoin/bitcoin/pull/21286). Its usage makes code much more readable. This PR does not change behavior. ACKs for top commit: Talkless: utACK cdbc2bd1f1c171848c1fef7f217afe140e1afb06. promag: Code review ACK cdbc2bd1f1c171848c1fef7f217afe140e1afb06. Tree-SHA512: 72002aa646b1a79bab62d498825b3f245dc7ebdc189280f8bd3b4076e1bb50be8802c02bc872ff6f70c1ea81faec66d3bec36471119dd98c9e70d87b990396ae --- src/qt/bitcoingui.cpp | 2 +- src/qt/intro.cpp | 2 +- src/qt/optionsdialog.cpp | 14 +++++++------- src/qt/qvaluecombobox.cpp | 2 +- src/qt/rpcconsole.cpp | 2 +- src/qt/sendcoinsdialog.cpp | 8 ++++---- src/qt/transactionview.cpp | 10 +++++----- src/qt/walletview.cpp | 6 +++--- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b6ae30d224ee4..3abef864e3f27 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -746,7 +746,7 @@ void BitcoinGUI::createToolBars() #ifdef ENABLE_WALLET m_wallet_selector = new QComboBox(this); m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents); - connect(m_wallet_selector, static_cast(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex); + connect(m_wallet_selector, qOverload(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex); QVBoxLayout* walletSelectorLayout = new QVBoxLayout(this); walletSelectorLayout->addWidget(m_wallet_selector); diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index ed522c61f4d1c..aeb5507b91bc0 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -156,7 +156,7 @@ Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_si UpdatePruneLabels(prune_checked); UpdateFreeSpaceLabel(); }); - connect(ui->pruneGB, QOverload::of(&QSpinBox::valueChanged), [this](int prune_GB) { + connect(ui->pruneGB, qOverload(&QSpinBox::valueChanged), [this](int prune_GB) { m_prune_target_gb = prune_GB; UpdatePruneLabels(ui->prune->isChecked()); UpdateFreeSpaceLabel(); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 1431342697baf..825e2cbc7ec67 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -258,9 +258,9 @@ void OptionsDialog::setModel(OptionsModel *_model) /* Main */ connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::togglePruneWarning); - connect(ui->pruneSize, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); - connect(ui->databaseCache, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); - connect(ui->threadsScriptVerif, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); + connect(ui->pruneSize, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); + connect(ui->databaseCache, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); + connect(ui->threadsScriptVerif, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning); /* Wallet */ connect(ui->showMasternodesTab, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); connect(ui->showGovernanceTab, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); @@ -270,8 +270,8 @@ void OptionsDialog::setModel(OptionsModel *_model) connect(ui->connectSocks, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); connect(ui->connectSocksTor, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning); /* Display */ - connect(ui->digits, static_cast(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); }); - connect(ui->lang, static_cast(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); }); + connect(ui->digits, qOverload<>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); }); + connect(ui->lang, qOverload<>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); }); connect(ui->thirdPartyTxUrls, &QLineEdit::textChanged, [this]{ showRestartWarning(); }); connect(ui->coinJoinEnabled, &QCheckBox::clicked, [=](bool fChecked) { @@ -296,8 +296,8 @@ void OptionsDialog::setModel(OptionsModel *_model) } }); - connect(ui->coinJoinDenomsGoal, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomGoal); - connect(ui->coinJoinDenomsHardCap, static_cast(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomHardCap); + connect(ui->coinJoinDenomsGoal, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomGoal); + connect(ui->coinJoinDenomsHardCap, qOverload(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomHardCap); #endif } diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index 3b2d44c00d193..fa9f50f4d5086 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -7,7 +7,7 @@ QValueComboBox::QValueComboBox(QWidget *parent) : QComboBox(parent), role(Qt::UserRole) { - connect(this, static_cast(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged); + connect(this, qOverload(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged); } QVariant QValueComboBox::value() const diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 7d2acbde956c1..a2a957572e8b4 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1151,7 +1151,7 @@ void RPCConsole::startExecutor() executor->moveToThread(&thread); // Replies from executor object must go to this object - connect(executor, &RPCExecutor::reply, this, static_cast(&RPCConsole::message)); + connect(executor, &RPCExecutor::reply, this, qOverload(&RPCConsole::message)); // Requests from this object must go to executor connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 6ce17d274c59e..067af81be674b 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -207,15 +207,15 @@ void SendCoinsDialog::setModel(WalletModel *_model) for (const int n : confTargets) { ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n)); } - connect(ui->confTargetSelector, static_cast(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel); - connect(ui->confTargetSelector, static_cast(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels); + connect(ui->confTargetSelector, qOverload(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel); + connect(ui->confTargetSelector, qOverload(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels); #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::updateFeeSectionControls); connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::coinControlUpdateLabels); #else - connect(ui->groupFee, static_cast(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls); - connect(ui->groupFee, static_cast(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels); + connect(ui->groupFee, qOverload(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls); + connect(ui->groupFee, qOverload(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels); #endif connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index f016ff872af33..728823d907c50 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -163,12 +163,12 @@ TransactionView::TransactionView(QWidget* parent) : showAddressQRCodeAction->setEnabled(false); #endif - connect(dateWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseDate); - connect(typeWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseType); - connect(watchOnlyWidget, static_cast(&QComboBox::activated), this, &TransactionView::chooseWatchonly); - connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, static_cast(&QTimer::start)); + connect(dateWidget, qOverload(&QComboBox::activated), this, &TransactionView::chooseDate); + connect(typeWidget, qOverload(&QComboBox::activated), this, &TransactionView::chooseType); + connect(watchOnlyWidget, qOverload(&QComboBox::activated), this, &TransactionView::chooseWatchonly); + connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, qOverload<>(&QTimer::start)); connect(amount_typing_delay, &QTimer::timeout, this, &TransactionView::changedAmount); - connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, static_cast(&QTimer::start)); + connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, qOverload<>(&QTimer::start)); connect(prefix_typing_delay, &QTimer::timeout, this, &TransactionView::changedSearch); connect(transactionView, &QTableView::doubleClicked, this, &TransactionView::doubleClicked); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index ac56bfc9c86d8..48605227e783b 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -99,14 +99,14 @@ 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, static_cast(&TransactionView::focusTransaction)); + connect(overviewPage, &OverviewPage::transactionClicked, transactionView, qOverload(&TransactionView::focusTransaction)); connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo); connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); // Highlight transaction after send - connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast(&TransactionView::focusTransaction)); - connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast(&TransactionView::focusTransaction)); + connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, qOverload(&TransactionView::focusTransaction)); + connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, transactionView, qOverload(&TransactionView::focusTransaction)); // Update wallet with sum of selected transactions connect(transactionView, &TransactionView::trxAmount, this, &WalletView::trxAmount); From c2735a8a6789f779d795e6b5b1e17f45fee883ed Mon Sep 17 00:00:00 2001 From: "W. J. van der Laan" Date: Wed, 12 May 2021 14:15:31 +0200 Subject: [PATCH 07/13] Merge bitcoin/bitcoin#21912: doc: Remove mention of priority estimation fa0ad7b9fe2488802d21f7e81d94a2b5f655ffeb doc: Remove mention of priority estimation (MarcoFalke) Pull request description: ACKs for top commit: laanwj: Documentation review ACK fa0ad7b9fe2488802d21f7e81d94a2b5f655ffeb Tree-SHA512: 1be856efc0a25c6bec31e6e58879bbccce18f69cc4f180b285a24362b032f1abeaabc55f9bb064c4c30d3217c38b3f96f52bdf80e13c6069c86cdc4d21f57ef3 --- doc/files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/files.md b/doc/files.md index 97c68727cb327..98a358a9394e8 100644 --- a/doc/files.md +++ b/doc/files.md @@ -65,7 +65,7 @@ Subdirectory | File(s) | Description `./` | `governance.dat` | stores data for governance objects `./` | `mncache.dat` | stores data for masternode list `./` | `netfulfilled.dat` | stores data about recently made network requests -`./` | `fee_estimates.dat` | Stores statistics used to estimate minimum transaction fees and priorities required for confirmation +`./` | `fee_estimates.dat` | Stores statistics used to estimate minimum transaction fees required for confirmation `./` | `guisettings.ini.bak` | Backup of former [GUI settings](#gui-settings) after `-resetguisettings` option is used `./` | `ip_asn.map` | IP addresses to Autonomous System Numbers (ASNs) mapping used for bucketing of the peers; path can be specified with the `-asmap` option `./` | `mempool.dat` | Dump of the mempool's transactions From 0e2e315fcc4f33e42fa0fa39762329f68ef5ae87 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 14 May 2021 08:21:56 +0200 Subject: [PATCH 08/13] Merge bitcoin/bitcoin#21942: docs: improve make with parallel jobs description. 07bc22ef105dee3c6c465a3ef31e52fd198e786d docs: improve make with parallel jobs description. (Klement Tan) Pull request description: Changed `use -jX here for parallelism` to `use "-j N" for N parallel jobs` **Rationale**: In my opinion `use -jX here for parallelism` is quite ambiguous as it could be perceived as a single option without any argument. Ie running: ```sh make -jX ``` Embarrassingly this caused me to be stuck for quite a long time until I opened the help menu for `make` but if I am the only one who faced this issue I would be happy to close this PR. ACKs for top commit: jarolrod: ACK 07bc22ef105dee3c6c465a3ef31e52fd198e786d Tree-SHA512: 2d119b6a461668906c63184b865d2cc9fb2f75abeba34e2e44bc1ef3bcb4adec4a49896ddaf3cc6a20c0095ad20d0de0908401b351eaca9443161d24d6b20d0b --- doc/build-freebsd.md | 2 +- doc/build-netbsd.md | 2 +- doc/build-openbsd.md | 2 +- doc/build-osx.md | 2 +- doc/build-unix.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/build-freebsd.md b/doc/build-freebsd.md index 7525cca863320..d5a3004c8aa0b 100644 --- a/doc/build-freebsd.md +++ b/doc/build-freebsd.md @@ -131,6 +131,6 @@ This explicitly enables the GUI and disables legacy wallet support. If `qt5` is **Important**: Use `gmake` (the non-GNU `make` will exit with an error). ```bash -gmake # use -jX here for parallelism +gmake # use "-j N" for N parallel jobs gmake check # Run tests if Python 3 is available ``` diff --git a/doc/build-netbsd.md b/doc/build-netbsd.md index b455b7371e55a..c28cb4df5b4c9 100644 --- a/doc/build-netbsd.md +++ b/doc/build-netbsd.md @@ -79,6 +79,6 @@ Without wallet: Build and run the tests: ```bash -gmake # use -jX here for parallelism +gmake # use "-j N" here for N parallel jobs gmake check ``` diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index bbda6de352ca0..7b4efce1fd459 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -85,7 +85,7 @@ To configure with GUI: Build and run the tests: ```bash -gmake # use -jX here for parallelism +gmake # use "-j N" here for N parallel jobs gmake check ``` diff --git a/doc/build-osx.md b/doc/build-osx.md index eaae4584751ec..417265793c709 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -276,7 +276,7 @@ After configuration, you are ready to compile. Run the following in your terminal to compile Dash Core: ``` bash -make -jx # use -jX here for parallelism +make # use "-j N" here for N parallel jobs make check # Run tests if Python 3 is available ``` diff --git a/doc/build-unix.md b/doc/build-unix.md index 27f00b5b1e845..07dcd80676cfc 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -22,7 +22,7 @@ To Build ```sh ./autogen.sh ./configure -make +make # use "-j N" for N parallel jobs make install # optional ``` From b442a59b6d8c3077b08b4387b63213b0254a69aa Mon Sep 17 00:00:00 2001 From: "W. J. van der Laan" Date: Tue, 18 May 2021 22:03:00 +0200 Subject: [PATCH 09/13] Merge bitcoin/bitcoin#21988: doc: note that brew installed qt is not supported 33b0b26a03a401bd39b88931b69d162c3c538d31 doc: note that brew installed qt is not supported (Raul Siles) Pull request description: picking up #21791, the author has stated they [cannot squash](https://github.com/bitcoin/bitcoin/pull/21791#issuecomment-828770283). This is a useful note to prevent any issues from being opened up about this. The reason that both cannot co-exist and build bitcoin is stated [here](https://github.com/bitcoin/bitcoin/pull/21791#issuecomment-837278123): > ... the reason is sharing /usr/local/include/ and /usr/local/lib/ directories by both qt5 and qt6 installations. Changes from original PR: - slightly move the note up in this section, this placement seems more appropriate to me - drop "Note:" [PR Render](https://github.com/jarolrod/bitcoin/blob/33b0b26a03a401bd39b88931b69d162c3c538d31/doc/build-osx.md#qt) ACKs for top commit: laanwj: LGTM ACK 33b0b26a03a401bd39b88931b69d162c3c538d31 hebasto: ACK 33b0b26a03a401bd39b88931b69d162c3c538d31 Tree-SHA512: f9efac1921a7a33b5791a9f9f4bada4b5369d358fc42e9884c077bfb4dc3f273fdd4432ce012006a8009dfafb87e13bddd56c6336fe84b6133f4b22f849c289a --- doc/build-osx.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/build-osx.md b/doc/build-osx.md index 417265793c709..4bb04d0f1760e 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -138,6 +138,14 @@ Skip if you don't intend to use the GUI. brew install qt@5 ``` +Ensure that the `qt@5` package is installed, not the `qt` package. +If 'qt' is installed, the build process will fail. +if installed, remove the `qt` package with the following command: + +``` bash +brew uninstall qt +``` + Note: Building with Qt binaries downloaded from the Qt website is not officially supported. See the notes in [#7714](https://github.com/dashpay/dash/issues/7714). From c52b75609b36dc52b52ea072583ce5d8ee58326a Mon Sep 17 00:00:00 2001 From: "W. J. van der Laan" Date: Thu, 20 May 2021 20:54:01 +0200 Subject: [PATCH 10/13] Merge bitcoin-core/gui#281: set shortcuts for console's resize buttons 2a45134b5694c12546d77cdff541612881f7e3e7 qt: Add shortcuts for console font resize buttons (Hennadii Stepanov) a2e122f0fe72d695762db2b83905e246f451300c qt: Add GUIUtil::AddButtonShortcut (Hennadii Stepanov) 4ee9ee72363d46c5ba0c71b8d8283d9c5621e3ed qt: Use native presentation of shortcut (Hennadii Stepanov) Pull request description: On `master` the only way to resize the console font is to manually move your mouse and click the resize buttons. This PR introduces convenient keyboard shortcuts to resize the console font. The common resize shortcuts for applications are `Ctrl+=`/`Ctrl++` and `Ctrl+-`/`Ctrl+_`. This means that the resize QPushButtons need two shortcuts each, but you cannot assign multiple shortcuts to a QPushButton. See: https://doc.qt.io/qt-5/qabstractbutton.html#shortcut-prop To get around this, we introduce a new function in `guiutil`, which connects a supplied `QKeySequence` shortcut to a `QAbstractButton`. This function can be reused in other situations where more than one shortcut is needed for a button. | PR on macOS | PR on Linux | | ---------------- | ------------ | | ![mac-resize-shortcuts](https://user-images.githubusercontent.com/23396902/114750132-a2752580-9d21-11eb-9542-15716f2c257d.gif) | ![linux-resize-shortcuts](https://user-images.githubusercontent.com/23396902/114750165-aacd6080-9d21-11eb-8abc-5388690dcf0b.gif) | ACKs for top commit: hebasto: re-ACK 2a45134b5694c12546d77cdff541612881f7e3e7 Talkless: tACK 2a45134b5694c12546d77cdff541612881f7e3e7, tested on Debian Sid with Qt 5.15.2, shortcuts still work. Tree-SHA512: e894ccb7e5c695ba83998c21a474d6c587c9c849f12ced665c5e0034feb6b143e41b32ba135cab6cfab22cbf153d5a52b1083b2a278e6dfca3f5ad14c0f6c573 --- src/qt/guiutil.cpp | 5 +++++ src/qt/guiutil.h | 9 +++++++++ src/qt/rpcconsole.cpp | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 983ae83752c19..a5875d0d94ce6 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -340,6 +340,11 @@ void setupAppearance(QWidget* parent, OptionsModel* model) } } +void AddButtonShortcut(QAbstractButton* button, const QKeySequence& shortcut) +{ + QObject::connect(new QShortcut(shortcut, button), &QShortcut::activated, [button]() { button->animateClick(); }); +} + bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) { // return if URI is not valid or is no dash: URI diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 07606cea0dd18..8f3cb7df71956 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -44,6 +44,7 @@ class QAction; class QButtonGroup; class QDateTime; class QFont; +class QKeySequence; class QLineEdit; class QMenu; class QPoint; @@ -135,6 +136,14 @@ namespace GUIUtil // Setup appearance settings if not done yet void setupAppearance(QWidget* parent, OptionsModel* model); + /** + * Connects an additional shortcut to a QAbstractButton. Works around the + * one shortcut limitation of the button's shortcut property. + * @param[in] button QAbstractButton to assign shortcut to + * @param[in] shortcut QKeySequence to use as shortcut + */ + void AddButtonShortcut(QAbstractButton* button, const QKeySequence& shortcut); + // Parse "dash:" URI into recipient object, return true on successful parsing bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out); bool parseBitcoinURI(QString uri, SendCoinsRecipient *out); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a2a957572e8b4..12d72d15d8e19 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -936,20 +936,23 @@ void RPCConsole::clear(bool keep_prompt) ).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) + "
" + - tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg(""+clsKey+"") + "
" + - 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); + 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); } void RPCConsole::keyPressEvent(QKeyEvent *event) @@ -1285,8 +1288,18 @@ void RPCConsole::setButtonIcons() { const QSize consoleButtonsSize(BUTTON_ICONSIZE * 0.8, BUTTON_ICONSIZE * 0.8); GUIUtil::setIcon(ui->clearButton, "remove", GUIUtil::ThemedColor::RED, consoleButtonsSize); + GUIUtil::setIcon(ui->fontBiggerButton, "fontbigger", GUIUtil::ThemedColor::BLUE, consoleButtonsSize); + //: Main shortcut to increase the RPC console font size. + ui->fontBiggerButton->setShortcut(tr("Ctrl++")); + //: Secondary shortcut to increase the RPC console font size. + GUIUtil::AddButtonShortcut(ui->fontBiggerButton, tr("Ctrl+=")); + GUIUtil::setIcon(ui->fontSmallerButton, "fontsmaller", GUIUtil::ThemedColor::BLUE, consoleButtonsSize); + //: Main shortcut to decrease the RPC console font size. + ui->fontSmallerButton->setShortcut(tr("Ctrl+-")); + //: Secondary shortcut to decrease the RPC console font size. + GUIUtil::AddButtonShortcut(ui->fontSmallerButton, tr("Ctrl+_")); } void RPCConsole::reloadThemedWidgets() From ed56e28a7c50578b5a703b11cdc5fa37e88b949f Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 20 May 2021 23:57:50 +0300 Subject: [PATCH 11/13] Merge bitcoin-core/gui#335: test: Use QSignalSpy instead of QEventLoop 7eea659fc908e5edfc90c185a6958ed07ecf5cd4 qt, test: use qsignalspy instead of qeventloop (Jarol Rodriguez) Pull request description: This PR refactors our GUI `apptests` to use [QSignalSpy](https://doc.qt.io/qt-5/qsignalspy.html) instead of [QEventLoop](https://doc.qt.io/qt-5/qeventloop.html). `QSignalSpy` is more appropriate for our GUI test's as it is purpose-built for testing emission of signals and sets up its own `QEventLoop` when the `wait` function is called. ACKs for top commit: hebasto: ACK 7eea659fc908e5edfc90c185a6958ed07ecf5cd4, tested on Linux Mint 20.1 (Qt 5.12.8). promag: Code review ACK 7eea659fc908e5edfc90c185a6958ed07ecf5cd4. Tree-SHA512: 3adddbcc5efd726302b606980c9923025c44bb8ee16cb8a183e633e423179c0822db66de9ccba20dc5124fff34af4151a379c9cd18130625c60789ce809ee6fd --- src/qt/test/apptests.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 38d446186b282..547ff055658cf 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -20,10 +20,10 @@ #endif #include -#include #include #include #include +#include #include #include #include @@ -34,13 +34,14 @@ namespace { //! Call getblockchaininfo RPC and check first field of JSON output. void TestRpcCommand(RPCConsole* console) { - QEventLoop loop; QTextEdit* messagesWidget = console->findChild("messagesWidget"); - QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit); QLineEdit* lineEdit = console->findChild("lineEdit"); + QSignalSpy mw_spy(messagesWidget, &QTextEdit::textChanged); + QVERIFY(mw_spy.isValid()); QTest::keyClicks(lineEdit, "getblockchaininfo"); QTest::keyClick(lineEdit, Qt::Key_Return); - loop.exec(); + QVERIFY(mw_spy.wait(1000)); + QCOMPARE(mw_spy.count(), 2); QString output = messagesWidget->toPlainText(); UniValue value; value.read(output.right(output.size() - output.indexOf("{")).toStdString()); From 25f87b9434b98a524d38a97d9fe580acc0fa47ce Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 26 May 2021 13:24:01 +0300 Subject: [PATCH 12/13] Merge bitcoin-core/gui#121: Early subscribe core signals in transaction table model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cafef080a2e59c2bcae6baeee3c3c7e187e931ae qt: Refactor to remove unnecessary block in DispatchNotifications (João Barbosa) 57785fb7f61e51e8a8a459486a594443665ea8c9 qt: Early subscribe core signals in transaction table model (João Barbosa) c6cbdf1a90a253fef0259b365a782bf88cd437f2 qt: Refactor ShowProgress to DispatchNotifications (João Barbosa) 3bccd50ad2f384e6c8c97c7f44bda7ae0d777696 qt: Set flag after inital load on transaction table model (João Barbosa) Pull request description: This fixes the case where transaction notifications arrive between `getWalletTxs` and `subscribeToCoreSignals`. Basically notifications are queued until `getWalletTxs` and wallet rescan complete. This is also a requirement to call `getWalletTxs` in a background thread. Motivated by https://github.com/bitcoin/bitcoin/issues/20241. ACKs for top commit: jonatack: tACK cafef080a2e59c2bcae6baeee3c3c7e187e931ae ryanofsky: Code review ACK cafef080a2e59c2bcae6baeee3c3c7e187e931ae. Only change since last review is splitting commits and replacing m_progress with m_loading. meshcollider: Code review ACK cafef080a2e59c2bcae6baeee3c3c7e187e931ae Tree-SHA512: 003caab2f2ae3522619711c8d02d521d2b8f7f280a467f6c3d08abf37ca81cc66b4b9fa10acfdf34e5fe250da7b696cfeec435f72b53c1ea97ccda96d8b4be33 --- src/qt/transactiontablemodel.cpp | 62 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index c08c7db2f92ef..a738428c6c84e 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -95,21 +95,23 @@ class TransactionTablePriv */ QList cachedWallet; - bool fQueueNotifications = false; + /** True when model finishes loading all wallet transactions on start */ + bool m_loaded = false; + /** True when transactions are being notified, for instance when scanning */ + bool m_loading = false; std::vector< TransactionNotification > vQueueNotifications; void NotifyTransactionChanged(const uint256 &hash, ChangeType status); void NotifyAddressBookChanged(const CTxDestination &address, const std::string &label, bool isMine, const std::string &purpose, ChangeType status); - void ShowProgress(const std::string &title, int nProgress); + void DispatchNotifications(); /* Query entire wallet anew from core. */ void refreshWallet(interfaces::Wallet& wallet) { - qDebug() << "TransactionTablePriv::refreshWallet"; parent->beginResetModel(); + assert(!m_loaded); try { - cachedWallet.clear(); for (const auto& wtx : wallet.getWalletTxs()) { if (TransactionRecord::showTransaction()) { cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, wtx)); @@ -119,6 +121,8 @@ class TransactionTablePriv QMessageBox::critical(nullptr, PACKAGE_NAME, QString("Failed to refresh wallet table: ") + QString::fromStdString(e.what())); } parent->endResetModel(); + m_loaded = true; + DispatchNotifications(); } /* Update our model of the wallet incrementally, to synchronize our model of the wallet @@ -267,12 +271,12 @@ TransactionTableModel::TransactionTableModel(WalletModel *parent): fProcessingQueuedTransactions(false), cachedChainLockHeight(-1) { + subscribeToCoreSignals(); + columns << QString() << QString() << tr("Date") << tr("Type") << tr("Address / Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); priv->refreshWallet(walletModel->wallet()); connect(walletModel->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &TransactionTableModel::updateDisplayUnit); - - subscribeToCoreSignals(); } TransactionTableModel::~TransactionTableModel() @@ -793,7 +797,7 @@ void TransactionTablePriv::NotifyTransactionChanged(const uint256 &hash, ChangeT TransactionNotification notification(hash, status, showTransaction); - if (fQueueNotifications) + if (!m_loaded || m_loading) { vQueueNotifications.push_back(notification); return; @@ -812,35 +816,30 @@ void TransactionTablePriv::NotifyAddressBookChanged(const CTxDestination &addres assert(invoked); } -void TransactionTablePriv::ShowProgress(const std::string &title, int nProgress) +void TransactionTablePriv::DispatchNotifications() { - if (nProgress == 0) - fQueueNotifications = true; + if (!m_loaded || m_loading) return; - if (nProgress == 100) - { - fQueueNotifications = false; - if (vQueueNotifications.size() < 10000) { - if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons - bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true)); + if (vQueueNotifications.size() < 10000) { + if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons + bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true)); + assert(invoked); + } + for (unsigned int i = 0; i < vQueueNotifications.size(); ++i) + { + if (vQueueNotifications.size() - i <= 10) { + bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false)); assert(invoked); } - for (unsigned int i = 0; i < vQueueNotifications.size(); ++i) - { - if (vQueueNotifications.size() - i <= 10) { - bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false)); - assert(invoked); - } - vQueueNotifications[i].invoke(parent); - } - } else { - // it's much faster to just refresh the whole thing instead - bool invoked = QMetaObject::invokeMethod(parent, "refreshWallet", Qt::QueuedConnection); - assert(invoked); + vQueueNotifications[i].invoke(parent); } - vQueueNotifications.clear(); + } else { + // it's much faster to just refresh the whole thing instead + bool invoked = QMetaObject::invokeMethod(parent, "refreshWallet", Qt::QueuedConnection); + assert(invoked); } + vQueueNotifications.clear(); } void TransactionTableModel::subscribeToCoreSignals() @@ -848,7 +847,10 @@ void TransactionTableModel::subscribeToCoreSignals() // Connect signals to wallet m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(std::bind(&TransactionTablePriv::NotifyTransactionChanged, priv, std::placeholders::_1, std::placeholders::_2)); m_handler_address_book_changed = walletModel->wallet().handleAddressBookChanged(std::bind(&TransactionTablePriv::NotifyAddressBookChanged, priv, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(&TransactionTablePriv::ShowProgress, priv, std::placeholders::_1, std::placeholders::_2)); + m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) { + priv->m_loading = progress < 100; + priv->DispatchNotifications(); + }); } void TransactionTableModel::unsubscribeFromCoreSignals() From c7d3161b3bdb18f2d93e9b0912149c16f650235a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 15 Jun 2021 00:50:24 +0300 Subject: [PATCH 13/13] Merge bitcoin-core/gui#362: Add keyboard shortcuts to context menus e4c916a0ea0637f4a765b1cb57ee10abef6fb4d6 Bugfix: GUI: Use a different shortcut for "1 d&ay" banning, due to conflict with "&Disconnect" (Luke Dashjr) 94e7cdd7e04ca79f89474df1400e1a189e068939 GUI: Add keyboard shortcuts for other context menus (Luke Dashjr) 02b5263cd4e02aa540cab35c2bf6cf9eda3522ae GUI: Restore keyboard shortcuts for context menu entries (Luke Dashjr) Pull request description: Various keyboard shortcuts were lost in #263; this restores them, and also adds new ones for other context menus. Note that with a context menu open, simply the shortcut by itself (no Alt) is used. ACKs for top commit: jarolrod: Code Review ACK e4c916a hebasto: ACK e4c916a0ea0637f4a765b1cb57ee10abef6fb4d6, tested on Linux Mint 20.1 (Qt 5.12.8). Tree-SHA512: 949461acf7aac592bc48a1c5abad41b167365830e0cedb3aa11b6a87bd347e16126830ea87936f9c9efc4b7df5b09d3833fae784964d6d119ed45703cfba2ffd --- src/qt/addressbookpage.cpp | 10 +++++----- src/qt/coincontroldialog.cpp | 12 ++++++------ src/qt/qrimagewidget.cpp | 4 ++-- src/qt/receivecoinsdialog.cpp | 10 +++++----- src/qt/rpcconsole.cpp | 12 ++++++------ src/qt/transactionview.cpp | 22 +++++++++++----------- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 9f8510b605bc5..b9db3fa5eb76e 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -109,16 +109,16 @@ AddressBookPage::AddressBookPage(Mode _mode, Tabs _tab, QWidget* parent) : // Build context menu contextMenu = new QMenu(this); - contextMenu->addAction(tr("Copy Address"), this, &AddressBookPage::on_copyAddress_clicked); - contextMenu->addAction(tr("Copy Label"), this, &AddressBookPage::onCopyLabelAction); - contextMenu->addAction(tr("Edit"), this, &AddressBookPage::onEditAction); - [[maybe_unused]] QAction* qrAction = contextMenu->addAction(tr("Show address QR code"), this, &AddressBookPage::on_showAddressQRCode_clicked); + contextMenu->addAction(tr("&Copy Address"), this, &AddressBookPage::on_copyAddress_clicked); + contextMenu->addAction(tr("Copy &Label"), this, &AddressBookPage::onCopyLabelAction); + contextMenu->addAction(tr("&Edit"), this, &AddressBookPage::onEditAction); + [[maybe_unused]] QAction* qrAction = contextMenu->addAction(tr("Show address &QR code"), this, &AddressBookPage::on_showAddressQRCode_clicked); #ifndef USE_QRCODE qrAction->setEnabled(false); #endif if (tab == SendingTab) { - contextMenu->addAction(tr("Delete"), this, &AddressBookPage::on_deleteAddress_clicked); + contextMenu->addAction(tr("&Delete"), this, &AddressBookPage::on_deleteAddress_clicked); } connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 9fd492cb97aa6..8a88c6161bce3 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -64,13 +64,13 @@ CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _m // context menu contextMenu = new QMenu(this); - contextMenu->addAction(tr("Copy address"), this, &CoinControlDialog::copyAddress); - contextMenu->addAction(tr("Copy label"), this, &CoinControlDialog::copyLabel); - contextMenu->addAction(tr("Copy amount"), this, &CoinControlDialog::copyAmount); - copyTransactionHashAction = contextMenu->addAction(tr("Copy transaction ID"), this, &CoinControlDialog::copyTransactionHash); + contextMenu->addAction(tr("&Copy address"), this, &CoinControlDialog::copyAddress); + contextMenu->addAction(tr("Copy &label"), this, &CoinControlDialog::copyLabel); + contextMenu->addAction(tr("Copy &amount"), this, &CoinControlDialog::copyAmount); + copyTransactionHashAction = contextMenu->addAction(tr("Copy transaction &ID"), this, &CoinControlDialog::copyTransactionHash); contextMenu->addSeparator(); - lockAction = contextMenu->addAction(tr("Lock unspent"), this, &CoinControlDialog::lockCoin); - unlockAction = contextMenu->addAction(tr("Unlock unspent"), this, &CoinControlDialog::unlockCoin); + lockAction = contextMenu->addAction(tr("L&ock unspent"), this, &CoinControlDialog::lockCoin); + unlockAction = contextMenu->addAction(tr("&Unlock unspent"), this, &CoinControlDialog::unlockCoin); connect(ui->treeWidget, &QWidget::customContextMenuRequested, this, &CoinControlDialog::showMenu); // clipboard actions diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index c3c6bd0eac7a7..b14416f60c383 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -27,8 +27,8 @@ QRImageWidget::QRImageWidget(QWidget *parent): QLabel(parent), contextMenu(nullptr) { contextMenu = new QMenu(this); - contextMenu->addAction(tr("Save Image…"), this, &QRImageWidget::saveImage); - contextMenu->addAction(tr("Copy Image"), this, &QRImageWidget::copyImage); + contextMenu->addAction(tr("&Save Image…"), this, &QRImageWidget::saveImage); + contextMenu->addAction(tr("&Copy Image"), this, &QRImageWidget::copyImage); } bool QRImageWidget::setQR(const QString& data, const QString& text) diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index b7f2258291bc0..3fe733005d011 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -33,11 +33,11 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) : // context menu contextMenu = new QMenu(this); - contextMenu->addAction(tr("Copy URI"), this, &ReceiveCoinsDialog::copyURI); - contextMenu->addAction(tr("Copy address"), this, &ReceiveCoinsDialog::copyAddress); - copyLabelAction = contextMenu->addAction(tr("Copy label"), this, &ReceiveCoinsDialog::copyLabel); - copyMessageAction = contextMenu->addAction(tr("Copy message"), this, &ReceiveCoinsDialog::copyMessage); - copyAmountAction = contextMenu->addAction(tr("Copy amount"), this, &ReceiveCoinsDialog::copyAmount); + contextMenu->addAction(tr("Copy &URI"), this, &ReceiveCoinsDialog::copyURI); + contextMenu->addAction(tr("&Copy address"), this, &ReceiveCoinsDialog::copyAddress); + copyLabelAction = contextMenu->addAction(tr("Copy &label"), this, &ReceiveCoinsDialog::copyLabel); + copyMessageAction = contextMenu->addAction(tr("Copy &message"), this, &ReceiveCoinsDialog::copyMessage); + copyAmountAction = contextMenu->addAction(tr("Copy &amount"), this, &ReceiveCoinsDialog::copyAmount); connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu); connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 12d72d15d8e19..9abc5c1799274 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -708,11 +708,11 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // create peer table context menu peersTableContextMenu = new QMenu(this); - peersTableContextMenu->addAction(tr("Disconnect"), this, &RPCConsole::disconnectSelectedNode); - peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 hour"), [this] { banSelectedNode(60 * 60); }); - peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 day"), [this] { banSelectedNode(60 * 60 * 24); }); - peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 week"), [this] { banSelectedNode(60 * 60 * 24 * 7); }); - peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 year"), [this] { banSelectedNode(60 * 60 * 24 * 365); }); + peersTableContextMenu->addAction(tr("&Disconnect"), this, &RPCConsole::disconnectSelectedNode); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &hour"), [this] { banSelectedNode(60 * 60); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 d&ay"), [this] { banSelectedNode(60 * 60 * 24); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &week"), [this] { banSelectedNode(60 * 60 * 24 * 7); }); + peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &year"), [this] { banSelectedNode(60 * 60 * 24 * 365); }); connect(ui->peerWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showPeersTableContextMenu); // peer table signal handling - update peer details when selecting new node @@ -731,7 +731,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ // create ban table context menu banTableContextMenu = new QMenu(this); - banTableContextMenu->addAction(tr("Unban"), this, &RPCConsole::unbanSelectedNode); + banTableContextMenu->addAction(tr("&Unban"), this, &RPCConsole::unbanSelectedNode); connect(ui->banlistWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showBanTableContextMenu); // ban table signal handling - clear peer details when clicking a peer in the ban table diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 728823d907c50..d32283c0ec01a 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -147,18 +147,18 @@ TransactionView::TransactionView(QWidget* parent) : contextMenu = new QMenu(this); contextMenu->setObjectName("contextMenu"); - copyAddressAction = contextMenu->addAction(tr("Copy address"), this, &TransactionView::copyAddress); - copyLabelAction = contextMenu->addAction(tr("Copy label"), this, &TransactionView::copyLabel); - contextMenu->addAction(tr("Copy amount"), this, &TransactionView::copyAmount); - contextMenu->addAction(tr("Copy transaction ID"), this, &TransactionView::copyTxID); - contextMenu->addAction(tr("Copy raw transaction"), this, &TransactionView::copyTxHex); - contextMenu->addAction(tr("Copy full transaction details"), this, &TransactionView::copyTxPlainText); - contextMenu->addAction(tr("Show transaction details"), this, &TransactionView::showDetails); + copyAddressAction = contextMenu->addAction(tr("&Copy address"), this, &TransactionView::copyAddress); + copyLabelAction = contextMenu->addAction(tr("Copy &label"), this, &TransactionView::copyLabel); + contextMenu->addAction(tr("Copy &amount"), this, &TransactionView::copyAmount); + contextMenu->addAction(tr("Copy transaction &ID"), this, &TransactionView::copyTxID); + contextMenu->addAction(tr("Copy &raw transaction"), this, &TransactionView::copyTxHex); + contextMenu->addAction(tr("Copy full transaction &details"), this, &TransactionView::copyTxPlainText); + contextMenu->addAction(tr("&Show transaction details"), this, &TransactionView::showDetails); contextMenu->addSeparator(); - abandonAction = contextMenu->addAction(tr("Abandon transaction"), this, &TransactionView::abandonTx); - resendAction = contextMenu->addAction(tr("Resend transaction"), this, &TransactionView::resendTx); - contextMenu->addAction(tr("Edit address label"), this, &TransactionView::editLabel); - [[maybe_unused]] QAction* showAddressQRCodeAction = contextMenu->addAction(tr("Show address QR code"), this, &TransactionView::showAddressQRCode); + abandonAction = contextMenu->addAction(tr("A&bandon transaction"), this, &TransactionView::abandonTx); + resendAction = contextMenu->addAction(tr("Rese&nd transaction"), this, &TransactionView::resendTx); + contextMenu->addAction(tr("&Edit address label"), this, &TransactionView::editLabel); + [[maybe_unused]] QAction* showAddressQRCodeAction = contextMenu->addAction(tr("Show address &QR code"), this, &TransactionView::showAddressQRCode); #ifndef USE_QRCODE showAddressQRCodeAction->setEnabled(false); #endif