Wallet encryption part 2: ask passphrase when needed, add menu options
[novacoin.git] / src / qt / bitcoingui.cpp
1 /*
2  * Qt4 bitcoin GUI.
3  *
4  * W.J. van der Laan 2011
5  */
6 #include "bitcoingui.h"
7 #include "transactiontablemodel.h"
8 #include "addressbookpage.h"
9 #include "sendcoinsdialog.h"
10 #include "optionsdialog.h"
11 #include "aboutdialog.h"
12 #include "clientmodel.h"
13 #include "walletmodel.h"
14 #include "editaddressdialog.h"
15 #include "optionsmodel.h"
16 #include "transactiondescdialog.h"
17 #include "addresstablemodel.h"
18 #include "transactionview.h"
19 #include "overviewpage.h"
20 #include "bitcoinunits.h"
21 #include "guiconstants.h"
22 #include "askpassphrasedialog.h"
23
24 #include <QApplication>
25 #include <QMainWindow>
26 #include <QMenuBar>
27 #include <QMenu>
28 #include <QIcon>
29 #include <QTabWidget>
30 #include <QVBoxLayout>
31 #include <QToolBar>
32 #include <QStatusBar>
33 #include <QLabel>
34 #include <QLineEdit>
35 #include <QPushButton>
36 #include <QLocale>
37 #include <QMessageBox>
38 #include <QProgressBar>
39 #include <QStackedWidget>
40 #include <QDateTime>
41 #include <QMovie>
42
43 #include <QDragEnterEvent>
44 #include <QUrl>
45
46 #include <iostream>
47
48 BitcoinGUI::BitcoinGUI(QWidget *parent):
49     QMainWindow(parent),
50     clientModel(0),
51     walletModel(0),
52     encryptWalletAction(0),
53     changePassphraseAction(0),
54     trayIcon(0)
55 {
56     resize(850, 550);
57     setWindowTitle(tr("Bitcoin Wallet"));
58     setWindowIcon(QIcon(":icons/bitcoin"));
59     // Accept D&D of URIs
60     setAcceptDrops(true);
61
62     createActions();
63
64     // Menus
65     QMenu *file = menuBar()->addMenu(tr("&File"));
66     file->addAction(sendCoinsAction);
67     file->addAction(receiveCoinsAction);
68     file->addSeparator();
69     file->addAction(quitAction);
70     
71     QMenu *settings = menuBar()->addMenu(tr("&Settings"));
72     settings->addAction(encryptWalletAction);
73     settings->addAction(changePassphraseAction);
74     settings->addSeparator();
75     settings->addAction(optionsAction);
76
77     QMenu *help = menuBar()->addMenu(tr("&Help"));
78     help->addAction(aboutAction);
79     
80     // Toolbars
81     QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
82     toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
83     toolbar->addAction(overviewAction);
84     toolbar->addAction(sendCoinsAction);
85     toolbar->addAction(receiveCoinsAction);
86     toolbar->addAction(historyAction);
87     toolbar->addAction(addressBookAction);
88
89     QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
90     toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
91     toolbar2->addAction(exportAction);
92
93     // Create tabs
94     overviewPage = new OverviewPage();
95
96     transactionsPage = new QWidget(this);
97     QVBoxLayout *vbox = new QVBoxLayout();
98     transactionView = new TransactionView(this);
99     vbox->addWidget(transactionView);
100     transactionsPage->setLayout(vbox);
101
102     addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab);
103
104     receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab);
105
106     sendCoinsPage = new SendCoinsDialog(this);
107
108     centralWidget = new QStackedWidget(this);
109     centralWidget->addWidget(overviewPage);
110     centralWidget->addWidget(transactionsPage);
111     centralWidget->addWidget(addressBookPage);
112     centralWidget->addWidget(receiveCoinsPage);
113     centralWidget->addWidget(sendCoinsPage);
114     setCentralWidget(centralWidget);
115
116     // Create status bar
117     statusBar();
118
119     // Status bar notification icons
120     QFrame *frameBlocks = new QFrame();
121     //frameBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
122     frameBlocks->setContentsMargins(0,0,0,0);
123     frameBlocks->setMinimumWidth(56);
124     frameBlocks->setMaximumWidth(56);
125     QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
126     frameBlocksLayout->setContentsMargins(3,0,3,0);
127     frameBlocksLayout->setSpacing(3);
128     labelEncryptionIcon = new QLabel();
129     labelConnectionsIcon = new QLabel();
130     labelBlocksIcon = new QLabel();
131     frameBlocksLayout->addStretch();
132     frameBlocksLayout->addWidget(labelEncryptionIcon);
133     frameBlocksLayout->addStretch();
134     frameBlocksLayout->addWidget(labelConnectionsIcon);
135     frameBlocksLayout->addStretch();
136     frameBlocksLayout->addWidget(labelBlocksIcon);
137     frameBlocksLayout->addStretch();
138
139     // Progress bar for blocks download
140     progressBarLabel = new QLabel(tr("Synchronizing with network..."));
141     progressBarLabel->setVisible(false);
142     progressBar = new QProgressBar();
143     progressBar->setToolTip(tr("Block chain synchronization in progress"));
144     progressBar->setVisible(false);
145
146     statusBar()->addWidget(progressBarLabel);
147     statusBar()->addWidget(progressBar);
148     statusBar()->addPermanentWidget(frameBlocks);
149
150     createTrayIcon();
151
152     syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
153
154     // Clicking on a transaction on the overview page simply sends you to transaction history page
155     connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
156
157     // Doubleclicking on a transaction on the transaction history page shows details
158     connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
159
160     gotoOverviewPage();
161 }
162
163 void BitcoinGUI::createActions()
164 {
165     QActionGroup *tabGroup = new QActionGroup(this);
166
167     overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
168     overviewAction->setToolTip(tr("Show general overview of wallet"));
169     overviewAction->setCheckable(true);
170     tabGroup->addAction(overviewAction);
171
172     historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
173     historyAction->setToolTip(tr("Browse transaction history"));
174     historyAction->setCheckable(true);
175     tabGroup->addAction(historyAction);
176
177     addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
178     addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
179     addressBookAction->setCheckable(true);
180     tabGroup->addAction(addressBookAction);
181
182     receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
183     receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
184     receiveCoinsAction->setCheckable(true);
185     tabGroup->addAction(receiveCoinsAction);
186
187     sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
188     sendCoinsAction->setToolTip(tr("Send coins to a bitcoin address"));
189     sendCoinsAction->setCheckable(true);
190     tabGroup->addAction(sendCoinsAction);
191
192     connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
193     connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
194     connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
195     connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
196     connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
197
198     quitAction = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this);
199     quitAction->setToolTip(tr("Quit application"));
200     aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this);
201     aboutAction->setToolTip(tr("Show information about Bitcoin"));
202     optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
203     optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
204     openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
205     openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
206     exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
207     exportAction->setToolTip(tr("Export the current view to a file"));
208     encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
209     encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
210     encryptWalletAction->setCheckable(true);
211     changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
212     changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
213
214     connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
215     connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
216     connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
217     connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(show()));
218     connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
219     connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
220 }
221
222 void BitcoinGUI::setClientModel(ClientModel *clientModel)
223 {
224     this->clientModel = clientModel;
225
226     if(clientModel->isTestNet())
227     {
228         QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]");
229         setWindowTitle(title_testnet);
230         setWindowIcon(QIcon(":icons/bitcoin_testnet"));
231         if(trayIcon)
232         {
233             trayIcon->setToolTip(title_testnet);
234             trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
235         }
236     }
237
238     // Keep up to date with client
239     setNumConnections(clientModel->getNumConnections());
240     connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
241
242     setNumBlocks(clientModel->getNumBlocks());
243     connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
244
245     // Report errors from network/worker thread
246     connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
247 }
248
249 void BitcoinGUI::setWalletModel(WalletModel *walletModel)
250 {
251     this->walletModel = walletModel;
252
253     // Report errors from wallet thread
254     connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
255
256     // Put transaction list in tabs
257     transactionView->setModel(walletModel);
258
259     overviewPage->setModel(walletModel);
260     addressBookPage->setModel(walletModel->getAddressTableModel());
261     receiveCoinsPage->setModel(walletModel->getAddressTableModel());
262     sendCoinsPage->setModel(walletModel);
263
264     setEncryptionStatus(walletModel->getEncryptionStatus());
265     connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
266
267     // Balloon popup for new transaction
268     connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
269             this, SLOT(incomingTransaction(QModelIndex,int,int)));
270
271     // Ask for passphrase if needed
272     connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
273 }
274
275 void BitcoinGUI::createTrayIcon()
276 {
277     QMenu *trayIconMenu = new QMenu(this);
278     trayIconMenu->addAction(openBitcoinAction);
279     trayIconMenu->addAction(optionsAction);
280     trayIconMenu->addSeparator();
281     trayIconMenu->addAction(quitAction);
282
283     trayIcon = new QSystemTrayIcon(this);
284     trayIcon->setContextMenu(trayIconMenu);
285     trayIcon->setToolTip("Bitcoin client");
286     trayIcon->setIcon(QIcon(":/icons/toolbar"));
287     connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
288             this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
289     trayIcon->show();
290 }
291
292 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
293 {
294     if(reason == QSystemTrayIcon::Trigger)
295     {
296         // Doubleclick on system tray icon triggers "open bitcoin"
297         openBitcoinAction->trigger();
298     }
299 }
300
301 void BitcoinGUI::optionsClicked()
302 {
303     OptionsDialog dlg;
304     dlg.setModel(clientModel->getOptionsModel());
305     dlg.exec();
306 }
307
308 void BitcoinGUI::aboutClicked()
309 {
310     AboutDialog dlg;
311     dlg.setModel(clientModel);
312     dlg.exec();
313 }
314
315 void BitcoinGUI::setNumConnections(int count)
316 {
317     QString icon;
318     switch(count)
319     {
320     case 0: icon = ":/icons/connect_0"; break;
321     case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
322     case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
323     case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
324     default: icon = ":/icons/connect_4"; break;
325     }
326     labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
327     labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
328 }
329
330 void BitcoinGUI::setNumBlocks(int count)
331 {
332     int total = clientModel->getTotalBlocksEstimate();
333     QString tooltip;
334
335     if(count < total)
336     {
337         progressBarLabel->setVisible(true);
338         progressBar->setVisible(true);
339         progressBar->setMaximum(total);
340         progressBar->setValue(count);
341         tooltip = tr("Downloaded %1 of %2 blocks of transaction history.").arg(count).arg(total);
342     }
343     else
344     {
345         progressBarLabel->setVisible(false);
346         progressBar->setVisible(false);
347         tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
348     }
349
350     QDateTime now = QDateTime::currentDateTime();
351     QDateTime lastBlockDate = clientModel->getLastBlockDate();
352     int secs = lastBlockDate.secsTo(now);
353     QString text;
354
355     // Represent time from last generated block in human readable text
356     if(secs < 60)
357     {
358         text = tr("%n second(s) ago","",secs);
359     }
360     else if(secs < 60*60)
361     {
362         text = tr("%n minute(s) ago","",secs/60);
363     }
364     else if(secs < 24*60*60)
365     {
366         text = tr("%n hour(s) ago","",secs/(60*60));
367     }
368     else
369     {
370         text = tr("%n day(s) ago","",secs/(60*60*24));
371     }
372
373     // Set icon state: spinning if catching up, tick otherwise
374     if(secs < 30*60)
375     {
376         tooltip = tr("Up to date") + QString("\n") + tooltip;
377         labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
378     }
379     else
380     {
381         tooltip = tr("Catching up...") + QString("\n") + tooltip;
382         labelBlocksIcon->setMovie(syncIconMovie);
383         syncIconMovie->start();
384     }
385
386     tooltip += QString("\n");
387     tooltip += tr("Last received block was generated %1.").arg(text);
388
389     labelBlocksIcon->setToolTip(tooltip);
390     progressBarLabel->setToolTip(tooltip);
391     progressBar->setToolTip(tooltip);
392 }
393
394 void BitcoinGUI::error(const QString &title, const QString &message)
395 {
396     // Report errors from network/worker thread
397     if(trayIcon->supportsMessages())
398     {
399         // Show as "balloon" message if possible
400         trayIcon->showMessage(title, message, QSystemTrayIcon::Critical);
401     }
402     else
403     {
404         // Fall back to old fashioned popup dialog if not
405         QMessageBox::critical(this, title,
406             message,
407             QMessageBox::Ok, QMessageBox::Ok);
408     }
409 }
410
411 void BitcoinGUI::changeEvent(QEvent *e)
412 {
413     if (e->type() == QEvent::WindowStateChange)
414     {
415         if(clientModel->getOptionsModel()->getMinimizeToTray())
416         {
417             if (isMinimized())
418             {
419                 hide();
420                 e->ignore();
421             }
422             else
423             {
424                 e->accept();
425             }
426         }
427     }
428     QMainWindow::changeEvent(e);
429 }
430
431 void BitcoinGUI::closeEvent(QCloseEvent *event)
432 {
433     if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
434        !clientModel->getOptionsModel()->getMinimizeOnClose())
435     {
436         qApp->quit();
437     }
438     QMainWindow::closeEvent(event);
439 }
440
441 void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
442 {
443     QString strMessage =
444         tr("This transaction is over the size limit.  You can still send it for a fee of %1, "
445           "which goes to the nodes that process your transaction and helps to support the network.  "
446           "Do you want to pay the fee?").arg(
447                 BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
448     QMessageBox::StandardButton retval = QMessageBox::question(
449           this, tr("Sending..."), strMessage,
450           QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
451     *payFee = (retval == QMessageBox::Yes);
452 }
453
454 void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
455 {
456     if(start == end)
457         return;
458     TransactionTableModel *ttm = walletModel->getTransactionTableModel();
459     qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
460                     .data(Qt::EditRole).toULongLong();
461     if(!clientModel->inInitialBlockDownload())
462     {
463         // On new transaction, make an info balloon
464         // Unless the initial block download is in progress, to prevent balloon-spam
465         QString date = ttm->index(start, TransactionTableModel::Date, parent)
466                         .data().toString();
467         QString type = ttm->index(start, TransactionTableModel::Type, parent)
468                         .data().toString();
469         QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
470                         .data().toString();
471
472         trayIcon->showMessage((amount)<0 ? tr("Sent transaction") :
473                                            tr("Incoming transaction"),
474                               tr("Date: ") + date + "\n" +
475                               tr("Amount: ") + BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true) + "\n" +
476                               tr("Type: ") + type + "\n" +
477                               tr("Address: ") + address + "\n",
478                               QSystemTrayIcon::Information);
479     }
480 }
481
482 void BitcoinGUI::gotoOverviewPage()
483 {
484     overviewAction->setChecked(true);
485     centralWidget->setCurrentWidget(overviewPage);
486
487     exportAction->setEnabled(false);
488     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
489 }
490
491 void BitcoinGUI::gotoHistoryPage()
492 {
493     historyAction->setChecked(true);
494     centralWidget->setCurrentWidget(transactionsPage);
495
496     exportAction->setEnabled(true);
497     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
498     connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked()));
499 }
500
501 void BitcoinGUI::gotoAddressBookPage()
502 {
503     addressBookAction->setChecked(true);
504     centralWidget->setCurrentWidget(addressBookPage);
505
506     exportAction->setEnabled(true);
507     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
508     connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked()));
509 }
510
511 void BitcoinGUI::gotoReceiveCoinsPage()
512 {
513     receiveCoinsAction->setChecked(true);
514     centralWidget->setCurrentWidget(receiveCoinsPage);
515
516     exportAction->setEnabled(true);
517     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
518     connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked()));
519 }
520
521 void BitcoinGUI::gotoSendCoinsPage()
522 {
523     sendCoinsAction->setChecked(true);
524     if(centralWidget->currentWidget() != sendCoinsPage)
525     {
526         // Clear the current contents if we arrived from another tab
527         sendCoinsPage->clear();
528     }
529     centralWidget->setCurrentWidget(sendCoinsPage);
530
531     exportAction->setEnabled(false);
532     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
533 }
534
535 void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
536 {
537     // Accept only URLs
538     if(event->mimeData()->hasUrls())
539         event->acceptProposedAction();
540 }
541
542 void BitcoinGUI::dropEvent(QDropEvent *event)
543 {
544     if(event->mimeData()->hasUrls())
545     {
546         gotoSendCoinsPage();
547         QList<QUrl> urls = event->mimeData()->urls();
548         foreach(const QUrl &url, urls)
549         {
550             sendCoinsPage->handleURL(&url);
551         }
552     }
553
554     event->acceptProposedAction();
555 }
556
557 void BitcoinGUI::setEncryptionStatus(int status)
558 {
559     switch(status)
560     {
561     case WalletModel::Unencrypted:
562         labelEncryptionIcon->hide();
563         encryptWalletAction->setChecked(false);
564         changePassphraseAction->setEnabled(false);
565         encryptWalletAction->setEnabled(true);
566         break;
567     case WalletModel::Unlocked:
568         labelEncryptionIcon->show();
569         labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
570         labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
571         encryptWalletAction->setChecked(true);
572         changePassphraseAction->setEnabled(true);
573         encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
574         break;
575     case WalletModel::Locked:
576         labelEncryptionIcon->show();
577         labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
578         labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
579         encryptWalletAction->setChecked(true);
580         changePassphraseAction->setEnabled(true);
581         encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
582         break;
583     }
584 }
585
586 void BitcoinGUI::encryptWallet(bool status)
587 {
588     AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
589                                      AskPassphraseDialog::Decrypt, this);
590     dlg.setModel(walletModel);
591     dlg.exec();
592
593     setEncryptionStatus(walletModel->getEncryptionStatus());
594 }
595
596 void BitcoinGUI::changePassphrase()
597 {
598     AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
599     dlg.setModel(walletModel);
600     dlg.exec();
601 }
602
603 void BitcoinGUI::unlockWallet()
604 {
605     // Unlock wallet if needed
606     if(walletModel->getEncryptionStatus() == WalletModel::Locked)
607     {
608         AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
609         dlg.setModel(walletModel);
610         dlg.exec();
611     }
612 }