Messagelib

themedelegate.cpp
1/******************************************************************************
2 *
3 * SPDX-FileCopyrightText: 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 *
7 *******************************************************************************/
8
9#include "core/themedelegate.h"
10#include "core/groupheaderitem.h"
11#include "core/messageitem.h"
12#include "messagelistsettings.h"
13
14#include "MessageCore/MessageCoreSettings"
15#include "MessageCore/StringUtil"
16
17#include <KColorScheme>
18#include <QAbstractItemView>
19#include <QFont>
20#include <QFontDatabase>
21#include <QFontMetrics>
22#include <QLinearGradient>
23#include <QPainter>
24#include <QPixmap>
25#include <QStyle>
26
27using namespace MessageList::Core;
28
29static const int gGroupHeaderOuterVerticalMargin = 1;
30static const int gGroupHeaderOuterHorizontalMargin = 1;
31static const int gGroupHeaderInnerVerticalMargin = 1;
32static const int gGroupHeaderInnerHorizontalMargin = 1;
33static const int gMessageVerticalMargin = 2;
34static const int gMessageHorizontalMargin = 2;
35static const int gHorizontalItemSpacing = 2;
36
37ThemeDelegate::ThemeDelegate(QAbstractItemView *parent)
38 : QStyledItemDelegate(parent)
39 , mItemView(parent)
40{
41}
42
43ThemeDelegate::~ThemeDelegate() = default;
44
45void ThemeDelegate::setTheme(const Theme *theme)
46{
47 mTheme = theme;
48
49 if (!mTheme) {
50 return; // hum
51 }
52
53 // Rebuild the group header background color cache
54 switch (mTheme->groupHeaderBackgroundMode()) {
56 mGroupHeaderBackgroundColor = QColor(); // invalid
57 break;
59 mGroupHeaderBackgroundColor = mTheme->groupHeaderBackgroundColor();
60 break;
61 case Theme::AutoColor: {
62 QPalette pal = mItemView->palette();
65 mGroupHeaderBackgroundColor = QColor((txt.red() + (bck.red() * 3)) / 4, (txt.green() + (bck.green() * 3)) / 4, (txt.blue() + (bck.blue() * 3)) / 4);
66 break;
67 }
68 }
69
71
72 mItemView->reset();
73}
74
75enum FontType {
76 Normal,
77 Bold,
78 Italic,
79 BoldItalic,
80
81 FontTypesCount,
82};
83
84static QFont sFontCache[FontTypesCount];
85static QFontMetrics sFontMetricsCache[FontTypesCount] = {QFontMetrics(QFont()), QFontMetrics(QFont()), QFontMetrics(QFont()), QFontMetrics(QFont())};
86static int sFontHeightCache = 0;
87
88static inline const QFontMetrics &cachedFontMetrics(const Theme::ContentItem *ci)
89{
90 return (!ci->isBold() && !ci->isItalic()) ? sFontMetricsCache[Normal]
91 : (ci->isBold() && !ci->isItalic()) ? sFontMetricsCache[Bold]
92 : (!ci->isBold() && ci->isItalic()) ? sFontMetricsCache[Italic]
93 : sFontMetricsCache[BoldItalic];
94}
95
96static inline const QFont &cachedFont(const Theme::ContentItem *ci)
97{
98 return (!ci->isBold() && !ci->isItalic()) ? sFontCache[Normal]
99 : (ci->isBold() && !ci->isItalic()) ? sFontCache[Bold]
100 : (!ci->isBold() && ci->isItalic()) ? sFontCache[Italic]
101 : sFontCache[BoldItalic];
102}
103
104static inline const QFont &cachedFont(const Theme::ContentItem *ci, const Item *i)
105{
106 if (i->type() != Item::Message) {
107 return cachedFont(ci);
108 }
109
110 const auto mi = static_cast<const MessageItem *>(i);
111 const bool bold = ci->isBold() || mi->isBold();
112 const bool italic = ci->isItalic() || mi->isItalic();
113 return (!bold && !italic) ? sFontCache[Normal] : (bold && !italic) ? sFontCache[Bold] : (!bold && italic) ? sFontCache[Italic] : sFontCache[BoldItalic];
114}
115
116static inline void paint_right_aligned_elided_text(const QString &text,
118 QPainter *painter,
119 int &left,
120 int top,
121 int &right,
122 Qt::LayoutDirection layoutDir,
123 const QFont &font)
124{
125 painter->setFont(font);
126 const QFontMetrics &fontMetrics = cachedFontMetrics(ci);
127 const int w = right - left;
128 const QString elidedText = fontMetrics.elidedText(text, layoutDir == Qt::LeftToRight ? Qt::ElideLeft : Qt::ElideRight, w);
129 const QRect rct(left, top, w, sFontHeightCache);
130 QRect outRct;
131
132 if (ci->softenByBlending()) {
133 qreal oldOpacity = painter->opacity();
134 painter->setOpacity(0.6);
135 painter->drawText(rct, Qt::AlignTop | Qt::AlignRight | Qt::TextSingleLine, elidedText, &outRct);
136 painter->setOpacity(oldOpacity);
137 } else {
138 painter->drawText(rct, Qt::AlignTop | Qt::AlignRight | Qt::TextSingleLine, elidedText, &outRct);
139 }
140 if (layoutDir == Qt::LeftToRight) {
141 right -= outRct.width() + gHorizontalItemSpacing;
142 } else {
143 left += outRct.width() + gHorizontalItemSpacing;
144 }
145}
146
147static inline void compute_bounding_rect_for_right_aligned_elided_text(const QString &text,
149 int &left,
150 int top,
151 int &right,
152 QRect &outRect,
153 Qt::LayoutDirection layoutDir,
154 const QFont &font)
155{
156 Q_UNUSED(font)
157 const QFontMetrics &fontMetrics = cachedFontMetrics(ci);
158 const int w = right - left;
159 const QString elidedText = fontMetrics.elidedText(text, layoutDir == Qt::LeftToRight ? Qt::ElideLeft : Qt::ElideRight, w);
160 const QRect rct(left, top, w, sFontHeightCache);
162 outRect = fontMetrics.boundingRect(rct, Qt::AlignTop | af | Qt::TextSingleLine, elidedText);
163 if (layoutDir == Qt::LeftToRight) {
164 right -= outRect.width() + gHorizontalItemSpacing;
165 } else {
166 left += outRect.width() + gHorizontalItemSpacing;
167 }
168}
169
170static inline void paint_left_aligned_elided_text(const QString &text,
172 QPainter *painter,
173 int &left,
174 int top,
175 int &right,
176 Qt::LayoutDirection layoutDir,
177 const QFont &font)
178{
179 painter->setFont(font);
180 const QFontMetrics &fontMetrics = cachedFontMetrics(ci);
181 const int w = right - left;
182 const QString elidedText = fontMetrics.elidedText(text, layoutDir == Qt::LeftToRight ? Qt::ElideRight : Qt::ElideLeft, w);
183 const QRect rct(left, top, w, sFontHeightCache);
184 QRect outRct;
185 if (ci->softenByBlending()) {
186 qreal oldOpacity = painter->opacity();
187 painter->setOpacity(0.6);
188 painter->drawText(rct, Qt::AlignTop | Qt::AlignLeft | Qt::TextSingleLine, elidedText, &outRct);
189 painter->setOpacity(oldOpacity);
190 } else {
191 painter->drawText(rct, Qt::AlignTop | Qt::AlignLeft | Qt::TextSingleLine, elidedText, &outRct);
192 }
193 if (layoutDir == Qt::LeftToRight) {
194 left += outRct.width() + gHorizontalItemSpacing;
195 } else {
196 right -= outRct.width() + gHorizontalItemSpacing;
197 }
198}
199
200static inline void compute_bounding_rect_for_left_aligned_elided_text(const QString &text,
202 int &left,
203 int top,
204 int &right,
205 QRect &outRect,
206 Qt::LayoutDirection layoutDir,
207 const QFont &font)
208{
209 Q_UNUSED(font)
210 const QFontMetrics &fontMetrics = cachedFontMetrics(ci);
211 const int w = right - left;
212 const QString elidedText = fontMetrics.elidedText(text, layoutDir == Qt::LeftToRight ? Qt::ElideRight : Qt::ElideLeft, w);
213 const QRect rct(left, top, w, sFontHeightCache);
215 outRect = fontMetrics.boundingRect(rct, Qt::AlignTop | af | Qt::TextSingleLine, elidedText);
216 if (layoutDir == Qt::LeftToRight) {
217 left += outRect.width() + gHorizontalItemSpacing;
218 } else {
219 right -= outRect.width() + gHorizontalItemSpacing;
220 }
221}
222
223static inline const QPixmap *get_read_state_icon(const Theme *theme, Item *item)
224{
225 if (item->status().isQueued()) {
226 return theme->pixmap(Theme::IconQueued);
227 } else if (item->status().isSent()) {
228 return theme->pixmap(Theme::IconSent);
229 } else if (item->status().isRead()) {
230 return theme->pixmap(Theme::IconRead);
231 } else if (!item->status().isRead()) {
232 return theme->pixmap(Theme::IconUnread);
233 } else if (item->status().isDeleted()) {
234 return theme->pixmap(Theme::IconDeleted);
235 }
236
237 // Uhm... should never happen.. but fallback to "read"...
238 return theme->pixmap(Theme::IconRead);
239}
240
241static inline const QPixmap *get_combined_read_replied_state_icon(const Theme *theme, MessageItem *messageItem)
242{
243 if (messageItem->status().isReplied()) {
244 if (messageItem->status().isForwarded()) {
245 return theme->pixmap(Theme::IconRepliedAndForwarded);
246 }
247 return theme->pixmap(Theme::IconReplied);
248 }
249 if (messageItem->status().isForwarded()) {
250 return theme->pixmap(Theme::IconForwarded);
251 }
252
253 return get_read_state_icon(theme, messageItem);
254}
255
256static inline const QPixmap *get_encryption_state_icon(const Theme *theme, MessageItem *messageItem, bool *treatAsEnabled)
257{
258 switch (messageItem->encryptionState()) {
259 case MessageItem::FullyEncrypted:
260 *treatAsEnabled = true;
261 return theme->pixmap(Theme::IconFullyEncrypted);
262 case MessageItem::PartiallyEncrypted:
263 *treatAsEnabled = true;
264 return theme->pixmap(Theme::IconPartiallyEncrypted);
265 case MessageItem::EncryptionStateUnknown:
266 *treatAsEnabled = false;
267 return theme->pixmap(Theme::IconUndefinedEncrypted);
268 case MessageItem::NotEncrypted:
269 *treatAsEnabled = false;
270 return theme->pixmap(Theme::IconNotEncrypted);
271 default:
272 // should never happen
273 Q_ASSERT(false);
274 break;
275 }
276
277 *treatAsEnabled = false;
278 return theme->pixmap(Theme::IconUndefinedEncrypted);
279}
280
281static inline const QPixmap *get_signature_state_icon(const Theme *theme, MessageItem *messageItem, bool *treatAsEnabled)
282{
283 switch (messageItem->signatureState()) {
284 case MessageItem::FullySigned:
285 *treatAsEnabled = true;
286 return theme->pixmap(Theme::IconFullySigned);
287 case MessageItem::PartiallySigned:
288 *treatAsEnabled = true;
289 return theme->pixmap(Theme::IconPartiallySigned);
290 case MessageItem::SignatureStateUnknown:
291 *treatAsEnabled = false;
292 return theme->pixmap(Theme::IconUndefinedSigned);
293 case MessageItem::NotSigned:
294 *treatAsEnabled = false;
295 return theme->pixmap(Theme::IconNotSigned);
296 default:
297 // should never happen
298 Q_ASSERT(false);
299 break;
300 }
301
302 *treatAsEnabled = false;
303 return theme->pixmap(Theme::IconUndefinedSigned);
304}
305
306static inline const QPixmap *get_replied_state_icon(const Theme *theme, MessageItem *messageItem)
307{
308 if (messageItem->status().isReplied()) {
309 if (messageItem->status().isForwarded()) {
310 return theme->pixmap(Theme::IconRepliedAndForwarded);
311 }
312 return theme->pixmap(Theme::IconReplied);
313 }
314 if (messageItem->status().isForwarded()) {
315 return theme->pixmap(Theme::IconForwarded);
316 }
317
318 return nullptr;
319}
320
321static inline const QPixmap *get_spam_ham_state_icon(const Theme *theme, MessageItem *messageItem)
322{
323 if (messageItem->status().isSpam()) {
324 return theme->pixmap(Theme::IconSpam);
325 } else if (messageItem->status().isHam()) {
326 return theme->pixmap(Theme::IconHam);
327 }
328 return nullptr;
329}
330
331static inline const QPixmap *get_watched_ignored_state_icon(const Theme *theme, MessageItem *messageItem)
332{
333 if (messageItem->status().isIgnored()) {
334 return theme->pixmap(Theme::IconIgnored);
335 } else if (messageItem->status().isWatched()) {
336 return theme->pixmap(Theme::IconWatched);
337 }
338 return nullptr;
339}
340
341static inline void paint_vertical_line(QPainter *painter, int &left, int top, int &right, int bottom, bool alignOnRight)
342{
343 if (alignOnRight) {
344 right -= 1;
345 if (right < 0) {
346 return;
347 }
348 painter->drawLine(right, top, right, bottom);
349 right -= 2;
350 right -= gHorizontalItemSpacing;
351 } else {
352 left += 1;
353 if (left > right) {
354 return;
355 }
356 painter->drawLine(left, top, left, bottom);
357 left += 2 + gHorizontalItemSpacing;
358 }
359}
360
361static inline void compute_bounding_rect_for_vertical_line(int &left, int top, int &right, int bottom, QRect &outRect, bool alignOnRight)
362{
363 if (alignOnRight) {
364 right -= 3;
365 outRect = QRect(right, top, 3, bottom - top);
366 right -= gHorizontalItemSpacing;
367 } else {
368 outRect = QRect(left, top, 3, bottom - top);
369 left += 3 + gHorizontalItemSpacing;
370 }
371}
372
373static inline void paint_horizontal_spacer(int &left, int, int &right, int, bool alignOnRight)
374{
375 if (alignOnRight) {
376 right -= 3 + gHorizontalItemSpacing;
377 } else {
378 left += 3 + gHorizontalItemSpacing;
379 }
380}
381
382static inline void compute_bounding_rect_for_horizontal_spacer(int &left, int top, int &right, int bottom, QRect &outRect, bool alignOnRight)
383{
384 if (alignOnRight) {
385 right -= 3;
386 outRect = QRect(right, top, 3, bottom - top);
387 right -= gHorizontalItemSpacing;
388 } else {
389 outRect = QRect(left, top, 3, bottom - top);
390 left += 3 + gHorizontalItemSpacing;
391 }
392}
393
394static inline void
395paint_permanent_icon(const QPixmap *pix, Theme::ContentItem *, QPainter *painter, int &left, int top, int &right, bool alignOnRight, int iconSize)
396{
397 if (alignOnRight) {
398 right -= iconSize; // this icon is always present
399 if (right < 0) {
400 return;
401 }
402 painter->drawPixmap(right, top, iconSize, iconSize, *pix);
403 right -= gHorizontalItemSpacing;
404 } else {
405 if (left > (right - iconSize)) {
406 return;
407 }
408 painter->drawPixmap(left, top, iconSize, iconSize, *pix);
409 left += iconSize + gHorizontalItemSpacing;
410 }
411}
412
413static inline void
414compute_bounding_rect_for_permanent_icon(Theme::ContentItem *, int &left, int top, int &right, QRect &outRect, bool alignOnRight, int iconSize)
415{
416 if (alignOnRight) {
417 right -= iconSize; // this icon is always present
418 outRect = QRect(right, top, iconSize, iconSize);
419 right -= gHorizontalItemSpacing;
420 } else {
421 outRect = QRect(left, top, iconSize, iconSize);
422 left += iconSize + gHorizontalItemSpacing;
423 }
424}
425
426static inline void paint_boolean_state_icon(bool enabled,
427 const QPixmap *pix,
429 QPainter *painter,
430 int &left,
431 int top,
432 int &right,
433 bool alignOnRight,
434 int iconSize)
435{
436 if (enabled) {
437 paint_permanent_icon(pix, ci, painter, left, top, right, alignOnRight, iconSize);
438 return;
439 }
440
441 // off -> icon disabled
442 if (ci->hideWhenDisabled()) {
443 return; // doesn't even take space
444 }
445
447 // still paint, but very soft
448 qreal oldOpacity = painter->opacity();
449 painter->setOpacity(0.1);
450 paint_permanent_icon(pix, ci, painter, left, top, right, alignOnRight, iconSize);
451 painter->setOpacity(oldOpacity);
452 return;
453 }
454
455 // just takes space
456 if (alignOnRight) {
457 right -= iconSize + gHorizontalItemSpacing;
458 } else {
459 left += iconSize + gHorizontalItemSpacing;
460 }
461}
462
463static inline void compute_bounding_rect_for_boolean_state_icon(bool enabled,
465 int &left,
466 int top,
467 int &right,
468 QRect &outRect,
469 bool alignOnRight,
470 int iconSize)
471{
472 if ((!enabled) && ci->hideWhenDisabled()) {
473 outRect = QRect();
474 return; // doesn't even take space
475 }
476
477 compute_bounding_rect_for_permanent_icon(ci, left, top, right, outRect, alignOnRight, iconSize);
478}
479
480static inline void paint_tag_list(const QList<MessageItem::Tag *> &tagList, QPainter *painter, int &left, int top, int &right, bool alignOnRight, int iconSize)
481{
482 if (alignOnRight) {
483 for (const MessageItem::Tag *tag : tagList) {
484 right -= iconSize; // this icon is always present
485 if (right < 0) {
486 return;
487 }
488 painter->drawPixmap(right, top, iconSize, iconSize, tag->pixmap());
489 right -= gHorizontalItemSpacing;
490 }
491 } else {
492 for (const MessageItem::Tag *tag : tagList) {
493 if (left > right - iconSize) {
494 return;
495 }
496 painter->drawPixmap(left, top, iconSize, iconSize, tag->pixmap());
497 left += iconSize + gHorizontalItemSpacing;
498 }
499 }
500}
501
502static inline void
503compute_bounding_rect_for_tag_list(const QList<MessageItem::Tag *> &tagList, int &left, int top, int &right, QRect &outRect, bool alignOnRight, int iconSize)
504{
505 int width = tagList.count() * (iconSize + gHorizontalItemSpacing);
506 if (alignOnRight) {
507 right -= width;
508 outRect = QRect(right, top, width, iconSize);
509 } else {
510 outRect = QRect(left, top, width, iconSize);
511 left += width;
512 }
513}
514
515static inline void compute_size_hint_for_item(Theme::ContentItem *ci, int &maxh, int &totalw, int iconSize, const Item *item)
516{
517 Q_UNUSED(item)
518 if (ci->displaysText()) {
519 if (sFontHeightCache > maxh) {
520 maxh = sFontHeightCache;
521 }
522 totalw += ci->displaysLongText() ? 128 : 64;
523 return;
524 }
525
526 if (ci->isIcon()) {
527 totalw += iconSize + gHorizontalItemSpacing;
528 if (maxh < iconSize) {
529 maxh = iconSize;
530 }
531 return;
532 }
533
534 if (ci->isSpacer()) {
535 if (18 > maxh) {
536 maxh = 18;
537 }
538 totalw += 3 + gHorizontalItemSpacing;
539 return;
540 }
541
542 // should never be reached
543 if (18 > maxh) {
544 maxh = 18;
545 }
546 totalw += gHorizontalItemSpacing;
547}
548
549static inline QSize compute_size_hint_for_row(const Theme::Row *r, int iconSize, const Item *item)
550{
551 int maxh = 8; // at least 8 pixels for a pixmap
552 int totalw = 0;
553
554 // right aligned stuff first
555 auto items = r->rightItems();
556 for (const auto it : std::as_const(items)) {
557 compute_size_hint_for_item(const_cast<Theme::ContentItem *>(it), maxh, totalw, iconSize, item);
558 }
559
560 // then left aligned stuff
561 items = r->leftItems();
562 for (const auto it : std::as_const(items)) {
563 compute_size_hint_for_item(const_cast<Theme::ContentItem *>(it), maxh, totalw, iconSize, item);
564 }
565
566 return {totalw, maxh};
567}
568
569void ThemeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
570{
571 if (!index.isValid()) {
572 return; // bleah
573 }
574
575 Item *item = itemFromIndex(index);
576 if (!item) {
577 return; // hm...
578 }
579
580 QStyleOptionViewItem opt = option;
581 initStyleOption(&opt, index);
582
583 opt.text.clear(); // draw no text for me, please.. I'll do it in a while
584
585 // Set background color of control if necessary
586 if (item->type() == Item::Message) {
587 auto msgItem = static_cast<MessageItem *>(item);
588 if (msgItem->backgroundColor().isValid()) {
589 opt.backgroundBrush = QBrush(msgItem->backgroundColor());
590 }
591 }
592
593 QStyle *style = mItemView->style();
594 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, mItemView);
595
596 if (!mTheme) {
597 return; // hm hm...
598 }
599
600 const Theme::Column *skcolumn = mTheme->column(index.column());
601 if (!skcolumn) {
602 return; // bleah
603 }
604
606
607 MessageItem *messageItem = nullptr;
608 GroupHeaderItem *groupHeaderItem = nullptr;
609
610 int top = opt.rect.top();
611 int right = opt.rect.left() + opt.rect.width(); // don't use opt.rect.right() since it's screwed
612 int left = opt.rect.left();
613
614 // Storing the changed members one by one is faster than saving the painter state
615 QFont oldFont = painter->font();
616 QPen oldPen = painter->pen();
617 qreal oldOpacity = painter->opacity();
618
619 QPen defaultPen;
620 bool usingNonDefaultTextColor = false;
621
622 switch (item->type()) {
623 case Item::Message:
624 rows = &(skcolumn->messageRows());
625 messageItem = static_cast<MessageItem *>(item);
626
627 if ((!(opt.state & QStyle::State_Enabled)) || messageItem->aboutToBeRemoved() || (!messageItem->isValid())) {
628 painter->setOpacity(0.5);
629 defaultPen = QPen(opt.palette.brush(QPalette::Disabled, QPalette::Text), 0);
630 } else {
632
633 if (opt.state & QStyle::State_Active) {
634 cg = QPalette::Normal;
635 } else {
637 }
638
639 if (opt.state & QStyle::State_Selected) {
640 defaultPen = QPen(opt.palette.brush(cg, QPalette::HighlightedText), 0);
641 } else {
642 if (messageItem->textColor().isValid()) {
643 usingNonDefaultTextColor = true;
644 defaultPen = QPen(messageItem->textColor(), 0);
645 } else {
646 defaultPen = QPen(opt.palette.brush(cg, QPalette::Text), 0);
647 }
648 }
649 }
650
651 top += gMessageVerticalMargin;
652 right -= gMessageHorizontalMargin;
653 left += gMessageHorizontalMargin;
654 break;
655 case Item::GroupHeader: {
656 rows = &(skcolumn->groupHeaderRows());
657 groupHeaderItem = static_cast<GroupHeaderItem *>(item);
658
660
661 if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active)) {
663 }
664
666
667 top += gGroupHeaderOuterVerticalMargin;
668 right -= gGroupHeaderOuterHorizontalMargin;
669 left += gGroupHeaderOuterHorizontalMargin;
670
671 switch (mTheme->groupHeaderBackgroundMode()) {
674 defaultPen = QPen(opt.palette.brush(cg, cr), 0);
675 break;
676 case Theme::AutoColor:
678 switch (mTheme->groupHeaderBackgroundStyle()) {
679 case Theme::PlainRect:
680 painter->fillRect(QRect(left, top, right - left, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
681 QBrush(mGroupHeaderBackgroundColor));
682 break;
684 int rleft = (opt.viewItemPosition == QStyleOptionViewItem::Beginning) || (opt.viewItemPosition == QStyleOptionViewItem::OnlyOne)
685 ? left
686 : opt.rect.left();
687 int rright = (opt.viewItemPosition == QStyleOptionViewItem::End) || (opt.viewItemPosition == QStyleOptionViewItem::OnlyOne)
688 ? right
689 : opt.rect.left() + opt.rect.width();
690 painter->fillRect(QRect(rleft, top, rright - rleft, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
691 QBrush(mGroupHeaderBackgroundColor));
692 break;
693 }
695 if (opt.viewItemPosition == QStyleOptionViewItem::Middle) {
696 painter->fillRect(QRect(opt.rect.left(), top, opt.rect.width(), opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
697 QBrush(mGroupHeaderBackgroundColor));
698 break; // don't fall through
699 }
700 if (opt.viewItemPosition == QStyleOptionViewItem::Beginning) {
701 painter->fillRect(QRect(opt.rect.left() + opt.rect.width() - 10, top, 10, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
702 QBrush(mGroupHeaderBackgroundColor));
703 } else if (opt.viewItemPosition == QStyleOptionViewItem::End) {
704 painter->fillRect(QRect(opt.rect.left(), top, 10, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
705 QBrush(mGroupHeaderBackgroundColor));
706 }
707 // fall through anyway
708 [[fallthrough]];
709 case Theme::RoundedRect: {
710 painter->setPen(Qt::NoPen);
711 bool hadAntialiasing = painter->renderHints() & QPainter::Antialiasing;
712 if (!hadAntialiasing) {
714 }
715 painter->setBrush(QBrush(mGroupHeaderBackgroundColor));
717 int w = right - left;
718 if (w > 0) {
719 painter->drawRoundedRect(QRect(left, top, w, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)), 4.0, 4.0);
720 }
721 if (!hadAntialiasing) {
722 painter->setRenderHint(QPainter::Antialiasing, false);
723 }
725 break;
726 }
728 // FIXME: Could cache this brush
729 QLinearGradient gradient(0, top, 0, top + opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2));
730 gradient.setColorAt(0.0, KColorScheme::shade(mGroupHeaderBackgroundColor, KColorScheme::LightShade, 0.3));
731 gradient.setColorAt(1.0, mGroupHeaderBackgroundColor);
732 if (opt.viewItemPosition == QStyleOptionViewItem::Middle) {
733 painter->fillRect(QRect(opt.rect.left(), top, opt.rect.width(), opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
734 QBrush(gradient));
735 break; // don't fall through
736 }
737 if (opt.viewItemPosition == QStyleOptionViewItem::Beginning) {
738 painter->fillRect(QRect(opt.rect.left() + opt.rect.width() - 10, top, 10, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)),
739 QBrush(gradient));
740 } else if (opt.viewItemPosition == QStyleOptionViewItem::End) {
741 painter->fillRect(QRect(opt.rect.left(), top, 10, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)), QBrush(gradient));
742 }
743 // fall through anyway
744 [[fallthrough]];
745 }
746 case Theme::GradientRect: {
747 // FIXME: Could cache this brush
748 QLinearGradient gradient(0, top, 0, top + opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2));
749 gradient.setColorAt(0.0, KColorScheme::shade(mGroupHeaderBackgroundColor, KColorScheme::LightShade, 0.3));
750 gradient.setColorAt(1.0, mGroupHeaderBackgroundColor);
751 painter->setPen(Qt::NoPen);
752 bool hadAntialiasing = painter->renderHints() & QPainter::Antialiasing;
753 if (!hadAntialiasing) {
755 }
756 painter->setBrush(QBrush(gradient));
758 int w = right - left;
759 if (w > 0) {
760 painter->drawRoundedRect(QRect(left, top, w, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2)), 4.0, 4.0);
761 }
762 if (!hadAntialiasing) {
763 painter->setRenderHint(QPainter::Antialiasing, false);
764 }
766 break;
767 }
769 // oxygen, for instance, has a nice graphics for selected items
770 opt.rect = QRect(left, top, right - left, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2));
771 opt.state |= QStyle::State_Selected;
772 opt.viewItemPosition = QStyleOptionViewItem::OnlyOne;
773 opt.palette.setColor(cg, QPalette::Highlight, mGroupHeaderBackgroundColor);
774 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, mItemView);
775 break;
777 int rleft = (opt.viewItemPosition == QStyleOptionViewItem::Beginning) || (opt.viewItemPosition == QStyleOptionViewItem::OnlyOne)
778 ? left
779 : opt.rect.left();
780 int rright = (opt.viewItemPosition == QStyleOptionViewItem::End) || (opt.viewItemPosition == QStyleOptionViewItem::OnlyOne)
781 ? right
782 : opt.rect.left() + opt.rect.width();
783 opt.rect = QRect(rleft, top, rright - rleft, opt.rect.height() - (gGroupHeaderInnerVerticalMargin * 2));
784 opt.state |= QStyle::State_Selected;
785 opt.palette.setColor(cg, QPalette::Highlight, mGroupHeaderBackgroundColor);
786 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, mItemView);
787 break;
788 }
789 }
790
791 defaultPen = QPen(opt.palette.brush(cg, QPalette::Text), 0);
792 break;
793 }
794 top += gGroupHeaderInnerVerticalMargin;
795 right -= gGroupHeaderInnerHorizontalMargin;
796 left += gGroupHeaderInnerHorizontalMargin;
797 break;
798 }
799 default:
800 Q_ASSERT(false);
801 return; // bug
802 }
803
804 Qt::LayoutDirection layoutDir = mItemView->layoutDirection();
805
806 for (const auto row : std::as_const(*rows)) {
807 QSize rowSizeHint = compute_size_hint_for_row(row, mTheme->iconSize(), item);
808
809 int bottom = top + rowSizeHint.height();
810
811 // paint right aligned stuff first
812 int r = right;
813 int l = left;
814 const auto rightItems = row->rightItems();
815 for (const auto itemit : rightItems) {
816 auto ci = const_cast<Theme::ContentItem *>(itemit);
817
818 if (ci->canUseCustomColor()) {
819 if (ci->useCustomColor() && (!(opt.state & QStyle::State_Selected))) {
820 if (usingNonDefaultTextColor) {
821 // merge the colors
822 QColor nonDefault = defaultPen.color();
823 QColor custom = ci->customColor();
824 QColor merged((nonDefault.red() + custom.red()) >> 1,
825 (nonDefault.green() + custom.green()) >> 1,
826 (nonDefault.blue() + custom.blue()) >> 1);
827 painter->setPen(QPen(merged));
828 } else {
829 painter->setPen(QPen(ci->customColor()));
830 }
831 } else {
832 painter->setPen(defaultPen);
833 }
834 } // otherwise setting a pen is useless at this time
835
836 const QFont &font = cachedFont(ci, item);
837
838 switch (ci->type()) {
840 paint_right_aligned_elided_text(item->subject(), ci, painter, l, top, r, layoutDir, font);
841 break;
843 paint_right_aligned_elided_text(item->displaySenderOrReceiver(), ci, painter, l, top, r, layoutDir, font);
844 break;
846 paint_right_aligned_elided_text(item->displayReceiver(), ci, painter, l, top, r, layoutDir, font);
847 break;
849 paint_right_aligned_elided_text(item->displaySender(), ci, painter, l, top, r, layoutDir, font);
850 break;
852 paint_right_aligned_elided_text(item->formattedDate(), ci, painter, l, top, r, layoutDir, font);
853 break;
855 paint_right_aligned_elided_text(item->formattedMaxDate(), ci, painter, l, top, r, layoutDir, font);
856 break;
858 paint_right_aligned_elided_text(item->formattedSize(), ci, painter, l, top, r, layoutDir, font);
859 break;
861 paint_right_aligned_elided_text(item->folder(), ci, painter, l, top, r, layoutDir, font);
862 break;
864 if (groupHeaderItem) {
865 paint_right_aligned_elided_text(groupHeaderItem->label(), ci, painter, l, top, r, layoutDir, font);
866 }
867 break;
869 paint_permanent_icon(get_read_state_icon(mTheme, item), ci, painter, l, top, r, layoutDir == Qt::LeftToRight, mTheme->iconSize());
870 break;
872 if (messageItem) {
873 paint_permanent_icon(get_combined_read_replied_state_icon(mTheme, messageItem),
874 ci,
875 painter,
876 l,
877 top,
878 r,
879 layoutDir == Qt::LeftToRight,
880 mTheme->iconSize());
881 }
882 break;
884 const QPixmap *pix =
885 item->childItemCount() > 0 ? mTheme->pixmap((option.state & QStyle::State_Open) ? Theme::IconShowLess : Theme::IconShowMore) : nullptr;
886 paint_boolean_state_icon(pix != nullptr,
887 pix ? pix : mTheme->pixmap(Theme::IconShowMore),
888 ci,
889 painter,
890 l,
891 top,
892 r,
893 layoutDir == Qt::LeftToRight,
894 mTheme->iconSize());
895 break;
896 }
898 if (messageItem) {
899 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
900 paint_boolean_state_icon(pix != nullptr,
901 pix ? pix : mTheme->pixmap(Theme::IconReplied),
902 ci,
903 painter,
904 l,
905 top,
906 r,
907 layoutDir == Qt::LeftToRight,
908 mTheme->iconSize());
909 }
910 break;
912 if (messageItem) {
913 bool enabled;
914 const QPixmap *pix = get_encryption_state_icon(mTheme, messageItem, &enabled);
915 paint_boolean_state_icon(enabled, pix, ci, painter, l, top, r, layoutDir == Qt::LeftToRight, mTheme->iconSize());
916 }
917 break;
919 if (messageItem) {
920 bool enabled;
921 const QPixmap *pix = get_signature_state_icon(mTheme, messageItem, &enabled);
922 paint_boolean_state_icon(enabled, pix, ci, painter, l, top, r, layoutDir == Qt::LeftToRight, mTheme->iconSize());
923 }
924 break;
926 if (messageItem) {
927 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
928 paint_boolean_state_icon(pix != nullptr,
929 pix ? pix : mTheme->pixmap(Theme::IconSpam),
930 ci,
931 painter,
932 l,
933 top,
934 r,
935 layoutDir == Qt::LeftToRight,
936 mTheme->iconSize());
937 }
938 break;
940 if (messageItem) {
941 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
942 paint_boolean_state_icon(pix != nullptr,
943 pix ? pix : mTheme->pixmap(Theme::IconWatched),
944 ci,
945 painter,
946 l,
947 top,
948 r,
949 layoutDir == Qt::LeftToRight,
950 mTheme->iconSize());
951 }
952 break;
954 if (messageItem) {
955 paint_boolean_state_icon(messageItem->status().hasAttachment(),
956 mTheme->pixmap(Theme::IconAttachment),
957 ci,
958 painter,
959 l,
960 top,
961 r,
962 layoutDir == Qt::LeftToRight,
963 mTheme->iconSize());
964 }
965 break;
967 if (messageItem) {
968 paint_boolean_state_icon(messageItem->status().hasInvitation(),
969 mTheme->pixmap(Theme::IconInvitation),
970 ci,
971 painter,
972 l,
973 top,
974 r,
975 layoutDir == Qt::LeftToRight,
976 mTheme->iconSize());
977 }
978 break;
980 if (messageItem) {
981 paint_boolean_state_icon(messageItem->status().isToAct(),
982 mTheme->pixmap(Theme::IconActionItem),
983 ci,
984 painter,
985 l,
986 top,
987 r,
988 layoutDir == Qt::LeftToRight,
989 mTheme->iconSize());
990 }
991 break;
993 if (messageItem) {
994 paint_boolean_state_icon(messageItem->status().isImportant(),
995 mTheme->pixmap(Theme::IconImportant),
996 ci,
997 painter,
998 l,
999 top,
1000 r,
1001 layoutDir == Qt::LeftToRight,
1002 mTheme->iconSize());
1003 }
1004 break;
1006 paint_vertical_line(painter, l, top, r, bottom, layoutDir == Qt::LeftToRight);
1007 break;
1009 paint_horizontal_spacer(l, top, r, bottom, layoutDir == Qt::LeftToRight);
1010 break;
1012 if (messageItem) {
1013 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1014 paint_tag_list(tagList, painter, l, top, r, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1015 }
1016 break;
1017 }
1018 }
1019
1020 // then paint left aligned stuff
1021 const auto leftItems = row->leftItems();
1022 for (const auto itemit : leftItems) {
1023 auto ci = const_cast<Theme::ContentItem *>(itemit);
1024
1025 if (ci->canUseCustomColor()) {
1026 if (ci->useCustomColor() && (!(opt.state & QStyle::State_Selected))) {
1027 if (usingNonDefaultTextColor) {
1028 // merge the colors
1029 QColor nonDefault = defaultPen.color();
1030 QColor custom = ci->customColor();
1031 QColor merged((nonDefault.red() + custom.red()) >> 1,
1032 (nonDefault.green() + custom.green()) >> 1,
1033 (nonDefault.blue() + custom.blue()) >> 1);
1034 painter->setPen(QPen(merged));
1035 } else {
1036 painter->setPen(QPen(ci->customColor()));
1037 }
1038 } else {
1039 painter->setPen(defaultPen);
1040 }
1041 } // otherwise setting a pen is useless at this time
1042
1043 const QFont &font = cachedFont(ci, item);
1044
1045 switch (ci->type()) {
1047 paint_left_aligned_elided_text(item->subject(), ci, painter, l, top, r, layoutDir, font);
1048 break;
1050 paint_left_aligned_elided_text(item->displaySenderOrReceiver(), ci, painter, l, top, r, layoutDir, font);
1051 break;
1053 paint_left_aligned_elided_text(item->displayReceiver(), ci, painter, l, top, r, layoutDir, font);
1054 break;
1056 paint_left_aligned_elided_text(item->displaySender(), ci, painter, l, top, r, layoutDir, font);
1057 break;
1059 paint_left_aligned_elided_text(item->formattedDate(), ci, painter, l, top, r, layoutDir, font);
1060 break;
1062 paint_left_aligned_elided_text(item->formattedMaxDate(), ci, painter, l, top, r, layoutDir, font);
1063 break;
1065 paint_left_aligned_elided_text(item->formattedSize(), ci, painter, l, top, r, layoutDir, font);
1066 break;
1068 paint_left_aligned_elided_text(item->folder(), ci, painter, l, top, r, layoutDir, font);
1069 break;
1071 if (groupHeaderItem) {
1072 paint_left_aligned_elided_text(groupHeaderItem->label(), ci, painter, l, top, r, layoutDir, font);
1073 }
1074 break;
1076 paint_permanent_icon(get_read_state_icon(mTheme, item), ci, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1077 break;
1079 if (messageItem) {
1080 paint_permanent_icon(get_combined_read_replied_state_icon(mTheme, messageItem),
1081 ci,
1082 painter,
1083 l,
1084 top,
1085 r,
1086 layoutDir != Qt::LeftToRight,
1087 mTheme->iconSize());
1088 }
1089 break;
1091 const QPixmap *pix =
1092 item->childItemCount() > 0 ? mTheme->pixmap((option.state & QStyle::State_Open) ? Theme::IconShowLess : Theme::IconShowMore) : nullptr;
1093 paint_boolean_state_icon(pix != nullptr,
1094 pix ? pix : mTheme->pixmap(Theme::IconShowMore),
1095 ci,
1096 painter,
1097 l,
1098 top,
1099 r,
1100 layoutDir != Qt::LeftToRight,
1101 mTheme->iconSize());
1102 break;
1103 }
1105 if (messageItem) {
1106 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
1107 paint_boolean_state_icon(pix != nullptr,
1108 pix ? pix : mTheme->pixmap(Theme::IconReplied),
1109 ci,
1110 painter,
1111 l,
1112 top,
1113 r,
1114 layoutDir != Qt::LeftToRight,
1115 mTheme->iconSize());
1116 }
1117 break;
1119 if (messageItem) {
1120 bool enabled;
1121 const QPixmap *pix = get_encryption_state_icon(mTheme, messageItem, &enabled);
1122 paint_boolean_state_icon(enabled, pix, ci, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1123 }
1124 break;
1126 if (messageItem) {
1127 bool enabled;
1128 const QPixmap *pix = get_signature_state_icon(mTheme, messageItem, &enabled);
1129 paint_boolean_state_icon(enabled, pix, ci, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1130 }
1131 break;
1133 if (messageItem) {
1134 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
1135 paint_boolean_state_icon(pix != nullptr,
1136 pix ? pix : mTheme->pixmap(Theme::IconSpam),
1137 ci,
1138 painter,
1139 l,
1140 top,
1141 r,
1142 layoutDir != Qt::LeftToRight,
1143 mTheme->iconSize());
1144 }
1145 break;
1147 if (messageItem) {
1148 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
1149 paint_boolean_state_icon(pix != nullptr,
1150 pix ? pix : mTheme->pixmap(Theme::IconWatched),
1151 ci,
1152 painter,
1153 l,
1154 top,
1155 r,
1156 layoutDir != Qt::LeftToRight,
1157 mTheme->iconSize());
1158 }
1159 break;
1161 if (messageItem) {
1162 paint_boolean_state_icon(messageItem->status().hasAttachment(),
1163 mTheme->pixmap(Theme::IconAttachment),
1164 ci,
1165 painter,
1166 l,
1167 top,
1168 r,
1169 layoutDir != Qt::LeftToRight,
1170 mTheme->iconSize());
1171 }
1172 break;
1174 if (messageItem) {
1175 paint_boolean_state_icon(messageItem->status().hasInvitation(),
1176 mTheme->pixmap(Theme::IconInvitation),
1177 ci,
1178 painter,
1179 l,
1180 top,
1181 r,
1182 layoutDir != Qt::LeftToRight,
1183 mTheme->iconSize());
1184 }
1185 break;
1187 if (messageItem) {
1188 paint_boolean_state_icon(messageItem->status().isToAct(),
1189 mTheme->pixmap(Theme::IconActionItem),
1190 ci,
1191 painter,
1192 l,
1193 top,
1194 r,
1195 layoutDir != Qt::LeftToRight,
1196 mTheme->iconSize());
1197 }
1198 break;
1200 if (messageItem) {
1201 paint_boolean_state_icon(messageItem->status().isImportant(),
1202 mTheme->pixmap(Theme::IconImportant),
1203 ci,
1204 painter,
1205 l,
1206 top,
1207 r,
1208 layoutDir != Qt::LeftToRight,
1209 mTheme->iconSize());
1210 }
1211 break;
1213 paint_vertical_line(painter, l, top, r, bottom, layoutDir != Qt::LeftToRight);
1214 break;
1216 paint_horizontal_spacer(l, top, r, bottom, layoutDir != Qt::LeftToRight);
1217 break;
1219 if (messageItem) {
1220 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1221 paint_tag_list(tagList, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1222 }
1223 break;
1224 }
1225 }
1226
1227 top = bottom;
1228 }
1229
1230 painter->setFont(oldFont);
1231 painter->setPen(oldPen);
1232 painter->setOpacity(oldOpacity);
1233}
1234
1235bool ThemeDelegate::hitTest(const QPoint &viewportPoint, bool exact)
1236{
1237 mHitItem = nullptr;
1238 mHitColumn = nullptr;
1239 mHitRow = nullptr;
1240 mHitContentItem = nullptr;
1241
1242 if (!mTheme) {
1243 return false; // hm hm...
1244 }
1245
1246 mHitIndex = mItemView->indexAt(viewportPoint);
1247
1248 if (!mHitIndex.isValid()) {
1249 return false; // bleah
1250 }
1251
1252 mHitItem = itemFromIndex(mHitIndex);
1253 if (!mHitItem) {
1254 return false; // hm...
1255 }
1256
1257 mHitItemRect = mItemView->visualRect(mHitIndex);
1258
1259 mHitColumn = mTheme->column(mHitIndex.column());
1260 if (!mHitColumn) {
1261 return false; // bleah
1262 }
1263
1264 const QList<Theme::Row *> *rows; // I'd like to have it as reference, but gcc complains...
1265
1266 MessageItem *messageItem = nullptr;
1267 GroupHeaderItem *groupHeaderItem = nullptr;
1268
1269 int top = mHitItemRect.top();
1270 int right = mHitItemRect.right();
1271 int left = mHitItemRect.left();
1272
1273 mHitRow = nullptr;
1274 mHitRowIndex = -1;
1275 mHitContentItem = nullptr;
1276
1277 switch (mHitItem->type()) {
1278 case Item::Message:
1279 mHitRowIsMessageRow = true;
1280 rows = &(mHitColumn->messageRows());
1281 messageItem = static_cast<MessageItem *>(mHitItem);
1282 // FIXME: paint eventual background here
1283
1284 top += gMessageVerticalMargin;
1285 right -= gMessageHorizontalMargin;
1286 left += gMessageHorizontalMargin;
1287 break;
1288 case Item::GroupHeader:
1289 mHitRowIsMessageRow = false;
1290 rows = &(mHitColumn->groupHeaderRows());
1291 groupHeaderItem = static_cast<GroupHeaderItem *>(mHitItem);
1292
1293 top += gGroupHeaderOuterVerticalMargin + gGroupHeaderInnerVerticalMargin;
1294 right -= gGroupHeaderOuterHorizontalMargin + gGroupHeaderInnerHorizontalMargin;
1295 left += gGroupHeaderOuterHorizontalMargin + gGroupHeaderInnerHorizontalMargin;
1296 break;
1297 default:
1298 return false; // bug
1299 break;
1300 }
1301
1302 int rowIdx = 0;
1303 int bestInexactDistance = 0xffffff;
1304 bool bestInexactItemRight = false;
1305 QRect bestInexactRect;
1306 const Theme::ContentItem *bestInexactContentItem = nullptr;
1307
1308 Qt::LayoutDirection layoutDir = mItemView->layoutDirection();
1309
1310 for (const auto row : std::as_const(*rows)) {
1311 QSize rowSizeHint = compute_size_hint_for_row(row, mTheme->iconSize(), mHitItem);
1312
1313 if ((viewportPoint.y() < top) && (rowIdx > 0)) {
1314 break; // not this row (tough we should have already found it... probably clicked upper margin)
1315 }
1316
1317 int bottom = top + rowSizeHint.height();
1318
1319 if (viewportPoint.y() > bottom) {
1320 top += rowSizeHint.height();
1321 rowIdx++;
1322 continue; // not this row
1323 }
1324
1325 bestInexactItemRight = false;
1326 bestInexactDistance = 0xffffff;
1327 bestInexactContentItem = nullptr;
1328
1329 // this row!
1330 mHitRow = row;
1331 mHitRowIndex = rowIdx;
1332 mHitRowRect = QRect(left, top, right - left, bottom - top);
1333
1334 // check right aligned stuff first
1335 mHitContentItemRight = true;
1336
1337 int r = right;
1338 int l = left;
1339 const auto rightItems = mHitRow->rightItems();
1340 for (const auto itemit : rightItems) {
1341 auto ci = const_cast<Theme::ContentItem *>(itemit);
1342
1343 mHitContentItemRect = QRect();
1344
1345 const QFont &font = cachedFont(ci, mHitItem);
1346
1347 switch (ci->type()) {
1349 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->subject(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1350 break;
1352 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->displaySenderOrReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1353 break;
1355 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->displayReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1356 break;
1358 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->displaySender(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1359 break;
1361 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->formattedDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1362 break;
1364 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->formattedMaxDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1365 break;
1367 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->formattedSize(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1368 break;
1370 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->folder(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1371 break;
1373 if (groupHeaderItem) {
1374 compute_bounding_rect_for_right_aligned_elided_text(groupHeaderItem->label(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1375 }
1376 break;
1378 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1379 break;
1381 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1382 break;
1384 compute_bounding_rect_for_boolean_state_icon(mHitItem->childItemCount() > 0,
1385 ci,
1386 l,
1387 top,
1388 r,
1389 mHitContentItemRect,
1390 layoutDir == Qt::LeftToRight,
1391 mTheme->iconSize());
1392 break;
1394 if (messageItem) {
1395 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
1396 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1397 ci,
1398 l,
1399 top,
1400 r,
1401 mHitContentItemRect,
1402 layoutDir == Qt::LeftToRight,
1403 mTheme->iconSize());
1404 }
1405 break;
1407 if (messageItem) {
1408 bool enabled;
1409 get_encryption_state_icon(mTheme, messageItem, &enabled);
1410 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1411 }
1412 break;
1414 if (messageItem) {
1415 bool enabled;
1416 get_signature_state_icon(mTheme, messageItem, &enabled);
1417 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1418 }
1419 break;
1421 if (messageItem) {
1422 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
1423 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1424 ci,
1425 l,
1426 top,
1427 r,
1428 mHitContentItemRect,
1429 layoutDir == Qt::LeftToRight,
1430 mTheme->iconSize());
1431 }
1432 break;
1434 if (messageItem) {
1435 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
1436 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1437 ci,
1438 l,
1439 top,
1440 r,
1441 mHitContentItemRect,
1442 layoutDir == Qt::LeftToRight,
1443 mTheme->iconSize());
1444 }
1445 break;
1447 if (messageItem) {
1448 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasAttachment(),
1449 ci,
1450 l,
1451 top,
1452 r,
1453 mHitContentItemRect,
1454 layoutDir == Qt::LeftToRight,
1455 mTheme->iconSize());
1456 }
1457 break;
1459 if (messageItem) {
1460 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasInvitation(),
1461 ci,
1462 l,
1463 top,
1464 r,
1465 mHitContentItemRect,
1466 layoutDir == Qt::LeftToRight,
1467 mTheme->iconSize());
1468 }
1469 break;
1471 if (messageItem) {
1472 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isToAct(),
1473 ci,
1474 l,
1475 top,
1476 r,
1477 mHitContentItemRect,
1478 layoutDir == Qt::LeftToRight,
1479 mTheme->iconSize());
1480 }
1481 break;
1483 if (messageItem) {
1484 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isImportant(),
1485 ci,
1486 l,
1487 top,
1488 r,
1489 mHitContentItemRect,
1490 layoutDir == Qt::LeftToRight,
1491 mTheme->iconSize());
1492 }
1493 break;
1495 compute_bounding_rect_for_vertical_line(l, top, r, bottom, mHitContentItemRect, layoutDir == Qt::LeftToRight);
1496 break;
1498 compute_bounding_rect_for_horizontal_spacer(l, top, r, bottom, mHitContentItemRect, layoutDir == Qt::LeftToRight);
1499 break;
1501 if (messageItem) {
1502 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1503 compute_bounding_rect_for_tag_list(tagList, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1504 }
1505 break;
1506 }
1507
1508 if (mHitContentItemRect.isValid()) {
1509 if (mHitContentItemRect.contains(viewportPoint)) {
1510 // caught!
1511 mHitContentItem = ci;
1512 return true;
1513 }
1514 if (!exact) {
1515 QRect inexactRect(mHitContentItemRect.left(), mHitRowRect.top(), mHitContentItemRect.width(), mHitRowRect.height());
1516 if (inexactRect.contains(viewportPoint)) {
1517 mHitContentItem = ci;
1518 return true;
1519 }
1520
1521 int inexactDistance =
1522 viewportPoint.x() > inexactRect.right() ? viewportPoint.x() - inexactRect.right() : inexactRect.left() - viewportPoint.x();
1523 if (inexactDistance < bestInexactDistance) {
1524 bestInexactDistance = inexactDistance;
1525 bestInexactRect = mHitContentItemRect;
1526 bestInexactItemRight = true;
1527 bestInexactContentItem = ci;
1528 }
1529 }
1530 }
1531 }
1532
1533 // then check left aligned stuff
1534 mHitContentItemRight = false;
1535
1536 const auto leftItems = mHitRow->leftItems();
1537 for (const auto itemit : leftItems) {
1538 auto ci = const_cast<Theme::ContentItem *>(itemit);
1539
1540 mHitContentItemRect = QRect();
1541
1542 const QFont &font = cachedFont(ci, mHitItem);
1543
1544 switch (ci->type()) {
1546 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->subject(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1547 break;
1549 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->displaySenderOrReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1550 break;
1552 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->displayReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1553 break;
1555 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->displaySender(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1556 break;
1558 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->formattedDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1559 break;
1561 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->formattedMaxDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1562 break;
1564 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->formattedSize(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1565 break;
1567 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->folder(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1568 break;
1570 if (groupHeaderItem) {
1571 compute_bounding_rect_for_left_aligned_elided_text(groupHeaderItem->label(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1572 }
1573 break;
1575 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1576 break;
1578 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1579 break;
1581 compute_bounding_rect_for_boolean_state_icon(mHitItem->childItemCount() > 0,
1582 ci,
1583 l,
1584 top,
1585 r,
1586 mHitContentItemRect,
1587 layoutDir != Qt::LeftToRight,
1588 mTheme->iconSize());
1589 break;
1591 if (messageItem) {
1592 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
1593 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1594 ci,
1595 l,
1596 top,
1597 r,
1598 mHitContentItemRect,
1599 layoutDir != Qt::LeftToRight,
1600 mTheme->iconSize());
1601 }
1602 break;
1604 if (messageItem) {
1605 bool enabled;
1606 get_encryption_state_icon(mTheme, messageItem, &enabled);
1607 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1608 }
1609 break;
1611 if (messageItem) {
1612 bool enabled;
1613 get_signature_state_icon(mTheme, messageItem, &enabled);
1614 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1615 }
1616 break;
1618 if (messageItem) {
1619 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
1620 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1621 ci,
1622 l,
1623 top,
1624 r,
1625 mHitContentItemRect,
1626 layoutDir != Qt::LeftToRight,
1627 mTheme->iconSize());
1628 }
1629 break;
1631 if (messageItem) {
1632 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
1633 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1634 ci,
1635 l,
1636 top,
1637 r,
1638 mHitContentItemRect,
1639 layoutDir != Qt::LeftToRight,
1640 mTheme->iconSize());
1641 }
1642 break;
1644 if (messageItem) {
1645 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasAttachment(),
1646 ci,
1647 l,
1648 top,
1649 r,
1650 mHitContentItemRect,
1651 layoutDir != Qt::LeftToRight,
1652 mTheme->iconSize());
1653 }
1654 break;
1656 if (messageItem) {
1657 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasInvitation(),
1658 ci,
1659 l,
1660 top,
1661 r,
1662 mHitContentItemRect,
1663 layoutDir != Qt::LeftToRight,
1664 mTheme->iconSize());
1665 }
1666 break;
1668 if (messageItem) {
1669 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isToAct(),
1670 ci,
1671 l,
1672 top,
1673 r,
1674 mHitContentItemRect,
1675 layoutDir != Qt::LeftToRight,
1676 mTheme->iconSize());
1677 }
1678 break;
1680 if (messageItem) {
1681 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isImportant(),
1682 ci,
1683 l,
1684 top,
1685 r,
1686 mHitContentItemRect,
1687 layoutDir != Qt::LeftToRight,
1688 mTheme->iconSize());
1689 }
1690 break;
1692 compute_bounding_rect_for_vertical_line(l, top, r, bottom, mHitContentItemRect, layoutDir != Qt::LeftToRight);
1693 break;
1695 compute_bounding_rect_for_horizontal_spacer(l, top, r, bottom, mHitContentItemRect, layoutDir != Qt::LeftToRight);
1696 break;
1698 if (messageItem) {
1699 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1700 compute_bounding_rect_for_tag_list(tagList, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1701 }
1702 break;
1703 }
1704
1705 if (mHitContentItemRect.isValid()) {
1706 if (mHitContentItemRect.contains(viewportPoint)) {
1707 // caught!
1708 mHitContentItem = ci;
1709 return true;
1710 }
1711 if (!exact) {
1712 QRect inexactRect(mHitContentItemRect.left(), mHitRowRect.top(), mHitContentItemRect.width(), mHitRowRect.height());
1713 if (inexactRect.contains(viewportPoint)) {
1714 mHitContentItem = ci;
1715 return true;
1716 }
1717
1718 int inexactDistance =
1719 viewportPoint.x() > inexactRect.right() ? viewportPoint.x() - inexactRect.right() : inexactRect.left() - viewportPoint.x();
1720 if (inexactDistance < bestInexactDistance) {
1721 bestInexactDistance = inexactDistance;
1722 bestInexactRect = mHitContentItemRect;
1723 bestInexactItemRight = false;
1724 bestInexactContentItem = ci;
1725 }
1726 }
1727 }
1728 }
1729
1730 top += rowSizeHint.height();
1731 rowIdx++;
1732 }
1733
1734 mHitContentItem = bestInexactContentItem;
1735 mHitContentItemRight = bestInexactItemRight;
1736 mHitContentItemRect = bestInexactRect;
1737 return true;
1738}
1739
1741{
1742 return mHitIndex;
1743}
1744
1746{
1747 return mHitItem;
1748}
1749
1751{
1752 return mHitItemRect;
1753}
1754
1756{
1757 return mHitColumn;
1758}
1759
1761{
1762 return mHitIndex.column();
1763}
1764
1766{
1767 return mHitRow;
1768}
1769
1771{
1772 return mHitRowIndex;
1773}
1774
1776{
1777 return mHitRowRect;
1778}
1779
1781{
1782 return mHitRowIsMessageRow;
1783}
1784
1786{
1787 return mHitContentItem;
1788}
1789
1791{
1792 return mHitContentItemRight;
1793}
1794
1796{
1797 return mHitContentItemRect;
1798}
1799
1801{
1802 if (!mTheme) {
1803 return {16, 16}; // bleah
1804 }
1805
1806 const Theme::Column *skcolumn = mTheme->column(column);
1807 if (!skcolumn) {
1808 return {16, 16}; // bleah
1809 }
1810
1811 const QList<Theme::Row *> *rows; // I'd like to have it as reference, but gcc complains...
1812
1813 // The sizeHint() is layout direction independent.
1814
1815 int marginw;
1816 int marginh;
1817
1818 switch (type) {
1819 case Item::Message:
1820 rows = &(skcolumn->messageRows());
1821
1822 marginh = gMessageVerticalMargin << 1;
1823 marginw = gMessageHorizontalMargin << 1;
1824 break;
1825 case Item::GroupHeader:
1826 rows = &(skcolumn->groupHeaderRows());
1827
1828 marginh = (gGroupHeaderOuterVerticalMargin + gGroupHeaderInnerVerticalMargin) << 1;
1829 marginw = (gGroupHeaderOuterVerticalMargin + gGroupHeaderInnerVerticalMargin) << 1;
1830 break;
1831 default:
1832 return {16, 16}; // bug
1833 break;
1834 }
1835
1836 int totalh = 0;
1837 int maxw = 0;
1838
1839 for (QList<Theme::Row *>::ConstIterator rowit = rows->constBegin(), endRowIt = rows->constEnd(); rowit != endRowIt; ++rowit) {
1840 const QSize sh = compute_size_hint_for_row((*rowit), mTheme->iconSize(), item);
1841 totalh += sh.height();
1842 if (sh.width() > maxw) {
1843 maxw = sh.width();
1844 }
1845 }
1846
1847 return {maxw + marginw, totalh + marginh};
1848}
1849
1851{
1852 if (!mTheme || !index.isValid()) {
1853 return {16, 16}; // hm hm...
1854 }
1855
1856 Item *item = itemFromIndex(index);
1857 if (!item) {
1858 return {16, 16}; // hm...
1859 }
1860
1861 const Item::Type type = item->type();
1862 if (type == Item::Message) {
1863 if (!mCachedMessageItemSizeHint.isValid()) {
1864 mCachedMessageItemSizeHint = sizeHintForItemTypeAndColumn(Item::Message, index.column(), item);
1865 }
1866 return mCachedMessageItemSizeHint;
1867 } else if (type == Item::GroupHeader) {
1868 if (!mCachedGroupHeaderItemSizeHint.isValid()) {
1869 mCachedGroupHeaderItemSizeHint = sizeHintForItemTypeAndColumn(Item::GroupHeader, index.column(), item);
1870 }
1871 return mCachedGroupHeaderItemSizeHint;
1872 } else {
1873 Q_ASSERT(false);
1874 return {};
1875 }
1876}
1877
1878// Store the new fonts when the generalFont changes and flush sizeHint cache
1880{
1881 mCachedMessageItemSizeHint = QSize();
1882 mCachedGroupHeaderItemSizeHint = QSize();
1883
1884 QFont font;
1885 if (MessageCore::MessageCoreSettings::self()->useDefaultFonts()) {
1887 } else {
1888 font = MessageListSettings::self()->messageListFont();
1889 }
1890 sFontCache[Normal] = font;
1891 sFontMetricsCache[Normal] = QFontMetrics(font);
1892 font.setBold(true);
1893 sFontCache[Bold] = font;
1894 sFontMetricsCache[Bold] = QFontMetrics(font);
1895 font.setBold(false);
1896 font.setItalic(true);
1897 sFontCache[Italic] = font;
1898 sFontMetricsCache[Italic] = QFontMetrics(font);
1899 font.setBold(true);
1900 font.setItalic(true);
1901 sFontCache[BoldItalic] = font;
1902 sFontMetricsCache[BoldItalic] = QFontMetrics(font);
1903
1904 sFontHeightCache = sFontMetricsCache[Normal].height();
1905}
1906
1907const Theme *ThemeDelegate::theme() const
1908{
1909 return mTheme;
1910}
1911
1912#include "moc_themedelegate.cpp"
bool isWatched() const
bool isImportant() const
bool isIgnored() const
bool hasInvitation() const
bool isForwarded() const
bool hasAttachment() const
bool isReplied() const
QColor shade(ShadeRole) const
A single item of the MessageList tree managed by MessageList::Model.
Definition item.h:36
QString formattedMaxDate() const
A string with a text rappresentation of maxDate() obtained via Manager.
Definition item.cpp:314
QString formattedDate() const
A string with a text rappresentation of date() obtained via Manager.
Definition item.cpp:305
const Akonadi::MessageStatus & status() const
Returns the status associated to this Item.
Definition item.cpp:446
Type type() const
Returns the type of this item.
Definition item.cpp:342
const QString & folder() const
Returns the folder associated to this Item.
Definition item.cpp:541
QString displayReceiver() const
Display receiver.
Definition item.cpp:511
QString displaySenderOrReceiver() const
Display sender or receiver.
Definition item.cpp:521
Type
The type of the Item.
Definition item.h:44
@ Message
This item is a MessageItem.
Definition item.h:46
@ GroupHeader
This item is a GroupHeaderItem.
Definition item.h:45
QString formattedSize() const
A string with a text rappresentation of size().
Definition item.cpp:299
int childItemCount() const
Returns the number of children of this Item.
Definition item.cpp:157
const QString & subject() const
Returns the subject associated to this Item.
Definition item.cpp:531
QString displaySender() const
Display sender.
Definition item.cpp:496
The MessageItem class.
Definition messageitem.h:35
virtual QList< Tag * > tagList() const
Returns the list of tags for this item.
bool isValid() const
Returns true if this ModelInvariantIndex is valid, that is, it has been attached to a ModelInvariantR...
QRect hitRowRect() const
Returns the rectangle of the row that was reported as hit by the previous call to hitTest().
const Theme::Column * hitColumn() const
Returns the theme column that was reported as hit by the previous call to hitTest().
bool hitTest(const QPoint &viewportPoint, bool exact=true)
Performs a hit test on the specified viewport point.
bool hitContentItemRight() const
Returns true if the hit theme content item was a right item and false otherwise.
Item * hitItem() const
Returns the Item that was reported as hit by the previous call to hitTest().
QRect hitContentItemRect() const
Returns the bounding rect of the content item that was reported as hit by the previous call to hitTes...
const Theme::ContentItem * hitContentItem() const
Returns the theme content item that was reported as hit by the previous call to hitTest().
QSize sizeHintForItemTypeAndColumn(Item::Type type, int column, const Item *item=nullptr) const
Returns a heuristic sizeHint() for the specified item type and column.
int hitColumnIndex() const
Returns the index of the theme column that was reported as hit by the previous call to hitTest().
void generalFontChanged()
Called when the global fonts change (from systemsettings)
virtual Item * itemFromIndex(const QModelIndex &index) const =0
Returns the Item for the specified model index.
const QModelIndex & hitIndex() const
Returns the model index that was reported as hit by the previous call to hitTest().
bool hitRowIsMessageRow() const
Returns true if the hitRow() is a message row, false otherwise.
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
Reimplemented from QStyledItemDelegate.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Reimplemented from QStyledItemDelegate.
const Theme::Row * hitRow() const
Returns the theme row that was reported as hit by the previous call to hitTest().
QRect hitItemRect() const
Returns the visual rectangle of the item that was reported as hit by the previous call to hitTest().
int hitRowIndex() const
Returns the index of the theme row that was reported as hit by the previous call to hitTest().
The Column class defines a view column available inside this theme.
Definition theme.h:501
const QList< Row * > & groupHeaderRows() const
Returns the list of rows visible in this column for a GroupHeaderItem.
Definition theme.cpp:743
const QList< Row * > & messageRows() const
Returns the list of rows visible in this column for a MessageItem.
Definition theme.cpp:700
The ContentItem class defines a content item inside a Row.
Definition theme.h:56
bool displaysText() const
Returns true if this item displays some kind of text.
Definition theme.cpp:77
bool hideWhenDisabled() const
Returns true if this item should be hidden when in disabled state.
Definition theme.cpp:223
bool isSpacer() const
Returns true if this item is a small spacer.
Definition theme.cpp:97
bool isBold() const
Returns true if this item uses a bold text.
Definition theme.cpp:195
Type type() const
Returns the type of this content item.
Definition theme.cpp:62
bool canUseCustomColor() const
Returns true if this ContentItem can make use of a custom color.
Definition theme.cpp:72
bool useCustomColor() const
Returns true if this item uses a custom color.
Definition theme.cpp:181
bool isIcon() const
Returns true if this item displays an icon.
Definition theme.cpp:87
bool softenByBlending() const
Returns true if this item should be always painted in a "soft" fashion.
Definition theme.cpp:251
bool softenByBlendingWhenDisabled() const
Returns true if this item should be painted in a "soft" fashion when in disabled state.
Definition theme.cpp:237
@ InvitationIcon
Whether the message is an invitation.
Definition theme.h:198
@ CombinedReadRepliedStateIcon
The combined icon that displays the unread/read/replied/forwarded state (never disabled)
Definition theme.h:190
@ SignatureStateIcon
The Signature state icon for messages.
Definition theme.h:174
@ Date
Formatted date time of the message/group.
Definition theme.h:114
@ MostRecentDate
The date of the most recent message in subtree.
Definition theme.h:186
@ ReadStateIcon
The icon that displays the unread/read state (never disabled)
Definition theme.h:134
@ RepliedStateIcon
The icon that displays the replied/forwarded state (may be disabled)
Definition theme.h:142
@ WatchedIgnoredStateIcon
The Watched/Ignored state icon.
Definition theme.h:162
@ ImportantStateIcon
The Important tag icon.
Definition theme.h:154
@ Folder
Folder of the message.
Definition theme.h:202
@ AttachmentStateIcon
The icon that displays the attachment state (may be disabled)
Definition theme.h:138
@ ExpandedStateIcon
The Expanded state icon for group headers.
Definition theme.h:166
@ SenderOrReceiver
From: or To: strip, depending on the folder settings.
Definition theme.h:118
@ GroupHeaderLabel
The group header label.
Definition theme.h:146
@ Subject
Display the subject of the message item.
Definition theme.h:110
@ VerticalLine
A vertical separation line.
Definition theme.h:178
@ HorizontalSpacer
A small empty spacer usable as separator.
Definition theme.h:182
@ EncryptionStateIcon
The Encryption state icon for messages.
Definition theme.h:170
@ TagList
The list of MessageItem::Tag entries.
Definition theme.h:194
@ Size
Formatted size of the message.
Definition theme.h:130
@ Receiver
To: strip, always.
Definition theme.h:126
@ ActionItemStateIcon
The ActionItem state icon.
Definition theme.h:150
@ Sender
From: strip, always.
Definition theme.h:122
@ SpamHamStateIcon
The Spam/Ham state icon.
Definition theme.h:158
const QColor & customColor() const
Returns the custom color set for this item.
Definition theme.cpp:265
bool displaysLongText() const
Returns true if this item displays a long text.
Definition theme.cpp:82
bool isItalic() const
Returns true if this item uses an italic text.
Definition theme.cpp:209
The Row class defines a row of items inside a Column.
Definition theme.h:408
const QList< ContentItem * > & rightItems() const
Returns the list of right aligned items for this row.
Definition theme.cpp:398
const QList< ContentItem * > & leftItems() const
Returns the list of left aligned items for this row.
Definition theme.cpp:489
The Theme class defines the visual appearance of the MessageList.
Definition theme.h:48
@ Transparent
No background at all: use style default.
Definition theme.h:794
@ CustomColor
Use a custom color.
Definition theme.h:796
@ AutoColor
Automatically determine the color (somewhere in the middle between background and text)
Definition theme.h:795
const QColor & groupHeaderBackgroundColor() const
Returns the group header background color for this theme.
Definition theme.cpp:1007
GroupHeaderBackgroundMode groupHeaderBackgroundMode() const
Returns the group header background mode for this theme.
Definition theme.cpp:986
GroupHeaderBackgroundStyle groupHeaderBackgroundStyle() const
Returns the group header background style for this theme.
Definition theme.cpp:1017
int iconSize() const
Returns the currently set icon size.
Definition theme.cpp:1054
Column * column(int idx) const
Returns a pointer to the column at the specified index or 0 if there is no such column.
Definition theme.cpp:955
@ RoundedJoinedRect
One big rounded rect for all the columns.
Definition theme.h:806
@ PlainRect
One plain rect per column.
Definition theme.h:803
@ GradientRect
One rounded gradient filled rect per column.
Definition theme.h:807
@ StyledRect
One styled rect per column.
Definition theme.h:809
@ RoundedRect
One rounded rect per column.
Definition theme.h:805
@ StyledJoinedRect
One big styled rect per column.
Definition theme.h:810
@ PlainJoinedRect
One big plain rect for all the columns.
Definition theme.h:804
@ GradientJoinedRect
One big rounded gradient rect for all the columns.
Definition theme.h:808
The implementation independent part of the MessageList library.
Definition aggregation.h:22
virtual QModelIndex indexAt(const QPoint &point) const const=0
virtual void reset()
virtual QRect visualRect(const QModelIndex &index) const const=0
int blue() const const
int green() const const
bool isValid() const const
int red() const const
void setBold(bool enable)
void setItalic(bool enable)
QFont systemFont(SystemFont type)
QRect boundingRect(QChar ch) const const
QString elidedText(const QString &text, Qt::TextElideMode mode, int width, int flags) const const
int height() const const
void setColorAt(qreal position, const QColor &color)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
int column() const const
bool isValid() const const
void drawLine(const QLine &line)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void drawText(const QPoint &position, const QString &text)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
qreal opacity() const const
const QPen & pen() const const
RenderHints renderHints() const const
void setBackgroundMode(Qt::BGMode mode)
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setOpacity(qreal opacity)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
const QColor & color(ColorGroup group, ColorRole role) const const
QColor color() const const
int x() const const
int y() const const
bool contains(const QPoint &point, bool proper) const const
int height() const const
bool isValid() const const
int left() const const
int right() const const
int top() const const
int width() const const
int height() const const
bool isValid() const const
int width() const const
virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const const
AlignTop
OpaqueMode
LayoutDirection
ElideLeft
TextSingleLine
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:33:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.