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