diff --git a/src/qml/bitcoin.cpp b/src/qml/bitcoin.cpp index bb3a368e47..25b700fef4 100644 --- a/src/qml/bitcoin.cpp +++ b/src/qml/bitcoin.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,7 @@ void SetupUIArgs(ArgsManager& argsman) argsman.AddArg("-resetguisettings", "Reset all settings changed in the GUI", ArgsManager::ALLOW_ANY, OptionsCategory::GUI); } -AppMode SetupAppMode() +AppMode* SetupAppMode() { bool wallet_enabled; AppMode::Mode mode; @@ -93,7 +94,7 @@ AppMode SetupAppMode() wallet_enabled = false; #endif // ENABLE_WALLET - return AppMode(mode, wallet_enabled); + return new AppMode(mode, wallet_enabled); } bool InitErrorMessageBox( @@ -103,9 +104,9 @@ bool InitErrorMessageBox( { QQmlApplicationEngine engine; - AppMode app_mode = SetupAppMode(); + AppMode* app_mode = SetupAppMode(); - qmlRegisterSingletonInstance("org.bitcoincore.qt", 1, 0, "AppMode", &app_mode); + qmlRegisterSingletonInstance("org.bitcoincore.qt", 1, 0, "AppMode", app_mode); engine.rootContext()->setContextProperty("message", QString::fromStdString(message.translated)); engine.load(QUrl(QStringLiteral("qrc:///qml/pages/initerrormessage.qml"))); if (engine.rootObjects().isEmpty()) { @@ -158,6 +159,188 @@ void setupChainQSettings(QGuiApplication* app, QString chain) app->setApplicationName(QAPP_APP_NAME_REGTEST); } } + +// added this function to set custom data directory when starting node +bool setCustomDataDir(QString strDataDir) +{ + if(fs::exists(GUIUtil::QStringToPath(strDataDir))){ + gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::QStringToPath(strDataDir))); + gArgs.ClearPathCache(); + return true; + } else { + return false; + } +} + +QGuiApplication* m_app; +QQmlApplicationEngine* m_engine; +// ArgsManager* m_gArgs; +QQuickWindow* m_window; +boost::signals2::connection m_handler_message_box; +std::unique_ptr m_init; +std::unique_ptr m_node; +std::unique_ptr m_chain; +NodeModel* m_node_model{nullptr}; +InitExecutor* m_executor{nullptr}; +ChainModel* m_chain_model{nullptr}; +OptionsQmlModel* m_options_model{nullptr}; +// OnboardingModel* m_onboarding_model{nullptr}; +int m_argc; +char** m_argv; +bool m_prune; +int m_prune_size_gb; +NetworkTrafficTower* m_network_traffic_tower; +PeerTableModel* m_peer_model; +PeerListSortProxy* m_peer_model_sort_proxy; +QThread* m_introThread; +bool m_isOnboarded; + +bool createNode(QGuiApplication& app, QQmlApplicationEngine& engine, int& argc, char* argv[], ArgsManager& gArgs) +{ + m_engine = &engine; + + InitLogging(gArgs); + InitParameterInteraction(gArgs); + + m_init = interfaces::MakeGuiInit(argc, argv); + + m_node = m_init->makeNode(); + m_chain = m_init->makeChain(); + + if (!m_node->baseInitialize()) { + // A dialog with detailed error will have been shown by InitError(). + return EXIT_FAILURE; + } + + m_handler_message_box.disconnect(); + + m_node_model = new NodeModel{*m_node}; + m_executor = new InitExecutor{*m_node}; + QObject::connect(m_node_model, &NodeModel::requestedInitialize, m_executor, &InitExecutor::initialize); + QObject::connect(m_node_model, &NodeModel::requestedShutdown, m_executor, &InitExecutor::shutdown); + QObject::connect(m_executor, &InitExecutor::initializeResult, m_node_model, &NodeModel::initializeResult); + QObject::connect(m_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection); + + m_network_traffic_tower = new NetworkTrafficTower{*m_node_model}; +#ifdef __ANDROID__ + AndroidNotifier android_notifier{*m_node_model}; +#endif + + m_chain_model = new ChainModel{*m_chain}; + m_chain_model->setCurrentNetworkName(QString::fromStdString(ChainTypeToString(gArgs.GetChainType()))); + setupChainQSettings(m_app, m_chain_model->currentNetworkName()); + + QObject::connect(m_node_model, &NodeModel::setTimeRatioList, m_chain_model, &ChainModel::setTimeRatioList); + QObject::connect(m_node_model, &NodeModel::setTimeRatioListInitial, m_chain_model, &ChainModel::setTimeRatioListInitial); + + qGuiApp->setQuitOnLastWindowClosed(false); + QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, [&] { + m_node->startShutdown(); + }); + + m_peer_model = new PeerTableModel{*m_node, nullptr}; + m_peer_model_sort_proxy = new PeerListSortProxy{nullptr}; + m_peer_model_sort_proxy->setSourceModel(m_peer_model); + + m_engine->rootContext()->setContextProperty("networkTrafficTower", m_network_traffic_tower); + m_engine->rootContext()->setContextProperty("nodeModel", m_node_model); + m_engine->rootContext()->setContextProperty("chainModel", m_chain_model); + m_engine->rootContext()->setContextProperty("peerTableModel", m_peer_model); + m_engine->rootContext()->setContextProperty("peerListModelProxy", m_peer_model_sort_proxy); + + m_options_model->setNode(&(*m_node), m_isOnboarded); + + QObject::connect(m_options_model, &OptionsQmlModel::requestedShutdown, m_executor, &InitExecutor::shutdown); + + m_engine->rootContext()->setContextProperty("optionsModel", m_options_model); + + m_node_model->startShutdownPolling(); + + return true; +} + +void startNodeAndTransitionSlot() { createNode(*m_app, *m_engine, m_argc, m_argv, gArgs); } + +bool startNode(QGuiApplication& app, QQmlApplicationEngine& engine, int& argc, char* argv[]) +{ + m_engine = &engine; + QScopedPointer network_style{NetworkStyle::instantiate(Params().GetChainType())}; + assert(!network_style.isNull()); + m_engine->addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()}); + + m_isOnboarded = true; + + m_options_model = new OptionsQmlModel{nullptr, m_isOnboarded}; + m_engine->rootContext()->setContextProperty("optionsModel", m_options_model); + + // moved this so that the settings.json file is read and parsed before creating the node + std::string error; + /// Read and parse settings.json file. + std::vector errors; + if (!gArgs.ReadSettingsFile(&errors)) { + error = strprintf("Failed loading settings file:\n%s\n", MakeUnorderedList(errors)); + InitError(Untranslated(error)); + return EXIT_FAILURE; + } + + createNode(*m_app, *m_engine, argc, argv, gArgs); + + AppMode* app_mode = SetupAppMode(); + + qmlRegisterSingletonInstance("org.bitcoincore.qt", 1, 0, "AppMode", app_mode); + qmlRegisterType("org.bitcoincore.qt", 1, 0, "BlockClockDial"); + qmlRegisterType("org.bitcoincore.qt", 1, 0, "LineGraph"); + + m_engine->load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml"))); + if (m_engine->rootObjects().isEmpty()) { + return EXIT_FAILURE; + } + + auto window = qobject_cast(engine.rootObjects().first()); + if (!window) { + return EXIT_FAILURE; + } + + // Install qDebug() message handler to route to debug.log + qInstallMessageHandler(DebugMessageHandler); + + qInfo() << "Graphics API in use:" << QmlUtil::GraphicsApi(window); + + return qGuiApp->exec(); +} + +bool startOnboarding(QGuiApplication& app, QQmlApplicationEngine& engine, ArgsManager& gArgs) +{ + m_engine = &engine; + QScopedPointer network_style{NetworkStyle::instantiate(Params().GetChainType())}; + assert(!network_style.isNull()); + m_engine->addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()}); + + m_isOnboarded = false; + + m_options_model = new OptionsQmlModel{nullptr, m_isOnboarded}; + m_engine->rootContext()->setContextProperty("optionsModel", m_options_model); + + QObject::connect(m_options_model, &OptionsQmlModel::onboardingFinished, startNodeAndTransitionSlot); + + AppMode* app_mode = SetupAppMode(); + + qmlRegisterSingletonInstance("org.bitcoincore.qt", 1, 0, "AppMode", app_mode); + qmlRegisterType("org.bitcoincore.qt", 1, 0, "BlockClockDial"); + qmlRegisterType("org.bitcoincore.qt", 1, 0, "LineGraph"); + + m_engine->load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml"))); + if (m_engine->rootObjects().isEmpty()) { + return EXIT_FAILURE; + } + + auto window = qobject_cast(m_engine->rootObjects().first()); + if (!window) { + return EXIT_FAILURE; + } + + return qGuiApp->exec(); +} } // namespace @@ -175,9 +358,7 @@ int QmlGuiMain(int argc, char* argv[]) QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls); QGuiApplication app(argc, argv); - auto handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(InitErrorMessageBox); - - std::unique_ptr init = interfaces::MakeGuiInit(argc, argv); + auto m_handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(InitErrorMessageBox); SetupEnvironment(); util::ThreadSetInternalName("main"); @@ -189,6 +370,10 @@ int QmlGuiMain(int argc, char* argv[]) app.setOrganizationDomain(QAPP_ORG_DOMAIN); app.setApplicationName(QAPP_APP_NAME_DEFAULT); + QSettings settings; + QString dataDir; + dataDir = settings.value("strDataDir", dataDir).toString(); + /// Parse command-line options. We do this after qt in order to show an error if there are problems parsing these. SetupServerArgs(gArgs); SetupUIArgs(gArgs); @@ -218,16 +403,9 @@ int QmlGuiMain(int argc, char* argv[]) return EXIT_FAILURE; } - /// Read and parse settings.json file. - std::vector errors; - if (!gArgs.ReadSettingsFile(&errors)) { - error = strprintf("Failed loading settings file:\n%s\n", MakeUnorderedList(errors)); - InitError(Untranslated(error)); - return EXIT_FAILURE; - } - QVariant need_onboarding(true); - if (gArgs.IsArgSet("-datadir") && !gArgs.GetPathArg("-datadir").empty()) { + if ((gArgs.IsArgSet("-datadir") && !gArgs.GetPathArg("-datadir").empty()) || fs::exists(GUIUtil::QStringToPath(dataDir)) ) { + setCustomDataDir(dataDir); need_onboarding.setValue(false); } else if (ConfigurationFileExists(gArgs)) { need_onboarding.setValue(false); @@ -240,89 +418,22 @@ int QmlGuiMain(int argc, char* argv[]) // Default printtoconsole to false for the GUI. GUI programs should not // print to the console unnecessarily. gArgs.SoftSetBoolArg("-printtoconsole", false); - InitLogging(gArgs); - InitParameterInteraction(gArgs); GUIUtil::LogQtInfo(); - - std::unique_ptr node = init->makeNode(); - std::unique_ptr chain = init->makeChain(); - if (!node->baseInitialize()) { - // A dialog with detailed error will have been shown by InitError(). - return EXIT_FAILURE; - } - - handler_message_box.disconnect(); - - NodeModel node_model{*node}; - InitExecutor init_executor{*node}; - QObject::connect(&node_model, &NodeModel::requestedInitialize, &init_executor, &InitExecutor::initialize); - QObject::connect(&node_model, &NodeModel::requestedShutdown, &init_executor, &InitExecutor::shutdown); - QObject::connect(&init_executor, &InitExecutor::initializeResult, &node_model, &NodeModel::initializeResult); - QObject::connect(&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection); - // QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException); - - NetworkTrafficTower network_traffic_tower{node_model}; -#ifdef __ANDROID__ - AndroidNotifier android_notifier{node_model}; -#endif - - ChainModel chain_model{*chain}; - chain_model.setCurrentNetworkName(QString::fromStdString(ChainTypeToString(gArgs.GetChainType()))); - setupChainQSettings(&app, chain_model.currentNetworkName()); - - QObject::connect(&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList); - QObject::connect(&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial); - - qGuiApp->setQuitOnLastWindowClosed(false); - QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, [&] { - node->startShutdown(); - }); - - PeerTableModel peer_model{*node, nullptr}; - PeerListSortProxy peer_model_sort_proxy{nullptr}; - peer_model_sort_proxy.setSourceModel(&peer_model); - GUIUtil::LoadFont(":/fonts/inter/regular"); GUIUtil::LoadFont(":/fonts/inter/semibold"); - QQmlApplicationEngine engine; + m_app = &app; - QScopedPointer network_style{NetworkStyle::instantiate(Params().GetChainType())}; - assert(!network_style.isNull()); - engine.addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()}); - - engine.rootContext()->setContextProperty("networkTrafficTower", &network_traffic_tower); - engine.rootContext()->setContextProperty("nodeModel", &node_model); - engine.rootContext()->setContextProperty("chainModel", &chain_model); - engine.rootContext()->setContextProperty("peerTableModel", &peer_model); - engine.rootContext()->setContextProperty("peerListModelProxy", &peer_model_sort_proxy); + QQmlApplicationEngine engine; - OptionsQmlModel options_model(*node, !need_onboarding.toBool()); - engine.rootContext()->setContextProperty("optionsModel", &options_model); engine.rootContext()->setContextProperty("needOnboarding", need_onboarding); - AppMode app_mode = SetupAppMode(); - - qmlRegisterSingletonInstance("org.bitcoincore.qt", 1, 0, "AppMode", &app_mode); - qmlRegisterType("org.bitcoincore.qt", 1, 0, "BlockClockDial"); - qmlRegisterType("org.bitcoincore.qt", 1, 0, "LineGraph"); - - engine.load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml"))); - if (engine.rootObjects().isEmpty()) { - return EXIT_FAILURE; - } - - auto window = qobject_cast(engine.rootObjects().first()); - if (!window) { - return EXIT_FAILURE; + if(need_onboarding.toBool()) { + startOnboarding(*m_app, engine, gArgs); + } else { + startNode(*m_app, engine, argc, argv); } - // Install qDebug() message handler to route to debug.log - qInstallMessageHandler(DebugMessageHandler); - - qInfo() << "Graphics API in use:" << QmlUtil::GraphicsApi(window); - - node_model.startShutdownPolling(); - return qGuiApp->exec(); + return 0; }