summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-04-18 20:21:03 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2021-04-18 21:53:39 +0200
commitc2e625756ce74b2691ec10fc7c67d0920b6749ac (patch)
tree89b92cf4c1b043788fc3a30e2a2af6036c79f179 /src
parentPrevent warning on empty user requests (diff)
downloadnheko-c2e625756ce74b2691ec10fc7c67d0920b6749ac.tar.xz
Use one CompletionProxy for everything including EmojiPicker
Diffstat (limited to 'src')
-rw-r--r--src/Cache_p.h44
-rw-r--r--src/CompletionProxyModel.cpp31
-rw-r--r--src/CompletionProxyModel.h6
-rw-r--r--src/emoji/EmojiModel.cpp70
-rw-r--r--src/emoji/EmojiModel.h32
-rw-r--r--src/emoji/EmojiSearchModel.h50
-rw-r--r--src/timeline/TimelineViewManager.cpp8
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);