From f58add023aedcfa2b9011af512b082285eb78dfe Mon Sep 17 00:00:00 2001 From: Tapani Mattila Date: Tue, 22 Mar 2022 16:45:43 +0200 Subject: [PATCH] Navigator: Add search/filter to navigator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QDS-6063 Change-Id: I922a04a46f673befe8811a62342cf2cdd9c61583 Reviewed-by: Reviewed-by: Henning Gründl Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../navigator/navigatormodelinterface.h | 1 + .../navigator/navigatorsearchwidget.cpp | 66 +++++++++++++++++++ .../navigator/navigatorsearchwidget.h | 49 ++++++++++++++ .../navigator/navigatortreemodel.cpp | 44 ++++++++++++- .../components/navigator/navigatortreemodel.h | 3 + .../components/navigator/navigatorview.cpp | 10 +++ .../components/navigator/navigatorview.h | 2 + .../components/navigator/navigatorwidget.cpp | 10 +++ .../components/navigator/navigatorwidget.h | 5 ++ src/plugins/qmldesigner/qmldesignerplugin.qbs | 2 + 11 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp create mode 100644 src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index bee619026ad..2a2c2314ba8 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -276,6 +276,7 @@ extend_qtc_plugin(QmlDesigner nameitemdelegate.cpp nameitemdelegate.h navigator.qrc navigatormodelinterface.h + navigatorsearchwidget.cpp navigatorsearchwidget.h navigatortreemodel.cpp navigatortreemodel.h navigatortreeview.cpp navigatortreeview.h navigatorview.cpp navigatorview.h diff --git a/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h b/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h index 8c914b50e45..52bfcfe6130 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h +++ b/src/plugins/qmldesigner/components/navigator/navigatormodelinterface.h @@ -45,6 +45,7 @@ public: virtual void notifyModelNodesMoved(const QList &modelNodes) = 0; virtual void notifyIconsChanged() = 0; virtual void setFilter(bool showObjects) = 0; + virtual void setNameFilter(const QString &filter) = 0; virtual void setOrder(bool reverse) = 0; virtual void resetModel() = 0; }; diff --git a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp new file mode 100644 index 00000000000..77199017c14 --- /dev/null +++ b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "navigatorsearchwidget.h" + +#include +#include + +#include +#include +#include + +namespace QmlDesigner { + +NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent) + : QWidget(parent) +{ + auto layout = new QBoxLayout(QBoxLayout::LeftToRight); + setLayout(layout); + + const QString fontName = "qtds_propertyIconFont.ttf"; + const int iconSize = 15; + const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::IconsBaseColor)); + const QIcon searchIcon = Utils::StyleHelper::getIconFromIconFont( + fontName, QmlDesigner::Theme::getIconUnicode(QmlDesigner::Theme::Icon::search), + iconSize, iconSize, iconColor); + + m_textField = new QLineEdit; + m_textField->setPlaceholderText(tr("Filter")); + m_textField->setFrame(false); + m_textField->setClearButtonEnabled(true); + m_textField->addAction(searchIcon, QLineEdit::LeadingPosition); + + connect(m_textField, &QLineEdit::textChanged, this, &NavigatorSearchWidget::textChanged); + + layout->addWidget(m_textField); +} + +void NavigatorSearchWidget::clear() +{ + m_textField->clear(); +} + +} // QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h new file mode 100644 index 00000000000..d1c4e0269b6 --- /dev/null +++ b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace QmlDesigner { + +class NavigatorSearchWidget : public QWidget +{ + Q_OBJECT + +public: + NavigatorSearchWidget(QWidget *parent = nullptr); + + void clear(); + +signals: + void textChanged(const QString &text); + +private: + + QLineEdit *m_textField; +}; + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 735df196afb..5f4ae027441 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -324,14 +324,25 @@ QList NavigatorTreeModel::filteredList(const NodeListProperty &proper return it.value(); QList list; + QList propertyNodes = property.toModelNodeList(); + QList nameFilteredList; + + if (m_nameFilter.isEmpty()) { + nameFilteredList = propertyNodes; + } else { + nameFilteredList.append(Utils::filtered(propertyNodes, [&] (const ModelNode &arg){ + const bool value = m_nameFilteredList.contains(arg); + return value; + })); + } if (filter) { - list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { + list.append(Utils::filtered(nameFilteredList, [] (const ModelNode &arg) { const bool value = QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); return value; })); } else { - list = property.toModelNodeList(); + list = nameFilteredList; } appendForcedNodes(property, list); @@ -1222,6 +1233,35 @@ void NavigatorTreeModel::setFilter(bool showOnlyVisibleItems) resetModel(); } +void NavigatorTreeModel::setNameFilter(const QString &filter) +{ + m_nameFilter = filter; + m_rowCache.clear(); + + ModelNode rootNode = m_view->rootModelNode(); + QList allNodes = rootNode.allSubModelNodes(); + m_nameFilteredList.clear(); + + if (filter.isEmpty()) { + m_nameFilteredList = allNodes; + } else { + for (ModelNode &node : rootNode.allSubModelNodes()) { + if (node.displayName().contains(filter, Qt::CaseSensitivity::CaseInsensitive)) { + m_nameFilteredList.append(node); + ModelNode n = node; + while (n.hasParentProperty()) { + n = n.parentProperty().parentModelNode(); + if (n.isRootNode() || m_nameFilteredList.contains(n)) + break; + m_nameFilteredList.append(n); + } + } + } + } + + resetModel(); +} + void NavigatorTreeModel::setOrder(bool reverseItemOrder) { m_reverseItemOrder = reverseItemOrder; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index c7b3f9b75f1..96529816076 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -101,6 +101,7 @@ public: void notifyModelNodesMoved(const QList &modelNodes) override; void notifyIconsChanged() override; void setFilter(bool showOnlyVisibleItems) override; + void setNameFilter(const QString &filter) override; void setOrder(bool reverseItemOrder) override; void resetModel() override; @@ -140,6 +141,8 @@ private: bool m_showOnlyVisibleItems = true; bool m_reverseItemOrder = false; DesignerActionManager *m_actionManager = nullptr; + QString m_nameFilter; + QList m_nameFilteredList; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index b1b12da2e0c..d9d713b5eb0 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -152,6 +152,8 @@ void NavigatorView::modelAttached(Model *model) treeView->setIndentation(20); m_currentModelInterface->setFilter(false); + m_currentModelInterface->setNameFilter(""); + m_widget->clearSearch(); QTimer::singleShot(0, this, [this, treeView]() { m_currentModelInterface->setFilter( @@ -576,6 +578,12 @@ void NavigatorView::reverseOrderToggled(bool flag) DesignerSettings::setValue(DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, flag); } +void NavigatorView::textFilterChanged(const QString &text) +{ + m_treeModel->setNameFilter(text); + treeWidget()->expandAll(); +} + void NavigatorView::changeSelection(const QItemSelection & /*newSelection*/, const QItemSelection &/*deselected*/) { if (m_blockSelectionChangedSignal) @@ -704,6 +712,8 @@ void NavigatorView::setupWidget() connect(m_widget.data(), &NavigatorWidget::filterToggled, this, &NavigatorView::filterToggled); connect(m_widget.data(), &NavigatorWidget::reverseOrderToggled, this, &NavigatorView::reverseOrderToggled); + connect(m_widget.data(), &NavigatorWidget::textFilterChanged, this, &NavigatorView::textFilterChanged); + #ifndef QMLDESIGNER_TEST const QString fontName = "qtds_propertyIconFont.ttf"; const QSize size = QSize(28, 28); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h index c779522baa7..a8a87c00828 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h @@ -118,6 +118,8 @@ private: void filterToggled(bool); void reverseOrderToggled(bool); + void textFilterChanged(const QString &text); + protected: //functions QTreeView *treeWidget() const; NavigatorTreeModel *treeModel(); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp index 00cd4758885..4929c75bd91 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "navigatorsearchwidget.h" #include "navigatorwidget.h" #include "navigatorview.h" @@ -160,6 +161,10 @@ QToolBar *NavigatorWidget::createToolBar() for (auto toolButton : buttons) toolBar->addWidget(toolButton); + m_searchWidget = new NavigatorSearchWidget(); + connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged); + toolBar->addWidget(m_searchWidget); + return toolBar; } @@ -211,4 +216,9 @@ QByteArray NavigatorWidget::dragType() const return m_dragType; } +void NavigatorWidget::clearSearch() +{ + m_searchWidget->clear(); +} + } diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.h b/src/plugins/qmldesigner/components/navigator/navigatorwidget.h index 785c3978f30..adbd5085dfd 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.h @@ -39,6 +39,7 @@ QT_FORWARD_DECLARE_CLASS(QAbstractItemModel) namespace QmlDesigner { class NavigatorView; +class NavigatorSearchWidget; class NavigatorWidget: public QFrame { @@ -59,6 +60,8 @@ public: void setDragType(const QByteArray &type); QByteArray dragType() const; + void clearSearch(); + signals: void leftButtonClicked(); void rightButtonClicked(); @@ -66,6 +69,7 @@ signals: void downButtonClicked(); void filterToggled(bool); void reverseOrderToggled(bool); + void textFilterChanged(const QString &name); protected: void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override; @@ -77,6 +81,7 @@ private: NavigatorTreeView *m_treeView; QPointer m_navigatorView; QByteArray m_dragType; + NavigatorSearchWidget *m_searchWidget; }; } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 09690f9d2f4..a0427d37809 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -680,6 +680,8 @@ Project { "navigator/nameitemdelegate.cpp", "navigator/nameitemdelegate.h", "navigator/navigator.qrc", + "navigator/navigatorsearchwidget.cpp", + "navigator/navigatorsearchwidget.h", "navigator/navigatortreemodel.cpp", "navigator/navigatortreemodel.h", "navigator/navigatortreeview.cpp",