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