Bitcoin Core  29.1.0
P2P Digital Currency
bitcoingui.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 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 <bitcoin-build-config.h> // IWYU pragma: keep
6 
7 #include <qt/bitcoingui.h>
8 
9 #include <qt/bitcoinunits.h>
10 #include <qt/clientmodel.h>
11 #include <qt/createwalletdialog.h>
12 #include <qt/guiconstants.h>
13 #include <qt/guiutil.h>
14 #include <qt/modaloverlay.h>
15 #include <qt/networkstyle.h>
16 #include <qt/notificator.h>
17 #include <qt/openuridialog.h>
18 #include <qt/optionsdialog.h>
19 #include <qt/optionsmodel.h>
20 #include <qt/platformstyle.h>
21 #include <qt/rpcconsole.h>
22 #include <qt/utilitydialog.h>
23 
24 #ifdef ENABLE_WALLET
25 #include <qt/walletcontroller.h>
26 #include <qt/walletframe.h>
27 #include <qt/walletmodel.h>
28 #include <qt/walletview.h>
29 #endif // ENABLE_WALLET
30 
31 #ifdef Q_OS_MACOS
32 #include <qt/macdockiconhandler.h>
33 #endif
34 
35 #include <chain.h>
36 #include <chainparams.h>
37 #include <common/system.h>
38 #include <interfaces/handler.h>
39 #include <interfaces/node.h>
40 #include <node/interface_ui.h>
41 #include <util/translation.h>
42 #include <validation.h>
43 
44 #include <functional>
45 
46 #include <QAction>
47 #include <QActionGroup>
48 #include <QApplication>
49 #include <QComboBox>
50 #include <QCursor>
51 #include <QDateTime>
52 #include <QDragEnterEvent>
53 #include <QInputDialog>
54 #include <QKeySequence>
55 #include <QListWidget>
56 #include <QMenu>
57 #include <QMenuBar>
58 #include <QMessageBox>
59 #include <QMimeData>
60 #include <QProgressDialog>
61 #include <QScreen>
62 #include <QSettings>
63 #include <QShortcut>
64 #include <QStackedWidget>
65 #include <QStatusBar>
66 #include <QStyle>
67 #include <QSystemTrayIcon>
68 #include <QTimer>
69 #include <QToolBar>
70 #include <QUrlQuery>
71 #include <QVBoxLayout>
72 #include <QWindow>
73 
74 
75 const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
76 #if defined(Q_OS_MACOS)
77  "macosx"
78 #elif defined(Q_OS_WIN)
79  "windows"
80 #else
81  "other"
82 #endif
83  ;
84 
85 BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
86  QMainWindow(parent),
87  m_node(node),
88  trayIconMenu{new QMenu()},
89  platformStyle(_platformStyle),
90  m_network_style(networkStyle)
91 {
92  QSettings settings;
93  if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
94  // Restore failed (perhaps missing setting), center the window
95  move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center());
96  }
97 
98  setContextMenuPolicy(Qt::PreventContextMenu);
99 
100 #ifdef ENABLE_WALLET
101  enableWallet = WalletModel::isWalletEnabled();
102 #endif // ENABLE_WALLET
103  QApplication::setWindowIcon(m_network_style->getTrayAndWindowIcon());
104  setWindowIcon(m_network_style->getTrayAndWindowIcon());
105  updateWindowTitle();
106 
107  rpcConsole = new RPCConsole(node, _platformStyle, nullptr);
108  helpMessageDialog = new HelpMessageDialog(this, false);
109 #ifdef ENABLE_WALLET
110  if(enableWallet)
111  {
113  walletFrame = new WalletFrame(_platformStyle, this);
115  connect(walletFrame, &WalletFrame::message, [this](const QString& title, const QString& message, unsigned int style) {
116  this->message(title, message, style);
117  });
118  connect(walletFrame, &WalletFrame::currentWalletSet, [this] { updateWalletStatus(); });
119  setCentralWidget(walletFrame);
120  } else
121 #endif // ENABLE_WALLET
122  {
123  /* When compiled without wallet or -disablewallet is provided,
124  * the central widget is the rpc console.
125  */
126  setCentralWidget(rpcConsole);
127  Q_EMIT consoleShown(rpcConsole);
128  }
129 
130  modalOverlay = new ModalOverlay(enableWallet, this->centralWidget());
131 
132  // Accept D&D of URIs
133  setAcceptDrops(true);
134 
135  // Create actions for the toolbar, menu bar and tray/dock icon
136  // Needs walletFrame to be initialized
137  createActions();
138 
139  // Create application menu bar
140  createMenuBar();
141 
142  // Create the toolbars
143  createToolBars();
144 
145  // Create system tray icon and notification
146  if (QSystemTrayIcon::isSystemTrayAvailable()) {
147  createTrayIcon();
148  }
149  notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
150 
151  // Create status bar
152  statusBar();
153 
154  // Disable size grip because it looks ugly and nobody needs it
155  statusBar()->setSizeGripEnabled(false);
156 
157  // Status bar notification icons
158  QFrame *frameBlocks = new QFrame();
159  frameBlocks->setContentsMargins(0,0,0,0);
160  frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
161  QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
162  frameBlocksLayout->setContentsMargins(3,0,3,0);
163  frameBlocksLayout->setSpacing(3);
164  unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
165  labelWalletEncryptionIcon = new GUIUtil::ThemedLabel(platformStyle);
166  labelWalletHDStatusIcon = new GUIUtil::ThemedLabel(platformStyle);
167  labelProxyIcon = new GUIUtil::ClickableLabel(platformStyle);
168  connectionsControl = new GUIUtil::ClickableLabel(platformStyle);
169  labelBlocksIcon = new GUIUtil::ClickableLabel(platformStyle);
170  if(enableWallet)
171  {
172  frameBlocksLayout->addStretch();
173  frameBlocksLayout->addWidget(unitDisplayControl);
174  frameBlocksLayout->addStretch();
175  frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
176  labelWalletEncryptionIcon->hide();
177  frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
178  labelWalletHDStatusIcon->hide();
179  }
180  frameBlocksLayout->addWidget(labelProxyIcon);
181  frameBlocksLayout->addStretch();
182  frameBlocksLayout->addWidget(connectionsControl);
183  frameBlocksLayout->addStretch();
184  frameBlocksLayout->addWidget(labelBlocksIcon);
185  frameBlocksLayout->addStretch();
186 
187  // Progress bar and label for blocks download
188  progressBarLabel = new QLabel();
189  progressBarLabel->setVisible(false);
190  progressBar = new GUIUtil::ProgressBar();
191  progressBar->setAlignment(Qt::AlignCenter);
192  progressBar->setVisible(false);
193 
194  // Override style sheet for progress bar for styles that have a segmented progress bar,
195  // as they make the text unreadable (workaround for issue #1071)
196  // See https://doc.qt.io/qt-5/gallery.html
197  QString curStyle = QApplication::style()->metaObject()->className();
198  if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
199  {
200  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; }");
201  }
202 
203  statusBar()->addWidget(progressBarLabel);
204  statusBar()->addWidget(progressBar);
205  statusBar()->addPermanentWidget(frameBlocks);
206 
207  // Install event filter to be able to catch status tip events (QEvent::StatusTip)
208  this->installEventFilter(this);
209 
210  // Initially wallet actions should be disabled
211  setWalletActionsEnabled(false);
212 
213  // Subscribe to notifications from core
214  subscribeToCoreSignals();
215 
216  connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked, [this] {
217  openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK);
218  });
219 
220  connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showModalOverlay);
222 
223 #ifdef Q_OS_MACOS
224  m_app_nap_inhibitor = new CAppNapInhibitor;
225 #endif
226 
228 }
229 
231 {
232  // Unsubscribe from notifications from core
234 
235  QSettings settings;
236  settings.setValue("MainWindowGeometry", saveGeometry());
237  if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
238  trayIcon->hide();
239 #ifdef Q_OS_MACOS
240  delete m_app_nap_inhibitor;
242 #endif
243 
244  delete rpcConsole;
245 }
246 
248 {
249  QActionGroup *tabGroup = new QActionGroup(this);
250  connect(modalOverlay, &ModalOverlay::triggered, tabGroup, &QActionGroup::setEnabled);
251 
252  overviewAction = new QAction(platformStyle->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
253  overviewAction->setStatusTip(tr("Show general overview of wallet"));
254  overviewAction->setToolTip(overviewAction->statusTip());
255  overviewAction->setCheckable(true);
256  overviewAction->setShortcut(QKeySequence(QStringLiteral("Alt+1")));
257  tabGroup->addAction(overviewAction);
258 
259  sendCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this);
260  sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
261  sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
262  sendCoinsAction->setCheckable(true);
263  sendCoinsAction->setShortcut(QKeySequence(QStringLiteral("Alt+2")));
264  tabGroup->addAction(sendCoinsAction);
265 
266  receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
267  receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
268  receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
269  receiveCoinsAction->setCheckable(true);
270  receiveCoinsAction->setShortcut(QKeySequence(QStringLiteral("Alt+3")));
271  tabGroup->addAction(receiveCoinsAction);
272 
273  historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
274  historyAction->setStatusTip(tr("Browse transaction history"));
275  historyAction->setToolTip(historyAction->statusTip());
276  historyAction->setCheckable(true);
277  historyAction->setShortcut(QKeySequence(QStringLiteral("Alt+4")));
278  tabGroup->addAction(historyAction);
279 
280 #ifdef ENABLE_WALLET
281  // These showNormalIfMinimized are needed because Send Coins and Receive Coins
282  // can be triggered from the tray menu, and need to show the GUI to be useful.
283  connect(overviewAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
284  connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage);
285  connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
286  connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
287  connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
288  connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
289  connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
290  connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
291 #endif // ENABLE_WALLET
292 
293  quitAction = new QAction(tr("E&xit"), this);
294  quitAction->setStatusTip(tr("Quit application"));
295  quitAction->setShortcut(QKeySequence(tr("Ctrl+Q")));
296  quitAction->setMenuRole(QAction::QuitRole);
297  aboutAction = new QAction(tr("&About %1").arg(CLIENT_NAME), this);
298  aboutAction->setStatusTip(tr("Show information about %1").arg(CLIENT_NAME));
299  aboutAction->setMenuRole(QAction::AboutRole);
300  aboutAction->setEnabled(false);
301  aboutQtAction = new QAction(tr("About &Qt"), this);
302  aboutQtAction->setStatusTip(tr("Show information about Qt"));
303  aboutQtAction->setMenuRole(QAction::AboutQtRole);
304  optionsAction = new QAction(tr("&Options…"), this);
305  optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(CLIENT_NAME));
306  optionsAction->setMenuRole(QAction::PreferencesRole);
307  optionsAction->setEnabled(false);
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  m_load_psbt_action = new QAction(tr("&Load PSBT from file…"), this);
321  m_load_psbt_action->setStatusTip(tr("Load Partially Signed Bitcoin Transaction"));
322  m_load_psbt_clipboard_action = new QAction(tr("Load PSBT from &clipboard…"), this);
323  m_load_psbt_clipboard_action->setStatusTip(tr("Load Partially Signed Bitcoin Transaction from clipboard"));
324 
325  openRPCConsoleAction = new QAction(tr("Node window"), this);
326  openRPCConsoleAction->setStatusTip(tr("Open node debugging and diagnostic console"));
327  // initially disable the debug window menu item
328  openRPCConsoleAction->setEnabled(false);
329  openRPCConsoleAction->setObjectName("openRPCConsoleAction");
330 
331  usedSendingAddressesAction = new QAction(tr("&Sending addresses"), this);
332  usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
333  usedReceivingAddressesAction = new QAction(tr("&Receiving addresses"), this);
334  usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
335 
336  openAction = new QAction(tr("Open &URI…"), this);
337  openAction->setStatusTip(tr("Open a bitcoin: URI"));
338 
339  m_open_wallet_action = new QAction(tr("Open Wallet"), this);
340  m_open_wallet_action->setEnabled(false);
341  m_open_wallet_action->setStatusTip(tr("Open a wallet"));
342  m_open_wallet_menu = new QMenu(this);
343 
344  m_close_wallet_action = new QAction(tr("Close Wallet…"), this);
345  m_close_wallet_action->setStatusTip(tr("Close wallet"));
346 
347  m_create_wallet_action = new QAction(tr("Create Wallet…"), this);
348  m_create_wallet_action->setEnabled(false);
349  m_create_wallet_action->setStatusTip(tr("Create a new wallet"));
350 
351  //: Name of the menu item that restores wallet from a backup file.
352  m_restore_wallet_action = new QAction(tr("Restore Wallet…"), this);
353  m_restore_wallet_action->setEnabled(false);
354  //: Status tip for Restore Wallet menu item
355  m_restore_wallet_action->setStatusTip(tr("Restore a wallet from a backup file"));
356 
357  m_close_all_wallets_action = new QAction(tr("Close All Wallets…"), this);
358  m_close_all_wallets_action->setStatusTip(tr("Close all wallets"));
359 
360  m_migrate_wallet_action = new QAction(tr("Migrate Wallet"), this);
361  m_migrate_wallet_action->setEnabled(false);
362  m_migrate_wallet_action->setStatusTip(tr("Migrate a wallet"));
363  m_migrate_wallet_menu = new QMenu(this);
364 
365  showHelpMessageAction = new QAction(tr("&Command-line options"), this);
366  showHelpMessageAction->setMenuRole(QAction::NoRole);
367  showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(CLIENT_NAME));
368 
369  m_mask_values_action = new QAction(tr("&Mask values"), this);
370  m_mask_values_action->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_M));
371  m_mask_values_action->setStatusTip(tr("Mask the values in the Overview tab"));
372  m_mask_values_action->setCheckable(true);
373 
374  connect(quitAction, &QAction::triggered, this, &BitcoinGUI::quitRequested);
375  connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
376  connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt);
377  connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked);
378  connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked);
379  connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow);
380  // prevents an open debug window from becoming stuck/unusable on client shutdown
381  connect(quitAction, &QAction::triggered, rpcConsole, &QWidget::hide);
382 
383 #ifdef ENABLE_WALLET
384  if(walletFrame)
385  {
386  connect(encryptWalletAction, &QAction::triggered, walletFrame, &WalletFrame::encryptWallet);
387  connect(backupWalletAction, &QAction::triggered, walletFrame, &WalletFrame::backupWallet);
388  connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase);
389  connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
390  connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); });
391  connect(m_load_psbt_action, &QAction::triggered, [this]{ gotoLoadPSBT(); });
392  connect(m_load_psbt_clipboard_action, &QAction::triggered, [this]{ gotoLoadPSBT(true); });
393  connect(verifyMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
394  connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); });
397  connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
398  connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] {
399  m_open_wallet_menu->clear();
400  for (const auto& [path, info] : m_wallet_controller->listWalletDir()) {
401  const auto& [loaded, _] = info;
402  QString name = GUIUtil::WalletDisplayName(path);
403  // An single ampersand in the menu item's text sets a shortcut for this item.
404  // Single & are shown when && is in the string. So replace & with &&.
405  name.replace(QChar('&'), QString("&&"));
406  QAction* action = m_open_wallet_menu->addAction(name);
407 
408  if (loaded) {
409  // This wallet is already loaded
410  action->setEnabled(false);
411  continue;
412  }
413 
414  connect(action, &QAction::triggered, [this, path] {
415  auto activity = new OpenWalletActivity(m_wallet_controller, this);
416  connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet, Qt::QueuedConnection);
417  connect(activity, &OpenWalletActivity::opened, rpcConsole, &RPCConsole::setCurrentWallet, Qt::QueuedConnection);
418  activity->open(path);
419  });
420  }
421  if (m_open_wallet_menu->isEmpty()) {
422  QAction* action = m_open_wallet_menu->addAction(tr("No wallets available"));
423  action->setEnabled(false);
424  }
425  });
426  connect(m_restore_wallet_action, &QAction::triggered, [this] {
427  //: Name of the wallet data file format.
428  QString name_data_file = tr("Wallet Data");
429 
430  //: The title for Restore Wallet File Windows
431  QString title_windows = tr("Load Wallet Backup");
432 
433  QString backup_file = GUIUtil::getOpenFileName(this, title_windows, QString(), name_data_file + QLatin1String(" (*.dat)"), nullptr);
434  if (backup_file.isEmpty()) return;
435 
436  bool wallet_name_ok;
437  /*: Title of pop-up window shown when the user is attempting to
438  restore a wallet. */
439  QString title = tr("Restore Wallet");
440  //: Label of the input field where the name of the wallet is entered.
441  QString label = tr("Wallet Name");
442  QString wallet_name = QInputDialog::getText(this, title, label, QLineEdit::Normal, "", &wallet_name_ok);
443  if (!wallet_name_ok || wallet_name.isEmpty()) return;
444 
445  auto activity = new RestoreWalletActivity(m_wallet_controller, this);
446  connect(activity, &RestoreWalletActivity::restored, this, &BitcoinGUI::setCurrentWallet, Qt::QueuedConnection);
447  connect(activity, &RestoreWalletActivity::restored, rpcConsole, &RPCConsole::setCurrentWallet, Qt::QueuedConnection);
448 
449  auto backup_file_path = fs::PathFromString(backup_file.toStdString());
450  activity->restore(backup_file_path, wallet_name.toStdString());
451  });
452  connect(m_close_wallet_action, &QAction::triggered, [this] {
454  });
455  connect(m_create_wallet_action, &QAction::triggered, this, &BitcoinGUI::createWallet);
456  connect(m_close_all_wallets_action, &QAction::triggered, [this] {
458  });
459  connect(m_migrate_wallet_menu, &QMenu::aboutToShow, [this] {
460  m_migrate_wallet_menu->clear();
461  for (const auto& [wallet_name, info] : m_wallet_controller->listWalletDir()) {
462  const auto& [loaded, format] = info;
463 
464  if (format != "bdb") { // Skip already migrated wallets
465  continue;
466  }
467 
468  QString name = GUIUtil::WalletDisplayName(wallet_name);
469  // An single ampersand in the menu item's text sets a shortcut for this item.
470  // Single & are shown when && is in the string. So replace & with &&.
471  name.replace(QChar('&'), QString("&&"));
472  QAction* action = m_migrate_wallet_menu->addAction(name);
473 
474  connect(action, &QAction::triggered, [this, wallet_name] {
475  auto activity = new MigrateWalletActivity(m_wallet_controller, this);
476  connect(activity, &MigrateWalletActivity::migrated, this, &BitcoinGUI::setCurrentWallet);
477  activity->migrate(wallet_name);
478  });
479  }
480  if (m_migrate_wallet_menu->isEmpty()) {
481  QAction* action = m_migrate_wallet_menu->addAction(tr("No wallets available"));
482  action->setEnabled(false);
483  }
484  });
485  connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy);
486  connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::enableHistoryAction);
487  }
488 #endif // ENABLE_WALLET
489 
490  connect(new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole);
491  connect(new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow);
492 }
493 
495 {
496  appMenuBar = menuBar();
497 
498  // Configure the menus
499  QMenu *file = appMenuBar->addMenu(tr("&File"));
500  if(walletFrame)
501  {
502  file->addAction(m_create_wallet_action);
503  file->addAction(m_open_wallet_action);
504  file->addAction(m_close_wallet_action);
505  file->addAction(m_close_all_wallets_action);
506  file->addAction(m_migrate_wallet_action);
507  file->addSeparator();
508  file->addAction(backupWalletAction);
509  file->addAction(m_restore_wallet_action);
510  file->addSeparator();
511  file->addAction(openAction);
512  file->addAction(signMessageAction);
513  file->addAction(verifyMessageAction);
514  file->addAction(m_load_psbt_action);
515  file->addAction(m_load_psbt_clipboard_action);
516  file->addSeparator();
517  }
518  file->addAction(quitAction);
519 
520  QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
521  if(walletFrame)
522  {
523  settings->addAction(encryptWalletAction);
524  settings->addAction(changePassphraseAction);
525  settings->addSeparator();
526  settings->addAction(m_mask_values_action);
527  settings->addSeparator();
528  }
529  settings->addAction(optionsAction);
530 
531  QMenu* window_menu = appMenuBar->addMenu(tr("&Window"));
532 
533  QAction* minimize_action = window_menu->addAction(tr("&Minimize"));
534  minimize_action->setShortcut(QKeySequence(tr("Ctrl+M")));
535  connect(minimize_action, &QAction::triggered, [] {
536  QApplication::activeWindow()->showMinimized();
537  });
538  connect(qApp, &QApplication::focusWindowChanged, this, [minimize_action] (QWindow* window) {
539  minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized);
540  });
541 
542 #ifdef Q_OS_MACOS
543  QAction* zoom_action = window_menu->addAction(tr("Zoom"));
544  connect(zoom_action, &QAction::triggered, [] {
545  QWindow* window = qApp->focusWindow();
546  if (window->windowState() != Qt::WindowMaximized) {
547  window->showMaximized();
548  } else {
549  window->showNormal();
550  }
551  });
552 
553  connect(qApp, &QApplication::focusWindowChanged, this, [zoom_action] (QWindow* window) {
554  zoom_action->setEnabled(window != nullptr);
555  });
556 #endif
557 
558  if (walletFrame) {
559 #ifdef Q_OS_MACOS
560  window_menu->addSeparator();
561  QAction* main_window_action = window_menu->addAction(tr("Main Window"));
562  connect(main_window_action, &QAction::triggered, [this] {
563  GUIUtil::bringToFront(this);
564  });
565 #endif
566  window_menu->addSeparator();
567  window_menu->addAction(usedSendingAddressesAction);
568  window_menu->addAction(usedReceivingAddressesAction);
569  }
570 
571  window_menu->addSeparator();
572  for (RPCConsole::TabTypes tab_type : rpcConsole->tabs()) {
573  QAction* tab_action = window_menu->addAction(rpcConsole->tabTitle(tab_type));
574  tab_action->setShortcut(rpcConsole->tabShortcut(tab_type));
575  connect(tab_action, &QAction::triggered, [this, tab_type] {
576  rpcConsole->setTabFocus(tab_type);
577  showDebugWindow();
578  });
579  }
580 
581  QMenu *help = appMenuBar->addMenu(tr("&Help"));
582  help->addAction(showHelpMessageAction);
583  help->addSeparator();
584  help->addAction(aboutAction);
585  help->addAction(aboutQtAction);
586 }
587 
589 {
590  if(walletFrame)
591  {
592  QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
593  appToolBar = toolbar;
594  toolbar->setMovable(false);
595  toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
596  toolbar->addAction(overviewAction);
597  toolbar->addAction(sendCoinsAction);
598  toolbar->addAction(receiveCoinsAction);
599  toolbar->addAction(historyAction);
600  overviewAction->setChecked(true);
601 
602 #ifdef ENABLE_WALLET
603  QWidget *spacer = new QWidget();
604  spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
605  toolbar->addWidget(spacer);
606 
607  m_wallet_selector = new QComboBox();
608  m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
609  connect(m_wallet_selector, qOverload<int>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
610 
611  m_wallet_selector_label = new QLabel();
612  m_wallet_selector_label->setText(tr("Wallet:") + " ");
614 
617 
618  m_wallet_selector_label_action->setVisible(false);
619  m_wallet_selector_action->setVisible(false);
620 #endif
621  }
622 }
623 
625 {
626  this->clientModel = _clientModel;
627  if(_clientModel)
628  {
629  // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
630  // while the client has not yet fully loaded
632 
633  // Keep up to date with client
637  });
639  connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive);
640 
641  modalOverlay->setKnownBestHeight(tip_info->header_height, QDateTime::fromSecsSinceEpoch(tip_info->header_time), /*presync=*/false);
642  setNumBlocks(tip_info->block_height, QDateTime::fromSecsSinceEpoch(tip_info->block_time), tip_info->verification_progress, SyncType::BLOCK_SYNC, SynchronizationState::INIT_DOWNLOAD);
643  connect(_clientModel, &ClientModel::numBlocksChanged, this, &BitcoinGUI::setNumBlocks);
644 
645  // Receive and report messages from client model
646  connect(_clientModel, &ClientModel::message, [this](const QString &title, const QString &message, unsigned int style){
647  this->message(title, message, style);
648  });
649 
650  // Show progress dialog
651  connect(_clientModel, &ClientModel::showProgress, this, &BitcoinGUI::showProgress);
652 
653  rpcConsole->setClientModel(_clientModel, tip_info->block_height, tip_info->block_time, tip_info->verification_progress);
654 
655  updateProxyIcon();
656 
657 #ifdef ENABLE_WALLET
658  if(walletFrame)
659  {
660  walletFrame->setClientModel(_clientModel);
661  }
662 #endif // ENABLE_WALLET
664 
665  OptionsModel* optionsModel = _clientModel->getOptionsModel();
666  if (optionsModel && trayIcon) {
667  // be aware of the tray icon disable state change reported by the OptionsModel object.
668  connect(optionsModel, &OptionsModel::showTrayIconChanged, trayIcon, &QSystemTrayIcon::setVisible);
669 
670  // initialize the disable state of the tray icon with the current value in the model.
671  trayIcon->setVisible(optionsModel->getShowTrayIcon());
672  }
673 
674  m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool());
675  } else {
676  // Shutdown requested, disable menus
677  if (trayIconMenu)
678  {
679  // Disable context menu on tray icon
680  trayIconMenu->clear();
681  }
682  // Propagate cleared model to child objects
683  rpcConsole->setClientModel(nullptr);
684 #ifdef ENABLE_WALLET
685  if (walletFrame)
686  {
687  walletFrame->setClientModel(nullptr);
688  }
689 #endif // ENABLE_WALLET
691  // Disable top bar menu actions
692  appMenuBar->clear();
693  }
694 }
695 
696 #ifdef ENABLE_WALLET
697 void BitcoinGUI::enableHistoryAction(bool privacy)
698 {
700  historyAction->setEnabled(!privacy);
701  if (historyAction->isChecked()) gotoOverviewPage();
702  }
703 }
704 
705 void BitcoinGUI::setWalletController(WalletController* wallet_controller, bool show_loading_minimized)
706 {
708  assert(wallet_controller);
709 
710  m_wallet_controller = wallet_controller;
711 
712  m_create_wallet_action->setEnabled(true);
713  m_open_wallet_action->setEnabled(true);
715  m_restore_wallet_action->setEnabled(true);
716  m_migrate_wallet_action->setEnabled(true);
718 
719  GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
720  connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
721  connect(wallet_controller, &WalletController::destroyed, this, [this] {
722  // wallet_controller gets destroyed manually, but it leaves our member copy dangling
723  m_wallet_controller = nullptr;
724  });
725 
726  auto activity = new LoadWalletsActivity(m_wallet_controller, this);
727  activity->load(show_loading_minimized);
728 }
729 
730 WalletController* BitcoinGUI::getWalletController()
731 {
732  return m_wallet_controller;
733 }
734 
735 void BitcoinGUI::addWallet(WalletModel* walletModel)
736 {
737  if (!walletFrame || !m_wallet_controller) return;
738 
739  WalletView* wallet_view = new WalletView(walletModel, platformStyle, walletFrame);
740  if (!walletFrame->addView(wallet_view)) return;
741 
742  rpcConsole->addWallet(walletModel);
743  if (m_wallet_selector->count() == 0) {
745  } else if (m_wallet_selector->count() == 1) {
746  m_wallet_selector_label_action->setVisible(true);
747  m_wallet_selector_action->setVisible(true);
748  }
749 
751  connect(wallet_view, &WalletView::transactionClicked, this, &BitcoinGUI::gotoHistoryPage);
752  connect(wallet_view, &WalletView::coinsSent, this, &BitcoinGUI::gotoHistoryPage);
753  connect(wallet_view, &WalletView::message, [this](const QString& title, const QString& message, unsigned int style) {
754  this->message(title, message, style);
755  });
756  connect(wallet_view, &WalletView::encryptionStatusChanged, this, &BitcoinGUI::updateWalletStatus);
757  connect(wallet_view, &WalletView::incomingTransaction, this, &BitcoinGUI::incomingTransaction);
758  connect(this, &BitcoinGUI::setPrivacy, wallet_view, &WalletView::setPrivacy);
759  const bool privacy = isPrivacyModeActivated();
760  wallet_view->setPrivacy(privacy);
761  enableHistoryAction(privacy);
762  const QString display_name = walletModel->getDisplayName();
763  m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
764 }
765 
766 void BitcoinGUI::removeWallet(WalletModel* walletModel)
767 {
768  if (!walletFrame) return;
769 
770  labelWalletHDStatusIcon->hide();
772 
773  int index = m_wallet_selector->findData(QVariant::fromValue(walletModel));
774  m_wallet_selector->removeItem(index);
775  if (m_wallet_selector->count() == 0) {
777  overviewAction->setChecked(true);
778  } else if (m_wallet_selector->count() == 1) {
779  m_wallet_selector_label_action->setVisible(false);
780  m_wallet_selector_action->setVisible(false);
781  }
782  rpcConsole->removeWallet(walletModel);
783  walletFrame->removeWallet(walletModel);
785 }
786 
787 void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model)
788 {
789  if (!walletFrame || !m_wallet_controller) return;
790  walletFrame->setCurrentWallet(wallet_model);
791  for (int index = 0; index < m_wallet_selector->count(); ++index) {
792  if (m_wallet_selector->itemData(index).value<WalletModel*>() == wallet_model) {
793  m_wallet_selector->setCurrentIndex(index);
794  break;
795  }
796  }
798 }
799 
800 void BitcoinGUI::setCurrentWalletBySelectorIndex(int index)
801 {
802  WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>();
803  if (wallet_model) setCurrentWallet(wallet_model);
804 }
805 
806 void BitcoinGUI::removeAllWallets()
807 {
808  if(!walletFrame)
809  return;
812 }
813 #endif // ENABLE_WALLET
814 
816 {
817  overviewAction->setEnabled(enabled);
818  sendCoinsAction->setEnabled(enabled);
819  receiveCoinsAction->setEnabled(enabled);
820  historyAction->setEnabled(enabled);
821  encryptWalletAction->setEnabled(enabled);
822  backupWalletAction->setEnabled(enabled);
823  changePassphraseAction->setEnabled(enabled);
824  signMessageAction->setEnabled(enabled);
825  verifyMessageAction->setEnabled(enabled);
826  usedSendingAddressesAction->setEnabled(enabled);
827  usedReceivingAddressesAction->setEnabled(enabled);
828  openAction->setEnabled(enabled);
829  m_close_wallet_action->setEnabled(enabled);
830  m_close_all_wallets_action->setEnabled(enabled);
831 }
832 
834 {
835  assert(QSystemTrayIcon::isSystemTrayAvailable());
836 
837 #ifndef Q_OS_MACOS
838  if (QSystemTrayIcon::isSystemTrayAvailable()) {
839  trayIcon = new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this);
840  QString toolTip = tr("%1 client").arg(CLIENT_NAME) + " " + m_network_style->getTitleAddText();
841  trayIcon->setToolTip(toolTip);
842  }
843 #endif
844 }
845 
847 {
848 #ifndef Q_OS_MACOS
849  if (!trayIcon) return;
850 #endif // Q_OS_MACOS
851 
852  // Configuration of the tray icon (or Dock icon) menu.
853  QAction* show_hide_action{nullptr};
854 #ifndef Q_OS_MACOS
855  // Note: On macOS, the Dock icon's menu already has Show / Hide action.
856  show_hide_action = trayIconMenu->addAction(QString(), this, &BitcoinGUI::toggleHidden);
857  trayIconMenu->addSeparator();
858 #endif // Q_OS_MACOS
859 
860  QAction* send_action{nullptr};
861  QAction* receive_action{nullptr};
862  QAction* sign_action{nullptr};
863  QAction* verify_action{nullptr};
864  if (enableWallet) {
865  send_action = trayIconMenu->addAction(sendCoinsAction->text(), sendCoinsAction, &QAction::trigger);
866  receive_action = trayIconMenu->addAction(receiveCoinsAction->text(), receiveCoinsAction, &QAction::trigger);
867  trayIconMenu->addSeparator();
868  sign_action = trayIconMenu->addAction(signMessageAction->text(), signMessageAction, &QAction::trigger);
869  verify_action = trayIconMenu->addAction(verifyMessageAction->text(), verifyMessageAction, &QAction::trigger);
870  trayIconMenu->addSeparator();
871  }
872  QAction* options_action = trayIconMenu->addAction(optionsAction->text(), optionsAction, &QAction::trigger);
873  options_action->setMenuRole(QAction::PreferencesRole);
874  QAction* node_window_action = trayIconMenu->addAction(openRPCConsoleAction->text(), openRPCConsoleAction, &QAction::trigger);
875  QAction* quit_action{nullptr};
876 #ifndef Q_OS_MACOS
877  // Note: On macOS, the Dock icon's menu already has Quit action.
878  trayIconMenu->addSeparator();
879  quit_action = trayIconMenu->addAction(quitAction->text(), quitAction, &QAction::trigger);
880 
881  trayIcon->setContextMenu(trayIconMenu.get());
882  connect(trayIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
883  if (reason == QSystemTrayIcon::Trigger) {
884  // Click on system tray icon triggers show/hide of the main window
885  toggleHidden();
886  }
887  });
888 #else
889  // Note: On macOS, the Dock icon is used to provide the tray's functionality.
891  connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, [this] {
892  if (m_node.shutdownRequested()) return; // nothing to show, node is shutting down.
893  show();
894  activateWindow();
895  });
896  trayIconMenu->setAsDockMenu();
897 #endif // Q_OS_MACOS
898 
899  connect(
900  // Using QSystemTrayIcon::Context is not reliable.
901  // See https://bugreports.qt.io/browse/QTBUG-91697
902  trayIconMenu.get(), &QMenu::aboutToShow,
903  [this, show_hide_action, send_action, receive_action, sign_action, verify_action, options_action, node_window_action, quit_action] {
904  if (m_node.shutdownRequested()) return; // nothing to do, node is shutting down.
905 
906  if (show_hide_action) show_hide_action->setText(
907  (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this)) ?
908  tr("&Hide") :
909  tr("S&how"));
910  if (QApplication::activeModalWidget()) {
911  for (QAction* a : trayIconMenu.get()->actions()) {
912  a->setEnabled(false);
913  }
914  } else {
915  if (show_hide_action) show_hide_action->setEnabled(true);
916  if (enableWallet) {
917  send_action->setEnabled(sendCoinsAction->isEnabled());
918  receive_action->setEnabled(receiveCoinsAction->isEnabled());
919  sign_action->setEnabled(signMessageAction->isEnabled());
920  verify_action->setEnabled(verifyMessageAction->isEnabled());
921  }
922  options_action->setEnabled(optionsAction->isEnabled());
923  node_window_action->setEnabled(openRPCConsoleAction->isEnabled());
924  if (quit_action) quit_action->setEnabled(true);
925  }
926  });
927 }
928 
930 {
932 }
933 
935 {
936  if(!clientModel)
937  return;
938 
939  auto dlg = new HelpMessageDialog(this, /*about=*/true);
941 }
942 
944 {
946  Q_EMIT consoleShown(rpcConsole);
947 }
948 
950 {
952  showDebugWindow();
953 }
954 
956 {
958 }
959 
960 #ifdef ENABLE_WALLET
961 void BitcoinGUI::openClicked()
962 {
963  OpenURIDialog dlg(platformStyle, this);
964  if(dlg.exec())
965  {
966  Q_EMIT receivedURI(dlg.getURI());
967  }
968 }
969 
970 void BitcoinGUI::gotoOverviewPage()
971 {
972  overviewAction->setChecked(true);
974 }
975 
976 void BitcoinGUI::gotoHistoryPage()
977 {
978  historyAction->setChecked(true);
980 }
981 
982 void BitcoinGUI::gotoReceiveCoinsPage()
983 {
984  receiveCoinsAction->setChecked(true);
986 }
987 
988 void BitcoinGUI::gotoSendCoinsPage(QString addr)
989 {
990  sendCoinsAction->setChecked(true);
992 }
993 
994 void BitcoinGUI::gotoSignMessageTab(QString addr)
995 {
997 }
998 
999 void BitcoinGUI::gotoVerifyMessageTab(QString addr)
1000 {
1002 }
1003 void BitcoinGUI::gotoLoadPSBT(bool from_clipboard)
1004 {
1005  if (walletFrame) walletFrame->gotoLoadPSBT(from_clipboard);
1006 }
1007 #endif // ENABLE_WALLET
1008 
1010 {
1011  if (!clientModel) return;
1013  QString icon;
1014  switch(count)
1015  {
1016  case 0: icon = ":/icons/connect_0"; break;
1017  case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
1018  case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
1019  case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
1020  default: icon = ":/icons/connect_4"; break;
1021  }
1022 
1023  QString tooltip;
1024 
1025  if (m_node.getNetworkActive()) {
1026  //: A substring of the tooltip.
1027  tooltip = tr("%n active connection(s) to Bitcoin network.", "", count);
1028  } else {
1029  //: A substring of the tooltip.
1030  tooltip = tr("Network activity disabled.");
1031  icon = ":/icons/network_disabled";
1032  }
1033 
1034  // Don't word-wrap this (fixed-width) tooltip
1035  tooltip = QLatin1String("<nobr>") + tooltip + QLatin1String("<br>") +
1036  //: A substring of the tooltip. "More actions" are available via the context menu.
1037  tr("Click for more actions.") + QLatin1String("</nobr>");
1038  connectionsControl->setToolTip(tooltip);
1039 
1041 }
1042 
1044 {
1046 }
1047 
1048 void BitcoinGUI::setNetworkActive(bool network_active)
1049 {
1051  m_network_context_menu->clear();
1052  m_network_context_menu->addAction(
1053  //: A context menu item. The "Peers tab" is an element of the "Node window".
1054  tr("Show Peers tab"),
1055  [this] {
1057  showDebugWindow();
1058  });
1059  m_network_context_menu->addAction(
1060  network_active ?
1061  //: A context menu item.
1062  tr("Disable network activity") :
1063  //: A context menu item. The network activity was disabled previously.
1064  tr("Enable network activity"),
1065  [this, new_state = !network_active] { m_node.setNetworkActive(new_state); });
1066 }
1067 
1069 {
1070  int64_t headersTipTime = clientModel->getHeaderTipTime();
1071  int headersTipHeight = clientModel->getHeaderTipHeight();
1072  int estHeadersLeft = (GetTime() - headersTipTime) / Params().GetConsensus().nPowTargetSpacing;
1073  if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC)
1074  progressBarLabel->setText(tr("Syncing Headers (%1%)…").arg(QString::number(100.0 / (headersTipHeight+estHeadersLeft)*headersTipHeight, 'f', 1)));
1075 }
1076 
1077 void BitcoinGUI::updateHeadersPresyncProgressLabel(int64_t height, const QDateTime& blockDate)
1078 {
1079  int estHeadersLeft = blockDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
1080  if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC)
1081  progressBarLabel->setText(tr("Pre-syncing Headers (%1%)…").arg(QString::number(100.0 / (height+estHeadersLeft)*height, 'f', 1)));
1082 }
1083 
1085 {
1087  return;
1088 
1089  auto dlg = new OptionsDialog(this, enableWallet);
1091  dlg->setCurrentTab(tab);
1092  dlg->setClientModel(clientModel);
1093  dlg->setModel(clientModel->getOptionsModel());
1095 }
1096 
1097 void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType synctype, SynchronizationState sync_state)
1098 {
1099 // Disabling macOS App Nap on initial sync, disk and reindex operations.
1100 #ifdef Q_OS_MACOS
1101  if (sync_state == SynchronizationState::POST_INIT) {
1102  m_app_nap_inhibitor->enableAppNap();
1103  } else {
1104  m_app_nap_inhibitor->disableAppNap();
1105  }
1106 #endif
1107 
1108  if (modalOverlay)
1109  {
1110  if (synctype != SyncType::BLOCK_SYNC)
1112  else
1113  modalOverlay->tipUpdate(count, blockDate, nVerificationProgress);
1114  }
1115  if (!clientModel)
1116  return;
1117 
1118  // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbled text)
1119  statusBar()->clearMessage();
1120 
1121  // Acquire current block source
1122  BlockSource blockSource{clientModel->getBlockSource()};
1123  switch (blockSource) {
1124  case BlockSource::NETWORK:
1125  if (synctype == SyncType::HEADER_PRESYNC) {
1127  return;
1128  } else if (synctype == SyncType::HEADER_SYNC) {
1130  return;
1131  }
1132  progressBarLabel->setText(tr("Synchronizing with network…"));
1134  break;
1135  case BlockSource::DISK:
1136  if (synctype != SyncType::BLOCK_SYNC) {
1137  progressBarLabel->setText(tr("Indexing blocks on disk…"));
1138  } else {
1139  progressBarLabel->setText(tr("Processing blocks on disk…"));
1140  }
1141  break;
1142  case BlockSource::NONE:
1143  if (synctype != SyncType::BLOCK_SYNC) {
1144  return;
1145  }
1146  progressBarLabel->setText(tr("Connecting to peers…"));
1147  break;
1148  }
1149 
1150  QString tooltip;
1151 
1152  QDateTime currentDate = QDateTime::currentDateTime();
1153  qint64 secs = blockDate.secsTo(currentDate);
1154 
1155  tooltip = tr("Processed %n block(s) of transaction history.", "", count);
1156 
1157  // Set icon state: spinning if catching up, tick otherwise
1158  if (secs < MAX_BLOCK_TIME_GAP) {
1159  tooltip = tr("Up to date") + QString(".<br>") + tooltip;
1160  labelBlocksIcon->setThemedPixmap(QStringLiteral(":/icons/synced"), STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE);
1161 
1162 #ifdef ENABLE_WALLET
1163  if(walletFrame)
1164  {
1166  modalOverlay->showHide(true, true);
1167  }
1168 #endif // ENABLE_WALLET
1169 
1170  progressBarLabel->setVisible(false);
1171  progressBar->setVisible(false);
1172  }
1173  else
1174  {
1175  QString timeBehindText = GUIUtil::formatNiceTimeOffset(secs);
1176 
1177  progressBarLabel->setVisible(true);
1178  progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
1179  progressBar->setMaximum(1000000000);
1180  progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5);
1181  progressBar->setVisible(true);
1182 
1183  tooltip = tr("Catching up…") + QString("<br>") + tooltip;
1184  if(count != prevBlocks)
1185  {
1187  QString(":/animation/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')),
1190  }
1191  prevBlocks = count;
1192 
1193 #ifdef ENABLE_WALLET
1194  if(walletFrame)
1195  {
1198  }
1199 #endif // ENABLE_WALLET
1200 
1201  tooltip += QString("<br>");
1202  tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
1203  tooltip += QString("<br>");
1204  tooltip += tr("Transactions after this will not yet be visible.");
1205  }
1206 
1207  // Don't word-wrap this (fixed-width) tooltip
1208  tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
1209 
1210  labelBlocksIcon->setToolTip(tooltip);
1211  progressBarLabel->setToolTip(tooltip);
1212  progressBar->setToolTip(tooltip);
1213 }
1214 
1216 {
1217 #ifdef ENABLE_WALLET
1218 #ifndef USE_SQLITE
1219  // Compiled without sqlite support (required for descriptor wallets)
1220  message(tr("Error creating wallet"), tr("Cannot create new wallet, the software was compiled without sqlite support (required for descriptor wallets)"), CClientUIInterface::MSG_ERROR);
1221  return;
1222 #endif // USE_SQLITE
1223  auto activity = new CreateWalletActivity(getWalletController(), this);
1224  connect(activity, &CreateWalletActivity::created, this, &BitcoinGUI::setCurrentWallet);
1225  connect(activity, &CreateWalletActivity::created, rpcConsole, &RPCConsole::setCurrentWallet);
1226  activity->create();
1227 #endif // ENABLE_WALLET
1228 }
1229 
1230 void BitcoinGUI::message(const QString& title, QString message, unsigned int style, bool* ret, const QString& detailed_message)
1231 {
1232  // Default title. On macOS, the window title is ignored (as required by the macOS Guidelines).
1233  QString strTitle{CLIENT_NAME};
1234  // Default to information icon
1235  int nMBoxIcon = QMessageBox::Information;
1236  int nNotifyIcon = Notificator::Information;
1237 
1238  QString msgType;
1239  if (!title.isEmpty()) {
1240  msgType = title;
1241  } else {
1242  switch (style) {
1244  msgType = tr("Error");
1245  message = tr("Error: %1").arg(message);
1246  break;
1248  msgType = tr("Warning");
1249  message = tr("Warning: %1").arg(message);
1250  break;
1252  msgType = tr("Information");
1253  // No need to prepend the prefix here.
1254  break;
1255  default:
1256  break;
1257  }
1258  }
1259 
1260  if (!msgType.isEmpty()) {
1261  strTitle += " - " + msgType;
1262  }
1263 
1264  if (style & CClientUIInterface::ICON_ERROR) {
1265  nMBoxIcon = QMessageBox::Critical;
1266  nNotifyIcon = Notificator::Critical;
1267  } else if (style & CClientUIInterface::ICON_WARNING) {
1268  nMBoxIcon = QMessageBox::Warning;
1269  nNotifyIcon = Notificator::Warning;
1270  }
1271 
1272  if (style & CClientUIInterface::MODAL) {
1273  // Check for buttons, use OK as default, if none was supplied
1274  QMessageBox::StandardButton buttons;
1275  if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK)))
1276  buttons = QMessageBox::Ok;
1277 
1279  QMessageBox mBox(static_cast<QMessageBox::Icon>(nMBoxIcon), strTitle, message, buttons, this);
1280  mBox.setTextFormat(Qt::PlainText);
1281  mBox.setDetailedText(detailed_message);
1282  int r = mBox.exec();
1283  if (ret != nullptr)
1284  *ret = r == QMessageBox::Ok;
1285  } else {
1286  notificator->notify(static_cast<Notificator::Class>(nNotifyIcon), strTitle, message);
1287  }
1288 }
1289 
1291 {
1292  if (e->type() == QEvent::PaletteChange) {
1293  overviewAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/overview")));
1294  sendCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/send")));
1295  receiveCoinsAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/receiving_addresses")));
1296  historyAction->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/history")));
1297  }
1298 
1299  QMainWindow::changeEvent(e);
1300 
1301 #ifndef Q_OS_MACOS // Ignored on Mac
1302  if(e->type() == QEvent::WindowStateChange)
1303  {
1305  {
1306  QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
1307  if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
1308  {
1309  QTimer::singleShot(0, this, &BitcoinGUI::hide);
1310  e->ignore();
1311  }
1312  else if((wsevt->oldState() & Qt::WindowMinimized) && !isMinimized())
1313  {
1314  QTimer::singleShot(0, this, &BitcoinGUI::show);
1315  e->ignore();
1316  }
1317  }
1318  }
1319 #endif
1320 }
1321 
1322 void BitcoinGUI::closeEvent(QCloseEvent *event)
1323 {
1324 #ifndef Q_OS_MACOS // Ignored on Mac
1326  {
1328  {
1329  // close rpcConsole in case it was open to make some space for the shutdown window
1330  rpcConsole->close();
1331 
1332  Q_EMIT quitRequested();
1333  }
1334  else
1335  {
1336  QMainWindow::showMinimized();
1337  event->ignore();
1338  }
1339  }
1340 #else
1341  QMainWindow::closeEvent(event);
1342 #endif
1343 }
1344 
1345 void BitcoinGUI::showEvent(QShowEvent *event)
1346 {
1347  // enable the debug window when the main window shows up
1348  openRPCConsoleAction->setEnabled(true);
1349  aboutAction->setEnabled(true);
1350  optionsAction->setEnabled(true);
1351 }
1352 
1353 #ifdef ENABLE_WALLET
1354 void BitcoinGUI::incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName)
1355 {
1356  // On new transaction, make an info balloon
1357  QString msg = tr("Date: %1\n").arg(date) +
1358  tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true));
1359  if (m_node.walletLoader().getWallets().size() > 1 && !walletName.isEmpty()) {
1360  msg += tr("Wallet: %1\n").arg(walletName);
1361  }
1362  msg += tr("Type: %1\n").arg(type);
1363  if (!label.isEmpty())
1364  msg += tr("Label: %1\n").arg(label);
1365  else if (!address.isEmpty())
1366  msg += tr("Address: %1\n").arg(address);
1367  message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
1369 }
1370 #endif // ENABLE_WALLET
1371 
1372 void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
1373 {
1374  // Accept only URIs
1375  if(event->mimeData()->hasUrls())
1376  event->acceptProposedAction();
1377 }
1378 
1379 void BitcoinGUI::dropEvent(QDropEvent *event)
1380 {
1381  if(event->mimeData()->hasUrls())
1382  {
1383  for (const QUrl &uri : event->mimeData()->urls())
1384  {
1385  Q_EMIT receivedURI(uri.toString());
1386  }
1387  }
1388  event->acceptProposedAction();
1389 }
1390 
1391 bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
1392 {
1393  // Catch status tip events
1394  if (event->type() == QEvent::StatusTip)
1395  {
1396  // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
1397  if (progressBarLabel->isVisible() || progressBar->isVisible())
1398  return true;
1399  }
1400  return QMainWindow::eventFilter(object, event);
1401 }
1402 
1403 #ifdef ENABLE_WALLET
1404 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
1405 {
1406  // URI has to be valid
1407  if (walletFrame && walletFrame->handlePaymentRequest(recipient))
1408  {
1410  gotoSendCoinsPage();
1411  return true;
1412  }
1413  return false;
1414 }
1415 
1416 void BitcoinGUI::setHDStatus(bool privkeyDisabled, int hdEnabled)
1417 {
1418  labelWalletHDStatusIcon->setThemedPixmap(privkeyDisabled ? QStringLiteral(":/icons/eye") : hdEnabled ? QStringLiteral(":/icons/hd_enabled") : QStringLiteral(":/icons/hd_disabled"), STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE);
1419  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>"));
1420  labelWalletHDStatusIcon->show();
1421 }
1422 
1423 void BitcoinGUI::setEncryptionStatus(int status)
1424 {
1425  switch(status)
1426  {
1427  case WalletModel::NoKeys:
1428  labelWalletEncryptionIcon->hide();
1429  encryptWalletAction->setChecked(false);
1430  changePassphraseAction->setEnabled(false);
1431  encryptWalletAction->setEnabled(false);
1432  break;
1434  labelWalletEncryptionIcon->hide();
1435  encryptWalletAction->setChecked(false);
1436  changePassphraseAction->setEnabled(false);
1437  encryptWalletAction->setEnabled(true);
1438  break;
1439  case WalletModel::Unlocked:
1440  labelWalletEncryptionIcon->show();
1441  labelWalletEncryptionIcon->setThemedPixmap(QStringLiteral(":/icons/lock_open"), STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE);
1442  labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
1443  encryptWalletAction->setChecked(true);
1444  changePassphraseAction->setEnabled(true);
1445  encryptWalletAction->setEnabled(false);
1446  break;
1447  case WalletModel::Locked:
1448  labelWalletEncryptionIcon->show();
1449  labelWalletEncryptionIcon->setThemedPixmap(QStringLiteral(":/icons/lock_closed"), STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE);
1450  labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
1451  encryptWalletAction->setChecked(true);
1452  changePassphraseAction->setEnabled(true);
1453  encryptWalletAction->setEnabled(false);
1454  break;
1455  }
1456 }
1457 
1458 void BitcoinGUI::updateWalletStatus()
1459 {
1461 
1462  WalletView * const walletView = walletFrame->currentWalletView();
1463  if (!walletView) {
1464  return;
1465  }
1466  WalletModel * const walletModel = walletView->getWalletModel();
1467  setEncryptionStatus(walletModel->getEncryptionStatus());
1468  setHDStatus(walletModel->wallet().privateKeysDisabled(), walletModel->wallet().hdEnabled());
1469 }
1470 #endif // ENABLE_WALLET
1471 
1473 {
1474  std::string ip_port;
1475  bool proxy_enabled = clientModel->getProxyInfo(ip_port);
1476 
1477  if (proxy_enabled) {
1479  QString ip_port_q = QString::fromStdString(ip_port);
1481  labelProxyIcon->setToolTip(tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q));
1482  } else {
1483  labelProxyIcon->show();
1484  }
1485  } else {
1486  labelProxyIcon->hide();
1487  }
1488 }
1489 
1491 {
1492  QString window_title = CLIENT_NAME;
1493 #ifdef ENABLE_WALLET
1494  if (walletFrame) {
1495  WalletModel* const wallet_model = walletFrame->currentWalletModel();
1496  if (wallet_model && !wallet_model->getWalletName().isEmpty()) {
1497  window_title += " - " + wallet_model->getDisplayName();
1498  }
1499  }
1500 #endif
1501  if (!m_network_style->getTitleAddText().isEmpty()) {
1502  window_title += " - " + m_network_style->getTitleAddText();
1503  }
1504  setWindowTitle(window_title);
1505 }
1506 
1507 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
1508 {
1509  if(!clientModel)
1510  return;
1511 
1512  if (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this) && fToggleHidden) {
1513  hide();
1514  } else {
1515  GUIUtil::bringToFront(this);
1516  }
1517 }
1518 
1520 {
1521  showNormalIfMinimized(true);
1522 }
1523 
1525 {
1526  if (m_node.shutdownRequested())
1527  {
1528  if(rpcConsole)
1529  rpcConsole->hide();
1530  Q_EMIT quitRequested();
1531  }
1532 }
1533 
1534 void BitcoinGUI::showProgress(const QString &title, int nProgress)
1535 {
1536  if (nProgress == 0) {
1537  progressDialog = new QProgressDialog(title, QString(), 0, 100);
1539  progressDialog->setWindowModality(Qt::ApplicationModal);
1540  progressDialog->setAutoClose(false);
1541  progressDialog->setValue(0);
1542  } else if (nProgress == 100) {
1543  if (progressDialog) {
1544  progressDialog->close();
1545  progressDialog->deleteLater();
1546  progressDialog = nullptr;
1547  }
1548  } else if (progressDialog) {
1549  progressDialog->setValue(nProgress);
1550  }
1551 }
1552 
1554 {
1555  if (modalOverlay && (progressBar->isVisible() || modalOverlay->isLayerVisible()))
1557 }
1558 
1559 static bool ThreadSafeMessageBox(BitcoinGUI* gui, const bilingual_str& message, const std::string& caption, unsigned int style)
1560 {
1561  bool modal = (style & CClientUIInterface::MODAL);
1562  // The SECURE flag has no effect in the Qt GUI.
1563  // bool secure = (style & CClientUIInterface::SECURE);
1564  style &= ~CClientUIInterface::SECURE;
1565  bool ret = false;
1566 
1567  QString detailed_message; // This is original message, in English, for googling and referencing.
1568  if (message.original != message.translated) {
1569  detailed_message = BitcoinGUI::tr("Original message:") + "\n" + QString::fromStdString(message.original);
1570  }
1571 
1572  // In case of modal message, use blocking connection to wait for user to click a button
1573  bool invoked = QMetaObject::invokeMethod(gui, "message",
1574  modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
1575  Q_ARG(QString, QString::fromStdString(caption)),
1576  Q_ARG(QString, QString::fromStdString(message.translated)),
1577  Q_ARG(unsigned int, style),
1578  Q_ARG(bool*, &ret),
1579  Q_ARG(QString, detailed_message));
1580  assert(invoked);
1581  return ret;
1582 }
1583 
1585 {
1586  // Connect signals to client
1587  m_handler_message_box = m_node.handleMessageBox(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
1588  m_handler_question = m_node.handleQuestion(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_3, std::placeholders::_4));
1589 }
1590 
1592 {
1593  // Disconnect signals from client
1594  m_handler_message_box->disconnect();
1595  m_handler_question->disconnect();
1596 }
1597 
1599 {
1601  return m_mask_values_action->isChecked();
1602 }
1603 
1605  : m_platform_style{platformStyle}
1606 {
1607  createContextMenu();
1608  setToolTip(tr("Unit to show amounts in. Click to select another unit."));
1609  QList<BitcoinUnit> units = BitcoinUnits::availableUnits();
1610  int max_width = 0;
1611  const QFontMetrics fm(font());
1612  for (const BitcoinUnit unit : units) {
1613  max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit)));
1614  }
1615  setMinimumSize(max_width, 0);
1616  setAlignment(Qt::AlignRight | Qt::AlignVCenter);
1617  setStyleSheet(QString("QLabel { color : %1 }").arg(m_platform_style->SingleColor().name()));
1618 }
1619 
1622 {
1623  onDisplayUnitsClicked(event->pos());
1624 }
1625 
1627 {
1628  if (e->type() == QEvent::PaletteChange) {
1629  QString style = QString("QLabel { color : %1 }").arg(m_platform_style->SingleColor().name());
1630  if (style != styleSheet()) {
1631  setStyleSheet(style);
1632  }
1633  }
1634 
1635  QLabel::changeEvent(e);
1636 }
1637 
1640 {
1641  menu = new QMenu(this);
1642  for (const BitcoinUnit u : BitcoinUnits::availableUnits()) {
1643  menu->addAction(BitcoinUnits::longName(u))->setData(QVariant::fromValue(u));
1644  }
1645  connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection);
1646 }
1647 
1650 {
1651  if (_optionsModel)
1652  {
1653  this->optionsModel = _optionsModel;
1654 
1655  // be aware of a display unit change reported by the OptionsModel object.
1657 
1658  // initialize the display units label with the current value in the model.
1659  updateDisplayUnit(_optionsModel->getDisplayUnit());
1660  }
1661 }
1662 
1665 {
1666  setText(BitcoinUnits::longName(newUnits));
1667 }
1668 
1671 {
1672  QPoint globalPos = mapToGlobal(point);
1673  menu->exec(globalPos);
1674 }
1675 
1678 {
1679  if (action)
1680  {
1681  optionsModel->setDisplayUnit(action->data());
1682  }
1683 }
virtual bool privateKeysDisabled()=0
void subscribeToCoreSignals()
Connect core signals to GUI client.
void unsubscribeFromCoreSignals()
Disconnect core signals from GUI client.
void showEvent(QShowEvent *event) override
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.
QMenu * m_migrate_wallet_menu
Definition: bitcoingui.h:165
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
WalletModel * currentWalletModel() const
Predefined combinations for certain default usage cases.
Definition: interface_ui.h:66
int ret
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
QAction * receiveCoinsAction
Definition: bitcoingui.h:146
UnitDisplayStatusBarControl * unitDisplayControl
Definition: bitcoingui.h:123
Local Bitcoin RPC console.
Definition: rpcconsole.h:41
QMenuBar * appMenuBar
Definition: bitcoingui.h:133
void quitRequested()
Unit
Bitcoin units.
Definition: bitcoinunits.h:42
interfaces::Wallet & wallet() const
Definition: walletmodel.h:138
QAction * m_mask_values_action
Definition: bitcoingui.h:163
QAction * signMessageAction
Definition: bitcoingui.h:141
void setThemedPixmap(const QString &image_filename, int width, int height)
Definition: guiutil.cpp:854
void receivedURI(const QString &uri)
Signal raised when a URI was entered or dragged to the GUI.
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:85
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
Definition: guiutil.cpp:353
virtual bool getNetworkActive()=0
Get network active.
QAction * aboutAction
Definition: bitcoingui.h:145
void updateNetworkState()
Update UI with latest network info from model.
assert(!tx.IsCoinBase())
void showNormalIfMinimized()
Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHid...
Definition: bitcoingui.h:311
UnitDisplayStatusBarControl(const PlatformStyle *platformStyle)
void createWalletButtonClicked()
QProgressDialog * progressDialog
Definition: bitcoingui.h:131
static bool isWalletEnabled()
void consoleShown(RPCConsole *console)
Signal raised when RPC console shown.
void createTrayIcon()
Create system tray icon and notification.
Definition: bitcoingui.cpp:833
Bilingual messages:
Definition: translation.h:24
void showDebugWindow()
Show debug window.
Definition: bitcoingui.cpp:943
GUIUtil::ClickableLabel * labelProxyIcon
Definition: bitcoingui.h:126
node::NodeContext m_node
Definition: bitcoin-gui.cpp:42
void PopupMenu(QMenu *menu, const QPoint &point, QAction *at_action)
Call QMenu::popup() only on supported QT_QPA_PLATFORM.
Definition: guiutil.cpp:948
ClientModel * clientModel
Definition: bitcoingui.h:120
void createToolBars()
Create the toolbars.
Definition: bitcoingui.cpp:588
int TextWidth(const QFontMetrics &fm, const QString &text)
Returns the distance in pixels appropriate for drawing a subsequent character after text...
Definition: guiutil.cpp:915
void setCurrentWallet(WalletModel *wallet_model)
Definition: walletframe.cpp:91
QAction * m_load_psbt_action
Definition: bitcoingui.h:143
void closeAllWallets(QWidget *parent=nullptr)
void setClientModel(ClientModel *model=nullptr, int bestblock_height=0, int64_t bestblock_date=0, double verification_progress=0.0)
Definition: rpcconsole.cpp:659
ModalOverlay * modalOverlay
Definition: bitcoingui.h:175
void createTrayIconMenu()
Create system tray menu (or setup the dock menu)
Definition: bitcoingui.cpp:846
RPCConsole * rpcConsole
Definition: bitcoingui.h:173
QAction * m_wallet_selector_action
Definition: bitcoingui.h:162
QAction * m_migrate_wallet_action
Definition: bitcoingui.h:164
QAction * overviewAction
Definition: bitcoingui.h:135
void opened(WalletModel *wallet_model)
QAction * verifyMessageAction
Definition: bitcoingui.h:142
QAction * quitAction
Definition: bitcoingui.h:137
void setPrivacy(bool privacy)
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:13
QAction * m_open_wallet_action
Definition: bitcoingui.h:156
void triggered(bool hidden)
void usedReceivingAddresses()
Show used receiving addresses.
QAction * m_close_wallet_action
Definition: bitcoingui.h:159
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const bilingual_str &message, const std::string &caption, unsigned int style)
Mask of all available buttons in CClientUIInterface::MessageBoxFlags This needs to be updated...
Definition: interface_ui.h:56
QAction * historyAction
Definition: bitcoingui.h:136
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:378
void updateHeadersPresyncProgressLabel(int64_t height, const QDateTime &blockDate)
void setWalletActionsEnabled(bool enabled)
Enable or disable all wallet-related actions.
Definition: bitcoingui.cpp:815
void networkActiveChanged(bool networkActive)
BitcoinUnit getDisplayUnit() const
Definition: optionsmodel.h:103
QAction * aboutQtAction
Definition: bitcoingui.h:151
void setClientModel(ClientModel *clientModel=nullptr, interfaces::BlockAndHeaderTipInfo *tip_info=nullptr)
Set the client model.
Definition: bitcoingui.cpp:624
Controller between interfaces::Node, WalletModel instances and the GUI.
OptionsModel * getOptionsModel()
bool getShowTrayIcon() const
Definition: optionsmodel.h:100
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
std::string translated
Definition: translation.h:26
QMenu * m_open_wallet_menu
Definition: bitcoingui.h:157
macOS-specific Dock icon handler.
void outOfSyncWarningClicked()
Notify that the out of sync warning icon has been pressed.
Bitcoin GUI main class.
Definition: bitcoingui.h:67
bool isLayerVisible() const
Definition: modaloverlay.h:33
HelpMessageDialog * helpMessageDialog
Definition: bitcoingui.h:174
QLabel * progressBarLabel
Definition: bitcoingui.h:129
QSystemTrayIcon * trayIcon
Definition: bitcoingui.h:170
QAction * showHelpMessageAction
Definition: bitcoingui.h:154
void ShowModalDialogAsynchronously(QDialog *dialog)
Shows a QDialog instance asynchronously, and deletes it on close.
Definition: guiutil.cpp:1004
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
Notify user of potential problem.
Definition: notificator.h:37
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
Modal overlay to display information about the chain-sync state.
Definition: modaloverlay.h:20
bool isPrivacyModeActivated() const
void changeEvent(QEvent *e) override
Warning
Definition: warning.h:9
const QString & getTitleAddText() const
Definition: networkstyle.h:24
void changeEvent(QEvent *e) override
void numConnectionsChanged(int count)
void setNetworkActive(bool network_active)
Set network state shown in the UI.
Signals for UI communication.
Definition: interface_ui.h:25
void removeAllWallets()
GUIUtil::ClickableLabel * connectionsControl
Definition: bitcoingui.h:127
QAction * backupWalletAction
Definition: bitcoingui.h:149
QAction * m_load_psbt_clipboard_action
Definition: bitcoingui.h:144
void setOptionsModel(OptionsModel *optionsModel)
Lets the control know about the Options Model (and its signals)
void dropEvent(QDropEvent *event) override
void bringToFront(QWidget *w)
Definition: guiutil.cpp:406
QString tabTitle(TabTypes tab_type) const
static QString formatWithUnit(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
Force blocking, modal message box dialog (not just OS notification)
Definition: interface_ui.h:60
void openOptionsDialogWithTab(OptionsDialog::Tab tab)
Open the OptionsDialog on the specified tab index.
EncryptionStatus getEncryptionStatus() const
virtual std::unique_ptr< Handler > handleMessageBox(MessageBoxFn fn)=0
void showOutOfSyncWarning(bool fShow)
void gotoHistoryPage()
Switch to history (transactions) page.
QAction * usedReceivingAddressesAction
Definition: bitcoingui.h:140
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
void showModalOverlay()
const NetworkStyle *const m_network_style
Definition: bitcoingui.h:188
WalletController * m_wallet_controller
Definition: bitcoingui.h:117
void gotoOverviewPage()
Switch to overview (home) page.
BlockSource getBlockSource() const
Returns the block source of the current importing/syncing state.
const PlatformStyle * platformStyle
Definition: bitcoingui.h:187
void displayUnitChanged(BitcoinUnit unit)
virtual bool hdEnabled()=0
void showProgress(const QString &title, int nProgress)
Show progress dialog e.g.
static MacDockIconHandler * instance()
void setClientModel(ClientModel *clientModel)
Definition: walletframe.cpp:60
bool isObscured(QWidget *w)
Definition: guiutil.cpp:397
QAction * m_wallet_selector_label_action
Definition: bitcoingui.h:161
int getNumConnections(unsigned int flags=CONNECTIONS_ALL) const
Return number of connections, default is in- and outbound (total)
Definition: clientmodel.cpp:84
OptionsModel * optionsModel
Definition: bitcoingui.h:340
void created(WalletModel *wallet_model)
QLabel * m_wallet_selector_label
Definition: bitcoingui.h:167
void optionsClicked()
Show configuration dialog.
Definition: bitcoingui.cpp:929
void setNumBlocks(int count, const QDateTime &blockDate, double nVerificationProgress, SyncType synctype, SynchronizationState sync_state)
Set number of blocks and last block date shown in the UI.
void closeWallet(WalletModel *wallet_model, QWidget *parent=nullptr)
void gotoVerifyMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to verify message tab.
void incomingTransaction(const QString &date, BitcoinUnit unit, const CAmount &amount, const QString &type, const QString &address, const QString &label, const QString &walletName)
Notify that a new transaction appeared.
bool HasPixmap(const QLabel *label)
Returns true if pixmap has been set.
Definition: guiutil.cpp:964
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:431
void notify(Class cls, const QString &title, const QString &text, const QIcon &icon=QIcon(), int millisTimeout=10000)
Show notification message.
const char * name
Definition: rest.cpp:49
QToolBar * appToolBar
Definition: bitcoingui.h:134
BlockSource
Definition: clientmodel.h:36
WalletFrame * walletFrame
Definition: bitcoingui.h:121
WalletView * currentWalletView() const
QAction * usedSendingAddressesAction
Definition: bitcoingui.h:139
void setTabFocus(enum TabTypes tabType)
set which tab has the focus (is visible)
int64_t nPowTargetSpacing
Definition: params.h:117
BitcoinGUI(interfaces::Node &node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent=nullptr)
Definition: bitcoingui.cpp:85
void updateDisplayUnit(BitcoinUnit newUnits)
When Display Units are changed on OptionsModel it will refresh the display text of the control on the...
void message(const QString &title, const QString &message, unsigned int style)
Fired when a message should be reported to the user.
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, SyncType header, SynchronizationState sync_state)
void toggleVisibility()
QVariant getOption(OptionID option, const std::string &suffix="") const
bool enableWallet
Definition: bitcoingui.h:95
auto ExceptionSafeConnect(Sender sender, Signal signal, Receiver receiver, Slot method, Qt::ConnectionType type=Qt::AutoConnection)
A drop-in replacement of QObject::connect function (see: https://doc.qt.io/qt-5/qobject.html#connect-3), that guaranties that all exceptions are handled within the slot.
Definition: guiutil.h:391
QAction * openRPCConsoleAction
Definition: bitcoingui.h:152
QAction * m_close_all_wallets_action
Definition: bitcoingui.h:160
void currentWalletSet()
std::vector< TabTypes > tabs() const
Definition: rpcconsole.h:76
void detectShutdown()
called by a timer to check if shutdown has been requested
void migrated(WalletModel *wallet_model)
Cross-platform desktop notification client.
Definition: notificator.h:22
void clicked(const QPoint &point)
Emitted when the label is clicked.
Block and header tip information.
Definition: node.h:50
void setKnownBestHeight(int count, const QDateTime &blockDate, bool presync)
GUIUtil::ClickableLabel * labelBlocksIcon
Definition: bitcoingui.h:128
Informational message.
Definition: notificator.h:36
GUIUtil::ClickableProgressBar * progressBar
Definition: bitcoingui.h:130
void updateWindowTitle()
void showHelpMessageClicked()
Show help message dialog.
Definition: bitcoingui.cpp:955
QString getWalletName() const
void walletAdded(WalletModel *wallet_model)
void message(const QString &title, const QString &message, unsigned int style)
Notificator * notificator
Definition: bitcoingui.h:172
void PolishProgressDialog(QProgressDialog *dialog)
Definition: guiutil.cpp:901
void changePassphrase()
Change encrypted wallet passphrase.
Model for Bitcoin network client.
Definition: clientmodel.h:56
An error occurred.
Definition: notificator.h:38
void restored(WalletModel *wallet_model)
const QIcon & getTrayAndWindowIcon() const
Definition: networkstyle.h:23
void mousePressEvent(QMouseEvent *event) override
So that it responds to left-button clicks.
ClickableProgressBar ProgressBar
Definition: guiutil.h:300
void gotoSignMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to sign message tab.
virtual bool shutdownRequested()=0
Return whether shutdown was requested.
virtual std::vector< std::unique_ptr< Wallet > > getWallets()=0
Return interfaces for accessing wallets (if any).
QAction * sendCoinsAction
Definition: bitcoingui.h:138
void showHide(bool hide=false, bool userRequested=false)
QAction * m_create_wallet_action
Definition: bitcoingui.h:155
SyncType
Definition: clientmodel.h:42
QKeySequence tabShortcut(TabTypes tab_type) const
Definition: messages.h:20
static const int STATUSBAR_ICONSIZE
Definition: guiconstants.h:23
void message(const QString &title, QString message, unsigned int style, bool *ret=nullptr, const QString &detailed_message=QString())
Notify the user of an event from the core network or transaction handling code.
QColor SingleColor() const
void encryptionStatusChanged()
Encryption status of wallet changed.
QAction * openAction
Definition: bitcoingui.h:153
bool getMinimizeOnClose() const
Definition: optionsmodel.h:102
void updateProxyIcon()
Set the proxy-enabled icon as shown in the UI.
QAction * changePassphraseAction
Definition: bitcoingui.h:150
void gotoSendCoinsPage(QString addr="")
Switch to send coins page.
virtual std::unique_ptr< Handler > handleQuestion(QuestionFn fn)=0
void encryptWallet()
Encrypt the wallet.
QString WalletDisplayName(const QString &name)
Definition: guiutil.cpp:1011
void gotoReceiveCoinsPage()
Switch to receive coins page.
const std::unique_ptr< QMenu > trayIconMenu
Definition: bitcoingui.h:171
QMenu * m_network_context_menu
Definition: bitcoingui.h:177
void setPrivacy(bool privacy)
std::string original
Definition: translation.h:25
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:42
std::unique_ptr< interfaces::Handler > m_handler_question
Definition: bitcoingui.h:119
const CChainParams & Params()
Return the currently selected parameters.
bool getMinimizeToTray() const
Definition: optionsmodel.h:101
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:47
virtual WalletLoader & walletLoader()=0
Get wallet loader.
QAction * m_restore_wallet_action
Definition: bitcoingui.h:158
std::map< std::string, std::pair< bool, std::string > > listWalletDir() const
Returns all wallet names in the wallet dir mapped to whether the wallet is loaded.
bool eventFilter(QObject *object, QEvent *event) override
WalletModel * getWalletModel() const noexcept
Definition: walletview.h:46
int prevBlocks
Keep track of previous number of blocks, to detect progress.
Definition: bitcoingui.h:184
void toggleHidden()
Simply calls showNormalIfMinimized(true)
interfaces::Node & m_node
Definition: bitcoingui.h:116
int spinnerFrame
Definition: bitcoingui.h:185
void walletRemoved(WalletModel *wallet_model)
GUIUtil::ThemedLabel * labelWalletEncryptionIcon
Definition: bitcoingui.h:124
void quitOnReset()
static int count
void setNumConnections(int count)
Set number of connections shown in the UI.
QString getDisplayName() const
"Help message" dialog box
Definition: utilitydialog.h:20
void backupWallet()
Backup the wallet.
void closeEvent(QCloseEvent *event) override
QComboBox * m_wallet_selector
Definition: bitcoingui.h:168
bool addView(WalletView *walletView)
Definition: walletframe.cpp:69
Preferences dialog.
Definition: optionsdialog.h:36
void clicked(const QPoint &point)
Emitted when the progressbar is clicked.
QString formatNiceTimeOffset(qint64 secs)
Definition: guiutil.cpp:787
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:949
void createActions()
Create the main UI actions.
Definition: bitcoingui.cpp:247
QAction * optionsAction
Definition: bitcoingui.h:147
QAction * encryptWalletAction
Definition: bitcoingui.h:148
void aboutClicked()
Show about dialog.
Definition: bitcoingui.cpp:934
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:93
const PlatformStyle * m_platform_style
Definition: bitcoingui.h:342
void createWallet()
Launch the wallet creation modal (no-op if wallet is not compiled)
void removeWallet(WalletModel *wallet_model)
int getHeaderTipHeight() const
Definition: clientmodel.cpp:98
void updateHeadersSyncProgressLabel()
void gotoLoadPSBT(bool from_clipboard=false)
Load Partially Signed Bitcoin Transaction.
int64_t GetTime()
DEPRECATED, see GetTime.
Definition: time.cpp:76
static const std::string DEFAULT_UIPLATFORM
Definition: bitcoingui.h:72
static QString longName(Unit unit)
Long name.
void coinsSent()
virtual void setNetworkActive(bool active)=0
Set network active.
int64_t getHeaderTipTime() const
GUIUtil::ThemedLabel * labelWalletHDStatusIcon
Definition: bitcoingui.h:125
static RPCHelpMan help()
Definition: server.cpp:127
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
void transactionClicked()
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:45
A container for embedding all wallet-related controls into BitcoinGUI.
Definition: walletframe.h:28
void showProgress(const QString &title, int nProgress)
void usedSendingAddresses()
Show used sending addresses.
void setDisplayUnit(const QVariant &new_unit)
Updates current unit in memory, settings and emits displayUnitChanged(new_unit) signal.
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:494
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:118
void showTrayIconChanged(bool)
#define SPINNER_FRAMES
Definition: guiconstants.h:47
void dragEnterEvent(QDragEnterEvent *event) override
bool getProxyInfo(std::string &ip_port) const