diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index b12833e59c7..27f8df50b3e 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2969,4 +2969,191 @@ SettingsGroupNester::~SettingsGroupNester() theSettings->endGroup(); } +class AddItemCommand : public QUndoCommand +{ +public: + AddItemCommand(AspectList *aspect, const std::shared_ptr &item) + : m_aspect(aspect) + , m_item(item) + {} + + void undo() override { m_aspect->actualRemoveItem(m_item); } + void redo() override { m_aspect->actualAddItem(m_item); } + +private: + AspectList *m_aspect; + std::shared_ptr m_item; +}; + +class RemoveItemCommand : public QUndoCommand +{ +public: + RemoveItemCommand(AspectList *aspect, const std::shared_ptr &item) + : m_aspect(aspect) + , m_item(item) + {} + + void undo() override { m_aspect->actualAddItem(m_item); } + void redo() override { m_aspect->actualRemoveItem(m_item); } + +private: + AspectList *m_aspect; + std::shared_ptr m_item; +}; + +class Internal::AspectListPrivate +{ +public: + QList> items; + QList> volatileItems; + AspectList::CreateItem createItem; + AspectList::ItemCallback itemAdded; + AspectList::ItemCallback itemRemoved; +}; + +AspectList::AspectList(Utils::AspectContainer *container) + : Utils::BaseAspect(container) + , d(std::make_unique()) +{} + +AspectList::~AspectList() = default; + +void AspectList::fromMap(const Utils::Store &map) +{ + QTC_ASSERT(!settingsKey().isEmpty(), return); + + QVariantList list = map[settingsKey()].toList(); + d->volatileItems.clear(); + for (const QVariant &entry : list) { + auto item = d->createItem(); + item->setAutoApply(isAutoApply()); + item->setUndoStack(undoStack()); + item->fromMap(Utils::storeFromVariant(entry)); + d->volatileItems.append(item); + } + d->items = d->volatileItems; +} + +QVariantList AspectList::toList(bool v) const +{ + QVariantList list; + const auto &items = v ? d->volatileItems : d->items; + + for (const auto &item : items) { + Utils::Store childStore; + if (v) + item->volatileToMap(childStore); + else + item->toMap(childStore); + + list.append(Utils::variantFromStore(childStore)); + } + + return list; +} + +void AspectList::toMap(Utils::Store &map) const +{ + QTC_ASSERT(!settingsKey().isEmpty(), return); + const Utils::Key key = settingsKey(); + map[key] = toList(false); +} + +void AspectList::volatileToMap(Utils::Store &map) const +{ + QTC_ASSERT(!settingsKey().isEmpty(), return); + const Utils::Key key = settingsKey(); + map[key] = toList(true); +} + +std::shared_ptr AspectList::actualAddItem(const std::shared_ptr &item) +{ + item->setAutoApply(isAutoApply()); + item->setUndoStack(undoStack()); + + d->volatileItems.append(item); + if (d->itemAdded) + d->itemAdded(item); + emit volatileValueChanged(); + if (isAutoApply()) + d->items = d->volatileItems; + return item; +} + +QList> AspectList::items() const +{ + return d->items; +} +QList> AspectList::volatileItems() const +{ + return d->volatileItems; +} + +std::shared_ptr AspectList::addItem(std::shared_ptr item) +{ + if (undoStack()) + pushUndo(new AddItemCommand(this, item)); + else + return actualAddItem(item); + + return item; +} + +void AspectList::actualRemoveItem(std::shared_ptr item) +{ + d->volatileItems.removeOne(item); + if (d->itemRemoved) + d->itemRemoved(item); + emit volatileValueChanged(); + if (isAutoApply()) + d->items = d->volatileItems; +} + +void AspectList::removeItem(std::shared_ptr item) +{ + if (undoStack()) + pushUndo(new RemoveItemCommand(this, item)); + else + actualRemoveItem(item); +} + +void AspectList::apply() +{ + d->items = d->volatileItems; + forEachItem([](const std::shared_ptr &aspect) { aspect->apply(); }); + emit changed(); +} + +void AspectList::setCreateItemFunction(CreateItem createItem) +{ + d->createItem = createItem; +} + +void AspectList::setItemAddedCallback(const ItemCallback &callback) +{ + d->itemAdded = callback; +} +void AspectList::setItemRemovedCallback(const ItemCallback &callback) +{ + d->itemRemoved = callback; +} + +qsizetype AspectList::size() const +{ + return d->volatileItems.size(); +} + +bool AspectList::isDirty() +{ + if (d->items != d->volatileItems) + return true; + + for (const auto &item : d->volatileItems) { + if (item->isDirty()) + return true; + } + return false; +} + + } // namespace Utils diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 0ffcaec7cb0..79f7b460847 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -8,8 +8,8 @@ #include "infolabel.h" #include "macroexpander.h" #include "pathchooser.h" -#include "store.h" #include "qtcsettings.h" +#include "store.h" #include #include @@ -46,6 +46,7 @@ class StringAspectPrivate; class StringListAspectPrivate; class TextDisplayPrivate; class CheckableAspectImplementation; +class AspectListPrivate; } // Internal class QTCREATOR_UTILS_EXPORT BaseAspect : public QObject @@ -994,4 +995,76 @@ private: T m_value; }; +class QTCREATOR_UTILS_EXPORT AspectList : public Utils::BaseAspect +{ +public: + using CreateItem = std::function()>; + using ItemCallback = std::function)>; + + AspectList(Utils::AspectContainer *container = nullptr); + ~AspectList() override; + + void fromMap(const Utils::Store &map) override; + void toMap(Utils::Store &map) const override; + + void volatileToMap(Utils::Store &map) const override; + QVariantList toList(bool v) const; + + QList> items() const; + QList> volatileItems() const; + + std::shared_ptr addItem(std::shared_ptr item); + std::shared_ptr actualAddItem(const std::shared_ptr &item); + + void removeItem(std::shared_ptr item); + void actualRemoveItem(std::shared_ptr item); + + void apply() override; + + void setCreateItemFunction(CreateItem createItem); + + template + void forEachItem(std::function &)> callback) + { + for (const auto &item : volatileItems()) + callback(std::static_pointer_cast(item)); + } + + template + void forEachItem(std::function &, int)> callback) + { + int idx = 0; + for (const auto &item : volatileItems()) + callback(std::static_pointer_cast(item), idx++); + } + + void setItemAddedCallback(const ItemCallback &callback); + void setItemRemovedCallback(const ItemCallback &callback); + + template + void setItemAddedCallback(const std::function)> &callback) + { + setItemAddedCallback([callback](const std::shared_ptr &item) { + callback(std::static_pointer_cast(item)); + }); + } + + template + void setItemRemovedCallback(const std::function)> &callback) + { + setItemRemovedCallback([callback](const std::shared_ptr &item) { + callback(std::static_pointer_cast(item)); + }); + } + + qsizetype size() const; + bool isDirty() override; + + QVariant volatileVariantValue() const override { return {}; } + + +private: + std::unique_ptr d; +}; + } // namespace Utils diff --git a/src/plugins/compilerexplorer/compilerexploreraspects.h b/src/plugins/compilerexplorer/compilerexploreraspects.h index 6796d088190..bb1e415f62f 100644 --- a/src/plugins/compilerexplorer/compilerexploreraspects.h +++ b/src/plugins/compilerexplorer/compilerexploreraspects.h @@ -70,138 +70,4 @@ private: QStandardItemModel *m_model{nullptr}; }; -template -class AspectListAspect : public Utils::BaseAspect -{ -public: - using ToBaseAspectPtr = std::function; - using CreateItem = std::function; - using ItemCallback = std::function; - using IsDirty = std::function; - using Apply = std::function; - - AspectListAspect(Utils::AspectContainer *container = nullptr) - : Utils::BaseAspect(container) - {} - - void fromMap(const Utils::Store &map) override - { - QTC_ASSERT(!settingsKey().isEmpty(), return); - - QVariantList list = map[settingsKey()].toList(); - for (const QVariant &entry : list) { - T item = m_createItem(); - m_toBaseAspect(item)->fromMap(Utils::storeFromVariant(entry)); - m_volatileItems.append(item); - } - m_items = m_volatileItems; - } - - QVariantList toList(bool v) const - { - QVariantList list; - const auto &items = v ? m_volatileItems : m_items; - - for (const auto &item : items) { - Utils::Store childMap; - if (v) - m_toBaseAspect(item)->volatileToMap(childMap); - else - m_toBaseAspect(item)->toMap(childMap); - - list.append(Utils::variantFromStore(childMap)); - } - - return list; - } - - void toMap(Utils::Store &map) const override - { - QTC_ASSERT(!settingsKey().isEmpty(), return); - const Utils::Key key = settingsKey(); - map[key] = toList(false); - } - - void volatileToMap(Utils::Store &map) const override - { - QTC_ASSERT(!settingsKey().isEmpty(), return); - const Utils::Key key = settingsKey(); - map[key] = toList(true); - } - - T addItem(T item) - { - m_volatileItems.append(item); - if (m_itemAdded) - m_itemAdded(item); - emit volatileValueChanged(); - if (isAutoApply()) - apply(); - return item; - } - - void removeItem(T item) - { - m_volatileItems.removeOne(item); - if (m_itemRemoved) - m_itemRemoved(item); - emit volatileValueChanged(); - if (isAutoApply()) - apply(); - } - - void apply() override - { - m_items = m_volatileItems; - if (m_apply) - forEachItem(m_apply); - emit changed(); - } - - void setToBaseAspectFunction(ToBaseAspectPtr toBaseAspect) { m_toBaseAspect = toBaseAspect; } - void setCreateItemFunction(CreateItem createItem) { m_createItem = createItem; } - void setIsDirtyFunction(IsDirty isDirty) { m_isDirty = isDirty; } - void setApplyFunction(Apply apply) { m_apply = apply; } - - void forEachItem(std::function callback) - { - for (const auto &item : m_volatileItems) - callback(item); - } - - void forEachItem(std::function callback) - { - int idx = 0; - for (const auto &item : m_volatileItems) - callback(item, idx++); - } - - void setItemAddedCallback(const ItemCallback &callback) { m_itemAdded = callback; } - void setItemRemovedCallback(const ItemCallback &callback) { m_itemRemoved = callback; } - - qsizetype size() { return m_volatileItems.size(); } - bool isDirty() override - { - if (m_isDirty) { - for (const auto &item : m_volatileItems) { - if (m_isDirty(item)) - return true; - } - } - return false; - } - - QVariant volatileVariantValue() const override { return {}; } - -private: - QList m_items; - QList m_volatileItems; - ToBaseAspectPtr m_toBaseAspect; - CreateItem m_createItem; - IsDirty m_isDirty; - Apply m_apply; - ItemCallback m_itemAdded; - ItemCallback m_itemRemoved; -}; - } // namespace CompilerExplorer diff --git a/src/plugins/compilerexplorer/compilerexplorereditor.cpp b/src/plugins/compilerexplorer/compilerexplorereditor.cpp index 992ce65f9be..a037278876e 100644 --- a/src/plugins/compilerexplorer/compilerexplorereditor.cpp +++ b/src/plugins/compilerexplorer/compilerexplorereditor.cpp @@ -515,13 +515,13 @@ EditorWidget::EditorWidget(const QSharedPointer &document, addDockWidget(Qt::LeftDockWidgetArea, dockWidget); - sourceSettings->compilers.forEachItem( + sourceSettings->compilers.forEachItem( [addCompiler, sourceSettings](const std::shared_ptr &compilerSettings, int idx) { addCompiler(sourceSettings, compilerSettings, idx + 1); }); - sourceSettings->compilers.setItemAddedCallback( + sourceSettings->compilers.setItemAddedCallback( [addCompiler, sourceSettings = sourceSettings.get()]( const std::shared_ptr &compilerSettings) { addCompiler(sourceSettings->shared_from_this(), @@ -529,7 +529,7 @@ EditorWidget::EditorWidget(const QSharedPointer &document, sourceSettings->compilers.size()); }); - sourceSettings->compilers.setItemRemovedCallback( + sourceSettings->compilers.setItemRemovedCallback( [this](const std::shared_ptr &compilerSettings) { m_compilerWidgets.removeIf([compilerSettings](const QDockWidget *c) { return static_cast(c->widget())->m_compilerSettings @@ -563,7 +563,7 @@ EditorWidget::EditorWidget(const QSharedPointer &document, m_sourceWidgets.clear(); m_compilerWidgets.clear(); - m_document->settings()->m_sources.forEachItem(addSourceEditor); + m_document->settings()->m_sources.forEachItem(addSourceEditor); QVariantMap windowState = m_document->settings()->windowState.value(); if (!windowState.isEmpty()) { @@ -589,8 +589,8 @@ EditorWidget::EditorWidget(const QSharedPointer &document, } }; - document->settings()->m_sources.setItemAddedCallback(addSourceEditor); - document->settings()->m_sources.setItemRemovedCallback(removeSourceEditor); + document->settings()->m_sources.setItemAddedCallback(addSourceEditor); + document->settings()->m_sources.setItemRemovedCallback(removeSourceEditor); connect(document.get(), &JsonSettingsDocument::settingsChanged, this, recreateEditors); m_context = new Core::IContext(this); diff --git a/src/plugins/compilerexplorer/compilerexplorersettings.cpp b/src/plugins/compilerexplorer/compilerexplorersettings.cpp index 175d2c29825..d80d77aa5ed 100644 --- a/src/plugins/compilerexplorer/compilerexplorersettings.cpp +++ b/src/plugins/compilerexplorer/compilerexplorersettings.cpp @@ -87,14 +87,6 @@ SourceSettings::SourceSettings(const ApiConfigFunction &apiConfigFunction) return result; }); - compilers.setToBaseAspectFunction([](const std::shared_ptr &item) { - return static_cast(item.get()); - }); - compilers.setIsDirtyFunction( - [](const std::shared_ptr &settings) { return settings->isDirty(); }); - compilers.setApplyFunction( - [](const std::shared_ptr &settings) { settings->apply(); }); - for (const auto &aspect : this->aspects()) connect(aspect, &Utils::BaseAspect::volatileValueChanged, @@ -108,7 +100,7 @@ void SourceSettings::refresh() cachedLanguages().clear(); languageId.refill(); - compilers.forEachItem(&CompilerSettings::refresh); + compilers.forEachItem(&CompilerSettings::refresh); } QString SourceSettings::languageExtension() const @@ -328,16 +320,9 @@ CompilerExplorerSettings::CompilerExplorerSettings() &CompilerExplorerSettings::changed); return newSourceSettings; }); - m_sources.setIsDirtyFunction( - [](const std::shared_ptr &settings) { return settings->isDirty(); }); - m_sources.setApplyFunction( - [](const std::shared_ptr &settings) { settings->apply(); }); - m_sources.setToBaseAspectFunction([](const std::shared_ptr &item) { - return static_cast(item.get()); - }); connect(&compilerExplorerUrl, &Utils::StringAspect::volatileValueChanged, this, [this] { - m_sources.forEachItem(&SourceSettings::refresh); + m_sources.forEachItem(&SourceSettings::refresh); }); for (const auto &aspect : this->aspects()) diff --git a/src/plugins/compilerexplorer/compilerexplorersettings.h b/src/plugins/compilerexplorer/compilerexplorersettings.h index 34850009af2..f4f3e2e5b60 100644 --- a/src/plugins/compilerexplorer/compilerexplorersettings.h +++ b/src/plugins/compilerexplorer/compilerexplorersettings.h @@ -34,7 +34,7 @@ public: Utils::StringAspect compilerExplorerUrl{this}; Utils::TypedAspect windowState{this}; - AspectListAspect> m_sources{this}; + Utils::AspectList m_sources{this}; Api::Config apiConfig() const { @@ -61,7 +61,7 @@ public: public: StringSelectionAspect languageId{this}; Utils::StringAspect source{this}; - AspectListAspect> compilers{this}; + Utils::AspectList compilers{this}; public: QString languageExtension() const;