Bitcoin Core  27.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 
29 WalletFrame::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 
58 WalletFrame::~WalletFrame() = default;
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);
76  walletView->showOutOfSyncWarning(bOutOfSync);
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 
193 void 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:54
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
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
WalletModel * getWalletModel() const noexcept
Definition: walletview.h:46
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:102
void ShowModalDialogAsynchronously(QDialog *dialog)
Shows a QDialog instance asynchronously, and deletes it on close.
Definition: guiutil.cpp:1005
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:356
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:66
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:277
A version of CTransaction with the PSBT format.
Definition: psbt.h:947
std::optional< std::vector< unsigned char > > DecodeBase64(std::string_view str)
assert(!tx.IsCoinBase())