Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@

#include "filteredflyoutmodel.h"

#include "global/translation.h"
#include <algorithm>

using namespace muse::uicomponents;
#include "global/translation.h"

namespace muse::uicomponents {
// Recursively traverse a flyout tree, collect all "leaves" (items without a sub item)...
static void flattenTreeModel(const QVariant& treeModel, const QString& categoryTitle, QVariantList& result, QVariant& alwaysAppend)
{
Expand Down Expand Up @@ -67,6 +68,25 @@ static void flattenTreeModel(const QVariant& treeModel, const QString& categoryT
}
}

static bool containsFuzzy(FuzzyMatcher& matcher, const std::u32string_view text, const std::vector<std::u32string>& patternTokens)
{
return std::all_of(patternTokens.begin(), patternTokens.end(), [&](const std::u32string& patternToken) {
const std::size_t tokenSize = patternToken.size();
if (tokenSize == 0) {
return true;
}

constexpr std::size_t MIN_TOKEN_SIZE_FOR_FUZZY_MATCH = 4;
constexpr std::size_t CHARS_PER_ERROR = 8;
const std::size_t maxDistance = tokenSize >= MIN_TOKEN_SIZE_FOR_FUZZY_MATCH
? 1 + (tokenSize / CHARS_PER_ERROR)
: 0;

matcher.match(text, patternToken, maxDistance);
return !matcher.empty();
});
}

FilteredFlyoutModel::FilteredFlyoutModel(QObject* parent)
: QObject(parent)
{
Expand Down Expand Up @@ -105,6 +125,15 @@ void FilteredFlyoutModel::setFilterText(const QString& filterText)
}
m_filterText = filterText;

const QString caseAdjustedPattern = m_filterText.simplified().toLower();
const QStringList tokens = caseAdjustedPattern.split(u' ');

m_patternTokens.clear();
m_patternTokens.reserve(tokens.size());
for (const auto& token : tokens) {
m_patternTokens.push_back(token.toStdU32String());
}

QVariantList newModel;
newModel.reserve(m_flattenedModel.toList().size());

Expand All @@ -113,7 +142,7 @@ void FilteredFlyoutModel::setFilterText(const QString& filterText)
for (const QVariant& item : m_flattenedModel.toList()) {
QVariantMap itemMap = item.toMap();
const QString title = itemMap.value("title").toString();
if (!title.contains(m_filterText, Qt::CaseInsensitive)) {
if (!containsFuzzy(m_matcher, title.toLower().toStdU32String(), m_patternTokens)) {
continue;
}
const QString prefix = title.section("-", 0, 0);
Expand All @@ -140,3 +169,4 @@ void FilteredFlyoutModel::setFilterText(const QString& filterText)

emit modelChanged();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,17 @@

#pragma once

#include <QObject>
#include <string>
#include <vector>

#include <qqmlintegration.h>

#include <QObject>
#include <QString>
#include <QVariant>

#include "global/stringsearch.h"

namespace muse::uicomponents {
class FilteredFlyoutModel : public QObject
{
Expand All @@ -49,6 +57,8 @@ class FilteredFlyoutModel : public QObject

private:
QString m_filterText;
std::vector<std::u32string> m_patternTokens;
FuzzyMatcher m_matcher;

QVariant m_rawModel;

Expand Down