#include "core/VaultSettings.h" #include #include #include #include namespace { QString cleanJournalDir(const QString &d) { QString t = d.trimmed(); t.replace(QLatin1Char('\\'), QLatin1Char('/')); // только один сегмент, без выхода наверх и служебных имён while (t.startsWith(QLatin1Char('/'))) t.remove(0, 1); while (t.endsWith(QLatin1Char('/')) && t.size() > 1) t.chop(1); if (t.isEmpty() || t == "." || t == ".." || t.contains(QLatin1String("..")) || t.contains(QLatin1Char('/')) || t.startsWith(QLatin1Char('.'))) return QStringLiteral("Журнал"); return t; } } // namespace VaultSettings::VaultSettings(QObject *parent) : QObject(parent) { } void VaultSettings::setJournalDir(const QString &d) { const QString clean = cleanJournalDir(d); if (m_journalDir == clean) return; m_journalDir = clean; emit changed(); } void VaultSettings::setSqlEnabled(bool on) { if (m_sqlEnabled == on) return; m_sqlEnabled = on; emit changed(); } void VaultSettings::setSqlMaxRows(int n) { if (n < 5) n = 5; if (n > 500) n = 500; if (m_sqlMaxRows == n) return; m_sqlMaxRows = n; emit changed(); } QString VaultSettings::settingsPath() const { if (m_vault.isEmpty()) return QString(); return QDir(m_vault).filePath(QStringLiteral(".flora/settings.json")); } bool VaultSettings::open(const QString &vaultPath) { const QString clean = QDir::cleanPath(vaultPath.trimmed()); if (clean.isEmpty() || !QDir(clean).exists()) return false; if (m_vault != clean) { m_vault = clean; emit vaultChanged(); } resetDefaults(); QFile f(settingsPath()); if (!f.exists()) return true; // нет файла — дефолты, это нормально if (!f.open(QIODevice::ReadOnly)) return false; QJsonParseError perr{}; const QJsonDocument doc = QJsonDocument::fromJson(f.readAll(), &perr); if (perr.error != QJsonParseError::NoError || !doc.isObject()) return false; const QJsonObject o = doc.object(); // Через сеттеры — с валидацией и без лишних сигналов setJournalDir(o.value(QStringLiteral("journalDir")).toString(m_journalDir)); if (o.contains(QStringLiteral("sqlEnabled"))) setSqlEnabled(o.value(QStringLiteral("sqlEnabled")).toBool(m_sqlEnabled)); if (o.contains(QStringLiteral("sqlMaxRows"))) setSqlMaxRows(o.value(QStringLiteral("sqlMaxRows")).toInt(m_sqlMaxRows)); return true; } bool VaultSettings::save() { if (m_vault.isEmpty()) return false; QDir().mkpath(QDir(m_vault).filePath(QStringLiteral(".flora"))); QFile f(settingsPath()); if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) return false; QJsonObject o; o.insert(QStringLiteral("journalDir"), m_journalDir); o.insert(QStringLiteral("sqlEnabled"), m_sqlEnabled); o.insert(QStringLiteral("sqlMaxRows"), m_sqlMaxRows); f.write(QJsonDocument(o).toJson(QJsonDocument::Indented)); return true; } void VaultSettings::resetDefaults() { bool touched = false; if (m_journalDir != QStringLiteral("Журнал")) { m_journalDir = QStringLiteral("Журнал"); touched = true; } if (!m_sqlEnabled) { m_sqlEnabled = true; touched = true; } if (m_sqlMaxRows != 50) { m_sqlMaxRows = 50; touched = true; } if (touched) emit changed(); }