// SPDX-FileCopyrightText: 2021 Nheko Contributors // // SPDX-License-Identifier: GPL-3.0-or-later #include "CompletionProxyModel.h" #include #include "CompletionModelRoles.h" #include "Logging.h" #include "Utils.h" CompletionProxyModel::CompletionProxyModel(QAbstractItemModel *model, int max_mistakes, QObject *parent) : QAbstractProxyModel(parent) , maxMistakes_(max_mistakes) { setSourceModel(model); QRegularExpression splitPoints("\\s+|-"); // insert all the full texts for (int i = 0; i < sourceModel()->rowCount(); i++) { if (i < 7) mapping.push_back(i); auto string1 = sourceModel() ->data(sourceModel()->index(i, 0), CompletionModel::SearchRole) .toString() .toLower(); trie_.insert(string1.toUcs4(), i); auto string2 = sourceModel() ->data(sourceModel()->index(i, 0), CompletionModel::SearchRole2) .toString() .toLower(); } // insert the partial matches for (int i = 0; i < sourceModel()->rowCount(); i++) { auto string1 = sourceModel() ->data(sourceModel()->index(i, 0), CompletionModel::SearchRole) .toString() .toLower(); for (const auto &e : string1.split(splitPoints)) { if (!e.isEmpty()) // NOTE(Nico): Use Qt::SkipEmptyParts in Qt 5.14 trie_.insert(e.toUcs4(), i); } auto string2 = sourceModel() ->data(sourceModel()->index(i, 0), CompletionModel::SearchRole2) .toString() .toLower(); if (!string2.isEmpty()) { for (const auto &e : string2.split(splitPoints)) { if (!e.isEmpty()) // NOTE(Nico): Use Qt::SkipEmptyParts in Qt 5.14 trie_.insert(e.toUcs4(), i); } } } connect( this, &CompletionProxyModel::newSearchString, this, [this](QString s) { s.remove(":"); s.remove("@"); searchString_ = s.toLower(); invalidate(); }, Qt::QueuedConnection); } void CompletionProxyModel::invalidate() { auto key = searchString_.toUcs4(); beginResetModel(); mapping = trie_.search(key, 7, maxMistakes_); endResetModel(); std::string temp; for (auto v : mapping) { temp += std::to_string(v) + ", "; } nhlog::ui()->debug("mapping: {}", temp); } QHash CompletionProxyModel::roleNames() const { return this->sourceModel()->roleNames(); } int CompletionProxyModel::rowCount(const QModelIndex &) const { return (int)mapping.size(); } QModelIndex CompletionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { for (int i = 0; i < (int)mapping.size(); i++) { if (mapping[i] == sourceIndex.row()) { return index(i, 0); } } return QModelIndex(); } QModelIndex CompletionProxyModel::mapToSource(const QModelIndex &proxyIndex) const { auto row = proxyIndex.row(); if (row < 0 || row >= (int)mapping.size()) return QModelIndex(); return sourceModel()->index(mapping[row], 0); } QModelIndex CompletionProxyModel::index(int row, int column, const QModelIndex &) const { return createIndex(row, column); } QModelIndex CompletionProxyModel::parent(const QModelIndex &) const { return QModelIndex{}; } int CompletionProxyModel::columnCount(const QModelIndex &) const { return sourceModel()->columnCount(); } QVariant CompletionProxyModel::completionAt(int i) const { if (i >= 0 && i < rowCount()) return data(index(i, 0), CompletionModel::CompletionRole); else return {}; } void CompletionProxyModel::setSearchString(QString s) { emit newSearchString(s); }