Partially revert acd906f9bbf55e42.
[novacoin.git] / src / qt / addressbookpage.cpp
1 #include "addressbookpage.h"
2 #include "ui_addressbookpage.h"
3
4 #include "addresstablemodel.h"
5 #include "optionsmodel.h"
6 #include "bitcoingui.h"
7 #include "editaddressdialog.h"
8 #include "csvmodelwriter.h"
9 #include "guiutil.h"
10
11 #ifdef USE_QRCODE
12 #include "qrcodedialog.h"
13 #endif
14
15 #include <QSortFilterProxyModel>
16 #include <QClipboard>
17 #include <QMessageBox>
18 #include <QMenu>
19
20
21 AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
22     QDialog(parent),
23     ui(new Ui::AddressBookPage),
24     model(0),
25     optionsModel(0),
26     mode(mode),
27     tab(tab)
28 {
29     ui->setupUi(this);
30
31 #ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
32     ui->newAddressButton->setIcon(QIcon());
33     ui->copyToClipboard->setIcon(QIcon());
34     ui->deleteButton->setIcon(QIcon());
35 #endif
36
37     switch(mode)
38     {
39     case ForSending:
40         connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
41         ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
42         ui->tableView->setFocus();
43         break;
44     case ForEditing:
45         ui->buttonBox->setVisible(false);
46         break;
47     }
48     switch(tab)
49     {
50     case SendingTab:
51         ui->labelExplanation->setVisible(false);
52         ui->deleteButton->setVisible(true);
53         ui->signMessage->setVisible(false);
54         ui->verifyMessage->setVisible(true);
55         break;
56     case ReceivingTab:
57         ui->deleteButton->setVisible(false);
58         ui->signMessage->setVisible(true);
59         ui->verifyMessage->setVisible(false);
60         break;
61     }
62
63     // Context menu actions
64     QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
65     QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this);
66     QAction *editAction = new QAction(tr("&Edit"), this);
67 #ifdef USE_QRCODE
68     QAction *showQRCodeAction = new QAction(tr("Show &QR Code"), this);
69 #endif
70     QAction *signMessageAction = new QAction(ui->signMessage->text(), this);
71     QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this);
72     deleteAction = new QAction(ui->deleteButton->text(), this);
73
74     // Build context menu
75     contextMenu = new QMenu();
76     contextMenu->addAction(copyAddressAction);
77     contextMenu->addAction(copyLabelAction);
78     contextMenu->addAction(editAction);
79     if(tab == SendingTab)
80         contextMenu->addAction(deleteAction);
81     contextMenu->addSeparator();
82     #ifdef USE_QRCODE
83         contextMenu->addAction(showQRCodeAction);
84     #endif
85     if(tab == ReceivingTab)
86         contextMenu->addAction(signMessageAction);
87     else if(tab == SendingTab)
88         contextMenu->addAction(verifyMessageAction);
89
90     // Connect signals for context menu actions
91     connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
92     connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
93     connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
94     connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
95     #ifdef USE_QRCODE
96         connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked()));
97     #endif
98     connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked()));
99     connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked()));
100     connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
101
102     // Pass through accept action from button box
103     connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
104 }
105
106 AddressBookPage::~AddressBookPage()
107 {
108     delete ui;
109 }
110
111 void AddressBookPage::setModel(AddressTableModel *model)
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     ui->tableView->horizontalHeader()->resizeSection(
140             AddressTableModel::Address, 320);
141 #if QT_VERSION < 0x050000
142     ui->tableView->horizontalHeader()->setResizeMode(
143             AddressTableModel::Label, QHeaderView::Stretch);
144 #else
145     ui->tableView->horizontalHeader()->setSectionResizeMode(
146     AddressTableModel::Label, QHeaderView::Stretch);
147 #endif
148     connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
149             this, SLOT(selectionChanged()));
150
151     // Select row for newly created address
152     connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
153             this, SLOT(selectNewAddress(QModelIndex,int,int)));
154
155     selectionChanged();
156 }
157
158 void AddressBookPage::setOptionsModel(OptionsModel *optionsModel)
159 {
160     this->optionsModel = optionsModel;
161 }
162
163 void AddressBookPage::on_copyToClipboard_clicked()
164 {
165     GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
166 }
167
168 void AddressBookPage::onCopyLabelAction()
169 {
170     GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
171 }
172
173 void AddressBookPage::onEditAction()
174 {
175     if(!ui->tableView->selectionModel())
176         return;
177     QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
178     if(indexes.isEmpty())
179         return;
180
181     EditAddressDialog dlg(
182             tab == SendingTab ?
183             EditAddressDialog::EditSendingAddress :
184             EditAddressDialog::EditReceivingAddress);
185     dlg.setModel(model);
186     QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
187     dlg.loadRow(origIndex.row());
188     dlg.exec();
189 }
190
191 void AddressBookPage::on_signMessage_clicked()
192 {
193     QTableView *table = ui->tableView;
194     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
195     QString addr;
196
197     foreach (QModelIndex index, indexes)
198     {
199         QVariant address = index.data();
200         addr = address.toString();
201     }
202
203     emit signMessage(addr);
204 }
205
206 void AddressBookPage::on_verifyMessage_clicked()
207 {
208     QTableView *table = ui->tableView;
209     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
210     QString addr;
211
212     foreach (QModelIndex index, indexes)
213     {
214         QVariant address = index.data();
215         addr = address.toString();
216     }
217
218     emit verifyMessage(addr);
219 }
220
221 void AddressBookPage::on_newAddressButton_clicked()
222 {
223     if(!model)
224         return;
225     EditAddressDialog dlg(
226             tab == SendingTab ?
227             EditAddressDialog::NewSendingAddress :
228             EditAddressDialog::NewReceivingAddress, this);
229     dlg.setModel(model);
230     if(dlg.exec())
231     {
232         newAddressToSelect = dlg.getAddress();
233     }
234 }
235
236 void AddressBookPage::on_deleteButton_clicked()
237 {
238     QTableView *table = ui->tableView;
239     if(!table->selectionModel())
240         return;
241     QModelIndexList indexes = table->selectionModel()->selectedRows();
242     if(!indexes.isEmpty())
243     {
244         table->model()->removeRow(indexes.at(0).row());
245     }
246 }
247
248 void AddressBookPage::selectionChanged()
249 {
250     // Set button states based on selected tab and selection
251     QTableView *table = ui->tableView;
252     if(!table->selectionModel())
253         return;
254
255     if(table->selectionModel()->hasSelection())
256     {
257         switch(tab)
258         {
259         case SendingTab:
260             // In sending tab, allow deletion of selection
261             ui->deleteButton->setEnabled(true);
262             ui->deleteButton->setVisible(true);
263             deleteAction->setEnabled(true);
264             ui->signMessage->setEnabled(false);
265             ui->signMessage->setVisible(false);
266             ui->verifyMessage->setEnabled(true);
267             ui->verifyMessage->setVisible(true);
268             break;
269         case ReceivingTab:
270             // Deleting receiving addresses, however, is not allowed
271             ui->deleteButton->setEnabled(false);
272             ui->deleteButton->setVisible(false);
273             deleteAction->setEnabled(false);
274             ui->signMessage->setEnabled(true);
275             ui->signMessage->setVisible(true);
276             ui->verifyMessage->setEnabled(false);
277             ui->verifyMessage->setVisible(false);
278             break;
279         }
280         ui->copyToClipboard->setEnabled(true);
281     }
282     else
283     {
284         ui->deleteButton->setEnabled(false);
285         ui->copyToClipboard->setEnabled(false);
286         ui->signMessage->setEnabled(false);
287         ui->verifyMessage->setEnabled(false);
288     }
289 }
290
291 void AddressBookPage::done(int retval)
292 {
293     QTableView *table = ui->tableView;
294     if(!table->selectionModel() || !table->model())
295         return;
296     // When this is a tab/widget and not a model dialog, ignore "done"
297     if(mode == ForEditing)
298         return;
299
300     // Figure out which address was selected, and return it
301     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
302
303     foreach (QModelIndex index, indexes)
304     {
305         QVariant address = table->model()->data(index);
306         returnValue = address.toString();
307     }
308
309     if(returnValue.isEmpty())
310     {
311         // If no address entry selected, return rejected
312         retval = Rejected;
313     }
314
315     QDialog::done(retval);
316 }
317
318 void AddressBookPage::exportClicked()
319 {
320     // CSV is currently the only supported format
321     QString filename = GUIUtil::getSaveFileName(
322             this,
323             tr("Export Address Book Data"), QString(),
324             tr("Comma separated file (*.csv)"));
325
326     if (filename.isNull()) return;
327
328     CSVModelWriter writer(filename);
329
330     // name, column, role
331     writer.setModel(proxyModel);
332     writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
333     writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
334
335     if(!writer.write())
336     {
337         QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
338                               QMessageBox::Abort, QMessageBox::Abort);
339     }
340 }
341
342 void AddressBookPage::on_showQRCode_clicked()
343 {
344  #ifdef USE_QRCODE
345     QTableView *table = ui->tableView;
346     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
347
348     foreach (QModelIndex index, indexes)
349     {
350         QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();
351
352         QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
353         if(optionsModel)
354             dialog->setModel(optionsModel);
355         dialog->setAttribute(Qt::WA_DeleteOnClose);
356         dialog->show();
357     }
358 #endif
359 }
360
361 void AddressBookPage::contextualMenu(const QPoint &point)
362 {
363     QModelIndex index = ui->tableView->indexAt(point);
364     if(index.isValid())
365     {
366         contextMenu->exec(QCursor::pos());
367     }
368 }
369
370 void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
371 {
372     QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
373     if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
374     {
375         // Select row of newly created address, once
376         ui->tableView->setFocus();
377         ui->tableView->selectRow(idx.row());
378         newAddressToSelect.clear();
379     }
380 }