From 3ff90526f5c84b40864fa467d0159cd14ac8baee Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Sat, 22 Apr 2023 01:44:27 +0200 Subject: [PATCH] QmlDesigner: Introduce SkipIterator Instead of having a cache using an iterator skipping entries is much easier because the cache has not to be anymore updated. When we get C++ 20 ranges use them instead. Change-Id: If5b45c53bbd0b12138328862ac152788ffd911b2 Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri Reviewed-by: --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../designercore/model/abstractview.cpp | 6 -- .../qmldesigner/designercore/model/model.cpp | 13 +--- .../qmldesigner/designercore/model/model_p.h | 41 +++++++--- .../designercore/model/skipiterator.h | 77 +++++++++++++++++++ 5 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 src/plugins/qmldesigner/designercore/model/skipiterator.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index b9459aeb1b5..c7989fda36d 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -371,6 +371,7 @@ extend_qtc_library(QmlDesignerCore rewriteactioncompressor.h rewriterview.cpp signalhandlerproperty.cpp + skipiterator.h stylesheetmerger.cpp textmodifier.cpp texttomodelmerger.cpp diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 07692f4a10c..a09db03dacd 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -143,9 +143,6 @@ The default implementation is setting the reference of the model to the view. void AbstractView::modelAttached(Model *model) { setModel(model); - - if (model) - model->d->updateEnabledViews(); } /*! @@ -617,9 +614,6 @@ bool AbstractView::isEnabled() const void AbstractView::setEnabled(bool b) { m_enabled = b; - - if (model()) - model()->d->updateEnabledViews(); } QList AbstractView::allModelNodes() const diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index e630cc96d84..fcdb66b8029 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -96,7 +96,6 @@ void ModelPrivate::detachAllViews() detachView(view.data(), true); m_viewList.clear(); - updateEnabledViews(); if (m_nodeInstanceView) { m_nodeInstanceView->modelAboutToBeDetached(m_model); @@ -299,9 +298,9 @@ void ModelPrivate::removeNodeFromModel(const InternalNodePointer &node) m_internalIdNodeHash.remove(node->internalId); } -const QList> ModelPrivate::enabledViews() const +EnabledViewRange ModelPrivate::enabledViews() const { - return m_enabledViewList; + return EnabledViewRange{m_viewList}; } void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node) @@ -754,7 +753,6 @@ void ModelPrivate::detachView(AbstractView *view, bool notifyView) if (notifyView) view->modelAboutToBeDetached(m_model); m_viewList.removeOne(view); - updateEnabledViews(); } void ModelPrivate::notifyNodeCreated(const InternalNodePointer &newInternalNodePointer) @@ -1317,13 +1315,6 @@ InternalNodePointer ModelPrivate::currentTimelineNode() const return m_currentTimelineNode; } -void ModelPrivate::updateEnabledViews() -{ - m_enabledViewList = Utils::filtered(m_viewList, [](QPointer view) { - return view->isEnabled(); - }); -} - InternalNodePointer ModelPrivate::nodeForId(const QString &id) const { return m_idNodeHash.value(id); diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index d1678192804..ce2a49fc42d 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -3,17 +3,20 @@ #pragma once +#include "qmldesignercorelib_global.h" + +#include "abstractview.h" +#include "metainfo.h" +#include "modelnode.h" +#include "skipiterator.h" + #include #include #include #include #include -#include "modelnode.h" -#include "abstractview.h" -#include "metainfo.h" - -#include "qmldesignercorelib_global.h" +#include QT_BEGIN_NAMESPACE class QPlainTextEdit; @@ -64,7 +67,28 @@ private: QPointer m_model; }; -class ModelPrivate : public QObject { +struct Increment +{ + using iterator = QList>::const_iterator; + auto operator()(iterator current) { + return std::find_if(std::next(current), + end, + [] (iterator::reference &view) { return view && view->isEnabled(); }); + } + + iterator end; +}; + +class EnabledViewRange : public SkipRange>, Increment> +{ +public: + EnabledViewRange(const container &views) + : base{views, Increment{views.end()}} + {} +}; + +class ModelPrivate : public QObject +{ Q_OBJECT friend Model; @@ -249,8 +273,6 @@ public: InternalNodePointer currentStateNode() const; InternalNodePointer currentTimelineNode() const; - void updateEnabledViews(); - private: void removePropertyWithoutNotification(const InternalPropertyPointer &property); void removeAllSubNodes(const InternalNodePointer &node); @@ -259,7 +281,7 @@ private: QList toModelNodeList(const QList &nodeList, AbstractView *view) const; QVector toModelNodeVector(const QVector &nodeVector, AbstractView *view) const; QVector toInternalNodeVector(const QVector &modelNodeVector) const; - const QList> enabledViews() const; + EnabledViewRange enabledViews() const; public: NotNullPointer projectStorage = nullptr; @@ -271,7 +293,6 @@ private: Imports m_possibleImportList; Imports m_usedImportList; QList> m_viewList; - QList> m_enabledViewList; QList m_selectedInternalNodeList; QHash m_idNodeHash; QHash m_internalIdNodeHash; diff --git a/src/plugins/qmldesigner/designercore/model/skipiterator.h b/src/plugins/qmldesigner/designercore/model/skipiterator.h new file mode 100644 index 00000000000..11efb7d97f0 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/model/skipiterator.h @@ -0,0 +1,77 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace QmlDesigner { + +template +class SkipIterator +{ +public: + using iterator_category = std::forward_iterator_tag; + using difference_type = qsizetype; + using value_type = typename BaseIterator::value_type; + using pointer = typename BaseIterator::pointer; + using reference = typename BaseIterator::reference; + + SkipIterator() = default; + SkipIterator(BaseIterator current, Increment increment) + : m_current{current} + , m_increment{std::move(increment)} + {} + + SkipIterator operator++() + { + m_current = m_increment(m_current); + return *this; + } + + SkipIterator operator++(int) + { + auto tmp = *this; + m_current = m_increment(m_current); + return tmp; + } + + reference operator*() const { return *m_current; } + pointer operator->() const { return m_current.operator->(); } + + friend bool operator==(const SkipIterator &first, const SkipIterator &second) + { + return first.m_current == second.m_current; + } + + friend bool operator!=(const SkipIterator &first, const SkipIterator &second) + { + return first.m_current != second.m_current; + } + +private: + BaseIterator m_current = {}; + Increment m_increment; +}; + +template +class SkipRange +{ +public: + using container = Container; + using base = SkipRange; + using iterator = SkipIterator; + + SkipRange(const Container &container, Increment increment) + : m_begin{container.begin(), increment} + , m_end{container.end(), increment} + {} + + iterator begin() const { return m_begin; } + iterator end() const { return m_end; } + +private: + iterator m_begin; + iterator m_end; +}; +} // namespace QmlDesigner