diff options
author | Nicolas Werner <nicolas.werner@hotmail.de> | 2021-04-18 20:21:03 +0200 |
---|---|---|
committer | Nicolas Werner <nicolas.werner@hotmail.de> | 2021-04-18 21:53:39 +0200 |
commit | c2e625756ce74b2691ec10fc7c67d0920b6749ac (patch) | |
tree | 89b92cf4c1b043788fc3a30e2a2af6036c79f179 /src | |
parent | Prevent warning on empty user requests (diff) | |
download | nheko-c2e625756ce74b2691ec10fc7c67d0920b6749ac.tar.xz |
Use one CompletionProxy for everything including EmojiPicker
Diffstat (limited to 'src')
-rw-r--r-- | src/Cache_p.h | 44 | ||||
-rw-r--r-- | src/CompletionProxyModel.cpp | 31 | ||||
-rw-r--r-- | src/CompletionProxyModel.h | 6 | ||||
-rw-r--r-- | src/emoji/EmojiModel.cpp | 70 | ||||
-rw-r--r-- | src/emoji/EmojiModel.h | 32 | ||||
-rw-r--r-- | src/emoji/EmojiSearchModel.h | 50 | ||||
-rw-r--r-- | src/timeline/TimelineViewManager.cpp | 8 |
7 files changed, 91 insertions, 150 deletions
diff --git a/src/Cache_p.h b/src/Cache_p.h index 51dc4cbc..1e388e77 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -405,6 +405,50 @@ private: event); } + template<typename T> + std::optional<mtx::events::StateEvent<T>> getStateEvent(lmdb::txn txn, + const std::string &room_id, + std::string_view state_key = "") + { + constexpr auto type = mtx::events::state_content_to_type<T>; + static_assert(type != mtx::events::EventType::Unsupported, + "Not a supported type in state events."); + + if (room_id.empty()) + return std::nullopt; + + std::string_view value; + if (state_key.empty()) { + auto db = getStatesDb(txn, room_id); + if (!db.get(txn, to_string(type), value)) { + return std::nullopt; + } + } else { + auto db = getStatesKeyDb(txn, room_id); + std::string d = json::object({{"key", state_key}}).dump(); + std::string_view data = d; + + auto cursor = lmdb::cursor::open(txn, db); + if (!cursor.get(state_key, data, MDB_GET_BOTH)) + return std::nullopt; + + try { + auto eventsDb = getEventsDb(txn, room_id); + if (!eventsDb.get( + txn, json::parse(data)["id"].get<std::string>(), value)) + return std::nullopt; + } catch (std::exception &e) { + return std::nullopt; + } + } + + try { + return json::parse(value).get<mtx::events::StateEvent<T>>(); + } catch (std::exception &e) { + return std::nullopt; + } + } + void saveInvites(lmdb::txn &txn, const std::map<std::string, mtx::responses::InvitedRoom> &rooms); diff --git a/src/CompletionProxyModel.cpp b/src/CompletionProxyModel.cpp index 2341c292..412708a2 100644 --- a/src/CompletionProxyModel.cpp +++ b/src/CompletionProxyModel.cpp @@ -12,16 +12,18 @@ CompletionProxyModel::CompletionProxyModel(QAbstractItemModel *model, int max_mistakes, + size_t max_completions, QObject *parent) : QAbstractProxyModel(parent) , maxMistakes_(max_mistakes) + , max_completions_(max_completions) { setSourceModel(model); QRegularExpression splitPoints("\\s+|-"); // insert all the full texts for (int i = 0; i < sourceModel()->rowCount(); i++) { - if (i < 7) + if (static_cast<size_t>(i) < max_completions_) mapping.push_back(i); auto string1 = sourceModel() @@ -82,14 +84,9 @@ CompletionProxyModel::invalidate() { auto key = searchString_.toUcs4(); beginResetModel(); - mapping = trie_.search(key, 7, maxMistakes_); + if (!key.empty()) // return default model data, if no search string + mapping = trie_.search(key, max_completions_, maxMistakes_); endResetModel(); - - std::string temp; - for (auto v : mapping) { - temp += std::to_string(v) + ", "; - } - nhlog::ui()->debug("mapping: {}", temp); } QHash<int, QByteArray> @@ -101,12 +98,22 @@ CompletionProxyModel::roleNames() const int CompletionProxyModel::rowCount(const QModelIndex &) const { - return (int)mapping.size(); + if (searchString_.isEmpty()) + return std::min(static_cast<int>(std::min<size_t>(max_completions_, + std::numeric_limits<int>::max())), + sourceModel()->rowCount()); + else + return (int)mapping.size(); } QModelIndex CompletionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { + // return default model data, if no search string + if (searchString_.isEmpty()) { + return index(sourceIndex.row(), 0); + } + for (int i = 0; i < (int)mapping.size(); i++) { if (mapping[i] == sourceIndex.row()) { return index(i, 0); @@ -119,6 +126,12 @@ QModelIndex CompletionProxyModel::mapToSource(const QModelIndex &proxyIndex) const { auto row = proxyIndex.row(); + + // return default model data, if no search string + if (searchString_.isEmpty()) { + return index(row, 0); + } + if (row < 0 || row >= (int)mapping.size()) return QModelIndex(); diff --git a/src/CompletionProxyModel.h b/src/CompletionProxyModel.h index f19e4d93..d85d9343 100644 --- a/src/CompletionProxyModel.h +++ b/src/CompletionProxyModel.h @@ -153,8 +153,9 @@ class CompletionProxyModel : public QAbstractProxyModel QString searchString READ searchString WRITE setSearchString NOTIFY newSearchString) public: CompletionProxyModel(QAbstractItemModel *model, - int max_mistakes = 2, - QObject *parent = nullptr); + int max_mistakes = 2, + size_t max_completions = 7, + QObject *parent = nullptr); void invalidate(); @@ -184,4 +185,5 @@ private: trie<uint, int> trie_; std::vector<int> mapping; int maxMistakes_; + size_t max_completions_; }; diff --git a/src/emoji/EmojiModel.cpp b/src/emoji/EmojiModel.cpp index 70b85934..66e7aeda 100644 --- a/src/emoji/EmojiModel.cpp +++ b/src/emoji/EmojiModel.cpp @@ -11,6 +11,20 @@ using namespace emoji; +int +EmojiModel::categoryToIndex(int category) +{ + auto dist = std::distance(Provider::emoji.begin(), + std::lower_bound(Provider::emoji.begin(), + Provider::emoji.end(), + static_cast<Emoji::Category>(category), + [](const struct Emoji &e, Emoji::Category c) { + return e.category < c; + })); + + return static_cast<int>(dist); +} + QHash<int, QByteArray> EmojiModel::roleNames() const { @@ -60,59 +74,3 @@ EmojiModel::data(const QModelIndex &index, int role) const return {}; } - -EmojiProxyModel::EmojiProxyModel(QObject *parent) - : QSortFilterProxyModel(parent) -{} - -EmojiProxyModel::~EmojiProxyModel() {} - -Emoji::Category -EmojiProxyModel::category() const -{ - return category_; -} - -void -EmojiProxyModel::setCategory(Emoji::Category cat) -{ - if (category_ == cat) { - return; - } - - category_ = cat; - emit categoryChanged(); - - invalidateFilter(); -} - -QString -EmojiProxyModel::filter() const -{ - return filterRegExp().pattern(); -} - -void -EmojiProxyModel::setFilter(const QString &filter) -{ - if (filterRegExp().pattern() == filter) { - return; - } - - setFilterWildcard(filter); - emit filterChanged(); -} - -bool -EmojiProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const -{ - const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); - const Emoji emoji = index.data(static_cast<int>(EmojiModel::Roles::Emoji)).value<Emoji>(); - - // TODO: Add favorites / recently used - if (category_ != Emoji::Category::Search) { - return emoji.category == category_; - } - - return filterRegExp().isEmpty() ? true : filterRegExp().indexIn(emoji.shortName) != -1; -} diff --git a/src/emoji/EmojiModel.h b/src/emoji/EmojiModel.h index 1a8bf029..679563f1 100644 --- a/src/emoji/EmojiModel.h +++ b/src/emoji/EmojiModel.h @@ -30,38 +30,10 @@ public: using QAbstractListModel::QAbstractListModel; + Q_INVOKABLE int categoryToIndex(int category); + QHash<int, QByteArray> roleNames() const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; }; - -class EmojiProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - - Q_PROPERTY( - emoji::Emoji::Category category READ category WRITE setCategory NOTIFY categoryChanged) - Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) - -public: - explicit EmojiProxyModel(QObject *parent = nullptr); - ~EmojiProxyModel() override; - - Emoji::Category category() const; - void setCategory(Emoji::Category cat); - - QString filter() const; - void setFilter(const QString &filter); - -signals: - void categoryChanged(); - void filterChanged(); - -protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - -private: - Emoji::Category category_ = Emoji::Category::Search; - emoji::Provider emoji_provider_; -}; } diff --git a/src/emoji/EmojiSearchModel.h b/src/emoji/EmojiSearchModel.h deleted file mode 100644 index 64af83dd..00000000 --- a/src/emoji/EmojiSearchModel.h +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Nheko Contributors -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "EmojiModel.h" - -#include <CompletionModelRoles.h> -#include <QDebug> -#include <QEvent> -#include <QSortFilterProxyModel> - -namespace emoji { - -// Map emoji data to searchable data -class EmojiSearchModel : public QSortFilterProxyModel -{ -public: - EmojiSearchModel(QObject *parent = nullptr) - : QSortFilterProxyModel(parent) - { - setSourceModel(new EmojiModel(this)); - } - QVariant data(const QModelIndex &index, int role = Qt::UserRole + 1) const override - { - switch (role) { - case Qt::DisplayRole: { - auto emoji = QSortFilterProxyModel::data(index, role).toString(); - return emoji + " :" + - toShortcode(data(index, EmojiModel::ShortName).toString()) + ":"; - } - case CompletionModel::CompletionRole: - return QSortFilterProxyModel::data(index, EmojiModel::Unicode); - case CompletionModel::SearchRole: { - return toShortcode( - QSortFilterProxyModel::data(index, EmojiModel::ShortName).toString()); - } - default: - return QSortFilterProxyModel::data(index, role); - } - } - -private: - QString toShortcode(QString shortname) const - { - return shortname.replace(" ", "-").replace(":", "-").replace("--", "-").toLower(); - } -}; -} diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index f15b0b14..e9986c7e 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -172,9 +172,6 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par qRegisterMetaType<std::vector<DeviceInfo>>(); qmlRegisterType<emoji::EmojiModel>("im.nheko.EmojiModel", 1, 0, "EmojiModel"); - qmlRegisterType<emoji::EmojiProxyModel>("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel"); - qmlRegisterUncreatableType<QAbstractItemModel>( - "im.nheko.EmojiModel", 1, 0, "QAbstractItemModel", "Used by proxy models"); qmlRegisterUncreatableType<emoji::Emoji>( "im.nheko.EmojiModel", 1, 0, "Emoji", "Used by emoji models"); qmlRegisterUncreatableMetaObject(emoji::staticMetaObject, @@ -595,6 +592,11 @@ TimelineViewManager::completerFor(QString completerName, QString roomId) auto proxy = new CompletionProxyModel(emojiModel); emojiModel->setParent(proxy); return proxy; + } else if (completerName == "allemoji") { + auto emojiModel = new emoji::EmojiModel(); + auto proxy = new CompletionProxyModel(emojiModel, 1, static_cast<size_t>(-1) / 4); + emojiModel->setParent(proxy); + return proxy; } else if (completerName == "room") { auto roomModel = new RoomsModel(false); auto proxy = new CompletionProxyModel(roomModel, 4); |