#pragma once // qt #include #include #include #include #include #include #include #ifndef STRINGIFY #define STRINGIFY(var) (#var) #endif class GlobalSettings; class GlobalSettings : public QSettings { Q_OBJECT public: static QSharedPointer instance(); private: GlobalSettings( GlobalSettings::Format format, GlobalSettings::Scope scope, const QString& organization, const QString& application = QString() ); static QSharedPointer m_instance; }; #define QML_DECLARATION(type, name) \ protected: \ Q_PROPERTY( \ type name READ get_##name WRITE set_##name NOTIFY name##Changed FINAL \ ) #define G_PROPERTY_DECL(type, name) \ QML_DECLARATION(type, name) protected : type m_##name; #define G_PROPERTY_DECL_DEFAULT(type, name, default) \ QML_DECLARATION(type, name) protected : type m_##name = default; #define G_PROPERTY_SIGNAL(type, name) \ Q_SIGNALS: \ void name##Changed(); \ void name##Changed(type value) #define G_PROPERTY_GET(type, name) \ public: \ Q_INVOKABLE virtual type& get_##name() \ { \ return m_##name; \ } \ Q_INVOKABLE virtual type get_##name() const \ { \ return m_##name; \ } #define G_PROPERTY_GET_DEBUG(type, name) \ public: \ virtual type get_##name() const \ { \ qDebug() << "PROPERTY: GET" << #name << m_##name; \ return m_##name; \ } #define G_PROPERTY_SET(type, name) \ public Q_SLOTS: \ virtual void set_##name(type a) \ { \ if (m_##name == a) \ return; \ m_##name = a; \ emit name##Changed(); \ emit name##Changed(m_##name); \ } #define G_PROPERTY_SET_DEBUG(type, name) \ public Q_SLOTS: \ virtual void set_##name(type a) \ { \ DEBUG_INFO("PROPERTY: SET" << #name << a); \ m_##name = a; \ emit name##Changed(); \ emit name##Changed(m_##name); \ } #define G_PROPERTY(type, name) \ G_PROPERTY_DECL(type, name) \ G_PROPERTY_SET(type, name) \ G_PROPERTY_GET(type, name) \ G_PROPERTY_SIGNAL(type, name) #define G_PROPERTY_DEFAULT(type, name, default) \ G_PROPERTY_DECL_DEFAULT(type, name, default) \ G_PROPERTY_SET(type, name) \ G_PROPERTY_GET(type, name) \ G_PROPERTY_SIGNAL(type, name) #define G_PROPERTY_CUSTOM_SET(type, name) \ G_PROPERTY_DECL(type, name) \ G_PROPERTY_GET(type, name) \ G_PROPERTY_SIGNAL(type, name) \ public Q_SLOTS: \ virtual void set_##name(type a); #define G_PROPERTY_DEBUG(type, name) \ G_PROPERTY_DECL(type, name) \ G_PROPERTY_SET_DEBUG(type, name) \ G_PROPERTY_GET_DEBUG(type, name) \ G_PROPERTY_SIGNAL(type, name) #define PROPERTY(type, name) \ G_PROPERTY_SET(type, name) \ G_PROPERTY_GET(type, name) \ G_PROPERTY_SIGNAL(type, name) #define G_PROPERTY_BASE(type, name) \ G_PROPERTY_DECL(type, name) \ G_PROPERTY_SIGNAL(type, name) #define G_PROPERTY_WRAP(type, name) \ QML_DECLARATION(type, name) \ public Q_SLOTS: \ virtual void set_##name(type a) \ { \ *(type*)&name = a; \ emit name##Changed(); \ emit name##Changed(name); \ } \ \ public: \ virtual type get_##name() const \ { \ return name; \ } \ G_PROPERTY_SIGNAL(type, name) #define INI_PROPERTY_SET(type, name) \ public Q_SLOTS: \ virtual void set_##name(const type& a) \ { \ auto old = get_##name(); \ if (old == a) \ { \ return; \ } \ auto n = QString(this->staticMetaObject.className()) + "/" + #name; \ GlobalSettings::instance()->setValue(n, QVariant::fromValue(a)); \ GlobalSettings::instance()->sync(); \ emit name##Changed(); \ emit name##Changed(a); \ } #define INI_PROPERTY_GET(type, name, defaultValue) \ public: \ virtual type get_##name() const \ { \ qDebug() << "read" << #name; \ const auto result = static_cast( \ GlobalSettings::instance() \ ->value( \ QString(this->staticMetaObject.className()) + "/" + #name, \ defaultValue \ ) \ .value() \ ); \ qDebug() << #name << "result:" << result; \ return result; \ } #define INI_PROPERTY_GET_CAST(type, name, defaultValue) \ public: \ virtual type get_##name() const \ { \ return GlobalSettings::instance()->value( \ QString(this->staticMetaObject.className()) + "/" + #name, \ defaultValue \ ); \ } #define INI_PROPERTY_GET_VAR(type, name, defaultValue) \ public: \ virtual type get_##name() \ { \ return GlobalSettings::instance() \ ->value( \ QString(this->staticMetaObject.className()) + "/" + #name, \ QVariant::fromValue(defaultValue) \ ) \ .value(); \ } #define INI_PROPERTY(type, name, defaultValue) \ INI_PROPERTY_SET(type, name) \ INI_PROPERTY_GET(type, name, defaultValue) \ QML_DECLARATION(type, name) \ G_PROPERTY_SIGNAL(type, name) #define INI_PROPERTY_CAST(type, name, defaultValue) \ INI_PROPERTY_SET(type, name) \ INI_PROPERTY_GET_CAST(type, name, defaultValue) \ QML_DECLARATION(type, name) \ G_PROPERTY_SIGNAL(type, name) #define INI_PROPERTY_VAR(type, name, defaultValue) \ INI_PROPERTY_SET(type, name) \ INI_PROPERTY_GET_VAR(type, name, defaultValue) \ QML_DECLARATION(type, name) \ G_PROPERTY_SIGNAL(type, name) #define INI_PROPERTY_DEBUG(name) \ INI_PROPERTY_SET(name) \ INI_PROPERTY_GET(name) \ QML_DECLARATION(type, name) \ G_PROPERTY_SIGNAL(type, name) #define RO_PROPERTY(type, name, value) \ protected: \ Q_PROPERTY(type name READ get_##name NOTIFY name##Changed) \ public: \ inline bool get_##name() \ { \ return m_##value; \ } \ Q_SIGNALS: \ void name##Changed(); \ \ protected: \ type m_##name; #define STATIC_PROPERTY(type, name) \ public: \ static inline type get_##name() \ { \ return m_##name; \ } \ static inline void set_##name(type value) \ { \ m_##name = value; \ } \ \ private: \ static type m_##name // there must be QJsonObject json in scope; // TODO: use QVariant::value() #define READ_FROM_JSON(type, name, default) \ set_##name( \ json[#name] == QJsonValue::Undefined \ ? default \ : json[#name].toVariant().value() \ ) #define INIT_FROM_JSON(type, var, default) \ m_##var( \ (json.contains(#var)) \ ? (json[STRINGIFY(var)].toVariant().value()) \ : (default) \ ) #define INIT_OBJECT_JSON(var, default) \ m_##var((json.contains(#var)) ? (json[STRINGIFY(var)]) : (default)) // for QJsonObject(std::initializer_list > args) // TODO: make type first argument #define WRITE_TO_JSON(var, cast) (#var), cast(m_##var) #define WRITE_ENUM_TO_JSON(var) (#var), QVariant(m_##var).toJsonValue() #define WRITE_ENUM_KEY_TO_JSON(var) \ (#var), \ QString( \ QMetaEnum::fromType().valueToKey(int(m_##var)) \ ) #define WRITE_VARIANT_TO_JSON(var) (#var), QJsonValue::fromVariant(m_##var) #define WRITE_ARRAY_TO_JSON(var) (#var), QJsonArray(m_##var) #define WRITE_STRINGLIST_TO_JSON(var) \ (#var), QJsonArray::fromStringList(m_##var) #define WRITE_TO_JSON_NO_CAST(var) (#var), (m_##var) #define WRITE_PTR_TO_JSON(var) (#var), QJsonObject(*m_##var) // without 's' in the end of name please #define G_QML_LIST_PROPERTY(classname, type, name) \ protected: \ Q_PROPERTY( \ QQmlListProperty name##s READ name##s NOTIFY name##sChanged \ ) \ public: \ QQmlListProperty name##s() \ { \ return QQmlListProperty( \ this, \ this, \ &classname ::append_##name, \ &classname ::name##sCount, \ &classname ::name, \ &classname ::clear_##name##s \ ); \ } \ void append_##name(type* item) \ { \ m_##name##s.append(item); \ emit name##sChanged(); \ emit name##sChanged(m_##name##s); \ } \ int name##sCount() const \ { \ return m_##name##s.count(); \ } \ type* name(int index) const \ { \ return m_##name##s.at(index); \ } \ void clear_##name##s() \ { \ while (!m_##name##s.isEmpty()) \ { \ auto tmp = m_##name##s.takeLast(); \ if (tmp->parent() == this) \ delete tmp; \ } \ emit name##sChanged(); \ emit name##sChanged(m_##name##s); \ } \ inline QList& get_##name##s() \ { \ return m_##name##s; \ } \ Q_SIGNALS: \ void name##sChanged(); \ \ protected: \ static void append_##name(QQmlListProperty* list, type* item) \ { \ reinterpret_cast(list->data)->append_##name(item); \ } \ static int name##sCount(QQmlListProperty* list) \ { \ return reinterpret_cast(list->data)->name##sCount(); \ } \ static type* name(QQmlListProperty* list, int index) \ { \ return reinterpret_cast(list->data)->name(index); \ } \ static void clear_##name##s(QQmlListProperty* list) \ { \ reinterpret_cast(list->data)->clear_##name##s(); \ } \ QList m_##name##s #define INIT_FIELD(name) m_##name(name) #define INIT_FROM_OTHER(name) m_##name(other.m_##name) #define SET_FROM_OTHER(name) set_##name(other.m_##name) #define SET_FROM_OTHER_PTR(name) \ *m_##name = *other.m_##name; \ emit name##Changed(); \ emit name##Changed(m_##name) #define SET_FROM_JSON(type, name, default) \ set_##name( \ json.contains(#name) ? json[#name].toVariant().value() : default \ ) #define SET_FROM_JSON_ENUM_KEY(name, default) \ set_##name( \ json.contains(#name) \ ? (typeof(m_##name))(QMetaEnum::fromType() \ .keyToValue( \ json[#name] \ .toString() \ .toStdString() \ .c_str() \ )) \ : default \ ) #define COMPARE_WITH_OTHER(name) (get_##name() == other.get_##name()) template static QJsonArray listToJson(const QList& list) { QJsonArray result; for (const auto& item : list) { result << QJsonValue(*item); } return result; } template static QList listFromJson( const QJsonArray& array, QObject* parent = nullptr ) { QList result; for (const auto& jsonItem : array) { result << new T(jsonItem.toObject(), parent); } return result; } #define INIT_LIST_FROM_JSON(listName, className, parent) \ m_##listName(listFromJson(json[#listName].toArray(), parent)) #define WRITE_LIST_TO_JSON(listName, className) \ #listName, listToJson(m_##listName)