9#include "messageitem.h"
10#include "messageitem_p.h"
12#include "messagelist_debug.h"
13#include <Akonadi/EntityAnnotationsAttribute>
14#include <Akonadi/Item>
15#include <Akonadi/TagAttribute>
16#include <Akonadi/TagFetchJob>
17#include <Akonadi/TagFetchScope>
19#include <KLocalizedString>
24Q_GLOBAL_STATIC(TagCache, s_tagCache)
26class MessageItem::Tag::TagPrivate
51MessageItem::Tag::~Tag() =
default;
53const QPixmap &MessageItem::Tag::pixmap()
const
58const QString &MessageItem::Tag::name()
const
63const QString &MessageItem::Tag::id()
const
68const QColor &MessageItem::Tag::textColor()
const
73const QColor &MessageItem::Tag::backgroundColor()
const
75 return d->mBackgroundColor;
78const QFont &MessageItem::Tag::font()
const
83int MessageItem::Tag::priority()
const
88void MessageItem::Tag::setTextColor(
const QColor &textColor)
90 d->mTextColor = textColor;
93void MessageItem::Tag::setBackgroundColor(
const QColor &backgroundColor)
95 d->mBackgroundColor = backgroundColor;
98void MessageItem::Tag::setFont(
const QFont &font)
103void MessageItem::Tag::setPriority(
int priority)
105 d->mPriority = priority;
108class MessageItemPrivateSettings
111 QColor mColorUnreadMessage;
112 QColor mColorImportantMessage;
115 QFont mFontUnreadMessage;
116 QFont mFontImportantMessage;
117 QFont mFontToDoMessage;
125Q_GLOBAL_STATIC(MessageItemPrivateSettings, s_settings)
127MessageItemPrivate::MessageItemPrivate(
MessageItem *qq)
132 , mAboutToBeRemoved(false)
133 , mSubjectIsPrefixed(false)
138MessageItemPrivate::~MessageItemPrivate()
140 s_tagCache->cancelRequest(
this);
141 invalidateTagCache();
144void MessageItemPrivate::invalidateTagCache()
147 qDeleteAll(*mTagList);
153void MessageItemPrivate::invalidateAnnotationCache()
157const MessageItem::Tag *MessageItemPrivate::bestTag()
const
159 const MessageItem::Tag *best =
nullptr;
160 const auto tagList{getTagList()};
161 for (
const MessageItem::Tag *tag : tagList) {
162 if (!best || tag->priority() < best->priority()) {
169void MessageItemPrivate::fillTagList(
const Akonadi::Tag::List &taglist)
180 QString symbol = QStringLiteral(
"mail-tagged");
183 if (!attr->iconName().isEmpty()) {
184 symbol = attr->iconName();
190 messageListTag->setTextColor(attr->textColor());
191 messageListTag->setBackgroundColor(attr->backgroundColor());
192 if (!attr->font().isEmpty()) {
195 messageListTag->setFont(font);
198 if (attr->priority() != -1) {
199 messageListTag->setPriority(attr->priority());
201 messageListTag->setPriority(0xFFFF);
205 mTagList->append(messageListTag);
212 s_tagCache->retrieveTags(mAkonadiItem.tags(),
const_cast<MessageItemPrivate *
>(
this));
219bool MessageItemPrivate::tagListInitialized()
const
221 return mTagList !=
nullptr;
224MessageItem::MessageItem()
225 :
Item(Message, new MessageItemPrivate(this))
230MessageItem::MessageItem(MessageItemPrivate *dd)
236MessageItem::~MessageItem() =
default;
241 return d->getTagList();
256 const auto annotations = attr->annotations();
257 QByteArray annot = annotations.value(
"/private/comment");
261 annot = annotations.value(
"/shared/comment");
274 if (mAnnotationDialog->exec()) {
277 delete mAnnotationDialog;
280const MessageItem::Tag *MessageItemPrivate::findTagInternal(
const QString &szTagId)
const
282 const auto tagList{getTagList()};
283 for (
const MessageItem::Tag *tag : tagList) {
284 if (tag->id() == szTagId) {
294 return d->findTagInternal(szTagId);
297QString MessageItem::tagListDescription()
const
302 for (
const Tag *tag : tags) {
315 d->invalidateTagCache();
321 d->invalidateAnnotationCache();
324const QColor &MessageItem::textColor()
const
327 const Tag *bestTag = d->bestTag();
328 if (bestTag !=
nullptr && bestTag->textColor().isValid()) {
329 return bestTag->textColor();
333 if (!messageStatus.
isRead()) {
334 return s_settings->mColorUnreadMessage;
336 return s_settings->mColorImportantMessage;
337 }
else if (messageStatus.
isToAct()) {
338 return s_settings->mColorToDoMessage;
340 return s_settings->mColor;
344const QColor &MessageItem::backgroundColor()
const
347 const Tag *bestTag = d->bestTag();
349 return bestTag->backgroundColor();
351 return s_settings->mBackgroundColor;
355const QFont &MessageItem::font()
const
361 if (d->tagListInitialized()) {
362 const Tag *bestTag = d->bestTag();
363 if (bestTag && bestTag->font() !=
QFont()) {
364 return bestTag->font();
371 return s_settings->mFontImportantMessage;
372 }
else if (!messageStatus.
isRead()) {
373 return s_settings->mFontUnreadMessage;
374 }
else if (messageStatus.
isToAct()) {
375 return s_settings->mFontToDoMessage;
377 return s_settings->mFont;
381MessageItem::SignatureState MessageItem::signatureState()
const
384 return d->mSignatureState;
387void MessageItem::setSignatureState(SignatureState state)
390 d->mSignatureState = state;
393MessageItem::EncryptionState MessageItem::encryptionState()
const
396 return d->mEncryptionState;
399void MessageItem::setEncryptionState(EncryptionState state)
402 d->mEncryptionState = state;
408 return d->mMessageIdMD5;
411void MessageItem::setMessageIdMD5(
const QByteArray &md5)
414 d->mMessageIdMD5 = md5;
420 return d->mInReplyToIdMD5;
423void MessageItem::setInReplyToIdMD5(
const QByteArray &md5)
426 d->mInReplyToIdMD5 = md5;
429QByteArray MessageItem::referencesIdMD5()
const
432 return d->mReferencesIdMD5;
435void MessageItem::setReferencesIdMD5(
const QByteArray &md5)
438 d->mReferencesIdMD5 = md5;
441void MessageItem::setSubjectIsPrefixed(
bool subjectIsPrefixed)
444 d->mSubjectIsPrefixed = subjectIsPrefixed;
447bool MessageItem::subjectIsPrefixed()
const
450 return d->mSubjectIsPrefixed;
453QByteArray MessageItem::strippedSubjectMD5()
const
456 return d->mStrippedSubjectMD5;
459void MessageItem::setStrippedSubjectMD5(
const QByteArray &md5)
462 d->mStrippedSubjectMD5 = md5;
465bool MessageItem::aboutToBeRemoved()
const
468 return d->mAboutToBeRemoved;
471void MessageItem::setAboutToBeRemoved(
bool aboutToBeRemoved)
474 d->mAboutToBeRemoved = aboutToBeRemoved;
480 return d->mThreadingStatus;
483void MessageItem::setThreadingStatus(ThreadingStatus threadingStatus)
486 d->mThreadingStatus = threadingStatus;
489unsigned long MessageItem::uniqueId()
const
492 return d->mAkonadiItem.id();
495Akonadi::Item MessageList::Core::MessageItem::akonadiItem()
const
498 return d->mAkonadiItem;
501void MessageList::Core::MessageItem::setAkonadiItem(
const Akonadi::Item &item)
504 d->mAkonadiItem = item;
522 return d_ptr->mSubject;
524 return d_ptr->mSender;
526 return d_ptr->mReceiver;
544QString MessageItem::accessibleText(
const Theme *theme,
int columnIndex)
553 const auto leftItems = row->leftItems();
554 leftStrings.
reserve(leftItems.count());
556 leftStrings.
append(accessibleTextForField(contentItem->type()));
559 const auto rightItems = row->rightItems();
560 rightStrings.
reserve(rightItems.count());
562 rightStrings.
insert(rightStrings.
begin(), accessibleTextForField(contentItem->type()));
578 for (
const auto child : std::as_const(*childList)) {
584void MessageItem::setUnreadMessageColor(
const QColor &color)
586 s_settings->mColorUnreadMessage = color;
589void MessageItem::setImportantMessageColor(
const QColor &color)
591 s_settings->mColorImportantMessage = color;
594void MessageItem::setToDoMessageColor(
const QColor &color)
596 s_settings->mColorToDoMessage = color;
599void MessageItem::setGeneralFont(
const QFont &font)
601 s_settings->mFont = font;
604void MessageItem::setUnreadMessageFont(
const QFont &font)
606 s_settings->mFontUnreadMessage = font;
609void MessageItem::setImportantMessageFont(
const QFont &font)
611 s_settings->mFontImportantMessage = font;
614void MessageItem::setToDoMessageFont(
const QFont &font)
616 s_settings->mFontToDoMessage = font;
619FakeItemPrivate::FakeItemPrivate(
FakeItem *qq)
620 : MessageItemPrivate(qq)
632 qDeleteAll(d->mFakeTags);
654 , mMonitor(new
Akonadi::Monitor(this))
656 mCache.setMaxCost(100);
672 mCache.remove(tag.
id());
677 mCache.remove(tag.
id());
680void TagCache::retrieveTags(
const Akonadi::Tag::List &tags, MessageItemPrivate *m)
683 if (mRequests.key(m)) {
686 Akonadi::Tag::List toFetch;
687 Akonadi::Tag::List available;
689 if (mCache.contains(tag.
id())) {
690 available << *mCache.object(tag.
id());
696 if (!toFetch.isEmpty()) {
700 mRequests.insert(tagFetchJob, m);
702 m->fillTagList(available);
706void TagCache::cancelRequest(MessageItemPrivate *m)
709 for (
KJob *job : keys) {
714void TagCache::onTagsFetched(
KJob *job)
717 qCWarning(MESSAGELIST_LOG) <<
"Failed to fetch tags: " << job->
errorString();
721 const auto tags{fetchJob->
tags()};
725 if (
auto m = mRequests.take(fetchJob)) {
726 m->fillTagList(fetchJob->tags());
730#include "moc_messageitem_p.cpp"
void tagRemoved(const Akonadi::Tag &tag)
void tagChanged(const Akonadi::Tag &tag)
void tagAdded(const Akonadi::Tag &tag)
virtual QString errorString() const
A message item that can have a fake tag list and a fake annotation.
void setFakeTags(const QList< Tag * > &tagList)
Sets a list of fake tags for this item.
QList< Tag * > tagList() const override
Reimplemented to return the fake tag list.
bool hasAnnotation() const override
Reimplemented to always return true.
const QString & senderOrReceiver() const
Returns the sender or the receiver, depending on the underlying StorageModel settings.
QString formattedDate() const
A string with a text rappresentation of date() obtained via Manager.
const Akonadi::MessageStatus & status() const
Returns the status associated to this Item.
Type type() const
Returns the type of this item.
Item * parent() const
Returns the parent Item in the tree, or 0 if this item isn't attached to the tree.
@ Message
This item is a MessageItem.
QString formattedSize() const
A string with a text rappresentation of size().
QList< Item * > * childItems() const
Return the list of child items.
const Tag * findTag(const QString &szTagId) const
Returns Tag associated to this message that has the specified id or 0 if no such tag exists.
void editAnnotation(QWidget *parent)
Shows a dialog to edit or delete the annotation.
void invalidateTagCache()
Deletes all cached tags.
@ ParentMissing
this message might belong to a thread but its parent is actually missing
virtual bool hasAnnotation() const
Returns true if this message has an annotation.
void subTreeToList(QList< MessageItem * > &list)
Appends the whole subtree originating at this item to the specified list.
virtual QList< Tag * > tagList() const
Returns the list of tags for this item.
void invalidateAnnotationCache()
Same as invalidateTagCache(), only for the annotation.
QString annotation() const
Returns the annotation of the message, given that hasAnnotation() is true.
An invariant index that can be ALWAYS used to reference an item inside a QAbstractItemModel.
const QList< Row * > & messageRows() const
Returns the list of rows visible in this column for a MessageItem.
The ContentItem class defines a content item inside a Row.
Type
The available ContentItem types.
@ CombinedReadRepliedStateIcon
The combined icon that displays the unread/read/replied/forwarded state (never disabled)
@ Date
Formatted date time of the message/group.
@ ReadStateIcon
The icon that displays the unread/read state (never disabled)
@ RepliedStateIcon
The icon that displays the replied/forwarded state (may be disabled)
@ SenderOrReceiver
From: or To: strip, depending on the folder settings.
@ Subject
Display the subject of the message item.
@ Size
Formatted size of the message.
@ Receiver
To: strip, always.
@ Sender
From: strip, always.
The Row class defines a row of items inside a Column.
The Theme class defines the visual appearance of the MessageList.
Column * column(int idx) const
Returns a pointer to the column at the specified index or 0 if there is no such column.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
The implementation independent part of the MessageList library.
bool isEmpty() const const
bool fromString(const QString &descrip)
QIcon fromTheme(const QString &name)
QString name() const const
void append(QList< T > &&value)
qsizetype count() const const
iterator insert(const_iterator before, parameter_type value)
void remove(qsizetype i, qsizetype n)
void reserve(qsizetype size)
T qobject_cast(QObject *object)
void setObjectName(QAnyStringView name)
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QString join(QChar separator) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)