From 5c63ef280b4569d73202a111a8a390b141765c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BChler?= Date: Sun, 23 Aug 2026 18:10:31 +0200 Subject: [PATCH 1/2] palettes: Remove PaletteCellFilterProxyModel The required functionality is part of Qt's QSortFilterProxyModel: - `recursiveFilteringEnabled` (since Qt 5.10): Recurses down the tree and accepts parents with accepted children - `autoAcceptChildRows` (since Qt 6.0): Children of accepted parents are auto accepted. This is used to be able to search by palette name --- src/palette/internal/palettemodel.cpp | 41 ------------------------ src/palette/internal/palettemodel.h | 13 -------- src/palette/internal/paletteprovider.cpp | 6 +++- 3 files changed, 5 insertions(+), 55 deletions(-) diff --git a/src/palette/internal/palettemodel.cpp b/src/palette/internal/palettemodel.cpp index 342a8ee6a35ae..4dfb25ec0105f 100644 --- a/src/palette/internal/palettemodel.cpp +++ b/src/palette/internal/palettemodel.cpp @@ -1109,44 +1109,3 @@ bool FilterPaletteTreeModel::filterAcceptsRow(int sourceRow, const QModelIndex& } return cellFilter->accept(*cell); } - -//--------------------------------------------------------- -// PaletteCellFilterProxyModel::PaletteCellFilterProxyModel -//--------------------------------------------------------- - -PaletteCellFilterProxyModel::PaletteCellFilterProxyModel(QObject* parent) - : QSortFilterProxyModel(parent) -{ - setFilterRole(Qt::ToolTipRole); // palette cells have no data for DisplayRole -} - -//--------------------------------------------------------- -// PaletteCellFilterProxyModel::filterAcceptsRow -//--------------------------------------------------------- - -bool PaletteCellFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const -{ - const QAbstractItemModel* model = sourceModel(); - const QModelIndex rowIndex = model->index(sourceRow, 0, sourceParent); - const int rowCount = model->rowCount(rowIndex); - - if (rowCount == 0) { - if (QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent)) { - return true; - } - // accept row if its parent is accepted by filter: necessary to be able to search by palette name - if (sourceParent.isValid() - && QSortFilterProxyModel::filterAcceptsRow(sourceParent.row(), sourceParent.parent())) { - return true; - } - return false; - } - - for (int i = 0; i < rowCount; ++i) { - if (filterAcceptsRow(i, rowIndex)) { - return true; - } - } - - return false; -} diff --git a/src/palette/internal/palettemodel.h b/src/palette/internal/palettemodel.h index a58db9e9b79ba..fce3139e997f7 100644 --- a/src/palette/internal/palettemodel.h +++ b/src/palette/internal/palettemodel.h @@ -225,19 +225,6 @@ private slots: public: FilterPaletteTreeModel(PaletteCellFilter* filter, PaletteTreeModel* model, QObject* parent = nullptr); }; - -//--------------------------------------------------------- -// PaletteCellFilterProxyModel -//--------------------------------------------------------- - -class PaletteCellFilterProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - PaletteCellFilterProxyModel(QObject* parent = nullptr); - - bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; -}; } #endif diff --git a/src/palette/internal/paletteprovider.cpp b/src/palette/internal/paletteprovider.cpp index 32001e6a58a7d..3b1453bb38137 100644 --- a/src/palette/internal/paletteprovider.cpp +++ b/src/palette/internal/paletteprovider.cpp @@ -607,8 +607,12 @@ void PaletteProvider::init() m_masterPaletteModel = new PaletteTreeModel(PaletteCreator(iocContext()).newMasterPaletteTree(), iocContext(), this); - m_searchFilterModel = new PaletteCellFilterProxyModel(this); + m_searchFilterModel = new QSortFilterProxyModel(this); m_searchFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_searchFilterModel->setFilterRole(Qt::ToolTipRole); + m_searchFilterModel->setRecursiveFilteringEnabled(true); + // accept row if its parent is accepted by filter: necessary to be able to search by palette name + m_searchFilterModel->setAutoAcceptChildRows(true); m_visibilityFilterModel = new QSortFilterProxyModel(this); m_visibilityFilterModel->setFilterRole(PaletteTreeModel::VisibleRole); From 765d53b75a53c1986b5b85f6a822d1cba36e01e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20B=C3=BChler?= Date: Sun, 30 Aug 2026 17:24:01 +0200 Subject: [PATCH 2/2] palettes: Add fuzzy search and sorting Palettes are sorted according to the scores of their cells and their own score. --- muse | 2 +- src/palette/internal/paletteprovider.cpp | 41 +++++++++++++++++------- src/palette/internal/paletteprovider.h | 5 +++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/muse b/muse index ee2c97edf5fff..afd732b774539 160000 --- a/muse +++ b/muse @@ -1 +1 @@ -Subproject commit ee2c97edf5fff6ae46289851ec8e2968a5deb045 +Subproject commit afd732b774539618728fa168fb5d4c26a1314258 diff --git a/src/palette/internal/paletteprovider.cpp b/src/palette/internal/paletteprovider.cpp index 3b1453bb38137..347ee46d9b7cf 100644 --- a/src/palette/internal/paletteprovider.cpp +++ b/src/palette/internal/paletteprovider.cpp @@ -29,6 +29,14 @@ #include #include +#include "global/translation.h" +#include "global/io/path.h" +#include "global/types/uri.h" + +#include "uicomponents/qml/Muse/UiComponents/fuzzyfilter.h" +#include "uicomponents/qml/Muse/UiComponents/fuzzyscoresorter.h" +#include "uicomponents/qml/Muse/UiComponents/sortfilterproxymodel.h" + #include "engraving/dom/mscore.h" #include "notation/inotation.h" @@ -36,13 +44,9 @@ #include "palettecreator.h" -#include "io/path.h" - -#include "translation.h" -#include "types/uri.h" - #include "app_config.h" +using namespace Qt::StringLiterals; using namespace muse; using namespace mu::palette; using namespace mu::engraving; @@ -607,12 +611,25 @@ void PaletteProvider::init() m_masterPaletteModel = new PaletteTreeModel(PaletteCreator(iocContext()).newMasterPaletteTree(), iocContext(), this); - m_searchFilterModel = new QSortFilterProxyModel(this); - m_searchFilterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - m_searchFilterModel->setFilterRole(Qt::ToolTipRole); - m_searchFilterModel->setRecursiveFilteringEnabled(true); - // accept row if its parent is accepted by filter: necessary to be able to search by palette name - m_searchFilterModel->setAutoAcceptChildRows(true); + { + m_fuzzyFilter = new uicomponents::FuzzyFilter(this); + m_fuzzyFilter->setRoleName(u"toolTip"_s); + + auto* sorter = new uicomponents::FuzzyScoreSorter(this); + sorter->setFuzzyFilter(m_fuzzyFilter); + sorter->setEnabled(true); + + auto* searchFilterModel = new uicomponents::SortFilterProxyModel(this); + QQmlListProperty filters = searchFilterModel->filters(); + filters.append(&filters, m_fuzzyFilter); + QQmlListProperty sorters = searchFilterModel->sorters(); + sorters.append(&sorters, sorter); + searchFilterModel->setRecursiveFilteringEnabled(true); + // accept row if its parent is accepted by filter: necessary to be able to search by palette name + searchFilterModel->setAutoAcceptChildRows(true); + + m_searchFilterModel = searchFilterModel; + } m_visibilityFilterModel = new QSortFilterProxyModel(this); m_visibilityFilterModel->setFilterRole(PaletteTreeModel::VisibleRole); @@ -641,7 +658,7 @@ void PaletteProvider::setFilter(const QString& filter) // speed up the search in certain other scenarios, // e.g. when deleting search characters (going from fewer to more search results). m_searchFilterModel->setSourceModel(nullptr); - m_searchFilterModel->setFilterFixedString(filter); + m_fuzzyFilter->setFuzzyPattern(filter); if (!filter.isEmpty()) { m_searchFilterModel->setSourceModel(m_masterPaletteModel); } diff --git a/src/palette/internal/paletteprovider.h b/src/palette/internal/paletteprovider.h index 4da9b1fd53a36..5c28f4c28accf 100644 --- a/src/palette/internal/paletteprovider.h +++ b/src/palette/internal/paletteprovider.h @@ -34,6 +34,10 @@ #include "ipaletteprovider.h" #include "palettemodel.h" +namespace muse::uicomponents { +class FuzzyFilter; +} + namespace mu::palette { class AbstractPaletteController; class PaletteProvider; @@ -315,6 +319,7 @@ private slots: QSortFilterProxyModel* m_visibilityFilterModel = nullptr; QSortFilterProxyModel* m_searchFilterModel = nullptr; + muse::uicomponents::FuzzyFilter* m_fuzzyFilter = nullptr; QAbstractItemModel* m_mainPalette = nullptr; // visible userPalette entries // PaletteTreeModel* poolPalette; // masterPalette entries not yet added to mainPalette