From 69f2e061342e9d1cc3ed8db963cfb6809b62800c Mon Sep 17 00:00:00 2001 From: alexmontAmazon <85521892+alexmontAmazon@users.noreply.github.com> Date: Tue, 29 Jun 2021 17:31:27 -0700 Subject: [PATCH] rewrite of the filter code to fix [LYN-4156][LYN-4545] (#1640) * rewrite of the filter code to fix [LYN-4156][LYN-4545] Signed-off-by: Alex Montgomery * improved onRowCountChanged() per comments Signed-off-by: Alex Montgomery --- .../Components/FilteredSearchWidget.cpp | 275 +++++++++--------- .../Components/FilteredSearchWidget.h | 44 ++- .../Components/Widgets/ColorPicker.cpp | 4 +- .../Outliner/EntityOutlinerSearchWidget.cpp | 23 +- .../UI/Outliner/EntityOutlinerSearchWidget.h | 4 +- .../UI/Outliner/OutlinerSearchWidget.cpp | 24 +- .../UI/Outliner/OutlinerSearchWidget.h | 4 +- 7 files changed, 217 insertions(+), 161 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp index 5ba223dec4..6298654414 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.cpp @@ -140,7 +140,6 @@ namespace AzQtComponents SearchTypeSelector::SearchTypeSelector(QWidget* parent /* = nullptr */) : QMenu(parent) - , m_unfilteredData(nullptr) { Q_ASSERT(parent != nullptr); @@ -201,7 +200,17 @@ namespace AzQtComponents itemLayout->addWidget(m_tree); m_model = new QStandardItemModel(this); - m_tree->setModel(m_model); + m_filterModel = new SearchTypeSelectorFilterModel(this); + m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_filterModel->setRecursiveFilteringEnabled(true); + m_filterModel->setSourceModel(m_model); + + // make sure all entries enter the view expanded + connect(m_filterModel, &QAbstractItemModel::rowsInserted, this, [this]() + { + m_tree->expandAll(); + }); + m_tree->setModel(m_filterModel); m_tree->setHeaderHidden(true); connect(m_model, &QStandardItemModel::itemChanged, this, [this](QStandardItem* item) @@ -210,11 +219,6 @@ namespace AzQtComponents if (!m_settingUp) { int index = item->data().toInt(); - if (index < m_filteredItemIndices.size()) - { - index = m_filteredItemIndices[item->data().toInt()]; - } - bool enabled = item->checkState() == Qt::Checked; emit TypeToggled(index, enabled); } @@ -233,169 +237,116 @@ namespace AzQtComponents QMenu::showEvent(e); } - void SearchTypeSelector::resetData() - { - m_estimatedTableHeight = 0; - m_estimatedTableWidth = 0; - - m_filteredItemIndices.clear(); - m_model->clear(); - } - void SearchTypeSelector::initItem(QStandardItem* item, const SearchTypeFilter& filter, int unfilteredDataIndex) { Q_UNUSED(filter); - Q_UNUSED(unfilteredDataIndex); + item->setData(unfilteredDataIndex); + item->setEditable(false); item->setCheckable(true); item->setCheckState(filter.enabled ? Qt::Checked : Qt::Unchecked); } - bool SearchTypeSelector::filterItemOut(int unfilteredDataIndex, bool itemMatchesFilter, bool categoryMatchesFilter) + int SearchTypeSelector::getUnfilteredDataIndex(QStandardItem* item) { - Q_UNUSED(unfilteredDataIndex); - - return !itemMatchesFilter && !categoryMatchesFilter; + const QVariant itemData = item->data(); + if (itemData.isValid()) + { + return item->data().toInt(); + } + return -1; } - void SearchTypeSelector::RepopulateDataModel() + void SearchTypeSelector::RepopulateDataModel(const SearchTypeFilterList& unfilteredData) { - resetData(); - - if (!m_unfilteredData) - { - return; - } - - bool amFiltering = !m_filterString.isEmpty(); + m_estimatedTableHeight = 0; + m_estimatedTableWidth = 0; + m_model->clear(); + m_filterModel->setNoResultsMessageRow(-1); // reset the index for the "no results" message QScopedValueRollback setupGuard(m_settingUp, true); - QMap categories; - QStandardItem* firstCategory = nullptr; - QStandardItem* firstItem = nullptr; - int numCategories = 0; - int numItems = 0; - int numItemsAdded = 0; + QVector categoriesInOrder; // categories in originally specified order + QMap> categoryToEntryItems; // category name to sub-items that will be added + - for (int unfilteredDataIndex = 0, length = m_unfilteredData->length(); unfilteredDataIndex < length; ++unfilteredDataIndex) + const int numItems = unfilteredData.length(); + for (int unfilteredDataIndex = 0; unfilteredDataIndex < numItems; ++unfilteredDataIndex) { - const SearchTypeFilter& filter = m_unfilteredData->at(unfilteredDataIndex); - bool addItem = true; - - bool itemMatchesFilter = true; - bool categoryMatchesFilter = true; - - if (amFiltering) - { - itemMatchesFilter = filter.displayName.contains(m_filterString, Qt::CaseSensitivity::CaseInsensitive); - categoryMatchesFilter = filter.category.contains(m_filterString, Qt::CaseSensitivity::CaseInsensitive); - } - - if (filterItemOut(unfilteredDataIndex, itemMatchesFilter, categoryMatchesFilter)) - { - addItem = false; - } - - QStandardItem* categoryItem = nullptr; - if (categories.contains(filter.category)) - { - categoryItem = categories[filter.category]; - } - else - { - if (categoryMatchesFilter || addItem) - { - categoryItem = new QStandardItem(filter.category); - categories[filter.category] = categoryItem; - m_model->appendRow(categoryItem); - categoryItem->setEditable(false); - - numCategories++; - if (!firstCategory) - { - firstCategory = firstCategory ? firstCategory : categoryItem; - } - } - } - - // count the item even if we filter it out, so that the estimated height includes what it could be if the filter changes - numItems++; - - if (!addItem) - { - continue; - } - - numItemsAdded++; - - m_filteredItemIndices.append(unfilteredDataIndex); + const SearchTypeFilter& filter = unfilteredData.at(unfilteredDataIndex); + // create each item, but don't add them yet, as we don't know if we will be adding to the category items, + // or to the model directly QStandardItem* item = new QStandardItem(filter.displayName); - item->setData(unfilteredDataIndex); - item->setEditable(false); - initItem(item, filter, unfilteredDataIndex); - - if (categoryItem) + categoryToEntryItems[filter.category].push_back(item); + + if (categoriesInOrder.indexOf(filter.category) == -1) { - categoryItem->appendRow(item); - } - else - { - m_model->appendRow(item); + // need to add these category items as they are first encountered so + // that the original category ordering is maintained + categoriesInOrder.push_back(filter.category); } int textWidth = fontMetrics().horizontalAdvance(filter.displayName); if (textWidth > m_estimatedTableWidth) { - m_estimatedTableWidth = textWidth; + m_estimatedTableWidth = textWidth; } + } + const int numCategories = categoriesInOrder.size(); - if (!firstItem) + // If there is only one category and its name is empty, discard it, + // and add its children directly to the model as one big column of N rows + if (numCategories == 1 && categoriesInOrder[0].isEmpty()) + { + auto& entryItems = categoryToEntryItems.begin().value(); + m_model->appendColumn(entryItems); + } + else + { + for (int categoryIndex = 0; categoryIndex < numCategories; ++categoryIndex) { - firstItem = item; + const QString& currCategory = categoriesInOrder[categoryIndex]; + QStandardItem* categoryItem = new QStandardItem(currCategory); + auto& entryItems = categoryToEntryItems[currCategory]; + + categoryItem->appendColumn(entryItems); + m_model->appendRow(categoryItem); // add the parent last, so the model just gets one row add per category } } - if (numItemsAdded == GetNumFixedItems()) - { - QStandardItem* item = new QStandardItem(QObject::tr("No result found.")); - m_model->appendRow(item); - item->setEditable(false); - ++numItems; - } + // add a special row that indicates that no categories (other than the fixed ones) match the filter + // this row itself will be filtered out when there are other matching categories + m_filterModel->setNoResultsMessageRow(m_model->rowCount()); + QStandardItem* noResultsMessage = new QStandardItem(QObject::tr("No result found.")); + noResultsMessage->setEditable(false); + m_model->appendRow(new QStandardItem(QObject::tr("No result found."))); - // If there is only one category and its name is empty, let put everything at root. - if (categories.count() == 1 && categories.begin().key().isEmpty()) - { - m_tree->setRootIndex(categories.begin().value()->index()); - - numCategories = 0; - } - - estimateTableHeight(firstCategory, numCategories, firstItem, numItems); + estimateTableHeight(numCategories, numItems); } - void SearchTypeSelector::estimateTableHeight(QStandardItem* firstCategory, int numCategories, QStandardItem* firstItem, int numItems) + void SearchTypeSelector::estimateTableHeight(int numCategories, int numItems) { m_tree->expandAll(); int totalCategoryHeight = 0; int totalItemHeight = 0; - if (firstItem) + auto* theModel = m_tree->model(); + QModelIndex firstIndex(theModel->index(0, 0)); + QModelIndex firstChild(theModel->index(0, 0, firstIndex)); + + if (firstIndex.isValid()) { - QModelIndex index = m_model->indexFromItem(firstItem); - int itemHeight = m_tree->fetchRowHeight(index); + int itemHeight = m_tree->fetchRowHeight(firstIndex); totalItemHeight += (itemHeight * numItems); } - if (firstCategory) + if (firstChild.isValid()) { - QModelIndex index = m_model->indexFromItem(firstCategory); - int categoryHeight = m_tree->fetchRowHeight(index); + int categoryHeight = m_tree->fetchRowHeight(firstChild); totalCategoryHeight += (categoryHeight * numCategories); } @@ -509,10 +460,7 @@ namespace AzQtComponents void SearchTypeSelector::Setup(const SearchTypeFilterList& searchTypes) { - m_unfilteredData = &searchTypes; - - RepopulateDataModel(); - + RepopulateDataModel(searchTypes); setFixedWidth(m_estimatedTableWidth + FilterWindowWidthPadding); } @@ -583,8 +531,75 @@ namespace AzQtComponents void SearchTypeSelector::FilterTextChanged(const QString& newFilter) { m_filterString = newFilter; + m_filterModel->setFilterWildcard(m_filterString); + } - RepopulateDataModel(); + SearchTypeSelectorFilterModel::SearchTypeSelectorFilterModel(SearchTypeSelector* searchTypeSelector) + : QSortFilterProxyModel(searchTypeSelector), m_searchTypeSelector(searchTypeSelector) + { + // use queued connections so that the normal sort/filter operations get a chance to finish the index remapping before we act + connect(this, &QAbstractItemModel::rowsInserted, this, &SearchTypeSelectorFilterModel::onRowCountChanged, Qt::QueuedConnection); + connect(this, &QAbstractItemModel::rowsRemoved, this, &SearchTypeSelectorFilterModel::onRowCountChanged, Qt::QueuedConnection); + } + + void SearchTypeSelectorFilterModel::setNoResultsMessageRow(int row) + { + m_noResultsRow = row; + invalidateFilter(); + } + + + void SearchTypeSelectorFilterModel::onRowCountChanged() + { + // see if we need to hide or show the "no results" message item + const int numLeafNodes = getNumLeafNodes(); + + // check if we're down to the (never filtered) fixed items, and should show the "no results" message, + // or if we were already showing that message, check if we have more than the fixed items plus the message itself + const bool hasResultsChanged = (m_showingNoResultsMessage ? numLeafNodes > m_searchTypeSelector->GetNumFixedItems() + 1 + : numLeafNodes <= m_searchTypeSelector->GetNumFixedItems()); + + if (hasResultsChanged) + { + m_showingNoResultsMessage = !m_showingNoResultsMessage; + QModelIndex noResultsMessageIndex = sourceModel()->index(m_noResultsRow, 0); + + // The no results row is in the source model, so trigger dataChanged to allow us to re-filter it + emit sourceModel()->dataChanged(noResultsMessageIndex, noResultsMessageIndex); + } + } + + bool SearchTypeSelectorFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const + { + // if we're considering the "no results" item, accept it only if we're m_showingNoResultsMessage + if (!source_parent.isValid() && source_row == m_noResultsRow) + { + return m_showingNoResultsMessage; + } + + const bool filteredByBase = ! QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); + + // allow searchTypeSelector to make the final decision whether to filter out this item + return !(m_searchTypeSelector->filterItemOut(m_searchTypeSelector->m_model->index(source_row, 0, source_parent), filteredByBase)); + } + + int SearchTypeSelectorFilterModel::getNumLeafNodes(const QModelIndex& theIndex) + { + // count the number of leaf nodes descending from this index, not including itself + int numLeafNodes = 0; + for (int childRow = 0, numChildRows = rowCount(theIndex); childRow < numChildRows; ++childRow) + { + QModelIndex childIndex = index(childRow, 0, theIndex); + if (rowCount(childIndex) == 0) + { + ++numLeafNodes; + } + else + { + numLeafNodes += getNumLeafNodes(childIndex); + } + } + return numLeafNodes; } FilteredSearchWidget::Config FilteredSearchWidget::loadConfig(QSettings& settings) @@ -934,7 +949,7 @@ namespace AzQtComponents { { QSignalBlocker blocker(this); - ConfigHelpers::GroupGuard(&settings, widgetName); + ConfigHelpers::GroupGuard guard(&settings, widgetName); const auto textFilter = settings.value(g_textFilterKey); if (textFilter.isValid()) { @@ -958,7 +973,7 @@ namespace AzQtComponents void FilteredSearchWidget::writeSettings(QSettings& settings, const QString& widgetName) { - ConfigHelpers::GroupGuard(&settings, widgetName); + ConfigHelpers::GroupGuard guard(&settings, widgetName); settings.setValue(g_textFilterKey, textFilter()); const int size = m_typeFilters.size(); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.h index f5fd9f4834..6257ee8448 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/FilteredSearchWidget.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #endif @@ -33,9 +35,7 @@ namespace Ui class FlowLayout; class QTreeView; -class QSortFilterProxyModel; class QStandardItemModel; -class QStandardItem; class QSettings; class QLineEdit; class QToolButton; @@ -48,6 +48,7 @@ namespace AzQtComponents { class Style; class FilteredSearchItemDelegate; + class SearchTypeSelectorFilterModel; class AZ_QT_COMPONENTS_API FilterCriteriaButton : public QFrame @@ -165,28 +166,27 @@ namespace AzQtComponents void FilterTextChanged(const QString& newFilter); protected: - void estimateTableHeight(QStandardItem* firstCategory, int numCategories, QStandardItem* firstItem, int numItems); - void resetData(); + void estimateTableHeight(int numCategories, int numItems); - // can be used to override the logic when adding items in RepopulateDataModel - virtual bool filterItemOut(int index, bool itemMatchesFilter, bool categoryMatchesFilter); + // allows child classes to override the logic of accepting filter categories + virtual bool filterItemOut(const QModelIndex& sourceIndex, bool filteredByBase) { Q_UNUSED(sourceIndex); return filteredByBase; } virtual void initItem(QStandardItem* item, const SearchTypeFilter& filter, int unfilteredDataIndex); + int getUnfilteredDataIndex(QStandardItem* item); // get the original filter index from the item itself // Returns the number of items that always appear in the list, regardless of the filtering. virtual int GetNumFixedItems() { return 0; } void showEvent(QShowEvent* e) override; - virtual void RepopulateDataModel(); + void RepopulateDataModel(const SearchTypeFilterList& unfilteredData); void maximizeGeometryToFitScreen(); SearchTypeSelectorTreeView* m_tree; QStandardItemModel* m_model; - const SearchTypeFilterList* m_unfilteredData; - AZ_PUSH_DISABLE_WARNING(4127 4251, "-Wunknown-warning-option") // conditional expression is constant, needs to have dll-interface to be used by clients of class 'AzQtComponents::SearchTypeSelector' - QVector m_filteredItemIndices; - AZ_POP_DISABLE_WARNING - QString m_filterString; + + friend class SearchTypeSelectorFilterModel; + SearchTypeSelectorFilterModel* m_filterModel; + QString m_filterString; bool m_settingUp = false; int m_fixedWidth = 256; QLineEdit* m_searchField = nullptr; @@ -198,6 +198,26 @@ namespace AzQtComponents bool m_lineEditSearchVisible = true; }; + class SearchTypeSelectorFilterModel : public QSortFilterProxyModel + { + Q_OBJECT + + public: + SearchTypeSelectorFilterModel(SearchTypeSelector* searchTypeSelector); + void setNoResultsMessageRow(int row); // row of specialized "no results" message in the source model + + protected slots: + void onRowCountChanged(); + + protected: + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; + int getNumLeafNodes(const QModelIndex& theIndex = QModelIndex()); // gets the number of leaf node descendants of current index. Current index is *not* considered + + SearchTypeSelector* m_searchTypeSelector = nullptr; + int m_noResultsRow = -1; // row of specialized "no results" message in the source model + bool m_showingNoResultsMessage = false; + }; + class AZ_QT_COMPONENTS_API FilteredSearchWidget : public QFrame { diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/ColorPicker.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/ColorPicker.cpp index bca4a1d837..95bbca5006 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/ColorPicker.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/ColorPicker.cpp @@ -114,13 +114,13 @@ namespace AzQtComponents void ReadColorGridConfig(QSettings& settings, const QString& name, ColorPicker::ColorGridConfig& colorGrid) { - ConfigHelpers::GroupGuard(&settings, name); + ConfigHelpers::GroupGuard guard(&settings, name); ConfigHelpers::read(settings, QStringLiteral("MinimumSize"), colorGrid.minimumSize); } void ReadDialoButtonsConfig(QSettings& settings, const QString& name, ColorPicker::DialogButtonsConfig& dialogButtons) { - ConfigHelpers::GroupGuard(&settings, name); + ConfigHelpers::GroupGuard guard(&settings, name); ConfigHelpers::read(settings, QStringLiteral("TopPadding"), dialogButtons.topPadding); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.cpp index 0fe9cbde1d..8f20f37790 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.cpp @@ -41,18 +41,29 @@ namespace AzToolsFramework { } - bool EntityOutlinerSearchTypeSelector::filterItemOut(int unfilteredDataIndex, bool itemMatchesFilter, bool categoryMatchesFilter) + bool EntityOutlinerSearchTypeSelector::filterItemOut(const QModelIndex& sourceIndex, bool filteredByBase) { - bool unfilteredIndexInvalid = (unfilteredDataIndex >= aznumeric_cast(EntityOutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)); - return SearchTypeSelector::filterItemOut(unfilteredDataIndex, itemMatchesFilter, categoryMatchesFilter) && unfilteredIndexInvalid; + auto* currItem = m_model->itemFromIndex(sourceIndex); + if (currItem != nullptr) + { + int unfilteredIndex = getUnfilteredDataIndex(currItem); + if (unfilteredIndex >= 0 && unfilteredIndex < aznumeric_cast(EntityOutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)) + { + // never filter out the categories before FirstRealFilter (unlocked/locked, visible/hidden, etc.) + return false; + } + } + // no special case, return the result of the base filter + return filteredByBase; } void EntityOutlinerSearchTypeSelector::initItem(QStandardItem* item, const AzQtComponents::SearchTypeFilter& filter, int unfilteredDataIndex) { - if (filter.displayName != "--------") + SearchTypeSelector::initItem(item, filter, unfilteredDataIndex); + if (filter.displayName == "--------") { - item->setCheckable(true); - item->setCheckState(filter.enabled ? Qt::Checked : Qt::Unchecked); + SearchTypeSelector::initItem(item, filter, unfilteredDataIndex); + item->setCheckable(false); } if (unfilteredDataIndex < aznumeric_cast(EntityOutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.h index 9ccce17ef2..59a490c42e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSearchWidget.h @@ -44,8 +44,8 @@ namespace AzToolsFramework EntityOutlinerSearchTypeSelector(QWidget* parent = nullptr); protected: - // can be used to override the logic when adding items in RepopulateDataModel - bool filterItemOut(int unfilteredDataIndex, bool itemMatchesFilter, bool categoryMatchesFilter) override; + // override the logic of accepting filter categories + bool filterItemOut(const QModelIndex& sourceIndex, bool filteredByBase) override; void initItem(QStandardItem* item, const AzQtComponents::SearchTypeFilter& filter, int unfilteredDataIndex) override; int GetNumFixedItems() override; }; diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.cpp index 1297085e64..f0bbb83a84 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.cpp @@ -37,21 +37,31 @@ namespace AzQtComponents { } - bool OutlinerSearchTypeSelector::filterItemOut(int unfilteredDataIndex, bool itemMatchesFilter, bool categoryMatchesFilter) + bool OutlinerSearchTypeSelector::filterItemOut(const QModelIndex& sourceIndex, bool filteredByBase) { - bool unfilteredIndexInvalid = (unfilteredDataIndex >= static_cast(OutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)); - return SearchTypeSelector::filterItemOut(unfilteredDataIndex, itemMatchesFilter, categoryMatchesFilter) && unfilteredIndexInvalid; + auto* currItem = m_model->itemFromIndex(sourceIndex); + if (currItem != nullptr) + { + int unfilteredIndex = getUnfilteredDataIndex(currItem); + if (unfilteredIndex >= 0 && unfilteredIndex < aznumeric_cast(OutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)) + { + // never filter out the categories before FirstRealFilter (unlocked/locked, visible/hidden, etc.) + return false; + } + } + // no special case, return the result of the base filter + return filteredByBase; } void OutlinerSearchTypeSelector::initItem(QStandardItem* item, const SearchTypeFilter& filter, int unfilteredDataIndex) { - if (filter.displayName != "--------") + SearchTypeSelector::initItem(item, filter, unfilteredDataIndex); + if (filter.displayName == "--------") { - item->setCheckable(true); - item->setCheckState(filter.enabled ? Qt::Checked : Qt::Unchecked); + item->setCheckable(false); } - if (unfilteredDataIndex < static_cast(OutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)) + if (unfilteredDataIndex >= 0 && unfilteredDataIndex < static_cast(OutlinerSearchWidget::GlobalSearchCriteria::FirstRealFilter)) { item->setIcon(OutlinerIcons::GetInstance().GetIcon(unfilteredDataIndex)); } diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.h b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.h index 2de0c95559..379398e5b0 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.h +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSearchWidget.h @@ -42,8 +42,8 @@ namespace AzQtComponents OutlinerSearchTypeSelector(QWidget* parent = nullptr); protected: - // can be used to override the logic when adding items in RepopulateDataModel - bool filterItemOut(int unfilteredDataIndex, bool itemMatchesFilter, bool categoryMatchesFilter) override; + // override the logic of accepting filter categories + bool filterItemOut(const QModelIndex& sourceIndex, bool filteredByBase) override; void initItem(QStandardItem* item, const SearchTypeFilter& filter, int unfilteredDataIndex) override; int GetNumFixedItems() override; };