88 lines
2.7 KiB
C++
88 lines
2.7 KiB
C++
#include "ConfigSection.hpp"
|
|
|
|
#include <QMetaType>
|
|
#include <QVariant>
|
|
|
|
namespace {
|
|
// Property index to start scanning from - skips QObject's own "objectName"
|
|
// property, which we never want in the JSON.
|
|
int firstOwnProperty() {
|
|
return QObject::staticMetaObject.propertyCount();
|
|
}
|
|
}
|
|
|
|
ConfigSection::ConfigSection(QObject *parent) : QObject(parent) {}
|
|
|
|
void ConfigSection::wireSignals() {
|
|
if (m_wired) return;
|
|
m_wired = true;
|
|
|
|
const QMetaObject *mo = metaObject();
|
|
const int slotIdx = mo->indexOfSlot("onPropertyChanged()");
|
|
Q_ASSERT(slotIdx != -1);
|
|
const QMetaMethod slot = mo->method(slotIdx);
|
|
|
|
const int start = firstOwnProperty();
|
|
for (int i = start; i < mo->propertyCount(); ++i) {
|
|
const QMetaProperty prop = mo->property(i);
|
|
|
|
if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
|
|
if (auto *child = qobject_cast<ConfigSection *>(prop.read(this).value<QObject *>())) {
|
|
// Child sections bubble their changes straight up as our
|
|
// own changed() - no need to also react to our own notify.
|
|
connect(child, &ConfigSection::changed, this, &ConfigSection::changed);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (prop.hasNotifySignal())
|
|
connect(this, prop.notifySignal(), this, slot);
|
|
}
|
|
}
|
|
|
|
void ConfigSection::onPropertyChanged() {
|
|
Q_EMIT changed();
|
|
}
|
|
|
|
void ConfigSection::fromJson(const QJsonObject &obj) {
|
|
const QMetaObject *mo = metaObject();
|
|
const int start = firstOwnProperty();
|
|
|
|
for (int i = start; i < mo->propertyCount(); ++i) {
|
|
const QMetaProperty prop = mo->property(i);
|
|
const QLatin1String name(prop.name());
|
|
|
|
if (!obj.contains(name)) continue;
|
|
|
|
if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
|
|
if (auto *child = qobject_cast<ConfigSection *>(prop.read(this).value<QObject *>())) {
|
|
child->fromJson(obj.value(name).toObject());
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (prop.isWritable())
|
|
prop.write(this, obj.value(name).toVariant());
|
|
}
|
|
}
|
|
|
|
QJsonObject ConfigSection::toJson() const {
|
|
QJsonObject obj;
|
|
const QMetaObject *mo = metaObject();
|
|
const int start = firstOwnProperty();
|
|
|
|
for (int i = start; i < mo->propertyCount(); ++i) {
|
|
const QMetaProperty prop = mo->property(i);
|
|
|
|
if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
|
|
if (auto *child = qobject_cast<ConfigSection *>(prop.read(this).value<QObject *>())) {
|
|
obj.insert(QLatin1String(prop.name()), child->toJson());
|
|
continue;
|
|
}
|
|
}
|
|
|
|
obj.insert(QLatin1String(prop.name()), QJsonValue::fromVariant(prop.read(this)));
|
|
}
|
|
return obj;
|
|
}
|