diff options
author | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2021-09-09 16:50:45 +0300 |
---|---|---|
committer | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2021-10-28 12:40:02 +0300 |
commit | 3ad787d0dd580a8cfb37f4e56b55f1889e24727b (patch) | |
tree | 39cf797e89b96e0c119c55ca0d2196416f853975 /src/libs/installer/componentselectionpage_p.cpp | |
parent | f64011e117e759754f7b4f2885f9bf335a6596ff (diff) |
Add possibility to search for components in ComponentSelectionPage
Introduce ComponentSortFilterProxyModel, that compared to its base
class QSortFilterProxyModel, accepts also child indexes of a source
model index which is directly accepted by the filter.
Also remove emitting of QAbstractItemModel::dataChanged() for each
item in the ComponentModel, which was done regardless of if data at
index was changed or not, after reset or when check state or data for
any item was changed. If the ComponentModel acts as a source model
for a proxy model with 'dynamicSortFilter' property set to true, the
extra emits hurt the performance as the model gets filtered again for
each source model change. Actual changes done to the ComponentModel
are still notified.
Task-number: QTIFW-1404
Change-Id: Iea696f8b9abf79d877fb2568488b09dc3cb061be
Reviewed-by: Katja Marttila <katja.marttila@qt.io>
Diffstat (limited to 'src/libs/installer/componentselectionpage_p.cpp')
-rw-r--r-- | src/libs/installer/componentselectionpage_p.cpp | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp index a180888d1..7717f4cf3 100644 --- a/src/libs/installer/componentselectionpage_p.cpp +++ b/src/libs/installer/componentselectionpage_p.cpp @@ -50,6 +50,7 @@ #include <QStackedLayout> #include <QStackedWidget> #include <QToolBox> +#include <QLineEdit> namespace QInstaller { @@ -71,8 +72,11 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP , m_descriptionBaseWidget(nullptr) , m_categoryWidget(Q_NULLPTR) , m_categoryLayoutVisible(false) + , m_proxyModel(new ComponentSortFilterProxyModel(q)) { m_treeView->setObjectName(QLatin1String("ComponentsTreeView")); + m_proxyModel->setRecursiveFilteringEnabled(true); + m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_descriptionBaseWidget = new QWidget(q); m_descriptionBaseWidget->setObjectName(QLatin1String("DescriptionBaseWidget")); @@ -155,9 +159,18 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP metaLayout->addWidget(m_progressBar); metaLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding)); + m_searchLineEdit = new QLineEdit(q); + m_searchLineEdit->setObjectName(QLatin1String("SearchLineEdit")); + m_searchLineEdit->setPlaceholderText(ComponentSelectionPage::tr("Search")); + m_searchLineEdit->setClearButtonEnabled(true); + connect(m_searchLineEdit, &QLineEdit::textChanged, + this, &ComponentSelectionPagePrivate::setSearchPattern); + connect(q, &ComponentSelectionPage::entered, m_searchLineEdit, &QLineEdit::clear); + QVBoxLayout *treeViewVLayout = new QVBoxLayout; treeViewVLayout->setObjectName(QLatin1String("TreeviewLayout")); treeViewVLayout->addWidget(m_treeView, 3); + treeViewVLayout->addWidget(m_searchLineEdit); QWidget *mainStackedWidget = new QWidget(); m_mainGLayout = new QGridLayout(mainStackedWidget); @@ -292,15 +305,11 @@ void ComponentSelectionPagePrivate::updateTreeView() this, &ComponentSelectionPagePrivate::currentSelectedChanged); } + m_searchLineEdit->setVisible(!m_core->isUpdater()); m_currentModel = m_core->isUpdater() ? m_updaterModel : m_allModel; - m_treeView->setModel(m_currentModel); - m_treeView->setExpanded(m_currentModel->index(0, 0), true); - foreach (Component *component, m_core->components(PackageManagerCore::ComponentType::All)) { - if (component->isExpandedByDefault()) { - const QModelIndex index = m_currentModel->indexFromComponentName(component->treeName()); - m_treeView->setExpanded(index, true); - } - } + m_proxyModel->setSourceModel(m_currentModel); + m_treeView->setModel(m_proxyModel); + expandDefault(); const bool installActionColumnVisible = m_core->settings().installActionColumnVisible(); if (!installActionColumnVisible) @@ -341,7 +350,44 @@ void ComponentSelectionPagePrivate::updateTreeView() connect(m_treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ComponentSelectionPagePrivate::currentSelectedChanged); - m_treeView->setCurrentIndex(m_currentModel->index(0, 0)); + m_treeView->setCurrentIndex(m_proxyModel->index(0, 0)); +} + +/*! + Expands components that should be expanded by default. +*/ +void ComponentSelectionPagePrivate::expandDefault() +{ + m_treeView->setExpanded(m_proxyModel->index(0, 0), true); + foreach (auto *component, m_core->components(PackageManagerCore::ComponentType::All)) { + if (component->isExpandedByDefault()) { + const QModelIndex index = m_proxyModel->mapFromSource( + m_currentModel->indexFromComponentName(component->treeName())); + m_treeView->setExpanded(index, true); + } + } +} + +/*! + Expands components that were accepted by proxy models filter. +*/ +void ComponentSelectionPagePrivate::expandSearchResults() +{ + // Expand parents of root indexes accepted by filter + const QVector<QModelIndex> acceptedIndexes = m_proxyModel->directlyAcceptedIndexes(); + for (auto proxyModelIndex : acceptedIndexes) { + if (!proxyModelIndex.isValid()) + continue; + + QModelIndex index = proxyModelIndex.parent(); + while (index.isValid()) { + if (m_treeView->isExpanded(index)) + break; // Multiple direct matches in a branch, can be skipped + + m_treeView->expand(index); + index = index.parent(); + } + } } void ComponentSelectionPagePrivate::currentSelectedChanged(const QModelIndex ¤t) @@ -351,12 +397,12 @@ void ComponentSelectionPagePrivate::currentSelectedChanged(const QModelIndex &cu m_sizeLabel->setText(QString()); - QString description = m_currentModel->data(m_currentModel->index(current.row(), + QString description = m_proxyModel->data(m_proxyModel->index(current.row(), ComponentModelHelper::NameColumn, current.parent()), Qt::ToolTipRole).toString(); m_descriptionLabel->setText(description); - Component *component = m_currentModel->componentFromIndex(current); + Component *component = m_currentModel->componentFromIndex(m_proxyModel->mapToSource(current)); if ((m_core->isUninstaller()) || (!component)) return; @@ -429,6 +475,7 @@ void ComponentSelectionPagePrivate::fetchRepositoryCategories() QLatin1String("FailToFetchPackages"), tr("Error"), m_core->error()); } updateWidgetVisibility(false); + m_searchLineEdit->text().isEmpty() ? expandDefault() : expandSearchResults(); } void ComponentSelectionPagePrivate::customButtonClicked(int which) @@ -507,4 +554,26 @@ void ComponentSelectionPagePrivate::onModelStateChanged(QInstaller::ComponentMod currentSelectedChanged(m_treeView->selectionModel()->currentIndex()); } +/*! + Sets the new filter pattern to \a text and expands the tree nodes. +*/ +void ComponentSelectionPagePrivate::setSearchPattern(const QString &text) +{ + m_proxyModel->setFilterWildcard(text); + + m_treeView->collapseAll(); + if (text.isEmpty()) { + // Expand user selection and default expanded, ensure selected is visible + QModelIndex index = m_treeView->selectionModel()->currentIndex(); + while (index.isValid()) { + m_treeView->expand(index); + index = index.parent(); + } + expandDefault(); + m_treeView->scrollTo(m_treeView->selectionModel()->currentIndex()); + } else { + expandSearchResults(); + } +} + } // namespace QInstaller |