delete unknown json objects + write missing objects to config file
This commit is contained in:
@@ -7,6 +7,51 @@
|
||||
|
||||
namespace ZShell::config {
|
||||
|
||||
namespace {
|
||||
|
||||
bool isStringArray(const QJsonArray& arr) {
|
||||
for (const auto& v : arr) {
|
||||
if (!v.isString()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool jsonValueMatchesType(const QJsonValue& val, QMetaType type) {
|
||||
switch (val.type()) {
|
||||
case QJsonValue::Bool:
|
||||
return type.id() == QMetaType::Bool;
|
||||
|
||||
case QJsonValue::Double:
|
||||
switch (type.id()) {
|
||||
case QMetaType::Int:
|
||||
case QMetaType::UInt:
|
||||
case QMetaType::LongLong:
|
||||
case QMetaType::ULongLong:
|
||||
case QMetaType::Double:
|
||||
case QMetaType::Float:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case QJsonValue::String:
|
||||
return type.id() == QMetaType::QString;
|
||||
|
||||
case QJsonValue::Array:
|
||||
if (type.id() == QMetaType::QStringList)
|
||||
return isStringArray(val.toArray());
|
||||
return type.id() == QMetaType::QVariantList;
|
||||
|
||||
case QJsonValue::Object:
|
||||
case QJsonValue::Null:
|
||||
case QJsonValue::Undefined:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
|
||||
|
||||
void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||
@@ -14,6 +59,7 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||
const auto* meta = metaObject();
|
||||
|
||||
QSet<QString> known;
|
||||
QSet<QString> invalid;
|
||||
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
auto prop = meta->property(i);
|
||||
@@ -34,6 +80,15 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||
|
||||
if (!prop.isWritable()) continue;
|
||||
|
||||
if (!jsonValueMatchesType(jsonVal, prop.metaType())) {
|
||||
qWarning() << "Config: type mismatch for" << key << "in"
|
||||
<< meta->className() << "- expected"
|
||||
<< prop.metaType().name() << "got value" << jsonVal
|
||||
<< "- resetting to default";
|
||||
invalid.insert(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop.metaType().id() == QMetaType::QStringList) {
|
||||
QStringList list;
|
||||
const auto jsonArr = jsonVal.toArray();
|
||||
@@ -56,10 +111,12 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||
|
||||
m_extras = {};
|
||||
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
||||
if (!known.contains(it.key())) {
|
||||
if (!known.contains(it.key()) || invalid.contains(it.key())) {
|
||||
m_extras.insert(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
materializeDefaults();
|
||||
}
|
||||
|
||||
QJsonValue ConfigObject::toJson() const {
|
||||
@@ -104,9 +161,6 @@ QJsonValue ConfigObject::toJson() const {
|
||||
obj.insert(key, QJsonValue::fromVariant(value));
|
||||
}
|
||||
|
||||
for (auto it = m_extras.begin(); it != m_extras.end(); ++it)
|
||||
obj.insert(it.key(), it.value());
|
||||
|
||||
if (obj.isEmpty()) return QJsonValue::Undefined;
|
||||
|
||||
return obj;
|
||||
@@ -159,6 +213,26 @@ QList<ConfigNode*> ConfigObject::childNodes() const {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
void ConfigObject::materializeDefaults() {
|
||||
const auto* meta = metaObject();
|
||||
|
||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||
const auto prop = meta->property(i);
|
||||
const auto key = QString::fromUtf8(prop.name());
|
||||
|
||||
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
||||
node->materializeDefaults();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prop.isWritable()) continue;
|
||||
|
||||
if (m_global) continue;
|
||||
|
||||
m_loadedKeys.insert(key);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigObject::syncValuesFromGlobal() {
|
||||
const auto* meta = metaObject();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user