17
17
#include < qml/appmode.h>
18
18
#ifdef __ANDROID__
19
19
#include < qml/androidnotifier.h>
20
+ #include < qml/androidcustomdatadir.h>
20
21
#endif
21
22
#include < qml/components/blockclockdial.h>
22
23
#include < qml/controls/linegraph.h>
45
46
#include < QQmlApplicationEngine>
46
47
#include < QQmlContext>
47
48
#include < QQuickWindow>
49
+ #include < QSettings>
48
50
#include < QString>
49
51
#include < QStyleHints>
50
52
#include < QUrl>
@@ -158,6 +160,186 @@ void setupChainQSettings(QGuiApplication* app, QString chain)
158
160
app->setApplicationName (QAPP_APP_NAME_REGTEST);
159
161
}
160
162
}
163
+
164
+ bool setCustomDataDir (QString strDataDir)
165
+ {
166
+ if (fs::exists (GUIUtil::QStringToPath (strDataDir))){
167
+ gArgs .SoftSetArg (" -datadir" , fs::PathToString (GUIUtil::QStringToPath (strDataDir)));
168
+ gArgs .ClearPathCache ();
169
+ return true ;
170
+ } else {
171
+ return false ;
172
+ }
173
+ }
174
+
175
+ QGuiApplication* m_app;
176
+ QQmlApplicationEngine* m_engine;
177
+ boost::signals2::connection m_handler_message_box;
178
+ std::unique_ptr<interfaces::Init> m_init;
179
+ std::unique_ptr<interfaces::Node> m_node;
180
+ std::unique_ptr<interfaces::Chain> m_chain;
181
+ NodeModel* m_node_model{nullptr };
182
+ InitExecutor* m_executor{nullptr };
183
+ ChainModel* m_chain_model{nullptr };
184
+ OptionsQmlModel* m_options_model{nullptr };
185
+ int m_argc;
186
+ char ** m_argv;
187
+ NetworkTrafficTower* m_network_traffic_tower;
188
+ PeerTableModel* m_peer_model;
189
+ PeerListSortProxy* m_peer_model_sort_proxy;
190
+ bool m_isOnboarded;
191
+
192
+ bool createNode (QGuiApplication& app, QQmlApplicationEngine& engine, int & argc, char * argv[], ArgsManager& gArgs )
193
+ {
194
+ m_engine = &engine;
195
+
196
+ InitLogging (gArgs );
197
+ InitParameterInteraction (gArgs );
198
+
199
+ m_init = interfaces::MakeGuiInit (argc, argv);
200
+
201
+ m_node = m_init->makeNode ();
202
+ m_chain = m_init->makeChain ();
203
+
204
+ if (!m_node->baseInitialize ()) {
205
+ // A dialog with detailed error will have been shown by InitError().
206
+ return EXIT_FAILURE;
207
+ }
208
+
209
+ m_handler_message_box.disconnect ();
210
+
211
+ m_node_model = new NodeModel{*m_node};
212
+ m_executor = new InitExecutor{*m_node};
213
+ QObject::connect (m_node_model, &NodeModel::requestedInitialize, m_executor, &InitExecutor::initialize);
214
+ QObject::connect (m_node_model, &NodeModel::requestedShutdown, m_executor, &InitExecutor::shutdown);
215
+ QObject::connect (m_executor, &InitExecutor::initializeResult, m_node_model, &NodeModel::initializeResult);
216
+ QObject::connect (m_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
217
+
218
+ m_network_traffic_tower = new NetworkTrafficTower{*m_node_model};
219
+ #ifdef __ANDROID__
220
+ AndroidNotifier android_notifier{*m_node_model};
221
+ #endif
222
+
223
+ m_chain_model = new ChainModel{*m_chain};
224
+ m_chain_model->setCurrentNetworkName (QString::fromStdString (ChainTypeToString (gArgs .GetChainType ())));
225
+ setupChainQSettings (m_app, m_chain_model->currentNetworkName ());
226
+
227
+ QObject::connect (m_node_model, &NodeModel::setTimeRatioList, m_chain_model, &ChainModel::setTimeRatioList);
228
+ QObject::connect (m_node_model, &NodeModel::setTimeRatioListInitial, m_chain_model, &ChainModel::setTimeRatioListInitial);
229
+
230
+ qGuiApp->setQuitOnLastWindowClosed (false );
231
+ QObject::connect (qGuiApp, &QGuiApplication::lastWindowClosed, [&] {
232
+ m_node->startShutdown ();
233
+ });
234
+
235
+ m_peer_model = new PeerTableModel{*m_node, nullptr };
236
+ m_peer_model_sort_proxy = new PeerListSortProxy{nullptr };
237
+ m_peer_model_sort_proxy->setSourceModel (m_peer_model);
238
+
239
+ m_engine->rootContext ()->setContextProperty (" networkTrafficTower" , m_network_traffic_tower);
240
+ m_engine->rootContext ()->setContextProperty (" nodeModel" , m_node_model);
241
+ m_engine->rootContext ()->setContextProperty (" chainModel" , m_chain_model);
242
+ m_engine->rootContext ()->setContextProperty (" peerTableModel" , m_peer_model);
243
+ m_engine->rootContext ()->setContextProperty (" peerListModelProxy" , m_peer_model_sort_proxy);
244
+
245
+ m_options_model->setNode (&(*m_node), m_isOnboarded);
246
+
247
+ QObject::connect (m_options_model, &OptionsQmlModel::requestedShutdown, m_executor, &InitExecutor::shutdown);
248
+
249
+ m_engine->rootContext ()->setContextProperty (" optionsModel" , m_options_model);
250
+
251
+ m_node_model->startShutdownPolling ();
252
+
253
+ return true ;
254
+ }
255
+
256
+ void startNodeAndTransitionSlot () { createNode (*m_app, *m_engine, m_argc, m_argv, gArgs ); }
257
+
258
+ int initializeAndRunApplication (QGuiApplication* app, QQmlApplicationEngine* m_engine) {
259
+ AppMode app_mode = SetupAppMode ();
260
+
261
+ // Register the singleton instance for AppMode with the QML engine
262
+ qmlRegisterSingletonInstance<AppMode>(" org.bitcoincore.qt" , 1 , 0 , " AppMode" , &app_mode);
263
+
264
+ // Register custom QML types
265
+ qmlRegisterType<BlockClockDial>(" org.bitcoincore.qt" , 1 , 0 , " BlockClockDial" );
266
+ qmlRegisterType<LineGraph>(" org.bitcoincore.qt" , 1 , 0 , " LineGraph" );
267
+
268
+ // Load the main QML file
269
+ m_engine->load (QUrl (QStringLiteral (" qrc:///qml/pages/main.qml" )));
270
+
271
+ // Check if the QML engine failed to load the main QML file
272
+ if (m_engine->rootObjects ().isEmpty ()) {
273
+ return EXIT_FAILURE;
274
+ }
275
+
276
+ // Get the first root object as a QQuickWindow
277
+ auto window = qobject_cast<QQuickWindow*>(m_engine->rootObjects ().first ());
278
+ if (!window) {
279
+ return EXIT_FAILURE;
280
+ }
281
+
282
+ // Install the custom message handler for qDebug()
283
+ qInstallMessageHandler (DebugMessageHandler);
284
+
285
+ // Log the graphics API in use
286
+ qInfo () << " Graphics API in use:" << QmlUtil::GraphicsApi (window);
287
+
288
+ // Execute the application
289
+ return qGuiApp->exec ();
290
+ }
291
+
292
+ bool startNode (QGuiApplication& app, QQmlApplicationEngine& engine, int & argc, char * argv[])
293
+ {
294
+ m_engine = &engine;
295
+ QScopedPointer<const NetworkStyle> network_style{NetworkStyle::instantiate (Params ().GetChainType ())};
296
+ assert (!network_style.isNull ());
297
+ m_engine->addImageProvider (QStringLiteral (" images" ), new ImageProvider{network_style.data ()});
298
+
299
+ m_isOnboarded = true ;
300
+
301
+ m_options_model = new OptionsQmlModel{nullptr , m_isOnboarded};
302
+ m_engine->rootContext ()->setContextProperty (" optionsModel" , m_options_model);
303
+
304
+ // moved this so that the settings.json file is read and parsed before creating the node
305
+ std::string error;
306
+ // / Read and parse settings.json file.
307
+ std::vector<std::string> errors;
308
+ if (!gArgs .ReadSettingsFile (&errors)) {
309
+ error = strprintf (" Failed loading settings file:\n %s\n " , MakeUnorderedList (errors));
310
+ InitError (Untranslated (error));
311
+ return EXIT_FAILURE;
312
+ }
313
+
314
+ createNode (*m_app, *m_engine, argc, argv, gArgs );
315
+
316
+ initializeAndRunApplication (&app, m_engine);
317
+ return true ;
318
+ }
319
+
320
+ bool startOnboarding (QGuiApplication& app, QQmlApplicationEngine& engine, ArgsManager& gArgs )
321
+ {
322
+ m_engine = &engine;
323
+ QScopedPointer<const NetworkStyle> network_style{NetworkStyle::instantiate (Params ().GetChainType ())};
324
+ assert (!network_style.isNull ());
325
+ m_engine->addImageProvider (QStringLiteral (" images" ), new ImageProvider{network_style.data ()});
326
+
327
+ m_isOnboarded = false ;
328
+
329
+ m_options_model = new OptionsQmlModel{nullptr , m_isOnboarded};
330
+
331
+ if (gArgs .IsArgSet (" -resetguisettings" )) {
332
+ m_options_model->defaultReset ();
333
+ }
334
+
335
+ m_engine->rootContext ()->setContextProperty (" optionsModel" , m_options_model);
336
+
337
+ QObject::connect (m_options_model, &OptionsQmlModel::onboardingFinished, startNodeAndTransitionSlot);
338
+
339
+ initializeAndRunApplication (&app, m_engine);
340
+
341
+ return true ;
342
+ }
161
343
} // namespace
162
344
163
345
@@ -175,9 +357,7 @@ int QmlGuiMain(int argc, char* argv[])
175
357
QGuiApplication::styleHints ()->setTabFocusBehavior (Qt::TabFocusAllControls);
176
358
QGuiApplication app (argc, argv);
177
359
178
- auto handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect (InitErrorMessageBox);
179
-
180
- std::unique_ptr<interfaces::Init> init = interfaces::MakeGuiInit (argc, argv);
360
+ auto m_handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect (InitErrorMessageBox);
181
361
182
362
SetupEnvironment ();
183
363
util::ThreadSetInternalName (" main" );
@@ -189,6 +369,10 @@ int QmlGuiMain(int argc, char* argv[])
189
369
app.setOrganizationDomain (QAPP_ORG_DOMAIN);
190
370
app.setApplicationName (QAPP_APP_NAME_DEFAULT);
191
371
372
+ QSettings settings;
373
+ QString dataDir;
374
+ dataDir = settings.value (" strDataDir" , dataDir).toString ();
375
+
192
376
// / Parse command-line options. We do this after qt in order to show an error if there are problems parsing these.
193
377
SetupServerArgs (gArgs );
194
378
SetupUIArgs (gArgs );
@@ -218,20 +402,24 @@ int QmlGuiMain(int argc, char* argv[])
218
402
return EXIT_FAILURE;
219
403
}
220
404
221
- // / Read and parse settings.json file.
222
- std::vector<std::string> errors;
223
- if (!gArgs .ReadSettingsFile (&errors)) {
224
- error = strprintf (" Failed loading settings file:\n %s\n " , MakeUnorderedList (errors));
225
- InitError (Untranslated (error));
226
- return EXIT_FAILURE;
227
- }
228
-
229
405
QVariant need_onboarding (true );
230
- if (gArgs .IsArgSet (" -datadir" ) && !gArgs .GetPathArg (" -datadir" ).empty ()) {
406
+ #ifdef __ANDROID__
407
+ AndroidCustomDataDir custom_data_dir;
408
+ QString storePath = custom_data_dir.readCustomDataDir ();
409
+ if (!storePath.isEmpty ()) {
410
+ custom_data_dir.setDataDir (storePath);
411
+ need_onboarding.setValue (false );
412
+ } else if (ConfigurationFileExists (gArgs )) {
413
+ need_onboarding.setValue (false );
414
+ }
415
+ #else
416
+ if ((gArgs .IsArgSet (" -datadir" ) && !gArgs .GetPathArg (" -datadir" ).empty ()) || fs::exists (GUIUtil::QStringToPath (dataDir)) ) {
417
+ setCustomDataDir (dataDir);
231
418
need_onboarding.setValue (false );
232
419
} else if (ConfigurationFileExists (gArgs )) {
233
420
need_onboarding.setValue (false );
234
421
}
422
+ #endif // __ANDROID__
235
423
236
424
if (gArgs .IsArgSet (" -resetguisettings" )) {
237
425
need_onboarding.setValue (true );
@@ -240,89 +428,22 @@ int QmlGuiMain(int argc, char* argv[])
240
428
// Default printtoconsole to false for the GUI. GUI programs should not
241
429
// print to the console unnecessarily.
242
430
gArgs .SoftSetBoolArg (" -printtoconsole" , false );
243
- InitLogging (gArgs );
244
- InitParameterInteraction (gArgs );
245
431
246
432
GUIUtil::LogQtInfo ();
247
-
248
- std::unique_ptr<interfaces::Node> node = init->makeNode ();
249
- std::unique_ptr<interfaces::Chain> chain = init->makeChain ();
250
- if (!node->baseInitialize ()) {
251
- // A dialog with detailed error will have been shown by InitError().
252
- return EXIT_FAILURE;
253
- }
254
-
255
- handler_message_box.disconnect ();
256
-
257
- NodeModel node_model{*node};
258
- InitExecutor init_executor{*node};
259
- QObject::connect (&node_model, &NodeModel::requestedInitialize, &init_executor, &InitExecutor::initialize);
260
- QObject::connect (&node_model, &NodeModel::requestedShutdown, &init_executor, &InitExecutor::shutdown);
261
- QObject::connect (&init_executor, &InitExecutor::initializeResult, &node_model, &NodeModel::initializeResult);
262
- QObject::connect (&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
263
- // QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException);
264
-
265
- NetworkTrafficTower network_traffic_tower{node_model};
266
- #ifdef __ANDROID__
267
- AndroidNotifier android_notifier{node_model};
268
- #endif
269
-
270
- ChainModel chain_model{*chain};
271
- chain_model.setCurrentNetworkName (QString::fromStdString (ChainTypeToString (gArgs .GetChainType ())));
272
- setupChainQSettings (&app, chain_model.currentNetworkName ());
273
-
274
- QObject::connect (&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList);
275
- QObject::connect (&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial);
276
-
277
- qGuiApp->setQuitOnLastWindowClosed (false );
278
- QObject::connect (qGuiApp, &QGuiApplication::lastWindowClosed, [&] {
279
- node->startShutdown ();
280
- });
281
-
282
- PeerTableModel peer_model{*node, nullptr };
283
- PeerListSortProxy peer_model_sort_proxy{nullptr };
284
- peer_model_sort_proxy.setSourceModel (&peer_model);
285
-
286
433
GUIUtil::LoadFont (" :/fonts/inter/regular" );
287
434
GUIUtil::LoadFont (" :/fonts/inter/semibold" );
288
435
289
- QQmlApplicationEngine engine ;
436
+ m_app = &app ;
290
437
291
- QScopedPointer<const NetworkStyle> network_style{NetworkStyle::instantiate (Params ().GetChainType ())};
292
- assert (!network_style.isNull ());
293
- engine.addImageProvider (QStringLiteral (" images" ), new ImageProvider{network_style.data ()});
294
-
295
- engine.rootContext ()->setContextProperty (" networkTrafficTower" , &network_traffic_tower);
296
- engine.rootContext ()->setContextProperty (" nodeModel" , &node_model);
297
- engine.rootContext ()->setContextProperty (" chainModel" , &chain_model);
298
- engine.rootContext ()->setContextProperty (" peerTableModel" , &peer_model);
299
- engine.rootContext ()->setContextProperty (" peerListModelProxy" , &peer_model_sort_proxy);
438
+ QQmlApplicationEngine engine;
300
439
301
- OptionsQmlModel options_model (*node, !need_onboarding.toBool ());
302
- engine.rootContext ()->setContextProperty (" optionsModel" , &options_model);
303
440
engine.rootContext ()->setContextProperty (" needOnboarding" , need_onboarding);
304
441
305
- AppMode app_mode = SetupAppMode ();
306
-
307
- qmlRegisterSingletonInstance<AppMode>(" org.bitcoincore.qt" , 1 , 0 , " AppMode" , &app_mode);
308
- qmlRegisterType<BlockClockDial>(" org.bitcoincore.qt" , 1 , 0 , " BlockClockDial" );
309
- qmlRegisterType<LineGraph>(" org.bitcoincore.qt" , 1 , 0 , " LineGraph" );
310
-
311
- engine.load (QUrl (QStringLiteral (" qrc:///qml/pages/main.qml" )));
312
- if (engine.rootObjects ().isEmpty ()) {
313
- return EXIT_FAILURE;
314
- }
315
-
316
- auto window = qobject_cast<QQuickWindow*>(engine.rootObjects ().first ());
317
- if (!window) {
318
- return EXIT_FAILURE;
442
+ if (need_onboarding.toBool ()) {
443
+ startOnboarding (*m_app, engine, gArgs );
444
+ } else {
445
+ startNode (*m_app, engine, argc, argv);
319
446
}
320
447
321
- // Install qDebug() message handler to route to debug.log
322
- qInstallMessageHandler (DebugMessageHandler);
323
-
324
- qInfo () << " Graphics API in use:" << QmlUtil::GraphicsApi (window);
325
-
326
- node_model.startShutdownPolling ();
327
- return qGuiApp->exec ();
448
+ return 0 ;
328
449
}
0 commit comments