Dogecoin Core  1.14.2
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 
9 #include "addressbookpage.h"
10 #include "ui_addressbookpage.h"
11 
12 #include "addresstablemodel.h"
13 #include "bitcoingui.h"
14 #include "csvmodelwriter.h"
15 #include "editaddressdialog.h"
16 #include "guiutil.h"
17 #include "platformstyle.h"
18 
19 #include <QIcon>
20 #include <QMenu>
21 #include <QMessageBox>
22 #include <QSortFilterProxyModel>
23 
24 AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
25  QDialog(parent),
26  ui(new Ui::AddressBookPage),
27  model(0),
28  mode(_mode),
29  tab(_tab)
30 {
31  ui->setupUi(this);
32 
33  if (!platformStyle->getImagesOnButtons()) {
34  ui->newAddress->setIcon(QIcon());
35  ui->copyAddress->setIcon(QIcon());
36  ui->deleteAddress->setIcon(QIcon());
37  ui->exportButton->setIcon(QIcon());
38  } else {
39  ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
40  ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
41  ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
42  ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
43  }
44 
45  switch(mode)
46  {
47  case ForSelection:
48  switch(tab)
49  {
50  case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
51  case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
52  }
53  connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
54  ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
55  ui->tableView->setFocus();
56  ui->closeButton->setText(tr("C&hoose"));
57  ui->exportButton->hide();
58  break;
59  case ForEditing:
60  switch(tab)
61  {
62  case SendingTab: setWindowTitle(tr("Such sending addresses")); break;
63  case ReceivingTab: setWindowTitle(tr("Much receiving addresses")); break;
64  }
65  break;
66  }
67  switch(tab)
68  {
69  case SendingTab:
70  ui->labelExplanation->setText(tr("These are your Dogecoin addresses for sending payments. Always check the amount and the receiving address before sending coins."));
71  ui->deleteAddress->setVisible(true);
72  break;
73  case ReceivingTab:
74  ui->labelExplanation->setText(tr("These are your Dogecoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
75  ui->deleteAddress->setVisible(false);
76  break;
77  }
78 
79  // Context menu actions
80  QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
81  QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
82  QAction *editAction = new QAction(tr("&Edit"), this);
83  deleteAction = new QAction(ui->deleteAddress->text(), this);
84 
85  // Build context menu
86  contextMenu = new QMenu(this);
87  contextMenu->addAction(copyAddressAction);
88  contextMenu->addAction(copyLabelAction);
89  contextMenu->addAction(editAction);
90  if(tab == SendingTab)
91  contextMenu->addAction(deleteAction);
92  contextMenu->addSeparator();
93 
94  // Connect signals for context menu actions
95  connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyAddress_clicked()));
96  connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
97  connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
98  connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteAddress_clicked()));
99 
100  connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
101 
102  connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(accept()));
103 }
104 
106 {
107  delete ui;
108 }
109 
111 {
112  this->model = _model;
113  if(!_model)
114  return;
115 
116  proxyModel = new QSortFilterProxyModel(this);
117  proxyModel->setSourceModel(_model);
118  proxyModel->setDynamicSortFilter(true);
119  proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
120  proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
121  switch(tab)
122  {
123  case ReceivingTab:
124  // Receive filter
125  proxyModel->setFilterRole(AddressTableModel::TypeRole);
126  proxyModel->setFilterFixedString(AddressTableModel::Receive);
127  break;
128  case SendingTab:
129  // Send filter
130  proxyModel->setFilterRole(AddressTableModel::TypeRole);
131  proxyModel->setFilterFixedString(AddressTableModel::Send);
132  break;
133  }
134  ui->tableView->setModel(proxyModel);
135  ui->tableView->sortByColumn(0, Qt::AscendingOrder);
136 
137  // Set column widths
138 #if QT_VERSION < 0x050000
139  ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
140  ui->tableView->horizontalHeader()->setResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
141 #else
142  ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
143  ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
144 #endif
145 
146  connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
147  this, SLOT(selectionChanged()));
148 
149  // Select row for newly created address
150  connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));
151 
153 }
154 
156 {
158 }
159 
161 {
163 }
164 
166 {
167  if(!model)
168  return;
169 
170  if(!ui->tableView->selectionModel())
171  return;
172  QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
173  if(indexes.isEmpty())
174  return;
175 
176  EditAddressDialog dlg(
177  tab == SendingTab ?
180  dlg.setModel(model);
181  QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
182  dlg.loadRow(origIndex.row());
183  dlg.exec();
184 }
185 
187 {
188  if(!model)
189  return;
190 
191  EditAddressDialog dlg(
192  tab == SendingTab ?
195  dlg.setModel(model);
196  if(dlg.exec())
197  {
199  }
200 }
201 
203 {
204  QTableView *table = ui->tableView;
205  if(!table->selectionModel())
206  return;
207 
208  QModelIndexList indexes = table->selectionModel()->selectedRows();
209  if(!indexes.isEmpty())
210  {
211  table->model()->removeRow(indexes.at(0).row());
212  }
213 }
214 
216 {
217  // Set button states based on selected tab and selection
218  QTableView *table = ui->tableView;
219  if(!table->selectionModel())
220  return;
221 
222  if(table->selectionModel()->hasSelection())
223  {
224  switch(tab)
225  {
226  case SendingTab:
227  // In sending tab, allow deletion of selection
228  ui->deleteAddress->setEnabled(true);
229  ui->deleteAddress->setVisible(true);
230  deleteAction->setEnabled(true);
231  break;
232  case ReceivingTab:
233  // Deleting receiving addresses, however, is not allowed
234  ui->deleteAddress->setEnabled(false);
235  ui->deleteAddress->setVisible(false);
236  deleteAction->setEnabled(false);
237  break;
238  }
239  ui->copyAddress->setEnabled(true);
240  }
241  else
242  {
243  ui->deleteAddress->setEnabled(false);
244  ui->copyAddress->setEnabled(false);
245  }
246 }
247 
248 void AddressBookPage::done(int retval)
249 {
250  QTableView *table = ui->tableView;
251  if(!table->selectionModel() || !table->model())
252  return;
253 
254  // Figure out which address was selected, and return it
255  QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
256 
257  Q_FOREACH (const QModelIndex& index, indexes) {
258  QVariant address = table->model()->data(index);
259  returnValue = address.toString();
260  }
261 
262  if(returnValue.isEmpty())
263  {
264  // If no address entry selected, return rejected
265  retval = Rejected;
266  }
267 
268  QDialog::done(retval);
269 }
270 
272 {
273  // CSV is currently the only supported format
274  QString filename = GUIUtil::getSaveFileName(this,
275  tr("Export Address List"), QString(),
276  tr("Comma separated file (*.csv)"), NULL);
277 
278  if (filename.isNull())
279  return;
280 
281  CSVModelWriter writer(filename);
282 
283  // name, column, role
284  writer.setModel(proxyModel);
285  writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
286  writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
287 
288  if(!writer.write()) {
289  QMessageBox::critical(this, tr("Exporting Failed"),
290  tr("There was an error trying to save the address list to %1. Please try again.").arg(filename));
291  }
292 }
293 
294 void AddressBookPage::contextualMenu(const QPoint &point)
295 {
296  QModelIndex index = ui->tableView->indexAt(point);
297  if(index.isValid())
298  {
299  contextMenu->exec(QCursor::pos());
300  }
301 }
302 
303 void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
304 {
305  QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
306  if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
307  {
308  // Select row of newly created address, once
309  ui->tableView->setFocus();
310  ui->tableView->selectRow(idx.row());
311  newAddressToSelect.clear();
312  }
313 }
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 on_copyAddress_clicked()
Copy address of currently selected address entry to clipboard.
void on_exportButton_clicked()
Export button clicked.
void done(int retval)
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.
AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent)
QSortFilterProxyModel * proxyModel
QAction * deleteAction
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
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:21
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
void copyEntryData(QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
Definition: guiutil.cpp:274