#ifndef JSONHANDLER_H #define JSONHANDLER_H #include #include #include #include #include #include "jsonreply.h" class JsonHandler : public QObject { Q_OBJECT public: enum BasicType { Uuid, String, StringList, Int, Uint, Double, Bool, Variant, Color, Time, Object }; Q_ENUM(BasicType) explicit JsonHandler(QObject *parent = nullptr); virtual ~JsonHandler() = default; virtual QString name() const = 0; QVariantMap jsonEnums() const; QVariantMap jsonFlags() const; QVariantMap jsonObjects() const; QVariantMap jsonMethods() const; QVariantMap jsonNotifications() const; template static QString enumRef(); static QString objectRef(const QString &objectName); template static QString enumValueName(T value); template static T enumNameToValue(const QString &name); static BasicType variantTypeToBasicType(QVariant::Type variantType); static QVariant::Type basicTypeToVariantType(BasicType basicType); template QVariantMap pack(const T &value) const; protected: template void registerEnum(); template void registerEnum(); template void registerObject(); template void registerObject(); void registerObject(const QString &name, const QVariantMap &object); void registerMethod(const QString &name, const QString &description, const QVariantMap ¶ms, const QVariantMap &returns, bool deprecated = false); void registerNotification(const QString &name, const QString &description, const QVariantMap ¶ms, bool deprecated = false); JsonReply *createReply(const QVariantMap &data) const; JsonReply *createAsyncReply(const QString &method) const; private: QVariantMap pack(const QMetaObject &metaObject, const void *gadget) const; private: QVariantMap m_enums; QHash m_metaEnums; QVariantMap m_flags; QHash m_metaFlags; QHash m_flagsEnums; QVariantMap m_objects; QHash m_metaObjects; QHash m_listMetaObjects; QHash m_listEntryTypes; QVariantMap m_methods; QVariantMap m_notifications; }; Q_DECLARE_METATYPE(QVariant::Type) template void JsonHandler::registerEnum() { QMetaEnum metaEnum = QMetaEnum::fromType(); QStringList values; for (int i = 0; i < metaEnum.keyCount(); i++) { values << metaEnum.key(i); } m_enums.insert(metaEnum.name(), values); m_metaEnums.insert(metaEnum.name(), metaEnum); } template void JsonHandler::registerEnum() { registerEnum(); QMetaEnum metaEnum = QMetaEnum::fromType(); QMetaEnum metaFlags = QMetaEnum::fromType(); m_metaFlags.insert(metaFlags.name(), metaFlags); m_flagsEnums.insert(metaFlags.name(), metaEnum.name()); m_flags.insert(metaFlags.name(), QVariantList() << QString("$ref:%1").arg(metaEnum.name())); } template void JsonHandler::registerObject() { qRegisterMetaType(); QMetaObject metaObject = ObjectType::staticMetaObject; QString className = QString(metaObject.className()).split("::").last(); QVariantMap description; for (int i = 0; i < metaObject.propertyCount(); i++) { QMetaProperty metaProperty = metaObject.property(i); QString name = metaProperty.name(); if (name == "objectName") { continue; // Skip QObject's objectName property } if (metaProperty.isUser()) { name.prepend("o:"); } QVariant typeName; // qWarning() << ".-.-.-.-.-" << metaProperty.name() << metaProperty.type() << metaProperty.typeName(); if (metaProperty.type() == QVariant::UserType) { if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) { typeName = QString("$ref:BasicType"); } else if (QString(metaProperty.typeName()).startsWith("QList")) { typeName = QVariantList() << "$ref:" + QString(metaProperty.typeName()).remove("QList<").remove(">"); } else { typeName = QString("$ref:%1").arg(QString(metaProperty.typeName()).split("::").last()); } } else if (metaProperty.isEnumType()) { typeName = QString("$ref:%1").arg(QString(metaProperty.typeName()).split("::").last()); } else if (metaProperty.isFlagType()) { typeName = QVariantList() << "$ref:" + m_flagsEnums.value(metaProperty.name()); } else if (metaProperty.type() == QVariant::List) { typeName = QVariantList() << enumValueName(Variant); } else { typeName = enumValueName(variantTypeToBasicType(metaProperty.type())); } description.insert(name, typeName); } m_objects.insert(className, description); m_metaObjects.insert(className, metaObject); } template void JsonHandler::registerObject() { registerObject(); QMetaObject metaObject = ObjectType::staticMetaObject; QMetaObject listMetaObject = ListType::staticMetaObject; m_objects.insert(listMetaObject.className(), QVariantList() << QVariant(QString("$ref:%1").arg(metaObject.className()))); m_metaObjects.insert(listMetaObject.className(), listMetaObject); m_listMetaObjects.insert(listMetaObject.className(), listMetaObject); m_listEntryTypes.insert(listMetaObject.className(), metaObject.className()); Q_ASSERT_X(listMetaObject.indexOfProperty("count") >= 0, "JsonHandler", "List type does not implement \"count\" property!"); Q_ASSERT_X(listMetaObject.indexOfMethod("get(int)") >= 0, "JsonHandler", "List type does not implement \"Q_INVOKABLE QVariant get(int index)\" method!"); } //template //void JsonHandler::registerList() //{ // QMetaObject metaObject = T::staticMetaObject; // m_lists.insert(metaObject.className(), metaObject); // m_objects.insert(metaObject.classInfo(), QVariantList() << ) //} template QString JsonHandler::enumRef() { QMetaEnum metaEnum = QMetaEnum::fromType(); return QString("$ref:%1").arg(metaEnum.name()); } template QString JsonHandler::enumValueName(T value) { QMetaEnum metaEnum = QMetaEnum::fromType(); return metaEnum.valueToKey(value); } template T JsonHandler::enumNameToValue(const QString &name) { QMetaEnum metaEnum = QMetaEnum::fromType(); return static_cast(metaEnum.keyToValue(name.toUtf8())); } template QVariantMap JsonHandler::pack(const T &value) const { QMetaObject metaObject = T::staticMetaObject; return pack(metaObject, static_cast(&value)); } #endif // JSONHANDLER_H