#include "core/ConfigStore.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QSaveFile>
#include <QStandardPaths>
#include <algorithm>
namespace whittle {
namespace {
QJsonObject readJson(const QString& path) {
QFile f(path);
if (!f.open(QIODevice::ReadOnly)) return {};
const QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
return doc.isObject() ? doc.object() : QJsonObject{};
}
bool writeJson(const QString& path, const QJsonObject& obj) {
QDir().mkpath(QFileInfo(path).absolutePath());
QSaveFile f(path);
if (!f.open(QIODevice::WriteOnly)) return false;
f.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
return f.commit();
}
QString settingsPath() { return ConfigStore::configDir() + "/settings.json"; }
QString schemesPath() { return ConfigStore::configDir() + "/schemes.json"; }
constexpr char kSchemes[] = "schemes";
} // namespace
QString ConfigStore::configDir() {
QString base = QStandardPaths::writableLocation(
QStandardPaths::GenericConfigLocation);
if (base.isEmpty()) base = QDir::homePath() + "/.config";
const QString dir = base + "/whittle";
QDir().mkpath(dir);
return dir;
}
FilterSettings ConfigStore::loadFilter() {
FilterSettings f;
const QJsonObject o = readJson(settingsPath());
if (o.isEmpty()) return f;
f.compareSize = o.value("compareSize").toBool(f.compareSize);
f.compareTime = o.value("compareTime").toBool(f.compareTime);
if (!f.compareSize && !f.compareTime) f.compareSize = f.compareTime = true;
f.toleranceNs = qint64(o.value("toleranceNs").toDouble(double(f.toleranceNs)));
f.display = (o.value("display").toString() == QLatin1String("all"))
? FilterSettings::Display::All
: FilterSettings::Display::OnlyDiff;
f.recursive = o.value("recursive").toBool(f.recursive);
f.loadLastScheme = o.value("loadLastScheme").toBool(f.loadLastScheme);
return f;
}
bool ConfigStore::saveFilter(const FilterSettings& f) {
QJsonObject o = readJson(settingsPath());
o["compareSize"] = f.compareSize;
o["compareTime"] = f.compareTime;
o["toleranceNs"] = double(f.toleranceNs);
o["display"] = (f.display == FilterSettings::Display::All)
? QStringLiteral("all") : QStringLiteral("diff");
o["recursive"] = f.recursive;
o["loadLastScheme"] = f.loadLastScheme;
return writeJson(settingsPath(), o);
}
QString ConfigStore::loadLastSchemeName() {
return readJson(settingsPath()).value("lastScheme").toString();
}
bool ConfigStore::saveLastSchemeName(const QString& name) {
QJsonObject o = readJson(settingsPath());
o["lastScheme"] = name;
return writeJson(settingsPath(), o);
}
QStringList ConfigStore::schemeNames() {
const QJsonObject all = readJson(schemesPath())
.value(kSchemes).toObject();
QStringList names = all.keys();
std::sort(names.begin(), names.end(), [](const QString& a, const QString& b) {
return a.compare(b, Qt::CaseInsensitive) < 0;
});
return names;
}
bool ConfigStore::hasScheme(const QString& name) {
return readJson(schemesPath()).value(kSchemes).toObject().contains(name);
}
bool ConfigStore::saveScheme(const QString& name, const Scheme& s) {
if (name.trimmed().isEmpty()) return false;
QJsonObject root = readJson(schemesPath());
QJsonObject all = root.value(kSchemes).toObject();
QJsonArray roots;
for (const QString& r : s.roots) roots.append(r);
QJsonArray excluded;
for (const QString& e : s.excluded) excluded.append(e);
QJsonObject entry;
entry["recursive"] = s.recursive;
entry["roots"] = roots;
entry["excluded"] = excluded;
all[name] = entry;
root[kSchemes] = all;
return writeJson(schemesPath(), root);
}
ConfigStore::Scheme ConfigStore::loadScheme(const QString& name, bool* found) {
Scheme s;
const QJsonObject all = readJson(schemesPath()).value(kSchemes).toObject();
const auto it = all.find(name);
if (it == all.end()) { if (found) *found = false; return s; }
const QJsonObject entry = it->toObject();
s.recursive = entry.value("recursive").toBool(true);
for (const QJsonValue& v : entry.value("roots").toArray()) {
const QString p = v.toString();
if (!p.isEmpty()) s.roots << p;
}
for (const QJsonValue& v : entry.value("excluded").toArray()) {
const QString p = v.toString();
if (!p.isEmpty()) s.excluded << p;
}
if (found) *found = true;
return s;
}
bool ConfigStore::deleteScheme(const QString& name) {
QJsonObject root = readJson(schemesPath());
QJsonObject all = root.value(kSchemes).toObject();
if (!all.contains(name)) return false;
all.remove(name);
root[kSchemes] = all;
if (!writeJson(schemesPath(), root)) return false;
if (loadLastSchemeName() == name) saveLastSchemeName(QString());
return true;
}
}