diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml index 50ff7324..d9592e14 100644 --- a/resources/qml/MessageInput.qml +++ b/resources/qml/MessageInput.qml @@ -128,6 +128,9 @@ Rectangle { textArea.clear(); event.accepted = true; } + if (popup.opened) + popup.completer.setSearchString(textArea.getText(completerTriggeredAt, cursorPosition)); + } Connections { diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h index 757aa990..ee8236e3 100644 --- a/src/CompletionProxyModel.h +++ b/src/CompletionProxyModel.h @@ -5,6 +5,7 @@ #include #include "CompletionModelRoles.h" +#include "Utils.h" class CompletionProxyModel : public QSortFilterProxyModel { @@ -15,6 +16,20 @@ public: : QSortFilterProxyModel(parent) { setSourceModel(model); + sort(0, Qt::AscendingOrder); + setFilterRole(CompletionModel::SearchRole); + + connect( + this, + &CompletionProxyModel::newSearchString, + this, + [this](QString s) { + s.remove(":"); + s.remove("@"); + searchString = s.toLower(); + invalidate(); + }, + Qt::QueuedConnection); } QHash roleNames() const override @@ -28,6 +43,79 @@ public: return (row_count < 7) ? row_count : 7; } + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const + { + if (searchString.size() < 1) + return true; + + auto source_index = sourceModel()->index(source_row, 0, source_parent); + auto role1 = sourceModel() + ->data(source_index, CompletionModel::SearchRole) + .toString() + .toLower(); + + if (role1.contains(searchString)) + return true; + // auto score = + // utils::levenshtein_distance(searchString, role1.toLower().toStdString()); + // if ((size_t)role1.size() >= searchString.size() && + // ((size_t)score) < (size_t)role1.size() - searchString.size() + 2) + // return true; + + auto role2 = sourceModel() + ->data(source_index, CompletionModel::SearchRole2) + .toString() + .toLower(); + if (role2.contains(searchString)) + return true; + // if (!role2.isEmpty()) { + // score = + // utils::levenshtein_distance(searchString, + // role2.toLower().toStdString()); + // if ((size_t)role2.size() >= searchString.size() && + // ((size_t)score) < (size_t)role2.size() - searchString.size() + 2) + // return true; + //} + + return false; + } + + bool lessThan(const QModelIndex &source_left, + const QModelIndex &source_right) const override + { + if (searchString.size() < 1) + return false; + + auto left1 = + sourceModel()->data(source_left, CompletionModel::SearchRole).toString(); + auto left2 = + sourceModel()->data(source_left, CompletionModel::SearchRole2).toString(); + auto left = left1.toLower().indexOf(searchString); + // utils::levenshtein_distance(searchString, left1.toLower().toStdString()); + if (!left2.isEmpty()) { + // left = std::min( + // utils::levenshtein_distance(searchString, + // left2.toLower().toStdString()), left); + left = std::min(left2.toLower().indexOf(searchString), left); + } + + auto right1 = + sourceModel()->data(source_right, CompletionModel::SearchRole).toString(); + auto right2 = + sourceModel()->data(source_right, CompletionModel::SearchRole2).toString(); + auto right = right1.toLower().indexOf(searchString); + // auto right = + // utils::levenshtein_distance(searchString, right1.toLower().toStdString()); + if (!right2.isEmpty()) { + // right = std::min( + // utils::levenshtein_distance(searchString, + // right2.toLower().toStdString()), right); + right = std::min(right2.toLower().indexOf(searchString), right); + } + + return left < right; + } + public slots: QVariant completionAt(int i) const { @@ -36,4 +124,12 @@ public slots: else return {}; } + + void setSearchString(QString s) { emit newSearchString(s); } + +signals: + void newSearchString(QString); + +private: + QString searchString; }; diff --git a/src/UsersModel.cpp b/src/UsersModel.cpp index f102cff1..cb9f8f75 100644 --- a/src/UsersModel.cpp +++ b/src/UsersModel.cpp @@ -8,6 +8,10 @@ UsersModel::UsersModel(const std::string &roomId, QObject *parent) , room_id(roomId) { roomMembers_ = cache::roomMembers(roomId); + for (const auto &m : roomMembers_) { + displayNames.push_back(QString::fromStdString(cache::displayName(room_id, m))); + userids.push_back(QString::fromStdString(m)); + } } QHash @@ -31,10 +35,9 @@ UsersModel::data(const QModelIndex &index, int role) const case CompletionModel::SearchRole: case Qt::DisplayRole: case Roles::DisplayName: - return QString::fromStdString( - cache::displayName(room_id, roomMembers_[index.row()])); + return displayNames[index.row()]; case CompletionModel::SearchRole2: - return QString::fromStdString(roomMembers_[index.row()]); + return userids[index.row()]; case Roles::AvatarUrl: return cache::avatarUrl(QString::fromStdString(room_id), QString::fromStdString(roomMembers_[index.row()])); diff --git a/src/UsersModel.h b/src/UsersModel.h index 6ee8261f..cddcdd84 100644 --- a/src/UsersModel.h +++ b/src/UsersModel.h @@ -23,4 +23,6 @@ public: private: std::string room_id; std::vector roomMembers_; + std::vector displayNames; + std::vector userids; };