показывать подсказки в контекстном меню
[novacoin.git] / src / qt / bitcoingui.cpp
1 /*
2  * Qt4 bitcoin GUI.
3  *
4  * W.J. van der Laan 2011-2012
5  * The Bitcoin Developers 2011-2012
6  */
7 #include "bitcoingui.h"
8 #include "transactiontablemodel.h"
9 #include "addressbookpage.h"
10 #include "sendcoinsdialog.h"
11 #include "signverifymessagedialog.h"
12 #include "multisigdialog.h"
13 #include "optionsdialog.h"
14 #include "aboutdialog.h"
15 #include "clientmodel.h"
16 #include "walletmodel.h"
17 #include "editaddressdialog.h"
18 #include "optionsmodel.h"
19 #include "transactiondescdialog.h"
20 #include "addresstablemodel.h"
21 #include "transactionview.h"
22 #include "overviewpage.h"
23 #include "bitcoinunits.h"
24 #include "guiconstants.h"
25 #include "askpassphrasedialog.h"
26 #include "notificator.h"
27 #include "guiutil.h"
28 #include "ui_interface.h"
29 #include "rpcconsole.h"
30 #include "mintingview.h"
31
32 #ifdef Q_OS_MAC
33 #include "macdockiconhandler.h"
34 #endif
35
36 #include <QApplication>
37 #if QT_VERSION < 0x050000
38 #include <QMainWindow>
39 #endif
40 #include <QMenuBar>
41 #include <QMenu>
42 #include <QIcon>
43 #include <QTabWidget>
44 #include <QVBoxLayout>
45 #include <QToolBar>
46 #include <QStatusBar>
47 #include <QLabel>
48 #include <QLineEdit>
49 #include <QPushButton>
50 #include <QLocale>
51 #include <QMessageBox>
52 #include <QProgressBar>
53 #include <QStackedWidget>
54 #include <QDateTime>
55 #include <QMovie>
56 #include <QFileDialog>
57 #if QT_VERSION < 0x050000
58 #include <QDesktopServices>
59 #else
60 #include <QStandardPaths>
61 #endif
62 #include <QTimer>
63 #include <QDragEnterEvent>
64 #if QT_VERSION < 0x050000
65 #include <QUrl>
66 #endif
67 #include <QStyle>
68 #include <QMimeData>
69
70 #include <iostream>
71
72 extern bool fWalletUnlockMintOnly;
73
74 BitcoinGUI::BitcoinGUI(QWidget *parent):
75     QMainWindow(parent),
76     clientModel(0),
77     walletModel(0),
78     encryptWalletAction(0),
79     lockWalletAction(0),
80     unlockWalletAction(0),
81     unlockWalletMiningAction(0),
82     changePassphraseAction(0),
83     aboutQtAction(0),
84     trayIcon(0),
85     notificator(0),
86     rpcConsole(0),
87     aboutDialog(0)
88 {
89     resize(850, 550);
90     setWindowTitle(tr("NovaCoin") + " - " + tr("Wallet"));
91 #ifndef Q_OS_MAC
92     qApp->setWindowIcon(QIcon(":icons/bitcoin"));
93     setWindowIcon(QIcon(":icons/bitcoin"));
94 #else
95     setUnifiedTitleAndToolBarOnMac(true);
96     QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
97 #endif
98     // Accept D&D of URIs
99     setAcceptDrops(true);
100
101     // Create actions for the toolbar, menu bar and tray/dock icon
102     createActions();
103
104     // Create application menu bar
105     createMenuBar();
106
107     // Create the toolbars
108     createToolBars();
109
110     // Create the tray icon (or setup the dock icon)
111     createTrayIcon();
112
113     // Create tabs
114     overviewPage = new OverviewPage();
115
116     transactionsPage = new QWidget(this);
117     QVBoxLayout *vbox = new QVBoxLayout();
118     transactionView = new TransactionView(this);
119     vbox->addWidget(transactionView);
120     transactionsPage->setLayout(vbox);
121
122     mintingPage = new QWidget(this);
123     QVBoxLayout *vboxMinting = new QVBoxLayout();
124     mintingView = new MintingView(this);
125     vboxMinting->addWidget(mintingView);
126     mintingPage->setLayout(vboxMinting);
127
128     addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab);
129
130     receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab);
131
132     sendCoinsPage = new SendCoinsDialog(this);
133
134     signVerifyMessageDialog = new SignVerifyMessageDialog(this);
135
136     multisigPage = new MultisigDialog(this);
137
138     centralWidget = new QStackedWidget(this);
139     centralWidget->addWidget(overviewPage);
140     centralWidget->addWidget(transactionsPage);
141     centralWidget->addWidget(mintingPage);
142     centralWidget->addWidget(addressBookPage);
143     centralWidget->addWidget(receiveCoinsPage);
144     centralWidget->addWidget(sendCoinsPage);
145     setCentralWidget(centralWidget);
146
147     // Create status bar
148     statusBar();
149
150     // Status bar notification icons
151     QFrame *frameBlocks = new QFrame();
152     frameBlocks->setContentsMargins(0,0,0,0);
153     frameBlocks->setMinimumWidth(72);
154     frameBlocks->setMaximumWidth(72);
155     QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
156     frameBlocksLayout->setContentsMargins(3,0,3,0);
157     frameBlocksLayout->setSpacing(3);
158     labelEncryptionIcon = new QLabel();
159     labelMiningIcon = new QLabel();
160     labelConnectionsIcon = new QLabel();
161     labelBlocksIcon = new QLabel();
162     frameBlocksLayout->addStretch();
163     frameBlocksLayout->addWidget(labelEncryptionIcon);
164     frameBlocksLayout->addStretch();
165     frameBlocksLayout->addWidget(labelMiningIcon);
166     frameBlocksLayout->addStretch();
167     frameBlocksLayout->addWidget(labelConnectionsIcon);
168     frameBlocksLayout->addStretch();
169     frameBlocksLayout->addWidget(labelBlocksIcon);
170     frameBlocksLayout->addStretch();
171
172     // Progress bar and label for blocks download
173     progressBarLabel = new QLabel();
174     progressBarLabel->setVisible(false);
175     progressBar = new QProgressBar();
176     progressBar->setAlignment(Qt::AlignCenter);
177     progressBar->setVisible(false);
178
179     // Override style sheet for progress bar for styles that have a segmented progress bar,
180     // as they make the text unreadable (workaround for issue #1071)
181     // See https://qt-project.org/doc/qt-4.8/gallery.html
182     QString curStyle = qApp->style()->metaObject()->className();
183     if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
184     {
185         progressBar->setStyleSheet("QProgressBar { background-color: #e8e8e8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: 7px; margin: 0px; }");
186     }
187
188     statusBar()->addWidget(progressBarLabel);
189     statusBar()->addWidget(progressBar);
190     statusBar()->addPermanentWidget(frameBlocks);
191
192     syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
193
194     // Clicking on a transaction on the overview page simply sends you to transaction history page
195     connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
196     connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex)));
197
198     // Double-clicking on a transaction on the transaction history page shows details
199     connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
200
201     rpcConsole = new RPCConsole(0);
202     connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
203
204     aboutDialog = new AboutDialog(0);
205
206     // Clicking on "Verify Message" in the address book sends you to the verify message tab
207     connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString)));
208     // Clicking on "Sign Message" in the receive coins page sends you to the sign message tab
209     connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString)));
210
211     gotoOverviewPage();
212 }
213
214 BitcoinGUI::~BitcoinGUI()
215 {
216     if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
217         trayIcon->hide();
218 #ifdef Q_OS_MAC
219     delete appMenuBar;
220 #endif
221
222     delete rpcConsole;
223     delete aboutDialog;
224 }
225
226 void BitcoinGUI::createActions()
227 {
228     QActionGroup *tabGroup = new QActionGroup(this);
229
230     overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
231     overviewAction->setToolTip(tr("Show general overview of wallet"));
232     overviewAction->setCheckable(true);
233     overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
234     tabGroup->addAction(overviewAction);
235
236     sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
237     sendCoinsAction->setToolTip(tr("Send coins to a NovaCoin address"));
238     sendCoinsAction->setCheckable(true);
239     sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
240     tabGroup->addAction(sendCoinsAction);
241
242     receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
243     receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
244     receiveCoinsAction->setCheckable(true);
245     receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
246     tabGroup->addAction(receiveCoinsAction);
247
248     historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
249     historyAction->setToolTip(tr("Browse transaction history"));
250     historyAction->setCheckable(true);
251     historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
252     tabGroup->addAction(historyAction);
253
254     mintingAction = new QAction(QIcon(":/icons/history"), tr("&Minting"), this);
255     mintingAction->setToolTip(tr("Show your minting capacity"));
256     mintingAction->setCheckable(true);
257     mintingAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
258     tabGroup->addAction(mintingAction);
259
260     addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
261     addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
262     addressBookAction->setCheckable(true);
263     addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_6));
264     tabGroup->addAction(addressBookAction);
265
266     multisigAction = new QAction(QIcon(":/icons/send"), tr("Multisig"), this);
267     multisigAction->setStatusTip(tr("Open window for working with multisig addresses"));
268     tabGroup->addAction(multisigAction);
269
270     connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
271     connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
272     connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
273     connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
274     connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
275     connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
276     connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
277     connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
278     connect(mintingAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
279     connect(mintingAction, SIGNAL(triggered()), this, SLOT(gotoMintingPage()));
280     connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
281     connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
282     connect(multisigAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
283     connect(multisigAction, SIGNAL(triggered()), this, SLOT(gotoMultisigPage()));
284
285     quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
286     quitAction->setStatusTip(tr("Quit application"));
287     quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
288     quitAction->setMenuRole(QAction::QuitRole);
289     aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About NovaCoin"), this);
290     aboutAction->setStatusTip(tr("Show information about NovaCoin"));
291     aboutAction->setMenuRole(QAction::AboutRole);
292 #if QT_VERSION < 0x050000
293     aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
294 #else
295     aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
296 #endif
297     aboutQtAction->setStatusTip(tr("Show information about Qt"));
298     aboutQtAction->setMenuRole(QAction::AboutQtRole);
299     optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
300     optionsAction->setStatusTip(tr("Modify configuration options for NovaCoin"));
301     optionsAction->setMenuRole(QAction::PreferencesRole);
302     toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
303     encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
304     encryptWalletAction->setStatusTip(tr("Encrypt or decrypt wallet"));
305     encryptWalletAction->setCheckable(true);
306     backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
307     backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
308     dumpWalletAction = new QAction(QIcon(":/icons/dump"), tr("&Dump Wallet..."), this);
309     dumpWalletAction->setStatusTip(tr("Dump keys to a text file"));
310     importWalletAction = new QAction(QIcon(":/icons/import"), tr("&Import Wallet..."), this);
311     importWalletAction->setStatusTip(tr("Import keys into a wallet"));
312     changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
313     changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
314     signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
315     signMessageAction->setStatusTip(tr("Sign messages with your Novacoin addresses to prove you own them"));
316     verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
317     verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Novacoin addresses"));
318
319     lockWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Lock wallet"), this);
320     lockWalletAction->setStatusTip(tr("Lock wallet"));
321     lockWalletAction->setCheckable(true);
322
323     unlockWalletAction = new QAction(QIcon(":/icons/lock_open"), tr("Unlo&ck wallet"), this);
324     unlockWalletAction->setStatusTip(tr("Unlock wallet"));
325     unlockWalletAction->setCheckable(true);
326
327     unlockWalletMiningAction = new QAction(QIcon(":/icons/mining_active"), tr("Unlo&ck wallet for mining"), this);
328     unlockWalletMiningAction->setStatusTip(tr("Unlock wallet for mining"));
329     unlockWalletMiningAction->setCheckable(true);
330
331     exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
332     exportAction->setStatusTip(tr("Export the data in the current tab to a file"));
333     openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this);
334     openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
335
336     connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
337     connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
338     connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
339     connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
340     connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
341     connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
342     connect(lockWalletAction, SIGNAL(triggered(bool)), this, SLOT(lockWallet()));
343     connect(unlockWalletAction, SIGNAL(triggered(bool)), this, SLOT(unlockWallet()));
344     connect(unlockWalletMiningAction, SIGNAL(triggered(bool)), this, SLOT(unlockWalletMining(bool)));
345     connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
346     connect(dumpWalletAction, SIGNAL(triggered()), this, SLOT(dumpWallet()));
347     connect(importWalletAction, SIGNAL(triggered()), this, SLOT(importWallet()));
348     connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
349     connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
350     connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
351 }
352
353 void BitcoinGUI::createMenuBar()
354 {
355 #ifdef Q_OS_MAC
356     // Create a decoupled menu bar on Mac which stays even if the window is closed
357     appMenuBar = new QMenuBar();
358 #else
359     // Get the main window's menu bar on other platforms
360     appMenuBar = menuBar();
361 #endif
362
363     // Configure the menus
364     QMenu *file = appMenuBar->addMenu(tr("&File"));
365     file->addAction(backupWalletAction);
366     file->addSeparator();
367     file->addAction(dumpWalletAction);
368     file->addAction(importWalletAction);
369     file->addAction(exportAction);
370     file->addAction(signMessageAction);
371     file->addAction(verifyMessageAction);
372     file->addAction(multisigAction);
373     file->addSeparator();
374     file->addAction(quitAction);
375
376     QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
377     QMenu *securityMenu = settings->addMenu(QIcon(":/icons/key"), tr("&Wallet security"));
378     securityMenu->addAction(encryptWalletAction);
379     securityMenu->addAction(changePassphraseAction);
380     securityMenu->addAction(unlockWalletAction);
381     securityMenu->addAction(unlockWalletMiningAction);
382     securityMenu->addAction(lockWalletAction);
383     settings->addAction(optionsAction);
384
385     QMenu *help = appMenuBar->addMenu(tr("&Help"));
386     help->addAction(openRPCConsoleAction);
387     help->addSeparator();
388     help->addAction(aboutAction);
389     help->addAction(aboutQtAction);
390 }
391
392 void BitcoinGUI::createToolBars()
393 {
394     QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
395     toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
396     toolbar->addAction(overviewAction);
397     toolbar->addAction(sendCoinsAction);
398     toolbar->addAction(receiveCoinsAction);
399     toolbar->addAction(historyAction);
400     toolbar->addAction(mintingAction);
401     toolbar->addAction(addressBookAction);
402
403     QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
404     toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
405     toolbar2->addAction(exportAction);
406     toolbar2->setVisible(false);
407     
408 }
409
410 void BitcoinGUI::setClientModel(ClientModel *clientModel)
411 {
412     this->clientModel = clientModel;
413     if(clientModel)
414     {
415         // Replace some strings and icons, when using the testnet
416         if(clientModel->isTestNet())
417         {
418             setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]"));
419 #ifndef Q_OS_MAC
420             qApp->setWindowIcon(QIcon(":icons/bitcoin_testnet"));
421             setWindowIcon(QIcon(":icons/bitcoin_testnet"));
422 #else
423             MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
424 #endif
425             if(trayIcon)
426             {
427                 trayIcon->setToolTip(tr("NovaCoin client") + QString(" ") + tr("[testnet]"));
428                 trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
429                 toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet"));
430             }
431
432             aboutAction->setIcon(QIcon(":/icons/toolbar_testnet"));
433         }
434
435         // Keep up to date with client
436         setNumConnections(clientModel->getNumConnections());
437         connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
438
439         setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
440         connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
441
442         QTimer *timer = new QTimer(this);
443         connect(timer, SIGNAL(timeout()), this, SLOT(updateMining()));
444         timer->start(10*1000); //10 seconds
445
446         // Report errors from network/worker thread
447         connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
448
449         rpcConsole->setClientModel(clientModel);
450         addressBookPage->setOptionsModel(clientModel->getOptionsModel());
451         receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
452     }
453 }
454
455 void BitcoinGUI::setWalletModel(WalletModel *walletModel)
456 {
457     this->walletModel = walletModel;
458     if(walletModel)
459     {
460         // Report errors from wallet thread
461         connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
462
463         // Put transaction list in tabs
464         transactionView->setModel(walletModel);
465         mintingView->setModel(walletModel);
466
467         overviewPage->setModel(walletModel);
468         addressBookPage->setModel(walletModel->getAddressTableModel());
469         receiveCoinsPage->setModel(walletModel->getAddressTableModel());
470         sendCoinsPage->setModel(walletModel);
471         signVerifyMessageDialog->setModel(walletModel);
472         multisigPage->setModel(walletModel);
473
474         setEncryptionStatus(walletModel->getEncryptionStatus());
475         connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
476         connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(updateMining()));
477
478         // Balloon pop-up for new transaction
479         connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
480                 this, SLOT(incomingTransaction(QModelIndex,int,int)));
481
482         // Ask for passphrase if needed
483         connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
484     }
485 }
486
487 void BitcoinGUI::createTrayIcon()
488 {
489     QMenu *trayIconMenu;
490 #ifndef Q_OS_MAC
491     trayIcon = new QSystemTrayIcon(this);
492     trayIconMenu = new QMenu(this);
493     trayIcon->setContextMenu(trayIconMenu);
494     trayIcon->setToolTip(tr("NovaCoin client"));
495     trayIcon->setIcon(QIcon(":/icons/toolbar"));
496     connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
497             this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
498     trayIcon->show();
499 #else
500     // Note: On Mac, the dock icon is used to provide the tray's functionality.
501     MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
502     dockIconHandler->setMainWindow((QMainWindow *)this);
503     trayIconMenu = dockIconHandler->dockMenu();
504 #endif
505
506     // Configuration of the tray icon (or dock icon) icon menu
507     trayIconMenu->addAction(toggleHideAction);
508     trayIconMenu->addSeparator();
509     trayIconMenu->addAction(sendCoinsAction);
510     trayIconMenu->addAction(multisigAction);
511     trayIconMenu->addAction(receiveCoinsAction);
512     trayIconMenu->addSeparator();
513     trayIconMenu->addAction(signMessageAction);
514     trayIconMenu->addAction(verifyMessageAction);
515     trayIconMenu->addSeparator();
516     trayIconMenu->addAction(optionsAction);
517     trayIconMenu->addAction(openRPCConsoleAction);
518 #ifndef Q_OS_MAC
519     // This is built-in on Mac
520     trayIconMenu->addSeparator();
521     trayIconMenu->addAction(quitAction);    
522 #endif
523     notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
524 }
525
526 #ifndef Q_OS_MAC
527 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
528 {
529     if(reason == QSystemTrayIcon::Trigger)
530     {
531         // Click on system tray icon triggers show/hide of the main window
532         toggleHideAction->trigger();
533     }
534 }
535 #endif
536
537 void BitcoinGUI::optionsClicked()
538 {
539     if(!clientModel || !clientModel->getOptionsModel())
540         return;
541     OptionsDialog dlg;
542     dlg.setModel(clientModel->getOptionsModel());
543     dlg.exec();
544 }
545
546 void BitcoinGUI::aboutClicked()
547 {
548     aboutDialog->setModel(clientModel);
549     aboutDialog->setWindowModality(Qt::ApplicationModal);
550     aboutDialog->show();
551 }
552
553 void BitcoinGUI::setNumConnections(int count)
554 {
555     QString icon;
556     switch(count)
557     {
558     case 0: icon = ":/icons/connect_0"; break;
559     case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
560     case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
561     case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
562     default: icon = ":/icons/connect_4"; break;
563     }
564     labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
565     labelConnectionsIcon->setToolTip(tr("%n active connection(s) to NovaCoin network", "", count));
566 }
567
568 void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
569 {
570     // don't show / hide progress bar and its label if we have no connection to the network
571     if (!clientModel || clientModel->getNumConnections() == 0)
572     {
573         progressBarLabel->setVisible(false);
574         progressBar->setVisible(false);
575
576         return;
577     }
578
579     QString strStatusBarWarnings = clientModel->getStatusBarWarnings();
580     QString tooltip;
581
582     if(count < nTotalBlocks)
583     {
584         int nRemainingBlocks = nTotalBlocks - count;
585         float nPercentageDone = count / (nTotalBlocks * 0.01f);
586
587         if (strStatusBarWarnings.isEmpty())
588         {
589             progressBarLabel->setText(tr("Synchronizing with network..."));
590             progressBarLabel->setVisible(true);
591             progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
592             progressBar->setMaximum(nTotalBlocks);
593             progressBar->setValue(count);
594             progressBar->setVisible(true);
595         }
596
597         tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
598     }
599     else
600     {
601         if (strStatusBarWarnings.isEmpty())
602             progressBarLabel->setVisible(false);
603
604         progressBar->setVisible(false);
605         tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
606     }
607
608     // Override progressBarLabel text and hide progress bar, when we have warnings to display
609     if (!strStatusBarWarnings.isEmpty())
610     {
611         progressBarLabel->setText(strStatusBarWarnings);
612         progressBarLabel->setVisible(true);
613         progressBar->setVisible(false);
614     }
615
616     QDateTime lastBlockDate = clientModel->getLastBlockDate();
617     int secs = lastBlockDate.secsTo(QDateTime::currentDateTime());
618     QString text;
619
620     // Represent time from last generated block in human readable text
621     if(secs <= 0)
622     {
623         // Fully up to date. Leave text empty.
624     }
625     else if(secs < 60)
626     {
627         text = tr("%n second(s) ago","",secs);
628     }
629     else if(secs < 60*60)
630     {
631         text = tr("%n minute(s) ago","",secs/60);
632     }
633     else if(secs < 24*60*60)
634     {
635         text = tr("%n hour(s) ago","",secs/(60*60));
636     }
637     else
638     {
639         text = tr("%n day(s) ago","",secs/(60*60*24));
640     }
641
642     // Set icon state: spinning if catching up, tick otherwise
643     if(secs < 90*60 && count >= nTotalBlocks)
644     {
645         tooltip = tr("Up to date") + QString(".<br>") + tooltip;
646         labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
647
648         overviewPage->showOutOfSyncWarning(false);
649     }
650     else
651     {
652         tooltip = tr("Catching up...") + QString("<br>") + tooltip;
653         labelBlocksIcon->setMovie(syncIconMovie);
654         syncIconMovie->start();
655
656         overviewPage->showOutOfSyncWarning(true);
657     }
658
659     if(!text.isEmpty())
660     {
661         tooltip += QString("<br>");
662         tooltip += tr("Last received block was generated %1.").arg(text);
663     }
664
665     // Don't word-wrap this (fixed-width) tooltip
666     tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
667
668     labelBlocksIcon->setToolTip(tooltip);
669     progressBarLabel->setToolTip(tooltip);
670     progressBar->setToolTip(tooltip);
671 }
672
673 void BitcoinGUI::updateMining()
674 {
675    if(!walletModel)
676       return;
677
678     labelMiningIcon->setPixmap(QIcon(":/icons/mining_inactive").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
679
680     if (!clientModel->getNumConnections())
681     {
682         labelMiningIcon->setToolTip(tr("Wallet is offline"));
683         return;
684     }
685
686     if (walletModel->getEncryptionStatus() == WalletModel::Locked)
687     {
688         labelMiningIcon->setToolTip(tr("Wallet is locked"));
689         return;
690     }
691
692     if (clientModel->inInitialBlockDownload() || clientModel->getNumBlocksOfPeers() > clientModel->getNumBlocks())
693     {
694         labelMiningIcon->setToolTip(tr("Blockchain download is in progress"));
695         return;
696     }
697
698     float nKernelsRate = 0, nCoinDaysRate = 0;
699     walletModel->getStakeStats(nKernelsRate, nCoinDaysRate);
700
701     if (nKernelsRate > 0)
702     {
703         labelMiningIcon->setPixmap(QIcon(":/icons/mining_active").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
704
705         uint64_t nNetworkWeight = clientModel->getPoSKernelPS();
706 /*
707         double dDifficulty = clientModel->getDifficulty(true);
708         QString msg;
709
710         int nApproxTime = 4294967297 * dDifficulty / nTotalWeight;
711
712         if (nApproxTime < 60)
713             msg = tr("%n second(s)", "", nApproxTime);
714         else if (nApproxTime < 60*60)
715             msg = tr("%n minute(s)", "", nApproxTime / 60);
716         else if (nApproxTime < 24*60*60)
717             msg = tr("%n hour(s)", "", nApproxTime / 3600);
718         else
719             msg = tr("%n day(s)", "", nApproxTime / 86400);
720
721         labelMiningIcon->setToolTip(tr("Stake miner is active\nYour current stake weight is %1\nNetwork weight is %2\nAverage block generation time is %3").arg(nTotalWeight).arg(dNetworkWeight).arg(msg));
722 */
723
724         labelMiningIcon->setToolTip(QString("<nobr>")+tr("Stake miner is active<br>Kernel rate is %1 k/s<br>CD rate is %2 CD/s<br>Network weight is %3").arg(nKernelsRate).arg(nCoinDaysRate).arg(nNetworkWeight)+QString("<\nobr>"));
725     }
726     else
727         labelMiningIcon->setToolTip(tr("No suitable inputs were found"));
728 }
729
730 void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
731 {
732     // Report errors from network/worker thread
733     if(modal)
734     {
735         QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
736     } else {
737         notificator->notify(Notificator::Critical, title, message);
738     }
739 }
740
741 void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, const QString &detail)
742 {
743     QString strTitle = tr("NovaCoin") + " - ";
744     // Default to information icon
745     int nMBoxIcon = QMessageBox::Information;
746     int nNotifyIcon = Notificator::Information;
747
748
749     // Check for usage of predefined title
750     switch (style) {
751     case CClientUIInterface::MSG_ERROR:
752         strTitle += tr("Error");
753         break;
754     case CClientUIInterface::MSG_WARNING:
755         strTitle += tr("Warning");
756         break;
757     case CClientUIInterface::MSG_INFORMATION:
758         strTitle += tr("Information");
759         break;
760     default:
761         strTitle += title; // Use supplied title
762     }
763
764     // Check for error/warning icon
765     if (style & CClientUIInterface::ICON_ERROR) {
766         nMBoxIcon = QMessageBox::Critical;
767         nNotifyIcon = Notificator::Critical;
768     }
769     else if (style & CClientUIInterface::ICON_WARNING) {
770         nMBoxIcon = QMessageBox::Warning;
771         nNotifyIcon = Notificator::Warning;
772     }
773
774     // Display message
775     if (style & CClientUIInterface::MODAL) {
776         // Check for buttons, use OK as default, if none was supplied
777         QMessageBox::StandardButton buttons;
778         buttons = QMessageBox::Ok;
779
780         QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons);
781
782         if(!detail.isEmpty()) { mBox.setDetailedText(detail); }
783
784         mBox.exec();
785     }
786     else
787         notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
788 }
789
790
791 void BitcoinGUI::changeEvent(QEvent *e)
792 {
793     QMainWindow::changeEvent(e);
794 #ifndef Q_OS_MAC // Ignored on Mac
795     if(e->type() == QEvent::WindowStateChange)
796     {
797         if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray())
798         {
799             QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
800             if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
801             {
802                 QTimer::singleShot(0, this, SLOT(hide()));
803                 e->ignore();
804             }
805         }
806     }
807 #endif
808 }
809
810 void BitcoinGUI::closeEvent(QCloseEvent *event)
811 {
812     if(clientModel)
813     {
814 #ifndef Q_OS_MAC // Ignored on Mac
815         if(!clientModel->getOptionsModel()->getMinimizeOnClose())
816         {
817             qApp->quit();
818         }
819 #endif
820     }
821     // close rpcConsole in case it was open to make some space for the shutdown window
822     rpcConsole->close();
823
824     QMainWindow::closeEvent(event);
825 }
826
827 void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
828 {
829     QString strMessage =
830         tr("This transaction is over the size limit.  You can still send it for a fee of %1, "
831           "which goes to the nodes that process your transaction and helps to support the network.  "
832           "Do you want to pay the fee?").arg(
833                 BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
834     QMessageBox::StandardButton retval = QMessageBox::question(
835           this, tr("Confirm transaction fee"), strMessage,
836           QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
837     *payFee = (retval == QMessageBox::Yes);
838 }
839
840 void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
841 {
842     if(!walletModel || !clientModel)
843         return;
844     TransactionTableModel *ttm = walletModel->getTransactionTableModel();
845     qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
846                     .data(Qt::EditRole).toULongLong();
847     if(!clientModel->inInitialBlockDownload())
848     {
849         // On new transaction, make an info balloon
850         // Unless the initial block download is in progress, to prevent balloon-spam
851         QString date = ttm->index(start, TransactionTableModel::Date, parent)
852                         .data().toString();
853         QString type = ttm->index(start, TransactionTableModel::Type, parent)
854                         .data().toString();
855         QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
856                         .data().toString();
857         QIcon icon = qvariant_cast<QIcon>(ttm->index(start,
858                             TransactionTableModel::ToAddress, parent)
859                         .data(Qt::DecorationRole));
860
861         notificator->notify(Notificator::Information,
862                             (amount)<0 ? tr("Sent transaction") :
863                                          tr("Incoming transaction"),
864                               tr("Date: %1\n"
865                                  "Amount: %2\n"
866                                  "Type: %3\n"
867                                  "Address: %4\n")
868                               .arg(date)
869                               .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
870                               .arg(type)
871                               .arg(address), icon);
872     }
873 }
874
875 void BitcoinGUI::gotoOverviewPage()
876 {
877     overviewAction->setChecked(true);
878     centralWidget->setCurrentWidget(overviewPage);
879
880     exportAction->setEnabled(false);
881     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
882 }
883
884 void BitcoinGUI::gotoHistoryPage()
885 {
886     historyAction->setChecked(true);
887     centralWidget->setCurrentWidget(transactionsPage);
888
889     exportAction->setEnabled(true);
890     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
891     connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked()));
892 }
893
894 void BitcoinGUI::gotoMintingPage()
895 {
896     mintingAction->setChecked(true);
897     centralWidget->setCurrentWidget(mintingPage);
898
899     exportAction->setEnabled(true);
900     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
901     connect(exportAction, SIGNAL(triggered()), mintingView, SLOT(exportClicked()));
902 }
903
904
905 void BitcoinGUI::gotoAddressBookPage()
906 {
907     addressBookAction->setChecked(true);
908     centralWidget->setCurrentWidget(addressBookPage);
909
910     exportAction->setEnabled(true);
911     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
912     connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked()));
913 }
914
915 void BitcoinGUI::gotoReceiveCoinsPage()
916 {
917     receiveCoinsAction->setChecked(true);
918     centralWidget->setCurrentWidget(receiveCoinsPage);
919
920     exportAction->setEnabled(true);
921     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
922     connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked()));
923 }
924
925 void BitcoinGUI::gotoSendCoinsPage()
926 {
927     sendCoinsAction->setChecked(true);
928     centralWidget->setCurrentWidget(sendCoinsPage);
929
930     exportAction->setEnabled(false);
931     disconnect(exportAction, SIGNAL(triggered()), 0, 0);
932 }
933
934 void BitcoinGUI::gotoSignMessageTab(QString addr)
935 {
936     // call show() in showTab_SM()
937     signVerifyMessageDialog->showTab_SM(true);
938
939     if(!addr.isEmpty())
940         signVerifyMessageDialog->setAddress_SM(addr);
941 }
942
943 void BitcoinGUI::gotoVerifyMessageTab(QString addr)
944 {
945     // call show() in showTab_VM()
946     signVerifyMessageDialog->showTab_VM(true);
947
948     if(!addr.isEmpty())
949         signVerifyMessageDialog->setAddress_VM(addr);
950 }
951
952 void BitcoinGUI::gotoMultisigPage()
953 {
954     multisigPage->show();
955     multisigPage->setFocus();
956 }
957
958 void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
959 {
960     // Accept only URIs
961     if(event->mimeData()->hasUrls())
962         event->acceptProposedAction();
963 }
964
965 void BitcoinGUI::dropEvent(QDropEvent *event)
966 {
967     if(event->mimeData()->hasUrls())
968     {
969         int nValidUrisFound = 0;
970         QList<QUrl> uris = event->mimeData()->urls();
971         foreach(const QUrl &uri, uris)
972         {
973             if (sendCoinsPage->handleURI(uri.toString()))
974                 nValidUrisFound++;
975         }
976
977         // if valid URIs were found
978         if (nValidUrisFound)
979             gotoSendCoinsPage();
980         else
981             notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid NovaCoin address or malformed URI parameters."));
982     }
983
984     event->acceptProposedAction();
985 }
986
987 void BitcoinGUI::handleURI(QString strURI)
988 {
989     // URI has to be valid
990     if (sendCoinsPage->handleURI(strURI))
991     {
992         showNormalIfMinimized();
993         gotoSendCoinsPage();
994     }
995     else
996         notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid NovaCoin address or malformed URI parameters."));
997 }
998
999 void BitcoinGUI::setEncryptionStatus(int status)
1000 {
1001     switch(status)
1002     {
1003     case WalletModel::Unencrypted:
1004         labelEncryptionIcon->hide();
1005         encryptWalletAction->setChecked(false);
1006         changePassphraseAction->setEnabled(false);
1007         lockWalletAction->setEnabled(false);
1008         unlockWalletAction->setEnabled(false);
1009         unlockWalletMiningAction->setEnabled(false);
1010         encryptWalletAction->setEnabled(true);
1011         break;
1012     case WalletModel::Unlocked:
1013         labelEncryptionIcon->show();
1014         labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
1015         labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
1016         encryptWalletAction->setChecked(true);
1017         changePassphraseAction->setEnabled(true);
1018         encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
1019
1020         lockWalletAction->setEnabled(true);
1021         lockWalletAction->setChecked(false);
1022         unlockWalletAction->setEnabled(false);
1023         unlockWalletMiningAction->setEnabled(false);
1024
1025         if (fWalletUnlockMintOnly)
1026             unlockWalletMiningAction->setChecked(true);
1027         else
1028             unlockWalletAction->setChecked(true);
1029
1030         break;
1031     case WalletModel::Locked:
1032         labelEncryptionIcon->show();
1033         labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
1034         labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
1035         encryptWalletAction->setChecked(true);
1036         changePassphraseAction->setEnabled(true);
1037         encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
1038
1039         lockWalletAction->setChecked(true);
1040         unlockWalletAction->setChecked(false);
1041         unlockWalletMiningAction->setChecked(false);
1042
1043         lockWalletAction->setEnabled(false);
1044         unlockWalletAction->setEnabled(true);
1045         unlockWalletMiningAction->setEnabled(true);
1046         break;
1047     }
1048 }
1049
1050 void BitcoinGUI::encryptWallet(bool status)
1051 {
1052     if(!walletModel)
1053         return;
1054     AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
1055                                      AskPassphraseDialog::Decrypt, this);
1056     dlg.setModel(walletModel);
1057     dlg.exec();
1058
1059     setEncryptionStatus(walletModel->getEncryptionStatus());
1060 }
1061
1062 void BitcoinGUI::unlockWalletMining(bool status)
1063 {
1064     if(!walletModel)
1065         return;
1066
1067     // Unlock wallet when requested by wallet model
1068     if(walletModel->getEncryptionStatus() == WalletModel::Locked)
1069     {
1070         AskPassphraseDialog dlg(AskPassphraseDialog::UnlockMining, this);
1071         dlg.setModel(walletModel);
1072         dlg.exec();
1073     }
1074 }
1075
1076 void BitcoinGUI::backupWallet()
1077 {
1078 #if QT_VERSION < 0x050000
1079     QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
1080 #else
1081     QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
1082 #endif
1083     QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
1084     if(!filename.isEmpty()) {
1085         if(!walletModel->backupWallet(filename)) {
1086             QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."));
1087         }
1088     }
1089 }
1090
1091 void BitcoinGUI::dumpWallet()
1092 {
1093    if(!walletModel)
1094       return;
1095
1096    WalletModel::UnlockContext ctx(walletModel->requestUnlock());
1097    if(!ctx.isValid())
1098    {
1099        // Unlock wallet failed or was cancelled
1100        return;
1101    }
1102
1103 #if QT_VERSION < 0x050000
1104     QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
1105 #else
1106     QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
1107 #endif
1108     QString filename = QFileDialog::getSaveFileName(this, tr("Dump Wallet"), saveDir, tr("Wallet dump (*.txt)"));
1109     if(!filename.isEmpty()) {
1110         if(!walletModel->dumpWallet(filename)) {
1111             error(tr("Dump failed"),
1112                          tr("An error happened while trying to save the keys to your location.\n"
1113                             "Keys were not saved.")
1114                       ,CClientUIInterface::MSG_ERROR);
1115         }
1116         else
1117           message(tr("Dump successful"),
1118                        tr("Keys were saved to this file:\n%2")
1119                        .arg(filename)
1120                       ,CClientUIInterface::MSG_INFORMATION);
1121     }
1122 }
1123
1124 void BitcoinGUI::importWallet()
1125 {
1126    if(!walletModel)
1127       return;
1128
1129    WalletModel::UnlockContext ctx(walletModel->requestUnlock());
1130    if(!ctx.isValid())
1131    {
1132        // Unlock wallet failed or was cancelled
1133        return;
1134    }
1135
1136 #if QT_VERSION < 0x050000
1137     QString openDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
1138 #else
1139     QString openDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
1140 #endif
1141     QString filename = QFileDialog::getOpenFileName(this, tr("Import Wallet"), openDir, tr("Wallet dump (*.txt)"));
1142     if(!filename.isEmpty()) {
1143         if(!walletModel->importWallet(filename)) {
1144             error(tr("Import Failed"),
1145                          tr("An error happened while trying to import the keys.\n"
1146                             "Some or all keys from:\n %1,\n were not imported into your wallet.")
1147                          .arg(filename)
1148                       ,CClientUIInterface::MSG_ERROR);
1149         }
1150         else
1151           message(tr("Import Successful"),
1152                        tr("All keys from:\n %1,\n were imported into your wallet.")
1153                        .arg(filename)
1154                       ,CClientUIInterface::MSG_INFORMATION);
1155     }
1156 }
1157
1158
1159 void BitcoinGUI::changePassphrase()
1160 {
1161     AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
1162     dlg.setModel(walletModel);
1163     dlg.exec();
1164 }
1165
1166 void BitcoinGUI::unlockWallet()
1167 {
1168     if(!walletModel)
1169         return;
1170     // Unlock wallet when requested by wallet model
1171     if(walletModel->getEncryptionStatus() == WalletModel::Locked)
1172     {
1173         AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
1174         dlg.setModel(walletModel);
1175         dlg.exec();
1176     }
1177 }
1178
1179 void BitcoinGUI::lockWallet()
1180 {
1181     if(!walletModel)
1182         return;
1183
1184     walletModel->setWalletLocked(true);
1185 }
1186
1187 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
1188 {
1189     // activateWindow() (sometimes) helps with keyboard focus on Windows
1190     if (isHidden())
1191     {
1192         // Make sure the window is not minimized
1193         setWindowState(windowState() & (~Qt::WindowMinimized | Qt::WindowActive));
1194         // Then show it
1195         show();
1196         raise();
1197         activateWindow();
1198     }
1199     else if (isMinimized())
1200     {
1201         showNormal();
1202         raise();
1203         activateWindow();
1204     }
1205     else if (GUIUtil::isObscured(this))
1206     {
1207         raise();
1208         activateWindow();
1209         if(fToggleHidden)
1210         {
1211             Sleep(1);
1212             if (GUIUtil::isObscured(this))
1213                 hide();
1214         }
1215     }
1216     else if(fToggleHidden)
1217         hide();
1218 }
1219
1220 void BitcoinGUI::toggleHidden()
1221 {
1222     showNormalIfMinimized(true);
1223 }