From 3aad6a9b6b0d0f7906a66f2f87a950f72e63ee8d Mon Sep 17 00:00:00 2001 From: apogio Date: Sun, 5 Oct 2025 20:42:34 +0300 Subject: [PATCH] gui: add coins (UTXOs) tab and makes it view-only - Shows Coins tab next to Transactions - Adds view-only mode to coin control dialog --- src/qt/bitcoin.qrc | 1 + src/qt/bitcoingui.cpp | 66 +++++++++++++++++++++++++++++++++++ src/qt/bitcoingui.h | 9 +++++ src/qt/coincontroldialog.cpp | 41 ++++++++++++++++++++-- src/qt/coincontroldialog.h | 4 +++ src/qt/res/icons/coins.png | Bin 0 -> 10310 bytes src/qt/res/src/coins.svg | 15 ++++++++ src/qt/walletview.cpp | 30 ++++++++++++++++ src/qt/walletview.h | 11 ++++++ 9 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 src/qt/res/icons/coins.png create mode 100644 src/qt/res/src/coins.svg diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index fed373e551c..c3a68966bd2 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -3,6 +3,7 @@ res/icons/bitcoin.png res/icons/address-book.png res/icons/send.png + res/icons/coins.png res/icons/connect0.png res/icons/connect1.png res/icons/connect2.png diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 9413356b412..a65d7709bde 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -277,6 +277,13 @@ void BitcoinGUI::createActions() historyAction->setShortcut(QKeySequence(QStringLiteral("Alt+4"))); tabGroup->addAction(historyAction); + showCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/coins"), tr("&Coins"), this); + showCoinsAction->setStatusTip(tr("View wallet coins (UTXOs)")); + showCoinsAction->setToolTip(showCoinsAction->statusTip()); + showCoinsAction->setCheckable(true); + showCoinsAction->setShortcut(QKeySequence(QStringLiteral("Alt+5"))); + tabGroup->addAction(showCoinsAction); + #ifdef ENABLE_WALLET // These showNormalIfMinimized are needed because Send Coins and Receive Coins // can be triggered from the tray menu, and need to show the GUI to be useful. @@ -288,6 +295,7 @@ void BitcoinGUI::createActions() connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage); + connect(showCoinsAction, &QAction::triggered, this, &BitcoinGUI::showCoins); #endif // ENABLE_WALLET quitAction = new QAction(tr("E&xit"), this); @@ -601,8 +609,12 @@ void BitcoinGUI::createToolBars() toolbar->addAction(sendCoinsAction); toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); + toolbar->addAction(showCoinsAction); overviewAction->setChecked(true); + showCoinsAction->setVisible(false); + showCoinsAction->setEnabled(false); + #ifdef ENABLE_WALLET QWidget *spacer = new QWidget(); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -676,6 +688,14 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH } m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool()); + + // watch for runtime changes and hide/show the coins tab accordingly + updateCoinsTabVisibility(); + if (optionsModel) { + connect(optionsModel, &OptionsModel::coinControlFeaturesChanged, this, [this](bool) { + updateCoinsTabVisibility(); + }); + } } else { // Shutdown requested, disable menus if (trayIconMenu) @@ -822,6 +842,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) sendCoinsAction->setEnabled(enabled); receiveCoinsAction->setEnabled(enabled); historyAction->setEnabled(enabled); + showCoinsAction->setEnabled(enabled); encryptWalletAction->setEnabled(enabled); backupWalletAction->setEnabled(enabled); changePassphraseAction->setEnabled(enabled); @@ -832,6 +853,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) openAction->setEnabled(enabled); m_close_wallet_action->setEnabled(enabled); m_close_all_wallets_action->setEnabled(enabled); + m_wallet_actions_enabled = enabled; + updateCoinsTabVisibility(); } void BitcoinGUI::createTrayIcon() @@ -1293,6 +1316,7 @@ void BitcoinGUI::changeEvent(QEvent *e) sendCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/send"))); receiveCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/receiving_addresses"))); historyAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/history"))); + showCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/coins"))); } QMainWindow::changeEvent(e); @@ -1468,6 +1492,24 @@ void BitcoinGUI::updateWalletStatus() } #endif // ENABLE_WALLET +#ifdef ENABLE_WALLET +void BitcoinGUI::showCoins() +{ + if (!(clientModel && clientModel->getOptionsModel() && clientModel->getOptionsModel()->getCoinControlFeatures())) { + if (overviewAction) overviewAction->setChecked(true); + // if user disables coin control features while this view is active, switch to overview + if (walletFrame) walletFrame->gotoOverviewPage(); + return; + } + + if (showCoinsAction) showCoinsAction->setChecked(true); + if (!walletFrame) return; + if (WalletView* wv = walletFrame->currentWalletView()) { + wv->gotoCoinsPage(); + } +} +#endif // ENABLE_WALLET + void BitcoinGUI::updateProxyIcon() { std::string ip_port; @@ -1680,3 +1722,27 @@ void UnitDisplayStatusBarControl::onMenuSelection(QAction* action) optionsModel->setDisplayUnit(action->data()); } } + +void BitcoinGUI::updateCoinsTabVisibility() +{ + if (!showCoinsAction) return; + + bool coin_control_enabled = false; + if (clientModel && clientModel->getOptionsModel()) { + coin_control_enabled = clientModel->getOptionsModel()->getCoinControlFeatures(); + } + + // Visible only when wallet is compiled/enabled and coin control is enabled + const bool visible = enableWallet && coin_control_enabled; + showCoinsAction->setVisible(visible); + + // Enabled only when visible and wallet actions are globally enabled + showCoinsAction->setEnabled(visible && m_wallet_actions_enabled); + +#ifdef ENABLE_WALLET + // If the Coins tab is active but we turn it off, switch to Overview page + if (!visible && showCoinsAction->isChecked()) { + gotoOverviewPage(); + } +#endif +} diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 32fb7488fb0..2d3711fef46 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -136,6 +136,7 @@ class BitcoinGUI : public QMainWindow QAction* historyAction = nullptr; QAction* quitAction = nullptr; QAction* sendCoinsAction = nullptr; + QAction* showCoinsAction = nullptr; QAction* usedSendingAddressesAction = nullptr; QAction* usedReceivingAddressesAction = nullptr; QAction* signMessageAction = nullptr; @@ -213,6 +214,12 @@ class BitcoinGUI : public QMainWindow /** Open the OptionsDialog on the specified tab index */ void openOptionsDialogWithTab(OptionsDialog::Tab tab); + // Track whether wallet actions are globally enabled + bool m_wallet_actions_enabled{false}; + + /** Update the visibility and enabled state of the Coins tab/action based on options. */ + void updateCoinsTabVisibility(); + Q_SIGNALS: void quitRequested(); /** Signal raised when a URI was entered or dragged to the GUI */ @@ -283,6 +290,8 @@ public Q_SLOTS: void gotoReceiveCoinsPage(); /** Switch to send coins page */ void gotoSendCoinsPage(QString addr = ""); + /** Switch to show coins page*/ + void showCoins(); /** Show Sign/Verify Message dialog and switch to sign message tab */ void gotoSignMessageTab(QString addr = ""); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index febf1ee82fa..50867b80fba 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -550,6 +550,39 @@ void CoinControlDialog::changeEvent(QEvent* e) QDialog::changeEvent(e); } +void CoinControlDialog::setViewOnly(bool view_only) +{ + m_view_only = view_only; + + ui->pushButtonSelectAll->setVisible(true); + ui->treeWidget->setColumnHidden(COLUMN_CHECKBOX, false); + ui->frame->setVisible(true); + + ui->radioListMode->setVisible(true); + ui->radioTreeMode->setVisible(true); + ui->radioListMode->setEnabled(true); + ui->radioTreeMode->setEnabled(true); + + ui->labelCoinControlQuantity->setVisible(true); + ui->labelCoinControlAmount->setVisible(true); + ui->labelCoinControlFee->setVisible(!view_only); + ui->labelCoinControlAfterFee->setVisible(!view_only); + ui->labelCoinControlBytes->setVisible(!view_only); + ui->labelCoinControlChange->setVisible(!view_only); + + ui->labelCoinControlQuantityText->setVisible(true); + ui->labelCoinControlAmountText->setVisible(true); + ui->labelCoinControlFeeText->setVisible(!view_only); + ui->labelCoinControlAfterFeeText->setVisible(!view_only); + ui->labelCoinControlBytesText->setVisible(!view_only); + ui->labelCoinControlChangeText->setVisible(!view_only); + + if (view_only) { + lockAction->setVisible(false); + unlockAction->setVisible(false); + } +} + void CoinControlDialog::updateView() { if (!model || !model->getOptionsModel() || !model->getAddressTableModel()) @@ -560,8 +593,9 @@ void CoinControlDialog::updateView() ui->treeWidget->clear(); ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox ui->treeWidget->setAlternatingRowColors(!treeMode); - QFlags flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; - QFlags flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate; + + QFlags flgCheckbox = (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + QFlags flgTristate = (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate); BitcoinUnit nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); @@ -578,6 +612,7 @@ void CoinControlDialog::updateView() itemWalletAddress = new CCoinControlWidgetItem(ui->treeWidget); itemWalletAddress->setFlags(flgTristate); + itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); // label @@ -599,7 +634,7 @@ void CoinControlDialog::updateView() if (treeMode) itemOutput = new CCoinControlWidgetItem(itemWalletAddress); else itemOutput = new CCoinControlWidgetItem(ui->treeWidget); itemOutput->setFlags(flgCheckbox); - itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); + itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); // address CTxDestination outputAddress; diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 5fc2cdca9b7..8878c148fa6 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -53,6 +53,8 @@ class CoinControlDialog : public QDialog static QList payAmounts; static bool fSubtractFeeFromAmount; + void setViewOnly(bool view_only); + protected: void changeEvent(QEvent* e) override; @@ -71,6 +73,8 @@ class CoinControlDialog : public QDialog const PlatformStyle *platformStyle; + bool m_view_only{false}; + void sortView(int, Qt::SortOrder); void updateView(); diff --git a/src/qt/res/icons/coins.png b/src/qt/res/icons/coins.png new file mode 100644 index 0000000000000000000000000000000000000000..34a8f017d8fbaea258e490cb5497d5de5c4e6cad GIT binary patch literal 10310 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 literal 0 HcmV?d00001 diff --git a/src/qt/res/src/coins.svg b/src/qt/res/src/coins.svg new file mode 100644 index 00000000000..8835674bdd7 --- /dev/null +++ b/src/qt/res/src/coins.svg @@ -0,0 +1,15 @@ + + + + coin_2_line + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 39e9dcadeed..40c8e05a1da 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #include #include @@ -69,10 +72,26 @@ WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platform usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this); usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel()); + // Create embedded Coins (UTXOs) page + coinsPage = new QWidget(this); + { + QVBoxLayout* coinsLayout = new QVBoxLayout(coinsPage); + coinsWidget = new CoinControlDialog(coinsPageCoinControl, walletModel, platformStyle, coinsPage); + coinsWidget->setViewOnly(true); + // Make it behave as a plain widget in-page + coinsWidget->setWindowFlags(Qt::Widget); + // Hide the dialog button box when embedded + if (auto bb = coinsWidget->findChild("buttonBox")) { + bb->setVisible(false); + } + coinsLayout->addWidget(coinsWidget); + } + addWidget(overviewPage); addWidget(transactionsPage); addWidget(receiveCoinsPage); addWidget(sendCoinsPage); + addWidget(coinsPage); connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked); // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page @@ -166,6 +185,17 @@ void WalletView::gotoSendCoinsPage(QString addr) sendCoinsPage->setAddress(addr); } +void WalletView::gotoCoinsPage() +{ + setCurrentWidget(coinsPage); +} + +void WalletView::showCoinsDialog() +{ + if (!walletModel) return; + gotoCoinsPage(); +} + void WalletView::gotoSignMessageTab(QString addr) { // calls show() in showTab_SM() diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 475085044db..119459b24b5 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -10,6 +10,8 @@ #include +#include + class ClientModel; class OverviewPage; class PlatformStyle; @@ -19,6 +21,7 @@ class SendCoinsRecipient; class TransactionView; class WalletModel; class AddressBookPage; +class CoinControlDialog; QT_BEGIN_NAMESPACE class QModelIndex; @@ -65,6 +68,10 @@ class WalletView : public QStackedWidget AddressBookPage *usedSendingAddressesPage; AddressBookPage *usedReceivingAddressesPage; + QWidget* coinsPage{nullptr}; + CoinControlDialog* coinsWidget{nullptr}; + wallet::CCoinControl coinsPageCoinControl; + TransactionView *transactionView; QProgressDialog* progressDialog{nullptr}; @@ -79,6 +86,10 @@ public Q_SLOTS: void gotoReceiveCoinsPage(); /** Switch to send coins page */ void gotoSendCoinsPage(QString addr = ""); + /** Switch to embedded Coins (UTXOs) page */ + void gotoCoinsPage(); + /** Switch to show coins page*/ + void showCoinsDialog(); /** Show Sign/Verify Message dialog and switch to sign message tab */ void gotoSignMessageTab(QString addr = "");