#include "ConfigSection.hpp" #include #include 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(prop.read(this).value())) { // 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(prop.read(this).value())) { 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(prop.read(this).value())) { obj.insert(QLatin1String(prop.name()), child->toJson()); continue; } } obj.insert(QLatin1String(prop.name()), QJsonValue::fromVariant(prop.read(this))); } return obj; }