File indexing completed on 2024-12-15 04:54:40
0001 /****************************************************************************** 0002 * 0003 * SPDX-FileCopyrightText: 2008 Szymon Tomasz Stefanek <pragma@kvirc.net> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 * 0007 *******************************************************************************/ 0008 0009 #pragma once 0010 0011 #include <QAbstractItemModel> 0012 #include <QHash> 0013 #include <QList> 0014 #include <QMultiHash> 0015 0016 #include "core/enums.h" 0017 0018 #include <ctime> // time_t 0019 #include <memory> 0020 0021 namespace MessageList 0022 { 0023 namespace Core 0024 { 0025 using MessageItemSetReference = long; 0026 0027 class Filter; 0028 class GroupHeaderItem; 0029 class Item; 0030 class MessageItem; 0031 class Theme; 0032 class StorageModel; 0033 class View; 0034 class ModelPrivate; 0035 class SortOrder; 0036 class Aggregation; 0037 0038 /** 0039 * This class manages the huge tree of displayable objects: GroupHeaderItems and MessageItems. 0040 * The tree is exposed via a 'hacked' QAbstractItemModel interface to a QTreeView 0041 * subclass (which is MessageList::View). 0042 * 0043 * The keypoint in this class is that it has to be non-blocking in manipulating the tree: 0044 * fill, cleanup and update operations are performed in timed chunks. Perfect non-blocking 0045 * behaviour is not possible since there are some small operations that basically can't be 0046 * split in chunks. However, these exceptions apply to a minority of tasks and in the 0047 * average case the user will not notice. 0048 * 0049 * The data for building the tree is obtained from a subclass of StorageModel. The 0050 * StorageModel must offer a consistent rappresentation of a "flat" folder containing 0051 * messages. 0052 */ 0053 class Model : public QAbstractItemModel 0054 { 0055 friend class Item; 0056 friend class ItemPrivate; 0057 0058 Q_OBJECT 0059 public: 0060 /** 0061 * Creates the mighty Model attached to the specified View. 0062 */ 0063 explicit Model(View *pParent); 0064 0065 /** 0066 * Destroys the mighty model along with the tree of items it manages. 0067 */ 0068 ~Model() override; 0069 0070 /** 0071 * Returns the StorageModel currently set. 0072 */ 0073 StorageModel *storageModel() const; 0074 0075 /** 0076 * Sets the storage model from that the messages to be displayed should be fetched. 0077 * The model is then reset and a new fill operation is started. The fill operation may 0078 * or may not complete before setStorageModel() returns. This depends on the fill 0079 * strategy and the size of the folder. You can check if the fill operation has 0080 * completed by looking at the return value of isLoading(). 0081 * 0082 * Pre-selection is the action of automatically selecting a message just after the folder 0083 * has finished loading. We may want to select the message that was selected the last 0084 * time this folder has been open, or we may want to select the first unread message. 0085 * We also may want to do no pre-selection at all (for example, when the user 0086 * starts navigating the view before the pre-selection could actually be made 0087 * and pre-selecting would confuse him). The pre-selection is applied once 0088 * loading is complete. 0089 */ 0090 void setStorageModel(StorageModel *storageModel, PreSelectionMode preSelectionMode = PreSelectLastSelected); 0091 0092 /** 0093 * Sets the pre-selection mode. 0094 * 0095 * Called with PreSelectNone to abort any pending message pre-selection. This may be done if the user 0096 * starts navigating the view and selecting items before we actually could 0097 * apply the pre-selection. 0098 */ 0099 void setPreSelectionMode(PreSelectionMode preSelect); 0100 0101 /** 0102 * Returns the hidden root item that all the messages are (or will be) attached to. 0103 * The returned value is never 0. 0104 */ 0105 Item *rootItem() const; 0106 0107 /** 0108 * Returns true if the view is currently loading, that is 0109 * it's in the first (possibly lengthy) job batch after attaching to a StorageModel. 0110 */ 0111 [[nodiscard]] bool isLoading() const; 0112 0113 /** 0114 * Returns the message item that is at the _current_ storage row index 0115 * or zero if no such storage item is found. Please note that this may return 0 0116 * also if the specified storage row hasn't been actually read yet. This may happen 0117 * if isLoading() returns true. In this case the only thing you can do is to retry in a while. 0118 */ 0119 MessageItem *messageItemByStorageRow(int row) const; 0120 0121 /** 0122 * Sets the Aggregation mode. 0123 * Does not reload the model in any way: you need to call setStorageModel( storageModel() ) for this to happen. 0124 * The pointer ownership remains of the caller which must ensure its validity until the next 0125 * call to setAggretation() or until this Model dies. The caller, in fact, is Widget which 0126 * takes care of meeting the above conditions. The aggregation pointer must not be null. 0127 */ 0128 void setAggregation(const Aggregation *aggregation); 0129 0130 /** 0131 * Sets the Theme. 0132 * Does not reload the model in any way: you need to call setStorageModel( storageModel() ) for this to happen. 0133 * The pointer ownership remains of the caller which must ensure its validity until the next 0134 * call to setTheme() or until this Model dies. The caller, in fact, is Widget which 0135 * takes care of meeting the above conditions. The theme pointer must not be null. 0136 */ 0137 void setTheme(const Theme *theme); 0138 0139 /** 0140 * Sets the sort order. As with setTheme() and setAggregation(), this does not reload the 0141 * model in any way. 0142 */ 0143 void setSortOrder(const SortOrder *sortOrder); 0144 0145 /** 0146 * Returns the sort order 0147 */ 0148 const SortOrder *sortOrder() const; 0149 0150 /** 0151 * Sets the Filter to be applied on messages. filter may be null (no filter is applied). 0152 * The pointer ownership remains of the caller which must ensure its validity until the next 0153 * call to setFilter() or until this Model dies. The caller, in fact, is Widget which 0154 * takes care of meeting the above conditions. The Filter pointer may be null. 0155 */ 0156 void setFilter(const Filter *filter); 0157 0158 /** 0159 * Creates a persistent set for the specified MessageItems and 0160 * returns its reference. Later you can use this reference 0161 * to retrieve the list of MessageItems that are still valid. 0162 * See persistentSetActualMessageList() for that. 0163 * 0164 * Persistent sets consume resources (both memory and CPU time 0165 * while manipulating the view) so be sure to call deletePersistentSet() 0166 * when you no longer need it. 0167 */ 0168 [[nodiscard]] MessageItemSetReference createPersistentSet(const QList<MessageItem *> &items); 0169 0170 /** 0171 * Returns the list of MessageItems that are still existing in the 0172 * set pointed by the specified reference. This list will contain 0173 * at most the messages that you have passed to createPersistentSet() 0174 * but may contain less (even 0) if these MessageItem object were removed 0175 * from the view for some reason. 0176 */ 0177 [[nodiscard]] QList<MessageItem *> persistentSetCurrentMessageItemList(MessageItemSetReference ref); 0178 0179 /** 0180 * Deletes the persistent set pointed by the specified reference. 0181 * If the set does not exist anymore, nothing happens. 0182 */ 0183 void deletePersistentSet(MessageItemSetReference ref); 0184 0185 // Mandatory QAbstractItemModel interface. 0186 0187 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0188 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 0189 QVariant headerData(int section, Qt::Orientation orientation, int role) const override; 0190 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 0191 QModelIndex index(Item *item, int column) const; 0192 QModelIndex parent(const QModelIndex &index) const override; 0193 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0194 Qt::ItemFlags flags(const QModelIndex &index) const override; 0195 0196 /// Called when user initiates a drag from the messagelist 0197 QMimeData *mimeData(const QModelIndexList &indexes) const override; 0198 0199 Q_SIGNALS: 0200 /** 0201 * Notify the outside when updating the status bar with a message 0202 * could be useful 0203 */ 0204 void statusMessage(const QString &message); 0205 0206 private: 0207 friend class ModelPrivate; 0208 std::unique_ptr<ModelPrivate> const d; 0209 }; 0210 } // namespace Core 0211 } // namespace MessageList