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

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 "item_p.h"
0012 #include "messageitem.h"
0013 #include <Akonadi/Item>
0014 #include <Akonadi/Monitor>
0015 #include <Akonadi/Tag>
0016 #include <KJob>
0017 #include <PimCommonAkonadi/AnnotationDialog>
0018 #include <QCache>
0019 
0020 namespace MessageList
0021 {
0022 namespace Core
0023 {
0024 class MessageItemPrivate : public ItemPrivate
0025 {
0026 public:
0027     explicit MessageItemPrivate(MessageItem *qq);
0028     ~MessageItemPrivate() override;
0029 
0030     /**
0031      * Linear search in the list of tags. The lists of tags
0032      * associated to a message are supposed to be very short (c'mon.. you won't add more than a couple of tags to a single msg).
0033      * so a linear search is better than a hash lookup in most cases.
0034      */
0035     const MessageItem::Tag *findTagInternal(const QString &szTagId) const;
0036 
0037     /// Returns the list of tags. This is calculated on demand and cached in mTagList
0038     QList<MessageItem::Tag *> getTagList() const;
0039 
0040     bool tagListInitialized() const;
0041 
0042     /// Returns the tag with the highest priority, or 0 if there are no tags
0043     const MessageItem::Tag *bestTag() const;
0044 
0045     /// Deletes the internal list of tags
0046     void invalidateTagCache();
0047 
0048     /// Deletes the cache of the annotation
0049     void invalidateAnnotationCache();
0050 
0051     // This creates mTagList and fills it with useful data
0052     void fillTagList(const Akonadi::Tag::List &taglist);
0053 
0054     QByteArray mMessageIdMD5; ///< always set
0055     QByteArray mInReplyToIdMD5; ///< set only if we're doing threading
0056     QByteArray mReferencesIdMD5; ///< set only if we're doing threading
0057     QByteArray mStrippedSubjectMD5; ///< set only if we're doing threading
0058     Akonadi::Item mAkonadiItem;
0059     MessageItem::ThreadingStatus mThreadingStatus : 4;
0060     MessageItem::EncryptionState mEncryptionState : 4;
0061     MessageItem::SignatureState mSignatureState : 4;
0062 
0063     bool mAboutToBeRemoved : 1; ///< Set to true when this item is going to be deleted and shouldn't be selectable
0064     bool mSubjectIsPrefixed : 1; ///< set only if we're doing subject based threading
0065 
0066 private:
0067     // List of all tags. If this is 0, it means we have not yet calculated this list. It is calculated
0068     // on demand when needed.
0069     mutable QList<MessageItem::Tag *> *mTagList;
0070 };
0071 
0072 class FakeItemPrivate : public MessageItemPrivate
0073 {
0074 public:
0075     explicit FakeItemPrivate(FakeItem *qq);
0076     QList<MessageItem::Tag *> mFakeTags;
0077 };
0078 
0079 /**
0080  * A tag cache
0081  */
0082 class TagCache : public QObject
0083 {
0084     Q_OBJECT
0085 public:
0086     TagCache();
0087     void retrieveTags(const Akonadi::Tag::List &tags, MessageItemPrivate *m);
0088     void cancelRequest(MessageItemPrivate *m);
0089 
0090 private Q_SLOTS:
0091     void onTagAdded(const Akonadi::Tag &);
0092     void onTagChanged(const Akonadi::Tag &);
0093     void onTagRemoved(const Akonadi::Tag &);
0094     void onTagsFetched(KJob *);
0095 
0096 private:
0097     QHash<KJob *, MessageItemPrivate *> mRequests;
0098     QCache<Akonadi::Tag::Id, Akonadi::Tag> mCache;
0099     Akonadi::Monitor *mMonitor = nullptr;
0100 };
0101 }
0102 }