1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "bitcoingui.h"
7 #include "bitcoinunits.h"
8 #include "clientmodel.h"
9 #include "guiconstants.h"
11 #include "notificator.h"
12 #include "openuridialog.h"
13 #include "optionsdialog.h"
14 #include "optionsmodel.h"
15 #include "rpcconsole.h"
16 #include "utilitydialog.h"
18 #include "walletframe.h"
19 #include "walletmodel.h"
23 #include "macdockiconhandler.h"
27 #include "ui_interface.h"
31 #include <QApplication>
33 #include <QDesktopWidget>
34 #include <QDragEnterEvent>
37 #include <QListWidget>
40 #include <QMessageBox>
42 #include <QProgressBar>
44 #include <QStackedWidget>
49 #include <QVBoxLayout>
51 #if QT_VERSION < 0x050000
53 #include <QTextDocument>
58 const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
60 BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
64 encryptWalletAction(0),
65 changePassphraseAction(0),
73 GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
75 QString windowTitle = tr("Bitcoin Core") + " - ";
77 /* if compiled with wallet support, -disablewallet can still disable the wallet */
78 bool enableWallet = !GetBoolArg("-disablewallet", false);
80 bool enableWallet = false;
84 windowTitle += tr("Wallet");
86 windowTitle += tr("Node");
92 QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
93 setWindowIcon(QIcon(":icons/bitcoin"));
95 MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
100 windowTitle += " " + tr("[testnet]");
102 QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
103 setWindowIcon(QIcon(":icons/bitcoin_testnet"));
105 MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
108 setWindowTitle(windowTitle);
110 #if defined(Q_OS_MAC) && QT_VERSION < 0x050000
111 // This property is not implemented in Qt 5. Setting it has no effect.
112 // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
113 setUnifiedTitleAndToolBarOnMac(true);
116 rpcConsole = new RPCConsole(enableWallet ? this : 0);
120 /** Create wallet frame and make it the central widget */
121 walletFrame = new WalletFrame(this);
122 setCentralWidget(walletFrame);
126 /* When compiled without wallet or -disablewallet is provided,
127 * the central widget is the rpc console.
129 setCentralWidget(rpcConsole);
132 // Accept D&D of URIs
133 setAcceptDrops(true);
135 // Create actions for the toolbar, menu bar and tray/dock icon
136 // Needs walletFrame to be initialized
137 createActions(fIsTestnet);
139 // Create application menu bar
142 // Create the toolbars
145 // Create system tray icon and notification
146 createTrayIcon(fIsTestnet);
151 // Status bar notification icons
152 QFrame *frameBlocks = new QFrame();
153 frameBlocks->setContentsMargins(0,0,0,0);
154 frameBlocks->setMinimumWidth(56);
155 frameBlocks->setMaximumWidth(56);
156 QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
157 frameBlocksLayout->setContentsMargins(3,0,3,0);
158 frameBlocksLayout->setSpacing(3);
159 labelEncryptionIcon = new QLabel();
160 labelConnectionsIcon = new QLabel();
161 labelBlocksIcon = new QLabel();
162 frameBlocksLayout->addStretch();
163 frameBlocksLayout->addWidget(labelEncryptionIcon);
164 frameBlocksLayout->addStretch();
165 frameBlocksLayout->addWidget(labelConnectionsIcon);
166 frameBlocksLayout->addStretch();
167 frameBlocksLayout->addWidget(labelBlocksIcon);
168 frameBlocksLayout->addStretch();
170 // Progress bar and label for blocks download
171 progressBarLabel = new QLabel();
172 progressBarLabel->setVisible(false);
173 progressBar = new QProgressBar();
174 progressBar->setAlignment(Qt::AlignCenter);
175 progressBar->setVisible(false);
177 // Override style sheet for progress bar for styles that have a segmented progress bar,
178 // as they make the text unreadable (workaround for issue #1071)
179 // See https://qt-project.org/doc/qt-4.8/gallery.html
180 QString curStyle = QApplication::style()->metaObject()->className();
181 if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
183 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 statusBar()->addWidget(progressBarLabel);
187 statusBar()->addWidget(progressBar);
188 statusBar()->addPermanentWidget(frameBlocks);
190 connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
192 // prevents an oben debug window from becoming stuck/unusable on client shutdown
193 connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide()));
195 // Install event filter to be able to catch status tip events (QEvent::StatusTip)
196 this->installEventFilter(this);
198 // Initially wallet actions should be disabled
199 setWalletActionsEnabled(false);
201 // Subscribe to notifications from core
202 subscribeToCoreSignals();
205 BitcoinGUI::~BitcoinGUI()
207 // Unsubscribe from notifications from core
208 unsubscribeFromCoreSignals();
210 GUIUtil::saveWindowGeometry("nWindow", this);
211 if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
215 MacDockIconHandler::instance()->setMainWindow(NULL);
219 void BitcoinGUI::createActions(bool fIsTestnet)
221 QActionGroup *tabGroup = new QActionGroup(this);
223 overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
224 overviewAction->setStatusTip(tr("Show general overview of wallet"));
225 overviewAction->setToolTip(overviewAction->statusTip());
226 overviewAction->setCheckable(true);
227 overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
228 tabGroup->addAction(overviewAction);
230 sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send"), this);
231 sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
232 sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
233 sendCoinsAction->setCheckable(true);
234 sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
235 tabGroup->addAction(sendCoinsAction);
237 receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
238 receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
239 receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
240 receiveCoinsAction->setCheckable(true);
241 receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
242 tabGroup->addAction(receiveCoinsAction);
244 historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
245 historyAction->setStatusTip(tr("Browse transaction history"));
246 historyAction->setToolTip(historyAction->statusTip());
247 historyAction->setCheckable(true);
248 historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
249 tabGroup->addAction(historyAction);
251 // These showNormalIfMinimized are needed because Send Coins and Receive Coins
252 // can be triggered from the tray menu, and need to show the GUI to be useful.
253 connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
254 connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
255 connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
256 connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
257 connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
258 connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
259 connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
260 connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
262 quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
263 quitAction->setStatusTip(tr("Quit application"));
264 quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
265 quitAction->setMenuRole(QAction::QuitRole);
267 aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin Core"), this);
269 aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin Core"), this);
270 aboutAction->setStatusTip(tr("Show information about Bitcoin"));
271 aboutAction->setMenuRole(QAction::AboutRole);
272 #if QT_VERSION < 0x050000
273 aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
275 aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
277 aboutQtAction->setStatusTip(tr("Show information about Qt"));
278 aboutQtAction->setMenuRole(QAction::AboutQtRole);
279 optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
280 optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
281 optionsAction->setMenuRole(QAction::PreferencesRole);
283 toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
285 toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this);
286 toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
288 encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
289 encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
290 encryptWalletAction->setCheckable(true);
291 backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
292 backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
293 changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
294 changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
295 signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
296 signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
297 verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
298 verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
300 openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this);
301 openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
303 usedSendingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
304 usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
305 usedReceivingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
306 usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
308 openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this);
309 openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
311 showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line options"), this);
312 showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options"));
314 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
315 connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
316 connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
317 connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
318 connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
319 connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked()));
323 connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool)));
324 connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet()));
325 connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase()));
326 connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
327 connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
328 connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses()));
329 connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses()));
330 connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked()));
335 void BitcoinGUI::createMenuBar()
338 // Create a decoupled menu bar on Mac which stays even if the window is closed
339 appMenuBar = new QMenuBar();
341 // Get the main window's menu bar on other platforms
342 appMenuBar = menuBar();
345 // Configure the menus
346 QMenu *file = appMenuBar->addMenu(tr("&File"));
349 file->addAction(openAction);
350 file->addAction(backupWalletAction);
351 file->addAction(signMessageAction);
352 file->addAction(verifyMessageAction);
353 file->addSeparator();
354 file->addAction(usedSendingAddressesAction);
355 file->addAction(usedReceivingAddressesAction);
356 file->addSeparator();
358 file->addAction(quitAction);
360 QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
363 settings->addAction(encryptWalletAction);
364 settings->addAction(changePassphraseAction);
365 settings->addSeparator();
367 settings->addAction(optionsAction);
369 QMenu *help = appMenuBar->addMenu(tr("&Help"));
372 help->addAction(openRPCConsoleAction);
374 help->addAction(showHelpMessageAction);
375 help->addSeparator();
376 help->addAction(aboutAction);
377 help->addAction(aboutQtAction);
380 void BitcoinGUI::createToolBars()
384 QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
385 toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
386 toolbar->addAction(overviewAction);
387 toolbar->addAction(sendCoinsAction);
388 toolbar->addAction(receiveCoinsAction);
389 toolbar->addAction(historyAction);
390 overviewAction->setChecked(true);
394 void BitcoinGUI::setClientModel(ClientModel *clientModel)
396 this->clientModel = clientModel;
399 // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
400 // while the client has not yet fully loaded
401 createTrayIconMenu();
403 // Keep up to date with client
404 setNumConnections(clientModel->getNumConnections());
405 connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
407 setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
408 connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
410 // Receive and report messages from client model
411 connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
413 rpcConsole->setClientModel(clientModel);
417 walletFrame->setClientModel(clientModel);
424 bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel)
428 setWalletActionsEnabled(true);
429 return walletFrame->addWallet(name, walletModel);
432 bool BitcoinGUI::setCurrentWallet(const QString& name)
436 return walletFrame->setCurrentWallet(name);
439 void BitcoinGUI::removeAllWallets()
443 setWalletActionsEnabled(false);
444 walletFrame->removeAllWallets();
448 void BitcoinGUI::setWalletActionsEnabled(bool enabled)
450 overviewAction->setEnabled(enabled);
451 sendCoinsAction->setEnabled(enabled);
452 receiveCoinsAction->setEnabled(enabled);
453 historyAction->setEnabled(enabled);
454 encryptWalletAction->setEnabled(enabled);
455 backupWalletAction->setEnabled(enabled);
456 changePassphraseAction->setEnabled(enabled);
457 signMessageAction->setEnabled(enabled);
458 verifyMessageAction->setEnabled(enabled);
459 usedSendingAddressesAction->setEnabled(enabled);
460 usedReceivingAddressesAction->setEnabled(enabled);
461 openAction->setEnabled(enabled);
464 void BitcoinGUI::createTrayIcon(bool fIsTestnet)
467 trayIcon = new QSystemTrayIcon(this);
471 trayIcon->setToolTip(tr("Bitcoin client"));
472 trayIcon->setIcon(QIcon(":/icons/toolbar"));
476 trayIcon->setToolTip(tr("Bitcoin client") + " " + tr("[testnet]"));
477 trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
483 notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
486 void BitcoinGUI::createTrayIconMenu()
490 // return if trayIcon is unset (only on non-Mac OSes)
494 trayIconMenu = new QMenu(this);
495 trayIcon->setContextMenu(trayIconMenu);
497 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
498 this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
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();
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(receiveCoinsAction);
511 trayIconMenu->addSeparator();
512 trayIconMenu->addAction(signMessageAction);
513 trayIconMenu->addAction(verifyMessageAction);
514 trayIconMenu->addSeparator();
515 trayIconMenu->addAction(optionsAction);
516 trayIconMenu->addAction(openRPCConsoleAction);
517 #ifndef Q_OS_MAC // This is built-in on Mac
518 trayIconMenu->addSeparator();
519 trayIconMenu->addAction(quitAction);
524 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
526 if(reason == QSystemTrayIcon::Trigger)
528 // Click on system tray icon triggers show/hide of the main window
529 toggleHideAction->trigger();
534 void BitcoinGUI::optionsClicked()
536 if(!clientModel || !clientModel->getOptionsModel())
539 OptionsDialog dlg(this);
540 dlg.setModel(clientModel->getOptionsModel());
544 void BitcoinGUI::aboutClicked()
549 AboutDialog dlg(this);
550 dlg.setModel(clientModel);
554 void BitcoinGUI::showHelpMessageClicked()
556 HelpMessageDialog *help = new HelpMessageDialog(this);
557 help->setAttribute(Qt::WA_DeleteOnClose);
562 void BitcoinGUI::openClicked()
564 OpenURIDialog dlg(this);
567 emit receivedURI(dlg.getURI());
571 void BitcoinGUI::gotoOverviewPage()
573 overviewAction->setChecked(true);
574 if (walletFrame) walletFrame->gotoOverviewPage();
577 void BitcoinGUI::gotoHistoryPage()
579 historyAction->setChecked(true);
580 if (walletFrame) walletFrame->gotoHistoryPage();
583 void BitcoinGUI::gotoReceiveCoinsPage()
585 receiveCoinsAction->setChecked(true);
586 if (walletFrame) walletFrame->gotoReceiveCoinsPage();
589 void BitcoinGUI::gotoSendCoinsPage(QString addr)
591 sendCoinsAction->setChecked(true);
592 if (walletFrame) walletFrame->gotoSendCoinsPage(addr);
595 void BitcoinGUI::gotoSignMessageTab(QString addr)
597 if (walletFrame) walletFrame->gotoSignMessageTab(addr);
600 void BitcoinGUI::gotoVerifyMessageTab(QString addr)
602 if (walletFrame) walletFrame->gotoVerifyMessageTab(addr);
606 void BitcoinGUI::setNumConnections(int count)
611 case 0: icon = ":/icons/connect_0"; break;
612 case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
613 case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
614 case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
615 default: icon = ":/icons/connect_4"; break;
617 labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
618 labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
621 void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
623 // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text)
624 statusBar()->clearMessage();
626 // Acquire current block source
627 enum BlockSource blockSource = clientModel->getBlockSource();
628 switch (blockSource) {
629 case BLOCK_SOURCE_NETWORK:
630 progressBarLabel->setText(tr("Synchronizing with network..."));
632 case BLOCK_SOURCE_DISK:
633 progressBarLabel->setText(tr("Importing blocks from disk..."));
635 case BLOCK_SOURCE_REINDEX:
636 progressBarLabel->setText(tr("Reindexing blocks on disk..."));
638 case BLOCK_SOURCE_NONE:
639 // Case: not Importing, not Reindexing and no network connection
640 progressBarLabel->setText(tr("No block source available..."));
646 QDateTime lastBlockDate = clientModel->getLastBlockDate();
647 QDateTime currentDate = QDateTime::currentDateTime();
648 int secs = lastBlockDate.secsTo(currentDate);
650 if(count < nTotalBlocks)
652 tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks);
656 tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
659 // Set icon state: spinning if catching up, tick otherwise
660 if(secs < 90*60 && count >= nTotalBlocks)
662 tooltip = tr("Up to date") + QString(".<br>") + tooltip;
663 labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
667 walletFrame->showOutOfSyncWarning(false);
670 progressBarLabel->setVisible(false);
671 progressBar->setVisible(false);
675 // Represent time from last generated block in human readable text
676 QString timeBehindText;
679 timeBehindText = tr("%n hour(s)","",secs/(60*60));
681 else if(secs < 14*24*60*60)
683 timeBehindText = tr("%n day(s)","",secs/(24*60*60));
687 timeBehindText = tr("%n week(s)","",secs/(7*24*60*60));
690 progressBarLabel->setVisible(true);
691 progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
692 progressBar->setMaximum(1000000000);
693 progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5);
694 progressBar->setVisible(true);
696 tooltip = tr("Catching up...") + QString("<br>") + tooltip;
697 if(count != prevBlocks)
699 labelBlocksIcon->setPixmap(QIcon(QString(
700 ":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')))
701 .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
702 spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES;
708 walletFrame->showOutOfSyncWarning(true);
711 tooltip += QString("<br>");
712 tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
713 tooltip += QString("<br>");
714 tooltip += tr("Transactions after this will not yet be visible.");
717 // Don't word-wrap this (fixed-width) tooltip
718 tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
720 labelBlocksIcon->setToolTip(tooltip);
721 progressBarLabel->setToolTip(tooltip);
722 progressBar->setToolTip(tooltip);
725 void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
727 QString strTitle = tr("Bitcoin"); // default title
728 // Default to information icon
729 int nMBoxIcon = QMessageBox::Information;
730 int nNotifyIcon = Notificator::Information;
734 // Prefer supplied title over style based title
735 if (!title.isEmpty()) {
740 case CClientUIInterface::MSG_ERROR:
741 msgType = tr("Error");
743 case CClientUIInterface::MSG_WARNING:
744 msgType = tr("Warning");
746 case CClientUIInterface::MSG_INFORMATION:
747 msgType = tr("Information");
753 // Append title to "Bitcoin - "
754 if (!msgType.isEmpty())
755 strTitle += " - " + msgType;
757 // Check for error/warning icon
758 if (style & CClientUIInterface::ICON_ERROR) {
759 nMBoxIcon = QMessageBox::Critical;
760 nNotifyIcon = Notificator::Critical;
762 else if (style & CClientUIInterface::ICON_WARNING) {
763 nMBoxIcon = QMessageBox::Warning;
764 nNotifyIcon = Notificator::Warning;
768 if (style & CClientUIInterface::MODAL) {
769 // Check for buttons, use OK as default, if none was supplied
770 QMessageBox::StandardButton buttons;
771 if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK)))
772 buttons = QMessageBox::Ok;
774 // Ensure we get users attention, but only if main window is visible
775 // as we don't want to pop up the main window for messages that happen before
776 // initialization is finished.
777 if(!(style & CClientUIInterface::NOSHOWGUI))
778 showNormalIfMinimized();
779 QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
782 *ret = r == QMessageBox::Ok;
785 notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
788 void BitcoinGUI::changeEvent(QEvent *e)
790 QMainWindow::changeEvent(e);
791 #ifndef Q_OS_MAC // Ignored on Mac
792 if(e->type() == QEvent::WindowStateChange)
794 if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray())
796 QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
797 if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
799 QTimer::singleShot(0, this, SLOT(hide()));
807 void BitcoinGUI::closeEvent(QCloseEvent *event)
811 #ifndef Q_OS_MAC // Ignored on Mac
812 if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
813 !clientModel->getOptionsModel()->getMinimizeOnClose())
815 QApplication::quit();
819 QMainWindow::closeEvent(event);
823 void BitcoinGUI::incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address)
825 // On new transaction, make an info balloon
826 message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
832 .arg(BitcoinUnits::formatWithUnit(unit, amount, true))
834 .arg(address), CClientUIInterface::MSG_INFORMATION);
838 void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
841 if(event->mimeData()->hasUrls())
842 event->acceptProposedAction();
845 void BitcoinGUI::dropEvent(QDropEvent *event)
847 if(event->mimeData()->hasUrls())
849 foreach(const QUrl &uri, event->mimeData()->urls())
851 emit receivedURI(uri.toString());
854 event->acceptProposedAction();
857 bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
859 // Catch status tip events
860 if (event->type() == QEvent::StatusTip)
862 // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
863 if (progressBarLabel->isVisible() || progressBar->isVisible())
866 return QMainWindow::eventFilter(object, event);
870 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
872 // URI has to be valid
873 if (walletFrame && walletFrame->handlePaymentRequest(recipient))
875 showNormalIfMinimized();
883 void BitcoinGUI::setEncryptionStatus(int status)
887 case WalletModel::Unencrypted:
888 labelEncryptionIcon->hide();
889 encryptWalletAction->setChecked(false);
890 changePassphraseAction->setEnabled(false);
891 encryptWalletAction->setEnabled(true);
893 case WalletModel::Unlocked:
894 labelEncryptionIcon->show();
895 labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
896 labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
897 encryptWalletAction->setChecked(true);
898 changePassphraseAction->setEnabled(true);
899 encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
901 case WalletModel::Locked:
902 labelEncryptionIcon->show();
903 labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
904 labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
905 encryptWalletAction->setChecked(true);
906 changePassphraseAction->setEnabled(true);
907 encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
913 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
915 // activateWindow() (sometimes) helps with keyboard focus on Windows
921 else if (isMinimized())
926 else if (GUIUtil::isObscured(this))
931 else if(fToggleHidden)
935 void BitcoinGUI::toggleHidden()
937 showNormalIfMinimized(true);
940 void BitcoinGUI::detectShutdown()
942 if (ShutdownRequested())
950 static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
952 bool modal = (style & CClientUIInterface::MODAL);
954 // In case of modal message, use blocking connection to wait for user to click a button
955 QMetaObject::invokeMethod(gui, "message",
956 modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
957 Q_ARG(QString, QString::fromStdString(caption)),
958 Q_ARG(QString, QString::fromStdString(message)),
959 Q_ARG(unsigned int, style),
964 void BitcoinGUI::subscribeToCoreSignals()
966 // Connect signals to client
967 uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
970 void BitcoinGUI::unsubscribeFromCoreSignals()
972 // Disconnect signals from client
973 uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));