LCOV - code coverage report
Current view: top level - src/qt - bitcoin.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 43 317 13.6 %
Date: 2020-09-26 01:30:44 Functions: 8 35 22.9 %

          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             : #if defined(HAVE_CONFIG_H)
       6             : #include <config/bitcoin-config.h>
       7             : #endif
       8             : 
       9             : #include <qt/bitcoin.h>
      10             : #include <qt/bitcoingui.h>
      11             : 
      12             : #include <chainparams.h>
      13             : #include <qt/clientmodel.h>
      14             : #include <qt/guiconstants.h>
      15             : #include <qt/guiutil.h>
      16             : #include <qt/intro.h>
      17             : #include <qt/networkstyle.h>
      18             : #include <qt/optionsmodel.h>
      19             : #include <qt/platformstyle.h>
      20             : #include <qt/splashscreen.h>
      21             : #include <qt/utilitydialog.h>
      22             : #include <qt/winshutdownmonitor.h>
      23             : 
      24             : #ifdef ENABLE_WALLET
      25             : #include <qt/paymentserver.h>
      26             : #include <qt/walletcontroller.h>
      27             : #include <qt/walletmodel.h>
      28             : #endif // ENABLE_WALLET
      29             : 
      30             : #include <init.h>
      31             : #include <interfaces/handler.h>
      32             : #include <interfaces/node.h>
      33             : #include <node/context.h>
      34             : #include <node/ui_interface.h>
      35             : #include <noui.h>
      36             : #include <uint256.h>
      37             : #include <util/system.h>
      38             : #include <util/threadnames.h>
      39             : #include <util/translation.h>
      40             : #include <validation.h>
      41             : 
      42             : #include <boost/signals2/connection.hpp>
      43             : #include <memory>
      44             : 
      45             : #include <QApplication>
      46             : #include <QDebug>
      47             : #include <QLibraryInfo>
      48             : #include <QLocale>
      49             : #include <QMessageBox>
      50             : #include <QSettings>
      51             : #include <QThread>
      52             : #include <QTimer>
      53             : #include <QTranslator>
      54             : 
      55             : #if defined(QT_STATICPLUGIN)
      56             : #include <QtPlugin>
      57             : #if defined(QT_QPA_PLATFORM_XCB)
      58             : Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
      59             : #elif defined(QT_QPA_PLATFORM_WINDOWS)
      60             : Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
      61             : #elif defined(QT_QPA_PLATFORM_COCOA)
      62             : Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
      63             : #endif
      64             : #endif
      65             : 
      66             : // Declare meta types used for QMetaObject::invokeMethod
      67           2 : Q_DECLARE_METATYPE(bool*)
      68             : Q_DECLARE_METATYPE(CAmount)
      69           2 : Q_DECLARE_METATYPE(SynchronizationState)
      70             : Q_DECLARE_METATYPE(uint256)
      71             : 
      72           1 : static void RegisterMetaTypes()
      73             : {
      74             :     // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
      75           1 :     qRegisterMetaType<bool*>();
      76           1 :     qRegisterMetaType<SynchronizationState>();
      77             :   #ifdef ENABLE_WALLET
      78           1 :     qRegisterMetaType<WalletModel*>();
      79             :   #endif
      80             :     // Register typedefs (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
      81             :     // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
      82           1 :     qRegisterMetaType<CAmount>("CAmount");
      83           1 :     qRegisterMetaType<size_t>("size_t");
      84             : 
      85           1 :     qRegisterMetaType<std::function<void()>>("std::function<void()>");
      86           1 :     qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
      87           1 :     qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
      88           1 : }
      89             : 
      90           0 : static QString GetLangTerritory()
      91             : {
      92           0 :     QSettings settings;
      93             :     // Get desired locale (e.g. "de_DE")
      94             :     // 1) System default language
      95           0 :     QString lang_territory = QLocale::system().name();
      96             :     // 2) Language from QSettings
      97           0 :     QString lang_territory_qsettings = settings.value("language", "").toString();
      98           0 :     if(!lang_territory_qsettings.isEmpty())
      99           0 :         lang_territory = lang_territory_qsettings;
     100             :     // 3) -lang command line argument
     101           0 :     lang_territory = QString::fromStdString(gArgs.GetArg("-lang", lang_territory.toStdString()));
     102             :     return lang_territory;
     103           0 : }
     104             : 
     105             : /** Set up translations */
     106           0 : static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
     107             : {
     108             :     // Remove old translators
     109           0 :     QApplication::removeTranslator(&qtTranslatorBase);
     110           0 :     QApplication::removeTranslator(&qtTranslator);
     111           0 :     QApplication::removeTranslator(&translatorBase);
     112           0 :     QApplication::removeTranslator(&translator);
     113             : 
     114             :     // Get desired locale (e.g. "de_DE")
     115           1 :     // 1) System default language
     116           1 :     QString lang_territory = GetLangTerritory();
     117             : 
     118             :     // Convert to "de" only by truncating "_DE"
     119           0 :     QString lang = lang_territory;
     120           0 :     lang.truncate(lang_territory.lastIndexOf('_'));
     121           1 : 
     122           1 :     // Load language files for configured locale:
     123             :     // - First load the translator for the base language, without territory
     124             :     // - Then load the more specific locale translator
     125             : 
     126             :     // Load e.g. qt_de.qm
     127           0 :     if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
     128           0 :         QApplication::installTranslator(&qtTranslatorBase);
     129             : 
     130             :     // Load e.g. qt_de_DE.qm
     131           0 :     if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
     132           0 :         QApplication::installTranslator(&qtTranslator);
     133             : 
     134             :     // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
     135           0 :     if (translatorBase.load(lang, ":/translations/"))
     136           0 :         QApplication::installTranslator(&translatorBase);
     137             : 
     138             :     // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
     139           0 :     if (translator.load(lang_territory, ":/translations/"))
     140           0 :         QApplication::installTranslator(&translator);
     141           0 : }
     142             : 
     143             : /* qDebug() message handler --> debug.log */
     144           0 : void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
     145             : {
     146             :     Q_UNUSED(context);
     147           0 :     if (type == QtDebugMsg) {
     148           0 :         LogPrint(BCLog::QT, "GUI: %s\n", msg.toStdString());
     149             :     } else {
     150           0 :         LogPrintf("GUI: %s\n", msg.toStdString());
     151             :     }
     152           0 : }
     153             : 
     154           0 : BitcoinCore::BitcoinCore(interfaces::Node& node) :
     155           0 :     QObject(), m_node(node)
     156           0 : {
     157           0 : }
     158             : 
     159           0 : void BitcoinCore::handleRunawayException(const std::exception *e)
     160             : {
     161           0 :     PrintExceptionContinue(e, "Runaway exception");
     162           0 :     Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings().translated));
     163           0 : }
     164             : 
     165           0 : void BitcoinCore::initialize()
     166             : {
     167             :     try
     168             :     {
     169           0 :         qDebug() << __func__ << ": Running initialization in thread";
     170           0 :         util::ThreadRename("qt-init");
     171           0 :         interfaces::BlockAndHeaderTipInfo tip_info;
     172           0 :         bool rv = m_node.appInitMain(&tip_info);
     173           0 :         Q_EMIT initializeResult(rv, tip_info);
     174           0 :     } catch (const std::exception& e) {
     175           0 :         handleRunawayException(&e);
     176           0 :     } catch (...) {
     177           0 :         handleRunawayException(nullptr);
     178           0 :     }
     179           0 : }
     180             : 
     181           0 : void BitcoinCore::shutdown()
     182             : {
     183             :     try
     184             :     {
     185           0 :         qDebug() << __func__ << ": Running Shutdown in thread";
     186           0 :         m_node.appShutdown();
     187           0 :         qDebug() << __func__ << ": Shutdown finished";
     188           0 :         Q_EMIT shutdownResult();
     189           0 :     } catch (const std::exception& e) {
     190           0 :         handleRunawayException(&e);
     191           0 :     } catch (...) {
     192           0 :         handleRunawayException(nullptr);
     193           0 :     }
     194           0 : }
     195             : 
     196             : static int qt_argc = 1;
     197             : static const char* qt_argv = "bitcoin-qt";
     198             : 
     199           2 : BitcoinApplication::BitcoinApplication():
     200           1 :     QApplication(qt_argc, const_cast<char **>(&qt_argv)),
     201           1 :     coreThread(nullptr),
     202           1 :     optionsModel(nullptr),
     203           1 :     clientModel(nullptr),
     204           1 :     window(nullptr),
     205           1 :     pollShutdownTimer(nullptr),
     206           1 :     returnValue(0),
     207           1 :     platformStyle(nullptr)
     208           2 : {
     209             :     // Qt runs setlocale(LC_ALL, "") on initialization.
     210           1 :     RegisterMetaTypes();
     211           1 :     setQuitOnLastWindowClosed(false);
     212           2 : }
     213             : 
     214           0 : void BitcoinApplication::setupPlatformStyle()
     215             : {
     216             :     // UI per-platform customization
     217             :     // This must be done inside the BitcoinApplication constructor, or after it, because
     218             :     // PlatformStyle::instantiate requires a QApplication
     219           0 :     std::string platformName;
     220           0 :     platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
     221           0 :     platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
     222           0 :     if (!platformStyle) // Fall back to "other" if specified name not found
     223           0 :         platformStyle = PlatformStyle::instantiate("other");
     224           0 :     assert(platformStyle);
     225           0 : }
     226             : 
     227           2 : BitcoinApplication::~BitcoinApplication()
     228           2 : {
     229           1 :     if(coreThread)
     230             :     {
     231           0 :         qDebug() << __func__ << ": Stopping thread";
     232           0 :         coreThread->quit();
     233           0 :         coreThread->wait();
     234           0 :         qDebug() << __func__ << ": Stopped thread";
     235           0 :     }
     236             : 
     237           1 :     delete window;
     238           1 :     window = nullptr;
     239           1 :     delete platformStyle;
     240           1 :     platformStyle = nullptr;
     241           2 : }
     242             : 
     243             : #ifdef ENABLE_WALLET
     244           0 : void BitcoinApplication::createPaymentServer()
     245             : {
     246           0 :     paymentServer = new PaymentServer(this);
     247           0 : }
     248             : #endif
     249             : 
     250           0 : void BitcoinApplication::createOptionsModel(bool resetSettings)
     251             : {
     252           0 :     optionsModel = new OptionsModel(this, resetSettings);
     253           0 : }
     254             : 
     255           0 : void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
     256             : {
     257           0 :     window = new BitcoinGUI(node(), platformStyle, networkStyle, nullptr);
     258             : 
     259           0 :     pollShutdownTimer = new QTimer(window);
     260           0 :     connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown);
     261           0 : }
     262             : 
     263           0 : void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
     264             : {
     265           0 :     assert(!m_splash);
     266           0 :     m_splash = new SplashScreen(nullptr, networkStyle);
     267             :     // We don't hold a direct pointer to the splash screen after creation, but the splash
     268             :     // screen will take care of deleting itself when finish() happens.
     269           0 :     m_splash->show();
     270           0 :     connect(this, &BitcoinApplication::requestedInitialize, m_splash, &SplashScreen::handleLoadWallet);
     271           0 :     connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish);
     272           0 :     connect(this, &BitcoinApplication::requestedShutdown, m_splash, &QWidget::close);
     273           0 : }
     274             : 
     275           1 : void BitcoinApplication::setNode(interfaces::Node& node)
     276             : {
     277           1 :     assert(!m_node);
     278           1 :     m_node = &node;
     279           1 :     if (optionsModel) optionsModel->setNode(*m_node);
     280           1 :     if (m_splash) m_splash->setNode(*m_node);
     281           1 : }
     282             : 
     283           0 : bool BitcoinApplication::baseInitialize()
     284             : {
     285           0 :     return node().baseInitialize();
     286             : }
     287             : 
     288           0 : void BitcoinApplication::startThread()
     289             : {
     290           0 :     if(coreThread)
     291             :         return;
     292           0 :     coreThread = new QThread(this);
     293           0 :     BitcoinCore *executor = new BitcoinCore(node());
     294           0 :     executor->moveToThread(coreThread);
     295             : 
     296             :     /*  communication to and from thread */
     297           0 :     connect(executor, &BitcoinCore::initializeResult, this, &BitcoinApplication::initializeResult);
     298           0 :     connect(executor, &BitcoinCore::shutdownResult, this, &BitcoinApplication::shutdownResult);
     299           0 :     connect(executor, &BitcoinCore::runawayException, this, &BitcoinApplication::handleRunawayException);
     300           0 :     connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize);
     301           0 :     connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown);
     302             :     /*  make sure executor object is deleted in its own thread */
     303           0 :     connect(coreThread, &QThread::finished, executor, &QObject::deleteLater);
     304             : 
     305           0 :     coreThread->start();
     306           0 : }
     307             : 
     308           0 : void BitcoinApplication::parameterSetup()
     309             : {
     310             :     // Default printtoconsole to false for the GUI. GUI programs should not
     311             :     // print to the console unnecessarily.
     312           0 :     gArgs.SoftSetBoolArg("-printtoconsole", false);
     313             : 
     314           0 :     InitLogging(gArgs);
     315           0 :     InitParameterInteraction(gArgs);
     316           0 : }
     317             : 
     318           0 : void BitcoinApplication::InitializePruneSetting(bool prune)
     319             : {
     320             :     // If prune is set, intentionally override existing prune size with
     321             :     // the default size since this is called when choosing a new datadir.
     322           0 :     optionsModel->SetPruneTargetGB(prune ? DEFAULT_PRUNE_TARGET_GB : 0, true);
     323           0 : }
     324             : 
     325           0 : void BitcoinApplication::requestInitialize()
     326             : {
     327           0 :     qDebug() << __func__ << ": Requesting initialize";
     328           0 :     startThread();
     329           0 :     Q_EMIT requestedInitialize();
     330           0 : }
     331             : 
     332           0 : void BitcoinApplication::requestShutdown()
     333             : {
     334             :     // Show a simple window indicating shutdown status
     335             :     // Do this first as some of the steps may take some time below,
     336             :     // for example the RPC console may still be executing a command.
     337           0 :     shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));
     338             : 
     339           0 :     qDebug() << __func__ << ": Requesting shutdown";
     340           0 :     startThread();
     341           0 :     window->hide();
     342             :     // Must disconnect node signals otherwise current thread can deadlock since
     343             :     // no event loop is running.
     344           0 :     window->unsubscribeFromCoreSignals();
     345             :     // Request node shutdown, which can interrupt long operations, like
     346             :     // rescanning a wallet.
     347           0 :     node().startShutdown();
     348             :     // Unsetting the client model can cause the current thread to wait for node
     349             :     // to complete an operation, like wait for a RPC execution to complete.
     350           0 :     window->setClientModel(nullptr);
     351           0 :     pollShutdownTimer->stop();
     352             : 
     353           0 :     delete clientModel;
     354           0 :     clientModel = nullptr;
     355             : 
     356             :     // Request shutdown from core thread
     357           0 :     Q_EMIT requestedShutdown();
     358           0 : }
     359             : 
     360           0 : void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
     361             : {
     362           0 :     qDebug() << __func__ << ": Initialization result: " << success;
     363             :     // Set exit result.
     364           0 :     returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE;
     365           0 :     if(success)
     366             :     {
     367             :         // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
     368           0 :         qInfo() << "Platform customization:" << platformStyle->getName();
     369           0 :         clientModel = new ClientModel(node(), optionsModel);
     370           0 :         window->setClientModel(clientModel, &tip_info);
     371             : #ifdef ENABLE_WALLET
     372           0 :         if (WalletModel::isWalletEnabled()) {
     373           0 :             m_wallet_controller = new WalletController(*clientModel, platformStyle, this);
     374           0 :             window->setWalletController(m_wallet_controller);
     375           0 :             if (paymentServer) {
     376           0 :                 paymentServer->setOptionsModel(optionsModel);
     377           0 :             }
     378             :         }
     379             : #endif // ENABLE_WALLET
     380             : 
     381             :         // If -min option passed, start window minimized (iconified) or minimized to tray
     382           0 :         if (!gArgs.GetBoolArg("-min", false)) {
     383           0 :             window->show();
     384           0 :         } else if (clientModel->getOptionsModel()->getMinimizeToTray() && window->hasTrayIcon()) {
     385             :             // do nothing as the window is managed by the tray icon
     386             :         } else {
     387           0 :             window->showMinimized();
     388             :         }
     389           0 :         Q_EMIT splashFinished();
     390           0 :         Q_EMIT windowShown(window);
     391             : 
     392             : #ifdef ENABLE_WALLET
     393             :         // Now that initialization/startup is done, process any command-line
     394             :         // bitcoin: URIs or payment requests:
     395           0 :         if (paymentServer) {
     396           0 :             connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
     397           0 :             connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
     398           0 :             connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
     399           0 :                 window->message(title, message, style);
     400           0 :             });
     401           0 :             QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
     402           0 :         }
     403             : #endif
     404           0 :         pollShutdownTimer->start(200);
     405           0 :     } else {
     406           0 :         Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown
     407           0 :         quit(); // Exit first main loop invocation
     408             :     }
     409           0 : }
     410             : 
     411           0 : void BitcoinApplication::shutdownResult()
     412             : {
     413           0 :     quit(); // Exit second main loop invocation after shutdown finished
     414           0 : }
     415             : 
     416           0 : void BitcoinApplication::handleRunawayException(const QString &message)
     417             : {
     418           0 :     QMessageBox::critical(nullptr, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) + QString("<br><br>") + message);
     419           0 :     ::exit(EXIT_FAILURE);
     420           0 : }
     421             : 
     422           0 : WId BitcoinApplication::getMainWinId() const
     423             : {
     424           0 :     if (!window)
     425           0 :         return 0;
     426             : 
     427           0 :     return window->winId();
     428           0 : }
     429             : 
     430           0 : static void SetupUIArgs(ArgsManager& argsman)
     431             : {
     432           0 :     argsman.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     433           0 :     argsman.AddArg("-lang=<lang>", "Set language, for example \"de_DE\" (default: system locale)", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     434           0 :     argsman.AddArg("-min", "Start minimized", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     435           0 :     argsman.AddArg("-resetguisettings", "Reset all settings changed in the GUI", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     436           0 :     argsman.AddArg("-splash", strprintf("Show splash screen on startup (default: %u)", DEFAULT_SPLASHSCREEN), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
     437           0 :     argsman.AddArg("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::GUI);
     438           0 : }
     439             : 
     440           0 : int GuiMain(int argc, char* argv[])
     441             : {
     442             : #ifdef WIN32
     443             :     util::WinCmdLineArgs winArgs;
     444             :     std::tie(argc, argv) = winArgs.get();
     445             : #endif
     446           0 :     SetupEnvironment();
     447           0 :     util::ThreadSetInternalName("main");
     448             : 
     449           0 :     NodeContext node_context;
     450           0 :     std::unique_ptr<interfaces::Node> node = interfaces::MakeNode(&node_context);
     451             : 
     452             :     // Subscribe to global signals from core
     453           0 :     boost::signals2::scoped_connection handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox);
     454           0 :     boost::signals2::scoped_connection handler_question = ::uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion);
     455           0 :     boost::signals2::scoped_connection handler_init_message = ::uiInterface.InitMessage_connect(noui_InitMessage);
     456             : 
     457             :     // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
     458             : 
     459             :     /// 1. Basic Qt initialization (not dependent on parameters or configuration)
     460           0 :     Q_INIT_RESOURCE(bitcoin);
     461           0 :     Q_INIT_RESOURCE(bitcoin_locale);
     462             : 
     463             :     // Generate high-dpi pixmaps
     464           0 :     QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
     465             : #if QT_VERSION >= 0x050600
     466           0 :     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
     467             : #endif
     468             : 
     469           0 :     BitcoinApplication app;
     470             : 
     471             :     /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
     472             :     // Command-line options take precedence:
     473           0 :     SetupServerArgs(node_context);
     474           0 :     SetupUIArgs(gArgs);
     475           0 :     std::string error;
     476           0 :     if (!gArgs.ParseParameters(argc, argv, error)) {
     477           0 :         InitError(strprintf(Untranslated("Error parsing command line arguments: %s\n"), error));
     478             :         // Create a message box, because the gui has neither been created nor has subscribed to core signals
     479           0 :         QMessageBox::critical(nullptr, PACKAGE_NAME,
     480             :             // message can not be translated because translations have not been initialized
     481           0 :             QString::fromStdString("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
     482           0 :         return EXIT_FAILURE;
     483             :     }
     484             : 
     485             :     // Now that the QApplication is setup and we have parsed our parameters, we can set the platform style
     486           0 :     app.setupPlatformStyle();
     487             : 
     488             :     /// 3. Application identification
     489             :     // must be set before OptionsModel is initialized or translations are loaded,
     490             :     // as it is used to locate QSettings
     491           0 :     QApplication::setOrganizationName(QAPP_ORG_NAME);
     492           0 :     QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
     493           0 :     QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
     494             : 
     495             :     /// 4. Initialization of translations, so that intro dialog is in user's language
     496             :     // Now that QSettings are accessible, initialize translations
     497           0 :     QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
     498           0 :     initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
     499             : 
     500             :     // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
     501             :     // but before showing splash screen.
     502           0 :     if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
     503           0 :         HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version"));
     504           0 :         help.showOrPrint();
     505             :         return EXIT_SUCCESS;
     506           0 :     }
     507             : 
     508             :     /// 5. Now that settings and translations are available, ask user for data directory
     509             :     // User language is set up: pick a data directory
     510           0 :     bool did_show_intro = false;
     511           0 :     bool prune = false; // Intro dialog prune check box
     512             :     // Gracefully exit if the user cancels
     513           0 :     if (!Intro::showIfNeeded(did_show_intro, prune)) return EXIT_SUCCESS;
     514             : 
     515             :     /// 6. Determine availability of data directory and parse bitcoin.conf
     516             :     /// - Do not call GetDataDir(true) before this step finishes
     517           0 :     if (!CheckDataDirOption()) {
     518           0 :         InitError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", "")));
     519           0 :         QMessageBox::critical(nullptr, PACKAGE_NAME,
     520           0 :             QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
     521           0 :         return EXIT_FAILURE;
     522             :     }
     523           0 :     if (!gArgs.ReadConfigFiles(error, true)) {
     524           0 :         InitError(strprintf(Untranslated("Error reading configuration file: %s\n"), error));
     525           0 :         QMessageBox::critical(nullptr, PACKAGE_NAME,
     526           0 :             QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
     527           0 :         return EXIT_FAILURE;
     528             :     }
     529             : 
     530             :     /// 7. Determine network (and switch to network specific options)
     531             :     // - Do not call Params() before this step
     532             :     // - Do this after parsing the configuration file, as the network can be switched there
     533             :     // - QSettings() will use the new application name after this, resulting in network-specific settings
     534             :     // - Needs to be done before createOptionsModel
     535             : 
     536             :     // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause)
     537             :     try {
     538           0 :         SelectParams(gArgs.GetChainName());
     539           0 :     } catch(std::exception &e) {
     540           0 :         InitError(Untranslated(strprintf("%s\n", e.what())));
     541           0 :         QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
     542             :         return EXIT_FAILURE;
     543           0 :     }
     544             : #ifdef ENABLE_WALLET
     545             :     // Parse URIs on command line -- this can affect Params()
     546           0 :     PaymentServer::ipcParseCommandLine(argc, argv);
     547             : #endif
     548           0 :     if (!gArgs.InitSettings(error)) {
     549           0 :         InitError(Untranslated(error));
     550           0 :         QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error initializing settings: %1").arg(QString::fromStdString(error)));
     551           0 :         return EXIT_FAILURE;
     552             :     }
     553             : 
     554           0 :     QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().NetworkIDString()));
     555           0 :     assert(!networkStyle.isNull());
     556             :     // Allow for separate UI settings for testnets
     557           0 :     QApplication::setApplicationName(networkStyle->getAppName());
     558             :     // Re-initialize translations after changing application name (language in network-specific settings can be different)
     559           0 :     initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
     560             : 
     561             : #ifdef ENABLE_WALLET
     562             :     /// 8. URI IPC sending
     563             :     // - Do this early as we don't want to bother initializing if we are just calling IPC
     564             :     // - Do this *after* setting up the data directory, as the data directory hash is used in the name
     565             :     // of the server.
     566             :     // - Do this after creating app and setting up translations, so errors are
     567             :     // translated properly.
     568           0 :     if (PaymentServer::ipcSendCommandLine())
     569           0 :         exit(EXIT_SUCCESS);
     570             : 
     571             :     // Start up the payment server early, too, so impatient users that click on
     572             :     // bitcoin: links repeatedly have their payment requests routed to this process:
     573           0 :     if (WalletModel::isWalletEnabled()) {
     574           0 :         app.createPaymentServer();
     575             :     }
     576             : #endif // ENABLE_WALLET
     577             : 
     578             :     /// 9. Main GUI initialization
     579             :     // Install global event filter that makes sure that long tooltips can be word-wrapped
     580           0 :     app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
     581             :     // Install global event filter that makes sure that out-of-focus labels do not contain text cursor.
     582           0 :     app.installEventFilter(new GUIUtil::LabelOutOfFocusEventFilter(&app));
     583             : #if defined(Q_OS_WIN)
     584             :     // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
     585             :     qApp->installNativeEventFilter(new WinShutdownMonitor());
     586             : #endif
     587             :     // Install qDebug() message handler to route to debug.log
     588           0 :     qInstallMessageHandler(DebugMessageHandler);
     589             :     // Allow parameter interaction before we create the options model
     590           0 :     app.parameterSetup();
     591           0 :     GUIUtil::LogQtInfo();
     592             :     // Load GUI settings from QSettings
     593           0 :     app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
     594             : 
     595           0 :     if (did_show_intro) {
     596             :         // Store intro dialog settings other than datadir (network specific)
     597           0 :         app.InitializePruneSetting(prune);
     598             :     }
     599             : 
     600           0 :     if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
     601           0 :         app.createSplashScreen(networkStyle.data());
     602             : 
     603           0 :     app.setNode(*node);
     604             : 
     605             :     int rv = EXIT_SUCCESS;
     606             :     try
     607             :     {
     608           0 :         app.createWindow(networkStyle.data());
     609             :         // Perform base initialization before spinning up initialization/shutdown thread
     610             :         // This is acceptable because this function only contains steps that are quick to execute,
     611             :         // so the GUI thread won't be held up.
     612           0 :         if (app.baseInitialize()) {
     613           0 :             app.requestInitialize();
     614             : #if defined(Q_OS_WIN)
     615             :             WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
     616             : #endif
     617           0 :             app.exec();
     618           0 :             app.requestShutdown();
     619           0 :             app.exec();
     620           0 :             rv = app.getReturnValue();
     621           0 :         } else {
     622             :             // A dialog with detailed error will have been shown by InitError()
     623             :             rv = EXIT_FAILURE;
     624             :         }
     625           0 :     } catch (const std::exception& e) {
     626           0 :         PrintExceptionContinue(&e, "Runaway exception");
     627           0 :         app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
     628           0 :     } catch (...) {
     629           0 :         PrintExceptionContinue(nullptr, "Runaway exception");
     630           0 :         app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
     631           0 :     }
     632             :     return rv;
     633           0 : }

Generated by: LCOV version 1.15