#include "g_object.h" // qt #include #include #include G_Object::G_Object(QObject* parent) : QObject(parent) { } G_Object::G_Object(const QJsonObject& json, QObject* parent) : QObject(parent) { // use G_Object static offset, not virtual constructFromJson(json); } G_Object::G_Object(const QJsonValue& json, QObject* parent) : QObject(parent) { constructFromJson(json.toObject()); } G_Object::G_Object(const G_Object& other, QObject* parent) : QObject(parent) { // NOTE: always G_Object's assignment operator will be called, not derived *this = other; } G_Object& G_Object::operator=(const G_Object& other) { // use G_Object static offset, not virtual for (int i = staticMetaObject.propertyOffset(); i < metaObject()->propertyCount(); i++) { auto key = metaObject()->property(i).name(); auto value = metaObject()->property(i).read(this); if (value != other.property(key)) { setProperty(key, other.property(key)); } } return *this; } G_Object& G_Object::operator=(const QJsonObject& json) { constructFromJson(json); return *this; } G_Object& G_Object::operator=(const QJsonValue& json) { constructFromJson(json.toObject()); return *this; } G_Object::operator const QJsonValue() const { return this->operator const QJsonObject(); } bool G_Object::operator==(const G_Object& other) const { for (int i = staticMetaObject.propertyOffset(); i < metaObject()->propertyCount(); i++) { auto key = metaObject()->property(i).name(); if (property(key) != other.property(key)) { return false; } } return true; } bool G_Object::constructFromJson(const QJsonObject& json) { auto offset = staticMetaObject.propertyOffset(); auto properiesCount = metaObject()->propertyCount(); for (int i = offset; i < properiesCount; i++) { auto key = metaObject()->property(i).name(); auto type = metaObject()->property(i).userType(); auto jsonValue = json[key]; auto variantValue = jsonValue.toVariant(); if (variantValue.isNull()) { if (type == QMetaType::Double) { setProperty(key, std::numeric_limits::quiet_NaN()); } else if (type == QMetaType::Float) { setProperty(key, std::numeric_limits::quiet_NaN()); } else { return false; } continue; } auto converted = variantValue.convert(type); if (!converted) { qDebug() << Q_FUNC_INFO << "cannot convert" << key << "property from type" << QMetaType::typeName(variantValue.userType()) << "to type" << QMetaType::typeName(type); return false; } setProperty(key, variantValue); } return true; } G_Object::operator const QJsonObject() const { QJsonObject result; // use G_Object static offset, not virtual for (int i = staticMetaObject.propertyOffset(); i < metaObject()->propertyCount(); i++) { auto key = metaObject()->property(i).name(); auto type = metaObject()->property(i).userType(); auto value = metaObject()->property(i).read(this); if (value.isNull()) { continue; } auto converted = value.convert(type); if (!converted) { qDebug() << "G_Object::operator const QJsonObject() const:" << "cannot convert" << key << "property from type" << QMetaType::typeName(value.userType()) << "to type" << QMetaType::typeName(type); } result[key] = QJsonValue::fromVariant(value); } return result; } QDebug operator<<(QDebug d, const G_Object& o) { d << o.metaObject()->className() << ":\n"; for (int i = 0; i < o.metaObject()->propertyCount(); i++) { d << "\t" << o.metaObject()->property(i).name() << ":\t" << o.metaObject()->property(i).read(&o) << Qt::endl; } return d; }