summary refs log tree commit diff
path: root/src/CompletionProxyModel.h
diff options
context:
space:
mode:
authorDeepBlueV7.X <nicolas.werner@hotmail.de>2020-11-25 21:59:23 +0100
committerGitHub <noreply@github.com>2020-11-25 21:59:23 +0100
commit54d75466c71f339893dbec44793531b001cf9b87 (patch)
tree1ab1ed3fa72dea0b2ab8ed861a0d0fe685864c1c /src/CompletionProxyModel.h
parentMerge pull request #337 from trilene/master (diff)
parentOpen completer on tab (diff)
downloadnheko-54d75466c71f339893dbec44793531b001cf9b87.tar.xz
Merge pull request #335 from Nheko-Reborn/qml-text-input
Qml text input
Diffstat (limited to 'src/CompletionProxyModel.h')
-rw-r--r--src/CompletionProxyModel.h159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h
new file mode 100644

index 00000000..1517505f --- /dev/null +++ b/src/CompletionProxyModel.h
@@ -0,0 +1,159 @@ +#pragma once + +// Class for showing a limited amount of completions at a time + +#include <QAbstractProxyModel> + +template<typename Key, typename Value> +struct trie +{ + std::vector<Value> values; + std::map<Key, trie> next; + + void insert(const QVector<Key> &keys, const Value &v) + { + auto t = this; + for (const auto k : keys) { + t = &t->next[k]; + } + + t->values.push_back(v); + } + + std::vector<Value> valuesAndSubvalues(size_t limit = -1) const + { + std::vector<Value> ret; + if (limit < 200) + ret.reserve(limit); + + for (const auto &v : values) { + if (ret.size() >= limit) + return ret; + else + ret.push_back(v); + } + + for (const auto &[k, t] : next) { + (void)k; + if (ret.size() >= limit) + return ret; + else { + auto temp = t.valuesAndSubvalues(limit - ret.size()); + for (auto &&v : temp) { + if (ret.size() >= limit) + return ret; + + if (std::find(ret.begin(), ret.end(), v) == ret.end()) { + ret.push_back(std::move(v)); + } + } + } + } + + return ret; + } + + std::vector<Value> search(const QVector<Key> &keys, //< TODO(Nico): replace this with a span + size_t limit, + size_t max_distance = 2) const + { + std::vector<Value> ret; + if (!limit) + return ret; + + if (keys.isEmpty()) + return valuesAndSubvalues(limit); + + auto append = [&ret, limit](std::vector<Value> &&in) { + for (auto &&v : in) { + if (ret.size() >= limit) + return; + + if (std::find(ret.begin(), ret.end(), v) == ret.end()) { + ret.push_back(std::move(v)); + } + } + }; + + if (auto e = this->next.find(keys[0]); e != this->next.end()) { + append(e->second.search(keys.mid(1), limit, max_distance)); + } + + if (max_distance && ret.size() < limit) { + max_distance -= 1; + + // swap chars case + if (keys.size() >= 2) { + auto t = this; + for (int i = 1; i >= 0; i--) { + if (auto e = t->next.find(keys[i]); e != t->next.end()) { + t = &e->second; + } else { + t = nullptr; + break; + } + } + + if (t) { + append(t->search( + keys.mid(2), (limit - ret.size()) * 2, max_distance)); + } + } + + // delete character case + append(this->search(keys.mid(1), (limit - ret.size()) * 2, max_distance)); + + // substitute and insert cases + for (const auto &[k, t] : this->next) { + if (k == keys[0] || ret.size() >= limit) + break; + + // substitute + append(t.search(keys.mid(1), limit - ret.size(), max_distance)); + + if (ret.size() >= limit) + break; + + // insert + append(t.search(keys, limit - ret.size(), max_distance)); + } + } + + return ret; + } +}; + +class CompletionProxyModel : public QAbstractProxyModel +{ + Q_OBJECT + +public: + CompletionProxyModel(QAbstractItemModel *model, QObject *parent = nullptr); + + void invalidate(); + + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &) const override; + + QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override; + QModelIndex mapToSource(const QModelIndex &proxyIndex) const override; + + QModelIndex index(int row, + int column, + const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &) const override; + +public slots: + QVariant completionAt(int i) const; + + void setSearchString(QString s); + +signals: + void newSearchString(QString); + +private: + QString searchString; + trie<uint, int> trie_; + std::vector<int> mapping; +};