Bitcoin Core  0.19.99
P2P Digital Currency
bitcoingui.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2020 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.
4 
5 #include <qt/bitcoingui.h>
6 
7 #include <qt/bitcoinunits.h>
8 #include <qt/clientmodel.h>
10 #include <qt/guiconstants.h>
11 #include <qt/guiutil.h>
12 #include <qt/modaloverlay.h>
13 #include <qt/networkstyle.h>
14 #include <qt/notificator.h>
15 #include <qt/openuridialog.h>
16 #include <qt/optionsdialog.h>
17 #include <qt/optionsmodel.h>
18 #include <qt/platformstyle.h>
19 #include <qt/rpcconsole.h>
20 #include <qt/utilitydialog.h>
21 
22 #ifdef ENABLE_WALLET
23 #include <qt/walletcontroller.h>
24 #include <qt/walletframe.h>
25 #include <qt/walletmodel.h>
26 #include <qt/walletview.h>
27 #endif // ENABLE_WALLET
28 
29 #ifdef Q_OS_MAC
30 #include <qt/macdockiconhandler.h>
31 #endif
32 
33 #include <chain.h>
34 #include <chainparams.h>
35 #include <interfaces/handler.h>
36 #include <interfaces/node.h>
37 #include <ui_interface.h>
38 #include <util/system.h>
39 
40 #include <QAction>
41 #include <QApplication>
42 #include <QComboBox>
43 #include <QDateTime>
44 #include <QDragEnterEvent>
45 #include <QListWidget>
46 #include <QMenu>
47 #include <QMenuBar>
48 #include <QMessageBox>
49 #include <QMimeData>
50 #include <QProgressDialog>
51 #include <QScreen>
52 #include <QSettings>
53 #include <QShortcut>
54 #include <QStackedWidget>
55 #include <QStatusBar>
56 #include <QStyle>
57 #include <QSystemTrayIcon>
58 #include <QTimer>
59 #include <QToolBar>
60 #include <QUrlQuery>
61 #include <QVBoxLayout>
62 #include <QWindow>
63 
64 
65 const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
66 #if defined(Q_OS_MAC)
67  "macosx"
68 #elif defined(Q_OS_WIN)
69  "windows"
70 #else
71  "other"
72 #endif
73  ;
74 
75 BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
76  QMainWindow(parent),
77  m_node(node),
78  trayIconMenu{new QMenu()},
79  platformStyle(_platformStyle),
80  m_network_style(networkStyle)
81 {
82  QSettings settings;
83  if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
84  // Restore failed (perhaps missing setting), center the window
85  move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center());
86  }
87 
88 #ifdef ENABLE_WALLET
90 #endif // ENABLE_WALLET
91  QApplication::setWindowIcon(m_network_style->getTrayAndWindowIcon());
92  setWindowIcon(m_network_style->getTrayAndWindowIcon());
94 
95  rpcConsole = new RPCConsole(node, _platformStyle, nullptr);
96  helpMessageDialog = new HelpMessageDialog(node, this, false);
97 #ifdef ENABLE_WALLET
98  if(enableWallet)
99  {
101  walletFrame = new WalletFrame(_platformStyle, this);
102  setCentralWidget(walletFrame);
103  } else
104 #endif // ENABLE_WALLET
105  {
106  /* When compiled without wallet or -disablewallet is provided,
107  * the central widget is the rpc console.
108  */
109  setCentralWidget(rpcConsole);
110  Q_EMIT consoleShown(rpcConsole);
111  }
112 
113  // Accept D&D of URIs
114  setAcceptDrops(true);
115 
116  // Create actions for the toolbar, menu bar and tray/dock icon
117  // Needs walletFrame to be initialized
118  createActions();
119 
120  // Create application menu bar
121  createMenuBar();
122 
123  // Create the toolbars
124  createToolBars();
125 
126  // Create system tray icon and notification
127  if (QSystemTrayIcon::isSystemTrayAvailable()) {
128  createTrayIcon();
129  }
130  notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
131 
132  // Create status bar
133  statusBar();
134 
135  // Disable size grip because it looks ugly and nobody needs it
136  statusBar()->setSizeGripEnabled(false);
137 
138  // Status bar notification icons
139  QFrame *frameBlocks = new QFrame();
140  frameBlocks->setContentsMargins(0,0,0,0);
141  frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
142  QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
143  frameBlocksLayout->setContentsMargins(3,0,3,0);
144  frameBlocksLayout->setSpacing(3);
146  labelWalletEncryptionIcon = new QLabel();
147  labelWalletHDStatusIcon = new QLabel();
151  if(enableWallet)
152  {
153  frameBlocksLayout->addStretch();
154  frameBlocksLayout->addWidget(unitDisplayControl);
155  frameBlocksLayout->addStretch();
156  frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
157  frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
158  }
159  frameBlocksLayout->addWidget(labelProxyIcon);
160  frameBlocksLayout->addStretch();
161  frameBlocksLayout->addWidget(connectionsControl);
162  frameBlocksLayout->addStretch();
163  frameBlocksLayout->addWidget(labelBlocksIcon);
164  frameBlocksLayout->addStretch();
165 
166  // Progress bar and label for blocks download
167  progressBarLabel = new QLabel();
168  progressBarLabel->setVisible(false);
170  progressBar->setAlignment(Qt::AlignCenter);
171  progressBar->setVisible(false);
172 
173  // Override style sheet for progress bar for styles that have a segmented progress bar,
174  // as they make the text unreadable (workaround for issue #1071)
175  // See https://doc.qt.io/qt-5/gallery.html
176  QString curStyle = QApplication::style()->metaObject()->className();
177  if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
178  {
179  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; }");
180  }
181 
182  statusBar()->addWidget(progressBarLabel);
183  statusBar()->addWidget(progressBar);
184  statusBar()->addPermanentWidget(frameBlocks);
185 
186  // Install event filter to be able to catch status tip events (QEvent::StatusTip)
187  this->installEventFilter(this);
188 
189  // Initially wallet actions should be disabled
191 
192  // Subscribe to notifications from core
194 
197  });
200  });
201 
202  modalOverlay = new ModalOverlay(enableWallet, this->centralWidget());
205 #ifdef ENABLE_WALLET
206  if(enableWallet) {
208  }
209 #endif
210 
211 #ifdef Q_OS_MAC
212  m_app_nap_inhibitor = new CAppNapInhibitor;
213 #endif
214 }
215 
217 {
218  // Unsubscribe from notifications from core
220 
221  QSettings settings;
222  settings.setValue("MainWindowGeometry", saveGeometry());
223  if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
224  trayIcon->hide();
225 #ifdef Q_OS_MAC
226  delete m_app_nap_inhibitor;
227  delete appMenuBar;
229 #endif
230 
231  delete rpcConsole;
232 }
233 
235 {
236  QActionGroup *tabGroup = new QActionGroup(this);
237 
238  overviewAction = new QAction(platformStyle->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
239  overviewAction->setStatusTip(tr("Show general overview of wallet"));
240  overviewAction->setToolTip(overviewAction->statusTip());
241  overviewAction->setCheckable(true);
242  overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
243  tabGroup->addAction(overviewAction);
244 
245  sendCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this);
246  sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
247  sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
248  sendCoinsAction->setCheckable(true);
249  sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
250  tabGroup->addAction(sendCoinsAction);
251 
252  sendCoinsMenuAction = new QAction(sendCoinsAction->text(), this);
253  sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
254  sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
255 
256  receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
257  receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
258  receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
259  receiveCoinsAction->setCheckable(true);
260  receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
261  tabGroup->addAction(receiveCoinsAction);
262 
263  receiveCoinsMenuAction = new QAction(receiveCoinsAction->text(), this);
264  receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
265  receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
266 
267  historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
268  historyAction->setStatusTip(tr("Browse transaction history"));
269  historyAction->setToolTip(historyAction->statusTip());
270  historyAction->setCheckable(true);
271  historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
272  tabGroup->addAction(historyAction);
273 
274 #ifdef ENABLE_WALLET
275  // These showNormalIfMinimized are needed because Send Coins and Receive Coins
276  // can be triggered from the tray menu, and need to show the GUI to be useful.
277  connect(overviewAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
278  connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage);
279  connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
280  connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
281  connect(sendCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
282  connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
283  connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
284  connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
285  connect(receiveCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
286  connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
287  connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
288  connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
289 #endif // ENABLE_WALLET
290 
291  quitAction = new QAction(tr("E&xit"), this);
292  quitAction->setStatusTip(tr("Quit application"));
293  quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
294  quitAction->setMenuRole(QAction::QuitRole);
295  aboutAction = new QAction(tr("&About %1").arg(PACKAGE_NAME), this);
296  aboutAction->setStatusTip(tr("Show information about %1").arg(PACKAGE_NAME));
297  aboutAction->setMenuRole(QAction::AboutRole);
298  aboutAction->setEnabled(false);
299  aboutQtAction = new QAction(tr("About &Qt"), this);
300  aboutQtAction->setStatusTip(tr("Show information about Qt"));
301  aboutQtAction->setMenuRole(QAction::AboutQtRole);
302  optionsAction = new QAction(tr("&Options..."), this);
303  optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME));
304  optionsAction->setMenuRole(QAction::PreferencesRole);
305  optionsAction->setEnabled(false);
306  toggleHideAction = new QAction(tr("&Show / Hide"), this);
307  toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
308 
309  encryptWalletAction = new QAction(tr("&Encrypt Wallet..."), this);
310  encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
311  encryptWalletAction->setCheckable(true);
312  backupWalletAction = new QAction(tr("&Backup Wallet..."), this);
313  backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
314  changePassphraseAction = new QAction(tr("&Change Passphrase..."), this);
315  changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
316  signMessageAction = new QAction(tr("Sign &message..."), this);
317  signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
318  verifyMessageAction = new QAction(tr("&Verify message..."), this);
319  verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
320 
321  openRPCConsoleAction = new QAction(tr("Node window"), this);
322  openRPCConsoleAction->setStatusTip(tr("Open node debugging and diagnostic console"));
323  // initially disable the debug window menu item
324  openRPCConsoleAction->setEnabled(false);
325  openRPCConsoleAction->setObjectName("openRPCConsoleAction");
326 
327  usedSendingAddressesAction = new QAction(tr("&Sending addresses"), this);
328  usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
329  usedReceivingAddressesAction = new QAction(tr("&Receiving addresses"), this);
330  usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
331 
332  openAction = new QAction(tr("Open &URI..."), this);
333  openAction->setStatusTip(tr("Open a bitcoin: URI"));
334 
335  m_open_wallet_action = new QAction(tr("Open Wallet"), this);
336  m_open_wallet_action->setEnabled(false);
337  m_open_wallet_action->setStatusTip(tr("Open a wallet"));
338  m_open_wallet_menu = new QMenu(this);
339 
340  m_close_wallet_action = new QAction(tr("Close Wallet..."), this);
341  m_close_wallet_action->setStatusTip(tr("Close wallet"));
342 
343  m_create_wallet_action = new QAction(tr("Create Wallet..."), this);
344  m_create_wallet_action->setEnabled(false);
345  m_create_wallet_action->setStatusTip(tr("Create a new wallet"));
346 
347  showHelpMessageAction = new QAction(tr("&Command-line options"), this);
348  showHelpMessageAction->setMenuRole(QAction::NoRole);
349  showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME));
350 
351  connect(quitAction, &QAction::triggered, qApp, QApplication::quit);
352  connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
353  connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt);
354  connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked);
355  connect(toggleHideAction, &QAction::triggered, this, &BitcoinGUI::toggleHidden);
356  connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked);
357  connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow);
358  // prevents an open debug window from becoming stuck/unusable on client shutdown
359  connect(quitAction, &QAction::triggered, rpcConsole, &QWidget::hide);
360 
361 #ifdef ENABLE_WALLET
362  if(walletFrame)
363  {
364  connect(encryptWalletAction, &QAction::triggered, walletFrame, &WalletFrame::encryptWallet);
365  connect(backupWalletAction, &QAction::triggered, walletFrame, &WalletFrame::backupWallet);
366  connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase);
367  connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
368  connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); });
369  connect(verifyMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
370  connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); });
373  connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
374  connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] {
375  m_open_wallet_menu->clear();
376  for (const std::pair<const std::string, bool>& i : m_wallet_controller->listWalletDir()) {
377  const std::string& path = i.first;
378  QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
379  // Menu items remove single &. Single & are shown when && is in
380  // the string, but only the first occurrence. So replace only
381  // the first & with &&.
382  name.replace(name.indexOf(QChar('&')), 1, QString("&&"));
383  QAction* action = m_open_wallet_menu->addAction(name);
384 
385  if (i.second) {
386  // This wallet is already loaded
387  action->setEnabled(false);
388  continue;
389  }
390 
391  connect(action, &QAction::triggered, [this, path] {
392  auto activity = new OpenWalletActivity(m_wallet_controller, this);
393  connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet);
394  connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater);
395  activity->open(path);
396  });
397  }
398  if (m_open_wallet_menu->isEmpty()) {
399  QAction* action = m_open_wallet_menu->addAction(tr("No wallets available"));
400  action->setEnabled(false);
401  }
402  });
403  connect(m_close_wallet_action, &QAction::triggered, [this] {
405  });
406  connect(m_create_wallet_action, &QAction::triggered, [this] {
407  auto activity = new CreateWalletActivity(m_wallet_controller, this);
408  connect(activity, &CreateWalletActivity::created, this, &BitcoinGUI::setCurrentWallet);
409  connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
410  activity->create();
411  });
412  }
413 #endif // ENABLE_WALLET
414 
415  connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole);
416  connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow);
417 }
418 
420 {
421 #ifdef Q_OS_MAC
422  // Create a decoupled menu bar on Mac which stays even if the window is closed
423  appMenuBar = new QMenuBar();
424 #else
425  // Get the main window's menu bar on other platforms
426  appMenuBar = menuBar();
427 #endif
428 
429  // Configure the menus
430  QMenu *file = appMenuBar->addMenu(tr("&File"));
431  if(walletFrame)
432  {
433  file->addAction(m_create_wallet_action);
434  file->addAction(m_open_wallet_action);
435  file->addAction(m_close_wallet_action);
436  file->addSeparator();
437  file->addAction(openAction);
438  file->addAction(backupWalletAction);
439  file->addAction(signMessageAction);
440  file->addAction(verifyMessageAction);
441  file->addSeparator();
442  }
443  file->addAction(quitAction);
444 
445  QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
446  if(walletFrame)
447  {
448  settings->addAction(encryptWalletAction);
449  settings->addAction(changePassphraseAction);
450  settings->addSeparator();
451  }
452  settings->addAction(optionsAction);
453 
454  QMenu* window_menu = appMenuBar->addMenu(tr("&Window"));
455 
456  QAction* minimize_action = window_menu->addAction(tr("Minimize"));
457  minimize_action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
458  connect(minimize_action, &QAction::triggered, [] {
459  qApp->focusWindow()->showMinimized();
460  });
461  connect(qApp, &QApplication::focusWindowChanged, [minimize_action] (QWindow* window) {
462  minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized);
463  });
464 
465 #ifdef Q_OS_MAC
466  QAction* zoom_action = window_menu->addAction(tr("Zoom"));
467  connect(zoom_action, &QAction::triggered, [] {
468  QWindow* window = qApp->focusWindow();
469  if (window->windowState() != Qt::WindowMaximized) {
470  window->showMaximized();
471  } else {
472  window->showNormal();
473  }
474  });
475 
476  connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) {
477  zoom_action->setEnabled(window != nullptr);
478  });
479 #endif
480 
481  if (walletFrame) {
482 #ifdef Q_OS_MAC
483  window_menu->addSeparator();
484  QAction* main_window_action = window_menu->addAction(tr("Main Window"));
485  connect(main_window_action, &QAction::triggered, [this] {
486  GUIUtil::bringToFront(this);
487  });
488 #endif
489  window_menu->addSeparator();
490  window_menu->addAction(usedSendingAddressesAction);
491  window_menu->addAction(usedReceivingAddressesAction);
492  }
493 
494  window_menu->addSeparator();
495  for (RPCConsole::TabTypes tab_type : rpcConsole->tabs()) {
496  QAction* tab_action = window_menu->addAction(rpcConsole->tabTitle(tab_type));
497  tab_action->setShortcut(rpcConsole->tabShortcut(tab_type));
498  connect(tab_action, &QAction::triggered, [this, tab_type] {
499  rpcConsole->setTabFocus(tab_type);
500  showDebugWindow();
501  });
502  }
503 
504  QMenu *help = appMenuBar->addMenu(tr("&Help"));
505  help->addAction(showHelpMessageAction);
506  help->addSeparator();
507  help->addAction(aboutAction);
508  help->addAction(aboutQtAction);
509 }
510 
512 {
513  if(walletFrame)
514  {
515  QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
516  appToolBar = toolbar;
517  toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
518  toolbar->setMovable(false);
519  toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
520  toolbar->addAction(overviewAction);
521  toolbar->addAction(sendCoinsAction);
522  toolbar->addAction(receiveCoinsAction);
523  toolbar->addAction(historyAction);
524  overviewAction->setChecked(true);
525 
526 #ifdef ENABLE_WALLET
527  QWidget *spacer = new QWidget();
528  spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
529  toolbar->addWidget(spacer);
530 
531  m_wallet_selector = new QComboBox();
532  m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
533  connect(m_wallet_selector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
534 
535  m_wallet_selector_label = new QLabel();
536  m_wallet_selector_label->setText(tr("Wallet:") + " ");
538 
541 
542  m_wallet_selector_label_action->setVisible(false);
543  m_wallet_selector_action->setVisible(false);
544 #endif
545  }
546 }
547 
549 {
550  this->clientModel = _clientModel;
551  if(_clientModel)
552  {
553  // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
554  // while the client has not yet fully loaded
556 
557  // Keep up to date with client
560  connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive);
561 
562  modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
564  connect(_clientModel, &ClientModel::numBlocksChanged, this, &BitcoinGUI::setNumBlocks);
565 
566  // Receive and report messages from client model
567  connect(_clientModel, &ClientModel::message, [this](const QString &title, const QString &message, unsigned int style){
568  this->message(title, message, style);
569  });
570 
571  // Show progress dialog
572  connect(_clientModel, &ClientModel::showProgress, this, &BitcoinGUI::showProgress);
573 
574  rpcConsole->setClientModel(_clientModel);
575 
576  updateProxyIcon();
577 
578 #ifdef ENABLE_WALLET
579  if(walletFrame)
580  {
581  walletFrame->setClientModel(_clientModel);
582  }
583 #endif // ENABLE_WALLET
585 
586  OptionsModel* optionsModel = _clientModel->getOptionsModel();
587  if (optionsModel && trayIcon) {
588  // be aware of the tray icon disable state change reported by the OptionsModel object.
590 
591  // initialize the disable state of the tray icon with the current value in the model.
592  setTrayIconVisible(optionsModel->getHideTrayIcon());
593  }
594  } else {
595  // Disable possibility to show main window via action
596  toggleHideAction->setEnabled(false);
597  if(trayIconMenu)
598  {
599  // Disable context menu on tray icon
600  trayIconMenu->clear();
601  }
602  // Propagate cleared model to child objects
603  rpcConsole->setClientModel(nullptr);
604 #ifdef ENABLE_WALLET
605  if (walletFrame)
606  {
607  walletFrame->setClientModel(nullptr);
608  }
609 #endif // ENABLE_WALLET
611  }
612 }
613 
614 #ifdef ENABLE_WALLET
615 void BitcoinGUI::setWalletController(WalletController* wallet_controller)
616 {
617  assert(!m_wallet_controller);
618  assert(wallet_controller);
619 
620  m_wallet_controller = wallet_controller;
621 
622  m_create_wallet_action->setEnabled(true);
623  m_open_wallet_action->setEnabled(true);
625 
626  connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
627  connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
628 
629  for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) {
630  addWallet(wallet_model);
631  }
632 }
633 
634 void BitcoinGUI::addWallet(WalletModel* walletModel)
635 {
636  if (!walletFrame) return;
637  if (!walletFrame->addWallet(walletModel)) return;
638  const QString display_name = walletModel->getDisplayName();
640  rpcConsole->addWallet(walletModel);
641  m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
642  if (m_wallet_selector->count() == 2) {
643  m_wallet_selector_label_action->setVisible(true);
644  m_wallet_selector_action->setVisible(true);
645  }
646 }
647 
648 void BitcoinGUI::removeWallet(WalletModel* walletModel)
649 {
650  if (!walletFrame) return;
651 
652  labelWalletHDStatusIcon->hide();
654 
655  int index = m_wallet_selector->findData(QVariant::fromValue(walletModel));
656  m_wallet_selector->removeItem(index);
657  if (m_wallet_selector->count() == 0) {
659  } else if (m_wallet_selector->count() == 1) {
660  m_wallet_selector_label_action->setVisible(false);
661  m_wallet_selector_action->setVisible(false);
662  }
663  rpcConsole->removeWallet(walletModel);
664  walletFrame->removeWallet(walletModel);
666 }
667 
668 void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model)
669 {
670  if (!walletFrame) return;
671  walletFrame->setCurrentWallet(wallet_model);
672  for (int index = 0; index < m_wallet_selector->count(); ++index) {
673  if (m_wallet_selector->itemData(index).value<WalletModel*>() == wallet_model) {
674  m_wallet_selector->setCurrentIndex(index);
675  break;
676  }
677  }
679 }
680 
681 void BitcoinGUI::setCurrentWalletBySelectorIndex(int index)
682 {
683  WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>();
684  if (wallet_model) setCurrentWallet(wallet_model);
685 }
686 
687 void BitcoinGUI::removeAllWallets()
688 {
689  if(!walletFrame)
690  return;
693 }
694 #endif // ENABLE_WALLET
695 
697 {
698  overviewAction->setEnabled(enabled);
699  sendCoinsAction->setEnabled(enabled);
700  sendCoinsMenuAction->setEnabled(enabled);
701  receiveCoinsAction->setEnabled(enabled);
702  receiveCoinsMenuAction->setEnabled(enabled);
703  historyAction->setEnabled(enabled);
704  encryptWalletAction->setEnabled(enabled);
705  backupWalletAction->setEnabled(enabled);
706  changePassphraseAction->setEnabled(enabled);
707  signMessageAction->setEnabled(enabled);
708  verifyMessageAction->setEnabled(enabled);
709  usedSendingAddressesAction->setEnabled(enabled);
710  usedReceivingAddressesAction->setEnabled(enabled);
711  openAction->setEnabled(enabled);
712  m_close_wallet_action->setEnabled(enabled);
713 }
714 
716 {
717  assert(QSystemTrayIcon::isSystemTrayAvailable());
718 
719 #ifndef Q_OS_MAC
720  if (QSystemTrayIcon::isSystemTrayAvailable()) {
721  trayIcon = new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this);
722  QString toolTip = tr("%1 client").arg(PACKAGE_NAME) + " " + m_network_style->getTitleAddText();
723  trayIcon->setToolTip(toolTip);
724  }
725 #endif
726 }
727 
729 {
730 #ifndef Q_OS_MAC
731  // return if trayIcon is unset (only on non-macOSes)
732  if (!trayIcon)
733  return;
734 
735  trayIcon->setContextMenu(trayIconMenu.get());
736  connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated);
737 #else
738  // Note: On macOS, the Dock icon is used to provide the tray's functionality.
740  connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated);
741  trayIconMenu->setAsDockMenu();
742 #endif
743 
744  // Configuration of the tray icon (or Dock icon) menu
745 #ifndef Q_OS_MAC
746  // Note: On macOS, the Dock icon's menu already has Show / Hide action.
747  trayIconMenu->addAction(toggleHideAction);
748  trayIconMenu->addSeparator();
749 #endif
750  if (enableWallet) {
751  trayIconMenu->addAction(sendCoinsMenuAction);
753  trayIconMenu->addSeparator();
754  trayIconMenu->addAction(signMessageAction);
755  trayIconMenu->addAction(verifyMessageAction);
756  trayIconMenu->addSeparator();
757  }
758  trayIconMenu->addAction(optionsAction);
760 #ifndef Q_OS_MAC // This is built-in on macOS
761  trayIconMenu->addSeparator();
762  trayIconMenu->addAction(quitAction);
763 #endif
764 }
765 
766 #ifndef Q_OS_MAC
767 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
768 {
769  if(reason == QSystemTrayIcon::Trigger)
770  {
771  // Click on system tray icon triggers show/hide of the main window
772  toggleHidden();
773  }
774 }
775 #else
776 void BitcoinGUI::macosDockIconActivated()
777 {
778  show();
779  activateWindow();
780 }
781 #endif
782 
784 {
786 }
787 
789 {
790  if(!clientModel)
791  return;
792 
793  HelpMessageDialog dlg(m_node, this, true);
794  dlg.exec();
795 }
796 
798 {
800  Q_EMIT consoleShown(rpcConsole);
801 }
802 
804 {
806  showDebugWindow();
807 }
808 
810 {
811  helpMessageDialog->show();
812 }
813 
814 #ifdef ENABLE_WALLET
815 void BitcoinGUI::openClicked()
816 {
817  OpenURIDialog dlg(this);
818  if(dlg.exec())
819  {
820  Q_EMIT receivedURI(dlg.getURI());
821  }
822 }
823 
824 void BitcoinGUI::gotoOverviewPage()
825 {
826  overviewAction->setChecked(true);
828 }
829 
830 void BitcoinGUI::gotoHistoryPage()
831 {
832  historyAction->setChecked(true);
834 }
835 
836 void BitcoinGUI::gotoReceiveCoinsPage()
837 {
838  receiveCoinsAction->setChecked(true);
840 }
841 
842 void BitcoinGUI::gotoSendCoinsPage(QString addr)
843 {
844  sendCoinsAction->setChecked(true);
846 }
847 
848 void BitcoinGUI::gotoSignMessageTab(QString addr)
849 {
851 }
852 
853 void BitcoinGUI::gotoVerifyMessageTab(QString addr)
854 {
856 }
857 #endif // ENABLE_WALLET
858 
860 {
862  QString icon;
863  switch(count)
864  {
865  case 0: icon = ":/icons/connect_0"; break;
866  case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
867  case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
868  case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
869  default: icon = ":/icons/connect_4"; break;
870  }
871 
872  QString tooltip;
873 
874  if (m_node.getNetworkActive()) {
875  tooltip = tr("%n active connection(s) to Bitcoin network", "", count) + QString(".<br>") + tr("Click to disable network activity.");
876  } else {
877  tooltip = tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again.");
878  icon = ":/icons/network_disabled";
879  }
880 
881  // Don't word-wrap this (fixed-width) tooltip
882  tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
883  connectionsControl->setToolTip(tooltip);
884 
886 }
887 
889 {
891 }
892 
893 void BitcoinGUI::setNetworkActive(bool networkActive)
894 {
896 }
897 
899 {
900  int64_t headersTipTime = clientModel->getHeaderTipTime();
901  int headersTipHeight = clientModel->getHeaderTipHeight();
902  int estHeadersLeft = (GetTime() - headersTipTime) / Params().GetConsensus().nPowTargetSpacing;
903  if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC)
904  progressBarLabel->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight+estHeadersLeft)*headersTipHeight, 'f', 1)));
905 }
906 
908 {
910  return;
911 
912  OptionsDialog dlg(this, enableWallet);
913  dlg.setCurrentTab(tab);
915  dlg.exec();
916 }
917 
918 void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
919 {
920 // Disabling macOS App Nap on initial sync, disk and reindex operations.
921 #ifdef Q_OS_MAC
922  (m_node.isInitialBlockDownload() || m_node.getReindex() || m_node.getImporting()) ? m_app_nap_inhibitor->disableAppNap() : m_app_nap_inhibitor->enableAppNap();
923 #endif
924 
925  if (modalOverlay)
926  {
927  if (header)
928  modalOverlay->setKnownBestHeight(count, blockDate);
929  else
930  modalOverlay->tipUpdate(count, blockDate, nVerificationProgress);
931  }
932  if (!clientModel)
933  return;
934 
935  // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbled text)
936  statusBar()->clearMessage();
937 
938  // Acquire current block source
939  enum BlockSource blockSource = clientModel->getBlockSource();
940  switch (blockSource) {
942  if (header) {
944  return;
945  }
946  progressBarLabel->setText(tr("Synchronizing with network..."));
948  break;
949  case BlockSource::DISK:
950  if (header) {
951  progressBarLabel->setText(tr("Indexing blocks on disk..."));
952  } else {
953  progressBarLabel->setText(tr("Processing blocks on disk..."));
954  }
955  break;
957  progressBarLabel->setText(tr("Reindexing blocks on disk..."));
958  break;
959  case BlockSource::NONE:
960  if (header) {
961  return;
962  }
963  progressBarLabel->setText(tr("Connecting to peers..."));
964  break;
965  }
966 
967  QString tooltip;
968 
969  QDateTime currentDate = QDateTime::currentDateTime();
970  qint64 secs = blockDate.secsTo(currentDate);
971 
972  tooltip = tr("Processed %n block(s) of transaction history.", "", count);
973 
974  // Set icon state: spinning if catching up, tick otherwise
975  if (secs < MAX_BLOCK_TIME_GAP) {
976  tooltip = tr("Up to date") + QString(".<br>") + tooltip;
978 
979 #ifdef ENABLE_WALLET
980  if(walletFrame)
981  {
983  modalOverlay->showHide(true, true);
984  }
985 #endif // ENABLE_WALLET
986 
987  progressBarLabel->setVisible(false);
988  progressBar->setVisible(false);
989  }
990  else
991  {
992  QString timeBehindText = GUIUtil::formatNiceTimeOffset(secs);
993 
994  progressBarLabel->setVisible(true);
995  progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
996  progressBar->setMaximum(1000000000);
997  progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5);
998  progressBar->setVisible(true);
999 
1000  tooltip = tr("Catching up...") + QString("<br>") + tooltip;
1001  if(count != prevBlocks)
1002  {
1003  labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(QString(
1004  ":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')))
1007  }
1008  prevBlocks = count;
1009 
1010 #ifdef ENABLE_WALLET
1011  if(walletFrame)
1012  {
1015  }
1016 #endif // ENABLE_WALLET
1017 
1018  tooltip += QString("<br>");
1019  tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
1020  tooltip += QString("<br>");
1021  tooltip += tr("Transactions after this will not yet be visible.");
1022  }
1023 
1024  // Don't word-wrap this (fixed-width) tooltip
1025  tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
1026 
1027  labelBlocksIcon->setToolTip(tooltip);
1028  progressBarLabel->setToolTip(tooltip);
1029  progressBar->setToolTip(tooltip);
1030 }
1031 
1032 void BitcoinGUI::message(const QString& title, QString message, unsigned int style, bool* ret)
1033 {
1034  // Default title. On macOS, the window title is ignored (as required by the macOS Guidelines).
1035  QString strTitle{PACKAGE_NAME};
1036  // Default to information icon
1037  int nMBoxIcon = QMessageBox::Information;
1038  int nNotifyIcon = Notificator::Information;
1039 
1040  bool prefix = !(style & CClientUIInterface::MSG_NOPREFIX);
1041  style &= ~CClientUIInterface::MSG_NOPREFIX;
1042 
1043  QString msgType;
1044  if (!title.isEmpty()) {
1045  msgType = title;
1046  } else {
1047  switch (style) {
1049  msgType = tr("Error");
1050  if (prefix) message = tr("Error: %1").arg(message);
1051  break;
1053  msgType = tr("Warning");
1054  if (prefix) message = tr("Warning: %1").arg(message);
1055  break;
1057  msgType = tr("Information");
1058  // No need to prepend the prefix here.
1059  break;
1060  default:
1061  break;
1062  }
1063  }
1064 
1065  if (!msgType.isEmpty()) {
1066  strTitle += " - " + msgType;
1067  }
1068 
1069  if (style & CClientUIInterface::ICON_ERROR) {
1070  nMBoxIcon = QMessageBox::Critical;
1071  nNotifyIcon = Notificator::Critical;
1072  } else if (style & CClientUIInterface::ICON_WARNING) {
1073  nMBoxIcon = QMessageBox::Warning;
1074  nNotifyIcon = Notificator::Warning;
1075  }
1076 
1077  if (style & CClientUIInterface::MODAL) {
1078  // Check for buttons, use OK as default, if none was supplied
1079  QMessageBox::StandardButton buttons;
1080  if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK)))
1081  buttons = QMessageBox::Ok;
1082 
1084  QMessageBox mBox(static_cast<QMessageBox::Icon>(nMBoxIcon), strTitle, message, buttons, this);
1085  mBox.setTextFormat(Qt::PlainText);
1086  int r = mBox.exec();
1087  if (ret != nullptr)
1088  *ret = r == QMessageBox::Ok;
1089  } else {
1090  notificator->notify(static_cast<Notificator::Class>(nNotifyIcon), strTitle, message);
1091  }
1092 }
1093 
1095 {
1096  QMainWindow::changeEvent(e);
1097 #ifndef Q_OS_MAC // Ignored on Mac
1098  if(e->type() == QEvent::WindowStateChange)
1099  {
1101  {
1102  QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
1103  if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
1104  {
1105  QTimer::singleShot(0, this, &BitcoinGUI::hide);
1106  e->ignore();
1107  }
1108  else if((wsevt->oldState() & Qt::WindowMinimized) && !isMinimized())
1109  {
1110  QTimer::singleShot(0, this, &BitcoinGUI::show);
1111  e->ignore();
1112  }
1113  }
1114  }
1115 #endif
1116 }
1117 
1118 void BitcoinGUI::closeEvent(QCloseEvent *event)
1119 {
1120 #ifndef Q_OS_MAC // Ignored on Mac
1122  {
1124  {
1125  // close rpcConsole in case it was open to make some space for the shutdown window
1126  rpcConsole->close();
1127 
1128  QApplication::quit();
1129  }
1130  else
1131  {
1132  QMainWindow::showMinimized();
1133  event->ignore();
1134  }
1135  }
1136 #else
1137  QMainWindow::closeEvent(event);
1138 #endif
1139 }
1140 
1141 void BitcoinGUI::showEvent(QShowEvent *event)
1142 {
1143  // enable the debug window when the main window shows up
1144  openRPCConsoleAction->setEnabled(true);
1145  aboutAction->setEnabled(true);
1146  optionsAction->setEnabled(true);
1147 }
1148 
1149 #ifdef ENABLE_WALLET
1150 void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName)
1151 {
1152  // On new transaction, make an info balloon
1153  QString msg = tr("Date: %1\n").arg(date) +
1154  tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true));
1155  if (m_node.getWallets().size() > 1 && !walletName.isEmpty()) {
1156  msg += tr("Wallet: %1\n").arg(walletName);
1157  }
1158  msg += tr("Type: %1\n").arg(type);
1159  if (!label.isEmpty())
1160  msg += tr("Label: %1\n").arg(label);
1161  else if (!address.isEmpty())
1162  msg += tr("Address: %1\n").arg(address);
1163  message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
1165 }
1166 #endif // ENABLE_WALLET
1167 
1168 void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
1169 {
1170  // Accept only URIs
1171  if(event->mimeData()->hasUrls())
1172  event->acceptProposedAction();
1173 }
1174 
1175 void BitcoinGUI::dropEvent(QDropEvent *event)
1176 {
1177  if(event->mimeData()->hasUrls())
1178  {
1179  for (const QUrl &uri : event->mimeData()->urls())
1180  {
1181  Q_EMIT receivedURI(uri.toString());
1182  }
1183  }
1184  event->acceptProposedAction();
1185 }
1186 
1187 bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
1188 {
1189  // Catch status tip events
1190  if (event->type() == QEvent::StatusTip)
1191  {
1192  // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
1193  if (progressBarLabel->isVisible() || progressBar->isVisible())
1194  return true;
1195  }
1196  return QMainWindow::eventFilter(object, event);
1197 }
1198 
1199 #ifdef ENABLE_WALLET
1200 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
1201 {
1202  // URI has to be valid
1203  if (walletFrame && walletFrame->handlePaymentRequest(recipient))
1204  {
1206  gotoSendCoinsPage();
1207  return true;
1208  }
1209  return false;
1210 }
1211 
1212 void BitcoinGUI::setHDStatus(bool privkeyDisabled, int hdEnabled)
1213 {
1214  labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(privkeyDisabled ? ":/icons/eye" : hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
1215  labelWalletHDStatusIcon->setToolTip(privkeyDisabled ? tr("Private key <b>disabled</b>") : hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
1216  labelWalletHDStatusIcon->show();
1217  // eventually disable the QLabel to set its opacity to 50%
1218  labelWalletHDStatusIcon->setEnabled(hdEnabled);
1219 }
1220 
1221 void BitcoinGUI::setEncryptionStatus(int status)
1222 {
1223  switch(status)
1224  {
1226  labelWalletEncryptionIcon->hide();
1227  encryptWalletAction->setChecked(false);
1228  changePassphraseAction->setEnabled(false);
1229  encryptWalletAction->setEnabled(true);
1230  break;
1231  case WalletModel::Unlocked:
1232  labelWalletEncryptionIcon->show();
1234  labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
1235  encryptWalletAction->setChecked(true);
1236  changePassphraseAction->setEnabled(true);
1237  encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
1238  break;
1239  case WalletModel::Locked:
1240  labelWalletEncryptionIcon->show();
1242  labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
1243  encryptWalletAction->setChecked(true);
1244  changePassphraseAction->setEnabled(true);
1245  encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
1246  break;
1247  }
1248 }
1249 
1250 void BitcoinGUI::updateWalletStatus()
1251 {
1252  if (!walletFrame) {
1253  return;
1254  }
1255  WalletView * const walletView = walletFrame->currentWalletView();
1256  if (!walletView) {
1257  return;
1258  }
1259  WalletModel * const walletModel = walletView->getWalletModel();
1260  setEncryptionStatus(walletModel->getEncryptionStatus());
1261  setHDStatus(walletModel->privateKeysDisabled(), walletModel->wallet().hdEnabled());
1262 }
1263 #endif // ENABLE_WALLET
1264 
1266 {
1267  std::string ip_port;
1268  bool proxy_enabled = clientModel->getProxyInfo(ip_port);
1269 
1270  if (proxy_enabled) {
1271  if (labelProxyIcon->pixmap() == nullptr) {
1272  QString ip_port_q = QString::fromStdString(ip_port);
1273  labelProxyIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/proxy").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
1274  labelProxyIcon->setToolTip(tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q));
1275  } else {
1276  labelProxyIcon->show();
1277  }
1278  } else {
1279  labelProxyIcon->hide();
1280  }
1281 }
1282 
1284 {
1285  QString window_title = PACKAGE_NAME;
1286 #ifdef ENABLE_WALLET
1287  if (walletFrame) {
1288  WalletModel* const wallet_model = walletFrame->currentWalletModel();
1289  if (wallet_model && !wallet_model->getWalletName().isEmpty()) {
1290  window_title += " - " + wallet_model->getDisplayName();
1291  }
1292  }
1293 #endif
1294  if (!m_network_style->getTitleAddText().isEmpty()) {
1295  window_title += " - " + m_network_style->getTitleAddText();
1296  }
1297  setWindowTitle(window_title);
1298 }
1299 
1300 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
1301 {
1302  if(!clientModel)
1303  return;
1304 
1305  if (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this) && fToggleHidden) {
1306  hide();
1307  } else {
1308  GUIUtil::bringToFront(this);
1309  }
1310 }
1311 
1313 {
1314  showNormalIfMinimized(true);
1315 }
1316 
1318 {
1319  if (m_node.shutdownRequested())
1320  {
1321  if(rpcConsole)
1322  rpcConsole->hide();
1323  qApp->quit();
1324  }
1325 }
1326 
1327 void BitcoinGUI::showProgress(const QString &title, int nProgress)
1328 {
1329  if (nProgress == 0) {
1330  progressDialog = new QProgressDialog(title, QString(), 0, 100);
1332  progressDialog->setWindowModality(Qt::ApplicationModal);
1333  progressDialog->setMinimumDuration(0);
1334  progressDialog->setAutoClose(false);
1335  progressDialog->setValue(0);
1336  } else if (nProgress == 100) {
1337  if (progressDialog) {
1338  progressDialog->close();
1339  progressDialog->deleteLater();
1340  progressDialog = nullptr;
1341  }
1342  } else if (progressDialog) {
1343  progressDialog->setValue(nProgress);
1344  }
1345 }
1346 
1347 void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon)
1348 {
1349  if (trayIcon)
1350  {
1351  trayIcon->setVisible(!fHideTrayIcon);
1352  }
1353 }
1354 
1356 {
1357  if (modalOverlay && (progressBar->isVisible() || modalOverlay->isLayerVisible()))
1359 }
1360 
1361 static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, const std::string& caption, unsigned int style)
1362 {
1363  bool modal = (style & CClientUIInterface::MODAL);
1364  // The SECURE flag has no effect in the Qt GUI.
1365  // bool secure = (style & CClientUIInterface::SECURE);
1366  style &= ~CClientUIInterface::SECURE;
1367  bool ret = false;
1368  // In case of modal message, use blocking connection to wait for user to click a button
1369  bool invoked = QMetaObject::invokeMethod(gui, "message",
1370  modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
1371  Q_ARG(QString, QString::fromStdString(caption)),
1372  Q_ARG(QString, QString::fromStdString(message)),
1373  Q_ARG(unsigned int, style),
1374  Q_ARG(bool*, &ret));
1375  assert(invoked);
1376  return ret;
1377 }
1378 
1380 {
1381  // Connect signals to client
1382  m_handler_message_box = m_node.handleMessageBox(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
1383  m_handler_question = m_node.handleQuestion(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_3, std::placeholders::_4));
1384 }
1385 
1387 {
1388  // Disconnect signals from client
1389  m_handler_message_box->disconnect();
1390  m_handler_question->disconnect();
1391 }
1392 
1394  optionsModel(nullptr),
1395  menu(nullptr)
1396 {
1398  setToolTip(tr("Unit to show amounts in. Click to select another unit."));
1399  QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
1400  int max_width = 0;
1401  const QFontMetrics fm(font());
1402  for (const BitcoinUnits::Unit unit : units)
1403  {
1404  max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit)));
1405  }
1406  setMinimumSize(max_width, 0);
1407  setAlignment(Qt::AlignRight | Qt::AlignVCenter);
1408  setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle->SingleColor().name()));
1409 }
1410 
1413 {
1414  onDisplayUnitsClicked(event->pos());
1415 }
1416 
1419 {
1420  menu = new QMenu(this);
1422  {
1423  QAction *menuAction = new QAction(QString(BitcoinUnits::longName(u)), this);
1424  menuAction->setData(QVariant(u));
1425  menu->addAction(menuAction);
1426  }
1427  connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection);
1428 }
1429 
1432 {
1433  if (_optionsModel)
1434  {
1435  this->optionsModel = _optionsModel;
1436 
1437  // be aware of a display unit change reported by the OptionsModel object.
1439 
1440  // initialize the display units label with the current value in the model.
1441  updateDisplayUnit(_optionsModel->getDisplayUnit());
1442  }
1443 }
1444 
1447 {
1448  setText(BitcoinUnits::longName(newUnits));
1449 }
1450 
1453 {
1454  QPoint globalPos = mapToGlobal(point);
1455  menu->exec(globalPos);
1456 }
1457 
1460 {
1461  if (action)
1462  {
1463  optionsModel->setDisplayUnit(action->data());
1464  }
1465 }
void subscribeToCoreSignals()
Connect core signals to GUI client.
void unsubscribeFromCoreSignals()
Disconnect core signals from GUI client.
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
void message(const QString &title, const QString &message, unsigned int style)
Fired when a message should be reported to the user.
void setNetworkActive(bool networkActive)
Set network state shown in the UI.
Definition: bitcoingui.cpp:893
void addWallet(WalletModel *const walletModel)
WalletModel * currentWalletModel() const
QAction * receiveCoinsAction
Definition: bitcoingui.h:139
UnitDisplayStatusBarControl * unitDisplayControl
Definition: bitcoingui.h:117
Local Bitcoin RPC console.
Definition: rpcconsole.h:36
QMenuBar * appMenuBar
Definition: bitcoingui.h:127
Unit
Bitcoin units.
Definition: bitcoinunits.h:41
interfaces::Wallet & wallet() const
Definition: walletmodel.h:147
virtual bool isInitialBlockDownload()=0
Is initial block download.
QAction * signMessageAction
Definition: bitcoingui.h:136
void receivedURI(const QString &uri)
Signal raised when a URI was entered or dragged to the GUI.
QAction * aboutAction
Definition: bitcoingui.h:138
virtual bool getNetworkActive()=0
Get network active.
void updateNetworkState()
Update UI with latest network info from model.
Definition: bitcoingui.cpp:859
QLabel * labelWalletHDStatusIcon
Definition: bitcoingui.h:119
void mousePressEvent(QMouseEvent *event)
So that it responds to left-button clicks.
void showNormalIfMinimized()
Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHid...
Definition: bitcoingui.h:296
UnitDisplayStatusBarControl(const PlatformStyle *platformStyle)
QProgressDialog * progressDialog
Definition: bitcoingui.h:125
static bool isWalletEnabled()
void hideTrayIconChanged(bool)
void consoleShown(RPCConsole *console)
Signal raised when RPC console shown.
void createTrayIcon()
Create system tray icon and notification.
Definition: bitcoingui.cpp:715
void showDebugWindow()
Show debug window.
Definition: bitcoingui.cpp:797
GUIUtil::ClickableLabel * labelProxyIcon
Definition: bitcoingui.h:120
virtual double getVerificationProgress()=0
Get verification progress.
ClientModel * clientModel
Definition: bitcoingui.h:114
void createToolBars()
Create the toolbars.
Definition: bitcoingui.cpp:511
int TextWidth(const QFontMetrics &fm, const QString &text)
Returns the distance in pixels appropriate for drawing a subsequent character after text...
Definition: guiutil.cpp:879
NodeContext & m_node
Definition: chain.cpp:374
void setCurrentWallet(WalletModel *wallet_model)
Definition: walletframe.cpp:80
ModalOverlay * modalOverlay
Definition: bitcoingui.h:165
void createTrayIconMenu()
Create system tray menu (or setup the dock menu)
Definition: bitcoingui.cpp:728
RPCConsole * rpcConsole
Definition: bitcoingui.h:163
QAction * m_wallet_selector_action
Definition: bitcoingui.h:155
QAction * overviewAction
Definition: bitcoingui.h:129
void opened(WalletModel *wallet_model)
const char * prefix
Definition: rest.cpp:650
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string &message, const std::string &caption, unsigned int style)
QAction * verifyMessageAction
Definition: bitcoingui.h:137
QAction * quitAction
Definition: bitcoingui.h:131
virtual bool getImporting()=0
Get importing.
static constexpr int HEADER_HEIGHT_DELTA_SYNC
The required delta of headers to the estimated number of available headers until we show the IBD prog...
Definition: modaloverlay.h:12
QAction * m_open_wallet_action
Definition: bitcoingui.h:151
void dropEvent(QDropEvent *event)
void usedReceivingAddresses()
Show used receiving addresses.
QAction * m_close_wallet_action
Definition: bitcoingui.h:153
QAction * historyAction
Definition: bitcoingui.h:130
void tipUpdate(int count, const QDateTime &blockDate, double nVerificationProgress)
Qt::ConnectionType blockingGUIThreadConnection()
Get connection type to call object slot in GUI thread with invokeMethod.
Definition: guiutil.cpp:335
void setWalletActionsEnabled(bool enabled)
Enable or disable all wallet-related actions.
Definition: bitcoingui.cpp:696
void networkActiveChanged(bool networkActive)
QAction * aboutQtAction
Definition: bitcoingui.h:146
#define PACKAGE_NAME
Controller between interfaces::Node, WalletModel instances and the GUI.
OptionsModel * getOptionsModel()
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
void encryptWallet(bool status)
Encrypt the wallet.
QMenu * m_open_wallet_menu
Definition: bitcoingui.h:152
macOS-specific Dock icon handler.
Mask of all available buttons in CClientUIInterface::MessageBoxFlags This needs to be updated...
Definition: ui_interface.h:61
Bitcoin GUI main class.
Definition: bitcoingui.h:64
bool isLayerVisible() const
Definition: modaloverlay.h:35
HelpMessageDialog * helpMessageDialog
Definition: bitcoingui.h:164
QLabel * progressBarLabel
Definition: bitcoingui.h:123
QSystemTrayIcon * trayIcon
Definition: bitcoingui.h:160
virtual std::vector< std::unique_ptr< Wallet > > getWallets()=0
Return interfaces for accessing wallets (if any).
QAction * showHelpMessageAction
Definition: bitcoingui.h:149
Notify user of potential problem.
Definition: notificator.h:39
Modal overlay to display information about the chain-sync state.
Definition: modaloverlay.h:19
const QString & getTitleAddText() const
Definition: networkstyle.h:22
static QString longName(int unit)
Long name.
void numConnectionsChanged(int count)
Signals for UI communication.
Definition: ui_interface.h:29
void removeAllWallets()
Definition: walletframe.cpp:99
GUIUtil::ClickableLabel * connectionsControl
Definition: bitcoingui.h:121
QAction * backupWalletAction
Definition: bitcoingui.h:144
void setOptionsModel(OptionsModel *optionsModel)
Lets the control know about the Options Model (and its signals)
void bringToFront(QWidget *w)
Definition: guiutil.cpp:363
std::map< std::string, bool > listWalletDir() const
Returns all wallet names in the wallet dir mapped to whether the wallet is loaded.
QString tabTitle(TabTypes tab_type) const
void openOptionsDialogWithTab(OptionsDialog::Tab tab)
Open the OptionsDialog on the specified tab index.
Definition: bitcoingui.cpp:907
EncryptionStatus getEncryptionStatus() const
int getDisplayUnit() const
Definition: optionsmodel.h:81
virtual std::unique_ptr< Handler > handleMessageBox(MessageBoxFn fn)=0
Force blocking, modal message box dialog (not just OS notification)
Definition: ui_interface.h:65
void showOutOfSyncWarning(bool fShow)
void setClientModel(ClientModel *model)
Definition: rpcconsole.cpp:557
void gotoHistoryPage()
Switch to history (transactions) page.
QAction * usedReceivingAddressesAction
Definition: bitcoingui.h:135
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
void setClientModel(ClientModel *clientModel)
Set the client model.
Definition: bitcoingui.cpp:548
WalletModel * getWalletModel()
Definition: walletview.h:45
void showModalOverlay()
const NetworkStyle *const m_network_style
Definition: bitcoingui.h:176
WalletController * m_wallet_controller
Definition: bitcoingui.h:111
void gotoOverviewPage()
Switch to overview (home) page.
const PlatformStyle * platformStyle
Definition: bitcoingui.h:175
QAction * toggleHideAction
Definition: bitcoingui.h:142
virtual bool hdEnabled()=0
void showProgress(const QString &title, int nProgress)
Show progress dialog e.g.
static MacDockIconHandler * instance()
void setDisplayUnit(const QVariant &value)
Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal.
void setClientModel(ClientModel *clientModel)
Definition: walletframe.cpp:37
bool isObscured(QWidget *w)
Definition: guiutil.cpp:354
QAction * m_wallet_selector_label_action
Definition: bitcoingui.h:154
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:66
OptionsModel * optionsModel
Definition: bitcoingui.h:327
void created(WalletModel *wallet_model)
QLabel * m_wallet_selector_label
Definition: bitcoingui.h:157
enum BlockSource getBlockSource() const
Returns enum BlockSource of the current importing/syncing state.
void setKnownBestHeight(int count, const QDateTime &blockDate)
void optionsClicked()
Show configuration dialog.
Definition: bitcoingui.cpp:783
void closeWallet(WalletModel *wallet_model, QWidget *parent=nullptr)
void gotoVerifyMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to verify message tab.
void notify(Class cls, const QString &title, const QString &text, const QIcon &icon=QIcon(), int millisTimeout=10000)
Show notification message.
bool eventFilter(QObject *object, QEvent *event)
const char * name
Definition: rest.cpp:40
QToolBar * appToolBar
Definition: bitcoingui.h:128
BlockSource
Definition: clientmodel.h:29
WalletFrame * walletFrame
Definition: bitcoingui.h:115
void updateDisplayUnit(int newUnits)
When Display Units are changed on OptionsModel it will refresh the display text of the control on the...
WalletView * currentWalletView() const
QAction * usedSendingAddressesAction
Definition: bitcoingui.h:134
void setTabFocus(enum TabTypes tabType)
set which tab has the focus (is visible)
int64_t nPowTargetSpacing
Definition: params.h:78
BitcoinGUI(interfaces::Node &node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent=nullptr)
Definition: bitcoingui.cpp:75
void setTrayIconVisible(bool)
When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly.
void toggleVisibility()
bool privateKeysDisabled() const
bool enableWallet
Definition: bitcoingui.h:91
void setModel(OptionsModel *model)
QAction * openRPCConsoleAction
Definition: bitcoingui.h:147
std::vector< TabTypes > tabs() const
Definition: rpcconsole.h:68
void detectShutdown()
called by a timer to check if ShutdownRequested() has been set
Cross-platform desktop notification client.
Definition: notificator.h:24
void clicked(const QPoint &point)
Emitted when the label is clicked.
QLabel * labelWalletEncryptionIcon
Definition: bitcoingui.h:118
GUIUtil::ClickableLabel * labelBlocksIcon
Definition: bitcoingui.h:122
void setCurrentTab(OptionsDialog::Tab tab)
Informational message.
Definition: notificator.h:38
GUIUtil::ClickableProgressBar * progressBar
Definition: bitcoingui.h:124
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, bool header)
void updateWindowTitle()
UniValue help(const JSONRPCRequest &jsonRequest)
Definition: server.cpp:130
void showHelpMessageClicked()
Show help message dialog.
Definition: bitcoingui.cpp:809
QString getWalletName() const
void dragEnterEvent(QDragEnterEvent *event)
void walletAdded(WalletModel *wallet_model)
Notificator * notificator
Definition: bitcoingui.h:162
void displayUnitChanged(int unit)
void PolishProgressDialog(QProgressDialog *dialog)
Definition: guiutil.cpp:867
void changePassphrase()
Change encrypted wallet passphrase.
Model for Bitcoin network client.
Definition: clientmodel.h:44
An error occurred.
Definition: notificator.h:40
const QIcon & getTrayAndWindowIcon() const
Definition: networkstyle.h:21
QAction * receiveCoinsMenuAction
Definition: bitcoingui.h:140
ClickableProgressBar ProgressBar
Definition: guiutil.h:243
void gotoSignMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to sign message tab.
void message(const QString &title, QString message, unsigned int style, bool *ret=nullptr)
Notify the user of an event from the core network or transaction handling code.
virtual bool shutdownRequested()=0
Return whether shutdown was requested.
QAction * sendCoinsAction
Definition: bitcoingui.h:132
void showHide(bool hide=false, bool userRequested=false)
QAction * m_create_wallet_action
Definition: bitcoingui.h:150
QKeySequence tabShortcut(TabTypes tab_type) const
static const int STATUSBAR_ICONSIZE
Definition: guiconstants.h:17
QColor SingleColor() const
Definition: platformstyle.h:25
void requestedSyncWarningInfo()
Notify that the user has requested more information about the out-of-sync warning.
QAction * openAction
Definition: bitcoingui.h:148
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
virtual bool getReindex()=0
Get reindex.
void trayIconActivated(QSystemTrayIcon::ActivationReason reason)
Handle tray icon clicked.
Definition: bitcoingui.cpp:767
bool getMinimizeOnClose() const
Definition: optionsmodel.h:80
void updateProxyIcon()
Set the proxy-enabled icon as shown in the UI.
QAction * changePassphraseAction
Definition: bitcoingui.h:145
virtual int64_t getLastBlockTime()=0
Get last block time.
void gotoSendCoinsPage(QString addr="")
Switch to send coins page.
virtual std::unique_ptr< Handler > handleQuestion(QuestionFn fn)=0
void gotoReceiveCoinsPage()
Switch to receive coins page.
std::vector< WalletModel * > getOpenWallets() const
Returns wallet models currently open.
void closeEvent(QCloseEvent *event)
const std::unique_ptr< QMenu > trayIconMenu
Definition: bitcoingui.h:161
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:36
std::unique_ptr< interfaces::Handler > m_handler_question
Definition: bitcoingui.h:113
const CChainParams & Params()
Return the currently selected parameters.
bool getMinimizeToTray() const
Definition: optionsmodel.h:79
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:50
QString getURI()
QAction * sendCoinsMenuAction
Definition: bitcoingui.h:133
void changeEvent(QEvent *e)
Do not prepend error/warning prefix.
Definition: ui_interface.h:68
int prevBlocks
Keep track of previous number of blocks, to detect progress.
Definition: bitcoingui.h:172
void toggleHidden()
Simply calls showNormalIfMinimized(true) for use in SLOT() macro.
interfaces::Node & m_node
Definition: bitcoingui.h:110
int spinnerFrame
Definition: bitcoingui.h:173
void walletRemoved(WalletModel *wallet_model)
void removeWallet(WalletModel *const walletModel)
void showEvent(QShowEvent *event)
static int count
Definition: tests.c:45
bool addWallet(WalletModel *walletModel)
Definition: walletframe.cpp:46
void setNumConnections(int count)
Set number of connections shown in the UI.
Definition: bitcoingui.cpp:888
QString getDisplayName() const
"Help message" dialog box
Definition: utilitydialog.h:24
void backupWallet()
Backup the wallet.
QComboBox * m_wallet_selector
Definition: bitcoingui.h:158
Preferences dialog.
Definition: optionsdialog.h:35
void clicked(const QPoint &point)
Emitted when the progressbar is clicked.
virtual int getNumBlocks()=0
Get num blocks.
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:786
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
void createContextMenu()
Creates context menu, its actions, and wires up all the relevant signals for mouse events...
void showDebugWindowActivateConsole()
Show debug window and set focus to the console.
Definition: bitcoingui.cpp:803
void createActions()
Create the main UI actions.
Definition: bitcoingui.cpp:234
QAction * optionsAction
Definition: bitcoingui.h:141
QAction * encryptWalletAction
Definition: bitcoingui.h:143
void aboutClicked()
Show about dialog.
Definition: bitcoingui.cpp:788
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:60
void removeWallet(WalletModel *wallet_model)
Definition: walletframe.cpp:90
int getHeaderTipHeight() const
Definition: clientmodel.cpp:80
void updateHeadersSyncProgressLabel()
Definition: bitcoingui.cpp:898
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:20
static const std::string DEFAULT_UIPLATFORM
Definition: bitcoingui.h:69
virtual void setNetworkActive(bool active)=0
Set network active.
int64_t getHeaderTipTime() const
Definition: clientmodel.cpp:95
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:39
static constexpr int64_t MAX_BLOCK_TIME_GAP
Maximum gap between node time and block time used for the "Catching up..." mode in GUI...
Definition: chain.h:38
A container for embedding all wallet-related controls into BitcoinGUI.
Definition: walletframe.h:29
void showProgress(const QString &title, int nProgress)
void usedSendingAddresses()
Show used sending addresses.
void setNumBlocks(int count, const QDateTime &blockDate, double nVerificationProgress, bool headers)
Set number of blocks and last block date shown in the UI.
Definition: bitcoingui.cpp:918
bool getHideTrayIcon() const
Definition: optionsmodel.h:78
void onDisplayUnitsClicked(const QPoint &point)
Shows context menu with Display Unit options by the mouse coordinates.
void createMenuBar()
Create the menu bar and sub-menus.
Definition: bitcoingui.cpp:419
void onMenuSelection(QAction *action)
Tells underlying optionsModel to update its current display unit.
std::unique_ptr< interfaces::Handler > m_handler_message_box
Definition: bitcoingui.h:112
Predefined combinations for certain default usage cases.
Definition: ui_interface.h:74
#define SPINNER_FRAMES
Definition: guiconstants.h:43
bool getProxyInfo(std::string &ip_port) const