#pragma once #include #include #include #include "changebatcher.hpp" #include "common.hpp" #include "quarantine.hpp" #include "schema.hpp" namespace ZShell::settings { class Node : public QObject { Q_OBJECT public: // Global only nodes are inherited, anything inside one is also global only explicit Node( Node* fallback, QObject* parent = nullptr, bool globalOnly = false); [[nodiscard]] QString key() const; // The key of this in the parent node [[nodiscard]] QString path() const; [[nodiscard]] virtual QString pathFor(const QString& key) const; [[nodiscard]] static QString elementPath( const QString& path, const QString& index); [[nodiscard]] Node* parentNode() const; [[nodiscard]] Node* rootNode() const; [[nodiscard]] Node* fallbackNode() const; void detachFallback(); // Recursive, unlinks this and its children from the fallback layer [[nodiscard]] Q_INVOKABLE bool isGlobalOnly() const; [[nodiscard]] bool isOverride(const QString& key) const; [[nodiscard]] const QSet& overrides() const; [[nodiscard]] bool hasContent() const; // Recursive [[nodiscard]] virtual const Schema& schema() const = 0; [[nodiscard]] virtual QVariant value(const QString& key) const; virtual bool setValue( const QString& key, const QVariant& value); // Returns whether the write was successful or not virtual void resetToDefaults(); // Recursive, resets to fallbacks then defaults if not overridden [[nodiscard]] virtual QJsonValue toJson(bool sparse = true) const = 0; // Returns false if the entire node was rejected virtual bool syncJson( const QJsonValue& json, QList& diagnostics) = 0; [[nodiscard]] const Quarantine* quarantine() const; signals: void optionChanged(const QString& key); protected: // Null means empty, otherwise it has content std::unique_ptr m_quarantine; const bool m_globalOnly; // Own flag or inherited from the parent node void warnGlobalRead(const QString& key) const; // Returns true if the write should be skipped afterwards, the value is not one of the allowed types [[nodiscard]] bool rejectInvalidWrite( const QString& key, const QVariant& value) const; template [[nodiscard]] bool rejectInvalidWrite( const QString& key, const T& value) const; // Returns true if the write should be skipped afterwards, overlays cannot write global options bool rejectGlobalWrite(const QString& key); static void warnGlobalSync( QList& diagnostics, const QString& path); bool rejectGlobalSync(QList& diagnostics) const; // Returns true if the sync should be rejected // Returns true if the notify signal should be emitted virtual bool recordWrite(const QString& key, bool changed); [[nodiscard]] bool removeQuarantined(const QString& key); [[nodiscard]] ChangeBatcher* batcher() const; [[nodiscard]] virtual QString keyOf(const Node* child) const; template [[nodiscard]] T fallbackValue( T C::* member, std::type_identity_t defaultValue) const; private: QSet m_overrides; // Overridden keys from file/qml writes Node* const m_rootNode; Node* m_fallbackNode; // No fallback node either means global tree or inside overridden list // For root node use only WriteOrigin m_writeOrigin; bool m_internalRead; ChangeBatcher* const m_batcher; void onFallbackNotify(const QString& key); friend class WriteScope; friend class InternalRead; }; template bool Node::rejectInvalidWrite(const QString& key, const T& value) const { Q_UNUSED(key) Q_UNUSED(value) return false; // Only QVariant unions can be given the wrong type } template T Node::fallbackValue( T C::* member, std::type_identity_t defaultValue) const { const auto* fallback = static_cast(m_fallbackNode); return fallback ? fallback->*member : defaultValue; } } // namespace ZShell::settings