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) {
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()) {
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);
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);
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));
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));
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
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))) {
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,
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,
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,
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,
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,
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,
963 mTheme->iconSize());
964 }
965 break;
967 if (messageItem) {
968 paint_boolean_state_icon(messageItem->hasAnnotation(),
969 mTheme->pixmap(Theme::IconAnnotation),
970 ci,
971 painter,
972 l,
973 top,
974 r,
976 mTheme->iconSize());
977 }
978 break;
980 if (messageItem) {
981 paint_boolean_state_icon(messageItem->status().hasInvitation(),
982 mTheme->pixmap(Theme::IconInvitation),
983 ci,
984 painter,
985 l,
986 top,
987 r,
989 mTheme->iconSize());
990 }
991 break;
993 if (messageItem) {
994 paint_boolean_state_icon(messageItem->status().isToAct(),
995 mTheme->pixmap(Theme::IconActionItem),
996 ci,
997 painter,
998 l,
999 top,
1000 r,
1002 mTheme->iconSize());
1003 }
1004 break;
1006 if (messageItem) {
1007 paint_boolean_state_icon(messageItem->status().isImportant(),
1008 mTheme->pixmap(Theme::IconImportant),
1009 ci,
1010 painter,
1011 l,
1012 top,
1013 r,
1015 mTheme->iconSize());
1016 }
1017 break;
1019 paint_vertical_line(painter, l, top, r, bottom, layoutDir == Qt::LeftToRight);
1020 break;
1022 paint_horizontal_spacer(l, top, r, bottom, layoutDir == Qt::LeftToRight);
1023 break;
1025 if (messageItem) {
1026 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1027 paint_tag_list(tagList, painter, l, top, r, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1028 }
1029 break;
1030 }
1031 }
1032
1033 // then paint left aligned stuff
1034 const auto leftItems = row->leftItems();
1035 for (const auto itemit : leftItems) {
1036 auto ci = const_cast<Theme::ContentItem *>(itemit);
1037
1038 if (ci->canUseCustomColor()) {
1039 if (ci->useCustomColor() && (!(opt.state & QStyle::State_Selected))) {
1041 // merge the colors
1042 QColor nonDefault = defaultPen.color();
1043 QColor custom = ci->customColor();
1044 QColor merged((nonDefault.red() + custom.red()) >> 1,
1045 (nonDefault.green() + custom.green()) >> 1,
1046 (nonDefault.blue() + custom.blue()) >> 1);
1047 painter->setPen(QPen(merged));
1048 } else {
1049 painter->setPen(QPen(ci->customColor()));
1050 }
1051 } else {
1052 painter->setPen(defaultPen);
1053 }
1054 } // otherwise setting a pen is useless at this time
1055
1056 const QFont &font = cachedFont(ci, item);
1057
1058 switch (ci->type()) {
1060 paint_left_aligned_elided_text(item->subject(), ci, painter, l, top, r, layoutDir, font);
1061 break;
1063 paint_left_aligned_elided_text(item->displaySenderOrReceiver(), ci, painter, l, top, r, layoutDir, font);
1064 break;
1066 paint_left_aligned_elided_text(item->displayReceiver(), ci, painter, l, top, r, layoutDir, font);
1067 break;
1069 paint_left_aligned_elided_text(item->displaySender(), ci, painter, l, top, r, layoutDir, font);
1070 break;
1072 paint_left_aligned_elided_text(item->formattedDate(), ci, painter, l, top, r, layoutDir, font);
1073 break;
1075 paint_left_aligned_elided_text(item->formattedMaxDate(), ci, painter, l, top, r, layoutDir, font);
1076 break;
1078 paint_left_aligned_elided_text(item->formattedSize(), ci, painter, l, top, r, layoutDir, font);
1079 break;
1081 paint_left_aligned_elided_text(item->folder(), ci, painter, l, top, r, layoutDir, font);
1082 break;
1084 if (groupHeaderItem) {
1085 paint_left_aligned_elided_text(groupHeaderItem->label(), ci, painter, l, top, r, layoutDir, font);
1086 }
1087 break;
1089 paint_permanent_icon(get_read_state_icon(mTheme, item), ci, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1090 break;
1092 if (messageItem) {
1093 paint_permanent_icon(get_combined_read_replied_state_icon(mTheme, messageItem),
1094 ci,
1095 painter,
1096 l,
1097 top,
1098 r,
1100 mTheme->iconSize());
1101 }
1102 break;
1104 const QPixmap *pix =
1105 item->childItemCount() > 0 ? mTheme->pixmap((option.state & QStyle::State_Open) ? Theme::IconShowLess : Theme::IconShowMore) : nullptr;
1106 paint_boolean_state_icon(pix != nullptr,
1107 pix ? pix : mTheme->pixmap(Theme::IconShowMore),
1108 ci,
1109 painter,
1110 l,
1111 top,
1112 r,
1114 mTheme->iconSize());
1115 break;
1116 }
1118 if (messageItem) {
1119 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
1120 paint_boolean_state_icon(pix != nullptr,
1121 pix ? pix : mTheme->pixmap(Theme::IconReplied),
1122 ci,
1123 painter,
1124 l,
1125 top,
1126 r,
1128 mTheme->iconSize());
1129 }
1130 break;
1132 if (messageItem) {
1133 bool enabled;
1134 const QPixmap *pix = get_encryption_state_icon(mTheme, messageItem, &enabled);
1135 paint_boolean_state_icon(enabled, pix, ci, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1136 }
1137 break;
1139 if (messageItem) {
1140 bool enabled;
1141 const QPixmap *pix = get_signature_state_icon(mTheme, messageItem, &enabled);
1142 paint_boolean_state_icon(enabled, pix, ci, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1143 }
1144 break;
1146 if (messageItem) {
1147 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
1148 paint_boolean_state_icon(pix != nullptr,
1149 pix ? pix : mTheme->pixmap(Theme::IconSpam),
1150 ci,
1151 painter,
1152 l,
1153 top,
1154 r,
1156 mTheme->iconSize());
1157 }
1158 break;
1160 if (messageItem) {
1161 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
1162 paint_boolean_state_icon(pix != nullptr,
1163 pix ? pix : mTheme->pixmap(Theme::IconWatched),
1164 ci,
1165 painter,
1166 l,
1167 top,
1168 r,
1170 mTheme->iconSize());
1171 }
1172 break;
1174 if (messageItem) {
1175 paint_boolean_state_icon(messageItem->status().hasAttachment(),
1176 mTheme->pixmap(Theme::IconAttachment),
1177 ci,
1178 painter,
1179 l,
1180 top,
1181 r,
1183 mTheme->iconSize());
1184 }
1185 break;
1187 if (messageItem) {
1188 paint_boolean_state_icon(messageItem->hasAnnotation(),
1189 mTheme->pixmap(Theme::IconAnnotation),
1190 ci,
1191 painter,
1192 l,
1193 top,
1194 r,
1196 mTheme->iconSize());
1197 }
1198 break;
1200 if (messageItem) {
1201 paint_boolean_state_icon(messageItem->status().hasInvitation(),
1202 mTheme->pixmap(Theme::IconInvitation),
1203 ci,
1204 painter,
1205 l,
1206 top,
1207 r,
1209 mTheme->iconSize());
1210 }
1211 break;
1213 if (messageItem) {
1214 paint_boolean_state_icon(messageItem->status().isToAct(),
1215 mTheme->pixmap(Theme::IconActionItem),
1216 ci,
1217 painter,
1218 l,
1219 top,
1220 r,
1222 mTheme->iconSize());
1223 }
1224 break;
1226 if (messageItem) {
1227 paint_boolean_state_icon(messageItem->status().isImportant(),
1228 mTheme->pixmap(Theme::IconImportant),
1229 ci,
1230 painter,
1231 l,
1232 top,
1233 r,
1235 mTheme->iconSize());
1236 }
1237 break;
1239 paint_vertical_line(painter, l, top, r, bottom, layoutDir != Qt::LeftToRight);
1240 break;
1242 paint_horizontal_spacer(l, top, r, bottom, layoutDir != Qt::LeftToRight);
1243 break;
1245 if (messageItem) {
1246 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1247 paint_tag_list(tagList, painter, l, top, r, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1248 }
1249 break;
1250 }
1251 }
1252
1253 top = bottom;
1254 }
1255
1256 painter->setFont(oldFont);
1257 painter->setPen(oldPen);
1258 painter->setOpacity(oldOpacity);
1259}
1260
1261bool ThemeDelegate::hitTest(const QPoint &viewportPoint, bool exact)
1262{
1263 mHitItem = nullptr;
1264 mHitColumn = nullptr;
1265 mHitRow = nullptr;
1266 mHitContentItem = nullptr;
1267
1268 if (!mTheme) {
1269 return false; // hm hm...
1270 }
1271
1272 mHitIndex = mItemView->indexAt(viewportPoint);
1273
1274 if (!mHitIndex.isValid()) {
1275 return false; // bleah
1276 }
1277
1278 mHitItem = itemFromIndex(mHitIndex);
1279 if (!mHitItem) {
1280 return false; // hm...
1281 }
1282
1283 mHitItemRect = mItemView->visualRect(mHitIndex);
1284
1285 mHitColumn = mTheme->column(mHitIndex.column());
1286 if (!mHitColumn) {
1287 return false; // bleah
1288 }
1289
1290 const QList<Theme::Row *> *rows; // I'd like to have it as reference, but gcc complains...
1291
1292 MessageItem *messageItem = nullptr;
1293 GroupHeaderItem *groupHeaderItem = nullptr;
1294
1295 int top = mHitItemRect.top();
1296 int right = mHitItemRect.right();
1297 int left = mHitItemRect.left();
1298
1299 mHitRow = nullptr;
1300 mHitRowIndex = -1;
1301 mHitContentItem = nullptr;
1302
1303 switch (mHitItem->type()) {
1304 case Item::Message:
1305 mHitRowIsMessageRow = true;
1306 rows = &(mHitColumn->messageRows());
1307 messageItem = static_cast<MessageItem *>(mHitItem);
1308 // FIXME: paint eventual background here
1309
1310 top += gMessageVerticalMargin;
1311 right -= gMessageHorizontalMargin;
1312 left += gMessageHorizontalMargin;
1313 break;
1314 case Item::GroupHeader:
1315 mHitRowIsMessageRow = false;
1316 rows = &(mHitColumn->groupHeaderRows());
1317 groupHeaderItem = static_cast<GroupHeaderItem *>(mHitItem);
1318
1319 top += gGroupHeaderOuterVerticalMargin + gGroupHeaderInnerVerticalMargin;
1320 right -= gGroupHeaderOuterHorizontalMargin + gGroupHeaderInnerHorizontalMargin;
1321 left += gGroupHeaderOuterHorizontalMargin + gGroupHeaderInnerHorizontalMargin;
1322 break;
1323 default:
1324 return false; // bug
1325 break;
1326 }
1327
1328 int rowIdx = 0;
1329 int bestInexactDistance = 0xffffff;
1330 bool bestInexactItemRight = false;
1333
1335
1336 for (const auto row : std::as_const(*rows)) {
1337 QSize rowSizeHint = compute_size_hint_for_row(row, mTheme->iconSize(), mHitItem);
1338
1339 if ((viewportPoint.y() < top) && (rowIdx > 0)) {
1340 break; // not this row (tough we should have already found it... probably clicked upper margin)
1341 }
1342
1343 int bottom = top + rowSizeHint.height();
1344
1345 if (viewportPoint.y() > bottom) {
1346 top += rowSizeHint.height();
1347 rowIdx++;
1348 continue; // not this row
1349 }
1350
1351 bestInexactItemRight = false;
1352 bestInexactDistance = 0xffffff;
1353 bestInexactContentItem = nullptr;
1354
1355 // this row!
1356 mHitRow = row;
1357 mHitRowIndex = rowIdx;
1358 mHitRowRect = QRect(left, top, right - left, bottom - top);
1359
1360 // check right aligned stuff first
1361 mHitContentItemRight = true;
1362
1363 int r = right;
1364 int l = left;
1365 const auto rightItems = mHitRow->rightItems();
1366 for (const auto itemit : rightItems) {
1367 auto ci = const_cast<Theme::ContentItem *>(itemit);
1368
1369 mHitContentItemRect = QRect();
1370
1371 const QFont &font = cachedFont(ci, mHitItem);
1372
1373 switch (ci->type()) {
1375 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->subject(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1376 break;
1378 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->displaySenderOrReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1379 break;
1381 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->displayReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1382 break;
1384 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->displaySender(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1385 break;
1387 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->formattedDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1388 break;
1390 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->formattedMaxDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1391 break;
1393 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->formattedSize(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1394 break;
1396 compute_bounding_rect_for_right_aligned_elided_text(mHitItem->folder(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1397 break;
1399 if (groupHeaderItem) {
1400 compute_bounding_rect_for_right_aligned_elided_text(groupHeaderItem->label(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1401 }
1402 break;
1404 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1405 break;
1407 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1408 break;
1410 compute_bounding_rect_for_boolean_state_icon(mHitItem->childItemCount() > 0,
1411 ci,
1412 l,
1413 top,
1414 r,
1415 mHitContentItemRect,
1417 mTheme->iconSize());
1418 break;
1420 if (messageItem) {
1421 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
1422 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1423 ci,
1424 l,
1425 top,
1426 r,
1427 mHitContentItemRect,
1429 mTheme->iconSize());
1430 }
1431 break;
1433 if (messageItem) {
1434 bool enabled;
1435 get_encryption_state_icon(mTheme, messageItem, &enabled);
1436 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1437 }
1438 break;
1440 if (messageItem) {
1441 bool enabled;
1442 get_signature_state_icon(mTheme, messageItem, &enabled);
1443 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1444 }
1445 break;
1447 if (messageItem) {
1448 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
1449 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1450 ci,
1451 l,
1452 top,
1453 r,
1454 mHitContentItemRect,
1456 mTheme->iconSize());
1457 }
1458 break;
1460 if (messageItem) {
1461 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
1462 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1463 ci,
1464 l,
1465 top,
1466 r,
1467 mHitContentItemRect,
1469 mTheme->iconSize());
1470 }
1471 break;
1473 if (messageItem) {
1474 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasAttachment(),
1475 ci,
1476 l,
1477 top,
1478 r,
1479 mHitContentItemRect,
1481 mTheme->iconSize());
1482 }
1483 break;
1485 if (messageItem) {
1486 compute_bounding_rect_for_boolean_state_icon(messageItem->hasAnnotation(),
1487 ci,
1488 l,
1489 top,
1490 r,
1491 mHitContentItemRect,
1493 mTheme->iconSize());
1494 }
1495 break;
1497 if (messageItem) {
1498 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasInvitation(),
1499 ci,
1500 l,
1501 top,
1502 r,
1503 mHitContentItemRect,
1505 mTheme->iconSize());
1506 }
1507 break;
1509 if (messageItem) {
1510 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isToAct(),
1511 ci,
1512 l,
1513 top,
1514 r,
1515 mHitContentItemRect,
1517 mTheme->iconSize());
1518 }
1519 break;
1521 if (messageItem) {
1522 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isImportant(),
1523 ci,
1524 l,
1525 top,
1526 r,
1527 mHitContentItemRect,
1529 mTheme->iconSize());
1530 }
1531 break;
1533 compute_bounding_rect_for_vertical_line(l, top, r, bottom, mHitContentItemRect, layoutDir == Qt::LeftToRight);
1534 break;
1536 compute_bounding_rect_for_horizontal_spacer(l, top, r, bottom, mHitContentItemRect, layoutDir == Qt::LeftToRight);
1537 break;
1539 if (messageItem) {
1540 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1541 compute_bounding_rect_for_tag_list(tagList, l, top, r, mHitContentItemRect, layoutDir == Qt::LeftToRight, mTheme->iconSize());
1542 }
1543 break;
1544 }
1545
1546 if (mHitContentItemRect.isValid()) {
1547 if (mHitContentItemRect.contains(viewportPoint)) {
1548 // caught!
1549 mHitContentItem = ci;
1550 return true;
1551 }
1552 if (!exact) {
1553 QRect inexactRect(mHitContentItemRect.left(), mHitRowRect.top(), mHitContentItemRect.width(), mHitRowRect.height());
1554 if (inexactRect.contains(viewportPoint)) {
1555 mHitContentItem = ci;
1556 return true;
1557 }
1558
1559 int inexactDistance =
1560 viewportPoint.x() > inexactRect.right() ? viewportPoint.x() - inexactRect.right() : inexactRect.left() - viewportPoint.x();
1563 bestInexactRect = mHitContentItemRect;
1564 bestInexactItemRight = true;
1566 }
1567 }
1568 }
1569 }
1570
1571 // then check left aligned stuff
1572 mHitContentItemRight = false;
1573
1574 const auto leftItems = mHitRow->leftItems();
1575 for (const auto itemit : leftItems) {
1576 auto ci = const_cast<Theme::ContentItem *>(itemit);
1577
1578 mHitContentItemRect = QRect();
1579
1580 const QFont &font = cachedFont(ci, mHitItem);
1581
1582 switch (ci->type()) {
1584 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->subject(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1585 break;
1587 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->displaySenderOrReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1588 break;
1590 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->displayReceiver(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1591 break;
1593 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->displaySender(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1594 break;
1596 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->formattedDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1597 break;
1599 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->formattedMaxDate(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1600 break;
1602 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->formattedSize(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1603 break;
1605 compute_bounding_rect_for_left_aligned_elided_text(mHitItem->folder(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1606 break;
1608 if (groupHeaderItem) {
1609 compute_bounding_rect_for_left_aligned_elided_text(groupHeaderItem->label(), ci, l, top, r, mHitContentItemRect, layoutDir, font);
1610 }
1611 break;
1613 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1614 break;
1616 compute_bounding_rect_for_permanent_icon(ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1617 break;
1619 compute_bounding_rect_for_boolean_state_icon(mHitItem->childItemCount() > 0,
1620 ci,
1621 l,
1622 top,
1623 r,
1624 mHitContentItemRect,
1626 mTheme->iconSize());
1627 break;
1629 if (messageItem) {
1630 const QPixmap *pix = get_replied_state_icon(mTheme, messageItem);
1631 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1632 ci,
1633 l,
1634 top,
1635 r,
1636 mHitContentItemRect,
1638 mTheme->iconSize());
1639 }
1640 break;
1642 if (messageItem) {
1643 bool enabled;
1644 get_encryption_state_icon(mTheme, messageItem, &enabled);
1645 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1646 }
1647 break;
1649 if (messageItem) {
1650 bool enabled;
1651 get_signature_state_icon(mTheme, messageItem, &enabled);
1652 compute_bounding_rect_for_boolean_state_icon(enabled, ci, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1653 }
1654 break;
1656 if (messageItem) {
1657 const QPixmap *pix = get_spam_ham_state_icon(mTheme, messageItem);
1658 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1659 ci,
1660 l,
1661 top,
1662 r,
1663 mHitContentItemRect,
1665 mTheme->iconSize());
1666 }
1667 break;
1669 if (messageItem) {
1670 const QPixmap *pix = get_watched_ignored_state_icon(mTheme, messageItem);
1671 compute_bounding_rect_for_boolean_state_icon(pix != nullptr,
1672 ci,
1673 l,
1674 top,
1675 r,
1676 mHitContentItemRect,
1678 mTheme->iconSize());
1679 }
1680 break;
1682 if (messageItem) {
1683 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasAttachment(),
1684 ci,
1685 l,
1686 top,
1687 r,
1688 mHitContentItemRect,
1690 mTheme->iconSize());
1691 }
1692 break;
1694 if (messageItem) {
1695 compute_bounding_rect_for_boolean_state_icon(messageItem->hasAnnotation(),
1696 ci,
1697 l,
1698 top,
1699 r,
1700 mHitContentItemRect,
1702 mTheme->iconSize());
1703 }
1704 break;
1706 if (messageItem) {
1707 compute_bounding_rect_for_boolean_state_icon(messageItem->status().hasInvitation(),
1708 ci,
1709 l,
1710 top,
1711 r,
1712 mHitContentItemRect,
1714 mTheme->iconSize());
1715 }
1716 break;
1718 if (messageItem) {
1719 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isToAct(),
1720 ci,
1721 l,
1722 top,
1723 r,
1724 mHitContentItemRect,
1726 mTheme->iconSize());
1727 }
1728 break;
1730 if (messageItem) {
1731 compute_bounding_rect_for_boolean_state_icon(messageItem->status().isImportant(),
1732 ci,
1733 l,
1734 top,
1735 r,
1736 mHitContentItemRect,
1738 mTheme->iconSize());
1739 }
1740 break;
1742 compute_bounding_rect_for_vertical_line(l, top, r, bottom, mHitContentItemRect, layoutDir != Qt::LeftToRight);
1743 break;
1745 compute_bounding_rect_for_horizontal_spacer(l, top, r, bottom, mHitContentItemRect, layoutDir != Qt::LeftToRight);
1746 break;
1748 if (messageItem) {
1749 const QList<MessageItem::Tag *> tagList = messageItem->tagList();
1750 compute_bounding_rect_for_tag_list(tagList, l, top, r, mHitContentItemRect, layoutDir != Qt::LeftToRight, mTheme->iconSize());
1751 }
1752 break;
1753 }
1754
1755 if (mHitContentItemRect.isValid()) {
1756 if (mHitContentItemRect.contains(viewportPoint)) {
1757 // caught!
1758 mHitContentItem = ci;
1759 return true;
1760 }
1761 if (!exact) {
1762 QRect inexactRect(mHitContentItemRect.left(), mHitRowRect.top(), mHitContentItemRect.width(), mHitRowRect.height());
1763 if (inexactRect.contains(viewportPoint)) {
1764 mHitContentItem = ci;
1765 return true;
1766 }
1767
1768 int inexactDistance =
1769 viewportPoint.x() > inexactRect.right() ? viewportPoint.x() - inexactRect.right() : inexactRect.left() - viewportPoint.x();
1772 bestInexactRect = mHitContentItemRect;
1773 bestInexactItemRight = false;
1775 }
1776 }
1777 }
1778 }
1779
1780 top += rowSizeHint.height();
1781 rowIdx++;
1782 }
1783
1784 mHitContentItem = bestInexactContentItem;
1785 mHitContentItemRight = bestInexactItemRight;
1786 mHitContentItemRect = bestInexactRect;
1787 return true;
1788}
1789
1791{
1792 return mHitIndex;
1793}
1794
1796{
1797 return mHitItem;
1798}
1799
1801{
1802 return mHitItemRect;
1803}
1804
1806{
1807 return mHitColumn;
1808}
1809
1811{
1812 return mHitIndex.column();
1813}
1814
1816{
1817 return mHitRow;
1818}
1819
1821{
1822 return mHitRowIndex;
1823}
1824
1826{
1827 return mHitRowRect;
1828}
1829
1831{
1832 return mHitRowIsMessageRow;
1833}
1834
1836{
1837 return mHitContentItem;
1838}
1839
1841{
1842 return mHitContentItemRight;
1843}
1844
1846{
1847 return mHitContentItemRect;
1848}
1849
1851{
1852 if (!mTheme) {
1853 return {16, 16}; // bleah
1854 }
1855
1856 const Theme::Column *skcolumn = mTheme->column(column);
1857 if (!skcolumn) {
1858 return {16, 16}; // bleah
1859 }
1860
1861 const QList<Theme::Row *> *rows; // I'd like to have it as reference, but gcc complains...
1862
1863 // The sizeHint() is layout direction independent.
1864
1865 int marginw;
1866 int marginh;
1867
1868 switch (type) {
1869 case Item::Message:
1870 rows = &(skcolumn->messageRows());
1871
1872 marginh = gMessageVerticalMargin << 1;
1873 marginw = gMessageHorizontalMargin << 1;
1874 break;
1875 case Item::GroupHeader:
1876 rows = &(skcolumn->groupHeaderRows());
1877
1878 marginh = (gGroupHeaderOuterVerticalMargin + gGroupHeaderInnerVerticalMargin) << 1;
1879 marginw = (gGroupHeaderOuterVerticalMargin + gGroupHeaderInnerVerticalMargin) << 1;
1880 break;
1881 default:
1882 return {16, 16}; // bug
1883 break;
1884 }
1885
1886 int totalh = 0;
1887 int maxw = 0;
1888
1890 const QSize sh = compute_size_hint_for_row((*rowit), mTheme->iconSize(), item);
1891 totalh += sh.height();
1892 if (sh.width() > maxw) {
1893 maxw = sh.width();
1894 }
1895 }
1896
1897 return {maxw + marginw, totalh + marginh};
1898}
1899
1901{
1902 if (!mTheme || !index.isValid()) {
1903 return {16, 16}; // hm hm...
1904 }
1905
1906 Item *item = itemFromIndex(index);
1907 if (!item) {
1908 return {16, 16}; // hm...
1909 }
1910
1911 const Item::Type type = item->type();
1912 if (type == Item::Message) {
1913 if (!mCachedMessageItemSizeHint.isValid()) {
1914 mCachedMessageItemSizeHint = sizeHintForItemTypeAndColumn(Item::Message, index.column(), item);
1915 }
1916 return mCachedMessageItemSizeHint;
1917 } else if (type == Item::GroupHeader) {
1918 if (!mCachedGroupHeaderItemSizeHint.isValid()) {
1919 mCachedGroupHeaderItemSizeHint = sizeHintForItemTypeAndColumn(Item::GroupHeader, index.column(), item);
1920 }
1921 return mCachedGroupHeaderItemSizeHint;
1922 } else {
1923 Q_ASSERT(false);
1924 return {};
1925 }
1926}
1927
1928// Store the new fonts when the generalFont changes and flush sizeHint cache
1930{
1931 mCachedMessageItemSizeHint = QSize();
1932 mCachedGroupHeaderItemSizeHint = QSize();
1933
1934 QFont font;
1935 if (MessageCore::MessageCoreSettings::self()->useDefaultFonts()) {
1937 } else {
1938 font = MessageListSettings::self()->messageListFont();
1939 }
1940 sFontCache[Normal] = font;
1941 sFontMetricsCache[Normal] = QFontMetrics(font);
1942 font.setBold(true);
1943 sFontCache[Bold] = font;
1944 sFontMetricsCache[Bold] = QFontMetrics(font);
1945 font.setBold(false);
1946 font.setItalic(true);
1947 sFontCache[Italic] = font;
1948 sFontMetricsCache[Italic] = QFontMetrics(font);
1949 font.setBold(true);
1950 font.setItalic(true);
1951 sFontCache[BoldItalic] = font;
1952 sFontMetricsCache[BoldItalic] = QFontMetrics(font);
1953
1954 sFontHeightCache = sFontMetricsCache[Normal].height();
1955}
1956
1957const Theme *ThemeDelegate::theme() const
1958{
1959 return mTheme;
1960}
1961
1962#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:315
QString formattedDate() const
A string with a text rappresentation of date() obtained via Manager.
Definition item.cpp:306
const Akonadi::MessageStatus & status() const
Returns the status associated to this Item.
Definition item.cpp:447
Type type() const
Returns the type of this item.
Definition item.cpp:343
const QString & folder() const
Returns the folder associated to this Item.
Definition item.cpp:542
QString displayReceiver() const
Display receiver.
Definition item.cpp:512
QString displaySenderOrReceiver() const
Display sender or receiver.
Definition item.cpp:522
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:300
int childItemCount() const
Returns the number of children of this Item.
Definition item.cpp:158
const QString & subject() const
Returns the subject associated to this Item.
Definition item.cpp:532
QString displaySender() const
Display sender.
Definition item.cpp:497
The MessageItem class.
Definition messageitem.h:35
virtual bool hasAnnotation() const
Returns true if this message has an annotation.
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:506
const QList< Row * > & groupHeaderRows() const
Returns the list of rows visible in this column for a GroupHeaderItem.
Definition theme.cpp:761
const QList< Row * > & messageRows() const
Returns the list of rows visible in this column for a MessageItem.
Definition theme.cpp:718
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:78
bool hideWhenDisabled() const
Returns true if this item should be hidden when in disabled state.
Definition theme.cpp:226
bool isSpacer() const
Returns true if this item is a small spacer.
Definition theme.cpp:98
bool isBold() const
Returns true if this item uses a bold text.
Definition theme.cpp:198
bool isIcon() const
Returns true if this item displays an icon.
Definition theme.cpp:88
bool softenByBlending() const
Returns true if this item should be always painted in a "soft" fashion.
Definition theme.cpp:254
bool softenByBlendingWhenDisabled() const
Returns true if this item should be painted in a "soft" fashion when in disabled state.
Definition theme.cpp:240
@ InvitationIcon
Whether the message is an invitation.
Definition theme.h:203
@ 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:207
@ 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
@ AnnotationIcon
Whether the message has a annotation/note.
Definition theme.h:198
@ 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
bool displaysLongText() const
Returns true if this item displays a long text.
Definition theme.cpp:83
bool isItalic() const
Returns true if this item uses an italic text.
Definition theme.cpp:212
The Row class defines a row of items inside a Column.
Definition theme.h:413
const QList< ContentItem * > & rightItems() const
Returns the list of right aligned items for this row.
Definition theme.cpp:402
const QList< ContentItem * > & leftItems() const
Returns the list of left aligned items for this row.
Definition theme.cpp:507
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:799
@ CustomColor
Use a custom color.
Definition theme.h:801
@ AutoColor
Automatically determine the color (somewhere in the middle between background and text)
Definition theme.h:800
const QColor & groupHeaderBackgroundColor() const
Returns the group header background color for this theme.
Definition theme.cpp:1025
GroupHeaderBackgroundMode groupHeaderBackgroundMode() const
Returns the group header background mode for this theme.
Definition theme.cpp:1004
GroupHeaderBackgroundStyle groupHeaderBackgroundStyle() const
Returns the group header background style for this theme.
Definition theme.cpp:1035
int iconSize() const
Returns the currently set icon size.
Definition theme.cpp:1072
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:973
@ RoundedJoinedRect
One big rounded rect for all the columns.
Definition theme.h:811
@ PlainRect
One plain rect per column.
Definition theme.h:808
@ GradientRect
One rounded gradient filled rect per column.
Definition theme.h:812
@ StyledRect
One styled rect per column.
Definition theme.h:814
@ RoundedRect
One rounded rect per column.
Definition theme.h:810
@ StyledJoinedRect
One big styled rect per column.
Definition theme.h:815
@ PlainJoinedRect
One big plain rect for all the columns.
Definition theme.h:809
@ GradientJoinedRect
One big rounded gradient rect for all the columns.
Definition theme.h:813
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
T qobject_cast(QObject *object)
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)
QColor color() 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
bool isValid() 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 Fri Jun 14 2024 11:49:07 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.