File indexing completed on 2024-05-05 05:01:26

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         OrderRole,
0055         ChildTimestampRole,
0056     };
0057 
0058     explicit SpaceChildrenModel(QObject *parent = nullptr);
0059     ~SpaceChildrenModel();
0060 
0061     NeoChatRoom *space() const;
0062     void setSpace(NeoChatRoom *space);
0063 
0064     bool loading() const;
0065 
0066     /**
0067      * @brief Get the given role value at the given index.
0068      *
0069      * @sa QAbstractItemModel::data
0070      */
0071     QVariant data(const QModelIndex &index, int role = DisplayNameRole) const override;
0072 
0073     /**
0074      * @brief Returns the index of the item in the model specified by the given row, column and parent index.
0075      *
0076      * @sa QAbstractItemModel::index
0077      */
0078     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0079 
0080     /**
0081      * @brief Returns the parent of the model item with the given index.
0082      *
0083      * If the item has no parent, an invalid QModelIndex is returned.
0084      *
0085      * @sa QAbstractItemModel::parent
0086      */
0087     QModelIndex parent(const QModelIndex &index) const override;
0088 
0089     /**
0090      * @brief Number of rows in the model.
0091      *
0092      * @sa QAbstractItemModel::rowCount
0093      */
0094     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0095 
0096     /**
0097      * @brief Number of columns in the model.
0098      *
0099      * @sa QAbstractItemModel::columnCount
0100      */
0101     int columnCount(const QModelIndex &parent = QModelIndex()) const override;
0102 
0103     /**
0104      * @brief Returns a mapping from Role enum values to role names.
0105      *
0106      * @sa Roles, QAbstractItemModel::roleNames()
0107      */
0108     QHash<int, QByteArray> roleNames() const override;
0109 
0110     /**
0111      * @brief Whether the room has been replaced.
0112      *
0113      * @note This information is only available if the local user is either a member
0114      *       of the replaced room or is a member of the successor room as currently
0115      *       there is no other way to obtain the required information.
0116      */
0117     bool isRoomReplaced(const QString &roomId) const;
0118 
0119     /**
0120      * @brief Add the name of new child room that is expected to be added soon.
0121      *
0122      * A pending child is one where Quotient::Connection::createRoom has been called
0123      * but the room hasn't synced with the server yet. This list is used to check
0124      * whether a new room loading should trigger a refresh of the model, as we only
0125      * want to trigger a refresh if the loading room is part of this space.
0126      */
0127     Q_INVOKABLE void addPendingChild(const QString &childName);
0128 
0129 Q_SIGNALS:
0130     void spaceChanged();
0131     void loadingChanged();
0132 
0133 private:
0134     NeoChatRoom *m_space = nullptr;
0135     SpaceTreeItem *m_rootItem;
0136 
0137     bool m_loading = false;
0138     QList<QPointer<Quotient::GetSpaceHierarchyJob>> m_currentJobs;
0139     QList<QString> m_pendingChildren;
0140 
0141     QList<QString> m_replacedRooms;
0142 
0143     SpaceTreeItem *getItem(const QModelIndex &index) const;
0144 
0145     void refreshModel();
0146     void insertChildren(std::vector<Quotient::GetSpaceHierarchyJob::ChildRoomsChunk> children, const QModelIndex &parent = QModelIndex());
0147 };