summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-10-08 20:14:13 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-10-08 20:14:13 +0200
commit6c6370c83fab2140a81f431b8909746a0b6833dc (patch)
tree9c0aeaece5cdb461fdbc0863ea276e259b86137b /src
parentReimplement mention highlight and scroll to highlight (diff)
downloadnheko-6c6370c83fab2140a81f431b8909746a0b6833dc.tar.xz
Switch to manual polishing of event delegates
Diffstat (limited to 'src')
-rw-r--r--src/timeline/EventDelegateChooser.cpp78
-rw-r--r--src/timeline/EventDelegateChooser.h60
-rw-r--r--src/timeline/TimelineModel.cpp8
3 files changed, 128 insertions, 18 deletions
diff --git a/src/timeline/EventDelegateChooser.cpp b/src/timeline/EventDelegateChooser.cpp
index 2218d9ee..0060907d 100644
--- a/src/timeline/EventDelegateChooser.cpp
+++ b/src/timeline/EventDelegateChooser.cpp
@@ -131,7 +131,7 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
             roleToPropIdx.insert(*role, i);
             roles.emplace_back(*role);
 
-            nhlog::ui()->critical("Found prop {}, idx {}, role {}", prop.name(), i, *role);
+            // nhlog::ui()->critical("Found prop {}, idx {}, role {}", prop.name(), i, *role);
         } else {
             nhlog::ui()->critical("Required property {} not found in model!", prop.name());
         }
@@ -140,14 +140,15 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
     nhlog::ui()->debug("Querying data for id {}", currentId.toStdString());
     chooser.room_->multiData(currentId, forReply ? chooser.eventId_ : QString(), roles);
 
+    Qt::beginPropertyUpdateGroup();
     for (const auto &role : roles) {
         const auto &roleName = roleNames[role.role()];
-        nhlog::ui()->critical("Setting role {}, {} to {}",
-                              role.role(),
-                              roleName.toStdString(),
-                              role.data().toString().toStdString());
+        // nhlog::ui()->critical("Setting role {}, {} to {}",
+        //                       role.role(),
+        //                       roleName.toStdString(),
+        //                       role.data().toString().toStdString());
 
-        nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[role.role()]).name());
+        // nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[role.role()]).name());
         mo->property(roleToPropIdx[role.role()]).write(obj, role.data());
 
         if (const auto &req = requiredProperties.find(roleName); req != requiredProperties.end())
@@ -156,14 +157,15 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
 
     if (isReplyNeeded) {
         const auto roleName = QByteArray("isReply");
-        nhlog::ui()->critical("Setting role {} to {}", roleName.toStdString(), forReply);
+        // nhlog::ui()->critical("Setting role {} to {}", roleName.toStdString(), forReply);
 
-        nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[-1]).name());
+        // nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[-1]).name());
         mo->property(roleToPropIdx[-1]).write(obj, forReply);
 
         if (const auto &req = requiredProperties.find(roleName); req != requiredProperties.end())
             QQmlIncubatorPrivate::get(this)->requiredProperties()->remove(*req);
     }
+    Qt::endPropertyUpdateGroup();
 
     // setInitialProperties(rolesToSet);
 
@@ -188,9 +190,12 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
           auto mo = obj->metaObject();
           chooser.room_->multiData(
             currentId, forReply ? chooser.eventId_ : QString(), rolesToRequest);
+
+          Qt::beginPropertyUpdateGroup();
           for (const auto &role : rolesToRequest) {
               mo->property(roleToPropIdx[role.role()]).write(obj, role.data());
           }
+          Qt::endPropertyUpdateGroup();
       };
 
     if (!forReply) {
@@ -257,11 +262,22 @@ EventDelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status sta
 
         child->setParentItem(&chooser);
         QQmlEngine::setObjectOwnership(child, QQmlEngine::ObjectOwnership::JavaScriptOwnership);
+
+        // connect(child, &QQuickItem::parentChanged, child, [child](QQuickItem *) {
+        //     // QTBUG-115687
+        //     if (child->flags().testFlag(QQuickItem::ItemObservesViewport)) {
+        //         nhlog::ui()->critical("SETTING OBSERVES VIEWPORT");
+        //         // Re-trigger the parent traversal to get subtreeTransformChangedEnabled turned
+        //         on child->setFlag(QQuickItem::ItemObservesViewport);
+        //     }
+        // });
+
         if (forReply)
             emit chooser.replyChanged();
         else
             emit chooser.mainChanged();
 
+        chooser.polish();
     } else if (status == QQmlIncubator::Error) {
         auto errors_ = errors();
         for (const auto &e : qAsConst(errors_))
@@ -269,3 +285,49 @@ EventDelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status sta
     }
 }
 
+void
+EventDelegateChooser::updatePolish()
+{
+    auto mainChild = qobject_cast<QQuickItem *>(eventIncubator.object());
+    auto replyChild = qobject_cast<QQuickItem *>(replyIncubator.object());
+
+    nhlog::ui()->critical("POLISHING {}", (void *)this);
+
+    if (mainChild) {
+        auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
+          qmlAttachedPropertiesObject<EventDelegateChooser>(mainChild));
+        Q_ASSERT(attached != nullptr);
+
+        // in theory we could also reset the width, but that doesn't seem to work nicely for text
+        // areas because of how they cache it.
+        mainChild->setWidth(maxWidth_);
+        mainChild->ensurePolished();
+        auto width = mainChild->implicitWidth();
+
+        if (width > maxWidth_ || attached->fillWidth())
+            width = maxWidth_;
+
+        nhlog::ui()->debug(
+          "Made event delegate width: {}, {}", width, mainChild->metaObject()->className());
+        mainChild->setWidth(width);
+        mainChild->ensurePolished();
+    }
+
+    if (replyChild) {
+        auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
+          qmlAttachedPropertiesObject<EventDelegateChooser>(replyChild));
+        Q_ASSERT(attached != nullptr);
+
+        // in theory we could also reset the width, but that doesn't seem to work nicely for text
+        // areas because of how they cache it.
+        replyChild->setWidth(maxWidth_);
+        replyChild->ensurePolished();
+        auto width = replyChild->implicitWidth();
+
+        if (width > maxWidth_ || attached->fillWidth())
+            width = maxWidth_;
+
+        replyChild->setWidth(width);
+        replyChild->ensurePolished();
+    }
+}
diff --git a/src/timeline/EventDelegateChooser.h b/src/timeline/EventDelegateChooser.h
index 1cd2d65a..ff67ccd8 100644
--- a/src/timeline/EventDelegateChooser.h
+++ b/src/timeline/EventDelegateChooser.h
@@ -2,9 +2,6 @@
 //
 // SPDX-License-Identifier: GPL-3.0-or-later
 
-// A DelegateChooser like the one, that was added to Qt5.12 (in labs), but compatible with older Qt
-// versions see KDE/kquickitemviews see qtdeclarative/qqmldelagatecomponent
-
 #pragma once
 
 #include <QAbstractItemModel>
@@ -17,6 +14,32 @@
 
 #include "TimelineModel.h"
 
+class EventDelegateChooserAttachedType : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged)
+    QML_ANONYMOUS
+public:
+    EventDelegateChooserAttachedType(QObject *parent)
+      : QObject(parent)
+    {
+    }
+    bool fillWidth() const { return fillWidth_; }
+    void setFillWidth(bool fill)
+    {
+        fillWidth_ = fill;
+        emit fillWidthChanged();
+    }
+signals:
+    void fillWidthChanged();
+
+private:
+    bool fillWidth_ = false, keepAspectRatio = false;
+    double aspectRatio = 1.;
+    int maxWidth       = -1;
+    int maxHeight      = -1;
+};
+
 class EventDelegateChoice : public QObject
 {
     Q_OBJECT
@@ -51,14 +74,18 @@ class EventDelegateChooser : public QQuickItem
     QML_ELEMENT
     Q_CLASSINFO("DefaultProperty", "choices")
 
-public:
+    QML_ATTACHED(EventDelegateChooserAttachedType)
+
     Q_PROPERTY(QQmlListProperty<EventDelegateChoice> choices READ choices CONSTANT FINAL)
     Q_PROPERTY(QQuickItem *main READ main NOTIFY mainChanged FINAL)
     Q_PROPERTY(QQuickItem *reply READ reply NOTIFY replyChanged FINAL)
     Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged REQUIRED FINAL)
     Q_PROPERTY(QString replyTo READ replyTo WRITE setReplyTo NOTIFY replyToChanged REQUIRED FINAL)
     Q_PROPERTY(TimelineModel *room READ room WRITE setRoom NOTIFY roomChanged REQUIRED FINAL)
+    Q_PROPERTY(bool sameWidth READ sameWidth WRITE setSameWidth NOTIFY sameWidthChanged)
+    Q_PROPERTY(int maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
 
+public:
     QQmlListProperty<EventDelegateChoice> choices();
 
     [[nodiscard]] QQuickItem *main() const
@@ -70,6 +97,20 @@ public:
         return qobject_cast<QQuickItem *>(replyIncubator.object());
     }
 
+    bool sameWidth() const { return sameWidth_; }
+    void setSameWidth(bool width)
+    {
+        sameWidth_ = width;
+        emit sameWidthChanged();
+    }
+    bool maxWidth() const { return maxWidth_; }
+    void setMaxWidth(int width)
+    {
+        maxWidth_ = width;
+        emit maxWidthChanged();
+        polish();
+    }
+
     void setRoom(TimelineModel *m)
     {
         if (m != room_) {
@@ -105,12 +146,21 @@ public:
 
     void componentComplete() override;
 
+    static EventDelegateChooserAttachedType *qmlAttachedProperties(QObject *object)
+    {
+        return new EventDelegateChooserAttachedType(object);
+    }
+
+    void updatePolish() override;
+
 signals:
     void mainChanged();
     void replyChanged();
     void roomChanged();
     void eventIdChanged();
     void replyToChanged();
+    void sameWidthChanged();
+    void maxWidthChanged();
 
 private:
     struct DelegateIncubator final : public QQmlIncubator
@@ -142,6 +192,8 @@ private:
     TimelineModel *room_{nullptr};
     QString eventId_;
     QString replyId;
+    bool sameWidth_ = false;
+    int maxWidth_   = 400;
 
     static void appendChoice(QQmlListProperty<EventDelegateChoice> *, EventDelegateChoice *);
     static qsizetype choiceCount(QQmlListProperty<EventDelegateChoice> *);
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 3e0c6688..f5b9e142 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -601,12 +601,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
     case UserName:
         return QVariant(displayName(QString::fromStdString(acc::sender(event))));
     case UserPowerlevel: {
-        return static_cast<qlonglong>(mtx::events::state::PowerLevels{
-          cache::client()
-            ->getStateEvent<mtx::events::state::PowerLevels>(room_id_.toStdString())
-            .value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
-            .content}
-                                        .user_level(acc::sender(event)));
+        return static_cast<qlonglong>(
+          permissions_.powerlevelEvent().user_level(acc::sender(event)));
     }
 
     case Day: {