Bitcoin ABC 0.30.5
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
23class AddressBookSortFilterProxyModel final : public QSortFilterProxyModel {
24 const QString m_type;
25
26public:
27 AddressBookSortFilterProxyModel(const QString &type, QObject *parent)
28 : QSortFilterProxyModel(parent), m_type(type) {
29 setDynamicSortFilter(true);
30 setFilterCaseSensitivity(Qt::CaseInsensitive);
31 setSortCaseSensitivity(Qt::CaseInsensitive);
32 }
33
34protected:
35 bool filterAcceptsRow(int row, const QModelIndex &parent) const override {
36 auto model = sourceModel();
37 auto label = model->index(row, AddressTableModel::Label, parent);
38
39 if (model->data(label, AddressTableModel::TypeRole).toString() !=
40 m_type) {
41 return false;
42 }
43
44 auto address = model->index(row, AddressTableModel::Address, parent);
45
46 if (filterRegExp().indexIn(model->data(address).toString()) < 0 &&
47 filterRegExp().indexIn(model->data(label).toString()) < 0) {
48 return false;
49 }
50
51 return true;
52 }
53};
54
56 Tabs _tab, QWidget *parent)
57 : QDialog(parent), ui(new Ui::AddressBookPage), model(nullptr), mode(_mode),
58 tab(_tab) {
59 ui->setupUi(this);
60
61 if (!platformStyle->getImagesOnButtons()) {
62 ui->newAddress->setIcon(QIcon());
63 ui->copyAddress->setIcon(QIcon());
64 ui->deleteAddress->setIcon(QIcon());
65 ui->exportButton->setIcon(QIcon());
66 } else {
67 ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
68 ui->copyAddress->setIcon(
69 platformStyle->SingleColorIcon(":/icons/editcopy"));
70 ui->deleteAddress->setIcon(
71 platformStyle->SingleColorIcon(":/icons/remove"));
72 ui->exportButton->setIcon(
73 platformStyle->SingleColorIcon(":/icons/export"));
74 }
75
76 switch (mode) {
77 case ForSelection:
78 switch (tab) {
79 case SendingTab:
80 setWindowTitle(tr("Choose the address to send coins to"));
81 break;
82 case ReceivingTab:
83 setWindowTitle(
84 tr("Choose the address to receive coins with"));
85 break;
86 }
87 connect(ui->tableView, &QTableView::doubleClicked, this,
88 &QDialog::accept);
89 ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
90 ui->tableView->setFocus();
91 ui->closeButton->setText(tr("C&hoose"));
92 ui->exportButton->hide();
93 break;
94 case ForEditing:
95 switch (tab) {
96 case SendingTab:
97 setWindowTitle(tr("Sending addresses"));
98 break;
99 case ReceivingTab:
100 setWindowTitle(tr("Receiving addresses"));
101 break;
102 }
103 break;
104 }
105 switch (tab) {
106 case SendingTab:
107 ui->labelExplanation->setText(
108 tr("These are your Bitcoin addresses for sending payments. "
109 "Always check the amount and the receiving address before "
110 "sending coins."));
111 ui->deleteAddress->setVisible(true);
112 ui->newAddress->setVisible(true);
113 break;
114 case ReceivingTab:
115 ui->labelExplanation->setText(
116 tr("These are your Bitcoin addresses for receiving payments. "
117 "Use the 'Create new receiving address' button in the "
118 "receive tab to create new addresses."));
119 ui->deleteAddress->setVisible(false);
120 ui->newAddress->setVisible(false);
121 break;
122 }
123
124 // Context menu actions
125 QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
126 QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
127 QAction *editAction = new QAction(tr("&Edit"), this);
128 deleteAction = new QAction(ui->deleteAddress->text(), this);
129
130 // Build context menu
131 contextMenu = new QMenu(this);
132 contextMenu->addAction(copyAddressAction);
133 contextMenu->addAction(copyLabelAction);
134 contextMenu->addAction(editAction);
135 if (tab == SendingTab) {
136 contextMenu->addAction(deleteAction);
137 }
138 contextMenu->addSeparator();
139
140 // Connect signals for context menu actions
141 connect(copyAddressAction, &QAction::triggered, this,
143 connect(copyLabelAction, &QAction::triggered, this,
145 connect(editAction, &QAction::triggered, this,
147 connect(deleteAction, &QAction::triggered, this,
149
150 connect(ui->tableView, &QWidget::customContextMenuRequested, this,
152
153 connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept);
154
156}
157
159 delete ui;
160}
161
163 this->model = _model;
164 if (!_model) {
165 return;
166 }
167
171 proxyModel->setSourceModel(_model);
172
173 connect(ui->searchLineEdit, &QLineEdit::textChanged, proxyModel,
174 &QSortFilterProxyModel::setFilterWildcard);
175
176 ui->tableView->setModel(proxyModel);
177 ui->tableView->sortByColumn(0, Qt::AscendingOrder);
178
179 // Set column widths
180 ui->tableView->horizontalHeader()->setSectionResizeMode(
181 AddressTableModel::Label, QHeaderView::Stretch);
182 ui->tableView->horizontalHeader()->setSectionResizeMode(
183 AddressTableModel::Address, QHeaderView::ResizeToContents);
184
185 connect(ui->tableView->selectionModel(),
186 &QItemSelectionModel::selectionChanged, this,
188
189 // Select row for newly created address
190 connect(_model, &AddressTableModel::rowsInserted, this,
192
194}
195
198}
199
202}
203
205 if (!model) {
206 return;
207 }
208
209 if (!ui->tableView->selectionModel()) {
210 return;
211 }
212 QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
213 if (indexes.isEmpty()) {
214 return;
215 }
216
220 this);
221 dlg.setModel(model);
222 QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
223 dlg.loadRow(origIndex.row());
224 dlg.exec();
225}
226
228 if (!model) {
229 return;
230 }
231
232 if (tab == ReceivingTab) {
233 return;
234 }
235
237 dlg.setModel(model);
238 if (dlg.exec()) {
240 }
241}
242
244 QTableView *table = ui->tableView;
245 if (!table->selectionModel()) {
246 return;
247 }
248
249 QModelIndexList indexes = table->selectionModel()->selectedRows();
250 if (!indexes.isEmpty()) {
251 table->model()->removeRow(indexes.at(0).row());
252 }
253}
254
256 // Set button states based on selected tab and selection
257 QTableView *table = ui->tableView;
258 if (!table->selectionModel()) {
259 return;
260 }
261
262 if (table->selectionModel()->hasSelection()) {
263 switch (tab) {
264 case SendingTab:
265 // In sending tab, allow deletion of selection
266 ui->deleteAddress->setEnabled(true);
267 ui->deleteAddress->setVisible(true);
268 deleteAction->setEnabled(true);
269 break;
270 case ReceivingTab:
271 // Deleting receiving addresses, however, is not allowed
272 ui->deleteAddress->setEnabled(false);
273 ui->deleteAddress->setVisible(false);
274 deleteAction->setEnabled(false);
275 break;
276 }
277 ui->copyAddress->setEnabled(true);
278 } else {
279 ui->deleteAddress->setEnabled(false);
280 ui->copyAddress->setEnabled(false);
281 }
282}
283
284void AddressBookPage::done(int retval) {
285 QTableView *table = ui->tableView;
286 if (!table->selectionModel() || !table->model()) {
287 return;
288 }
289
290 // Figure out which address was selected, and return it
291 QModelIndexList indexes =
292 table->selectionModel()->selectedRows(AddressTableModel::Address);
293
294 for (const QModelIndex &index : indexes) {
295 QVariant address = table->model()->data(index);
296 returnValue = address.toString();
297 }
298
299 if (returnValue.isEmpty()) {
300 // If no address entry selected, return rejected
301 retval = Rejected;
302 }
303
304 QDialog::done(retval);
305}
306
308 // CSV is currently the only supported format
309 QString filename =
310 GUIUtil::getSaveFileName(this, tr("Export Address List"), QString(),
311 tr("Comma separated file (*.csv)"), nullptr);
312
313 if (filename.isNull()) {
314 return;
315 }
316
317 CSVModelWriter writer(filename);
318
319 // name, column, role
320 writer.setModel(proxyModel);
321 writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
322 writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
323
324 if (!writer.write()) {
325 QMessageBox::critical(this, tr("Exporting Failed"),
326 tr("There was an error trying to save the "
327 "address list to %1. Please try again.")
328 .arg(filename));
329 }
330}
331
332void AddressBookPage::contextualMenu(const QPoint &point) {
333 QModelIndex index = ui->tableView->indexAt(point);
334 if (index.isValid()) {
335 contextMenu->exec(QCursor::pos());
336 }
337}
338
339void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin,
340 int /*end*/) {
341 QModelIndex idx = proxyModel->mapFromSource(
342 model->index(begin, AddressTableModel::Address, parent));
343 if (idx.isValid() &&
344 (idx.data(Qt::EditRole).toString() == newAddressToSelect)) {
345 // Select row of newly created address, once
346 ui->tableView->setFocus();
347 ui->tableView->selectRow(idx.row());
348 newAddressToSelect.clear();
349 }
350}
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 handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:407
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:263
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:294