Skip to content

Commit f007a77

Browse files
UdjinM6claude
andcommitted
feat(qt): add "(un)lock all" button to Coin Control dialog
Expose CWallet::UnlockAllCoins() and a new CWallet::LockAllCoins() through the interfaces::Wallet layer and add a "(un)lock all" button to the Coin Control dialog toolbar, placed next to "(un)select all". Mirrors the "(un)select all" behavior: if any coins are locked, clicking unlocks all; if none are locked, clicking locks all visible UTXOs. Works in both tree and list modes. Both lock and unlock paths use a single WalletBatch transaction for all outputs, avoiding per-coin DB overhead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent bb5dea2 commit f007a77

File tree

5 files changed

+80
-0
lines changed

5 files changed

+80
-0
lines changed

src/interfaces/wallet.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ class Wallet
172172
//! List locked coins.
173173
virtual std::vector<COutPoint> listLockedCoins() = 0;
174174

175+
//! Lock the provided coins in a single batch.
176+
virtual bool lockCoins(const std::vector<COutPoint>& outputs) = 0;
177+
178+
//! Unlock the provided coins in a single batch.
179+
virtual bool unlockCoins(const std::vector<COutPoint>& outputs) = 0;
180+
175181
//! List protx coins.
176182
virtual std::vector<COutPoint> listProTxCoins() = 0;
177183

src/qt/coincontroldialog.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _m
117117
// Toggle lock state
118118
connect(ui->pushButtonToggleLock, &QPushButton::clicked, this, &CoinControlDialog::buttonToggleLockClicked);
119119

120+
// Unlock all locked coins
121+
connect(ui->pushButtonUnlockAll, &QPushButton::clicked, this, &CoinControlDialog::buttonUnlockAllClicked);
122+
120123
ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 94);
121124
ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
122125
ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
@@ -223,6 +226,42 @@ void CoinControlDialog::buttonToggleLockClicked()
223226
}
224227
}
225228

229+
// (un)lock all
230+
void CoinControlDialog::buttonUnlockAllClicked()
231+
{
232+
// Collect all visible UTXOs and determine target state from their lock status
233+
// (works in both tree and list modes)
234+
std::vector<COutPoint> outputs;
235+
bool fUnlock = false;
236+
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) {
237+
QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i);
238+
if (item->data(COLUMN_ADDRESS, TxHashRole).toString().length() == 64) {
239+
// List mode: top-level item is a UTXO
240+
outputs.emplace_back(uint256S(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()),
241+
item->data(COLUMN_ADDRESS, VOutRole).toUInt());
242+
if (item->isDisabled()) fUnlock = true;
243+
} else {
244+
// Tree mode: top-level item is an address group; collect children
245+
for (int j = 0; j < item->childCount(); j++) {
246+
QTreeWidgetItem* child = item->child(j);
247+
outputs.emplace_back(uint256S(child->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()),
248+
child->data(COLUMN_ADDRESS, VOutRole).toUInt());
249+
if (child->isDisabled()) fUnlock = true;
250+
}
251+
}
252+
}
253+
bool success = fUnlock ? model->wallet().unlockCoins(outputs)
254+
: model->wallet().lockCoins(outputs);
255+
if (!success) {
256+
QMessageBox::warning(this, tr("Wallet error"),
257+
fUnlock ? tr("Failed to unlock some coins.")
258+
: tr("Failed to lock some coins."));
259+
}
260+
updateView();
261+
updateLabelLocked();
262+
CoinControlDialog::updateLabels(m_coin_control, model, this);
263+
}
264+
226265
// context menu
227266
void CoinControlDialog::showMenu(const QPoint &point)
228267
{

src/qt/coincontroldialog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ private Q_SLOTS:
109109
void buttonBoxClicked(QAbstractButton*);
110110
void buttonSelectAllClicked();
111111
void buttonToggleLockClicked();
112+
void buttonUnlockAllClicked();
112113
void updateLabelLocked();
113114
void on_hideButton_clicked();
114115
};

src/qt/forms/coincontroldialog.ui

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,22 @@
274274
</property>
275275
</widget>
276276
</item>
277+
<item>
278+
<widget class="QPushButton" name="pushButtonUnlockAll">
279+
<property name="sizePolicy">
280+
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
281+
<horstretch>0</horstretch>
282+
<verstretch>0</verstretch>
283+
</sizepolicy>
284+
</property>
285+
<property name="text">
286+
<string>(un)lock all</string>
287+
</property>
288+
<property name="autoDefault">
289+
<bool>false</bool>
290+
</property>
291+
</widget>
292+
</item>
277293
<item>
278294
<widget class="QPushButton" name="pushButtonToggleLock">
279295
<property name="sizePolicy">

src/wallet/interfaces.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,24 @@ class WalletImpl : public Wallet
326326
LOCK(m_wallet->cs_wallet);
327327
return m_wallet->ListLockedCoins();
328328
}
329+
bool lockCoins(const std::vector<COutPoint>& outputs) override
330+
{
331+
LOCK(m_wallet->cs_wallet);
332+
WalletBatch batch(m_wallet->GetDatabase());
333+
for (const auto& output : outputs) {
334+
if (!m_wallet->LockCoin(output, &batch)) return false;
335+
}
336+
return true;
337+
}
338+
bool unlockCoins(const std::vector<COutPoint>& outputs) override
339+
{
340+
LOCK(m_wallet->cs_wallet);
341+
WalletBatch batch(m_wallet->GetDatabase());
342+
for (const auto& output : outputs) {
343+
if (!m_wallet->UnlockCoin(output, &batch)) return false;
344+
}
345+
return true;
346+
}
329347
std::vector<COutPoint> listProTxCoins() override
330348
{
331349
LOCK(m_wallet->cs_wallet);

0 commit comments

Comments
 (0)