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