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