Bitcoin Core 28.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
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
25ReceiveCoinsDialog::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 {
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.
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
202void 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
256void 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
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:103
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:58
QString formatBitcoinURI(const SendCoinsRecipient &info)
Definition: guiutil.cpp:211
constexpr auto dialog_flags
Definition: guiutil.h:60
void setClipboard(const QString &str)
Definition: guiutil.cpp:668
const std::string & FormatOutputType(OutputType type)
Definition: outputtype.cpp:38
OutputType
Definition: outputtype.h:17
assert(!tx.IsCoinBase())