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