Bitcoin Core  21.99.0
P2P Digital Currency
addressbookpage.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2020 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 #if defined(HAVE_CONFIG_H)
7 #endif
8 
9 #include <qt/addressbookpage.h>
10 #include <qt/forms/ui_addressbookpage.h>
11 
12 #include <qt/addresstablemodel.h>
13 #include <qt/csvmodelwriter.h>
14 #include <qt/editaddressdialog.h>
15 #include <qt/guiutil.h>
16 #include <qt/platformstyle.h>
17 
18 #include <QIcon>
19 #include <QMenu>
20 #include <QMessageBox>
21 #include <QSortFilterProxyModel>
22 
23 class AddressBookSortFilterProxyModel final : public QSortFilterProxyModel
24 {
25  const QString m_type;
26 
27 public:
28  AddressBookSortFilterProxyModel(const QString& type, QObject* parent)
29  : QSortFilterProxyModel(parent)
30  , m_type(type)
31  {
32  setDynamicSortFilter(true);
33  setFilterCaseSensitivity(Qt::CaseInsensitive);
34  setSortCaseSensitivity(Qt::CaseInsensitive);
35  }
36 
37 protected:
38  bool filterAcceptsRow(int row, const QModelIndex& parent) const override
39  {
40  auto model = sourceModel();
41  auto label = model->index(row, AddressTableModel::Label, parent);
42 
43  if (model->data(label, AddressTableModel::TypeRole).toString() != m_type) {
44  return false;
45  }
46 
47  auto address = model->index(row, AddressTableModel::Address, parent);
48 
49  if (filterRegExp().indexIn(model->data(address).toString()) < 0 &&
50  filterRegExp().indexIn(model->data(label).toString()) < 0) {
51  return false;
52  }
53 
54  return true;
55  }
56 };
57 
58 AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
59  QDialog(parent, GUIUtil::dialog_flags),
60  ui(new Ui::AddressBookPage),
61  model(nullptr),
62  mode(_mode),
63  tab(_tab)
64 {
65  ui->setupUi(this);
66 
67  if (!platformStyle->getImagesOnButtons()) {
68  ui->newAddress->setIcon(QIcon());
69  ui->copyAddress->setIcon(QIcon());
70  ui->deleteAddress->setIcon(QIcon());
71  ui->exportButton->setIcon(QIcon());
72  } else {
73  ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
74  ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
75  ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
76  ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
77  }
78 
79  switch(mode)
80  {
81  case ForSelection:
82  switch(tab)
83  {
84  case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
85  case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
86  }
87  connect(ui->tableView, &QTableView::doubleClicked, this, &QDialog::accept);
88  ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
89  ui->tableView->setFocus();
90  ui->closeButton->setText(tr("C&hoose"));
91  ui->exportButton->hide();
92  break;
93  case ForEditing:
94  switch(tab)
95  {
96  case SendingTab: setWindowTitle(tr("Sending addresses")); break;
97  case ReceivingTab: setWindowTitle(tr("Receiving addresses")); break;
98  }
99  break;
100  }
101  switch(tab)
102  {
103  case SendingTab:
104  ui->labelExplanation->setText(tr("These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins."));
105  ui->deleteAddress->setVisible(true);
106  ui->newAddress->setVisible(true);
107  break;
108  case ReceivingTab:
109  ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.\nSigning is only possible with addresses of the type 'legacy'."));
110  ui->deleteAddress->setVisible(false);
111  ui->newAddress->setVisible(false);
112  break;
113  }
114 
115  // Context menu actions
116  QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
117  QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
118  QAction *editAction = new QAction(tr("&Edit"), this);
119  deleteAction = new QAction(ui->deleteAddress->text(), this);
120 
121  // Build context menu
122  contextMenu = new QMenu(this);
123  contextMenu->addAction(copyAddressAction);
124  contextMenu->addAction(copyLabelAction);
125  contextMenu->addAction(editAction);
126  if(tab == SendingTab)
127  contextMenu->addAction(deleteAction);
128  contextMenu->addSeparator();
129 
130  // Connect signals for context menu actions
131  connect(copyAddressAction, &QAction::triggered, this, &AddressBookPage::on_copyAddress_clicked);
132  connect(copyLabelAction, &QAction::triggered, this, &AddressBookPage::onCopyLabelAction);
133  connect(editAction, &QAction::triggered, this, &AddressBookPage::onEditAction);
134  connect(deleteAction, &QAction::triggered, this, &AddressBookPage::on_deleteAddress_clicked);
135 
136  connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu);
137 
138  connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept);
139 
141 }
142 
144 {
145  delete ui;
146 }
147 
149 {
150  this->model = _model;
151  if(!_model)
152  return;
153 
156  proxyModel->setSourceModel(_model);
157 
158  connect(ui->searchLineEdit, &QLineEdit::textChanged, proxyModel, &QSortFilterProxyModel::setFilterWildcard);
159 
160  ui->tableView->setModel(proxyModel);
161  ui->tableView->sortByColumn(0, Qt::AscendingOrder);
162 
163  // Set column widths
164  ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
165  ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
166 
167  connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
169 
170  // Select row for newly created address
171  connect(_model, &AddressTableModel::rowsInserted, this, &AddressBookPage::selectNewAddress);
172 
174 }
175 
177 {
179 }
180 
182 {
184 }
185 
187 {
188  if(!model)
189  return;
190 
191  if(!ui->tableView->selectionModel())
192  return;
193  QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
194  if(indexes.isEmpty())
195  return;
196 
197  EditAddressDialog dlg(
198  tab == SendingTab ?
201  dlg.setModel(model);
202  QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
203  dlg.loadRow(origIndex.row());
204  dlg.exec();
205 }
206 
208 {
209  if(!model)
210  return;
211 
212  if (tab == ReceivingTab) {
213  return;
214  }
215 
217  dlg.setModel(model);
218  if(dlg.exec())
219  {
221  }
222 }
223 
225 {
226  QTableView *table = ui->tableView;
227  if(!table->selectionModel())
228  return;
229 
230  QModelIndexList indexes = table->selectionModel()->selectedRows();
231  if(!indexes.isEmpty())
232  {
233  table->model()->removeRow(indexes.at(0).row());
234  }
235 }
236 
238 {
239  // Set button states based on selected tab and selection
240  QTableView *table = ui->tableView;
241  if(!table->selectionModel())
242  return;
243 
244  if(table->selectionModel()->hasSelection())
245  {
246  switch(tab)
247  {
248  case SendingTab:
249  // In sending tab, allow deletion of selection
250  ui->deleteAddress->setEnabled(true);
251  ui->deleteAddress->setVisible(true);
252  deleteAction->setEnabled(true);
253  break;
254  case ReceivingTab:
255  // Deleting receiving addresses, however, is not allowed
256  ui->deleteAddress->setEnabled(false);
257  ui->deleteAddress->setVisible(false);
258  deleteAction->setEnabled(false);
259  break;
260  }
261  ui->copyAddress->setEnabled(true);
262  }
263  else
264  {
265  ui->deleteAddress->setEnabled(false);
266  ui->copyAddress->setEnabled(false);
267  }
268 }
269 
270 void AddressBookPage::done(int retval)
271 {
272  QTableView *table = ui->tableView;
273  if(!table->selectionModel() || !table->model())
274  return;
275 
276  // Figure out which address was selected, and return it
277  QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
278 
279  for (const QModelIndex& index : indexes) {
280  QVariant address = table->model()->data(index);
281  returnValue = address.toString();
282  }
283 
284  if(returnValue.isEmpty())
285  {
286  // If no address entry selected, return rejected
287  retval = Rejected;
288  }
289 
290  QDialog::done(retval);
291 }
292 
294 {
295  // CSV is currently the only supported format
296  QString filename = GUIUtil::getSaveFileName(this,
297  tr("Export Address List"), QString(),
298  tr("Comma separated file (*.csv)"), nullptr);
299 
300  if (filename.isNull())
301  return;
302 
303  CSVModelWriter writer(filename);
304 
305  // name, column, role
306  writer.setModel(proxyModel);
307  writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
308  writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
309 
310  if(!writer.write()) {
311  QMessageBox::critical(this, tr("Exporting Failed"),
312  tr("There was an error trying to save the address list to %1. Please try again.").arg(filename));
313  }
314 }
315 
316 void AddressBookPage::contextualMenu(const QPoint &point)
317 {
318  QModelIndex index = ui->tableView->indexAt(point);
319  if(index.isValid())
320  {
321  contextMenu->exec(QCursor::pos());
322  }
323 }
324 
325 void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
326 {
327  QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
328  if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
329  {
330  // Select row of newly created address, once
331  ui->tableView->setFocus();
332  ui->tableView->selectRow(idx.row());
333  newAddressToSelect.clear();
334  }
335 }
AddressBookSortFilterProxyModel::AddressBookSortFilterProxyModel
AddressBookSortFilterProxyModel(const QString &type, QObject *parent)
Definition: addressbookpage.cpp:28
AddressBookPage::setModel
void setModel(AddressTableModel *model)
Definition: addressbookpage.cpp:148
AddressBookPage::SendingTab
@ SendingTab
Definition: addressbookpage.h:32
EditAddressDialog::loadRow
void loadRow(int row)
Definition: editaddressdialog.cpp:66
csvmodelwriter.h
AddressBookPage::on_deleteAddress_clicked
void on_deleteAddress_clicked()
Delete currently selected address entry.
Definition: addressbookpage.cpp:224
AddressBookPage::newAddressToSelect
QString newAddressToSelect
Definition: addressbookpage.h:59
AddressBookPage::on_exportButton_clicked
void on_exportButton_clicked()
Export button clicked.
Definition: addressbookpage.cpp:293
AddressBookPage::contextualMenu
void contextualMenu(const QPoint &point)
Spawn contextual menu (right mouse menu) for address book entry.
Definition: addressbookpage.cpp:316
PlatformStyle::SingleColorIcon
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
Definition: platformstyle.cpp:102
addressbookpage.h
CSVModelWriter::write
bool write()
Perform export of the model to CSV.
Definition: csvmodelwriter.cpp:49
EditAddressDialog::EditReceivingAddress
@ EditReceivingAddress
Definition: editaddressdialog.h:29
CSVModelWriter::addColumn
void addColumn(const QString &title, int column, int role=Qt::EditRole)
Definition: csvmodelwriter.cpp:22
AddressTableModel
Qt model of the address book in the core.
Definition: addresstablemodel.h:23
GUIUtil
Utility functions used by the Bitcoin Qt UI.
Definition: bitcoingui.h:58
AddressTableModel::Receive
static const QString Receive
Specifies receive address.
Definition: addresstablemodel.h:51
AddressBookPage::on_newAddress_clicked
void on_newAddress_clicked()
Create a new address for receiving coins and / or add a new address book entry.
Definition: addressbookpage.cpp:207
AddressBookPage::contextMenu
QMenu * contextMenu
Definition: addressbookpage.h:57
EditAddressDialog::setModel
void setModel(AddressTableModel *model)
Definition: editaddressdialog.cpp:55
bitcoin-config.h
GUIUtil::dialog_flags
constexpr auto dialog_flags
Definition: guiutil.h:51
EditAddressDialog::EditSendingAddress
@ EditSendingAddress
Definition: editaddressdialog.h:30
AddressBookSortFilterProxyModel::m_type
const QString m_type
Definition: addressbookpage.cpp:25
AddressBookPage::proxyModel
AddressBookSortFilterProxyModel * proxyModel
Definition: addressbookpage.h:56
AddressBookPage::Mode
Mode
Definition: addressbookpage.h:36
AddressBookPage::onEditAction
void onEditAction()
Edit currently selected address entry (no button)
Definition: addressbookpage.cpp:186
CSVModelWriter
Export a Qt table model to a CSV file.
Definition: csvmodelwriter.h:18
AddressBookPage::done
void done(int retval) override
Definition: addressbookpage.cpp:270
AddressBookPage::on_copyAddress_clicked
void on_copyAddress_clicked()
Copy address of currently selected address entry to clipboard.
Definition: addressbookpage.cpp:176
EditAddressDialog
Dialog for editing an address and associated information.
Definition: editaddressdialog.h:22
AddressBookPage::model
AddressTableModel * model
Definition: addressbookpage.h:52
AddressBookPage::returnValue
QString returnValue
Definition: addressbookpage.h:55
PlatformStyle::getImagesOnButtons
bool getImagesOnButtons() const
Definition: platformstyle.h:21
CSVModelWriter::setModel
void setModel(const QAbstractItemModel *model)
Definition: csvmodelwriter.cpp:17
AddressBookPage::selectionChanged
void selectionChanged()
Set button states based on selected tab and selection.
Definition: addressbookpage.cpp:237
AddressBookPage::ui
Ui::AddressBookPage * ui
Definition: addressbookpage.h:51
AddressBookPage
Widget that shows a list of sending or receiving addresses.
Definition: addressbookpage.h:26
AddressBookPage::selectNewAddress
void selectNewAddress(const QModelIndex &parent, int begin, int)
New entry/entries were added to address table.
Definition: addressbookpage.cpp:325
AddressTableModel::index
QModelIndex index(int row, int column, const QModelIndex &parent) const override
Definition: addresstablemodel.cpp:326
guiutil.h
AddressTableModel::Label
@ Label
User specified label.
Definition: addresstablemodel.h:32
AddressBookPage::deleteAction
QAction * deleteAction
Definition: addressbookpage.h:58
EditAddressDialog::NewSendingAddress
@ NewSendingAddress
Definition: editaddressdialog.h:28
AddressBookPage::~AddressBookPage
~AddressBookPage()
Definition: addressbookpage.cpp:143
editaddressdialog.h
GUIUtil::getSaveFileName
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:270
platformstyle.h
Ui
Definition: addressbookpage.h:14
AddressTableModel::TypeRole
@ TypeRole
Type of address (Send or Receive)
Definition: addresstablemodel.h:37
GUIUtil::copyEntryData
void copyEntryData(const QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
Definition: guiutil.cpp:238
AddressBookPage::tab
Tabs tab
Definition: addressbookpage.h:54
AddressBookSortFilterProxyModel
Definition: addressbookpage.cpp:23
AddressBookPage::AddressBookPage
AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent=nullptr)
Definition: addressbookpage.cpp:58
EditAddressDialog::getAddress
QString getAddress() const
Definition: editaddressdialog.cpp:157
AddressTableModel::Send
static const QString Send
Specifies send address.
Definition: addresstablemodel.h:50
GUIUtil::handleCloseWindowShortcut
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:393
AddressBookPage::onCopyLabelAction
void onCopyLabelAction()
Copy label of currently selected address entry to clipboard (no button)
Definition: addressbookpage.cpp:181
AddressBookPage::mode
Mode mode
Definition: addressbookpage.h:53
PlatformStyle
Definition: platformstyle.h:13
addresstablemodel.h
AddressBookPage::Tabs
Tabs
Definition: addressbookpage.h:31
AddressBookSortFilterProxyModel::filterAcceptsRow
bool filterAcceptsRow(int row, const QModelIndex &parent) const override
Definition: addressbookpage.cpp:38
AddressBookPage::ForEditing
@ ForEditing
Open address book for editing.
Definition: addressbookpage.h:38
AddressTableModel::Address
@ Address
Bitcoin address.
Definition: addresstablemodel.h:33
AddressBookPage::ForSelection
@ ForSelection
Open address book to pick address.
Definition: addressbookpage.h:37
AddressBookPage::ReceivingTab
@ ReceivingTab
Definition: addressbookpage.h:33