From d6ed717c39e545095b8eb43f3d974c76c863e00b Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Wed, 14 Feb 2024 03:03:41 -0800 Subject: [PATCH] feat: abstract out scavenger scopes --- src/cpp/scavenge.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/cpp/scavenge.hpp | 32 +++++++++++++++++++++++++++++++- src/cpp/shell.cpp | 38 -------------------------------------- src/cpp/shell.hpp | 19 ++----------------- 4 files changed, 74 insertions(+), 56 deletions(-) diff --git a/src/cpp/scavenge.cpp b/src/cpp/scavenge.cpp index 81f4851d..2ad77694 100644 --- a/src/cpp/scavenge.cpp +++ b/src/cpp/scavenge.cpp @@ -1,10 +1,16 @@ #include "scavenge.hpp" +#include #include #include #include #include #include +#include + +// FIXME: there are core problems with SCAVENGE_PARENT due to the qml engine liking to set parents really late. +// this should instead be handled by proxying all property values until a possible target is ready or definitely not coming. +// The parent should probably be stable in componentComplete() but should be tested. QObject* SCAVENGE_PARENT = nullptr; // NOLINT @@ -44,3 +50,38 @@ QObject* createComponentScavengeable( return instance; } + +void ScavengeableScope::earlyInit(QObject* old) { + auto* oldshell = qobject_cast(old); + + if (oldshell != nullptr) { + this->scavengeableData = std::move(oldshell->mData); + } +} + +QObject* ScavengeableScope::scavengeTargetFor(QObject* /* child */) { + if (this->scavengeableData.length() > this->mData.length()) { + return this->scavengeableData[this->mData.length()]; + } + + return nullptr; +} + +QQmlListProperty ScavengeableScope::data() { + return QQmlListProperty( + this, + nullptr, + &ScavengeableScope::appendComponent, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr + ); +} + +void ScavengeableScope::appendComponent(QQmlListProperty* list, QObject* component) { + auto* self = static_cast(list->object); // NOLINT + component->setParent(self); + self->mData.append(component); +} diff --git a/src/cpp/scavenge.hpp b/src/cpp/scavenge.hpp index 44c3f9c1..6e9e6d0c 100644 --- a/src/cpp/scavenge.hpp +++ b/src/cpp/scavenge.hpp @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include @@ -30,7 +32,7 @@ protected: class Scavengeable { public: - Scavengeable() = default; + explicit Scavengeable() = default; virtual ~Scavengeable() = default; Scavengeable(Scavengeable&) = delete; @@ -47,3 +49,31 @@ QObject* createComponentScavengeable( QQmlComponent& component, QVariantMap& initialProperties ); + +///! Reloader connection scope +/// Attempts to maintain scavengeable connections. +/// This is mostly useful to split a scavengeable component slot (e.g. `Variants`) +/// into multiple slots. +/// +/// If you don't know what that means you probably don't need it. +class ScavengeableScope: public Scavenger, virtual public Scavengeable { + Q_OBJECT; + Q_PROPERTY(QQmlListProperty data READ data); + Q_CLASSINFO("DefaultProperty", "data"); + QML_ELEMENT; + +public: + explicit ScavengeableScope(QObject* parent = nullptr): Scavenger(parent) {} + + void earlyInit(QObject* old) override; + QObject* scavengeTargetFor(QObject* child) override; + + QQmlListProperty data(); + +private: + static void appendComponent(QQmlListProperty* list, QObject* component); + + // track only the children assigned to `data` in order + QList mData; + QList scavengeableData; +}; diff --git a/src/cpp/shell.cpp b/src/cpp/shell.cpp index 5b4f2313..efa281e7 100644 --- a/src/cpp/shell.cpp +++ b/src/cpp/shell.cpp @@ -1,26 +1,7 @@ #include "shell.hpp" -#include -#include -#include #include -void ShellRoot::earlyInit(QObject* old) { - auto* oldshell = qobject_cast(old); - - if (oldshell != nullptr) { - this->scavengeableChildren = std::move(oldshell->children); - } -} - -QObject* ShellRoot::scavengeTargetFor(QObject* /* child */) { - if (this->scavengeableChildren.length() > this->children.length()) { - return this->scavengeableChildren[this->children.length()]; - } - - return nullptr; -} - void ShellRoot::setConfig(ShellConfig config) { this->mConfig = config; @@ -28,22 +9,3 @@ void ShellRoot::setConfig(ShellConfig config) { } ShellConfig ShellRoot::config() const { return this->mConfig; } - -QQmlListProperty ShellRoot::components() { - return QQmlListProperty( - this, - nullptr, - &ShellRoot::appendComponent, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr - ); -} - -void ShellRoot::appendComponent(QQmlListProperty* list, QObject* component) { - auto* shell = static_cast(list->object); // NOLINT - component->setParent(shell); - shell->children.append(component); -} diff --git a/src/cpp/shell.hpp b/src/cpp/shell.hpp index d4c1b5d7..cc2862ce 100644 --- a/src/cpp/shell.hpp +++ b/src/cpp/shell.hpp @@ -2,9 +2,7 @@ #include #include -#include #include -#include #include #include "scavenge.hpp" @@ -18,35 +16,22 @@ public: }; ///! Root config element -class ShellRoot: public Scavenger, virtual public Scavengeable { +class ShellRoot: public ScavengeableScope { Q_OBJECT; /// If `config.watchFiles` is true the configuration will be reloaded whenever it changes. /// Defaults to true. Q_PROPERTY(ShellConfig config READ config WRITE setConfig); - Q_PROPERTY(QQmlListProperty components READ components); - Q_CLASSINFO("DefaultProperty", "components"); QML_ELEMENT; public: - explicit ShellRoot(QObject* parent = nullptr): Scavenger(parent) {} - - void earlyInit(QObject* old) override; - QObject* scavengeTargetFor(QObject* child) override; + explicit ShellRoot(QObject* parent = nullptr): ScavengeableScope(parent) {} void setConfig(ShellConfig config); [[nodiscard]] ShellConfig config() const; - QQmlListProperty components(); - signals: void configChanged(); private: - static void appendComponent(QQmlListProperty* list, QObject* component); - ShellConfig mConfig; - - // track only the children assigned to `components` in order - QList children; - QList scavengeableChildren; };