Bitcoin ABC  0.22.12
P2P Digital Currency
walletview.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 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/walletview.h>
6 
7 #include <config.h> // For GetConfig
8 #include <interfaces/node.h>
9 #include <node/psbt.h>
10 #include <node/transaction.h>
11 #include <node/ui_interface.h>
12 #include <policy/policy.h>
13 #include <qt/addressbookpage.h>
14 #include <qt/askpassphrasedialog.h>
15 #include <qt/clientmodel.h>
16 #include <qt/guiutil.h>
17 #include <qt/optionsmodel.h>
18 #include <qt/overviewpage.h>
19 #include <qt/platformstyle.h>
20 #include <qt/receivecoinsdialog.h>
21 #include <qt/sendcoinsdialog.h>
24 #include <qt/transactionview.h>
25 #include <qt/walletmodel.h>
26 #include <util/strencodings.h>
27 
28 #include <QAction>
29 #include <QActionGroup>
30 #include <QFileDialog>
31 #include <QHBoxLayout>
32 #include <QProgressDialog>
33 #include <QPushButton>
34 #include <QVBoxLayout>
35 
36 WalletView::WalletView(const PlatformStyle *_platformStyle,
37  WalletModel *_walletModel, QWidget *parent)
38  : QStackedWidget(parent), clientModel(nullptr), walletModel(_walletModel),
39  platformStyle(_platformStyle) {
40  // Create tabs
42 
43  transactionsPage = new QWidget(this);
44  QVBoxLayout *vbox = new QVBoxLayout();
45  QHBoxLayout *hbox_buttons = new QHBoxLayout();
47  vbox->addWidget(transactionView);
48  QPushButton *exportButton = new QPushButton(tr("&Export"), this);
49  exportButton->setToolTip(
50  tr("Export the data in the current tab to a file"));
52  exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
53  }
54  hbox_buttons->addStretch();
55  hbox_buttons->addWidget(exportButton);
56  vbox->addLayout(hbox_buttons);
57  transactionsPage->setLayout(vbox);
58 
61 
68 
69  addWidget(overviewPage);
70  addWidget(transactionsPage);
71  addWidget(receiveCoinsPage);
72  addWidget(sendCoinsPage);
73 
76  // Clicking on a transaction on the overview pre-selects the transaction on
77  // the transaction history page
79  static_cast<void (TransactionView::*)(const QModelIndex &)>(
81 
84 
87  // Highlight transaction after send
89  static_cast<void (TransactionView::*)(const uint256 &)>(
91 
92  // Clicking on "Export" allows to export the transaction list
93  connect(exportButton, &QPushButton::clicked, transactionView,
95 
96  // Pass through messages from sendCoinsPage
99  // Pass through messages from transactionView
102 
103  // Set the model properly.
105 }
106 
108 
110  this->clientModel = _clientModel;
111 
112  overviewPage->setClientModel(_clientModel);
113  sendCoinsPage->setClientModel(_clientModel);
114 }
115 
117  this->walletModel = _walletModel;
118 
119  // Put transaction list in tabs
120  transactionView->setModel(_walletModel);
121  overviewPage->setWalletModel(_walletModel);
122  receiveCoinsPage->setModel(_walletModel);
123  sendCoinsPage->setModel(_walletModel);
125  _walletModel ? _walletModel->getAddressTableModel() : nullptr);
127  _walletModel ? _walletModel->getAddressTableModel() : nullptr);
128 
129  if (_walletModel) {
130  // Receive and pass through messages from wallet model
131  connect(_walletModel, &WalletModel::message, this,
133 
134  // Handle changes in encryption status
135  connect(_walletModel, &WalletModel::encryptionStatusChanged, this,
138 
139  // update HD status
140  Q_EMIT hdEnabledStatusChanged();
141 
142  // Balloon pop-up for new transaction
143  connect(_walletModel->getTransactionTableModel(),
144  &TransactionTableModel::rowsInserted, this,
146 
147  // Ask for passphrase if needed
148  connect(_walletModel, &WalletModel::requireUnlock, this,
150 
151  // Show progress dialog
152  connect(_walletModel, &WalletModel::showProgress, this,
154  }
155 }
156 
157 void WalletView::processNewTransaction(const QModelIndex &parent, int start,
158  int end) {
159  // Prevent balloon-spam when initial block download is in progress
160  if (!walletModel || !clientModel ||
162  return;
163  }
164 
166  if (!ttm || ttm->processingQueuedTransactions()) {
167  return;
168  }
169 
170  QString date = ttm->index(start, TransactionTableModel::Date, parent)
171  .data()
172  .toString();
173  qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
174  .data(Qt::EditRole)
175  .toULongLong();
176  QString type = ttm->index(start, TransactionTableModel::Type, parent)
177  .data()
178  .toString();
179  QModelIndex index = ttm->index(start, 0, parent);
180  QString address =
181  ttm->data(index, TransactionTableModel::AddressRole).toString();
182  QString label = GUIUtil::HtmlEscape(
183  ttm->data(index, TransactionTableModel::LabelRole).toString());
184 
185  Q_EMIT incomingTransaction(
187  int64_t(amount) * SATOSHI, type, address, label,
189 }
190 
192  setCurrentWidget(overviewPage);
193 }
194 
196  setCurrentWidget(transactionsPage);
197 }
198 
200  setCurrentWidget(receiveCoinsPage);
201 }
202 
203 void WalletView::gotoSendCoinsPage(QString addr) {
204  setCurrentWidget(sendCoinsPage);
205 
206  if (!addr.isEmpty()) {
207  sendCoinsPage->setAddress(addr);
208  }
209 }
210 
211 void WalletView::gotoSignMessageTab(QString addr) {
212  // calls show() in showTab_SM()
213  SignVerifyMessageDialog *signVerifyMessageDialog =
215  signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
216  signVerifyMessageDialog->setModel(walletModel);
217  signVerifyMessageDialog->showTab_SM(true);
218 
219  if (!addr.isEmpty()) {
220  signVerifyMessageDialog->setAddress_SM(addr);
221  }
222 }
223 
225  // calls show() in showTab_VM()
226  SignVerifyMessageDialog *signVerifyMessageDialog =
228  signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
229  signVerifyMessageDialog->setModel(walletModel);
230  signVerifyMessageDialog->showTab_VM(true);
231 
232  if (!addr.isEmpty()) {
233  signVerifyMessageDialog->setAddress_VM(addr);
234  }
235 }
236 
238  QString filename = GUIUtil::getOpenFileName(
239  this, tr("Load Transaction Data"), QString(),
240  tr("Partially Signed Transaction (*.psbt)"), nullptr);
241  if (filename.isEmpty()) {
242  return;
243  }
244  if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) ==
246  Q_EMIT message(tr("Error"),
247  tr("PSBT file must be smaller than 100 MiB"),
249  return;
250  }
251  std::ifstream in(filename.toLocal8Bit().data(), std::ios::binary);
252  std::string dataStr(std::istreambuf_iterator<char>{in}, {});
253 
254  std::string error;
256  if (!DecodeRawPSBT(psbtx, dataStr, error)) {
257  Q_EMIT message(tr("Error"),
258  tr("Unable to decode PSBT file") + "\n" +
259  QString::fromStdString(error),
261  return;
262  }
263 
265  bool complete = false;
266  PSBTAnalysis analysis = AnalyzePSBT(psbtx);
267  QMessageBox msgBox;
268  msgBox.setText("PSBT");
269  switch (analysis.next) {
270  case PSBTRole::CREATOR:
271  case PSBTRole::UPDATER:
272  msgBox.setInformativeText(
273  "PSBT is incomplete. Copy to clipboard for manual inspection?");
274  break;
275  case PSBTRole::SIGNER:
276  msgBox.setInformativeText(
277  "Transaction needs more signatures. Copy to clipboard?");
278  break;
279  case PSBTRole::FINALIZER:
280  case PSBTRole::EXTRACTOR:
281  complete = FinalizeAndExtractPSBT(psbtx, mtx);
282  if (complete) {
283  msgBox.setInformativeText(
284  tr("Would you like to send this transaction?"));
285  } else {
286  // The analyzer missed something, e.g. if there are
287  // final_scriptSig but with invalid signatures.
288  msgBox.setInformativeText(
289  tr("There was an unexpected problem processing the PSBT. "
290  "Copy to clipboard for manual inspection?"));
291  }
292  }
293 
294  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
295  switch (msgBox.exec()) {
296  case QMessageBox::Yes: {
297  if (complete) {
298  std::string err_string;
300 
302  *clientModel->node().context(), GetConfig(), tx, err_string,
303  DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true,
304  /* wait_callback */ false);
305  if (result == TransactionError::OK) {
306  Q_EMIT message(tr("Success"),
307  tr("Broadcasted transaction successfully."),
310  } else {
311  Q_EMIT message(tr("Error"),
312  QString::fromStdString(err_string),
314  }
315  } else {
316  // Serialize the PSBT
318  ssTx << psbtx;
319  GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
320  Q_EMIT message(tr("PSBT copied"), "Copied to clipboard",
322  return;
323  }
324  }
325  case QMessageBox::Cancel:
326  break;
327  default:
328  assert(false);
329  }
330 }
331 
333  return sendCoinsPage->handlePaymentRequest(recipient);
334 }
335 
338 }
339 
341  Q_EMIT encryptionStatusChanged();
342 }
343 
344 void WalletView::encryptWallet(bool status) {
345  if (!walletModel) {
346  return;
347  }
348 
351  this);
352  dlg.setModel(walletModel);
353  dlg.exec();
354 
356 }
357 
359  QString filename =
360  GUIUtil::getSaveFileName(this, tr("Backup Wallet"), QString(),
361  tr("Wallet Data (*.dat)"), nullptr);
362 
363  if (filename.isEmpty()) {
364  return;
365  }
366 
367  if (!walletModel->wallet().backupWallet(filename.toLocal8Bit().data())) {
368  Q_EMIT message(
369  tr("Backup Failed"),
370  tr("There was an error trying to save the wallet data to %1.")
371  .arg(filename),
373  } else {
374  Q_EMIT message(
375  tr("Backup Successful"),
376  tr("The wallet data was successfully saved to %1.").arg(filename),
378  }
379 }
380 
383  dlg.setModel(walletModel);
384  dlg.exec();
385 }
386 
388  if (!walletModel) {
389  return;
390  }
391 
392  // Unlock wallet when requested by wallet model
395  dlg.setModel(walletModel);
396  dlg.exec();
397  }
398 }
399 
401  if (!walletModel) {
402  return;
403  }
404 
406 }
407 
409  if (!walletModel) {
410  return;
411  }
412 
414 }
415 
416 void WalletView::showProgress(const QString &title, int nProgress) {
417  if (nProgress == 0) {
418  progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100);
420  progressDialog->setWindowModality(Qt::ApplicationModal);
421  progressDialog->setMinimumDuration(0);
422  progressDialog->setAutoClose(false);
423  progressDialog->setValue(0);
424  } else if (nProgress == 100) {
425  if (progressDialog) {
426  progressDialog->close();
427  progressDialog->deleteLater();
428  progressDialog = nullptr;
429  }
430  } else if (progressDialog) {
431  if (progressDialog->wasCanceled()) {
433  } else {
434  progressDialog->setValue(nProgress);
435  }
436  }
437 }
438 
440  Q_EMIT outOfSyncWarningClicked();
441 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:338
QWidget * transactionsPage
Definition: walletview.h:65
Dialog for requesting payment of bitcoins.
void processNewTransaction(const QModelIndex &parent, int start, int end)
Show incoming transaction notification for new transactions.
Definition: walletview.cpp:157
void setWalletModel(WalletModel *walletModel)
interfaces::Wallet & wallet() const
Definition: walletmodel.h:150
virtual bool isInitialBlockDownload()=0
Is initial block download.
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:316
void gotoVerifyMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to verify message tab.
Definition: walletview.cpp:224
OverviewPage * overviewPage
Definition: walletview.h:64
TransactionView * transactionView
Definition: walletview.h:71
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
Definition: psbt.cpp:15
void usedSendingAddresses()
Show used sending addresses.
Definition: walletview.cpp:400
void setAddress_VM(const QString &address)
void setModel(AddressTableModel *model)
void changePassphrase()
Change encrypted wallet passphrase.
Definition: walletview.cpp:381
ClientModel * clientModel
Definition: walletview.h:61
std::string str() const
Definition: streams.h:270
fs::ifstream ifstream
Definition: fs.h:98
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:339
void focusTransaction(const QModelIndex &)
Ask passphrase twice and encrypt.
PSBTRole next
Which of the BIP 174 roles needs to handle the transaction next.
Definition: psbt.h:42
virtual bool backupWallet(const std::string &filename)=0
Back up wallet.
void requestedSyncWarningInfo()
User has requested more information about the out of sync state.
Definition: walletview.cpp:439
std::string EncodeBase64(const uint8_t *pch, size_t len)
Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
Definition: psbt.h:32
WalletModel * walletModel
Definition: walletview.h:62
static constexpr Amount SATOSHI
Definition: amount.h:151
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
void showProgress(const QString &title, int nProgress)
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:238
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
A version of CTransaction with the PSBT format.
Definition: psbt.h:335
Open address book for editing.
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:196
void outOfSyncWarningClicked()
Notify that the out of sync warning icon has been pressed.
const PlatformStyle * platformStyle
Definition: walletview.h:74
AddressTableModel * getAddressTableModel()
void gotoSendCoinsPage(QString addr="")
Switch to send coins page.
Definition: walletview.cpp:203
bool FinalizeAndExtractPSBT(PartiallySignedTransaction &psbtx, CMutableTransaction &result)
Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized...
Definition: psbt.cpp:264
void updateEncryptionStatus()
Re-emit encryption status signal.
Definition: walletview.cpp:340
void outOfSyncWarningClicked()
void bringToFront(QWidget *w)
Definition: guiutil.cpp:369
void gotoLoadPSBT()
Load Partially Signed Bitcoin Transaction.
Definition: walletview.cpp:237
EncryptionStatus getEncryptionStatus() const
int getDisplayUnit() const
Definition: optionsmodel.h:96
Force blocking, modal message box dialog (not just OS notification)
Definition: ui_interface.h:65
SendCoinsDialog * sendCoinsPage
Definition: walletview.h:67
void setModel(WalletModel *model)
WalletModel * getWalletModel()
Definition: walletview.h:48
bool processingQueuedTransactions() const
void gotoHistoryPage()
Switch to history (transactions) page.
Definition: walletview.cpp:195
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:54
Ask passphrase and unlock.
void usedReceivingAddresses()
Show used receiving addresses.
Definition: walletview.cpp:408
void setWalletModel(WalletModel *walletModel)
Set the wallet model.
Definition: walletview.cpp:116
void setAddress(const QString &address)
void setClientModel(ClientModel *clientModel)
void setClipboard(const QString &str)
Definition: guiutil.cpp:732
static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE
Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls.
Definition: transaction.h:24
void message(const QString &title, const QString &message, unsigned int style)
Fired when a message should be reported to the user.
Widget showing the transaction list for a wallet, including a filter row.
void message(const QString &title, const QString &message, unsigned int style)
Fired when a message should be reported to the user.
interfaces::Node & node() const
Definition: clientmodel.h:49
const std::streamsize MAX_FILE_SIZE_PSBT
Definition: psbt.h:40
void unlockWallet()
Ask for passphrase to unlock wallet temporarily.
Definition: walletview.cpp:387
Dialog for sending bitcoins.
const Config & GetConfig()
Definition: config.cpp:34
void encryptionStatusChanged()
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QString getWalletName() const
TransactionTableModel * getTransactionTableModel()
Widget that shows a list of sending or receiving addresses.
UI model for the transaction table of a wallet.
void PolishProgressDialog(QProgressDialog *dialog)
Definition: guiutil.cpp:885
Model for Bitcoin network client.
Definition: clientmodel.h:34
void setModel(WalletModel *model)
void backupWallet()
Backup the wallet.
Definition: walletview.cpp:358
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
Definition: walletview.cpp:332
void transactionClicked(const QModelIndex &index)
void gotoOverviewPage()
Switch to overview (home) page.
Definition: walletview.cpp:191
void incomingTransaction(const QString &date, int unit, const Amount amount, const QString &type, const QString &address, const QString &label, const QString &walletName)
Notify that a new transaction appeared.
void encryptionStatusChanged()
Encryption status of wallet changed.
void showOutOfSyncWarning(bool fShow)
256-bit opaque blob.
Definition: uint256.h:120
void requireUnlock()
bool DecodeRawPSBT(PartiallySignedTransaction &psbt, const std::string &tx_data, std::string &error)
Decode a raw (binary blob) PSBT into a PartiallySignedTransaction.
Definition: psbt.cpp:327
AddressBookPage * usedSendingAddressesPage
Definition: walletview.h:68
void setModel(WalletModel *model)
void gotoSignMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to sign message tab.
Definition: walletview.cpp:211
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:47
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
void showProgress(const QString &title, int nProgress)
Show progress dialog e.g.
Definition: walletview.cpp:416
Multifunctional dialog to ask for passphrases.
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when ...
Definition: guiutil.cpp:273
A mutable version of CTransaction.
Definition: transaction.h:297
void message(const QString &title, const QString &message, unsigned int style)
virtual NodeContext * context()
Get and set internal node context.
Definition: node.h:254
void setClientModel(ClientModel *clientModel)
Set the client model.
Definition: walletview.cpp:109
TransactionError
Definition: error.h:22
Ask passphrase and decrypt wallet.
void setClientModel(ClientModel *clientModel)
Label of address related to transaction.
std::streampos GetFileSize(const char *path, std::streamsize max)
Get the size of a file by scanning it.
Definition: system.cpp:149
void hdEnabledStatusChanged()
HD-Enabled status of wallet changed (only possible during startup)
virtual void abortRescan()=0
Abort a rescan.
Ask old passphrase + new passphrase twice.
void encryptWallet(bool status)
Encrypt the wallet.
Definition: walletview.cpp:344
QVariant data(const QModelIndex &index, int role) const override
ReceiveCoinsDialog * receiveCoinsPage
Definition: walletview.h:66
void gotoReceiveCoinsPage()
Switch to receive coins page.
Definition: walletview.cpp:199
WalletView(const PlatformStyle *platformStyle, WalletModel *walletModel, QWidget *parent)
Definition: walletview.cpp:36
void message(const QString &title, const QString &message, unsigned int style)
void coinsSent(const uint256 &txid)
TransactionError BroadcastTransaction(NodeContext &node, const Config &config, const CTransactionRef tx, std::string &err_string, const Amount max_tx_fee, bool relay, bool wait_callback)
Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
Definition: transaction.cpp:20
void coinsSent()
void setModel(WalletModel *model)
bool error(const char *fmt, const Args &... args)
Definition: system.h:47
void transactionClicked()
Overview ("home") page widget.
Definition: overviewpage.h:28
void showOutOfSyncWarning(bool fShow)
Definition: walletview.cpp:336
QProgressDialog * progressDialog
Definition: walletview.h:73
bool getImagesOnButtons() const
Definition: platformstyle.h:20
OptionsModel * getOptionsModel()
Predefined combinations for certain default usage cases.
Definition: ui_interface.h:71
void setAddress_SM(const QString &address)
AddressBookPage * usedReceivingAddressesPage
Definition: walletview.h:69
void setModel(WalletModel *model)