1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #if defined(HAVE_CONFIG_H)
6 #include "config/bitcoin-config.h"
9 #include "bitcoingui.h"
11 #include "bitcoinunits.h"
12 #include "clientmodel.h"
13 #include "guiconstants.h"
15 #include "modaloverlay.h"
16 #include "networkstyle.h"
17 #include "notificator.h"
18 #include "openuridialog.h"
19 #include "optionsdialog.h"
20 #include "optionsmodel.h"
21 #include "platformstyle.h"
22 #include "rpcconsole.h"
23 #include "utilitydialog.h"
26 #include "walletframe.h"
27 #include "walletmodel.h"
28 #endif // ENABLE_WALLET
31 #include "macdockiconhandler.h"
34 #include "chainparams.h"
36 #include "ui_interface.h"
42 #include <QApplication>
44 #include <QDesktopWidget>
45 #include <QDragEnterEvent>
46 #include <QListWidget>
48 #include <QMessageBox>
50 #include <QProgressDialog>
53 #include <QStackedWidget>
58 #include <QVBoxLayout>
60 #if QT_VERSION < 0x050000
61 #include <QTextDocument>
67 const std::string
BitcoinGUI::DEFAULT_UIPLATFORM
=
70 #elif defined(Q_OS_WIN)
77 /** Display name for default wallet name. Uses tilde to avoid name
78 * collisions in the future with additional wallets */
79 const QString
BitcoinGUI::DEFAULT_WALLET
= "~Default";
81 BitcoinGUI::BitcoinGUI(const PlatformStyle
*_platformStyle
, const NetworkStyle
*networkStyle
, QWidget
*parent
) :
86 unitDisplayControl(0),
87 labelWalletEncryptionIcon(0),
88 labelWalletHDStatusIcon(0),
89 connectionsControl(0),
99 sendCoinsMenuAction(0),
100 usedSendingAddressesAction(0),
101 usedReceivingAddressesAction(0),
102 signMessageAction(0),
103 verifyMessageAction(0),
105 receiveCoinsAction(0),
106 receiveCoinsMenuAction(0),
109 encryptWalletAction(0),
110 backupWalletAction(0),
111 changePassphraseAction(0),
113 openRPCConsoleAction(0),
115 showHelpMessageAction(0),
120 helpMessageDialog(0),
124 platformStyle(_platformStyle
)
126 GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
128 QString windowTitle
= tr(PACKAGE_NAME
) + " - ";
130 enableWallet
= WalletModel::isWalletEnabled();
131 #endif // ENABLE_WALLET
134 windowTitle
+= tr("Wallet");
136 windowTitle
+= tr("Node");
138 windowTitle
+= " " + networkStyle
->getTitleAddText();
140 QApplication::setWindowIcon(networkStyle
->getTrayAndWindowIcon());
141 setWindowIcon(networkStyle
->getTrayAndWindowIcon());
143 MacDockIconHandler::instance()->setIcon(networkStyle
->getAppIcon());
145 setWindowTitle(windowTitle
);
147 #if defined(Q_OS_MAC) && QT_VERSION < 0x050000
148 // This property is not implemented in Qt 5. Setting it has no effect.
149 // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
150 setUnifiedTitleAndToolBarOnMac(true);
153 rpcConsole
= new RPCConsole(_platformStyle
, 0);
154 helpMessageDialog
= new HelpMessageDialog(this, false);
158 /** Create wallet frame and make it the central widget */
159 walletFrame
= new WalletFrame(_platformStyle
, this);
160 setCentralWidget(walletFrame
);
162 #endif // ENABLE_WALLET
164 /* When compiled without wallet or -disablewallet is provided,
165 * the central widget is the rpc console.
167 setCentralWidget(rpcConsole
);
170 // Accept D&D of URIs
171 setAcceptDrops(true);
173 // Create actions for the toolbar, menu bar and tray/dock icon
174 // Needs walletFrame to be initialized
177 // Create application menu bar
180 // Create the toolbars
183 // Create system tray icon and notification
184 createTrayIcon(networkStyle
);
189 // Disable size grip because it looks ugly and nobody needs it
190 statusBar()->setSizeGripEnabled(false);
192 // Status bar notification icons
193 QFrame
*frameBlocks
= new QFrame();
194 frameBlocks
->setContentsMargins(0,0,0,0);
195 frameBlocks
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Preferred
);
196 QHBoxLayout
*frameBlocksLayout
= new QHBoxLayout(frameBlocks
);
197 frameBlocksLayout
->setContentsMargins(3,0,3,0);
198 frameBlocksLayout
->setSpacing(3);
199 unitDisplayControl
= new UnitDisplayStatusBarControl(platformStyle
);
200 labelWalletEncryptionIcon
= new QLabel();
201 labelWalletHDStatusIcon
= new QLabel();
202 connectionsControl
= new GUIUtil::ClickableLabel();
203 labelBlocksIcon
= new GUIUtil::ClickableLabel();
206 frameBlocksLayout
->addStretch();
207 frameBlocksLayout
->addWidget(unitDisplayControl
);
208 frameBlocksLayout
->addStretch();
209 frameBlocksLayout
->addWidget(labelWalletEncryptionIcon
);
210 frameBlocksLayout
->addWidget(labelWalletHDStatusIcon
);
212 frameBlocksLayout
->addStretch();
213 frameBlocksLayout
->addWidget(connectionsControl
);
214 frameBlocksLayout
->addStretch();
215 frameBlocksLayout
->addWidget(labelBlocksIcon
);
216 frameBlocksLayout
->addStretch();
218 // Progress bar and label for blocks download
219 progressBarLabel
= new QLabel();
220 progressBarLabel
->setVisible(false);
221 progressBar
= new GUIUtil::ProgressBar();
222 progressBar
->setAlignment(Qt::AlignCenter
);
223 progressBar
->setVisible(false);
225 // Override style sheet for progress bar for styles that have a segmented progress bar,
226 // as they make the text unreadable (workaround for issue #1071)
227 // See https://qt-project.org/doc/qt-4.8/gallery.html
228 QString curStyle
= QApplication::style()->metaObject()->className();
229 if(curStyle
== "QWindowsStyle" || curStyle
== "QWindowsXPStyle")
231 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; }");
234 statusBar()->addWidget(progressBarLabel
);
235 statusBar()->addWidget(progressBar
);
236 statusBar()->addPermanentWidget(frameBlocks
);
238 // Install event filter to be able to catch status tip events (QEvent::StatusTip)
239 this->installEventFilter(this);
241 // Initially wallet actions should be disabled
242 setWalletActionsEnabled(false);
244 // Subscribe to notifications from core
245 subscribeToCoreSignals();
247 connect(connectionsControl
, SIGNAL(clicked(QPoint
)), this, SLOT(toggleNetworkActive()));
249 modalOverlay
= new ModalOverlay(this->centralWidget());
252 connect(walletFrame
, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay()));
253 connect(labelBlocksIcon
, SIGNAL(clicked(QPoint
)), this, SLOT(showModalOverlay()));
254 connect(progressBar
, SIGNAL(clicked(QPoint
)), this, SLOT(showModalOverlay()));
259 BitcoinGUI::~BitcoinGUI()
261 // Unsubscribe from notifications from core
262 unsubscribeFromCoreSignals();
264 GUIUtil::saveWindowGeometry("nWindow", this);
265 if(trayIcon
) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
269 MacDockIconHandler::cleanup();
275 void BitcoinGUI::createActions()
277 QActionGroup
*tabGroup
= new QActionGroup(this);
279 overviewAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
280 overviewAction
->setStatusTip(tr("Show general overview of wallet"));
281 overviewAction
->setToolTip(overviewAction
->statusTip());
282 overviewAction
->setCheckable(true);
283 overviewAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_1
));
284 tabGroup
->addAction(overviewAction
);
286 sendCoinsAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/send"), tr("&Send"), this);
287 sendCoinsAction
->setStatusTip(tr("Send coins to a Bitcoin address"));
288 sendCoinsAction
->setToolTip(sendCoinsAction
->statusTip());
289 sendCoinsAction
->setCheckable(true);
290 sendCoinsAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_2
));
291 tabGroup
->addAction(sendCoinsAction
);
293 sendCoinsMenuAction
= new QAction(platformStyle
->TextColorIcon(":/icons/send"), sendCoinsAction
->text(), this);
294 sendCoinsMenuAction
->setStatusTip(sendCoinsAction
->statusTip());
295 sendCoinsMenuAction
->setToolTip(sendCoinsMenuAction
->statusTip());
297 receiveCoinsAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
298 receiveCoinsAction
->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
299 receiveCoinsAction
->setToolTip(receiveCoinsAction
->statusTip());
300 receiveCoinsAction
->setCheckable(true);
301 receiveCoinsAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_3
));
302 tabGroup
->addAction(receiveCoinsAction
);
304 receiveCoinsMenuAction
= new QAction(platformStyle
->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction
->text(), this);
305 receiveCoinsMenuAction
->setStatusTip(receiveCoinsAction
->statusTip());
306 receiveCoinsMenuAction
->setToolTip(receiveCoinsMenuAction
->statusTip());
308 historyAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
309 historyAction
->setStatusTip(tr("Browse transaction history"));
310 historyAction
->setToolTip(historyAction
->statusTip());
311 historyAction
->setCheckable(true);
312 historyAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_4
));
313 tabGroup
->addAction(historyAction
);
316 // These showNormalIfMinimized are needed because Send Coins and Receive Coins
317 // can be triggered from the tray menu, and need to show the GUI to be useful.
318 connect(overviewAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
319 connect(overviewAction
, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
320 connect(sendCoinsAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
321 connect(sendCoinsAction
, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
322 connect(sendCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
323 connect(sendCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
324 connect(receiveCoinsAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
325 connect(receiveCoinsAction
, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
326 connect(receiveCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
327 connect(receiveCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
328 connect(historyAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
329 connect(historyAction
, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
330 #endif // ENABLE_WALLET
332 quitAction
= new QAction(platformStyle
->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
333 quitAction
->setStatusTip(tr("Quit application"));
334 quitAction
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_Q
));
335 quitAction
->setMenuRole(QAction::QuitRole
);
336 aboutAction
= new QAction(platformStyle
->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME
)), this);
337 aboutAction
->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME
)));
338 aboutAction
->setMenuRole(QAction::AboutRole
);
339 aboutAction
->setEnabled(false);
340 aboutQtAction
= new QAction(platformStyle
->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
341 aboutQtAction
->setStatusTip(tr("Show information about Qt"));
342 aboutQtAction
->setMenuRole(QAction::AboutQtRole
);
343 optionsAction
= new QAction(platformStyle
->TextColorIcon(":/icons/options"), tr("&Options..."), this);
344 optionsAction
->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME
)));
345 optionsAction
->setMenuRole(QAction::PreferencesRole
);
346 optionsAction
->setEnabled(false);
347 toggleHideAction
= new QAction(platformStyle
->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
348 toggleHideAction
->setStatusTip(tr("Show or hide the main Window"));
350 encryptWalletAction
= new QAction(platformStyle
->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
351 encryptWalletAction
->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
352 encryptWalletAction
->setCheckable(true);
353 backupWalletAction
= new QAction(platformStyle
->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
354 backupWalletAction
->setStatusTip(tr("Backup wallet to another location"));
355 changePassphraseAction
= new QAction(platformStyle
->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
356 changePassphraseAction
->setStatusTip(tr("Change the passphrase used for wallet encryption"));
357 signMessageAction
= new QAction(platformStyle
->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
358 signMessageAction
->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
359 verifyMessageAction
= new QAction(platformStyle
->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
360 verifyMessageAction
->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
362 openRPCConsoleAction
= new QAction(platformStyle
->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
363 openRPCConsoleAction
->setStatusTip(tr("Open debugging and diagnostic console"));
364 // initially disable the debug window menu item
365 openRPCConsoleAction
->setEnabled(false);
367 usedSendingAddressesAction
= new QAction(platformStyle
->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
368 usedSendingAddressesAction
->setStatusTip(tr("Show the list of used sending addresses and labels"));
369 usedReceivingAddressesAction
= new QAction(platformStyle
->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
370 usedReceivingAddressesAction
->setStatusTip(tr("Show the list of used receiving addresses and labels"));
372 openAction
= new QAction(platformStyle
->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
373 openAction
->setStatusTip(tr("Open a bitcoin: URI or payment request"));
375 showHelpMessageAction
= new QAction(platformStyle
->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
376 showHelpMessageAction
->setMenuRole(QAction::NoRole
);
377 showHelpMessageAction
->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME
)));
379 connect(quitAction
, SIGNAL(triggered()), qApp
, SLOT(quit()));
380 connect(aboutAction
, SIGNAL(triggered()), this, SLOT(aboutClicked()));
381 connect(aboutQtAction
, SIGNAL(triggered()), qApp
, SLOT(aboutQt()));
382 connect(optionsAction
, SIGNAL(triggered()), this, SLOT(optionsClicked()));
383 connect(toggleHideAction
, SIGNAL(triggered()), this, SLOT(toggleHidden()));
384 connect(showHelpMessageAction
, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked()));
385 connect(openRPCConsoleAction
, SIGNAL(triggered()), this, SLOT(showDebugWindow()));
386 // prevents an open debug window from becoming stuck/unusable on client shutdown
387 connect(quitAction
, SIGNAL(triggered()), rpcConsole
, SLOT(hide()));
392 connect(encryptWalletAction
, SIGNAL(triggered(bool)), walletFrame
, SLOT(encryptWallet(bool)));
393 connect(backupWalletAction
, SIGNAL(triggered()), walletFrame
, SLOT(backupWallet()));
394 connect(changePassphraseAction
, SIGNAL(triggered()), walletFrame
, SLOT(changePassphrase()));
395 connect(signMessageAction
, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
396 connect(verifyMessageAction
, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
397 connect(usedSendingAddressesAction
, SIGNAL(triggered()), walletFrame
, SLOT(usedSendingAddresses()));
398 connect(usedReceivingAddressesAction
, SIGNAL(triggered()), walletFrame
, SLOT(usedReceivingAddresses()));
399 connect(openAction
, SIGNAL(triggered()), this, SLOT(openClicked()));
401 #endif // ENABLE_WALLET
403 new QShortcut(QKeySequence(Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_C
), this, SLOT(showDebugWindowActivateConsole()));
404 new QShortcut(QKeySequence(Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_D
), this, SLOT(showDebugWindow()));
407 void BitcoinGUI::createMenuBar()
410 // Create a decoupled menu bar on Mac which stays even if the window is closed
411 appMenuBar
= new QMenuBar();
413 // Get the main window's menu bar on other platforms
414 appMenuBar
= menuBar();
417 // Configure the menus
418 QMenu
*file
= appMenuBar
->addMenu(tr("&File"));
421 file
->addAction(openAction
);
422 file
->addAction(backupWalletAction
);
423 file
->addAction(signMessageAction
);
424 file
->addAction(verifyMessageAction
);
425 file
->addSeparator();
426 file
->addAction(usedSendingAddressesAction
);
427 file
->addAction(usedReceivingAddressesAction
);
428 file
->addSeparator();
430 file
->addAction(quitAction
);
432 QMenu
*settings
= appMenuBar
->addMenu(tr("&Settings"));
435 settings
->addAction(encryptWalletAction
);
436 settings
->addAction(changePassphraseAction
);
437 settings
->addSeparator();
439 settings
->addAction(optionsAction
);
441 QMenu
*help
= appMenuBar
->addMenu(tr("&Help"));
444 help
->addAction(openRPCConsoleAction
);
446 help
->addAction(showHelpMessageAction
);
447 help
->addSeparator();
448 help
->addAction(aboutAction
);
449 help
->addAction(aboutQtAction
);
452 void BitcoinGUI::createToolBars()
456 QToolBar
*toolbar
= addToolBar(tr("Tabs toolbar"));
457 toolbar
->setMovable(false);
458 toolbar
->setToolButtonStyle(Qt::ToolButtonTextBesideIcon
);
459 toolbar
->addAction(overviewAction
);
460 toolbar
->addAction(sendCoinsAction
);
461 toolbar
->addAction(receiveCoinsAction
);
462 toolbar
->addAction(historyAction
);
463 overviewAction
->setChecked(true);
467 void BitcoinGUI::setClientModel(ClientModel
*_clientModel
)
469 this->clientModel
= _clientModel
;
472 // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
473 // while the client has not yet fully loaded
474 createTrayIconMenu();
476 // Keep up to date with client
477 updateNetworkState();
478 connect(_clientModel
, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
479 connect(_clientModel
, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
481 setNumBlocks(_clientModel
->getNumBlocks(), _clientModel
->getLastBlockDate(), _clientModel
->getVerificationProgress(NULL
), false);
482 connect(_clientModel
, SIGNAL(numBlocksChanged(int,QDateTime
,double,bool)), this, SLOT(setNumBlocks(int,QDateTime
,double,bool)));
484 // Receive and report messages from client model
485 connect(_clientModel
, SIGNAL(message(QString
,QString
,unsigned int)), this, SLOT(message(QString
,QString
,unsigned int)));
487 // Show progress dialog
488 connect(_clientModel
, SIGNAL(showProgress(QString
,int)), this, SLOT(showProgress(QString
,int)));
490 rpcConsole
->setClientModel(_clientModel
);
494 walletFrame
->setClientModel(_clientModel
);
496 #endif // ENABLE_WALLET
497 unitDisplayControl
->setOptionsModel(_clientModel
->getOptionsModel());
499 OptionsModel
* optionsModel
= _clientModel
->getOptionsModel();
502 // be aware of the tray icon disable state change reported by the OptionsModel object.
503 connect(optionsModel
,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
505 // initialize the disable state of the tray icon with the current value in the model.
506 setTrayIconVisible(optionsModel
->getHideTrayIcon());
509 modalOverlay
->setKnownBestHeight(clientModel
->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel
->getHeaderTipTime()));
511 // Disable possibility to show main window via action
512 toggleHideAction
->setEnabled(false);
515 // Disable context menu on tray icon
516 trayIconMenu
->clear();
518 // Propagate cleared model to child objects
519 rpcConsole
->setClientModel(nullptr);
523 walletFrame
->setClientModel(nullptr);
525 #endif // ENABLE_WALLET
526 unitDisplayControl
->setOptionsModel(nullptr);
531 bool BitcoinGUI::addWallet(const QString
& name
, WalletModel
*walletModel
)
535 setWalletActionsEnabled(true);
536 return walletFrame
->addWallet(name
, walletModel
);
539 bool BitcoinGUI::setCurrentWallet(const QString
& name
)
543 return walletFrame
->setCurrentWallet(name
);
546 void BitcoinGUI::removeAllWallets()
550 setWalletActionsEnabled(false);
551 walletFrame
->removeAllWallets();
553 #endif // ENABLE_WALLET
555 void BitcoinGUI::setWalletActionsEnabled(bool enabled
)
557 overviewAction
->setEnabled(enabled
);
558 sendCoinsAction
->setEnabled(enabled
);
559 sendCoinsMenuAction
->setEnabled(enabled
);
560 receiveCoinsAction
->setEnabled(enabled
);
561 receiveCoinsMenuAction
->setEnabled(enabled
);
562 historyAction
->setEnabled(enabled
);
563 encryptWalletAction
->setEnabled(enabled
);
564 backupWalletAction
->setEnabled(enabled
);
565 changePassphraseAction
->setEnabled(enabled
);
566 signMessageAction
->setEnabled(enabled
);
567 verifyMessageAction
->setEnabled(enabled
);
568 usedSendingAddressesAction
->setEnabled(enabled
);
569 usedReceivingAddressesAction
->setEnabled(enabled
);
570 openAction
->setEnabled(enabled
);
573 void BitcoinGUI::createTrayIcon(const NetworkStyle
*networkStyle
)
576 trayIcon
= new QSystemTrayIcon(this);
577 QString toolTip
= tr("%1 client").arg(tr(PACKAGE_NAME
)) + " " + networkStyle
->getTitleAddText();
578 trayIcon
->setToolTip(toolTip
);
579 trayIcon
->setIcon(networkStyle
->getTrayAndWindowIcon());
583 notificator
= new Notificator(QApplication::applicationName(), trayIcon
, this);
586 void BitcoinGUI::createTrayIconMenu()
589 // return if trayIcon is unset (only on non-Mac OSes)
593 trayIconMenu
= new QMenu(this);
594 trayIcon
->setContextMenu(trayIconMenu
);
596 connect(trayIcon
, SIGNAL(activated(QSystemTrayIcon::ActivationReason
)),
597 this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason
)));
599 // Note: On Mac, the dock icon is used to provide the tray's functionality.
600 MacDockIconHandler
*dockIconHandler
= MacDockIconHandler::instance();
601 dockIconHandler
->setMainWindow((QMainWindow
*)this);
602 trayIconMenu
= dockIconHandler
->dockMenu();
605 // Configuration of the tray icon (or dock icon) icon menu
606 trayIconMenu
->addAction(toggleHideAction
);
607 trayIconMenu
->addSeparator();
608 trayIconMenu
->addAction(sendCoinsMenuAction
);
609 trayIconMenu
->addAction(receiveCoinsMenuAction
);
610 trayIconMenu
->addSeparator();
611 trayIconMenu
->addAction(signMessageAction
);
612 trayIconMenu
->addAction(verifyMessageAction
);
613 trayIconMenu
->addSeparator();
614 trayIconMenu
->addAction(optionsAction
);
615 trayIconMenu
->addAction(openRPCConsoleAction
);
616 #ifndef Q_OS_MAC // This is built-in on Mac
617 trayIconMenu
->addSeparator();
618 trayIconMenu
->addAction(quitAction
);
623 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason
)
625 if(reason
== QSystemTrayIcon::Trigger
)
627 // Click on system tray icon triggers show/hide of the main window
633 void BitcoinGUI::optionsClicked()
635 if(!clientModel
|| !clientModel
->getOptionsModel())
638 OptionsDialog
dlg(this, enableWallet
);
639 dlg
.setModel(clientModel
->getOptionsModel());
643 void BitcoinGUI::aboutClicked()
648 HelpMessageDialog
dlg(this, true);
652 void BitcoinGUI::showDebugWindow()
654 rpcConsole
->showNormal();
657 rpcConsole
->activateWindow();
660 void BitcoinGUI::showDebugWindowActivateConsole()
662 rpcConsole
->setTabFocus(RPCConsole::TAB_CONSOLE
);
666 void BitcoinGUI::showHelpMessageClicked()
668 helpMessageDialog
->show();
672 void BitcoinGUI::openClicked()
674 OpenURIDialog
dlg(this);
677 Q_EMIT
receivedURI(dlg
.getURI());
681 void BitcoinGUI::gotoOverviewPage()
683 overviewAction
->setChecked(true);
684 if (walletFrame
) walletFrame
->gotoOverviewPage();
687 void BitcoinGUI::gotoHistoryPage()
689 historyAction
->setChecked(true);
690 if (walletFrame
) walletFrame
->gotoHistoryPage();
693 void BitcoinGUI::gotoReceiveCoinsPage()
695 receiveCoinsAction
->setChecked(true);
696 if (walletFrame
) walletFrame
->gotoReceiveCoinsPage();
699 void BitcoinGUI::gotoSendCoinsPage(QString addr
)
701 sendCoinsAction
->setChecked(true);
702 if (walletFrame
) walletFrame
->gotoSendCoinsPage(addr
);
705 void BitcoinGUI::gotoSignMessageTab(QString addr
)
707 if (walletFrame
) walletFrame
->gotoSignMessageTab(addr
);
710 void BitcoinGUI::gotoVerifyMessageTab(QString addr
)
712 if (walletFrame
) walletFrame
->gotoVerifyMessageTab(addr
);
714 #endif // ENABLE_WALLET
716 void BitcoinGUI::updateNetworkState()
718 int count
= clientModel
->getNumConnections();
722 case 0: icon
= ":/icons/connect_0"; break;
723 case 1: case 2: case 3: icon
= ":/icons/connect_1"; break;
724 case 4: case 5: case 6: icon
= ":/icons/connect_2"; break;
725 case 7: case 8: case 9: icon
= ":/icons/connect_3"; break;
726 default: icon
= ":/icons/connect_4"; break;
731 if (clientModel
->getNetworkActive()) {
732 tooltip
= tr("%n active connection(s) to Bitcoin network", "", count
) + QString(".<br>") + tr("Click to disable network activity.");
734 tooltip
= tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
735 icon
= ":/icons/network_disabled";
738 // Don't word-wrap this (fixed-width) tooltip
739 tooltip
= QString("<nobr>") + tooltip
+ QString("</nobr>");
740 connectionsControl
->setToolTip(tooltip
);
742 connectionsControl
->setPixmap(platformStyle
->SingleColorIcon(icon
).pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
745 void BitcoinGUI::setNumConnections(int count
)
747 updateNetworkState();
750 void BitcoinGUI::setNetworkActive(bool networkActive
)
752 updateNetworkState();
755 void BitcoinGUI::updateHeadersSyncProgressLabel()
757 int64_t headersTipTime
= clientModel
->getHeaderTipTime();
758 int headersTipHeight
= clientModel
->getHeaderTipHeight();
759 int estHeadersLeft
= (GetTime() - headersTipTime
) / Params().GetConsensus().nPowTargetSpacing
;
760 if (estHeadersLeft
> HEADER_HEIGHT_DELTA_SYNC
)
761 progressBarLabel
->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight
+estHeadersLeft
)*headersTipHeight
, 'f', 1)));
764 void BitcoinGUI::setNumBlocks(int count
, const QDateTime
& blockDate
, double nVerificationProgress
, bool header
)
769 modalOverlay
->setKnownBestHeight(count
, blockDate
);
771 modalOverlay
->tipUpdate(count
, blockDate
, nVerificationProgress
);
776 // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbled text)
777 statusBar()->clearMessage();
779 // Acquire current block source
780 enum BlockSource blockSource
= clientModel
->getBlockSource();
781 switch (blockSource
) {
782 case BLOCK_SOURCE_NETWORK
:
784 updateHeadersSyncProgressLabel();
787 progressBarLabel
->setText(tr("Synchronizing with network..."));
788 updateHeadersSyncProgressLabel();
790 case BLOCK_SOURCE_DISK
:
792 progressBarLabel
->setText(tr("Indexing blocks on disk..."));
794 progressBarLabel
->setText(tr("Processing blocks on disk..."));
797 case BLOCK_SOURCE_REINDEX
:
798 progressBarLabel
->setText(tr("Reindexing blocks on disk..."));
800 case BLOCK_SOURCE_NONE
:
804 progressBarLabel
->setText(tr("Connecting to peers..."));
810 QDateTime currentDate
= QDateTime::currentDateTime();
811 qint64 secs
= blockDate
.secsTo(currentDate
);
813 tooltip
= tr("Processed %n block(s) of transaction history.", "", count
);
815 // Set icon state: spinning if catching up, tick otherwise
818 tooltip
= tr("Up to date") + QString(".<br>") + tooltip
;
819 labelBlocksIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE
, STATUSBAR_ICONSIZE
));
824 walletFrame
->showOutOfSyncWarning(false);
825 modalOverlay
->showHide(true, true);
827 #endif // ENABLE_WALLET
829 progressBarLabel
->setVisible(false);
830 progressBar
->setVisible(false);
834 QString timeBehindText
= GUIUtil::formatNiceTimeOffset(secs
);
836 progressBarLabel
->setVisible(true);
837 progressBar
->setFormat(tr("%1 behind").arg(timeBehindText
));
838 progressBar
->setMaximum(1000000000);
839 progressBar
->setValue(nVerificationProgress
* 1000000000.0 + 0.5);
840 progressBar
->setVisible(true);
842 tooltip
= tr("Catching up...") + QString("<br>") + tooltip
;
843 if(count
!= prevBlocks
)
845 labelBlocksIcon
->setPixmap(platformStyle
->SingleColorIcon(QString(
846 ":/movies/spinner-%1").arg(spinnerFrame
, 3, 10, QChar('0')))
847 .pixmap(STATUSBAR_ICONSIZE
, STATUSBAR_ICONSIZE
));
848 spinnerFrame
= (spinnerFrame
+ 1) % SPINNER_FRAMES
;
855 walletFrame
->showOutOfSyncWarning(true);
856 modalOverlay
->showHide();
858 #endif // ENABLE_WALLET
860 tooltip
+= QString("<br>");
861 tooltip
+= tr("Last received block was generated %1 ago.").arg(timeBehindText
);
862 tooltip
+= QString("<br>");
863 tooltip
+= tr("Transactions after this will not yet be visible.");
866 // Don't word-wrap this (fixed-width) tooltip
867 tooltip
= QString("<nobr>") + tooltip
+ QString("</nobr>");
869 labelBlocksIcon
->setToolTip(tooltip
);
870 progressBarLabel
->setToolTip(tooltip
);
871 progressBar
->setToolTip(tooltip
);
874 void BitcoinGUI::message(const QString
&title
, const QString
&message
, unsigned int style
, bool *ret
)
876 QString strTitle
= tr("Bitcoin"); // default title
877 // Default to information icon
878 int nMBoxIcon
= QMessageBox::Information
;
879 int nNotifyIcon
= Notificator::Information
;
883 // Prefer supplied title over style based title
884 if (!title
.isEmpty()) {
889 case CClientUIInterface::MSG_ERROR
:
890 msgType
= tr("Error");
892 case CClientUIInterface::MSG_WARNING
:
893 msgType
= tr("Warning");
895 case CClientUIInterface::MSG_INFORMATION
:
896 msgType
= tr("Information");
902 // Append title to "Bitcoin - "
903 if (!msgType
.isEmpty())
904 strTitle
+= " - " + msgType
;
906 // Check for error/warning icon
907 if (style
& CClientUIInterface::ICON_ERROR
) {
908 nMBoxIcon
= QMessageBox::Critical
;
909 nNotifyIcon
= Notificator::Critical
;
911 else if (style
& CClientUIInterface::ICON_WARNING
) {
912 nMBoxIcon
= QMessageBox::Warning
;
913 nNotifyIcon
= Notificator::Warning
;
917 if (style
& CClientUIInterface::MODAL
) {
918 // Check for buttons, use OK as default, if none was supplied
919 QMessageBox::StandardButton buttons
;
920 if (!(buttons
= (QMessageBox::StandardButton
)(style
& CClientUIInterface::BTN_MASK
)))
921 buttons
= QMessageBox::Ok
;
923 showNormalIfMinimized();
924 QMessageBox
mBox((QMessageBox::Icon
)nMBoxIcon
, strTitle
, message
, buttons
, this);
927 *ret
= r
== QMessageBox::Ok
;
930 notificator
->notify((Notificator::Class
)nNotifyIcon
, strTitle
, message
);
933 void BitcoinGUI::changeEvent(QEvent
*e
)
935 QMainWindow::changeEvent(e
);
936 #ifndef Q_OS_MAC // Ignored on Mac
937 if(e
->type() == QEvent::WindowStateChange
)
939 if(clientModel
&& clientModel
->getOptionsModel() && clientModel
->getOptionsModel()->getMinimizeToTray())
941 QWindowStateChangeEvent
*wsevt
= static_cast<QWindowStateChangeEvent
*>(e
);
942 if(!(wsevt
->oldState() & Qt::WindowMinimized
) && isMinimized())
944 QTimer::singleShot(0, this, SLOT(hide()));
952 void BitcoinGUI::closeEvent(QCloseEvent
*event
)
954 #ifndef Q_OS_MAC // Ignored on Mac
955 if(clientModel
&& clientModel
->getOptionsModel())
957 if(!clientModel
->getOptionsModel()->getMinimizeOnClose())
959 // close rpcConsole in case it was open to make some space for the shutdown window
962 QApplication::quit();
966 QMainWindow::showMinimized();
971 QMainWindow::closeEvent(event
);
975 void BitcoinGUI::showEvent(QShowEvent
*event
)
977 // enable the debug window when the main window shows up
978 openRPCConsoleAction
->setEnabled(true);
979 aboutAction
->setEnabled(true);
980 optionsAction
->setEnabled(true);
984 void BitcoinGUI::incomingTransaction(const QString
& date
, int unit
, const CAmount
& amount
, const QString
& type
, const QString
& address
, const QString
& label
)
986 // On new transaction, make an info balloon
987 QString msg
= tr("Date: %1\n").arg(date
) +
988 tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit
, amount
, true)) +
989 tr("Type: %1\n").arg(type
);
990 if (!label
.isEmpty())
991 msg
+= tr("Label: %1\n").arg(label
);
992 else if (!address
.isEmpty())
993 msg
+= tr("Address: %1\n").arg(address
);
994 message((amount
)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
995 msg
, CClientUIInterface::MSG_INFORMATION
);
997 #endif // ENABLE_WALLET
999 void BitcoinGUI::dragEnterEvent(QDragEnterEvent
*event
)
1002 if(event
->mimeData()->hasUrls())
1003 event
->acceptProposedAction();
1006 void BitcoinGUI::dropEvent(QDropEvent
*event
)
1008 if(event
->mimeData()->hasUrls())
1010 Q_FOREACH(const QUrl
&uri
, event
->mimeData()->urls())
1012 Q_EMIT
receivedURI(uri
.toString());
1015 event
->acceptProposedAction();
1018 bool BitcoinGUI::eventFilter(QObject
*object
, QEvent
*event
)
1020 // Catch status tip events
1021 if (event
->type() == QEvent::StatusTip
)
1023 // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
1024 if (progressBarLabel
->isVisible() || progressBar
->isVisible())
1027 return QMainWindow::eventFilter(object
, event
);
1030 #ifdef ENABLE_WALLET
1031 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient
& recipient
)
1033 // URI has to be valid
1034 if (walletFrame
&& walletFrame
->handlePaymentRequest(recipient
))
1036 showNormalIfMinimized();
1037 gotoSendCoinsPage();
1043 void BitcoinGUI::setHDStatus(int hdEnabled
)
1045 labelWalletHDStatusIcon
->setPixmap(platformStyle
->SingleColorIcon(hdEnabled
? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1046 labelWalletHDStatusIcon
->setToolTip(hdEnabled
? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
1048 // eventually disable the QLabel to set its opacity to 50%
1049 labelWalletHDStatusIcon
->setEnabled(hdEnabled
);
1052 void BitcoinGUI::setEncryptionStatus(int status
)
1056 case WalletModel::Unencrypted
:
1057 labelWalletEncryptionIcon
->hide();
1058 encryptWalletAction
->setChecked(false);
1059 changePassphraseAction
->setEnabled(false);
1060 encryptWalletAction
->setEnabled(true);
1062 case WalletModel::Unlocked
:
1063 labelWalletEncryptionIcon
->show();
1064 labelWalletEncryptionIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1065 labelWalletEncryptionIcon
->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
1066 encryptWalletAction
->setChecked(true);
1067 changePassphraseAction
->setEnabled(true);
1068 encryptWalletAction
->setEnabled(false); // TODO: decrypt currently not supported
1070 case WalletModel::Locked
:
1071 labelWalletEncryptionIcon
->show();
1072 labelWalletEncryptionIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1073 labelWalletEncryptionIcon
->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
1074 encryptWalletAction
->setChecked(true);
1075 changePassphraseAction
->setEnabled(true);
1076 encryptWalletAction
->setEnabled(false); // TODO: decrypt currently not supported
1080 #endif // ENABLE_WALLET
1082 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden
)
1087 // activateWindow() (sometimes) helps with keyboard focus on Windows
1093 else if (isMinimized())
1098 else if (GUIUtil::isObscured(this))
1103 else if(fToggleHidden
)
1107 void BitcoinGUI::toggleHidden()
1109 showNormalIfMinimized(true);
1112 void BitcoinGUI::detectShutdown()
1114 if (ShutdownRequested())
1122 void BitcoinGUI::showProgress(const QString
&title
, int nProgress
)
1126 progressDialog
= new QProgressDialog(title
, "", 0, 100);
1127 progressDialog
->setWindowModality(Qt::ApplicationModal
);
1128 progressDialog
->setMinimumDuration(0);
1129 progressDialog
->setCancelButton(0);
1130 progressDialog
->setAutoClose(false);
1131 progressDialog
->setValue(0);
1133 else if (nProgress
== 100)
1137 progressDialog
->close();
1138 progressDialog
->deleteLater();
1141 else if (progressDialog
)
1142 progressDialog
->setValue(nProgress
);
1145 void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon
)
1149 trayIcon
->setVisible(!fHideTrayIcon
);
1153 void BitcoinGUI::showModalOverlay()
1155 if (modalOverlay
&& (progressBar
->isVisible() || modalOverlay
->isLayerVisible()))
1156 modalOverlay
->toggleVisibility();
1159 static bool ThreadSafeMessageBox(BitcoinGUI
*gui
, const std::string
& message
, const std::string
& caption
, unsigned int style
)
1161 bool modal
= (style
& CClientUIInterface::MODAL
);
1162 // The SECURE flag has no effect in the Qt GUI.
1163 // bool secure = (style & CClientUIInterface::SECURE);
1164 style
&= ~CClientUIInterface::SECURE
;
1166 // In case of modal message, use blocking connection to wait for user to click a button
1167 QMetaObject::invokeMethod(gui
, "message",
1168 modal
? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection
,
1169 Q_ARG(QString
, QString::fromStdString(caption
)),
1170 Q_ARG(QString
, QString::fromStdString(message
)),
1171 Q_ARG(unsigned int, style
),
1172 Q_ARG(bool*, &ret
));
1176 void BitcoinGUI::subscribeToCoreSignals()
1178 // Connect signals to client
1179 uiInterface
.ThreadSafeMessageBox
.connect(boost::bind(ThreadSafeMessageBox
, this, _1
, _2
, _3
));
1180 uiInterface
.ThreadSafeQuestion
.connect(boost::bind(ThreadSafeMessageBox
, this, _1
, _3
, _4
));
1183 void BitcoinGUI::unsubscribeFromCoreSignals()
1185 // Disconnect signals from client
1186 uiInterface
.ThreadSafeMessageBox
.disconnect(boost::bind(ThreadSafeMessageBox
, this, _1
, _2
, _3
));
1187 uiInterface
.ThreadSafeQuestion
.disconnect(boost::bind(ThreadSafeMessageBox
, this, _1
, _3
, _4
));
1190 void BitcoinGUI::toggleNetworkActive()
1193 clientModel
->setNetworkActive(!clientModel
->getNetworkActive());
1197 UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle
*platformStyle
) :
1201 createContextMenu();
1202 setToolTip(tr("Unit to show amounts in. Click to select another unit."));
1203 QList
<BitcoinUnits::Unit
> units
= BitcoinUnits::availableUnits();
1205 const QFontMetrics
fm(font());
1206 Q_FOREACH (const BitcoinUnits::Unit unit
, units
)
1208 max_width
= qMax(max_width
, fm
.width(BitcoinUnits::name(unit
)));
1210 setMinimumSize(max_width
, 0);
1211 setAlignment(Qt::AlignRight
| Qt::AlignVCenter
);
1212 setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle
->SingleColor().name()));
1215 /** So that it responds to button clicks */
1216 void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent
*event
)
1218 onDisplayUnitsClicked(event
->pos());
1221 /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
1222 void UnitDisplayStatusBarControl::createContextMenu()
1224 menu
= new QMenu(this);
1225 Q_FOREACH(BitcoinUnits::Unit u
, BitcoinUnits::availableUnits())
1227 QAction
*menuAction
= new QAction(QString(BitcoinUnits::name(u
)), this);
1228 menuAction
->setData(QVariant(u
));
1229 menu
->addAction(menuAction
);
1231 connect(menu
,SIGNAL(triggered(QAction
*)),this,SLOT(onMenuSelection(QAction
*)));
1234 /** Lets the control know about the Options Model (and its signals) */
1235 void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel
*_optionsModel
)
1239 this->optionsModel
= _optionsModel
;
1241 // be aware of a display unit change reported by the OptionsModel object.
1242 connect(_optionsModel
,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
1244 // initialize the display units label with the current value in the model.
1245 updateDisplayUnit(_optionsModel
->getDisplayUnit());
1249 /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
1250 void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits
)
1252 setText(BitcoinUnits::name(newUnits
));
1255 /** Shows context menu with Display Unit options by the mouse coordinates */
1256 void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint
& point
)
1258 QPoint globalPos
= mapToGlobal(point
);
1259 menu
->exec(globalPos
);
1262 /** Tells underlying optionsModel to update its current display unit. */
1263 void UnitDisplayStatusBarControl::onMenuSelection(QAction
* action
)
1267 optionsModel
->setDisplayUnit(action
->data());