File indexing completed on 2024-12-15 04:54:37

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 <QList>
0012 #include <QString>
0013 
0014 #include <ctime> // for time_t
0015 
0016 #include <KMime/Headers>
0017 
0018 #include <Akonadi/MessageStatus>
0019 
0020 #include "core/model.h"
0021 #include "messagelist_export.h"
0022 
0023 namespace MessageList
0024 {
0025 namespace Core
0026 {
0027 class ItemPrivate;
0028 
0029 /**
0030  * A single item of the MessageList tree managed by MessageList::Model.
0031  *
0032  * This class stores basic information needed in all the subclasses which
0033  * at the moment of writing are MessageItem and GroupHeaderItem.
0034  */
0035 class MESSAGELIST_EXPORT Item
0036 {
0037     friend class Model;
0038     friend class ModelPrivate;
0039 
0040 public:
0041     /**
0042      * The type of the Item.
0043      */
0044     enum Type {
0045         GroupHeader, ///< This item is a GroupHeaderItem
0046         Message, ///< This item is a MessageItem
0047         InvisibleRoot ///< This item is just Item and it's the only InvisibleRoot per Model.
0048     };
0049 
0050     /**
0051      * Specifies the initial expand status for the item that should be applied
0052      * when it's attached to the viewable tree. Needed as a workaround for
0053      * QTreeView limitations in handling item expansion.
0054      */
0055     enum InitialExpandStatus {
0056         ExpandNeeded, ///< Must expand when this item becomes viewable
0057         NoExpandNeeded, ///< No expand needed at all
0058         ExpandExecuted ///< Item already expanded
0059     };
0060 
0061 protected:
0062     /**
0063      * Creates an Item. Only derived classes and MessageList::Model should access this.
0064      */
0065     Item(Type type);
0066     Item(Type type, ItemPrivate *dd);
0067 
0068 public:
0069     /**
0070      * Destroys the Item. Should be protected just like the constructor but the QList<>
0071      * helpers need to access it, so it's public actually.
0072      */
0073     virtual ~Item();
0074 
0075     /**
0076      * Returns the type of this item. The Type can be set only in the constructor.
0077      */
0078     [[nodiscard]] Type type() const;
0079 
0080     /**
0081      * The initial expand status we have to honor when attaching to the viewable root.
0082      */
0083     [[nodiscard]] InitialExpandStatus initialExpandStatus() const;
0084 
0085     /**
0086      * Set the initial expand status we have to honor when attaching to the viewable root.
0087      */
0088     void setInitialExpandStatus(InitialExpandStatus initialExpandStatus);
0089 
0090     /**
0091      * Is this item attached to the viewable root ?
0092      */
0093     [[nodiscard]] bool isViewable() const;
0094 
0095     /**
0096      * Return true if Item pointed by it is an ancestor of this item (that is,
0097      * if it is its parent, parent of its parent, parent of its parent of its parent etc...
0098      */
0099     [[nodiscard]] bool hasAncestor(const Item *it) const;
0100 
0101     /**
0102      * Makes this item viewable, that is, notifies its existence to any listener
0103      * attached to the "rowsInserted()" signal, most notably QTreeView.
0104      *
0105      * This will also make all the children viewable.
0106      */
0107     void setViewable(Model *model, bool bViewable);
0108 
0109     /**
0110      * Return the list of child items. May be null.
0111      */
0112     [[nodiscard]] QList<Item *> *childItems() const;
0113 
0114     /**
0115      * Returns the child item at position idx or 0 if idx is out of the allowable range.
0116      */
0117     [[nodiscard]] Item *childItem(int idx) const;
0118 
0119     /**
0120      * Returns the first child item, if any.
0121      */
0122     [[nodiscard]] Item *firstChildItem() const;
0123 
0124     /**
0125      * Returns the item that is visually below the specified child if this item.
0126      * Note that the returned item may belong to a completely different subtree.
0127      */
0128     [[nodiscard]] Item *itemBelowChild(Item *child);
0129 
0130     /**
0131      * Returns the item that is visually above the specified child if this item.
0132      * Note that the returned item may belong to a completely different subtree.
0133      */
0134     [[nodiscard]] Item *itemAboveChild(Item *child);
0135 
0136     /**
0137      * Returns the deepest item in the subtree originating at this item.
0138      */
0139     [[nodiscard]] Item *deepestItem();
0140 
0141     /**
0142      * Returns the item that is visually below this item in the tree.
0143      * Note that the returned item may belong to a completely different subtree.
0144      */
0145     [[nodiscard]] Item *itemBelow();
0146 
0147     /**
0148      * Returns the item that is visually above this item in the tree.
0149      * Note that the returned item may belong to a completely different subtree.
0150      */
0151     [[nodiscard]] Item *itemAbove();
0152 
0153     /**
0154      * Debug helper. Dumps the structure of this subtree.
0155      */
0156     void dump(const QString &prefix);
0157 
0158     /**
0159      * Returns the number of children of this Item.
0160      */
0161     [[nodiscard]] int childItemCount() const;
0162 
0163     /**
0164      * Convenience function that returns true if this item has children.
0165      */
0166     [[nodiscard]] bool hasChildren() const;
0167 
0168     /**
0169      * A structure used with MessageList::Item::childItemStats().
0170      * Contains counts of total and unread messages in a subtree.
0171      */
0172     class ChildItemStats
0173     {
0174     public:
0175         unsigned int mTotalChildCount; // total
0176         unsigned int mUnreadChildCount; // unread only
0177     public:
0178         ChildItemStats()
0179             : mTotalChildCount(0)
0180             , mUnreadChildCount(0)
0181         {
0182         }
0183     };
0184 
0185     /**
0186      * Gathers statistics about child items.
0187      * For performance purposes assumes that this item has children.
0188      * You MUST check it before calling it.
0189      */
0190     void childItemStats(ChildItemStats &stats) const;
0191 
0192     /**
0193      * Returns the actual index of the child Item item or -1 if
0194      * item is not a child of this Item.
0195      */
0196     int indexOfChildItem(Item *item) const;
0197 
0198     /**
0199      * Sets the cached guess for the index of this item in the parent's child list.
0200      *
0201      * This is used to speed up the index lookup with the following algorithm:
0202      * Ask the parent if this item is at the position specified by index guess (this costs ~O(1)).
0203      * If the position matches we have finished, if it doesn't then perform
0204      * a linear search via indexOfChildItem() (which costs ~O(n)).
0205      */
0206     void setIndexGuess(int index);
0207 
0208     /**
0209      * Returns the parent Item in the tree, or 0 if this item isn't attached to the tree.
0210      * Please note that even if this item has a non-zero parent, it can be still non viewable.
0211      * That is: the topmost parent of this item may be not attached to the viewable root.
0212      */
0213     [[nodiscard]] Item *parent() const;
0214 
0215     /**
0216      * Sets the parent for this item. You should also take care of inserting
0217      * this item in the parent's child list.
0218      */
0219     void setParent(Item *pParent);
0220 
0221     /**
0222      * Returns the topmost parent item that is not a Root item (that is, is a Message or GroupHeader).
0223      */
0224     [[nodiscard]] Item *topmostNonRoot();
0225 
0226     /**
0227      * Returns the status associated to this Item.
0228      */
0229     const Akonadi::MessageStatus &status() const;
0230 
0231     /**
0232      * Sets the status associated to this Item.
0233      */
0234     void setStatus(Akonadi::MessageStatus status);
0235 
0236     /**
0237      * Returns a string describing the status e.g: "Read, Forwarded, Important"
0238      */
0239     [[nodiscard]] QString statusDescription() const;
0240 
0241     /**
0242      * Returns the size of this item (size of the Message, mainly)
0243      */
0244     size_t size() const;
0245 
0246     /**
0247      * Sets the size of this item (size of the Message, mainly)
0248      */
0249     void setSize(size_t size);
0250 
0251     /**
0252      * A string with a text rappresentation of size(). This is computed on-the-fly
0253      * and not cached.
0254      */
0255     [[nodiscard]] QString formattedSize() const;
0256 
0257     /**
0258      * Returns the date of this item
0259      */
0260     time_t date() const;
0261 
0262     /**
0263      * Sets the date of this item
0264      */
0265     void setDate(time_t date);
0266 
0267     /**
0268      * A string with a text rappresentation of date() obtained via Manager. This is computed on-the-fly
0269      * and not cached.
0270      */
0271     [[nodiscard]] QString formattedDate() const;
0272 
0273     /**
0274      * Returns the maximum date in the subtree originating from this item.
0275      * This is kept up-to-date by MessageList::Model.
0276      */
0277     time_t maxDate() const;
0278 
0279     /**
0280      * Sets the maximum date in the subtree originating from this item.
0281      */
0282     void setMaxDate(time_t date);
0283 
0284     /**
0285      * A string with a text rappresentation of maxDate() obtained via Manager. This is computed on-the-fly
0286      * and not cached.
0287      */
0288     [[nodiscard]] QString formattedMaxDate() const;
0289 
0290     /**
0291      * Recompute the maximum date from the current children list.
0292      * Return true if the current max date changed and false otherwise.
0293      */
0294     bool recomputeMaxDate();
0295 
0296     /**
0297      * Returns the sender associated to this item.
0298      */
0299     [[nodiscard]] const QString &sender() const;
0300 
0301     /**
0302      * Sets the sender associated to this item.
0303      */
0304     void setSender(const QString &sender);
0305 
0306     /**
0307      * Display sender.
0308      */
0309     [[nodiscard]] QString displaySender() const;
0310 
0311     /**
0312      * Returns the receiver associated to this item.
0313      */
0314     const QString &receiver() const;
0315 
0316     /**
0317      * Sets the sender associated to this item.
0318      */
0319     void setReceiver(const QString &receiver);
0320 
0321     /**
0322      * Display receiver.
0323      */
0324     [[nodiscard]] QString displayReceiver() const;
0325 
0326     /**
0327      * Returns the sender or the receiver, depending on the underlying StorageModel settings.
0328      */
0329     const QString &senderOrReceiver() const;
0330 
0331     /**
0332      * Display sender or receiver.
0333      */
0334     [[nodiscard]] QString displaySenderOrReceiver() const;
0335 
0336     /**
0337      * Returns whether sender or receiver is supposed to be displayed.
0338      */
0339     bool useReceiver() const;
0340 
0341     /**
0342      * Returns the subject associated to this Item.
0343      */
0344     const QString &subject() const;
0345 
0346     /**
0347      * Sets the subject associated to this Item.
0348      */
0349     void setSubject(const QString &subject);
0350 
0351     /**
0352      * Returns the folder associated to this Item.
0353      */
0354     const QString &folder() const;
0355 
0356     /**
0357      * Sets the folder associated to this Item.
0358      */
0359     void setFolder(const QString &folder);
0360 
0361     /**
0362      * This is meant to be called right after the constructor.
0363      * It sets up several items at once (so even if not inlined it's still a single call)
0364      * and it skips some calls that can be avoided at constructor time.
0365      */
0366     void initialSetup(time_t date, size_t size, const QString &sender, const QString &receiver, bool useReceiver);
0367 
0368     void setItemId(qint64 id);
0369     [[nodiscard]] qint64 itemId() const;
0370 
0371     void setParentCollectionId(qint64 id);
0372     [[nodiscard]] qint64 parentCollectionId() const;
0373 
0374     /**
0375      * This is meant to be called right after the constructor for MessageItem objects.
0376      * It sets up several items at once (so even if not inlined it's still a single call).
0377      */
0378     void setSubjectAndStatus(const QString &subject, Akonadi::MessageStatus status);
0379 
0380     /**
0381      * Appends an Item to this item's child list.
0382      * The Model is used for beginInsertRows()/endInsertRows() calls.
0383      */
0384     int appendChildItem(Model *model, Item *child);
0385 
0386     /**
0387      * Appends a child item without inserting it via the model.
0388      * This is useful in ThemeEditor which doesn't use a custom model for the items.
0389      * You shouldn't need to use this function...
0390      */
0391     void rawAppendChildItem(Item *child);
0392 
0393     /**
0394      * Removes a child from this item's child list without deleting it.
0395      * The Model is used for beginRemoveRows()/endRemoveRows() calls.
0396      */
0397     void takeChildItem(Model *model, Item *child);
0398 
0399     /**
0400      * Kills all the child items without emitting any signal, recursively.
0401      * It should be used only when MessageList::Model is reset() afterwards.
0402      */
0403     void killAllChildItems();
0404 
0405 protected:
0406     ItemPrivate *const d_ptr;
0407     Q_DECLARE_PRIVATE(Item)
0408 };
0409 } // namespace Core
0410 } // namespace MessageList