Bitcoin Core 28.99.0
P2P Digital Currency
walletframe.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2022 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <qt/walletframe.h>
6
7#include <node/interface_ui.h>
8#include <psbt.h>
9#include <qt/guiutil.h>
10#include <qt/overviewpage.h>
12#include <qt/walletmodel.h>
13#include <qt/walletview.h>
14#include <util/fs.h>
15#include <util/fs_helpers.h>
16
17#include <cassert>
18#include <fstream>
19#include <string>
20
21#include <QApplication>
22#include <QClipboard>
23#include <QGroupBox>
24#include <QHBoxLayout>
25#include <QLabel>
26#include <QPushButton>
27#include <QVBoxLayout>
28
29WalletFrame::WalletFrame(const PlatformStyle* _platformStyle, QWidget* parent)
30 : QFrame(parent),
31 platformStyle(_platformStyle),
32 m_size_hint(OverviewPage{platformStyle, nullptr}.sizeHint())
33{
34 // Leave HBox hook for adding a list view later
35 QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
36 setContentsMargins(0,0,0,0);
37 walletStack = new QStackedWidget(this);
38 walletFrameLayout->setContentsMargins(0,0,0,0);
39 walletFrameLayout->addWidget(walletStack);
40
41 // hbox for no wallet
42 QGroupBox* no_wallet_group = new QGroupBox(walletStack);
43 QVBoxLayout* no_wallet_layout = new QVBoxLayout(no_wallet_group);
44
45 QLabel *noWallet = new QLabel(tr("No wallet has been loaded.\nGo to File > Open Wallet to load a wallet.\n- OR -"));
46 noWallet->setAlignment(Qt::AlignCenter);
47 no_wallet_layout->addWidget(noWallet, 0, Qt::AlignHCenter | Qt::AlignBottom);
48
49 // A button for create wallet dialog
50 QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack);
51 connect(create_wallet_button, &QPushButton::clicked, this, &WalletFrame::createWalletButtonClicked);
52 no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop);
53 no_wallet_group->setLayout(no_wallet_layout);
54
55 walletStack->addWidget(no_wallet_group);
56}
57
59
61{
62 this->clientModel = _clientModel;
63
64 for (auto i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) {
65 i.value()->setClientModel(_clientModel);
66 }
67}
68
70{
71 if (!clientModel) return false;
72
73 if (mapWalletViews.count(walletView->getWalletModel()) > 0) return false;
74
75 walletView->setClientModel(clientModel);
77
78 WalletView* current_wallet_view = currentWalletView();
79 if (current_wallet_view) {
80 walletView->setCurrentIndex(current_wallet_view->currentIndex());
81 } else {
82 walletView->gotoOverviewPage();
83 }
84
85 walletStack->addWidget(walletView);
86 mapWalletViews[walletView->getWalletModel()] = walletView;
87
88 return true;
89}
90
92{
93 if (mapWalletViews.count(wallet_model) == 0) return;
94
95 // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget.
96 WalletView* view_about_to_hide = currentWalletView();
97 if (view_about_to_hide) {
98 QSizePolicy sp = view_about_to_hide->sizePolicy();
99 sp.setHorizontalPolicy(QSizePolicy::Ignored);
100 view_about_to_hide->setSizePolicy(sp);
101 }
102
103 WalletView *walletView = mapWalletViews.value(wallet_model);
104 assert(walletView);
105
106 // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously.
107 QSizePolicy sp = walletView->sizePolicy();
108 sp.setHorizontalPolicy(QSizePolicy::Preferred);
109 walletView->setSizePolicy(sp);
110 walletView->updateGeometry();
111
112 walletStack->setCurrentWidget(walletView);
113
114 Q_EMIT currentWalletSet();
115}
116
118{
119 if (mapWalletViews.count(wallet_model) == 0) return;
120
121 WalletView *walletView = mapWalletViews.take(wallet_model);
122 walletStack->removeWidget(walletView);
123 delete walletView;
124}
125
127{
128 QMap<WalletModel*, WalletView*>::const_iterator i;
129 for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
130 walletStack->removeWidget(i.value());
131 mapWalletViews.clear();
132}
133
135{
136 WalletView *walletView = currentWalletView();
137 if (!walletView)
138 return false;
139
140 return walletView->handlePaymentRequest(recipient);
141}
142
144{
145 bOutOfSync = fShow;
146 QMap<WalletModel*, WalletView*>::const_iterator i;
147 for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
148 i.value()->showOutOfSyncWarning(fShow);
149}
150
152{
153 QMap<WalletModel*, WalletView*>::const_iterator i;
154 for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
155 i.value()->gotoOverviewPage();
156}
157
159{
160 QMap<WalletModel*, WalletView*>::const_iterator i;
161 for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
162 i.value()->gotoHistoryPage();
163}
164
166{
167 QMap<WalletModel*, WalletView*>::const_iterator i;
168 for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
169 i.value()->gotoReceiveCoinsPage();
170}
171
173{
174 QMap<WalletModel*, WalletView*>::const_iterator i;
175 for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
176 i.value()->gotoSendCoinsPage(addr);
177}
178
180{
181 WalletView *walletView = currentWalletView();
182 if (walletView)
183 walletView->gotoSignMessageTab(addr);
184}
185
187{
188 WalletView *walletView = currentWalletView();
189 if (walletView)
190 walletView->gotoVerifyMessageTab(addr);
191}
192
193void WalletFrame::gotoLoadPSBT(bool from_clipboard)
194{
195 std::vector<unsigned char> data;
196
197 if (from_clipboard) {
198 std::string raw = QApplication::clipboard()->text().toStdString();
199 auto result = DecodeBase64(raw);
200 if (!result) {
201 Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
202 return;
203 }
204 data = std::move(*result);
205 } else {
206 QString filename = GUIUtil::getOpenFileName(this,
207 tr("Load Transaction Data"), QString(),
208 tr("Partially Signed Transaction (*.psbt)"), nullptr);
209 if (filename.isEmpty()) return;
210 if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) == MAX_FILE_SIZE_PSBT) {
211 Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR);
212 return;
213 }
214 std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
215 data.assign(std::istreambuf_iterator<char>{in}, {});
216
217 // Some psbt files may be base64 strings in the file rather than binary data
218 std::string b64_str{data.begin(), data.end()};
219 b64_str.erase(b64_str.find_last_not_of(" \t\n\r\f\v") + 1); // Trim trailing whitespace
220 auto b64_dec = DecodeBase64(b64_str);
221 if (b64_dec.has_value()) {
222 data = b64_dec.value();
223 }
224 }
225
226 std::string error;
228 if (!DecodeRawPSBT(psbtx, MakeByteSpan(data), error)) {
229 Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
230 return;
231 }
232
233 auto dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel);
234 dlg->openWithPSBT(psbtx);
236}
237
239{
240 WalletView *walletView = currentWalletView();
241 if (walletView)
242 walletView->encryptWallet();
243}
244
246{
247 WalletView *walletView = currentWalletView();
248 if (walletView)
249 walletView->backupWallet();
250}
251
253{
254 WalletView *walletView = currentWalletView();
255 if (walletView)
256 walletView->changePassphrase();
257}
258
260{
261 WalletView *walletView = currentWalletView();
262 if (walletView)
263 walletView->unlockWallet();
264}
265
267{
268 WalletView *walletView = currentWalletView();
269 if (walletView)
270 walletView->usedSendingAddresses();
271}
272
274{
275 WalletView *walletView = currentWalletView();
276 if (walletView)
277 walletView->usedReceivingAddresses();
278}
279
281{
282 return qobject_cast<WalletView*>(walletStack->currentWidget());
283}
284
286{
287 WalletView* wallet_view = currentWalletView();
288 return wallet_view ? wallet_view->getWalletModel() : nullptr;
289}
Model for Bitcoin network client.
Definition: clientmodel.h:57
Overview ("home") page widget.
Definition: overviewpage.h:29
Dialog showing transaction details.
void removeAllWallets()
void currentWalletSet()
bool addView(WalletView *walletView)
Definition: walletframe.cpp:69
void changePassphrase()
Change encrypted wallet passphrase.
WalletModel * currentWalletModel() const
void gotoHistoryPage()
Switch to history (transactions) page.
void unlockWallet()
Ask for passphrase to unlock wallet temporarily.
void gotoSignMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to sign message tab.
WalletView * currentWalletView() const
void gotoOverviewPage()
Switch to overview (home) page.
ClientModel * clientModel
Definition: walletframe.h:56
void gotoSendCoinsPage(QString addr="")
Switch to send coins page.
void removeWallet(WalletModel *wallet_model)
void setClientModel(ClientModel *clientModel)
Definition: walletframe.cpp:60
bool bOutOfSync
Definition: walletframe.h:59
void backupWallet()
Backup the wallet.
QStackedWidget * walletStack
Definition: walletframe.h:55
void usedSendingAddresses()
Show used sending addresses.
void createWalletButtonClicked()
void encryptWallet()
Encrypt the wallet.
void usedReceivingAddresses()
Show used receiving addresses.
void message(const QString &title, const QString &message, unsigned int style)
void setCurrentWallet(WalletModel *wallet_model)
Definition: walletframe.cpp:91
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
QMap< WalletModel *, WalletView * > mapWalletViews
Definition: walletframe.h:57
void gotoLoadPSBT(bool from_clipboard=false)
Load Partially Signed Bitcoin Transaction.
WalletFrame(const PlatformStyle *platformStyle, QWidget *parent)
Definition: walletframe.cpp:29
void showOutOfSyncWarning(bool fShow)
void gotoReceiveCoinsPage()
Switch to receive coins page.
void gotoVerifyMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to verify message tab.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:48
void gotoVerifyMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to verify message tab.
Definition: walletview.cpp:181
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
Definition: walletview.cpp:193
void changePassphrase()
Change encrypted wallet passphrase.
Definition: walletview.cpp:231
void setClientModel(ClientModel *clientModel)
Set the client model.
Definition: walletview.cpp:116
WalletModel * getWalletModel() const noexcept
Definition: walletview.h:46
void gotoSignMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to sign message tab.
Definition: walletview.cpp:169
void usedSendingAddresses()
Show used sending addresses.
Definition: walletview.cpp:250
void encryptWallet()
Encrypt the wallet.
Definition: walletview.cpp:203
void backupWallet()
Backup the wallet.
Definition: walletview.cpp:211
void unlockWallet()
Ask for passphrase to unlock wallet temporarily.
Definition: walletview.cpp:238
void gotoOverviewPage()
Switch to overview (home) page.
Definition: walletview.cpp:146
void usedReceivingAddresses()
Show used receiving addresses.
Definition: walletview.cpp:255
void showOutOfSyncWarning(bool fShow)
Definition: walletview.cpp:198
std::streampos GetFileSize(const char *path, std::streamsize max)
Get the size of a file by scanning it.
Definition: fs_helpers.cpp:101
void ShowModalDialogAsynchronously(QDialog *dialog)
Shows a QDialog instance asynchronously, and deletes it on close.
Definition: guiutil.cpp:1004
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
Definition: guiutil.cpp:353
bool DecodeRawPSBT(PartiallySignedTransaction &psbt, Span< const std::byte > tx_data, std::string &error)
Decode a raw (binary blob) PSBT into a PartiallySignedTransaction.
Definition: psbt.cpp:546
const std::streamsize MAX_FILE_SIZE_PSBT
Definition: psbt.h:70
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:270
A version of CTransaction with the PSBT format.
Definition: psbt.h:951
std::optional< std::vector< unsigned char > > DecodeBase64(std::string_view str)
assert(!tx.IsCoinBase())