File indexing completed on 2024-12-08 07:33:47

0001 // SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0003 
0004 #pragma once
0005 
0006 #include <QAbstractItemModel>
0007 #include <QQmlEngine>
0008 
0009 #include <Quotient/csapi/space_hierarchy.h>
0010 #include <qtmetamacros.h>
0011 
0012 #include "neochatroom.h"
0013 #include "spacetreeitem.h"
0014 
0015 /**
0016  * @class SpaceChildrenModel
0017  *
0018  * Create a model that contains a list of the child rooms for any given space id.
0019  */
0020 class SpaceChildrenModel : public QAbstractItemModel
0021 {
0022     Q_OBJECT
0023     QML_ELEMENT
0024 
0025     /**
0026      * @brief The current space that the hierarchy is being generated for.
0027      */
0028     Q_PROPERTY(NeoChatRoom *space READ space WRITE setSpace NOTIFY spaceChanged)
0029 
0030     /**
0031      * @brief Whether the model is loading the initial set of children.
0032      */
0033     Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
0034 
0035 public:
0036     enum Roles {
0037         DisplayNameRole = Qt::DisplayRole,
0038         AvatarUrlRole,
0039         TopicRole,
0040         RoomIDRole,
0041         AliasRole,
0042         MemberCountRole,
0043         AllowGuestsRole,
0044         WorldReadableRole,
0045         IsJoinedRole,
0046         IsSpaceRole,
0047         IsSuggestedRole,
0048         CanAddChildrenRole,
0049         ParentDisplayNameRole,
0050         CanSetParentRole,
0051         IsDeclaredParentRole,
0052         CanRemove,
0053         ParentRoomRole,
0054     };
0055 
0056     explicit SpaceChildrenModel(QObject *parent = nullptr);
0057     ~SpaceChildrenModel();
0058 
0059     NeoChatRoom *space() const;
0060     void setSpace(NeoChatRoom *space);
0061 
0062     bool loading() const;
0063 
0064     /**
0065      * @brief Get the given role value at the given index.
0066      *
0067      * @sa QAbstractItemModel::data
0068      */
0069     QVariant data(const QModelIndex &index, int role = DisplayNameRole) const override;
0070 
0071     /**
0072      * @brief Returns the index of the item in the model specified by the given row, column and parent index.
0073      *
0074      * @sa QAbstractItemModel::index
0075      */
0076     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0077 
0078     /**
0079      * @brief Returns the parent of the model item with the given index.
0080      *
0081      * If the item has no parent, an invalid QModelIndex is returned.
0082      *
0083      * @sa QAbstractItemModel::parent
0084      */
0085     QModelIndex parent(const QModelIndex &index) const override;
0086 
0087     /**
0088      * @brief Number of rows in the model.
0089      *
0090      * @sa QAbstractItemModel::rowCount
0091      */
0092     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0093 
0094     /**
0095      * @brief Number of columns in the model.
0096      *
0097      * @sa QAbstractItemModel::columnCount
0098      */
0099     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0100 
0101     /**
0102      * @brief Returns a mapping from Role enum values to role names.
0103      *
0104      * @sa Roles, QAbstractItemModel::roleNames()
0105      */
0106     QHash<int, QByteArray> roleNames() const override;
0107 
0108     /**
0109      * @brief Whether the room has been replaced.
0110      *
0111      * @note This information is only available if the local user is either a member
0112      *       of the replaced room or is a member of the successor room as currently
0113      *       there is no other way to obtain the required information.
0114      */
0115     bool isRoomReplaced(const QString &roomId) const;
0116 
0117     /**
0118      * @brief Add the name of new child room that is expected to be added soon.
0119      *
0120      * A pending child is one where Quotient::Connection::createRoom has been called
0121      * but the room hasn't synced with the server yet. This list is used to check
0122      * whether a new room loading should trigger a refresh of the model, as we only
0123      * want to trigger a refresh if the loading room is part of this space.
0124      */
0125     Q_INVOKABLE void addPendingChild(const QString &childName);
0126 
0127 Q_SIGNALS:
0128     void spaceChanged();
0129     void loadingChanged();
0130 
0131 private:
0132     NeoChatRoom *m_space = nullptr;
0133     SpaceTreeItem *m_rootItem;
0134 
0135     bool m_loading = false;
0136     QList<QPointer<Quotient::GetSpaceHierarchyJob>> m_currentJobs;
0137     QList<QString> m_pendingChildren;
0138 
0139     QList<QString> m_replacedRooms;
0140 
0141     SpaceTreeItem *getItem(const QModelIndex &index) const;
0142 
0143     void refreshModel();
0144     void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::ChildRoomsChunk> children, const QModelIndex &parent = QModelIndex());
0145 };