#pragma once #include "configobject.hpp" #include #include #include #include namespace ZShell::config { class ConfigList : public ConfigNode { Q_OBJECT QML_ANONYMOUS Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(QVariantList values READ values NOTIFY valuesChanged) public: explicit ConfigList( QObject* parent = nullptr, const QVariantList& defaults = {}); [[nodiscard]] int count() const; [[nodiscard]] QVariantList values() const; [[nodiscard]] ConfigObject* itemAt(int index) const; [[nodiscard]] const QList& items() const; Q_INVOKABLE void remove(int index); Q_INVOKABLE void move(int from, int to); Q_INVOKABLE void clear(); void loadFromJson(const QJsonValue& json) override; [[nodiscard]] QJsonValue toJson() const override; void clearLoadedKeys() override; [[nodiscard]] QStringList unknownKeys() const override; void materializeDefaults() override; void resyncFromGlobal() override; signals: void countChanged(); void valuesChanged(); protected: virtual ConfigObject* createItem() = 0; void resetToDefaults(); ConfigObject* insertItem(const QVariantMap& props, int index = -1); [[nodiscard]] QJsonArray elementsToJson() const; void syncValuesFromGlobal() override; void onGlobalPropertiesChanged( const QMap& changed) override; [[nodiscard]] QString childPath(const ConfigNode* child) const override; private: void populate(const QJsonArray& arr); static bool sameElement( const ConfigObject* item, const QJsonValue& current, const QJsonValue& json); void appendItem(const QJsonValue& json); void destroyItems(); void destroyItem(ConfigObject* item); void rejectGlobalOnlyElement(const ConfigObject* item) const; void connectItem(ConfigNode* node); void disconnectItem(ConfigNode* node); void onItemChanged(); void notifyChanged(); QJsonArray m_defaults; QList m_items; bool m_loaded = false; }; } // namespace ZShell::config #define CONFIG_LIST_TYPE(Element, Name) \ class Name : public ZShell::config::ConfigList { \ Q_OBJECT \ QML_ANONYMOUS \ \ public: \ explicit Name( \ QObject* parent = nullptr, const QVariantList& defaults = {}) \ : ZShell::config::ConfigList(parent, defaults) { \ resetToDefaults(); \ } \ \ Q_INVOKABLE ZShell::config::Element* at(int index) const { \ return static_cast(itemAt(index)); \ } \ Q_INVOKABLE ZShell::config::Element* insert( \ const QVariantMap& props, int index = -1) { \ return static_cast( \ insertItem(props, index)); \ } \ \ protected: \ [[nodiscard]] ZShell::config::ConfigObject* createItem() override { \ return new ZShell::config::Element(this); \ } \ }; #define CONFIG_LIST(Type, name, ...) \ Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \ \ public: \ [[nodiscard]] Type* name() const { \ return m_##name; \ } \ \ private: \ Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__)); #define LIST_ENTRY(id, enabled) \ vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}}) namespace ZShell::config { class ListEntry : public ConfigObject { Q_OBJECT QML_ANONYMOUS CFG_PROPERTY(QString, id) CFG_PROPERTY(bool, enabled, true) public: explicit ListEntry(QObject* parent = nullptr) : ConfigObject(parent) {} [[nodiscard]] QStringList identityKeys() const override { return {QStringLiteral("id")}; } }; CONFIG_LIST_TYPE(ListEntry, EntryList) } // namespace ZShell::config