Skip to content

Commit f7c7b34

Browse files
committed
gui: add coins (UTXOs) tab and makes it view-only
- Shows Coins tab next to Transactions - Adds view-only mode to coin control dialog
1 parent d298710 commit f7c7b34

File tree

9 files changed

+174
-3
lines changed

9 files changed

+174
-3
lines changed

src/qt/bitcoin.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<file alias="bitcoin">res/icons/bitcoin.png</file>
44
<file alias="address-book">res/icons/address-book.png</file>
55
<file alias="send">res/icons/send.png</file>
6+
<file alias="coins">res/icons/coins.png</file>
67
<file alias="connect_0">res/icons/connect0.png</file>
78
<file alias="connect_1">res/icons/connect1.png</file>
89
<file alias="connect_2">res/icons/connect2.png</file>

src/qt/bitcoingui.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ void BitcoinGUI::createActions()
277277
historyAction->setShortcut(QKeySequence(QStringLiteral("Alt+4")));
278278
tabGroup->addAction(historyAction);
279279

280+
showCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/coins"), tr("&Coins"), this);
281+
showCoinsAction->setStatusTip(tr("View wallet coins (UTXOs)"));
282+
showCoinsAction->setToolTip(showCoinsAction->statusTip());
283+
showCoinsAction->setCheckable(true);
284+
showCoinsAction->setShortcut(QKeySequence(QStringLiteral("Alt+5")));
285+
tabGroup->addAction(showCoinsAction);
286+
280287
#ifdef ENABLE_WALLET
281288
// These showNormalIfMinimized are needed because Send Coins and Receive Coins
282289
// can be triggered from the tray menu, and need to show the GUI to be useful.
@@ -288,6 +295,7 @@ void BitcoinGUI::createActions()
288295
connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
289296
connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
290297
connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
298+
connect(showCoinsAction, &QAction::triggered, this, &BitcoinGUI::showCoins);
291299
#endif // ENABLE_WALLET
292300

293301
quitAction = new QAction(tr("E&xit"), this);
@@ -601,8 +609,12 @@ void BitcoinGUI::createToolBars()
601609
toolbar->addAction(sendCoinsAction);
602610
toolbar->addAction(receiveCoinsAction);
603611
toolbar->addAction(historyAction);
612+
toolbar->addAction(showCoinsAction);
604613
overviewAction->setChecked(true);
605614

615+
showCoinsAction->setVisible(false);
616+
showCoinsAction->setEnabled(false);
617+
606618
#ifdef ENABLE_WALLET
607619
QWidget *spacer = new QWidget();
608620
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -676,6 +688,14 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
676688
}
677689

678690
m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool());
691+
692+
// watch for runtime changes and hide/show the coins tab accordingly
693+
updateCoinsTabVisibility();
694+
if (optionsModel) {
695+
connect(optionsModel, &OptionsModel::coinControlFeaturesChanged, this, [this](bool) {
696+
updateCoinsTabVisibility();
697+
});
698+
}
679699
} else {
680700
// Shutdown requested, disable menus
681701
if (trayIconMenu)
@@ -822,6 +842,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
822842
sendCoinsAction->setEnabled(enabled);
823843
receiveCoinsAction->setEnabled(enabled);
824844
historyAction->setEnabled(enabled);
845+
showCoinsAction->setEnabled(enabled);
825846
encryptWalletAction->setEnabled(enabled);
826847
backupWalletAction->setEnabled(enabled);
827848
changePassphraseAction->setEnabled(enabled);
@@ -832,6 +853,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
832853
openAction->setEnabled(enabled);
833854
m_close_wallet_action->setEnabled(enabled);
834855
m_close_all_wallets_action->setEnabled(enabled);
856+
m_wallet_actions_enabled = enabled;
857+
updateCoinsTabVisibility();
835858
}
836859

837860
void BitcoinGUI::createTrayIcon()
@@ -1293,6 +1316,7 @@ void BitcoinGUI::changeEvent(QEvent *e)
12931316
sendCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/send")));
12941317
receiveCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/receiving_addresses")));
12951318
historyAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/history")));
1319+
showCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/coins")));
12961320
}
12971321

12981322
QMainWindow::changeEvent(e);
@@ -1468,6 +1492,24 @@ void BitcoinGUI::updateWalletStatus()
14681492
}
14691493
#endif // ENABLE_WALLET
14701494

1495+
#ifdef ENABLE_WALLET
1496+
void BitcoinGUI::showCoins()
1497+
{
1498+
if (!(clientModel && clientModel->getOptionsModel() && clientModel->getOptionsModel()->getCoinControlFeatures())) {
1499+
if (overviewAction) overviewAction->setChecked(true);
1500+
// if user disables coin control features while this view is active, switch to overview
1501+
if (walletFrame) walletFrame->gotoOverviewPage();
1502+
return;
1503+
}
1504+
1505+
if (showCoinsAction) showCoinsAction->setChecked(true);
1506+
if (!walletFrame) return;
1507+
if (WalletView* wv = walletFrame->currentWalletView()) {
1508+
wv->gotoCoinsPage();
1509+
}
1510+
}
1511+
#endif // ENABLE_WALLET
1512+
14711513
void BitcoinGUI::updateProxyIcon()
14721514
{
14731515
std::string ip_port;
@@ -1680,3 +1722,27 @@ void UnitDisplayStatusBarControl::onMenuSelection(QAction* action)
16801722
optionsModel->setDisplayUnit(action->data());
16811723
}
16821724
}
1725+
1726+
void BitcoinGUI::updateCoinsTabVisibility()
1727+
{
1728+
if (!showCoinsAction) return;
1729+
1730+
bool coin_control_enabled = false;
1731+
if (clientModel && clientModel->getOptionsModel()) {
1732+
coin_control_enabled = clientModel->getOptionsModel()->getCoinControlFeatures();
1733+
}
1734+
1735+
// Visible only when wallet is compiled/enabled and coin control is enabled
1736+
const bool visible = enableWallet && coin_control_enabled;
1737+
showCoinsAction->setVisible(visible);
1738+
1739+
// Enabled only when visible and wallet actions are globally enabled
1740+
showCoinsAction->setEnabled(visible && m_wallet_actions_enabled);
1741+
1742+
#ifdef ENABLE_WALLET
1743+
// If the Coins tab is active but we turn it off, switch to Overview page
1744+
if (!visible && showCoinsAction->isChecked()) {
1745+
gotoOverviewPage();
1746+
}
1747+
#endif
1748+
}

src/qt/bitcoingui.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ class BitcoinGUI : public QMainWindow
136136
QAction* historyAction = nullptr;
137137
QAction* quitAction = nullptr;
138138
QAction* sendCoinsAction = nullptr;
139+
QAction* showCoinsAction = nullptr;
139140
QAction* usedSendingAddressesAction = nullptr;
140141
QAction* usedReceivingAddressesAction = nullptr;
141142
QAction* signMessageAction = nullptr;
@@ -213,6 +214,12 @@ class BitcoinGUI : public QMainWindow
213214
/** Open the OptionsDialog on the specified tab index */
214215
void openOptionsDialogWithTab(OptionsDialog::Tab tab);
215216

217+
// Track whether wallet actions are globally enabled
218+
bool m_wallet_actions_enabled{false};
219+
220+
/** Update the visibility and enabled state of the Coins tab/action based on options. */
221+
void updateCoinsTabVisibility();
222+
216223
Q_SIGNALS:
217224
void quitRequested();
218225
/** Signal raised when a URI was entered or dragged to the GUI */
@@ -283,6 +290,8 @@ public Q_SLOTS:
283290
void gotoReceiveCoinsPage();
284291
/** Switch to send coins page */
285292
void gotoSendCoinsPage(QString addr = "");
293+
/** Switch to show coins page*/
294+
void showCoins();
286295

287296
/** Show Sign/Verify Message dialog and switch to sign message tab */
288297
void gotoSignMessageTab(QString addr = "");

src/qt/coincontroldialog.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,39 @@ void CoinControlDialog::changeEvent(QEvent* e)
550550
QDialog::changeEvent(e);
551551
}
552552

553+
void CoinControlDialog::setViewOnly(bool view_only)
554+
{
555+
m_view_only = view_only;
556+
557+
ui->pushButtonSelectAll->setVisible(true);
558+
ui->treeWidget->setColumnHidden(COLUMN_CHECKBOX, false);
559+
ui->frame->setVisible(true);
560+
561+
ui->radioListMode->setVisible(true);
562+
ui->radioTreeMode->setVisible(true);
563+
ui->radioListMode->setEnabled(true);
564+
ui->radioTreeMode->setEnabled(true);
565+
566+
ui->labelCoinControlQuantity->setVisible(true);
567+
ui->labelCoinControlAmount->setVisible(true);
568+
ui->labelCoinControlFee->setVisible(!view_only);
569+
ui->labelCoinControlAfterFee->setVisible(!view_only);
570+
ui->labelCoinControlBytes->setVisible(!view_only);
571+
ui->labelCoinControlChange->setVisible(!view_only);
572+
573+
ui->labelCoinControlQuantityText->setVisible(true);
574+
ui->labelCoinControlAmountText->setVisible(true);
575+
ui->labelCoinControlFeeText->setVisible(!view_only);
576+
ui->labelCoinControlAfterFeeText->setVisible(!view_only);
577+
ui->labelCoinControlBytesText->setVisible(!view_only);
578+
ui->labelCoinControlChangeText->setVisible(!view_only);
579+
580+
if (view_only) {
581+
lockAction->setVisible(false);
582+
unlockAction->setVisible(false);
583+
}
584+
}
585+
553586
void CoinControlDialog::updateView()
554587
{
555588
if (!model || !model->getOptionsModel() || !model->getAddressTableModel())
@@ -560,8 +593,9 @@ void CoinControlDialog::updateView()
560593
ui->treeWidget->clear();
561594
ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
562595
ui->treeWidget->setAlternatingRowColors(!treeMode);
563-
QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
564-
QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate;
596+
597+
QFlags<Qt::ItemFlag> flgCheckbox = (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
598+
QFlags<Qt::ItemFlag> flgTristate = (Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
565599

566600
BitcoinUnit nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
567601

@@ -578,6 +612,7 @@ void CoinControlDialog::updateView()
578612
itemWalletAddress = new CCoinControlWidgetItem(ui->treeWidget);
579613

580614
itemWalletAddress->setFlags(flgTristate);
615+
581616
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
582617

583618
// label
@@ -599,7 +634,7 @@ void CoinControlDialog::updateView()
599634
if (treeMode) itemOutput = new CCoinControlWidgetItem(itemWalletAddress);
600635
else itemOutput = new CCoinControlWidgetItem(ui->treeWidget);
601636
itemOutput->setFlags(flgCheckbox);
602-
itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
637+
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
603638

604639
// address
605640
CTxDestination outputAddress;

src/qt/coincontroldialog.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class CoinControlDialog : public QDialog
5353
static QList<CAmount> payAmounts;
5454
static bool fSubtractFeeFromAmount;
5555

56+
void setViewOnly(bool view_only);
57+
5658
protected:
5759
void changeEvent(QEvent* e) override;
5860

@@ -71,6 +73,8 @@ class CoinControlDialog : public QDialog
7173

7274
const PlatformStyle *platformStyle;
7375

76+
bool m_view_only{false};
77+
7478
void sortView(int, Qt::SortOrder);
7579
void updateView();
7680

src/qt/res/icons/coins.png

10.1 KB
Loading

src/qt/res/src/coins.svg

Lines changed: 15 additions & 0 deletions
Loading

src/qt/walletview.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include <qt/transactiontablemodel.h>
1818
#include <qt/transactionview.h>
1919
#include <qt/walletmodel.h>
20+
#include <qt/coincontroldialog.h>
21+
#include <wallet/coincontrol.h>
22+
#include <QDialogButtonBox>
2023

2124
#include <interfaces/node.h>
2225
#include <node/interface_ui.h>
@@ -69,10 +72,26 @@ WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platform
6972
usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
7073
usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel());
7174

75+
// Create embedded Coins (UTXOs) page
76+
coinsPage = new QWidget(this);
77+
{
78+
QVBoxLayout* coinsLayout = new QVBoxLayout(coinsPage);
79+
coinsWidget = new CoinControlDialog(coinsPageCoinControl, walletModel, platformStyle, coinsPage);
80+
coinsWidget->setViewOnly(true);
81+
// Make it behave as a plain widget in-page
82+
coinsWidget->setWindowFlags(Qt::Widget);
83+
// Hide the dialog button box when embedded
84+
if (auto bb = coinsWidget->findChild<QDialogButtonBox*>("buttonBox")) {
85+
bb->setVisible(false);
86+
}
87+
coinsLayout->addWidget(coinsWidget);
88+
}
89+
7290
addWidget(overviewPage);
7391
addWidget(transactionsPage);
7492
addWidget(receiveCoinsPage);
7593
addWidget(sendCoinsPage);
94+
addWidget(coinsPage);
7695

7796
connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked);
7897
// 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)
166185
sendCoinsPage->setAddress(addr);
167186
}
168187

188+
void WalletView::gotoCoinsPage()
189+
{
190+
setCurrentWidget(coinsPage);
191+
}
192+
193+
void WalletView::showCoinsDialog()
194+
{
195+
if (!walletModel) return;
196+
gotoCoinsPage();
197+
}
198+
169199
void WalletView::gotoSignMessageTab(QString addr)
170200
{
171201
// calls show() in showTab_SM()

src/qt/walletview.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include <QStackedWidget>
1212

13+
#include <wallet/coincontrol.h>
14+
1315
class ClientModel;
1416
class OverviewPage;
1517
class PlatformStyle;
@@ -19,6 +21,7 @@ class SendCoinsRecipient;
1921
class TransactionView;
2022
class WalletModel;
2123
class AddressBookPage;
24+
class CoinControlDialog;
2225

2326
QT_BEGIN_NAMESPACE
2427
class QModelIndex;
@@ -65,6 +68,10 @@ class WalletView : public QStackedWidget
6568
AddressBookPage *usedSendingAddressesPage;
6669
AddressBookPage *usedReceivingAddressesPage;
6770

71+
QWidget* coinsPage{nullptr};
72+
CoinControlDialog* coinsWidget{nullptr};
73+
wallet::CCoinControl coinsPageCoinControl;
74+
6875
TransactionView *transactionView;
6976

7077
QProgressDialog* progressDialog{nullptr};
@@ -79,6 +86,10 @@ public Q_SLOTS:
7986
void gotoReceiveCoinsPage();
8087
/** Switch to send coins page */
8188
void gotoSendCoinsPage(QString addr = "");
89+
/** Switch to embedded Coins (UTXOs) page */
90+
void gotoCoinsPage();
91+
/** Switch to show coins page*/
92+
void showCoinsDialog();
8293

8394
/** Show Sign/Verify Message dialog and switch to sign message tab */
8495
void gotoSignMessageTab(QString addr = "");

0 commit comments

Comments
 (0)