Bitcoin Core  27.99.0
P2P Digital Currency
receivecoinsdialog.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 <wallet/wallet.h>
6 
8 #include <qt/forms/ui_receivecoinsdialog.h>
9 
10 #include <qt/addresstablemodel.h>
11 #include <qt/guiutil.h>
12 #include <qt/optionsmodel.h>
13 #include <qt/platformstyle.h>
16 #include <qt/walletmodel.h>
17 
18 #include <QAction>
19 #include <QCursor>
20 #include <QMessageBox>
21 #include <QScrollBar>
22 #include <QSettings>
23 #include <QTextDocument>
24 
25 ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
26  QDialog(parent, GUIUtil::dialog_flags),
27  ui(new Ui::ReceiveCoinsDialog),
28  platformStyle(_platformStyle)
29 {
30  ui->setupUi(this);
31 
32  if (!_platformStyle->getImagesOnButtons()) {
33  ui->clearButton->setIcon(QIcon());
34  ui->receiveButton->setIcon(QIcon());
35  ui->showRequestButton->setIcon(QIcon());
36  ui->removeRequestButton->setIcon(QIcon());
37  } else {
38  ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
39  ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
40  ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/eye"));
41  ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
42  }
43 
44  // context menu
45  contextMenu = new QMenu(this);
46  contextMenu->addAction(tr("Copy &URI"), this, &ReceiveCoinsDialog::copyURI);
47  contextMenu->addAction(tr("&Copy address"), this, &ReceiveCoinsDialog::copyAddress);
48  copyLabelAction = contextMenu->addAction(tr("Copy &label"), this, &ReceiveCoinsDialog::copyLabel);
49  copyMessageAction = contextMenu->addAction(tr("Copy &message"), this, &ReceiveCoinsDialog::copyMessage);
50  copyAmountAction = contextMenu->addAction(tr("Copy &amount"), this, &ReceiveCoinsDialog::copyAmount);
51  connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu);
52 
53  connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear);
54 
55  QTableView* tableView = ui->recentRequestsView;
56  tableView->verticalHeader()->hide();
57  tableView->setAlternatingRowColors(true);
58  tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
59  tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
60 
61  QSettings settings;
62  if (!tableView->horizontalHeader()->restoreState(settings.value("RecentRequestsViewHeaderState").toByteArray())) {
63  tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
64  tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
66  tableView->horizontalHeader()->setMinimumSectionSize(MINIMUM_COLUMN_WIDTH);
67  tableView->horizontalHeader()->setStretchLastSection(true);
68  }
69 }
70 
72 {
73  this->model = _model;
74 
75  if(_model && _model->getOptionsModel())
76  {
77  _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
80 
81  QTableView* tableView = ui->recentRequestsView;
82  tableView->setModel(_model->getRecentRequestsTableModel());
83  tableView->sortByColumn(RecentRequestsTableModel::Date, Qt::DescendingOrder);
84 
85  connect(tableView->selectionModel(),
86  &QItemSelectionModel::selectionChanged, this,
88 
89  // Populate address type dropdown and select default
90  auto add_address_type = [&](OutputType type, const QString& text, const QString& tooltip) {
91  const auto index = ui->addressType->count();
92  ui->addressType->addItem(text, (int) type);
93  ui->addressType->setItemData(index, tooltip, Qt::ToolTipRole);
94  if (model->wallet().getDefaultAddressType() == type) ui->addressType->setCurrentIndex(index);
95  };
96  add_address_type(OutputType::LEGACY, tr("Base58 (Legacy)"), tr("Not recommended due to higher fees and less protection against typos."));
97  add_address_type(OutputType::P2SH_SEGWIT, tr("Base58 (P2SH-SegWit)"), tr("Generates an address compatible with older wallets."));
98  add_address_type(OutputType::BECH32, tr("Bech32 (SegWit)"), tr("Generates a native segwit address (BIP-173). Some old wallets don't support it."));
99  if (model->wallet().taprootEnabled()) {
100  add_address_type(OutputType::BECH32M, tr("Bech32m (Taproot)"), tr("Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited."));
101  }
102 
103  // Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
104  ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
105 
106  // Enable/disable the receive button if the wallet is now able/unable to give out new addresses.
107  connect(model, &WalletModel::canGetAddressesChanged, [this] {
108  ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
109  });
110  }
111 }
112 
114 {
115  QSettings settings;
116  settings.setValue("RecentRequestsViewHeaderState", ui->recentRequestsView->horizontalHeader()->saveState());
117  delete ui;
118 }
119 
121 {
122  ui->reqAmount->clear();
123  ui->reqLabel->setText("");
124  ui->reqMessage->setText("");
126 }
127 
129 {
130  clear();
131 }
132 
134 {
135  clear();
136 }
137 
139 {
140  if(model && model->getOptionsModel())
141  {
142  ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
143  }
144 }
145 
147 {
149  return;
150 
151  QString address;
152  QString label = ui->reqLabel->text();
153  /* Generate new receiving address */
154  const OutputType address_type = (OutputType)ui->addressType->currentData().toInt();
155  address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
156 
158  {
159  case AddressTableModel::EditStatus::OK: {
160  // Success
161  SendCoinsRecipient info(address, label,
162  ui->reqAmount->value(), ui->reqMessage->text());
163  ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
164  dialog->setAttribute(Qt::WA_DeleteOnClose);
165  dialog->setModel(model);
166  dialog->setInfo(info);
167  dialog->show();
168 
169  /* Store request for later reference */
171  break;
172  }
173  case AddressTableModel::EditStatus::WALLET_UNLOCK_FAILURE:
174  QMessageBox::critical(this, windowTitle(),
175  tr("Could not unlock wallet."),
176  QMessageBox::Ok, QMessageBox::Ok);
177  break;
178  case AddressTableModel::EditStatus::KEY_GENERATION_FAILURE:
179  QMessageBox::critical(this, windowTitle(),
180  tr("Could not generate new %1 address").arg(QString::fromStdString(FormatOutputType(address_type))),
181  QMessageBox::Ok, QMessageBox::Ok);
182  break;
183  // These aren't valid return values for our action
184  case AddressTableModel::EditStatus::INVALID_ADDRESS:
185  case AddressTableModel::EditStatus::DUPLICATE_ADDRESS:
186  case AddressTableModel::EditStatus::NO_CHANGES:
187  assert(false);
188  }
189  clear();
190 }
191 
193 {
195  ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
196  dialog->setModel(model);
197  dialog->setInfo(submodel->entry(index.row()).recipient);
198  dialog->setAttribute(Qt::WA_DeleteOnClose);
199  dialog->show();
200 }
201 
202 void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
203 {
204  // Enable Show/Remove buttons only if anything is selected.
205  bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
206  ui->showRequestButton->setEnabled(enable);
207  ui->removeRequestButton->setEnabled(enable);
208 }
209 
211 {
212  if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
213  return;
214  QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
215 
216  for (const QModelIndex& index : selection) {
218  }
219 }
220 
222 {
223  if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
224  return;
225  QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
226  if(selection.empty())
227  return;
228  // correct for selection mode ContiguousSelection
229  QModelIndex firstIndex = selection.at(0);
230  model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
231 }
232 
234 {
235  if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
236  return QModelIndex();
237  QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
238  if(selection.empty())
239  return QModelIndex();
240  // correct for selection mode ContiguousSelection
241  QModelIndex firstIndex = selection.at(0);
242  return firstIndex;
243 }
244 
245 // copy column of selected row to clipboard
247 {
248  QModelIndex firstIndex = selectedRow();
249  if (!firstIndex.isValid()) {
250  return;
251  }
252  GUIUtil::setClipboard(model->getRecentRequestsTableModel()->index(firstIndex.row(), column).data(Qt::EditRole).toString());
253 }
254 
255 // context menu
256 void ReceiveCoinsDialog::showMenu(const QPoint &point)
257 {
258  const QModelIndex sel = selectedRow();
259  if (!sel.isValid()) {
260  return;
261  }
262 
263  // disable context menu actions when appropriate
265  const RecentRequestEntry& req = submodel->entry(sel.row());
266  copyLabelAction->setDisabled(req.recipient.label.isEmpty());
267  copyMessageAction->setDisabled(req.recipient.message.isEmpty());
268  copyAmountAction->setDisabled(req.recipient.amount == 0);
269 
270  contextMenu->exec(QCursor::pos());
271 }
272 
273 // context menu action: copy URI
275 {
276  QModelIndex sel = selectedRow();
277  if (!sel.isValid()) {
278  return;
279  }
280 
281  const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
282  const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
284 }
285 
286 // context menu action: copy address
288 {
289  const QModelIndex sel = selectedRow();
290  if (!sel.isValid()) {
291  return;
292  }
293 
295  const QString address = submodel->entry(sel.row()).recipient.address;
296  GUIUtil::setClipboard(address);
297 }
298 
299 // context menu action: copy label
301 {
303 }
304 
305 // context menu action: copy message
307 {
309 }
310 
311 // context menu action: copy amount
313 {
315 }
EditStatus getEditStatus() const
QString addRow(const QString &type, const QString &label, const QString &address, const OutputType address_type)
static const QString Receive
Specifies receive address.
void displayUnitChanged(BitcoinUnit unit)
BitcoinUnit getDisplayUnit() const
Definition: optionsmodel.h:104
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
bool getImagesOnButtons() const
Definition: platformstyle.h:21
Dialog for requesting payment of bitcoins.
Ui::ReceiveCoinsDialog * ui
void on_recentRequestsView_doubleClicked(const QModelIndex &index)
void recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
void setModel(WalletModel *model)
void showMenu(const QPoint &point)
ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent=nullptr)
void copyColumnToClipboard(int column)
void setModel(WalletModel *model)
void setInfo(const SendCoinsRecipient &info)
SendCoinsRecipient recipient
Model for list of recently generated payment requests / bitcoin: URIs.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
const RecentRequestEntry & entry(int row) const
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
void addNewRequest(const SendCoinsRecipient &recipient)
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:48
RecentRequestsTableModel * getRecentRequestsTableModel() const
AddressTableModel * getAddressTableModel() const
interfaces::Wallet & wallet() const
Definition: walletmodel.h:138
OptionsModel * getOptionsModel() const
void canGetAddressesChanged()
virtual OutputType getDefaultAddressType()=0
virtual bool taprootEnabled()=0
virtual bool canGetAddresses()=0
Utility functions used by the Bitcoin Qt UI.
Definition: bitcoingui.h:60
QString formatBitcoinURI(const SendCoinsRecipient &info)
Definition: guiutil.cpp:214
constexpr auto dialog_flags
Definition: guiutil.h:60
void setClipboard(const QString &str)
Definition: guiutil.cpp:664
const std::string & FormatOutputType(OutputType type)
Definition: outputtype.cpp:38
OutputType
Definition: outputtype.h:17
assert(!tx.IsCoinBase())