Skip to content

Commit 49c2f25

Browse files
committed
qml: stabilize pre-init datadir and settings resolution
Keep the datadir selected in onboarding separate from the path Core resolves after config parsing. Run pre-init preview and apply through a scratch ArgsManager seeded from the original argv so live gArgs reaches InitConfig without preloaded config or settings state. Finalize onboarding settings after InitConfig and chain-specific QSettings setup. Apply reset across Core and GUI stores transactionally, preserve strDataDir, honor final source precedence, and recover unreadable settings with the Qt reset-or-abort behavior. Only open and synchronize settings stores that are used or modified, preserving rollback without allowing unrelated stores to block startup. Add unit and functional coverage for datadir precedence, reset behavior, recovery, persistence, and rollback.
1 parent c238cef commit 49c2f25

11 files changed

Lines changed: 2631 additions & 413 deletions

qml/bitcoin.cpp

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#endif
7070
#include <util/fs.h>
7171
#include <util/fs_helpers.h>
72+
#include <util/string.h>
7273
#include <util/threadnames.h>
7374
#include <util/translation.h>
7475
#ifdef ENABLE_WALLET
@@ -77,6 +78,7 @@
7778

7879
#include <cassert>
7980
#include <memory>
81+
#include <optional>
8082
#include <tuple>
8183
#include <vector>
8284

@@ -89,6 +91,7 @@
8991
#include <QPixmap>
9092
#include <QGuiApplication>
9193
#include <QJSEngine>
94+
#include <QMessageBox>
9295
#include <QPointer>
9396
#include <QQmlApplicationEngine>
9497
#include <QQmlContext>
@@ -296,8 +299,35 @@ enum class PreInitOnboardingStatus {
296299
FAILED,
297300
};
298301

302+
bool ErrorSettingsRead(const bilingual_str& error, const std::vector<std::string>& details)
303+
{
304+
if (gArgs.GetBoolArg("-resetguisettings", false)) {
305+
return false;
306+
}
307+
308+
QMessageBox message_box{
309+
QMessageBox::Critical,
310+
CLIENT_NAME,
311+
QString::fromStdString(strprintf("%s.", error.translated)),
312+
QMessageBox::Reset | QMessageBox::Abort,
313+
};
314+
message_box.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
315+
message_box.setDetailedText(QString::fromStdString(util::MakeUnorderedList(details)));
316+
message_box.setTextFormat(Qt::PlainText);
317+
message_box.setDefaultButton(QMessageBox::Reset);
318+
switch (message_box.exec()) {
319+
case QMessageBox::Reset:
320+
return false;
321+
case QMessageBox::Abort:
322+
return true;
323+
default:
324+
assert(false);
325+
}
326+
}
327+
299328
struct PreInitOnboardingContext {
300329
std::unique_ptr<OnboardingOptionsModel> onboarding_options_model;
330+
std::optional<QmlOnboardingSettings::PendingApply> pending_apply;
301331
QScopedPointer<const NetworkStyle> network_style;
302332
std::unique_ptr<QQmlApplicationEngine> engine;
303333
#ifdef ENABLE_TEST_AUTOMATION
@@ -324,6 +354,9 @@ bool ShouldShowPreInitOnboarding(const std::vector<std::string>& argv, bool can_
324354
const QmlOnboardingSettings::OnboardingStartupStatus status{
325355
QmlOnboardingSettings::ResolveOnboardingStartupStatus(argv, can_listen_ipc)
326356
};
357+
if (status.settings_file_unreadable) {
358+
return false;
359+
}
327360
return !status.ok || status.should_show_onboarding;
328361
}
329362

@@ -380,11 +413,13 @@ PreInitOnboardingStatus RunPreInitOnboarding(PreInitOnboardingContext& context,
380413
}
381414

382415
QString error;
383-
if (!context.onboarding_options_model->applyToArgs(gArgs, &error)) {
416+
QmlOnboardingSettings::PendingApply pending_apply;
417+
if (!context.onboarding_options_model->prepareApplyToArgs(gArgs, pending_apply, &error)) {
384418
InitError(Untranslated(error.toStdString()));
385419
context.close();
386420
return PreInitOnboardingStatus::FAILED;
387421
}
422+
context.pending_apply = std::move(pending_apply);
388423
return PreInitOnboardingStatus::COMPLETED;
389424
}
390425
} // namespace
@@ -465,13 +500,9 @@ int QmlGuiMain(int argc, char* argv[])
465500

466501
app.setQuitOnLastWindowClosed(false);
467502
setupChainQSettings(&app, QString::fromStdString(gArgs.GetChainTypeString()).toUpper());
468-
if (gArgs.GetBoolArg("-resetguisettings", false)) {
469-
QString reset_error;
470-
if (!QmlDataDir::ResetGuiSettings(gArgs, &reset_error)) {
471-
InitError(Untranslated(reset_error.toStdString()));
472-
return EXIT_FAILURE;
473-
}
474-
}
503+
const QmlOnboardingSettings::GuiSettingsStore bootstrap_gui_settings{
504+
QmlOnboardingSettings::CurrentGuiSettingsStore()
505+
};
475506

476507
LoadFontResource(":/fonts/bitcoincoresans/regular");
477508
LoadFontResource(":/fonts/bitcoincoresans/semibold");
@@ -512,26 +543,21 @@ int QmlGuiMain(int argc, char* argv[])
512543

513544
if (auto error = common::InitConfig(
514545
gArgs,
515-
[](const bilingual_str& msg, const std::vector<std::string>& details) {
516-
return InitError(msg, details);
517-
})) {
546+
ErrorSettingsRead)) {
518547
return EXIT_FAILURE;
519548
}
520549

521-
const QmlLegacySettings::MigrationResult legacy_migration{
522-
QmlLegacySettings::MigrateCoreSettings(gArgs, QmlLegacySettings::MigrationMode::Persist)
523-
};
524-
if (!legacy_migration.error.isEmpty()) {
525-
InitError(Untranslated(legacy_migration.error.toStdString()));
550+
setupChainQSettings(&app, QString::fromStdString(gArgs.GetChainTypeString()).toUpper());
551+
QString finalize_settings_error;
552+
if (!QmlOnboardingSettings::FinalizeStartupSettings(
553+
gArgs,
554+
bootstrap_gui_settings,
555+
pre_init_onboarding_context.pending_apply ? &*pre_init_onboarding_context.pending_apply : nullptr,
556+
/*result=*/nullptr,
557+
&finalize_settings_error)) {
558+
InitError(Untranslated(finalize_settings_error.toStdString()));
526559
return EXIT_FAILURE;
527560
}
528-
if (legacy_migration.settings_changed) {
529-
std::vector<std::string> settings_errors;
530-
if (!gArgs.WriteSettingsFile(&settings_errors)) {
531-
InitError(_("Settings file could not be written"), settings_errors);
532-
return EXIT_FAILURE;
533-
}
534-
}
535561

536562
// legacy GUI: parameterSetup()
537563
// Default printtoconsole to false for the GUI. GUI programs should not
@@ -600,15 +626,6 @@ int QmlGuiMain(int argc, char* argv[])
600626

601627
ChainModel chain_model{*chain};
602628
chain_model.setCurrentNetworkName(QString::fromStdString(gArgs.GetChainTypeString()));
603-
setupChainQSettings(&app, chain_model.currentNetworkName());
604-
// Settings reset must happen before model instantiation so the models
605-
// read clean defaults from QSettings.
606-
if (gArgs.IsArgSet("-resetguisettings")) {
607-
QSettings settings;
608-
settings.remove(QStringLiteral("fHideTrayIcon"));
609-
settings.remove(QStringLiteral("fMinimizeToTray"));
610-
settings.remove(QStringLiteral("fMinimizeOnClose"));
611-
}
612629

613630
QObject::connect(&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList);
614631
QObject::connect(&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial);

qml/datadir.cpp

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -225,48 +225,6 @@ void PersistDefaultDataDirSelection()
225225
QmlLegacySettings::ClearLegacyGuiSettings(QString::fromStdString(Params().GetChainTypeString()));
226226
}
227227

228-
bool ResetGuiSettings(ArgsManager& args, QString* error)
229-
{
230-
if (error) error->clear();
231-
232-
QSettings settings;
233-
settings.clear();
234-
settings.setValue(RESET_GUI_SETTINGS_KEY, false);
235-
236-
try {
237-
SelectParams(args.GetChainType());
238-
args.SelectConfigNetwork(args.GetChainTypeString());
239-
QmlLegacySettings::ClearLegacyGuiSettings(QString::fromStdString(args.GetChainTypeString()));
240-
} catch (const std::exception& e) {
241-
if (error) *error = QString::fromStdString(e.what());
242-
return false;
243-
}
244-
245-
fs::path settings_path;
246-
if (!args.GetSettingsPath(&settings_path) || !fs::exists(settings_path)) {
247-
return true;
248-
}
249-
250-
std::vector<std::string> settings_errors;
251-
if (!args.ReadSettingsFile(&settings_errors)) {
252-
if (error) *error = QString::fromStdString(settings_errors.empty() ? std::string{"Settings file could not be read."} : settings_errors.front());
253-
return false;
254-
}
255-
if (!args.WriteSettingsFile(&settings_errors, /*backup=*/true)) {
256-
if (error) *error = QString::fromStdString(settings_errors.empty() ? std::string{"Settings file backup could not be written."} : settings_errors.front());
257-
return false;
258-
}
259-
args.LockSettings([](common::Settings& settings) {
260-
settings.rw_settings.clear();
261-
});
262-
settings_errors.clear();
263-
if (!args.WriteSettingsFile(&settings_errors)) {
264-
if (error) *error = QString::fromStdString(settings_errors.empty() ? std::string{"Settings file could not be written."} : settings_errors.front());
265-
return false;
266-
}
267-
return true;
268-
}
269-
270228
bool HasExplicitDataDirArg(const ArgsManager& args)
271229
{
272230
return args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").empty();

qml/datadir.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ StorageSpaceResult CheckStorageSpace(const QString& path);
4949
bool EnsureDataDir(const QString& path, QString* error = nullptr);
5050
bool PersistGuiDataDirSelection(const QString& path, QString* error = nullptr);
5151
void PersistDefaultDataDirSelection();
52-
bool ResetGuiSettings(ArgsManager& args, QString* error = nullptr);
5352

5453
bool HasExplicitDataDirArg(const ArgsManager& args);
5554
bool ShouldShowDataDirChooser(const ArgsManager& args);

0 commit comments

Comments
 (0)