summary refs log tree commit diff
path: root/src/timeline
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-06-19 01:38:40 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-06-19 01:38:40 +0200
commitce1a64bc19ffc21e115bdf2587bb053d7a417f3e (patch)
treea195d127228218772a535448de642f0bb7b6d053 /src/timeline
parentRemove explicit link styling (diff)
downloadnheko-ce1a64bc19ffc21e115bdf2587bb053d7a417f3e.tar.xz
Move to automatic type registration
Diffstat (limited to 'src/timeline')
-rw-r--r--src/timeline/CommunitiesModel.cpp1
-rw-r--r--src/timeline/CommunitiesModel.h28
-rw-r--r--src/timeline/DelegateChooser.h2
-rw-r--r--src/timeline/InputBar.h6
-rw-r--r--src/timeline/PresenceEmitter.h27
-rw-r--r--src/timeline/RoomlistModel.cpp2
-rw-r--r--src/timeline/RoomlistModel.h26
-rw-r--r--src/timeline/TimelineFilter.h2
-rw-r--r--src/timeline/TimelineModel.h5
-rw-r--r--src/timeline/TimelineViewManager.cpp30
-rw-r--r--src/timeline/TimelineViewManager.h25
11 files changed, 135 insertions, 19 deletions
diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp
index b04fd7a9..3c09d747 100644
--- a/src/timeline/CommunitiesModel.cpp
+++ b/src/timeline/CommunitiesModel.cpp
@@ -22,6 +22,7 @@ CommunitiesModel::CommunitiesModel(QObject *parent)
   , hiddenTagIds_{UserSettings::instance()->hiddenTags()}
   , mutedTagIds_{UserSettings::instance()->mutedTags()}
 {
+    instance_ = this;
 }
 
 QHash<int, QByteArray>
diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h
index a90fa6a2..d0841f4b 100644
--- a/src/timeline/CommunitiesModel.h
+++ b/src/timeline/CommunitiesModel.h
@@ -6,6 +6,7 @@
 
 #include <QAbstractListModel>
 #include <QHash>
+#include <QQmlEngine>
 #include <QSortFilterProxyModel>
 #include <QString>
 #include <QStringList>
@@ -21,6 +22,8 @@ class CommunitiesModel;
 class FilteredCommunitiesModel final : public QSortFilterProxyModel
 {
     Q_OBJECT
+    QML_ELEMENT
+    QML_UNCREATABLE("Use Communities.filtered() to create a FilteredCommunitiesModel")
 
 public:
     explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr);
@@ -73,6 +76,9 @@ public:
 class CommunitiesModel final : public QAbstractListModel
 {
     Q_OBJECT
+    QML_NAMED_ELEMENT(Communities)
+    QML_SINGLETON
+
     Q_PROPERTY(QString currentTagId READ currentTagId WRITE setCurrentTagId NOTIFY
                  currentTagIdChanged RESET resetCurrentTagId)
     Q_PROPERTY(QStringList tags READ tags NOTIFY tagsChanged)
@@ -149,6 +155,26 @@ public:
     };
 
     CommunitiesModel(QObject *parent = nullptr);
+
+    static CommunitiesModel *create(QQmlEngine *qmlEngine, QJSEngine *)
+    {
+        // The instance has to exist before it is used. We cannot replace it.
+        Q_ASSERT(instance_);
+
+        // The engine has to have the same thread affinity as the singleton.
+        Q_ASSERT(qmlEngine->thread() == instance_->thread());
+
+        // There can only be one engine accessing the singleton.
+        static QJSEngine *s_engine = nullptr;
+        if (s_engine)
+            Q_ASSERT(qmlEngine == s_engine);
+        else
+            s_engine = qmlEngine;
+
+        QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
+        return instance_;
+    }
+
     QHash<int, QByteArray> roleNames() const override;
     int rowCount(const QModelIndex &parent = QModelIndex()) const override
     {
@@ -221,4 +247,6 @@ private:
     mtx::responses::UnreadNotifications dmUnreads{};
 
     friend class FilteredCommunitiesModel;
+
+    inline static CommunitiesModel *instance_ = nullptr;
 };
diff --git a/src/timeline/DelegateChooser.h b/src/timeline/DelegateChooser.h
index c27f2c43..ac227382 100644
--- a/src/timeline/DelegateChooser.h
+++ b/src/timeline/DelegateChooser.h
@@ -19,6 +19,7 @@ class QQmlAdaptorModel;
 class DelegateChoice : public QObject
 {
     Q_OBJECT
+    QML_ELEMENT
     Q_CLASSINFO("DefaultProperty", "delegate")
 
 public:
@@ -45,6 +46,7 @@ private:
 class DelegateChooser : public QQuickItem
 {
     Q_OBJECT
+    QML_ELEMENT
     Q_CLASSINFO("DefaultProperty", "choices")
 
 public:
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index f03e6019..3cd65524 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -7,11 +7,13 @@
 #include <QIODevice>
 #include <QImage>
 #include <QObject>
+#include <QQmlEngine>
 #include <QSize>
 #include <QStringList>
 #include <QTimer>
 #include <QUrl>
 #include <QVariantList>
+
 #include <deque>
 #include <memory>
 
@@ -43,6 +45,10 @@ enum class MarkdownOverride
 class MediaUpload final : public QObject
 {
     Q_OBJECT
+
+    QML_ELEMENT
+    QML_UNCREATABLE("")
+
     Q_PROPERTY(int mediaType READ type NOTIFY mediaTypeChanged)
     // https://stackoverflow.com/questions/33422265/pass-qimage-to-qml/68554646#68554646
     Q_PROPERTY(QUrl thumbnail READ thumbnailDataUrl NOTIFY thumbnailChanged)
diff --git a/src/timeline/PresenceEmitter.h b/src/timeline/PresenceEmitter.h
index e89fb316..09ad1301 100644
--- a/src/timeline/PresenceEmitter.h
+++ b/src/timeline/PresenceEmitter.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <QObject>
+#include <QQmlEngine>
 
 #include <vector>
 
@@ -15,10 +16,33 @@ class PresenceEmitter final : public QObject
 {
     Q_OBJECT
 
+    QML_NAMED_ELEMENT(Presence)
+    QML_SINGLETON
+
 public:
     PresenceEmitter(QObject *p = nullptr)
       : QObject(p)
     {
+        instance_ = this;
+    }
+
+    static PresenceEmitter *create(QQmlEngine *qmlEngine, QJSEngine *)
+    {
+        // The instance has to exist before it is used. We cannot replace it.
+        Q_ASSERT(instance_);
+
+        // The engine has to have the same thread affinity as the singleton.
+        Q_ASSERT(qmlEngine->thread() == instance_->thread());
+
+        // There can only be one engine accessing the singleton.
+        static QJSEngine *s_engine = nullptr;
+        if (s_engine)
+            Q_ASSERT(qmlEngine == s_engine);
+        else
+            s_engine = qmlEngine;
+
+        QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
+        return instance_;
     }
 
     void sync(const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presences);
@@ -28,4 +52,7 @@ public:
 
 signals:
     void presenceChanged(QString userid);
+
+private:
+    inline static PresenceEmitter *instance_ = nullptr;
 };
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index ec41cc12..8d8d2977 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -909,6 +909,8 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
   : QSortFilterProxyModel(parent)
   , roomlistmodel(model)
 {
+    instance_ = this;
+
     this->sortByImportance = UserSettings::instance()->sortByImportance();
     this->sortByAlphabet   = UserSettings::instance()->sortByAlphabet();
     setSourceModel(model);
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index c06ab67d..34bf3f9a 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -167,12 +167,36 @@ private:
 class FilteredRoomlistModel final : public QSortFilterProxyModel
 {
     Q_OBJECT
+
+    QML_NAMED_ELEMENT(Rooms)
+    QML_SINGLETON
+
     Q_PROPERTY(
       TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET resetCurrentRoom)
     Q_PROPERTY(RoomPreview currentRoomPreview READ currentRoomPreview NOTIFY currentRoomChanged
                  RESET resetCurrentRoom)
 public:
     FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
+
+    static FilteredRoomlistModel *create(QQmlEngine *qmlEngine, QJSEngine *)
+    {
+        // The instance has to exist before it is used. We cannot replace it.
+        Q_ASSERT(instance_);
+
+        // The engine has to have the same thread affinity as the singleton.
+        Q_ASSERT(qmlEngine->thread() == instance_->thread());
+
+        // There can only be one engine accessing the singleton.
+        static QJSEngine *s_engine = nullptr;
+        if (s_engine)
+            Q_ASSERT(qmlEngine == s_engine);
+        else
+            s_engine = qmlEngine;
+
+        QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
+        return instance_;
+    }
+
     bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
     bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
 
@@ -249,4 +273,6 @@ private:
     FilterBy filterType = FilterBy::Nothing;
     QStringList hiddenTags, hiddenSpaces;
     bool hideDMs = false;
+
+    inline static FilteredRoomlistModel *instance_ = nullptr;
 };
diff --git a/src/timeline/TimelineFilter.h b/src/timeline/TimelineFilter.h
index 1c92c89a..658a8c57 100644
--- a/src/timeline/TimelineFilter.h
+++ b/src/timeline/TimelineFilter.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <QQmlEngine>
 #include <QSortFilterProxyModel>
 #include <QString>
 
@@ -14,6 +15,7 @@
 class TimelineFilter : public QSortFilterProxyModel
 {
     Q_OBJECT
+    QML_ELEMENT
 
     Q_PROPERTY(QString filterByThread READ filterByThread WRITE setThreadId NOTIFY threadIdChanged)
     Q_PROPERTY(QString filterByContent READ filterByContent WRITE setContentFilter NOTIFY
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index a232b4ee..fd1a4396 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -11,6 +11,7 @@
 #include <QTimer>
 #include <QVariant>
 
+#include <mtx/responses/common.hpp>
 #include <mtxclient/http/errors.hpp>
 
 #include "CacheCryptoStructs.h"
@@ -36,6 +37,7 @@ struct RelatedInfo;
 
 namespace qml_mtx_events {
 Q_NAMESPACE
+QML_NAMED_ELEMENT(MtxEvent)
 
 enum EventType
 {
@@ -193,6 +195,9 @@ class TimelineViewManager;
 class TimelineModel final : public QAbstractListModel
 {
     Q_OBJECT
+    QML_NAMED_ELEMENT(Room)
+    QML_UNCREATABLE("")
+
     Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
     Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
                  typingUsersChanged)
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index a3b91ce7..2f6553e5 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -96,29 +96,21 @@ TimelineViewManager::userColor(QString id, QColor background)
 TimelineViewManager::TimelineViewManager(CallManager *, ChatPage *parent)
   : QObject(parent)
   , rooms_(new RoomlistModel(this))
+  , frooms_(new FilteredRoomlistModel(this->rooms_))
   , communities_(new CommunitiesModel(this))
   , verificationManager_(new VerificationManager(this))
   , presenceEmitter(new PresenceEmitter(this))
 {
-    static auto self = this;
-    qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", self);
-    qmlRegisterSingletonType<RoomlistModel>(
-      "im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
-          auto ptr = new FilteredRoomlistModel(self->rooms_);
-
-          connect(self->communities_,
-                  &CommunitiesModel::currentTagIdChanged,
-                  ptr,
-                  &FilteredRoomlistModel::updateFilterTag);
-          connect(self->communities_,
-                  &CommunitiesModel::hiddenTagsChanged,
-                  ptr,
-                  &FilteredRoomlistModel::updateHiddenTagsAndSpaces);
-          return ptr;
-      });
-    qmlRegisterSingletonInstance("im.nheko", 1, 0, "Communities", self->communities_);
-    qmlRegisterSingletonInstance("im.nheko", 1, 0, "VerificationManager", verificationManager_);
-    qmlRegisterSingletonInstance("im.nheko", 1, 0, "Presence", presenceEmitter);
+    instance_ = this;
+
+    connect(this->communities_,
+            &CommunitiesModel::currentTagIdChanged,
+            frooms_,
+            &FilteredRoomlistModel::updateFilterTag);
+    connect(this->communities_,
+            &CommunitiesModel::hiddenTagsChanged,
+            frooms_,
+            &FilteredRoomlistModel::updateHiddenTagsAndSpaces);
 
     updateColorPalette();
 
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 303e2af2..a4bc6c41 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -34,6 +34,9 @@ class TimelineViewManager final : public QObject
 {
     Q_OBJECT
 
+    QML_NAMED_ELEMENT(TimelineManager)
+    QML_SINGLETON
+
     Q_PROPERTY(
       bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
     Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged)
@@ -41,6 +44,25 @@ class TimelineViewManager final : public QObject
 public:
     TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr);
 
+    static TimelineViewManager *create(QQmlEngine *qmlEngine, QJSEngine *)
+    {
+        // The instance has to exist before it is used. We cannot replace it.
+        Q_ASSERT(instance_);
+
+        // The engine has to have the same thread affinity as the singleton.
+        Q_ASSERT(qmlEngine->thread() == instance_->thread());
+
+        // There can only be one engine accessing the singleton.
+        static QJSEngine *s_engine = nullptr;
+        if (s_engine)
+            Q_ASSERT(qmlEngine == s_engine);
+        else
+            s_engine = qmlEngine;
+
+        QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
+        return instance_;
+    }
+
     void sync(const mtx::responses::Sync &sync_);
 
     VerificationManager *verificationManager() { return verificationManager_; }
@@ -123,6 +145,7 @@ private:
     bool isConnected_   = true;
 
     RoomlistModel *rooms_          = nullptr;
+    FilteredRoomlistModel *frooms_ = nullptr;
     CommunitiesModel *communities_ = nullptr;
 
     // don't move this above the rooms_
@@ -130,4 +153,6 @@ private:
     PresenceEmitter *presenceEmitter          = nullptr;
 
     QHash<QPair<QString, quint64>, QColor> userColors;
+
+    inline static TimelineViewManager *instance_ = nullptr;
 };