summaryrefslogtreecommitdiff
path: root/g_property.h
diff options
context:
space:
mode:
Diffstat (limited to 'g_property.h')
-rw-r--r--g_property.h420
1 files changed, 420 insertions, 0 deletions
diff --git a/g_property.h b/g_property.h
new file mode 100644
index 0000000..fa743cd
--- /dev/null
+++ b/g_property.h
@@ -0,0 +1,420 @@
+#pragma once
+
+// qt
+#include <QCoreApplication>
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QObject>
+#include <QQmlListProperty>
+#include <QSettings>
+#include <QSharedPointer>
+
+#ifndef STRINGIFY
+#define STRINGIFY(var) (#var)
+#endif
+
+class GlobalSettings;
+class GlobalSettings : public QSettings
+{
+ Q_OBJECT
+
+public:
+ static QSharedPointer<GlobalSettings> instance();
+
+private:
+ GlobalSettings(
+ GlobalSettings::Format format,
+ GlobalSettings::Scope scope,
+ const QString& organization,
+ const QString& application = QString()
+ );
+ static QSharedPointer<GlobalSettings> 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 \
+ { \
+ return static_cast<type>( \
+ GlobalSettings::instance() \
+ ->value( \
+ QString(this->staticMetaObject.className()) + "/" + #name, \
+ defaultValue \
+ ) \
+ .value<type>() \
+ ); \
+ }
+
+#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<type>(); \
+ }
+
+#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<type>() \
+ )
+
+#define INIT_FROM_JSON(type, var, default) \
+ m_##var( \
+ (json.contains(#var)) \
+ ? (json[STRINGIFY(var)].toVariant().value<type>()) \
+ : (default) \
+ )
+
+#define INIT_OBJECT_JSON(var, default) \
+ m_##var((json.contains(#var)) ? (json[STRINGIFY(var)]) : (default))
+
+// for QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > 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<typeof(m_##var)>().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<type> name##s READ name##s NOTIFY name##sChanged \
+ ) \
+public: \
+ QQmlListProperty<type> name##s() \
+ { \
+ return QQmlListProperty<type>( \
+ 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<type*>& get_##name##s() \
+ { \
+ return m_##name##s; \
+ } \
+Q_SIGNALS: \
+ void name##sChanged(); \
+ \
+protected: \
+ static void append_##name(QQmlListProperty<type>* list, type* item) \
+ { \
+ reinterpret_cast<classname*>(list->data)->append_##name(item); \
+ } \
+ static int name##sCount(QQmlListProperty<type>* list) \
+ { \
+ return reinterpret_cast<classname*>(list->data)->name##sCount(); \
+ } \
+ static type* name(QQmlListProperty<type>* list, int index) \
+ { \
+ return reinterpret_cast<classname*>(list->data)->name(index); \
+ } \
+ static void clear_##name##s(QQmlListProperty<type>* list) \
+ { \
+ reinterpret_cast<classname*>(list->data)->clear_##name##s(); \
+ } \
+ QList<type*> 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<type>() : default \
+ )
+
+#define SET_FROM_JSON_ENUM_KEY(name, default) \
+ set_##name( \
+ json.contains(#name) \
+ ? (typeof(m_##name))(QMetaEnum::fromType<typeof(m_##name)>() \
+ .keyToValue( \
+ json[#name] \
+ .toString() \
+ .toStdString() \
+ .c_str() \
+ )) \
+ : default \
+ )
+
+#define COMPARE_WITH_OTHER(name) (get_##name() == other.get_##name())
+
+template <class T> static QJsonArray listToJson(const QList<T*>& list)
+{
+ QJsonArray result;
+
+ for (const auto& item : list)
+ {
+ result << QJsonValue(*item);
+ }
+
+ return result;
+}
+
+template <class T>
+static QList<T*> listFromJson(
+ const QJsonArray& array,
+ QObject* parent = nullptr
+)
+{
+ QList<T*> 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<className>(json[#listName].toArray(), parent))
+
+#define WRITE_LIST_TO_JSON(listName, className) \
+ #listName, listToJson<className>(m_##listName)