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