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