Bitcoin Core  0.20.99
P2P Digital Currency
receivecoinsdialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2019 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/optionsmodel.h>
12 #include <qt/platformstyle.h>
15 #include <qt/walletmodel.h>
16 
17 #include <QAction>
18 #include <QCursor>
19 #include <QMessageBox>
20 #include <QScrollBar>
21 #include <QTextDocument>
22 
23 ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
24  QDialog(parent),
25  ui(new Ui::ReceiveCoinsDialog),
26  columnResizingFixer(nullptr),
27  model(nullptr),
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/edit"));
41  ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
42  }
43 
44  // context menu actions
45  QAction *copyURIAction = new QAction(tr("Copy URI"), this);
46  QAction *copyLabelAction = new QAction(tr("Copy label"), this);
47  QAction *copyMessageAction = new QAction(tr("Copy message"), this);
48  QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
49 
50  // context menu
51  contextMenu = new QMenu(this);
52  contextMenu->addAction(copyURIAction);
53  contextMenu->addAction(copyLabelAction);
54  contextMenu->addAction(copyMessageAction);
55  contextMenu->addAction(copyAmountAction);
56 
57  // context menu signals
58  connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu);
59  connect(copyURIAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyURI);
60  connect(copyLabelAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyLabel);
61  connect(copyMessageAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyMessage);
62  connect(copyAmountAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAmount);
63 
64  connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear);
65 }
66 
68 {
69  this->model = _model;
70 
71  if(_model && _model->getOptionsModel())
72  {
73  _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
76 
77  QTableView* tableView = ui->recentRequestsView;
78 
79  tableView->verticalHeader()->hide();
80  tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
81  tableView->setModel(_model->getRecentRequestsTableModel());
82  tableView->setAlternatingRowColors(true);
83  tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
84  tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
85  tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
86  tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
88 
89  connect(tableView->selectionModel(),
90  &QItemSelectionModel::selectionChanged, this,
92  // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready.
94 
96  ui->useBech32->setCheckState(Qt::Checked);
97  } else {
98  ui->useBech32->setCheckState(Qt::Unchecked);
99  }
100 
101  // Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
102  ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
103 
104  // Enable/disable the receive button if the wallet is now able/unable to give out new addresses.
105  connect(model, &WalletModel::canGetAddressesChanged, [this] {
106  ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
107  });
108  }
109 }
110 
112 {
113  delete ui;
114 }
115 
117 {
118  ui->reqAmount->clear();
119  ui->reqLabel->setText("");
120  ui->reqMessage->setText("");
122 }
123 
125 {
126  clear();
127 }
128 
130 {
131  clear();
132 }
133 
135 {
136  if(model && model->getOptionsModel())
137  {
138  ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
139  }
140 }
141 
143 {
145  return;
146 
147  QString address;
148  QString label = ui->reqLabel->text();
149  /* Generate new receiving address */
150  OutputType address_type;
151  if (ui->useBech32->isChecked()) {
152  address_type = OutputType::BECH32;
153  } else {
154  address_type = model->wallet().getDefaultAddressType();
155  if (address_type == OutputType::BECH32) {
156  address_type = OutputType::P2SH_SEGWIT;
157  }
158  }
159  address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
160 
162  {
163  case AddressTableModel::EditStatus::OK: {
164  // Success
165  SendCoinsRecipient info(address, label,
166  ui->reqAmount->value(), ui->reqMessage->text());
167  ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
168  dialog->setAttribute(Qt::WA_DeleteOnClose);
169  dialog->setModel(model);
170  dialog->setInfo(info);
171  dialog->show();
172 
173  /* Store request for later reference */
175  break;
176  }
177  case AddressTableModel::EditStatus::WALLET_UNLOCK_FAILURE:
178  QMessageBox::critical(this, windowTitle(),
179  tr("Could not unlock wallet."),
180  QMessageBox::Ok, QMessageBox::Ok);
181  break;
182  case AddressTableModel::EditStatus::KEY_GENERATION_FAILURE:
183  QMessageBox::critical(this, windowTitle(),
184  tr("Could not generate new %1 address").arg(QString::fromStdString(FormatOutputType(address_type))),
185  QMessageBox::Ok, QMessageBox::Ok);
186  break;
187  // These aren't valid return values for our action
188  case AddressTableModel::EditStatus::INVALID_ADDRESS:
189  case AddressTableModel::EditStatus::DUPLICATE_ADDRESS:
190  case AddressTableModel::EditStatus::NO_CHANGES:
191  assert(false);
192  }
193  clear();
194 }
195 
197 {
199  ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
200  dialog->setModel(model);
201  dialog->setInfo(submodel->entry(index.row()).recipient);
202  dialog->setAttribute(Qt::WA_DeleteOnClose);
203  dialog->show();
204 }
205 
206 void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
207 {
208  // Enable Show/Remove buttons only if anything is selected.
209  bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
210  ui->showRequestButton->setEnabled(enable);
211  ui->removeRequestButton->setEnabled(enable);
212 }
213 
215 {
216  if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
217  return;
218  QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
219 
220  for (const QModelIndex& index : selection) {
222  }
223 }
224 
226 {
227  if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
228  return;
229  QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
230  if(selection.empty())
231  return;
232  // correct for selection mode ContiguousSelection
233  QModelIndex firstIndex = selection.at(0);
234  model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
235 }
236 
237 // We override the virtual resizeEvent of the QWidget to adjust tables column
238 // sizes as the tables width is proportional to the dialogs width.
239 void ReceiveCoinsDialog::resizeEvent(QResizeEvent *event)
240 {
241  QWidget::resizeEvent(event);
243 }
244 
245 void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
246 {
247  if (event->key() == Qt::Key_Return)
248  {
249  // press return -> submit form
250  if (ui->reqLabel->hasFocus() || ui->reqAmount->hasFocus() || ui->reqMessage->hasFocus())
251  {
252  event->ignore();
254  return;
255  }
256  }
257 
258  this->QDialog::keyPressEvent(event);
259 }
260 
262 {
263  if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
264  return QModelIndex();
265  QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
266  if(selection.empty())
267  return QModelIndex();
268  // correct for selection mode ContiguousSelection
269  QModelIndex firstIndex = selection.at(0);
270  return firstIndex;
271 }
272 
273 // copy column of selected row to clipboard
275 {
276  QModelIndex firstIndex = selectedRow();
277  if (!firstIndex.isValid()) {
278  return;
279  }
280  GUIUtil::setClipboard(model->getRecentRequestsTableModel()->index(firstIndex.row(), column).data(Qt::EditRole).toString());
281 }
282 
283 // context menu
284 void ReceiveCoinsDialog::showMenu(const QPoint &point)
285 {
286  if (!selectedRow().isValid()) {
287  return;
288  }
289  contextMenu->exec(QCursor::pos());
290 }
291 
292 // context menu action: copy URI
294 {
295  QModelIndex sel = selectedRow();
296  if (!sel.isValid()) {
297  return;
298  }
299 
300  const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
301  const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
303 }
304 
305 // context menu action: copy label
307 {
309 }
310 
311 // context menu action: copy message
313 {
315 }
316 
317 // context menu action: copy amount
319 {
321 }
Model for list of recently generated payment requests / bitcoin: URIs.
void addNewRequest(const SendCoinsRecipient &recipient)
Dialog for requesting payment of bitcoins.
virtual bool canGetAddresses()=0
interfaces::Wallet & wallet() const
Definition: walletmodel.h:146
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void canGetAddressesChanged()
virtual OutputType getDefaultAddressType()=0
void recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
GUIUtil::TableViewLastColumnResizingFixer * columnResizingFixer
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
AddressTableModel * getAddressTableModel()
Ui::ReceiveCoinsDialog * ui
QString formatBitcoinURI(const SendCoinsRecipient &info)
Definition: guiutil.cpp:182
OutputType
Definition: outputtype.h:17
QString addRow(const QString &type, const QString &label, const QString &address, const OutputType address_type)
int getDisplayUnit() const
Definition: optionsmodel.h:81
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
void setModel(WalletModel *model)
void copyColumnToClipboard(int column)
virtual void keyPressEvent(QKeyEvent *event) override
void setClipboard(const QString &str)
Definition: guiutil.cpp:718
void on_recentRequestsView_doubleClicked(const QModelIndex &index)
void setInfo(const SendCoinsRecipient &info)
Makes a QTableView last column feel as if it was being resized from its left border.
Definition: guiutil.h:174
virtual void resizeEvent(QResizeEvent *event) override
const RecentRequestEntry & entry(int row) const
void displayUnitChanged(int unit)
ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent=nullptr)
const std::string & FormatOutputType(OutputType type)
Definition: outputtype.cpp:39
RecentRequestsTableModel * getRecentRequestsTableModel()
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:51
static const QString Receive
Specifies receive address.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
void showMenu(const QPoint &point)
EditStatus getEditStatus() const
bool getImagesOnButtons() const
Definition: platformstyle.h:21
OptionsModel * getOptionsModel()
void setModel(WalletModel *model)