diff options
Diffstat (limited to 'src/qt/bitcoingui.cpp')
-rw-r--r-- | src/qt/bitcoingui.cpp | 514 |
1 files changed, 335 insertions, 179 deletions
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index c8f8b9c7d3..ff66df376b 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2017 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,6 +19,7 @@ #include <qt/utilitydialog.h> #ifdef ENABLE_WALLET +#include <qt/walletcontroller.h> #include <qt/walletframe.h> #include <qt/walletmodel.h> #include <qt/walletview.h> @@ -28,13 +29,15 @@ #include <qt/macdockiconhandler.h> #endif +#include <chain.h> #include <chainparams.h> #include <interfaces/handler.h> #include <interfaces/node.h> #include <ui_interface.h> -#include <util.h> +#include <util/system.h> #include <iostream> +#include <memory> #include <QAction> #include <QApplication> @@ -43,6 +46,7 @@ #include <QDesktopWidget> #include <QDragEnterEvent> #include <QListWidget> +#include <QMenu> #include <QMenuBar> #include <QMessageBox> #include <QMimeData> @@ -52,10 +56,13 @@ #include <QStackedWidget> #include <QStatusBar> #include <QStyle> +#include <QSystemTrayIcon> #include <QTimer> #include <QToolBar> #include <QUrlQuery> #include <QVBoxLayout> +#include <QWindow> + const std::string BitcoinGUI::DEFAULT_UIPLATFORM = #if defined(Q_OS_MAC) @@ -70,7 +77,9 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), m_node(node), - platformStyle(_platformStyle) + trayIconMenu{new QMenu()}, + platformStyle(_platformStyle), + m_network_style(networkStyle) { QSettings settings; if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) { @@ -78,26 +87,14 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); } - QString windowTitle = tr(PACKAGE_NAME) + " - "; #ifdef ENABLE_WALLET enableWallet = WalletModel::isWalletEnabled(); #endif // ENABLE_WALLET - if(enableWallet) - { - windowTitle += tr("Wallet"); - } else { - windowTitle += tr("Node"); - } - windowTitle += " " + networkStyle->getTitleAddText(); -#ifndef Q_OS_MAC - QApplication::setWindowIcon(networkStyle->getTrayAndWindowIcon()); - setWindowIcon(networkStyle->getTrayAndWindowIcon()); -#else - MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon()); -#endif - setWindowTitle(windowTitle); + QApplication::setWindowIcon(m_network_style->getTrayAndWindowIcon()); + setWindowIcon(m_network_style->getTrayAndWindowIcon()); + updateWindowTitle(); - rpcConsole = new RPCConsole(node, _platformStyle, 0); + rpcConsole = new RPCConsole(node, _platformStyle, nullptr); helpMessageDialog = new HelpMessageDialog(node, this, false); #ifdef ENABLE_WALLET if(enableWallet) @@ -112,6 +109,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty * the central widget is the rpc console. */ setCentralWidget(rpcConsole); + Q_EMIT consoleShown(rpcConsole); } // Accept D&D of URIs @@ -128,7 +126,10 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty createToolBars(); // Create system tray icon and notification - createTrayIcon(networkStyle); + if (QSystemTrayIcon::isSystemTrayAvailable()) { + createTrayIcon(); + } + notificator = new Notificator(QApplication::applicationName(), trayIcon, this); // Create status bar statusBar(); @@ -146,7 +147,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle); labelWalletEncryptionIcon = new QLabel(); labelWalletHDStatusIcon = new QLabel(); - labelProxyIcon = new QLabel(); + labelProxyIcon = new GUIUtil::ClickableLabel(); connectionsControl = new GUIUtil::ClickableLabel(); labelBlocksIcon = new GUIUtil::ClickableLabel(); if(enableWallet) @@ -193,16 +194,25 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty // Subscribe to notifications from core subscribeToCoreSignals(); - connect(connectionsControl, SIGNAL(clicked(QPoint)), this, SLOT(toggleNetworkActive())); + connect(connectionsControl, &GUIUtil::ClickableLabel::clicked, [this] { + m_node.setNetworkActive(!m_node.getNetworkActive()); + }); + connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked, [this] { + openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK); + }); modalOverlay = new ModalOverlay(this->centralWidget()); #ifdef ENABLE_WALLET if(enableWallet) { - connect(walletFrame, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay())); - connect(labelBlocksIcon, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay())); - connect(progressBar, SIGNAL(clicked(QPoint)), this, SLOT(showModalOverlay())); + connect(walletFrame, &WalletFrame::requestedSyncWarningInfo, this, &BitcoinGUI::showModalOverlay); + connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showModalOverlay); + connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this, &BitcoinGUI::showModalOverlay); } #endif + +#ifdef Q_OS_MAC + m_app_nap_inhibitor = new CAppNapInhibitor; +#endif } BitcoinGUI::~BitcoinGUI() @@ -215,6 +225,7 @@ BitcoinGUI::~BitcoinGUI() if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) trayIcon->hide(); #ifdef Q_OS_MAC + delete m_app_nap_inhibitor; delete appMenuBar; MacDockIconHandler::cleanup(); #endif @@ -265,18 +276,18 @@ void BitcoinGUI::createActions() #ifdef ENABLE_WALLET // These showNormalIfMinimized are needed because Send Coins and Receive Coins // can be triggered from the tray menu, and need to show the GUI to be useful. - connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); - connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(sendCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); - connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); - connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(receiveCoinsMenuAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); - connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); - connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); + connect(overviewAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage); + connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); }); + connect(sendCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); }); + connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); + connect(receiveCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); + connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage); #endif // ENABLE_WALLET quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this); @@ -313,45 +324,104 @@ void BitcoinGUI::createActions() openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console")); // initially disable the debug window menu item openRPCConsoleAction->setEnabled(false); + openRPCConsoleAction->setObjectName("openRPCConsoleAction"); - usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this); + usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this); usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels")); - usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this); + usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses"), this); usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels")); openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a bitcoin: URI or payment request")); + m_open_wallet_action = new QAction(tr("Open Wallet"), this); + m_open_wallet_action->setMenu(new QMenu(this)); + m_open_wallet_action->setStatusTip(tr("Open a wallet")); + + m_close_wallet_action = new QAction(tr("Close Wallet..."), this); + m_close_wallet_action->setStatusTip(tr("Close wallet")); + showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME))); - connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); - connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); - connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); - connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); - connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); - connect(openRPCConsoleAction, SIGNAL(triggered()), this, SLOT(showDebugWindow())); + connect(quitAction, &QAction::triggered, qApp, QApplication::quit); + connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked); + connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt); + connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked); + connect(toggleHideAction, &QAction::triggered, this, &BitcoinGUI::toggleHidden); + connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked); + connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow); // prevents an open debug window from becoming stuck/unusable on client shutdown - connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide())); + connect(quitAction, &QAction::triggered, rpcConsole, &QWidget::hide); #ifdef ENABLE_WALLET if(walletFrame) { - connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool))); - connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet())); - connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase())); - connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); - connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); - connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses())); - connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); - connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); + connect(encryptWalletAction, &QAction::triggered, walletFrame, &WalletFrame::encryptWallet); + connect(backupWalletAction, &QAction::triggered, walletFrame, &WalletFrame::backupWallet); + connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase); + connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); }); + connect(verifyMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); + connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); }); + connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses); + connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses); + connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked); + connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] { + m_open_wallet_action->menu()->clear(); + std::vector<std::string> available_wallets = m_wallet_controller->getWalletsAvailableToOpen(); + std::vector<std::string> wallets = m_node.listWalletDir(); + for (const auto& path : wallets) { + QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); + QAction* action = m_open_wallet_action->menu()->addAction(name); + + if (std::find(available_wallets.begin(), available_wallets.end(), path) == available_wallets.end()) { + // This wallet is already loaded + action->setEnabled(false); + continue; + } + + connect(action, &QAction::triggered, [this, name, path] { + OpenWalletActivity* activity = m_wallet_controller->openWallet(path); + + QProgressDialog* dialog = new QProgressDialog(this); + dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped())); + dialog->setRange(0, 0); + dialog->setCancelButton(nullptr); + dialog->setWindowModality(Qt::ApplicationModal); + dialog->show(); + + connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) { + QMessageBox box; + box.setIcon(icon); + box.setText(tr("Open Wallet Failed")); + box.setInformativeText(text); + box.setStandardButtons(QMessageBox::Ok); + box.setDefaultButton(QMessageBox::Ok); + connect(this, &QObject::destroyed, &box, &QDialog::accept); + box.exec(); + }); + connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet); + connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater); + connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater); + bool invoked = QMetaObject::invokeMethod(activity, "open"); + assert(invoked); + }); + } + if (wallets.empty()) { + QAction* action = m_open_wallet_action->menu()->addAction(tr("No wallets available")); + action->setEnabled(false); + } + }); + connect(m_close_wallet_action, &QAction::triggered, [this] { + m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this); + }); } #endif // ENABLE_WALLET - new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this, SLOT(showDebugWindowActivateConsole())); - new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this, SLOT(showDebugWindow())); + connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindowActivateConsole); + connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this), &QShortcut::activated, this, &BitcoinGUI::showDebugWindow); } void BitcoinGUI::createMenuBar() @@ -368,14 +438,14 @@ void BitcoinGUI::createMenuBar() QMenu *file = appMenuBar->addMenu(tr("&File")); if(walletFrame) { + file->addAction(m_open_wallet_action); + file->addAction(m_close_wallet_action); + file->addSeparator(); file->addAction(openAction); file->addAction(backupWalletAction); file->addAction(signMessageAction); file->addAction(verifyMessageAction); file->addSeparator(); - file->addAction(usedSendingAddressesAction); - file->addAction(usedReceivingAddressesAction); - file->addSeparator(); } file->addAction(quitAction); @@ -388,11 +458,64 @@ void BitcoinGUI::createMenuBar() } settings->addAction(optionsAction); - QMenu *help = appMenuBar->addMenu(tr("&Help")); - if(walletFrame) - { - help->addAction(openRPCConsoleAction); + QMenu* window_menu = appMenuBar->addMenu(tr("&Window")); + + QAction* minimize_action = window_menu->addAction(tr("Minimize")); + minimize_action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M)); + connect(minimize_action, &QAction::triggered, [] { + qApp->focusWindow()->showMinimized(); + }); + connect(qApp, &QApplication::focusWindowChanged, [minimize_action] (QWindow* window) { + minimize_action->setEnabled(window != nullptr && (window->flags() & Qt::Dialog) != Qt::Dialog && window->windowState() != Qt::WindowMinimized); + }); + +#ifdef Q_OS_MAC + QAction* zoom_action = window_menu->addAction(tr("Zoom")); + connect(zoom_action, &QAction::triggered, [] { + QWindow* window = qApp->focusWindow(); + if (window->windowState() != Qt::WindowMaximized) { + window->showMaximized(); + } else { + window->showNormal(); + } + }); + + connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) { + zoom_action->setEnabled(window != nullptr); + }); +#else + QAction* restore_action = window_menu->addAction(tr("Restore")); + connect(restore_action, &QAction::triggered, [] { + qApp->focusWindow()->showNormal(); + }); + + connect(qApp, &QApplication::focusWindowChanged, [restore_action] (QWindow* window) { + restore_action->setEnabled(window != nullptr); + }); +#endif + + if (walletFrame) { + window_menu->addSeparator(); + QAction* main_window_action = window_menu->addAction(tr("Main Window")); + connect(main_window_action, &QAction::triggered, [this] { + GUIUtil::bringToFront(this); + }); + + window_menu->addSeparator(); + window_menu->addAction(usedSendingAddressesAction); + window_menu->addAction(usedReceivingAddressesAction); + } + + window_menu->addSeparator(); + for (RPCConsole::TabTypes tab_type : rpcConsole->tabs()) { + QAction* tab_action = window_menu->addAction(rpcConsole->tabTitle(tab_type)); + connect(tab_action, &QAction::triggered, [this, tab_type] { + rpcConsole->setTabFocus(tab_type); + showDebugWindow(); + }); } + + QMenu *help = appMenuBar->addMenu(tr("&Help")); help->addAction(showHelpMessageAction); help->addSeparator(); help->addAction(aboutAction); @@ -420,7 +543,8 @@ void BitcoinGUI::createToolBars() toolbar->addWidget(spacer); m_wallet_selector = new QComboBox(); - connect(m_wallet_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentWalletBySelectorIndex(int))); + m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents); + connect(m_wallet_selector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex); m_wallet_selector_label = new QLabel(); m_wallet_selector_label->setText(tr("Wallet:") + " "); @@ -446,18 +570,20 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) // Keep up to date with client updateNetworkState(); - connect(_clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool))); + connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections); + connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive); modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime())); setNumBlocks(m_node.getNumBlocks(), QDateTime::fromTime_t(m_node.getLastBlockTime()), m_node.getVerificationProgress(), false); - connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); + connect(_clientModel, &ClientModel::numBlocksChanged, this, &BitcoinGUI::setNumBlocks); // Receive and report messages from client model - connect(_clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); + connect(_clientModel, &ClientModel::message, [this](const QString &title, const QString &message, unsigned int style){ + this->message(title, message, style); + }); // Show progress dialog - connect(_clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); + connect(_clientModel, &ClientModel::showProgress, this, &BitcoinGUI::showProgress); rpcConsole->setClientModel(_clientModel); @@ -472,10 +598,9 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel()); OptionsModel* optionsModel = _clientModel->getOptionsModel(); - if(optionsModel) - { + if (optionsModel && trayIcon) { // be aware of the tray icon disable state change reported by the OptionsModel object. - connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool))); + connect(optionsModel, &OptionsModel::hideTrayIconChanged, this, &BitcoinGUI::setTrayIconVisible); // initialize the disable state of the tray icon with the current value in the model. setTrayIconVisible(optionsModel->getHideTrayIcon()); @@ -501,27 +626,39 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) } #ifdef ENABLE_WALLET -bool BitcoinGUI::addWallet(WalletModel *walletModel) +void BitcoinGUI::setWalletController(WalletController* wallet_controller) { - if(!walletFrame) - return false; - const QString name = walletModel->getWalletName(); - QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name; + assert(!m_wallet_controller); + assert(wallet_controller); + + m_wallet_controller = wallet_controller; + + connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); + connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); + + for (WalletModel* wallet_model : m_wallet_controller->getWallets()) { + addWallet(wallet_model); + } +} + +void BitcoinGUI::addWallet(WalletModel* walletModel) +{ + if (!walletFrame) return; + const QString display_name = walletModel->getDisplayName(); setWalletActionsEnabled(true); - m_wallet_selector->addItem(display_name, name); + rpcConsole->addWallet(walletModel); + walletFrame->addWallet(walletModel); + m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); if (m_wallet_selector->count() == 2) { m_wallet_selector_label_action->setVisible(true); m_wallet_selector_action->setVisible(true); } - rpcConsole->addWallet(walletModel); - return walletFrame->addWallet(walletModel); } -bool BitcoinGUI::removeWallet(WalletModel* walletModel) +void BitcoinGUI::removeWallet(WalletModel* walletModel) { - if (!walletFrame) return false; - QString name = walletModel->getWalletName(); - int index = m_wallet_selector->findData(name); + if (!walletFrame) return; + int index = m_wallet_selector->findData(QVariant::fromValue(walletModel)); m_wallet_selector->removeItem(index); if (m_wallet_selector->count() == 0) { setWalletActionsEnabled(false); @@ -530,20 +667,27 @@ bool BitcoinGUI::removeWallet(WalletModel* walletModel) m_wallet_selector_action->setVisible(false); } rpcConsole->removeWallet(walletModel); - return walletFrame->removeWallet(name); + walletFrame->removeWallet(walletModel); + updateWindowTitle(); } -bool BitcoinGUI::setCurrentWallet(const QString& name) +void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model) { - if(!walletFrame) - return false; - return walletFrame->setCurrentWallet(name); + if (!walletFrame) return; + walletFrame->setCurrentWallet(wallet_model); + for (int index = 0; index < m_wallet_selector->count(); ++index) { + if (m_wallet_selector->itemData(index).value<WalletModel*>() == wallet_model) { + m_wallet_selector->setCurrentIndex(index); + break; + } + } + updateWindowTitle(); } -bool BitcoinGUI::setCurrentWalletBySelectorIndex(int index) +void BitcoinGUI::setCurrentWalletBySelectorIndex(int index) { - QString internal_name = m_wallet_selector->itemData(index).toString(); - return setCurrentWallet(internal_name); + WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>(); + if (wallet_model) setCurrentWallet(wallet_model); } void BitcoinGUI::removeAllWallets() @@ -571,52 +715,55 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) usedSendingAddressesAction->setEnabled(enabled); usedReceivingAddressesAction->setEnabled(enabled); openAction->setEnabled(enabled); + m_close_wallet_action->setEnabled(enabled); } -void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) +void BitcoinGUI::createTrayIcon() { + assert(QSystemTrayIcon::isSystemTrayAvailable()); + #ifndef Q_OS_MAC - trayIcon = new QSystemTrayIcon(this); - QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); - trayIcon->setToolTip(toolTip); - trayIcon->setIcon(networkStyle->getTrayAndWindowIcon()); - trayIcon->hide(); + if (QSystemTrayIcon::isSystemTrayAvailable()) { + trayIcon = new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this); + QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + m_network_style->getTitleAddText(); + trayIcon->setToolTip(toolTip); + } #endif - - notificator = new Notificator(QApplication::applicationName(), trayIcon, this); } void BitcoinGUI::createTrayIconMenu() { #ifndef Q_OS_MAC - // return if trayIcon is unset (only on non-Mac OSes) + // return if trayIcon is unset (only on non-macOSes) if (!trayIcon) return; - trayIconMenu = new QMenu(this); - trayIcon->setContextMenu(trayIconMenu); - - connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), - this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); + trayIcon->setContextMenu(trayIconMenu.get()); + connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated); #else - // Note: On Mac, the dock icon is used to provide the tray's functionality. + // Note: On macOS, the Dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); - dockIconHandler->setMainWindow(static_cast<QMainWindow*>(this)); - trayIconMenu = dockIconHandler->dockMenu(); + connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated); + trayIconMenu->setAsDockMenu(); #endif - // Configuration of the tray icon (or dock icon) icon menu + // Configuration of the tray icon (or Dock icon) menu +#ifndef Q_OS_MAC + // Note: On macOS, the Dock icon's menu already has Show / Hide action. trayIconMenu->addAction(toggleHideAction); trayIconMenu->addSeparator(); - trayIconMenu->addAction(sendCoinsMenuAction); - trayIconMenu->addAction(receiveCoinsMenuAction); - trayIconMenu->addSeparator(); - trayIconMenu->addAction(signMessageAction); - trayIconMenu->addAction(verifyMessageAction); - trayIconMenu->addSeparator(); +#endif + if (enableWallet) { + trayIconMenu->addAction(sendCoinsMenuAction); + trayIconMenu->addAction(receiveCoinsMenuAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(signMessageAction); + trayIconMenu->addAction(verifyMessageAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(openRPCConsoleAction); + } trayIconMenu->addAction(optionsAction); - trayIconMenu->addAction(openRPCConsoleAction); -#ifndef Q_OS_MAC // This is built-in on Mac +#ifndef Q_OS_MAC // This is built-in on macOS trayIconMenu->addSeparator(); trayIconMenu->addAction(quitAction); #endif @@ -631,16 +778,17 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) toggleHidden(); } } +#else +void BitcoinGUI::macosDockIconActivated() +{ + show(); + activateWindow(); +} #endif void BitcoinGUI::optionsClicked() { - if(!clientModel || !clientModel->getOptionsModel()) - return; - - OptionsDialog dlg(this, enableWallet); - dlg.setModel(clientModel->getOptionsModel()); - dlg.exec(); + openOptionsDialogWithTab(OptionsDialog::TAB_MAIN); } void BitcoinGUI::aboutClicked() @@ -654,10 +802,8 @@ void BitcoinGUI::aboutClicked() void BitcoinGUI::showDebugWindow() { - rpcConsole->showNormal(); - rpcConsole->show(); - rpcConsole->raise(); - rpcConsole->activateWindow(); + GUIUtil::bringToFront(rpcConsole); + Q_EMIT consoleShown(rpcConsole); } void BitcoinGUI::showDebugWindowActivateConsole() @@ -764,8 +910,24 @@ void BitcoinGUI::updateHeadersSyncProgressLabel() progressBarLabel->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight+estHeadersLeft)*headersTipHeight, 'f', 1))); } +void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab) +{ + if (!clientModel || !clientModel->getOptionsModel()) + return; + + OptionsDialog dlg(this, enableWallet); + dlg.setCurrentTab(tab); + dlg.setModel(clientModel->getOptionsModel()); + dlg.exec(); +} + void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header) { +// Disabling macOS App Nap on initial sync, disk and reindex operations. +#ifdef Q_OS_MAC + (m_node.isInitialBlockDownload() || m_node.getReindex() || m_node.getImporting()) ? m_app_nap_inhibitor->disableAppNap() : m_app_nap_inhibitor->enableAppNap(); +#endif + if (modalOverlay) { if (header) @@ -816,8 +978,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer tooltip = tr("Processed %n block(s) of transaction history.", "", count); // Set icon state: spinning if catching up, tick otherwise - if(secs < 90*60) - { + if (secs < MAX_BLOCK_TIME_GAP) { tooltip = tr("Up to date") + QString(".<br>") + tooltip; labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); @@ -945,12 +1106,12 @@ void BitcoinGUI::changeEvent(QEvent *e) QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e); if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized()) { - QTimer::singleShot(0, this, SLOT(hide())); + QTimer::singleShot(0, this, &BitcoinGUI::hide); e->ignore(); } else if((wsevt->oldState() & Qt::WindowMinimized) && !isMinimized()) { - QTimer::singleShot(0, this, SLOT(show())); + QTimer::singleShot(0, this, &BitcoinGUI::show); e->ignore(); } } @@ -1052,10 +1213,10 @@ bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient) return false; } -void BitcoinGUI::setHDStatus(int hdEnabled) +void BitcoinGUI::setHDStatus(bool privkeyDisabled, int hdEnabled) { - labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); - labelWalletHDStatusIcon->setToolTip(hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>")); + labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(privkeyDisabled ? ":/icons/eye" : hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + 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>")); // eventually disable the QLabel to set its opacity to 50% labelWalletHDStatusIcon->setEnabled(hdEnabled); @@ -1101,7 +1262,7 @@ void BitcoinGUI::updateWalletStatus() } WalletModel * const walletModel = walletView->getWalletModel(); setEncryptionStatus(walletModel->getEncryptionStatus()); - setHDStatus(walletModel->wallet().hdEnabled()); + setHDStatus(walletModel->privateKeysDisabled(), walletModel->wallet().hdEnabled()); } #endif // ENABLE_WALLET @@ -1111,7 +1272,7 @@ void BitcoinGUI::updateProxyIcon() bool proxy_enabled = clientModel->getProxyInfo(ip_port); if (proxy_enabled) { - if (labelProxyIcon->pixmap() == 0) { + if (labelProxyIcon->pixmap() == nullptr) { QString ip_port_q = QString::fromStdString(ip_port); labelProxyIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/proxy").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelProxyIcon->setToolTip(tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q)); @@ -1123,29 +1284,33 @@ void BitcoinGUI::updateProxyIcon() } } +void BitcoinGUI::updateWindowTitle() +{ + QString window_title = tr(PACKAGE_NAME); +#ifdef ENABLE_WALLET + if (walletFrame) { + WalletModel* const wallet_model = walletFrame->currentWalletModel(); + if (wallet_model && !wallet_model->getWalletName().isEmpty()) { + window_title += " - " + wallet_model->getDisplayName(); + } + } +#endif + if (!m_network_style->getTitleAddText().isEmpty()) { + window_title += " - " + m_network_style->getTitleAddText(); + } + setWindowTitle(window_title); +} + void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) { if(!clientModel) return; - // activateWindow() (sometimes) helps with keyboard focus on Windows - if (isHidden()) - { - show(); - activateWindow(); - } - else if (isMinimized()) - { - showNormal(); - activateWindow(); - } - else if (GUIUtil::isObscured(this)) - { - raise(); - activateWindow(); - } - else if(fToggleHidden) + if (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this) && fToggleHidden) { hide(); + } else { + GUIUtil::bringToFront(this); + } } void BitcoinGUI::toggleHidden() @@ -1165,25 +1330,21 @@ void BitcoinGUI::detectShutdown() void BitcoinGUI::showProgress(const QString &title, int nProgress) { - if (nProgress == 0) - { - progressDialog = new QProgressDialog(title, "", 0, 100); + if (nProgress == 0) { + progressDialog = new QProgressDialog(title, QString(), 0, 100); + GUIUtil::PolishProgressDialog(progressDialog); progressDialog->setWindowModality(Qt::ApplicationModal); progressDialog->setMinimumDuration(0); - progressDialog->setCancelButton(0); progressDialog->setAutoClose(false); progressDialog->setValue(0); - } - else if (nProgress == 100) - { - if (progressDialog) - { + } else if (nProgress == 100) { + if (progressDialog) { progressDialog->close(); progressDialog->deleteLater(); } - } - else if (progressDialog) + } else if (progressDialog) { progressDialog->setValue(nProgress); + } } void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) @@ -1200,7 +1361,7 @@ void BitcoinGUI::showModalOverlay() modalOverlay->toggleVisibility(); } -static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style) +static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, const std::string& caption, unsigned int style) { bool modal = (style & CClientUIInterface::MODAL); // The SECURE flag has no effect in the Qt GUI. @@ -1220,8 +1381,8 @@ static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, co void BitcoinGUI::subscribeToCoreSignals() { // Connect signals to client - m_handler_message_box = m_node.handleMessageBox(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); - m_handler_question = m_node.handleQuestion(boost::bind(ThreadSafeMessageBox, this, _1, _3, _4)); + m_handler_message_box = m_node.handleMessageBox(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + m_handler_question = m_node.handleQuestion(std::bind(ThreadSafeMessageBox, this, std::placeholders::_1, std::placeholders::_3, std::placeholders::_4)); } void BitcoinGUI::unsubscribeFromCoreSignals() @@ -1231,14 +1392,9 @@ void BitcoinGUI::unsubscribeFromCoreSignals() m_handler_question->disconnect(); } -void BitcoinGUI::toggleNetworkActive() -{ - m_node.setNetworkActive(!m_node.getNetworkActive()); -} - UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) : - optionsModel(0), - menu(0) + optionsModel(nullptr), + menu(nullptr) { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); @@ -1264,13 +1420,13 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) + for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { QAction *menuAction = new QAction(QString(BitcoinUnits::longName(u)), this); menuAction->setData(QVariant(u)); menu->addAction(menuAction); } - connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*))); + connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection); } /** Lets the control know about the Options Model (and its signals) */ @@ -1281,7 +1437,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel) this->optionsModel = _optionsModel; // be aware of a display unit change reported by the OptionsModel object. - connect(_optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int))); + connect(_optionsModel, &OptionsModel::displayUnitChanged, this, &UnitDisplayStatusBarControl::updateDisplayUnit); // initialize the display units label with the current value in the model. updateDisplayUnit(_optionsModel->getDisplayUnit()); |