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 modalOverlay
->setKnownBestHeight(_clientModel
->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel
->getHeaderTipTime()));
482 setNumBlocks(_clientModel
->getNumBlocks(), _clientModel
->getLastBlockDate(), _clientModel
->getVerificationProgress(NULL
), false);
483 connect(_clientModel
, SIGNAL(numBlocksChanged(int,QDateTime
,double,bool)), this, SLOT(setNumBlocks(int,QDateTime
,double,bool)));
485 // Receive and report messages from client model
486 connect(_clientModel
, SIGNAL(message(QString
,QString
,unsigned int)), this, SLOT(message(QString
,QString
,unsigned int)));
488 // Show progress dialog
489 connect(_clientModel
, SIGNAL(showProgress(QString
,int)), this, SLOT(showProgress(QString
,int)));
491 rpcConsole
->setClientModel(_clientModel
);
495 walletFrame
->setClientModel(_clientModel
);
497 #endif // ENABLE_WALLET
498 unitDisplayControl
->setOptionsModel(_clientModel
->getOptionsModel());
500 OptionsModel
* optionsModel
= _clientModel
->getOptionsModel();
503 // be aware of the tray icon disable state change reported by the OptionsModel object.
504 connect(optionsModel
,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
506 // initialize the disable state of the tray icon with the current value in the model.
507 setTrayIconVisible(optionsModel
->getHideTrayIcon());
510 // Disable possibility to show main window via action
511 toggleHideAction
->setEnabled(false);
514 // Disable context menu on tray icon
515 trayIconMenu
->clear();
517 // Propagate cleared model to child objects
518 rpcConsole
->setClientModel(nullptr);
522 walletFrame
->setClientModel(nullptr);
524 #endif // ENABLE_WALLET
525 unitDisplayControl
->setOptionsModel(nullptr);
530 bool BitcoinGUI::addWallet(const QString
& name
, WalletModel
*walletModel
)
534 setWalletActionsEnabled(true);
535 return walletFrame
->addWallet(name
, walletModel
);
538 bool BitcoinGUI::setCurrentWallet(const QString
& name
)
542 return walletFrame
->setCurrentWallet(name
);
545 void BitcoinGUI::removeAllWallets()
549 setWalletActionsEnabled(false);
550 walletFrame
->removeAllWallets();
552 #endif // ENABLE_WALLET
554 void BitcoinGUI::setWalletActionsEnabled(bool enabled
)
556 overviewAction
->setEnabled(enabled
);
557 sendCoinsAction
->setEnabled(enabled
);
558 sendCoinsMenuAction
->setEnabled(enabled
);
559 receiveCoinsAction
->setEnabled(enabled
);
560 receiveCoinsMenuAction
->setEnabled(enabled
);
561 historyAction
->setEnabled(enabled
);
562 encryptWalletAction
->setEnabled(enabled
);
563 backupWalletAction
->setEnabled(enabled
);
564 changePassphraseAction
->setEnabled(enabled
);
565 signMessageAction
->setEnabled(enabled
);
566 verifyMessageAction
->setEnabled(enabled
);
567 usedSendingAddressesAction
->setEnabled(enabled
);
568 usedReceivingAddressesAction
->setEnabled(enabled
);
569 openAction
->setEnabled(enabled
);
572 void BitcoinGUI::createTrayIcon(const NetworkStyle
*networkStyle
)
575 trayIcon
= new QSystemTrayIcon(this);
576 QString toolTip
= tr("%1 client").arg(tr(PACKAGE_NAME
)) + " " + networkStyle
->getTitleAddText();
577 trayIcon
->setToolTip(toolTip
);
578 trayIcon
->setIcon(networkStyle
->getTrayAndWindowIcon());
582 notificator
= new Notificator(QApplication::applicationName(), trayIcon
, this);
585 void BitcoinGUI::createTrayIconMenu()
588 // return if trayIcon is unset (only on non-Mac OSes)
592 trayIconMenu
= new QMenu(this);
593 trayIcon
->setContextMenu(trayIconMenu
);
595 connect(trayIcon
, SIGNAL(activated(QSystemTrayIcon::ActivationReason
)),
596 this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason
)));
598 // Note: On Mac, the dock icon is used to provide the tray's functionality.
599 MacDockIconHandler
*dockIconHandler
= MacDockIconHandler::instance();
600 dockIconHandler
->setMainWindow((QMainWindow
*)this);
601 trayIconMenu
= dockIconHandler
->dockMenu();
604 // Configuration of the tray icon (or dock icon) icon menu
605 trayIconMenu
->addAction(toggleHideAction
);
606 trayIconMenu
->addSeparator();
607 trayIconMenu
->addAction(sendCoinsMenuAction
);
608 trayIconMenu
->addAction(receiveCoinsMenuAction
);
609 trayIconMenu
->addSeparator();
610 trayIconMenu
->addAction(signMessageAction
);
611 trayIconMenu
->addAction(verifyMessageAction
);
612 trayIconMenu
->addSeparator();
613 trayIconMenu
->addAction(optionsAction
);
614 trayIconMenu
->addAction(openRPCConsoleAction
);
615 #ifndef Q_OS_MAC // This is built-in on Mac
616 trayIconMenu
->addSeparator();
617 trayIconMenu
->addAction(quitAction
);
622 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason
)
624 if(reason
== QSystemTrayIcon::Trigger
)
626 // Click on system tray icon triggers show/hide of the main window
632 void BitcoinGUI::optionsClicked()
634 if(!clientModel
|| !clientModel
->getOptionsModel())
637 OptionsDialog
dlg(this, enableWallet
);
638 dlg
.setModel(clientModel
->getOptionsModel());
642 void BitcoinGUI::aboutClicked()
647 HelpMessageDialog
dlg(this, true);
651 void BitcoinGUI::showDebugWindow()
653 rpcConsole
->showNormal();
656 rpcConsole
->activateWindow();
659 void BitcoinGUI::showDebugWindowActivateConsole()
661 rpcConsole
->setTabFocus(RPCConsole::TAB_CONSOLE
);
665 void BitcoinGUI::showHelpMessageClicked()
667 helpMessageDialog
->show();
671 void BitcoinGUI::openClicked()
673 OpenURIDialog
dlg(this);
676 Q_EMIT
receivedURI(dlg
.getURI());
680 void BitcoinGUI::gotoOverviewPage()
682 overviewAction
->setChecked(true);
683 if (walletFrame
) walletFrame
->gotoOverviewPage();
686 void BitcoinGUI::gotoHistoryPage()
688 historyAction
->setChecked(true);
689 if (walletFrame
) walletFrame
->gotoHistoryPage();
692 void BitcoinGUI::gotoReceiveCoinsPage()
694 receiveCoinsAction
->setChecked(true);
695 if (walletFrame
) walletFrame
->gotoReceiveCoinsPage();
698 void BitcoinGUI::gotoSendCoinsPage(QString addr
)
700 sendCoinsAction
->setChecked(true);
701 if (walletFrame
) walletFrame
->gotoSendCoinsPage(addr
);
704 void BitcoinGUI::gotoSignMessageTab(QString addr
)
706 if (walletFrame
) walletFrame
->gotoSignMessageTab(addr
);
709 void BitcoinGUI::gotoVerifyMessageTab(QString addr
)
711 if (walletFrame
) walletFrame
->gotoVerifyMessageTab(addr
);
713 #endif // ENABLE_WALLET
715 void BitcoinGUI::updateNetworkState()
717 int count
= clientModel
->getNumConnections();
721 case 0: icon
= ":/icons/connect_0"; break;
722 case 1: case 2: case 3: icon
= ":/icons/connect_1"; break;
723 case 4: case 5: case 6: icon
= ":/icons/connect_2"; break;
724 case 7: case 8: case 9: icon
= ":/icons/connect_3"; break;
725 default: icon
= ":/icons/connect_4"; break;
730 if (clientModel
->getNetworkActive()) {
731 tooltip
= tr("%n active connection(s) to Bitcoin network", "", count
) + QString(".<br>") + tr("Click to disable network activity.");
733 tooltip
= tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
734 icon
= ":/icons/network_disabled";
737 // Don't word-wrap this (fixed-width) tooltip
738 tooltip
= QString("<nobr>") + tooltip
+ QString("</nobr>");
739 connectionsControl
->setToolTip(tooltip
);
741 connectionsControl
->setPixmap(platformStyle
->SingleColorIcon(icon
).pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
744 void BitcoinGUI::setNumConnections(int count
)
746 updateNetworkState();
749 void BitcoinGUI::setNetworkActive(bool networkActive
)
751 updateNetworkState();
754 void BitcoinGUI::updateHeadersSyncProgressLabel()
756 int64_t headersTipTime
= clientModel
->getHeaderTipTime();
757 int headersTipHeight
= clientModel
->getHeaderTipHeight();
758 int estHeadersLeft
= (GetTime() - headersTipTime
) / Params().GetConsensus().nPowTargetSpacing
;
759 if (estHeadersLeft
> HEADER_HEIGHT_DELTA_SYNC
)
760 progressBarLabel
->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight
+estHeadersLeft
)*headersTipHeight
, 'f', 1)));
763 void BitcoinGUI::setNumBlocks(int count
, const QDateTime
& blockDate
, double nVerificationProgress
, bool header
)
768 modalOverlay
->setKnownBestHeight(count
, blockDate
);
770 modalOverlay
->tipUpdate(count
, blockDate
, nVerificationProgress
);
775 // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbled text)
776 statusBar()->clearMessage();
778 // Acquire current block source
779 enum BlockSource blockSource
= clientModel
->getBlockSource();
780 switch (blockSource
) {
781 case BLOCK_SOURCE_NETWORK
:
783 updateHeadersSyncProgressLabel();
786 progressBarLabel
->setText(tr("Synchronizing with network..."));
787 updateHeadersSyncProgressLabel();
789 case BLOCK_SOURCE_DISK
:
791 progressBarLabel
->setText(tr("Indexing blocks on disk..."));
793 progressBarLabel
->setText(tr("Processing blocks on disk..."));
796 case BLOCK_SOURCE_REINDEX
:
797 progressBarLabel
->setText(tr("Reindexing blocks on disk..."));
799 case BLOCK_SOURCE_NONE
:
803 progressBarLabel
->setText(tr("Connecting to peers..."));
809 QDateTime currentDate
= QDateTime::currentDateTime();
810 qint64 secs
= blockDate
.secsTo(currentDate
);
812 tooltip
= tr("Processed %n block(s) of transaction history.", "", count
);
814 // Set icon state: spinning if catching up, tick otherwise
817 tooltip
= tr("Up to date") + QString(".<br>") + tooltip
;
818 labelBlocksIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE
, STATUSBAR_ICONSIZE
));
823 walletFrame
->showOutOfSyncWarning(false);
824 modalOverlay
->showHide(true, true);
826 #endif // ENABLE_WALLET
828 progressBarLabel
->setVisible(false);
829 progressBar
->setVisible(false);
833 QString timeBehindText
= GUIUtil::formatNiceTimeOffset(secs
);
835 progressBarLabel
->setVisible(true);
836 progressBar
->setFormat(tr("%1 behind").arg(timeBehindText
));
837 progressBar
->setMaximum(1000000000);
838 progressBar
->setValue(nVerificationProgress
* 1000000000.0 + 0.5);
839 progressBar
->setVisible(true);
841 tooltip
= tr("Catching up...") + QString("<br>") + tooltip
;
842 if(count
!= prevBlocks
)
844 labelBlocksIcon
->setPixmap(platformStyle
->SingleColorIcon(QString(
845 ":/movies/spinner-%1").arg(spinnerFrame
, 3, 10, QChar('0')))
846 .pixmap(STATUSBAR_ICONSIZE
, STATUSBAR_ICONSIZE
));
847 spinnerFrame
= (spinnerFrame
+ 1) % SPINNER_FRAMES
;
854 walletFrame
->showOutOfSyncWarning(true);
855 modalOverlay
->showHide();
857 #endif // ENABLE_WALLET
859 tooltip
+= QString("<br>");
860 tooltip
+= tr("Last received block was generated %1 ago.").arg(timeBehindText
);
861 tooltip
+= QString("<br>");
862 tooltip
+= tr("Transactions after this will not yet be visible.");
865 // Don't word-wrap this (fixed-width) tooltip
866 tooltip
= QString("<nobr>") + tooltip
+ QString("</nobr>");
868 labelBlocksIcon
->setToolTip(tooltip
);
869 progressBarLabel
->setToolTip(tooltip
);
870 progressBar
->setToolTip(tooltip
);
873 void BitcoinGUI::message(const QString
&title
, const QString
&message
, unsigned int style
, bool *ret
)
875 QString strTitle
= tr("Bitcoin"); // default title
876 // Default to information icon
877 int nMBoxIcon
= QMessageBox::Information
;
878 int nNotifyIcon
= Notificator::Information
;
882 // Prefer supplied title over style based title
883 if (!title
.isEmpty()) {
888 case CClientUIInterface::MSG_ERROR
:
889 msgType
= tr("Error");
891 case CClientUIInterface::MSG_WARNING
:
892 msgType
= tr("Warning");
894 case CClientUIInterface::MSG_INFORMATION
:
895 msgType
= tr("Information");
901 // Append title to "Bitcoin - "
902 if (!msgType
.isEmpty())
903 strTitle
+= " - " + msgType
;
905 // Check for error/warning icon
906 if (style
& CClientUIInterface::ICON_ERROR
) {
907 nMBoxIcon
= QMessageBox::Critical
;
908 nNotifyIcon
= Notificator::Critical
;
910 else if (style
& CClientUIInterface::ICON_WARNING
) {
911 nMBoxIcon
= QMessageBox::Warning
;
912 nNotifyIcon
= Notificator::Warning
;
916 if (style
& CClientUIInterface::MODAL
) {
917 // Check for buttons, use OK as default, if none was supplied
918 QMessageBox::StandardButton buttons
;
919 if (!(buttons
= (QMessageBox::StandardButton
)(style
& CClientUIInterface::BTN_MASK
)))
920 buttons
= QMessageBox::Ok
;
922 showNormalIfMinimized();
923 QMessageBox
mBox((QMessageBox::Icon
)nMBoxIcon
, strTitle
, message
, buttons
, this);
926 *ret
= r
== QMessageBox::Ok
;
929 notificator
->notify((Notificator::Class
)nNotifyIcon
, strTitle
, message
);
932 void BitcoinGUI::changeEvent(QEvent
*e
)
934 QMainWindow::changeEvent(e
);
935 #ifndef Q_OS_MAC // Ignored on Mac
936 if(e
->type() == QEvent::WindowStateChange
)
938 if(clientModel
&& clientModel
->getOptionsModel() && clientModel
->getOptionsModel()->getMinimizeToTray())
940 QWindowStateChangeEvent
*wsevt
= static_cast<QWindowStateChangeEvent
*>(e
);
941 if(!(wsevt
->oldState() & Qt::WindowMinimized
) && isMinimized())
943 QTimer::singleShot(0, this, SLOT(hide()));
951 void BitcoinGUI::closeEvent(QCloseEvent
*event
)
953 #ifndef Q_OS_MAC // Ignored on Mac
954 if(clientModel
&& clientModel
->getOptionsModel())
956 if(!clientModel
->getOptionsModel()->getMinimizeOnClose())
958 // close rpcConsole in case it was open to make some space for the shutdown window
961 QApplication::quit();
965 QMainWindow::showMinimized();
970 QMainWindow::closeEvent(event
);
974 void BitcoinGUI::showEvent(QShowEvent
*event
)
976 // enable the debug window when the main window shows up
977 openRPCConsoleAction
->setEnabled(true);
978 aboutAction
->setEnabled(true);
979 optionsAction
->setEnabled(true);
983 void BitcoinGUI::incomingTransaction(const QString
& date
, int unit
, const CAmount
& amount
, const QString
& type
, const QString
& address
, const QString
& label
)
985 // On new transaction, make an info balloon
986 QString msg
= tr("Date: %1\n").arg(date
) +
987 tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit
, amount
, true)) +
988 tr("Type: %1\n").arg(type
);
989 if (!label
.isEmpty())
990 msg
+= tr("Label: %1\n").arg(label
);
991 else if (!address
.isEmpty())
992 msg
+= tr("Address: %1\n").arg(address
);
993 message((amount
)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
994 msg
, CClientUIInterface::MSG_INFORMATION
);
996 #endif // ENABLE_WALLET
998 void BitcoinGUI::dragEnterEvent(QDragEnterEvent
*event
)
1001 if(event
->mimeData()->hasUrls())
1002 event
->acceptProposedAction();
1005 void BitcoinGUI::dropEvent(QDropEvent
*event
)
1007 if(event
->mimeData()->hasUrls())
1009 Q_FOREACH(const QUrl
&uri
, event
->mimeData()->urls())
1011 Q_EMIT
receivedURI(uri
.toString());
1014 event
->acceptProposedAction();
1017 bool BitcoinGUI::eventFilter(QObject
*object
, QEvent
*event
)
1019 // Catch status tip events
1020 if (event
->type() == QEvent::StatusTip
)
1022 // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
1023 if (progressBarLabel
->isVisible() || progressBar
->isVisible())
1026 return QMainWindow::eventFilter(object
, event
);
1029 #ifdef ENABLE_WALLET
1030 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient
& recipient
)
1032 // URI has to be valid
1033 if (walletFrame
&& walletFrame
->handlePaymentRequest(recipient
))
1035 showNormalIfMinimized();
1036 gotoSendCoinsPage();
1042 void BitcoinGUI::setHDStatus(int hdEnabled
)
1044 labelWalletHDStatusIcon
->setPixmap(platformStyle
->SingleColorIcon(hdEnabled
? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1045 labelWalletHDStatusIcon
->setToolTip(hdEnabled
? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
1047 // eventually disable the QLabel to set its opacity to 50%
1048 labelWalletHDStatusIcon
->setEnabled(hdEnabled
);
1051 void BitcoinGUI::setEncryptionStatus(int status
)
1055 case WalletModel::Unencrypted
:
1056 labelWalletEncryptionIcon
->hide();
1057 encryptWalletAction
->setChecked(false);
1058 changePassphraseAction
->setEnabled(false);
1059 encryptWalletAction
->setEnabled(true);
1061 case WalletModel::Unlocked
:
1062 labelWalletEncryptionIcon
->show();
1063 labelWalletEncryptionIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1064 labelWalletEncryptionIcon
->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
1065 encryptWalletAction
->setChecked(true);
1066 changePassphraseAction
->setEnabled(true);
1067 encryptWalletAction
->setEnabled(false); // TODO: decrypt currently not supported
1069 case WalletModel::Locked
:
1070 labelWalletEncryptionIcon
->show();
1071 labelWalletEncryptionIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1072 labelWalletEncryptionIcon
->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
1073 encryptWalletAction
->setChecked(true);
1074 changePassphraseAction
->setEnabled(true);
1075 encryptWalletAction
->setEnabled(false); // TODO: decrypt currently not supported
1079 #endif // ENABLE_WALLET
1081 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden
)
1086 // activateWindow() (sometimes) helps with keyboard focus on Windows
1092 else if (isMinimized())
1097 else if (GUIUtil::isObscured(this))
1102 else if(fToggleHidden
)
1106 void BitcoinGUI::toggleHidden()
1108 showNormalIfMinimized(true);
1111 void BitcoinGUI::detectShutdown()
1113 if (ShutdownRequested())
1121 void BitcoinGUI::showProgress(const QString
&title
, int nProgress
)
1125 progressDialog
= new QProgressDialog(title
, "", 0, 100);
1126 progressDialog
->setWindowModality(Qt::ApplicationModal
);
1127 progressDialog
->setMinimumDuration(0);
1128 progressDialog
->setCancelButton(0);
1129 progressDialog
->setAutoClose(false);
1130 progressDialog
->setValue(0);
1132 else if (nProgress
== 100)
1136 progressDialog
->close();
1137 progressDialog
->deleteLater();
1140 else if (progressDialog
)
1141 progressDialog
->setValue(nProgress
);
1144 void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon
)
1148 trayIcon
->setVisible(!fHideTrayIcon
);
1152 void BitcoinGUI::showModalOverlay()
1154 if (modalOverlay
&& (progressBar
->isVisible() || modalOverlay
->isLayerVisible()))
1155 modalOverlay
->toggleVisibility();
1158 static bool ThreadSafeMessageBox(BitcoinGUI
*gui
, const std::string
& message
, const std::string
& caption
, unsigned int style
)
1160 bool modal
= (style
& CClientUIInterface::MODAL
);
1161 // The SECURE flag has no effect in the Qt GUI.
1162 // bool secure = (style & CClientUIInterface::SECURE);
1163 style
&= ~CClientUIInterface::SECURE
;
1165 // In case of modal message, use blocking connection to wait for user to click a button
1166 QMetaObject::invokeMethod(gui
, "message",
1167 modal
? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection
,
1168 Q_ARG(QString
, QString::fromStdString(caption
)),
1169 Q_ARG(QString
, QString::fromStdString(message
)),
1170 Q_ARG(unsigned int, style
),
1171 Q_ARG(bool*, &ret
));
1175 void BitcoinGUI::subscribeToCoreSignals()
1177 // Connect signals to client
1178 uiInterface
.ThreadSafeMessageBox
.connect(boost::bind(ThreadSafeMessageBox
, this, _1
, _2
, _3
));
1179 uiInterface
.ThreadSafeQuestion
.connect(boost::bind(ThreadSafeMessageBox
, this, _1
, _3
, _4
));
1182 void BitcoinGUI::unsubscribeFromCoreSignals()
1184 // Disconnect signals from client
1185 uiInterface
.ThreadSafeMessageBox
.disconnect(boost::bind(ThreadSafeMessageBox
, this, _1
, _2
, _3
));
1186 uiInterface
.ThreadSafeQuestion
.disconnect(boost::bind(ThreadSafeMessageBox
, this, _1
, _3
, _4
));
1189 void BitcoinGUI::toggleNetworkActive()
1192 clientModel
->setNetworkActive(!clientModel
->getNetworkActive());
1196 UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle
*platformStyle
) :
1200 createContextMenu();
1201 setToolTip(tr("Unit to show amounts in. Click to select another unit."));
1202 QList
<BitcoinUnits::Unit
> units
= BitcoinUnits::availableUnits();
1204 const QFontMetrics
fm(font());
1205 Q_FOREACH (const BitcoinUnits::Unit unit
, units
)
1207 max_width
= qMax(max_width
, fm
.width(BitcoinUnits::name(unit
)));
1209 setMinimumSize(max_width
, 0);
1210 setAlignment(Qt::AlignRight
| Qt::AlignVCenter
);
1211 setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle
->SingleColor().name()));
1214 /** So that it responds to button clicks */
1215 void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent
*event
)
1217 onDisplayUnitsClicked(event
->pos());
1220 /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
1221 void UnitDisplayStatusBarControl::createContextMenu()
1223 menu
= new QMenu(this);
1224 Q_FOREACH(BitcoinUnits::Unit u
, BitcoinUnits::availableUnits())
1226 QAction
*menuAction
= new QAction(QString(BitcoinUnits::name(u
)), this);
1227 menuAction
->setData(QVariant(u
));
1228 menu
->addAction(menuAction
);
1230 connect(menu
,SIGNAL(triggered(QAction
*)),this,SLOT(onMenuSelection(QAction
*)));
1233 /** Lets the control know about the Options Model (and its signals) */
1234 void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel
*_optionsModel
)
1238 this->optionsModel
= _optionsModel
;
1240 // be aware of a display unit change reported by the OptionsModel object.
1241 connect(_optionsModel
,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
1243 // initialize the display units label with the current value in the model.
1244 updateDisplayUnit(_optionsModel
->getDisplayUnit());
1248 /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
1249 void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits
)
1251 setText(BitcoinUnits::name(newUnits
));
1254 /** Shows context menu with Display Unit options by the mouse coordinates */
1255 void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint
& point
)
1257 QPoint globalPos
= mapToGlobal(point
);
1258 menu
->exec(globalPos
);
1261 /** Tells underlying optionsModel to update its current display unit. */
1262 void UnitDisplayStatusBarControl::onMenuSelection(QAction
* action
)
1266 optionsModel
->setDisplayUnit(action
->data());