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
)
127 if (!restoreGeometry(settings
.value("MainWindowGeometry").toByteArray())) {
128 // Restore failed (perhaps missing setting), center the window
129 move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
132 QString windowTitle
= tr(PACKAGE_NAME
) + " - ";
134 enableWallet
= WalletModel::isWalletEnabled();
135 #endif // ENABLE_WALLET
138 windowTitle
+= tr("Wallet");
140 windowTitle
+= tr("Node");
142 windowTitle
+= " " + networkStyle
->getTitleAddText();
144 QApplication::setWindowIcon(networkStyle
->getTrayAndWindowIcon());
145 setWindowIcon(networkStyle
->getTrayAndWindowIcon());
147 MacDockIconHandler::instance()->setIcon(networkStyle
->getAppIcon());
149 setWindowTitle(windowTitle
);
151 #if defined(Q_OS_MAC) && QT_VERSION < 0x050000
152 // This property is not implemented in Qt 5. Setting it has no effect.
153 // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
154 setUnifiedTitleAndToolBarOnMac(true);
157 rpcConsole
= new RPCConsole(_platformStyle
, 0);
158 helpMessageDialog
= new HelpMessageDialog(this, false);
162 /** Create wallet frame and make it the central widget */
163 walletFrame
= new WalletFrame(_platformStyle
, this);
164 setCentralWidget(walletFrame
);
166 #endif // ENABLE_WALLET
168 /* When compiled without wallet or -disablewallet is provided,
169 * the central widget is the rpc console.
171 setCentralWidget(rpcConsole
);
174 // Accept D&D of URIs
175 setAcceptDrops(true);
177 // Create actions for the toolbar, menu bar and tray/dock icon
178 // Needs walletFrame to be initialized
181 // Create application menu bar
184 // Create the toolbars
187 // Create system tray icon and notification
188 createTrayIcon(networkStyle
);
193 // Disable size grip because it looks ugly and nobody needs it
194 statusBar()->setSizeGripEnabled(false);
196 // Status bar notification icons
197 QFrame
*frameBlocks
= new QFrame();
198 frameBlocks
->setContentsMargins(0,0,0,0);
199 frameBlocks
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Preferred
);
200 QHBoxLayout
*frameBlocksLayout
= new QHBoxLayout(frameBlocks
);
201 frameBlocksLayout
->setContentsMargins(3,0,3,0);
202 frameBlocksLayout
->setSpacing(3);
203 unitDisplayControl
= new UnitDisplayStatusBarControl(platformStyle
);
204 labelWalletEncryptionIcon
= new QLabel();
205 labelWalletHDStatusIcon
= new QLabel();
206 connectionsControl
= new GUIUtil::ClickableLabel();
207 labelBlocksIcon
= new GUIUtil::ClickableLabel();
210 frameBlocksLayout
->addStretch();
211 frameBlocksLayout
->addWidget(unitDisplayControl
);
212 frameBlocksLayout
->addStretch();
213 frameBlocksLayout
->addWidget(labelWalletEncryptionIcon
);
214 frameBlocksLayout
->addWidget(labelWalletHDStatusIcon
);
216 frameBlocksLayout
->addStretch();
217 frameBlocksLayout
->addWidget(connectionsControl
);
218 frameBlocksLayout
->addStretch();
219 frameBlocksLayout
->addWidget(labelBlocksIcon
);
220 frameBlocksLayout
->addStretch();
222 // Progress bar and label for blocks download
223 progressBarLabel
= new QLabel();
224 progressBarLabel
->setVisible(false);
225 progressBar
= new GUIUtil::ProgressBar();
226 progressBar
->setAlignment(Qt::AlignCenter
);
227 progressBar
->setVisible(false);
229 // Override style sheet for progress bar for styles that have a segmented progress bar,
230 // as they make the text unreadable (workaround for issue #1071)
231 // See https://qt-project.org/doc/qt-4.8/gallery.html
232 QString curStyle
= QApplication::style()->metaObject()->className();
233 if(curStyle
== "QWindowsStyle" || curStyle
== "QWindowsXPStyle")
235 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; }");
238 statusBar()->addWidget(progressBarLabel
);
239 statusBar()->addWidget(progressBar
);
240 statusBar()->addPermanentWidget(frameBlocks
);
242 // Install event filter to be able to catch status tip events (QEvent::StatusTip)
243 this->installEventFilter(this);
245 // Initially wallet actions should be disabled
246 setWalletActionsEnabled(false);
248 // Subscribe to notifications from core
249 subscribeToCoreSignals();
251 connect(connectionsControl
, SIGNAL(clicked(QPoint
)), this, SLOT(toggleNetworkActive()));
253 modalOverlay
= new ModalOverlay(this->centralWidget());
256 connect(walletFrame
, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay()));
257 connect(labelBlocksIcon
, SIGNAL(clicked(QPoint
)), this, SLOT(showModalOverlay()));
258 connect(progressBar
, SIGNAL(clicked(QPoint
)), this, SLOT(showModalOverlay()));
263 BitcoinGUI::~BitcoinGUI()
265 // Unsubscribe from notifications from core
266 unsubscribeFromCoreSignals();
269 settings
.setValue("MainWindowGeometry", saveGeometry());
270 if(trayIcon
) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
274 MacDockIconHandler::cleanup();
280 void BitcoinGUI::createActions()
282 QActionGroup
*tabGroup
= new QActionGroup(this);
284 overviewAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
285 overviewAction
->setStatusTip(tr("Show general overview of wallet"));
286 overviewAction
->setToolTip(overviewAction
->statusTip());
287 overviewAction
->setCheckable(true);
288 overviewAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_1
));
289 tabGroup
->addAction(overviewAction
);
291 sendCoinsAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/send"), tr("&Send"), this);
292 sendCoinsAction
->setStatusTip(tr("Send coins to a Bitcoin address"));
293 sendCoinsAction
->setToolTip(sendCoinsAction
->statusTip());
294 sendCoinsAction
->setCheckable(true);
295 sendCoinsAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_2
));
296 tabGroup
->addAction(sendCoinsAction
);
298 sendCoinsMenuAction
= new QAction(platformStyle
->TextColorIcon(":/icons/send"), sendCoinsAction
->text(), this);
299 sendCoinsMenuAction
->setStatusTip(sendCoinsAction
->statusTip());
300 sendCoinsMenuAction
->setToolTip(sendCoinsMenuAction
->statusTip());
302 receiveCoinsAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
303 receiveCoinsAction
->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
304 receiveCoinsAction
->setToolTip(receiveCoinsAction
->statusTip());
305 receiveCoinsAction
->setCheckable(true);
306 receiveCoinsAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_3
));
307 tabGroup
->addAction(receiveCoinsAction
);
309 receiveCoinsMenuAction
= new QAction(platformStyle
->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction
->text(), this);
310 receiveCoinsMenuAction
->setStatusTip(receiveCoinsAction
->statusTip());
311 receiveCoinsMenuAction
->setToolTip(receiveCoinsMenuAction
->statusTip());
313 historyAction
= new QAction(platformStyle
->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
314 historyAction
->setStatusTip(tr("Browse transaction history"));
315 historyAction
->setToolTip(historyAction
->statusTip());
316 historyAction
->setCheckable(true);
317 historyAction
->setShortcut(QKeySequence(Qt::ALT
+ Qt::Key_4
));
318 tabGroup
->addAction(historyAction
);
321 // These showNormalIfMinimized are needed because Send Coins and Receive Coins
322 // can be triggered from the tray menu, and need to show the GUI to be useful.
323 connect(overviewAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
324 connect(overviewAction
, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
325 connect(sendCoinsAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
326 connect(sendCoinsAction
, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
327 connect(sendCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
328 connect(sendCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
329 connect(receiveCoinsAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
330 connect(receiveCoinsAction
, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
331 connect(receiveCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
332 connect(receiveCoinsMenuAction
, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
333 connect(historyAction
, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
334 connect(historyAction
, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
335 #endif // ENABLE_WALLET
337 quitAction
= new QAction(platformStyle
->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
338 quitAction
->setStatusTip(tr("Quit application"));
339 quitAction
->setShortcut(QKeySequence(Qt::CTRL
+ Qt::Key_Q
));
340 quitAction
->setMenuRole(QAction::QuitRole
);
341 aboutAction
= new QAction(platformStyle
->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME
)), this);
342 aboutAction
->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME
)));
343 aboutAction
->setMenuRole(QAction::AboutRole
);
344 aboutAction
->setEnabled(false);
345 aboutQtAction
= new QAction(platformStyle
->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
346 aboutQtAction
->setStatusTip(tr("Show information about Qt"));
347 aboutQtAction
->setMenuRole(QAction::AboutQtRole
);
348 optionsAction
= new QAction(platformStyle
->TextColorIcon(":/icons/options"), tr("&Options..."), this);
349 optionsAction
->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME
)));
350 optionsAction
->setMenuRole(QAction::PreferencesRole
);
351 optionsAction
->setEnabled(false);
352 toggleHideAction
= new QAction(platformStyle
->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
353 toggleHideAction
->setStatusTip(tr("Show or hide the main Window"));
355 encryptWalletAction
= new QAction(platformStyle
->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
356 encryptWalletAction
->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
357 encryptWalletAction
->setCheckable(true);
358 backupWalletAction
= new QAction(platformStyle
->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
359 backupWalletAction
->setStatusTip(tr("Backup wallet to another location"));
360 changePassphraseAction
= new QAction(platformStyle
->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
361 changePassphraseAction
->setStatusTip(tr("Change the passphrase used for wallet encryption"));
362 signMessageAction
= new QAction(platformStyle
->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
363 signMessageAction
->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
364 verifyMessageAction
= new QAction(platformStyle
->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
365 verifyMessageAction
->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
367 openRPCConsoleAction
= new QAction(platformStyle
->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
368 openRPCConsoleAction
->setStatusTip(tr("Open debugging and diagnostic console"));
369 // initially disable the debug window menu item
370 openRPCConsoleAction
->setEnabled(false);
372 usedSendingAddressesAction
= new QAction(platformStyle
->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
373 usedSendingAddressesAction
->setStatusTip(tr("Show the list of used sending addresses and labels"));
374 usedReceivingAddressesAction
= new QAction(platformStyle
->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
375 usedReceivingAddressesAction
->setStatusTip(tr("Show the list of used receiving addresses and labels"));
377 openAction
= new QAction(platformStyle
->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
378 openAction
->setStatusTip(tr("Open a bitcoin: URI or payment request"));
380 showHelpMessageAction
= new QAction(platformStyle
->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
381 showHelpMessageAction
->setMenuRole(QAction::NoRole
);
382 showHelpMessageAction
->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME
)));
384 connect(quitAction
, SIGNAL(triggered()), qApp
, SLOT(quit()));
385 connect(aboutAction
, SIGNAL(triggered()), this, SLOT(aboutClicked()));
386 connect(aboutQtAction
, SIGNAL(triggered()), qApp
, SLOT(aboutQt()));
387 connect(optionsAction
, SIGNAL(triggered()), this, SLOT(optionsClicked()));
388 connect(toggleHideAction
, SIGNAL(triggered()), this, SLOT(toggleHidden()));
389 connect(showHelpMessageAction
, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked()));
390 connect(openRPCConsoleAction
, SIGNAL(triggered()), this, SLOT(showDebugWindow()));
391 // prevents an open debug window from becoming stuck/unusable on client shutdown
392 connect(quitAction
, SIGNAL(triggered()), rpcConsole
, SLOT(hide()));
397 connect(encryptWalletAction
, SIGNAL(triggered(bool)), walletFrame
, SLOT(encryptWallet(bool)));
398 connect(backupWalletAction
, SIGNAL(triggered()), walletFrame
, SLOT(backupWallet()));
399 connect(changePassphraseAction
, SIGNAL(triggered()), walletFrame
, SLOT(changePassphrase()));
400 connect(signMessageAction
, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
401 connect(verifyMessageAction
, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
402 connect(usedSendingAddressesAction
, SIGNAL(triggered()), walletFrame
, SLOT(usedSendingAddresses()));
403 connect(usedReceivingAddressesAction
, SIGNAL(triggered()), walletFrame
, SLOT(usedReceivingAddresses()));
404 connect(openAction
, SIGNAL(triggered()), this, SLOT(openClicked()));
406 #endif // ENABLE_WALLET
408 new QShortcut(QKeySequence(Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_C
), this, SLOT(showDebugWindowActivateConsole()));
409 new QShortcut(QKeySequence(Qt::CTRL
+ Qt::SHIFT
+ Qt::Key_D
), this, SLOT(showDebugWindow()));
412 void BitcoinGUI::createMenuBar()
415 // Create a decoupled menu bar on Mac which stays even if the window is closed
416 appMenuBar
= new QMenuBar();
418 // Get the main window's menu bar on other platforms
419 appMenuBar
= menuBar();
422 // Configure the menus
423 QMenu
*file
= appMenuBar
->addMenu(tr("&File"));
426 file
->addAction(openAction
);
427 file
->addAction(backupWalletAction
);
428 file
->addAction(signMessageAction
);
429 file
->addAction(verifyMessageAction
);
430 file
->addSeparator();
431 file
->addAction(usedSendingAddressesAction
);
432 file
->addAction(usedReceivingAddressesAction
);
433 file
->addSeparator();
435 file
->addAction(quitAction
);
437 QMenu
*settings
= appMenuBar
->addMenu(tr("&Settings"));
440 settings
->addAction(encryptWalletAction
);
441 settings
->addAction(changePassphraseAction
);
442 settings
->addSeparator();
444 settings
->addAction(optionsAction
);
446 QMenu
*help
= appMenuBar
->addMenu(tr("&Help"));
449 help
->addAction(openRPCConsoleAction
);
451 help
->addAction(showHelpMessageAction
);
452 help
->addSeparator();
453 help
->addAction(aboutAction
);
454 help
->addAction(aboutQtAction
);
457 void BitcoinGUI::createToolBars()
461 QToolBar
*toolbar
= addToolBar(tr("Tabs toolbar"));
462 toolbar
->setContextMenuPolicy(Qt::PreventContextMenu
);
463 toolbar
->setMovable(false);
464 toolbar
->setToolButtonStyle(Qt::ToolButtonTextBesideIcon
);
465 toolbar
->addAction(overviewAction
);
466 toolbar
->addAction(sendCoinsAction
);
467 toolbar
->addAction(receiveCoinsAction
);
468 toolbar
->addAction(historyAction
);
469 overviewAction
->setChecked(true);
473 void BitcoinGUI::setClientModel(ClientModel
*_clientModel
)
475 this->clientModel
= _clientModel
;
478 // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
479 // while the client has not yet fully loaded
480 createTrayIconMenu();
482 // Keep up to date with client
483 updateNetworkState();
484 connect(_clientModel
, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
485 connect(_clientModel
, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
487 modalOverlay
->setKnownBestHeight(_clientModel
->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel
->getHeaderTipTime()));
488 setNumBlocks(_clientModel
->getNumBlocks(), _clientModel
->getLastBlockDate(), _clientModel
->getVerificationProgress(nullptr), false);
489 connect(_clientModel
, SIGNAL(numBlocksChanged(int,QDateTime
,double,bool)), this, SLOT(setNumBlocks(int,QDateTime
,double,bool)));
491 // Receive and report messages from client model
492 connect(_clientModel
, SIGNAL(message(QString
,QString
,unsigned int)), this, SLOT(message(QString
,QString
,unsigned int)));
494 // Show progress dialog
495 connect(_clientModel
, SIGNAL(showProgress(QString
,int)), this, SLOT(showProgress(QString
,int)));
497 rpcConsole
->setClientModel(_clientModel
);
501 walletFrame
->setClientModel(_clientModel
);
503 #endif // ENABLE_WALLET
504 unitDisplayControl
->setOptionsModel(_clientModel
->getOptionsModel());
506 OptionsModel
* optionsModel
= _clientModel
->getOptionsModel();
509 // be aware of the tray icon disable state change reported by the OptionsModel object.
510 connect(optionsModel
,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool)));
512 // initialize the disable state of the tray icon with the current value in the model.
513 setTrayIconVisible(optionsModel
->getHideTrayIcon());
516 // Disable possibility to show main window via action
517 toggleHideAction
->setEnabled(false);
520 // Disable context menu on tray icon
521 trayIconMenu
->clear();
523 // Propagate cleared model to child objects
524 rpcConsole
->setClientModel(nullptr);
528 walletFrame
->setClientModel(nullptr);
530 #endif // ENABLE_WALLET
531 unitDisplayControl
->setOptionsModel(nullptr);
536 bool BitcoinGUI::addWallet(const QString
& name
, WalletModel
*walletModel
)
540 setWalletActionsEnabled(true);
541 return walletFrame
->addWallet(name
, walletModel
);
544 bool BitcoinGUI::setCurrentWallet(const QString
& name
)
548 return walletFrame
->setCurrentWallet(name
);
551 void BitcoinGUI::removeAllWallets()
555 setWalletActionsEnabled(false);
556 walletFrame
->removeAllWallets();
558 #endif // ENABLE_WALLET
560 void BitcoinGUI::setWalletActionsEnabled(bool enabled
)
562 overviewAction
->setEnabled(enabled
);
563 sendCoinsAction
->setEnabled(enabled
);
564 sendCoinsMenuAction
->setEnabled(enabled
);
565 receiveCoinsAction
->setEnabled(enabled
);
566 receiveCoinsMenuAction
->setEnabled(enabled
);
567 historyAction
->setEnabled(enabled
);
568 encryptWalletAction
->setEnabled(enabled
);
569 backupWalletAction
->setEnabled(enabled
);
570 changePassphraseAction
->setEnabled(enabled
);
571 signMessageAction
->setEnabled(enabled
);
572 verifyMessageAction
->setEnabled(enabled
);
573 usedSendingAddressesAction
->setEnabled(enabled
);
574 usedReceivingAddressesAction
->setEnabled(enabled
);
575 openAction
->setEnabled(enabled
);
578 void BitcoinGUI::createTrayIcon(const NetworkStyle
*networkStyle
)
581 trayIcon
= new QSystemTrayIcon(this);
582 QString toolTip
= tr("%1 client").arg(tr(PACKAGE_NAME
)) + " " + networkStyle
->getTitleAddText();
583 trayIcon
->setToolTip(toolTip
);
584 trayIcon
->setIcon(networkStyle
->getTrayAndWindowIcon());
588 notificator
= new Notificator(QApplication::applicationName(), trayIcon
, this);
591 void BitcoinGUI::createTrayIconMenu()
594 // return if trayIcon is unset (only on non-Mac OSes)
598 trayIconMenu
= new QMenu(this);
599 trayIcon
->setContextMenu(trayIconMenu
);
601 connect(trayIcon
, SIGNAL(activated(QSystemTrayIcon::ActivationReason
)),
602 this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason
)));
604 // Note: On Mac, the dock icon is used to provide the tray's functionality.
605 MacDockIconHandler
*dockIconHandler
= MacDockIconHandler::instance();
606 dockIconHandler
->setMainWindow((QMainWindow
*)this);
607 trayIconMenu
= dockIconHandler
->dockMenu();
610 // Configuration of the tray icon (or dock icon) icon menu
611 trayIconMenu
->addAction(toggleHideAction
);
612 trayIconMenu
->addSeparator();
613 trayIconMenu
->addAction(sendCoinsMenuAction
);
614 trayIconMenu
->addAction(receiveCoinsMenuAction
);
615 trayIconMenu
->addSeparator();
616 trayIconMenu
->addAction(signMessageAction
);
617 trayIconMenu
->addAction(verifyMessageAction
);
618 trayIconMenu
->addSeparator();
619 trayIconMenu
->addAction(optionsAction
);
620 trayIconMenu
->addAction(openRPCConsoleAction
);
621 #ifndef Q_OS_MAC // This is built-in on Mac
622 trayIconMenu
->addSeparator();
623 trayIconMenu
->addAction(quitAction
);
628 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason
)
630 if(reason
== QSystemTrayIcon::Trigger
)
632 // Click on system tray icon triggers show/hide of the main window
638 void BitcoinGUI::optionsClicked()
640 if(!clientModel
|| !clientModel
->getOptionsModel())
643 OptionsDialog
dlg(this, enableWallet
);
644 dlg
.setModel(clientModel
->getOptionsModel());
648 void BitcoinGUI::aboutClicked()
653 HelpMessageDialog
dlg(this, true);
657 void BitcoinGUI::showDebugWindow()
659 rpcConsole
->showNormal();
662 rpcConsole
->activateWindow();
665 void BitcoinGUI::showDebugWindowActivateConsole()
667 rpcConsole
->setTabFocus(RPCConsole::TAB_CONSOLE
);
671 void BitcoinGUI::showHelpMessageClicked()
673 helpMessageDialog
->show();
677 void BitcoinGUI::openClicked()
679 OpenURIDialog
dlg(this);
682 Q_EMIT
receivedURI(dlg
.getURI());
686 void BitcoinGUI::gotoOverviewPage()
688 overviewAction
->setChecked(true);
689 if (walletFrame
) walletFrame
->gotoOverviewPage();
692 void BitcoinGUI::gotoHistoryPage()
694 historyAction
->setChecked(true);
695 if (walletFrame
) walletFrame
->gotoHistoryPage();
698 void BitcoinGUI::gotoReceiveCoinsPage()
700 receiveCoinsAction
->setChecked(true);
701 if (walletFrame
) walletFrame
->gotoReceiveCoinsPage();
704 void BitcoinGUI::gotoSendCoinsPage(QString addr
)
706 sendCoinsAction
->setChecked(true);
707 if (walletFrame
) walletFrame
->gotoSendCoinsPage(addr
);
710 void BitcoinGUI::gotoSignMessageTab(QString addr
)
712 if (walletFrame
) walletFrame
->gotoSignMessageTab(addr
);
715 void BitcoinGUI::gotoVerifyMessageTab(QString addr
)
717 if (walletFrame
) walletFrame
->gotoVerifyMessageTab(addr
);
719 #endif // ENABLE_WALLET
721 void BitcoinGUI::updateNetworkState()
723 int count
= clientModel
->getNumConnections();
727 case 0: icon
= ":/icons/connect_0"; break;
728 case 1: case 2: case 3: icon
= ":/icons/connect_1"; break;
729 case 4: case 5: case 6: icon
= ":/icons/connect_2"; break;
730 case 7: case 8: case 9: icon
= ":/icons/connect_3"; break;
731 default: icon
= ":/icons/connect_4"; break;
736 if (clientModel
->getNetworkActive()) {
737 tooltip
= tr("%n active connection(s) to Bitcoin network", "", count
) + QString(".<br>") + tr("Click to disable network activity.");
739 tooltip
= tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
740 icon
= ":/icons/network_disabled";
743 // Don't word-wrap this (fixed-width) tooltip
744 tooltip
= QString("<nobr>") + tooltip
+ QString("</nobr>");
745 connectionsControl
->setToolTip(tooltip
);
747 connectionsControl
->setPixmap(platformStyle
->SingleColorIcon(icon
).pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
750 void BitcoinGUI::setNumConnections(int count
)
752 updateNetworkState();
755 void BitcoinGUI::setNetworkActive(bool networkActive
)
757 updateNetworkState();
760 void BitcoinGUI::updateHeadersSyncProgressLabel()
762 int64_t headersTipTime
= clientModel
->getHeaderTipTime();
763 int headersTipHeight
= clientModel
->getHeaderTipHeight();
764 int estHeadersLeft
= (GetTime() - headersTipTime
) / Params().GetConsensus().nPowTargetSpacing
;
765 if (estHeadersLeft
> HEADER_HEIGHT_DELTA_SYNC
)
766 progressBarLabel
->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight
+estHeadersLeft
)*headersTipHeight
, 'f', 1)));
769 void BitcoinGUI::setNumBlocks(int count
, const QDateTime
& blockDate
, double nVerificationProgress
, bool header
)
774 modalOverlay
->setKnownBestHeight(count
, blockDate
);
776 modalOverlay
->tipUpdate(count
, blockDate
, nVerificationProgress
);
781 // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbled text)
782 statusBar()->clearMessage();
784 // Acquire current block source
785 enum BlockSource blockSource
= clientModel
->getBlockSource();
786 switch (blockSource
) {
787 case BLOCK_SOURCE_NETWORK
:
789 updateHeadersSyncProgressLabel();
792 progressBarLabel
->setText(tr("Synchronizing with network..."));
793 updateHeadersSyncProgressLabel();
795 case BLOCK_SOURCE_DISK
:
797 progressBarLabel
->setText(tr("Indexing blocks on disk..."));
799 progressBarLabel
->setText(tr("Processing blocks on disk..."));
802 case BLOCK_SOURCE_REINDEX
:
803 progressBarLabel
->setText(tr("Reindexing blocks on disk..."));
805 case BLOCK_SOURCE_NONE
:
809 progressBarLabel
->setText(tr("Connecting to peers..."));
815 QDateTime currentDate
= QDateTime::currentDateTime();
816 qint64 secs
= blockDate
.secsTo(currentDate
);
818 tooltip
= tr("Processed %n block(s) of transaction history.", "", count
);
820 // Set icon state: spinning if catching up, tick otherwise
823 tooltip
= tr("Up to date") + QString(".<br>") + tooltip
;
824 labelBlocksIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE
, STATUSBAR_ICONSIZE
));
829 walletFrame
->showOutOfSyncWarning(false);
830 modalOverlay
->showHide(true, true);
832 #endif // ENABLE_WALLET
834 progressBarLabel
->setVisible(false);
835 progressBar
->setVisible(false);
839 QString timeBehindText
= GUIUtil::formatNiceTimeOffset(secs
);
841 progressBarLabel
->setVisible(true);
842 progressBar
->setFormat(tr("%1 behind").arg(timeBehindText
));
843 progressBar
->setMaximum(1000000000);
844 progressBar
->setValue(nVerificationProgress
* 1000000000.0 + 0.5);
845 progressBar
->setVisible(true);
847 tooltip
= tr("Catching up...") + QString("<br>") + tooltip
;
848 if(count
!= prevBlocks
)
850 labelBlocksIcon
->setPixmap(platformStyle
->SingleColorIcon(QString(
851 ":/movies/spinner-%1").arg(spinnerFrame
, 3, 10, QChar('0')))
852 .pixmap(STATUSBAR_ICONSIZE
, STATUSBAR_ICONSIZE
));
853 spinnerFrame
= (spinnerFrame
+ 1) % SPINNER_FRAMES
;
860 walletFrame
->showOutOfSyncWarning(true);
861 modalOverlay
->showHide();
863 #endif // ENABLE_WALLET
865 tooltip
+= QString("<br>");
866 tooltip
+= tr("Last received block was generated %1 ago.").arg(timeBehindText
);
867 tooltip
+= QString("<br>");
868 tooltip
+= tr("Transactions after this will not yet be visible.");
871 // Don't word-wrap this (fixed-width) tooltip
872 tooltip
= QString("<nobr>") + tooltip
+ QString("</nobr>");
874 labelBlocksIcon
->setToolTip(tooltip
);
875 progressBarLabel
->setToolTip(tooltip
);
876 progressBar
->setToolTip(tooltip
);
879 void BitcoinGUI::message(const QString
&title
, const QString
&message
, unsigned int style
, bool *ret
)
881 QString strTitle
= tr("Bitcoin"); // default title
882 // Default to information icon
883 int nMBoxIcon
= QMessageBox::Information
;
884 int nNotifyIcon
= Notificator::Information
;
888 // Prefer supplied title over style based title
889 if (!title
.isEmpty()) {
894 case CClientUIInterface::MSG_ERROR
:
895 msgType
= tr("Error");
897 case CClientUIInterface::MSG_WARNING
:
898 msgType
= tr("Warning");
900 case CClientUIInterface::MSG_INFORMATION
:
901 msgType
= tr("Information");
907 // Append title to "Bitcoin - "
908 if (!msgType
.isEmpty())
909 strTitle
+= " - " + msgType
;
911 // Check for error/warning icon
912 if (style
& CClientUIInterface::ICON_ERROR
) {
913 nMBoxIcon
= QMessageBox::Critical
;
914 nNotifyIcon
= Notificator::Critical
;
916 else if (style
& CClientUIInterface::ICON_WARNING
) {
917 nMBoxIcon
= QMessageBox::Warning
;
918 nNotifyIcon
= Notificator::Warning
;
922 if (style
& CClientUIInterface::MODAL
) {
923 // Check for buttons, use OK as default, if none was supplied
924 QMessageBox::StandardButton buttons
;
925 if (!(buttons
= (QMessageBox::StandardButton
)(style
& CClientUIInterface::BTN_MASK
)))
926 buttons
= QMessageBox::Ok
;
928 showNormalIfMinimized();
929 QMessageBox
mBox((QMessageBox::Icon
)nMBoxIcon
, strTitle
, message
, buttons
, this);
932 *ret
= r
== QMessageBox::Ok
;
935 notificator
->notify((Notificator::Class
)nNotifyIcon
, strTitle
, message
);
938 void BitcoinGUI::changeEvent(QEvent
*e
)
940 QMainWindow::changeEvent(e
);
941 #ifndef Q_OS_MAC // Ignored on Mac
942 if(e
->type() == QEvent::WindowStateChange
)
944 if(clientModel
&& clientModel
->getOptionsModel() && clientModel
->getOptionsModel()->getMinimizeToTray())
946 QWindowStateChangeEvent
*wsevt
= static_cast<QWindowStateChangeEvent
*>(e
);
947 if(!(wsevt
->oldState() & Qt::WindowMinimized
) && isMinimized())
949 QTimer::singleShot(0, this, SLOT(hide()));
957 void BitcoinGUI::closeEvent(QCloseEvent
*event
)
959 #ifndef Q_OS_MAC // Ignored on Mac
960 if(clientModel
&& clientModel
->getOptionsModel())
962 if(!clientModel
->getOptionsModel()->getMinimizeOnClose())
964 // close rpcConsole in case it was open to make some space for the shutdown window
967 QApplication::quit();
971 QMainWindow::showMinimized();
976 QMainWindow::closeEvent(event
);
980 void BitcoinGUI::showEvent(QShowEvent
*event
)
982 // enable the debug window when the main window shows up
983 openRPCConsoleAction
->setEnabled(true);
984 aboutAction
->setEnabled(true);
985 optionsAction
->setEnabled(true);
989 void BitcoinGUI::incomingTransaction(const QString
& date
, int unit
, const CAmount
& amount
, const QString
& type
, const QString
& address
, const QString
& label
)
991 // On new transaction, make an info balloon
992 QString msg
= tr("Date: %1\n").arg(date
) +
993 tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit
, amount
, true)) +
994 tr("Type: %1\n").arg(type
);
995 if (!label
.isEmpty())
996 msg
+= tr("Label: %1\n").arg(label
);
997 else if (!address
.isEmpty())
998 msg
+= tr("Address: %1\n").arg(address
);
999 message((amount
)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
1000 msg
, CClientUIInterface::MSG_INFORMATION
);
1002 #endif // ENABLE_WALLET
1004 void BitcoinGUI::dragEnterEvent(QDragEnterEvent
*event
)
1007 if(event
->mimeData()->hasUrls())
1008 event
->acceptProposedAction();
1011 void BitcoinGUI::dropEvent(QDropEvent
*event
)
1013 if(event
->mimeData()->hasUrls())
1015 for (const QUrl
&uri
: event
->mimeData()->urls())
1017 Q_EMIT
receivedURI(uri
.toString());
1020 event
->acceptProposedAction();
1023 bool BitcoinGUI::eventFilter(QObject
*object
, QEvent
*event
)
1025 // Catch status tip events
1026 if (event
->type() == QEvent::StatusTip
)
1028 // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
1029 if (progressBarLabel
->isVisible() || progressBar
->isVisible())
1032 return QMainWindow::eventFilter(object
, event
);
1035 #ifdef ENABLE_WALLET
1036 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient
& recipient
)
1038 // URI has to be valid
1039 if (walletFrame
&& walletFrame
->handlePaymentRequest(recipient
))
1041 showNormalIfMinimized();
1042 gotoSendCoinsPage();
1048 void BitcoinGUI::setHDStatus(int hdEnabled
)
1050 labelWalletHDStatusIcon
->setPixmap(platformStyle
->SingleColorIcon(hdEnabled
? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1051 labelWalletHDStatusIcon
->setToolTip(hdEnabled
? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
1053 // eventually disable the QLabel to set its opacity to 50%
1054 labelWalletHDStatusIcon
->setEnabled(hdEnabled
);
1057 void BitcoinGUI::setEncryptionStatus(int status
)
1061 case WalletModel::Unencrypted
:
1062 labelWalletEncryptionIcon
->hide();
1063 encryptWalletAction
->setChecked(false);
1064 changePassphraseAction
->setEnabled(false);
1065 encryptWalletAction
->setEnabled(true);
1067 case WalletModel::Unlocked
:
1068 labelWalletEncryptionIcon
->show();
1069 labelWalletEncryptionIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1070 labelWalletEncryptionIcon
->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
1071 encryptWalletAction
->setChecked(true);
1072 changePassphraseAction
->setEnabled(true);
1073 encryptWalletAction
->setEnabled(false); // TODO: decrypt currently not supported
1075 case WalletModel::Locked
:
1076 labelWalletEncryptionIcon
->show();
1077 labelWalletEncryptionIcon
->setPixmap(platformStyle
->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE
,STATUSBAR_ICONSIZE
));
1078 labelWalletEncryptionIcon
->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
1079 encryptWalletAction
->setChecked(true);
1080 changePassphraseAction
->setEnabled(true);
1081 encryptWalletAction
->setEnabled(false); // TODO: decrypt currently not supported
1085 #endif // ENABLE_WALLET
1087 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden
)
1092 // activateWindow() (sometimes) helps with keyboard focus on Windows
1098 else if (isMinimized())
1103 else if (GUIUtil::isObscured(this))
1108 else if(fToggleHidden
)
1112 void BitcoinGUI::toggleHidden()
1114 showNormalIfMinimized(true);
1117 void BitcoinGUI::detectShutdown()
1119 if (ShutdownRequested())
1127 void BitcoinGUI::showProgress(const QString
&title
, int nProgress
)
1131 progressDialog
= new QProgressDialog(title
, "", 0, 100);
1132 progressDialog
->setWindowModality(Qt::ApplicationModal
);
1133 progressDialog
->setMinimumDuration(0);
1134 progressDialog
->setCancelButton(0);
1135 progressDialog
->setAutoClose(false);
1136 progressDialog
->setValue(0);
1138 else if (nProgress
== 100)
1142 progressDialog
->close();
1143 progressDialog
->deleteLater();
1146 else if (progressDialog
)
1147 progressDialog
->setValue(nProgress
);
1150 void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon
)
1154 trayIcon
->setVisible(!fHideTrayIcon
);
1158 void BitcoinGUI::showModalOverlay()
1160 if (modalOverlay
&& (progressBar
->isVisible() || modalOverlay
->isLayerVisible()))
1161 modalOverlay
->toggleVisibility();
1164 static bool ThreadSafeMessageBox(BitcoinGUI
*gui
, const std::string
& message
, const std::string
& caption
, unsigned int style
)
1166 bool modal
= (style
& CClientUIInterface::MODAL
);
1167 // The SECURE flag has no effect in the Qt GUI.
1168 // bool secure = (style & CClientUIInterface::SECURE);
1169 style
&= ~CClientUIInterface::SECURE
;
1171 // In case of modal message, use blocking connection to wait for user to click a button
1172 QMetaObject::invokeMethod(gui
, "message",
1173 modal
? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection
,
1174 Q_ARG(QString
, QString::fromStdString(caption
)),
1175 Q_ARG(QString
, QString::fromStdString(message
)),
1176 Q_ARG(unsigned int, style
),
1177 Q_ARG(bool*, &ret
));
1181 void BitcoinGUI::subscribeToCoreSignals()
1183 // Connect signals to client
1184 uiInterface
.ThreadSafeMessageBox
.connect(boost::bind(ThreadSafeMessageBox
, this, _1
, _2
, _3
));
1185 uiInterface
.ThreadSafeQuestion
.connect(boost::bind(ThreadSafeMessageBox
, this, _1
, _3
, _4
));
1188 void BitcoinGUI::unsubscribeFromCoreSignals()
1190 // Disconnect signals from client
1191 uiInterface
.ThreadSafeMessageBox
.disconnect(boost::bind(ThreadSafeMessageBox
, this, _1
, _2
, _3
));
1192 uiInterface
.ThreadSafeQuestion
.disconnect(boost::bind(ThreadSafeMessageBox
, this, _1
, _3
, _4
));
1195 void BitcoinGUI::toggleNetworkActive()
1198 clientModel
->setNetworkActive(!clientModel
->getNetworkActive());
1202 UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle
*platformStyle
) :
1206 createContextMenu();
1207 setToolTip(tr("Unit to show amounts in. Click to select another unit."));
1208 QList
<BitcoinUnits::Unit
> units
= BitcoinUnits::availableUnits();
1210 const QFontMetrics
fm(font());
1211 for (const BitcoinUnits::Unit unit
: units
)
1213 max_width
= qMax(max_width
, fm
.width(BitcoinUnits::name(unit
)));
1215 setMinimumSize(max_width
, 0);
1216 setAlignment(Qt::AlignRight
| Qt::AlignVCenter
);
1217 setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle
->SingleColor().name()));
1220 /** So that it responds to button clicks */
1221 void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent
*event
)
1223 onDisplayUnitsClicked(event
->pos());
1226 /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
1227 void UnitDisplayStatusBarControl::createContextMenu()
1229 menu
= new QMenu(this);
1230 for (BitcoinUnits::Unit u
: BitcoinUnits::availableUnits())
1232 QAction
*menuAction
= new QAction(QString(BitcoinUnits::name(u
)), this);
1233 menuAction
->setData(QVariant(u
));
1234 menu
->addAction(menuAction
);
1236 connect(menu
,SIGNAL(triggered(QAction
*)),this,SLOT(onMenuSelection(QAction
*)));
1239 /** Lets the control know about the Options Model (and its signals) */
1240 void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel
*_optionsModel
)
1244 this->optionsModel
= _optionsModel
;
1246 // be aware of a display unit change reported by the OptionsModel object.
1247 connect(_optionsModel
,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
1249 // initialize the display units label with the current value in the model.
1250 updateDisplayUnit(_optionsModel
->getDisplayUnit());
1254 /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
1255 void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits
)
1257 setText(BitcoinUnits::name(newUnits
));
1260 /** Shows context menu with Display Unit options by the mouse coordinates */
1261 void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint
& point
)
1263 QPoint globalPos
= mapToGlobal(point
);
1264 menu
->exec(globalPos
);
1267 /** Tells underlying optionsModel to update its current display unit. */
1268 void UnitDisplayStatusBarControl::onMenuSelection(QAction
* action
)
1272 optionsModel
->setDisplayUnit(action
->data());