Bitcoin-Qt signmessage GUI (pull request #582)
[novacoin.git] / src / qt / addressbookpage.cpp
1 #include "addressbookpage.h"
2 #include "ui_addressbookpage.h"
3
4 #include "addresstablemodel.h"
5 #include "bitcoingui.h"
6 #include "editaddressdialog.h"
7 #include "csvmodelwriter.h"
8 #include "guiutil.h"
9
10 #include <QSortFilterProxyModel>
11 #include <QClipboard>
12 #include <QFileDialog>
13 #include <QMessageBox>
14 #include <QMenu>
15
16 #ifdef USE_QRCODE
17 #include "qrcodedialog.h"
18 #endif
19
20 AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
21     QDialog(parent),
22     ui(new Ui::AddressBookPage),
23     model(0),
24     mode(mode),
25     tab(tab)
26 {
27     ui->setupUi(this);
28
29 #ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac
30     ui->newAddressButton->setIcon(QIcon());
31     ui->copyToClipboard->setIcon(QIcon());
32     ui->deleteButton->setIcon(QIcon());
33 #endif
34
35 #ifndef USE_QRCODE
36     ui->showQRCode->setVisible(false);
37 #endif
38
39     switch(mode)
40     {
41     case ForSending:
42         connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
43         ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
44         ui->tableView->setFocus();
45         break;
46     case ForEditing:
47         ui->buttonBox->hide();
48         break;
49     }
50     switch(tab)
51     {
52     case SendingTab:
53         ui->labelExplanation->hide();
54         break;
55     case ReceivingTab:
56         break;
57     }
58     ui->tableView->setTabKeyNavigation(false);
59     ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
60
61     // Context menu actions
62     QAction *copyAddressAction = new QAction(tr("Copy address"), this);
63     QAction *copyLabelAction = new QAction(tr("Copy label"), this);
64     QAction *editAction = new QAction(tr("Edit"), this);
65     deleteAction = new QAction(tr("Delete"), this);
66
67     contextMenu = new QMenu();
68     contextMenu->addAction(copyAddressAction);
69     contextMenu->addAction(copyLabelAction);
70     contextMenu->addAction(editAction);
71     contextMenu->addAction(deleteAction);
72
73     connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
74     connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
75     connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
76     connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
77
78     connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
79
80     // Pass through accept action from button box
81     connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
82 }
83
84 AddressBookPage::~AddressBookPage()
85 {
86     delete ui;
87 }
88
89 void AddressBookPage::setModel(AddressTableModel *model)
90 {
91     this->model = model;
92     if(!model)
93         return;
94     // Refresh list from core
95     model->updateList();
96
97     proxyModel = new QSortFilterProxyModel(this);
98     proxyModel->setSourceModel(model);
99     proxyModel->setDynamicSortFilter(true);
100     switch(tab)
101     {
102     case ReceivingTab:
103         // Receive filter
104         proxyModel->setFilterRole(AddressTableModel::TypeRole);
105         proxyModel->setFilterFixedString(AddressTableModel::Receive);
106         break;
107     case SendingTab:
108         // Send filter
109         proxyModel->setFilterRole(AddressTableModel::TypeRole);
110         proxyModel->setFilterFixedString(AddressTableModel::Send);
111         break;
112     }
113     ui->tableView->setModel(proxyModel);
114     ui->tableView->sortByColumn(0, Qt::AscendingOrder);
115
116     // Set column widths
117     ui->tableView->horizontalHeader()->resizeSection(
118             AddressTableModel::Address, 320);
119     ui->tableView->horizontalHeader()->setResizeMode(
120             AddressTableModel::Label, QHeaderView::Stretch);
121
122     connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
123             this, SLOT(selectionChanged()));
124
125     if(mode == ForSending)
126     {
127         // Auto-select first row when in sending mode
128         ui->tableView->selectRow(0);
129     }
130     selectionChanged();
131 }
132
133 void AddressBookPage::on_copyToClipboard_clicked()
134 {
135     GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
136 }
137 void AddressBookPage::onCopyLabelAction()
138 {
139     GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
140 }
141
142 void AddressBookPage::onEditAction()
143 {
144     if(!ui->tableView->selectionModel())
145         return;
146     QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
147     if(indexes.isEmpty())
148         return;
149
150     EditAddressDialog dlg(
151             tab == SendingTab ?
152             EditAddressDialog::EditSendingAddress :
153             EditAddressDialog::EditReceivingAddress);
154     dlg.setModel(model);
155     QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
156     dlg.loadRow(origIndex.row());
157     dlg.exec();
158 }
159
160 void AddressBookPage::on_signMessage_clicked()
161 {
162     QTableView *table = ui->tableView;
163     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
164     QString addr;
165
166     foreach (QModelIndex index, indexes)
167     {
168         QVariant address = index.data();
169         addr = address.toString();
170     }
171
172     QObject *qoGUI = parent()->parent();
173     BitcoinGUI *gui = qobject_cast<BitcoinGUI *>(qoGUI);
174     if (gui)
175         gui->gotoMessagePage(addr);
176 }
177
178 void AddressBookPage::on_newAddressButton_clicked()
179 {
180     if(!model)
181         return;
182     EditAddressDialog dlg(
183             tab == SendingTab ?
184             EditAddressDialog::NewSendingAddress :
185             EditAddressDialog::NewReceivingAddress);
186     dlg.setModel(model);
187     if(dlg.exec())
188     {
189         // Select row for newly created address
190         QString address = dlg.getAddress();
191         QModelIndexList lst = proxyModel->match(proxyModel->index(0,
192                           AddressTableModel::Address, QModelIndex()),
193                           Qt::EditRole, address, 1, Qt::MatchExactly);
194         if(!lst.isEmpty())
195         {
196             ui->tableView->setFocus();
197             ui->tableView->selectRow(lst.at(0).row());
198         }
199     }
200 }
201
202 void AddressBookPage::on_deleteButton_clicked()
203 {
204     QTableView *table = ui->tableView;
205     if(!table->selectionModel())
206         return;
207     QModelIndexList indexes = table->selectionModel()->selectedRows();
208     if(!indexes.isEmpty())
209     {
210         table->model()->removeRow(indexes.at(0).row());
211     }
212 }
213
214 void AddressBookPage::selectionChanged()
215 {
216     // Set button states based on selected tab and selection
217     QTableView *table = ui->tableView;
218     if(!table->selectionModel())
219         return;
220
221     if(table->selectionModel()->hasSelection())
222     {
223         switch(tab)
224         {
225         case SendingTab:
226             // In sending tab, allow deletion of selection
227             ui->deleteButton->setEnabled(true);
228             deleteAction->setEnabled(true);
229             ui->signMessage->setEnabled(false);
230             break;
231         case ReceivingTab:
232             // Deleting receiving addresses, however, is not allowed
233             ui->deleteButton->setEnabled(false);
234             deleteAction->setEnabled(false);
235             ui->signMessage->setEnabled(true);
236             break;
237         }
238         ui->copyToClipboard->setEnabled(true);
239         ui->showQRCode->setEnabled(true);
240     }
241     else
242     {
243         ui->deleteButton->setEnabled(false);
244         ui->showQRCode->setEnabled(false);
245         ui->copyToClipboard->setEnabled(false);
246         ui->signMessage->setEnabled(false);
247     }
248 }
249
250 void AddressBookPage::done(int retval)
251 {
252     QTableView *table = ui->tableView;
253     if(!table->selectionModel() || !table->model())
254         return;
255     // When this is a tab/widget and not a model dialog, ignore "done"
256     if(mode == ForEditing)
257         return;
258
259     // Figure out which address was selected, and return it
260     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
261
262     foreach (QModelIndex index, indexes)
263     {
264         QVariant address = table->model()->data(index);
265         returnValue = address.toString();
266     }
267
268     if(returnValue.isEmpty())
269     {
270         // If no address entry selected, return rejected
271         retval = Rejected;
272     }
273
274     QDialog::done(retval);
275 }
276
277 void AddressBookPage::exportClicked()
278 {
279     // CSV is currently the only supported format
280     QString filename = QFileDialog::getSaveFileName(
281             this,
282             tr("Export Address Book Data"),
283             QDir::currentPath(),
284             tr("Comma separated file (*.csv)"));
285
286     if (filename.isNull()) return;
287
288     CSVModelWriter writer(filename);
289
290     // name, column, role
291     writer.setModel(proxyModel);
292     writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
293     writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
294
295     if(!writer.write())
296     {
297         QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
298                               QMessageBox::Abort, QMessageBox::Abort);
299     }
300 }
301
302 void AddressBookPage::on_showQRCode_clicked()
303 {
304 #ifdef USE_QRCODE
305     QTableView *table = ui->tableView;
306     QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
307
308
309     QRCodeDialog *d;
310     foreach (QModelIndex index, indexes)
311     {
312         QString address = index.data().toString(),
313             label = index.sibling(index.row(), 0).data().toString(),
314             title = QString("%1 << %2 >>").arg(label).arg(address);
315
316         QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this);
317         d->show();
318     }
319 #endif
320 }
321
322 void AddressBookPage::contextualMenu(const QPoint &point)
323 {
324     QModelIndex index = ui->tableView->indexAt(point);
325     if(index.isValid())
326     {
327         contextMenu->exec(QCursor::pos());
328     }
329 }