9#include "messageitem.h"
10#include "messageitem_p.h"
12#include "messagelist_debug.h"
13#include <Akonadi/Item>
14#include <Akonadi/TagAttribute>
15#include <Akonadi/TagFetchJob>
16#include <Akonadi/TagFetchScope>
18#include <KLocalizedString>
23Q_GLOBAL_STATIC(TagCache, s_tagCache)
25class MessageItem::Tag::TagPrivate
50MessageItem::Tag::~Tag() =
default;
52const QPixmap &MessageItem::Tag::pixmap()
const
57const QString &MessageItem::Tag::name()
const
62const QString &MessageItem::Tag::id()
const
67const QColor &MessageItem::Tag::textColor()
const
72const QColor &MessageItem::Tag::backgroundColor()
const
74 return d->mBackgroundColor;
77const QFont &MessageItem::Tag::font()
const
82int MessageItem::Tag::priority()
const
87void MessageItem::Tag::setTextColor(
const QColor &textColor)
89 d->mTextColor = textColor;
92void MessageItem::Tag::setBackgroundColor(
const QColor &backgroundColor)
94 d->mBackgroundColor = backgroundColor;
97void MessageItem::Tag::setFont(
const QFont &font)
102void MessageItem::Tag::setPriority(
int priority)
104 d->mPriority = priority;
107class MessageItemPrivateSettings
110 QColor mColorUnreadMessage;
111 QColor mColorImportantMessage;
114 QFont mFontUnreadMessage;
115 QFont mFontImportantMessage;
116 QFont mFontToDoMessage;
124Q_GLOBAL_STATIC(MessageItemPrivateSettings, s_settings)
126MessageItemPrivate::MessageItemPrivate(
MessageItem *qq)
131 , mAboutToBeRemoved(false)
132 , mSubjectIsPrefixed(false)
137MessageItemPrivate::~MessageItemPrivate()
139 s_tagCache->cancelRequest(
this);
140 invalidateTagCache();
143void MessageItemPrivate::invalidateTagCache()
146 qDeleteAll(*mTagList);
152const MessageItem::Tag *MessageItemPrivate::bestTag()
const
154 const MessageItem::Tag *best =
nullptr;
155 const auto tagList{getTagList()};
156 for (
const MessageItem::Tag *tag : tagList) {
157 if (!best || tag->priority() < best->priority()) {
164void MessageItemPrivate::fillTagList(
const Akonadi::Tag::List &taglist)
175 QString symbol = QStringLiteral(
"mail-tagged");
178 if (!attr->iconName().isEmpty()) {
179 symbol = attr->iconName();
185 messageListTag->setTextColor(attr->textColor());
186 messageListTag->setBackgroundColor(attr->backgroundColor());
187 if (!attr->font().isEmpty()) {
190 messageListTag->setFont(font);
193 if (attr->priority() != -1) {
194 messageListTag->setPriority(attr->priority());
196 messageListTag->setPriority(0xFFFF);
200 mTagList->append(messageListTag);
207 s_tagCache->retrieveTags(mAkonadiItem.tags(),
const_cast<MessageItemPrivate *
>(
this));
214bool MessageItemPrivate::tagListInitialized()
const
216 return mTagList !=
nullptr;
219MessageItem::MessageItem()
220 :
Item(Message, new MessageItemPrivate(this))
225MessageItem::MessageItem(MessageItemPrivate *dd)
231MessageItem::~MessageItem() =
default;
236 return d->getTagList();
239const MessageItem::Tag *MessageItemPrivate::findTagInternal(
const QString &szTagId)
const
241 const auto tagList{getTagList()};
242 for (
const MessageItem::Tag *tag : tagList) {
243 if (tag->id() == szTagId) {
253 return d->findTagInternal(szTagId);
256QString MessageItem::tagListDescription()
const
261 for (
const Tag *tag : tags) {
274 d->invalidateTagCache();
277const QColor &MessageItem::textColor()
const
280 const Tag *bestTag = d->bestTag();
281 if (bestTag !=
nullptr && bestTag->textColor().isValid()) {
282 return bestTag->textColor();
286 if (!messageStatus.
isRead()) {
287 return s_settings->mColorUnreadMessage;
289 return s_settings->mColorImportantMessage;
290 }
else if (messageStatus.
isToAct()) {
291 return s_settings->mColorToDoMessage;
293 return s_settings->mColor;
297const QColor &MessageItem::backgroundColor()
const
300 const Tag *bestTag = d->bestTag();
302 return bestTag->backgroundColor();
304 return s_settings->mBackgroundColor;
308const QFont &MessageItem::font()
const
314 if (d->tagListInitialized()) {
315 const Tag *bestTag = d->bestTag();
316 if (bestTag && bestTag->font() !=
QFont()) {
317 return bestTag->font();
324 return s_settings->mFontImportantMessage;
325 }
else if (!messageStatus.
isRead()) {
326 return s_settings->mFontUnreadMessage;
327 }
else if (messageStatus.
isToAct()) {
328 return s_settings->mFontToDoMessage;
330 return s_settings->mFont;
334MessageItem::SignatureState MessageItem::signatureState()
const
337 return d->mSignatureState;
340void MessageItem::setSignatureState(SignatureState state)
343 d->mSignatureState = state;
346MessageItem::EncryptionState MessageItem::encryptionState()
const
349 return d->mEncryptionState;
352void MessageItem::setEncryptionState(EncryptionState state)
355 d->mEncryptionState = state;
358MD5Hash MessageItem::messageIdMD5()
const
361 return d->mMessageIdMD5;
364void MessageItem::setMessageIdMD5(
MD5Hash md5)
367 d->mMessageIdMD5 = md5;
370MD5Hash MessageItem::inReplyToIdMD5()
const
373 return d->mInReplyToIdMD5;
376void MessageItem::setInReplyToIdMD5(
MD5Hash md5)
379 d->mInReplyToIdMD5 = md5;
382MD5Hash MessageItem::referencesIdMD5()
const
385 return d->mReferencesIdMD5;
388void MessageItem::setReferencesIdMD5(
MD5Hash md5)
391 d->mReferencesIdMD5 = md5;
394void MessageItem::setSubjectIsPrefixed(
bool subjectIsPrefixed)
397 d->mSubjectIsPrefixed = subjectIsPrefixed;
400bool MessageItem::subjectIsPrefixed()
const
403 return d->mSubjectIsPrefixed;
406MD5Hash MessageItem::strippedSubjectMD5()
const
409 return d->mStrippedSubjectMD5;
412void MessageItem::setStrippedSubjectMD5(
MD5Hash md5)
415 d->mStrippedSubjectMD5 = md5;
418bool MessageItem::aboutToBeRemoved()
const
421 return d->mAboutToBeRemoved;
424void MessageItem::setAboutToBeRemoved(
bool aboutToBeRemoved)
427 d->mAboutToBeRemoved = aboutToBeRemoved;
433 return d->mThreadingStatus;
436void MessageItem::setThreadingStatus(ThreadingStatus threadingStatus)
439 d->mThreadingStatus = threadingStatus;
442unsigned long MessageItem::uniqueId()
const
445 return d->mAkonadiItem.id();
448Akonadi::Item MessageList::Core::MessageItem::akonadiItem()
const
451 return d->mAkonadiItem;
454void MessageList::Core::MessageItem::setAkonadiItem(
const Akonadi::Item &item)
457 d->mAkonadiItem = item;
475 return d_ptr->mSubject;
477 return d_ptr->mSender;
479 return d_ptr->mReceiver;
497QString MessageItem::accessibleText(
const Theme *theme,
int columnIndex)
506 const auto leftItems = row->leftItems();
507 leftStrings.
reserve(leftItems.count());
509 leftStrings.
append(accessibleTextForField(contentItem->type()));
512 const auto rightItems = row->rightItems();
513 rightStrings.
reserve(rightItems.count());
515 rightStrings.
insert(rightStrings.
begin(), accessibleTextForField(contentItem->type()));
531 for (
const auto child : std::as_const(*childList)) {
537void MessageItem::setUnreadMessageColor(
const QColor &color)
539 s_settings->mColorUnreadMessage = color;
542void MessageItem::setImportantMessageColor(
const QColor &color)
544 s_settings->mColorImportantMessage = color;
547void MessageItem::setToDoMessageColor(
const QColor &color)
549 s_settings->mColorToDoMessage = color;
552void MessageItem::setGeneralFont(
const QFont &font)
554 s_settings->mFont = font;
557void MessageItem::setUnreadMessageFont(
const QFont &font)
559 s_settings->mFontUnreadMessage = font;
562void MessageItem::setImportantMessageFont(
const QFont &font)
564 s_settings->mFontImportantMessage = font;
567void MessageItem::setToDoMessageFont(
const QFont &font)
569 s_settings->mFontToDoMessage = font;
572FakeItemPrivate::FakeItemPrivate(
FakeItem *qq)
573 : MessageItemPrivate(qq)
585 qDeleteAll(d->mFakeTags);
602 , mMonitor(new
Akonadi::Monitor(this))
604 mCache.setMaxCost(100);
606 mMonitor->setTypeMonitored(Akonadi::Monitor::Tags);
607 mMonitor->tagFetchScope().fetchAttribute<Akonadi::TagAttribute>();
620 mCache.remove(tag.
id());
625 mCache.remove(tag.
id());
628void TagCache::retrieveTags(
const Akonadi::Tag::List &tags, MessageItemPrivate *m)
631 if (mRequests.key(m)) {
634 Akonadi::Tag::List toFetch;
635 Akonadi::Tag::List available;
637 if (mCache.contains(tag.
id())) {
638 available << *mCache.object(tag.
id());
644 if (!toFetch.isEmpty()) {
648 mRequests.insert(tagFetchJob, m);
650 m->fillTagList(available);
654void TagCache::cancelRequest(MessageItemPrivate *m)
657 for (
KJob *job : keys) {
658 mRequests.remove(job);
662void TagCache::onTagsFetched(
KJob *job)
665 qCWarning(MESSAGELIST_LOG) <<
"Failed to fetch tags: " << job->
errorString();
669 const auto tags{fetchJob->tags()};
673 if (
auto m = mRequests.take(fetchJob)) {
674 m->fillTagList(fetchJob->tags());
678#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.
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.
Compact storage of the result of an MD5 hash computation, for use in the threading code.
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 invalidateTagCache()
Deletes all cached tags.
@ ParentMissing
this message might belong to a thread but its parent is actually missing
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.
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 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 reserve(qsizetype size)
void setObjectName(QAnyStringView name)
bool isEmpty() const const
QString join(QChar separator) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)