Messagelib

theme.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/theme.h"
10
11#include <QApplication>
12#include <QDataStream>
13#include <QIcon>
14#include <QPixmap>
15#include <QStandardPaths>
16
17#include "messagelist_debug.h"
18#include <KLocalizedString>
19
20using namespace MessageList::Core;
21
22//
23// Theme versioning
24//
25// The themes simply have a DWORD version number attached.
26// The earliest version we're able to load is 0x1013.
27//
28// Theme revision history:
29//
30// Version Date introduced Description
31// --------------------------------------------------------------------------------------------------------------
32// 0x1013 08.11.2008 Initial theme version, introduced when this piece of code has been moved into trunk.
33// 0x1014 12.11.2008 Added runtime column data: width and column visibility
34// 0x1015 03.03.2009 Added icon size
35// 0x1016 08.03.2009 Added support for sorting by New/Unread status
36// 0x1017 16.08.2009 Added support for column icon
37// 0x1018 17.01.2010 Added support for annotation icon
38// 0x1019 13.07.2010 Added support for invitation icon
39//
40static const int gThemeCurrentVersion = 0x1019; // increase if you add new fields or change the meaning of some
41// you don't need to change the values below, but you might want to add new ones
42static const int gThemeMinimumSupportedVersion = 0x1013;
43static const int gThemeMinimumVersionWithColumnRuntimeData = 0x1014;
44static const int gThemeMinimumVersionWithIconSizeField = 0x1015;
45static const int gThemeMinimumVersionWithSortingByUnreadStatusAllowed = 0x1016;
46static const int gThemeMinimumVersionWithColumnIcon = 0x1017;
47static const int gThemeMinimumVersionWithInvitationIcon = 0x1019;
48
49// the default icon size
50static const int gThemeDefaultIconSize = 16;
51
53 : mType(type)
54 , mFlags(0)
55{
56}
57
59
60 = default;
61
63{
64 return mType;
65}
66
68{
69 return (static_cast<int>(mType) & CanBeDisabled) != 0;
70}
71
73{
74 return (static_cast<int>(mType) & CanUseCustomColor) != 0;
75}
76
78{
79 return (static_cast<int>(mType) & DisplaysText) != 0;
80}
81
83{
84 return (static_cast<int>(mType) & LongText) != 0;
85}
86
88{
89 return (static_cast<int>(mType) & IsIcon) != 0;
90}
91
93{
94 return (static_cast<int>(mType) & IsClickable) != 0;
95}
96
98{
99 return (static_cast<int>(mType) & IsSpacer) != 0;
100}
101
103{
104 switch (type) {
105 case Subject:
106 return i18nc("Description of Type Subject", "Subject");
107 break;
108 case Date:
109 return i18nc("Description of Type Date", "Date");
110 break;
111 case SenderOrReceiver:
112 return i18n("Sender/Receiver");
113 break;
114 case Sender:
115 return i18nc("Description of Type Sender", "Sender");
116 break;
117 case Receiver:
118 return i18nc("Description of Type Receiver", "Receiver");
119 break;
120 case Size:
121 return i18nc("Description of Type Size", "Size");
122 break;
123 case ReadStateIcon:
124 return i18n("Unread/Read Icon");
125 break;
126 case AttachmentStateIcon:
127 return i18n("Attachment Icon");
128 break;
129 case RepliedStateIcon:
130 return i18n("Replied/Forwarded Icon");
131 break;
132 case CombinedReadRepliedStateIcon:
133 return i18n("Combined New/Unread/Read/Replied/Forwarded Icon");
134 break;
135 case ActionItemStateIcon:
136 return i18n("Action Item Icon");
137 break;
138 case ImportantStateIcon:
139 return i18n("Important Icon");
140 break;
141 case GroupHeaderLabel:
142 return i18n("Group Header Label");
143 break;
144 case SpamHamStateIcon:
145 return i18n("Spam/Ham Icon");
146 break;
147 case WatchedIgnoredStateIcon:
148 return i18n("Watched/Ignored Icon");
149 break;
150 case ExpandedStateIcon:
151 return i18n("Group Header Expand/Collapse Icon");
152 break;
153 case EncryptionStateIcon:
154 return i18n("Encryption State Icon");
155 break;
156 case SignatureStateIcon:
157 return i18n("Signature State Icon");
158 break;
159 case VerticalLine:
160 return i18n("Vertical Separation Line");
161 break;
162 case HorizontalSpacer:
163 return i18n("Horizontal Spacer");
164 break;
165 case MostRecentDate:
166 return i18n("Max Date");
167 break;
168 case TagList:
169 return i18n("Message Tags");
170 break;
171 case InvitationIcon:
172 return i18n("Invitation Icon");
173 case Folder:
174 return i18nc("Description of Type Folder", "Folder");
175 default:
176 return i18nc("Description for an Unknown Type", "Unknown");
177 break;
178 }
179}
180
182{
183 return mFlags & UseCustomColor;
184}
185
187{
188 if (useCustomColor) {
189 mFlags |= UseCustomColor;
190 } else {
191 mFlags &= ~UseCustomColor;
192 }
193}
194
196{
197 return mFlags & IsBold;
198}
199
201{
202 if (isBold) {
203 mFlags |= IsBold;
204 } else {
205 mFlags &= ~IsBold;
206 }
207}
208
210{
211 return mFlags & IsItalic;
212}
213
215{
216 if (isItalic) {
217 mFlags |= IsItalic;
218 } else {
219 mFlags &= ~IsItalic;
220 }
221}
222
224{
225 return mFlags & HideWhenDisabled;
226}
227
229{
230 if (hideWhenDisabled) {
231 mFlags |= HideWhenDisabled;
232 } else {
233 mFlags &= ~HideWhenDisabled;
234 }
235}
236
238{
239 return mFlags & SoftenByBlendingWhenDisabled;
240}
241
242void Theme::ContentItem::setSoftenByBlendingWhenDisabled(bool softenByBlendingWhenDisabled)
243{
244 if (softenByBlendingWhenDisabled) {
245 mFlags |= SoftenByBlendingWhenDisabled;
246 } else {
247 mFlags &= ~SoftenByBlendingWhenDisabled;
248 }
249}
250
252{
253 return mFlags & SoftenByBlending;
254}
255
257{
258 if (softenByBlending) {
259 mFlags |= SoftenByBlending;
260 } else {
261 mFlags &= ~SoftenByBlending;
262 }
263}
264
266{
267 return mCustomColor;
268}
269
271{
272 mCustomColor = clr;
273}
274
276{
277 return static_cast<int>(type) & ApplicableToMessageItems;
278}
279
281{
282 return static_cast<int>(type) & ApplicableToGroupHeaderItems;
283}
284
286{
287 stream << (int)mType;
288 stream << mFlags;
289 stream << mCustomColor;
290}
291
292bool Theme::ContentItem::load(QDataStream &stream, int /*themeVersion*/)
293{
294 int val;
295
296 stream >> val;
297 mType = static_cast<Type>(val);
298 switch (mType) {
299 case Subject:
300 case Date:
301 case SenderOrReceiver:
302 case Sender:
303 case Receiver:
304 case Size:
305 case ReadStateIcon:
306 case AttachmentStateIcon:
307 case RepliedStateIcon:
308 case GroupHeaderLabel:
309 case ActionItemStateIcon:
310 case ImportantStateIcon:
311 case SpamHamStateIcon:
312 case WatchedIgnoredStateIcon:
313 case ExpandedStateIcon:
314 case EncryptionStateIcon:
315 case SignatureStateIcon:
316 case VerticalLine:
317 case HorizontalSpacer:
318 case MostRecentDate:
319 case CombinedReadRepliedStateIcon:
320 case TagList:
321 case InvitationIcon:
322 case Folder:
323 // ok
324 break;
325 default:
326 qCDebug(MESSAGELIST_LOG) << "Invalid content item type";
327 return false; // b0rken
328 break;
329 }
330
331 stream >> mFlags;
332 stream >> mCustomColor;
333 if (mFlags & UseCustomColor) {
334 if (!mCustomColor.isValid()) {
335 mFlags &= ~UseCustomColor;
336 }
337 }
338 return true;
339}
340
341Theme::Row::Row() = default;
342
343Theme::Row::Row(const Row &src)
344{
345 for (const auto ci : std::as_const(src.mLeftItems)) {
346 addLeftItem(new ContentItem(*ci));
347 }
348
349 for (const auto ci : std::as_const(src.mRightItems)) {
350 addRightItem(new ContentItem(*ci));
351 }
352}
353
354Theme::Row::~Row()
355{
356 removeAllLeftItems();
357 removeAllRightItems();
358}
359
361{
362 while (!mLeftItems.isEmpty()) {
363 delete mLeftItems.takeFirst();
364 }
365}
366
368{
369 mLeftItems.append(item);
370}
371
373{
374 while (!mRightItems.isEmpty()) {
375 delete mRightItems.takeFirst();
376 }
377}
378
380{
381 mRightItems.append(item);
382}
383
385{
386 if (idx >= mLeftItems.count()) {
387 mLeftItems.append(item);
388 return;
389 }
390 mLeftItems.insert(idx, item);
391}
392
394{
395 mLeftItems.removeAll(item);
396}
397
399{
400 return mRightItems;
401}
402
404{
405 if (idx >= mRightItems.count()) {
406 mRightItems.append(item);
407 return;
408 }
409 mRightItems.insert(idx, item);
410}
411
413{
414 mRightItems.removeAll(item);
415}
416
418{
419 for (const auto ci : std::as_const(mLeftItems)) {
420 if (ci->displaysText()) {
421 return true;
422 }
423 }
424 for (const auto ci : std::as_const(mRightItems)) {
425 if (ci->displaysText()) {
426 return true;
427 }
428 }
429 return false;
430}
431
432void Theme::Row::save(QDataStream &stream) const
433{
434 stream << (int)mLeftItems.count();
435
436 int cnt = mLeftItems.count();
437
438 for (int i = 0; i < cnt; ++i) {
439 ContentItem *ci = mLeftItems.at(i);
440 ci->save(stream);
441 }
442
443 stream << (int)mRightItems.count();
444
445 cnt = mRightItems.count();
446
447 for (int i = 0; i < cnt; ++i) {
448 ContentItem *ci = mRightItems.at(i);
449 ci->save(stream);
450 }
451}
452
453bool Theme::Row::LoadContentItem(int val, QDataStream &stream, int themeVersion, bool leftItem)
454{
455 if ((val < 0) || (val > 50)) {
456 return false; // senseless
457 }
458
459 // FIXME: Remove code duplication here
460
461 for (int i = 0; i < val; ++i) {
462 auto ci = new ContentItem(ContentItem::Subject); // dummy type
463 if (!ci->load(stream, themeVersion)) {
464 qCDebug(MESSAGELIST_LOG) << "Left content item loading failed";
465 delete ci;
466 return false;
467 }
468 if (leftItem) {
469 addLeftItem(ci);
470 } else {
471 addRightItem(ci);
472 }
473
474 // Same as above, for the invitation icon
475 if (ci->type() == ContentItem::AttachmentStateIcon && themeVersion < gThemeMinimumVersionWithInvitationIcon && val > 1) {
476 qCDebug(MESSAGELIST_LOG) << "Old theme version detected, adding invitation item next to attachment icon.";
477 auto invitationItem = new ContentItem(ContentItem::InvitationIcon);
478 invitationItem->setHideWhenDisabled(true);
479 if (leftItem) {
480 addLeftItem(invitationItem);
481 } else {
482 addRightItem(invitationItem);
483 }
484 }
485 }
486 return true;
487}
488
490{
491 return mLeftItems;
492}
493
494bool Theme::Row::load(QDataStream &stream, int themeVersion)
495{
496 removeAllLeftItems();
497 removeAllRightItems();
498
499 int val;
500
501 // left item count
502
503 stream >> val;
504 if (!LoadContentItem(val, stream, themeVersion, true)) {
505 return false;
506 }
507
508 // right item count
509
510 stream >> val;
511
512 if (!LoadContentItem(val, stream, themeVersion, false)) {
513 return false;
514 }
515
516 return true;
517}
518
519Theme::Column::SharedRuntimeData::SharedRuntimeData(bool currentlyVisible, double currentWidth)
520 : mReferences(0)
521 , mCurrentlyVisible(currentlyVisible)
522 , mCurrentWidth(currentWidth)
523{
524}
525
527
529{
530 mReferences++;
531}
532
534{
535 mReferences--;
536 Q_ASSERT(mReferences >= 0);
537 return mReferences > 0;
538}
539
541{
542 return mReferences;
543}
544
546{
547 return mCurrentlyVisible;
548}
549
551{
552 mCurrentlyVisible = visible;
553}
554
556{
557 return mCurrentWidth;
558}
559
564
566{
567 stream << mCurrentlyVisible;
568 stream << mCurrentWidth;
569}
570
571bool Theme::Column::SharedRuntimeData::load(QDataStream &stream, int /* themeVersion */)
572{
573 stream >> mCurrentlyVisible;
574 stream >> mCurrentWidth;
575 if (mCurrentWidth > 10000) {
576 qCDebug(MESSAGELIST_LOG) << "Theme has insane column width " << mCurrentWidth << " chopping to 100";
577 mCurrentWidth = 100; // avoid really insane values
578 }
579 return mCurrentWidth >= -1;
580}
581
583 : mVisibleByDefault(true)
584 , mIsSenderOrReceiver(false)
585 , mMessageSorting(SortOrder::NoMessageSorting)
586{
587 mSharedRuntimeData = new SharedRuntimeData(true, -1);
588 mSharedRuntimeData->addReference();
589}
590
592{
593 mLabel = src.mLabel;
594 mPixmapName = src.mPixmapName;
595 mVisibleByDefault = src.mVisibleByDefault;
596 mIsSenderOrReceiver = src.mIsSenderOrReceiver;
597 mMessageSorting = src.mMessageSorting;
598
599 mSharedRuntimeData = src.mSharedRuntimeData;
600 mSharedRuntimeData->addReference();
601 for (const auto row : std::as_const(src.mMessageRows)) {
602 addMessageRow(new Row(*row));
603 }
604
605 for (const auto row : std::as_const(src.mGroupHeaderRows)) {
606 addGroupHeaderRow(new Row(*row));
607 }
608}
609
611{
612 removeAllMessageRows();
613 removeAllGroupHeaderRows();
614 if (!(mSharedRuntimeData->deleteReference())) {
615 delete mSharedRuntimeData;
616 }
617}
618
620{
621 return mLabel;
622}
623
625{
626 mLabel = label;
627}
628
630{
631 return mPixmapName;
632}
633
635{
636 mPixmapName = pixmapName;
637}
638
640{
641 return mIsSenderOrReceiver;
642}
643
645{
646 mIsSenderOrReceiver = sor;
647}
648
650{
651 return mVisibleByDefault;
652}
653
655{
656 mVisibleByDefault = vbd;
657}
658
660{
661 if (mSharedRuntimeData->referenceCount() < 2) {
662 return; // nothing to detach
663 }
664 mSharedRuntimeData->deleteReference();
665
666 mSharedRuntimeData = new SharedRuntimeData(mVisibleByDefault, -1);
667 mSharedRuntimeData->addReference();
668}
669
671{
672 return mMessageSorting;
673}
674
676{
677 mMessageSorting = ms;
678}
679
681{
682 return mSharedRuntimeData->currentlyVisible();
683}
684
685void Theme::Column::setCurrentlyVisible(bool currentlyVisible)
686{
687 mSharedRuntimeData->setCurrentlyVisible(currentlyVisible);
688}
689
691{
692 return mSharedRuntimeData->currentWidth();
693}
694
695void Theme::Column::setCurrentWidth(double currentWidth)
696{
697 mSharedRuntimeData->setCurrentWidth(currentWidth);
698}
699
701{
702 return mMessageRows;
703}
704
706{
707 while (!mMessageRows.isEmpty()) {
708 delete mMessageRows.takeFirst();
709 }
710}
711
713{
714 mMessageRows.append(row);
715}
716
718{
719 while (!mGroupHeaderRows.isEmpty()) {
720 delete mGroupHeaderRows.takeFirst();
721 }
722}
723
725{
726 mGroupHeaderRows.append(row);
727}
728
730{
731 if (idx >= mMessageRows.count()) {
732 mMessageRows.append(row);
733 return;
734 }
735 mMessageRows.insert(idx, row);
736}
737
739{
740 mMessageRows.removeAll(row);
741}
742
744{
745 return mGroupHeaderRows;
746}
747
749{
750 if (idx >= mGroupHeaderRows.count()) {
751 mGroupHeaderRows.append(row);
752 return;
753 }
754 mGroupHeaderRows.insert(idx, row);
755}
756
758{
759 mGroupHeaderRows.removeAll(row);
760}
761
763{
764 for (const auto row : std::as_const(mMessageRows)) {
765 if (row->containsTextItems()) {
766 return true;
767 }
768 }
769 for (const auto row : std::as_const(mGroupHeaderRows)) {
770 if (row->containsTextItems()) {
771 return true;
772 }
773 }
774 return false;
775}
776
778{
779 stream << mLabel;
780 stream << mPixmapName;
781 stream << mVisibleByDefault;
782 stream << mIsSenderOrReceiver;
783 stream << static_cast<int>(mMessageSorting);
784
785 stream << static_cast<int>(mGroupHeaderRows.count());
786
787 int cnt = mGroupHeaderRows.count();
788
789 for (int i = 0; i < cnt; ++i) {
790 Row *row = mGroupHeaderRows.at(i);
791 row->save(stream);
792 }
793
794 cnt = mMessageRows.count();
795 stream << static_cast<int>(cnt);
796
797 for (int i = 0; i < cnt; ++i) {
798 Row *row = mMessageRows.at(i);
799 row->save(stream);
800 }
801
802 // added in version 0x1014
803 mSharedRuntimeData->save(stream);
804}
805
806bool Theme::Column::load(QDataStream &stream, int themeVersion)
807{
808 removeAllGroupHeaderRows();
809 removeAllMessageRows();
810
811 stream >> mLabel;
812
813 if (themeVersion >= gThemeMinimumVersionWithColumnIcon) {
814 stream >> mPixmapName;
815 }
816
817 stream >> mVisibleByDefault;
818 stream >> mIsSenderOrReceiver;
819
820 int val;
821
822 stream >> val;
823 mMessageSorting = static_cast<SortOrder::MessageSorting>(val);
824 if (!SortOrder::isValidMessageSorting(mMessageSorting)) {
825 qCDebug(MESSAGELIST_LOG) << "Invalid message sorting";
826 return false;
827 }
828
829 if (themeVersion < gThemeMinimumVersionWithSortingByUnreadStatusAllowed) {
830 // The default "Classic" theme "Unread" column had sorting disabled here.
831 // We want to be nice to the existing users and automatically set
832 // the new sorting method for this column (so they don't have to make the
833 // complex steps to set it by themselves).
834 // This piece of code isn't strictly required: it's just a niceness :)
835 if ((mMessageSorting == SortOrder::NoMessageSorting) && (mLabel == i18n("Unread"))) {
837 }
838 }
839
840 // group header row count
841 stream >> val;
842
843 if ((val < 0) || (val > 50)) {
844 qCDebug(MESSAGELIST_LOG) << "Invalid group header row count";
845 return false; // senseless
846 }
847
848 for (int i = 0; i < val; ++i) {
849 Row *row = new Row();
850 if (!row->load(stream, themeVersion)) {
851 qCDebug(MESSAGELIST_LOG) << "Group header row loading failed";
852 delete row;
853 return false;
854 }
855 addGroupHeaderRow(row);
856 }
857
858 // message row count
859 stream >> val;
860
861 if ((val < 0) || (val > 50)) {
862 qCDebug(MESSAGELIST_LOG) << "Invalid message row count";
863 return false; // senseless
864 }
865
866 for (int i = 0; i < val; ++i) {
867 Row *row = new Row();
868 if (!row->load(stream, themeVersion)) {
869 qCDebug(MESSAGELIST_LOG) << "Message row loading failed";
870 delete row;
871 return false;
872 }
873 addMessageRow(row);
874 }
875
876 if (themeVersion >= gThemeMinimumVersionWithColumnRuntimeData) {
877 // starting with version 0x1014 we have runtime data too
878 if (!mSharedRuntimeData->load(stream, themeVersion)) {
879 qCDebug(MESSAGELIST_LOG) << "Shared runtime data loading failed";
880 return false;
881 }
882 } else {
883 // assume default shared data
884 mSharedRuntimeData->setCurrentlyVisible(mVisibleByDefault);
885 mSharedRuntimeData->setCurrentWidth(-1);
886 }
887
888 return true;
889}
890
892 : OptionSet()
893{
894 mGroupHeaderBackgroundMode = AutoColor;
895 mViewHeaderPolicy = ShowHeaderAlways;
896 mIconSize = gThemeDefaultIconSize;
897 mGroupHeaderBackgroundStyle = StyledJoinedRect;
898}
899
900Theme::Theme(const QString &name, const QString &description, bool readOnly)
901 : OptionSet(name, description, readOnly)
902{
903 mGroupHeaderBackgroundMode = AutoColor;
904 mGroupHeaderBackgroundStyle = StyledJoinedRect;
905 mViewHeaderPolicy = ShowHeaderAlways;
906 mIconSize = gThemeDefaultIconSize;
907}
908
910 : OptionSet(src)
911{
912 mGroupHeaderBackgroundMode = src.mGroupHeaderBackgroundMode;
913 mGroupHeaderBackgroundColor = src.mGroupHeaderBackgroundColor;
914 mGroupHeaderBackgroundStyle = src.mGroupHeaderBackgroundStyle;
915 mViewHeaderPolicy = src.mViewHeaderPolicy;
916 mIconSize = src.mIconSize;
917 for (const auto col : std::as_const(src.mColumns)) {
918 addColumn(new Column(*col));
919 }
920}
921
923{
924 clearPixmapCache();
926}
927
929{
930 for (const auto col : std::as_const(mColumns)) {
931 col->detach();
932 }
933}
934
936{
937 for (const auto col : std::as_const(mColumns)) {
938 col->setCurrentlyVisible(col->visibleByDefault());
939 col->setCurrentWidth(-1);
940 }
941}
942
944{
945 for (const auto col : std::as_const(mColumns)) {
946 col->setCurrentWidth(-1);
947 }
948}
949
951{
952 return mColumns;
953}
954
956{
957 return mColumns.count() > idx ? mColumns.at(idx) : nullptr;
958}
959
961{
962 while (!mColumns.isEmpty()) {
963 delete mColumns.takeFirst();
964 }
965}
966
968{
969 mColumns.append(column);
970}
971
972void Theme::insertColumn(int idx, Column *column)
973{
974 if (idx >= mColumns.count()) {
975 mColumns.append(column);
976 return;
977 }
978 mColumns.insert(idx, column);
979}
980
982{
983 mColumns.removeAll(col);
984}
985
987{
988 return mGroupHeaderBackgroundMode;
989}
990
991void Theme::moveColumn(int idx, int newPosition)
992{
993 if ((newPosition >= mColumns.count()) || newPosition < 0) {
994 return;
995 }
996 mColumns.move(idx, newPosition);
997}
998
1000{
1001 mGroupHeaderBackgroundMode = bm;
1002 if ((bm == CustomColor) && !mGroupHeaderBackgroundColor.isValid()) {
1003 mGroupHeaderBackgroundColor = QColor(127, 127, 127); // something neutral
1004 }
1005}
1006
1008{
1009 return mGroupHeaderBackgroundColor;
1010}
1011
1013{
1014 mGroupHeaderBackgroundColor = clr;
1015}
1016
1018{
1019 return mGroupHeaderBackgroundStyle;
1020}
1021
1023{
1024 mGroupHeaderBackgroundStyle = groupHeaderBackgroundStyle;
1025}
1026
1028{
1029 return {{i18n("Never Show"), NeverShowHeader}, {i18n("Always Show"), ShowHeaderAlways}};
1030}
1031
1033{
1034 return {{i18n("Plain Rectangles"), PlainRect},
1035 {i18n("Plain Joined Rectangle"), PlainJoinedRect},
1036 {i18n("Rounded Rectangles"), RoundedRect},
1037 {i18n("Rounded Joined Rectangle"), RoundedJoinedRect},
1038 {i18n("Gradient Rectangles"), GradientRect},
1039 {i18n("Gradient Joined Rectangle"), GradientJoinedRect},
1040 {i18n("Styled Rectangles"), StyledRect},
1041 {i18n("Styled Joined Rectangles"), StyledJoinedRect}};
1042}
1043
1045{
1046 return mViewHeaderPolicy;
1047}
1048
1050{
1051 mViewHeaderPolicy = vhp;
1052}
1053
1055{
1056 return mIconSize;
1057}
1058
1059void Theme::setIconSize(int iconSize)
1060{
1061 if (mIconSize != iconSize) {
1062 clearPixmapCache();
1063
1064 mIconSize = iconSize;
1065 if ((mIconSize < 8) || (mIconSize > 64)) {
1066 mIconSize = gThemeDefaultIconSize;
1067 }
1068 }
1069}
1070
1072{
1074
1075 int themeVersion;
1076
1077 stream >> themeVersion;
1078
1079 // We support themes starting at version gThemeMinimumSupportedVersion (0x1013 actually)
1080
1081 if ((themeVersion > gThemeCurrentVersion) || (themeVersion < gThemeMinimumSupportedVersion)) {
1082 qCDebug(MESSAGELIST_LOG) << "Invalid theme version";
1083 return false; // b0rken (invalid version)
1084 }
1085
1086 int val;
1087
1088 stream >> val;
1089 mGroupHeaderBackgroundMode = static_cast<GroupHeaderBackgroundMode>(val);
1090 switch (mGroupHeaderBackgroundMode) {
1091 case Transparent:
1092 case AutoColor:
1093 case CustomColor:
1094 // ok
1095 break;
1096 default:
1097 qCDebug(MESSAGELIST_LOG) << "Invalid theme group header background mode";
1098 return false; // b0rken
1099 }
1100
1101 stream >> mGroupHeaderBackgroundColor;
1102
1103 stream >> val;
1104 mGroupHeaderBackgroundStyle = static_cast<GroupHeaderBackgroundStyle>(val);
1105 switch (mGroupHeaderBackgroundStyle) {
1106 case PlainRect:
1107 case PlainJoinedRect:
1108 case RoundedRect:
1109 case RoundedJoinedRect:
1110 case GradientRect:
1111 case GradientJoinedRect:
1112 case StyledRect:
1113 case StyledJoinedRect:
1114 // ok
1115 break;
1116 default:
1117 qCDebug(MESSAGELIST_LOG) << "Invalid theme group header background style";
1118 return false; // b0rken
1119 }
1120
1121 stream >> val;
1122 mViewHeaderPolicy = (ViewHeaderPolicy)val;
1123 switch (mViewHeaderPolicy) {
1124 case ShowHeaderAlways:
1125 case NeverShowHeader:
1126 // ok
1127 break;
1128 default:
1129 qCDebug(MESSAGELIST_LOG) << "Invalid theme view header policy";
1130 return false; // b0rken
1131 }
1132
1133 if (themeVersion >= gThemeMinimumVersionWithIconSizeField) {
1134 // icon size parameter
1135 stream >> mIconSize;
1136 if ((mIconSize < 8) || (mIconSize > 64)) {
1137 mIconSize = gThemeDefaultIconSize; // limit insane values
1138 }
1139 } else {
1140 mIconSize = gThemeDefaultIconSize;
1141 }
1142
1143 // column count
1144 stream >> val;
1145 if (val < 1 || val > 50) {
1146 return false; // plain b0rken ( negative, zero or more than 50 columns )
1147 }
1148
1149 for (int i = 0; i < val; ++i) {
1150 auto col = new Column();
1151 if (!col->load(stream, themeVersion)) {
1152 qCDebug(MESSAGELIST_LOG) << "Column loading failed";
1153 delete col;
1154 return false;
1155 }
1156 addColumn(col);
1157 }
1158
1159 return true;
1160}
1161
1162void Theme::save(QDataStream &stream) const
1163{
1164 stream << (int)gThemeCurrentVersion;
1165
1166 stream << (int)mGroupHeaderBackgroundMode;
1167 stream << mGroupHeaderBackgroundColor;
1168 stream << (int)mGroupHeaderBackgroundStyle;
1169 stream << (int)mViewHeaderPolicy;
1170 stream << mIconSize;
1171
1172 const int cnt = mColumns.count();
1173 stream << (int)cnt;
1174
1175 for (int i = 0; i < cnt; ++i) {
1176 Column *col = mColumns.at(i);
1177 col->save(stream);
1178 }
1179}
1180
1181void Theme::clearPixmapCache() const
1182{
1183 qDeleteAll(mPixmaps);
1184 mPixmaps.clear();
1185}
1186
1187void Theme::populatePixmapCache() const
1188{
1189 clearPixmapCache();
1190
1191 mPixmaps.reserve(_IconCount);
1192 // WARNING: The order of those icons must be in sync with order of the
1193 // corresponding enum values in ThemeIcon!
1194 mPixmaps << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-unread-new")).pixmap(mIconSize, mIconSize))
1195 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-unread")).pixmap(mIconSize, mIconSize))
1196 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-read")).pixmap(mIconSize, mIconSize))
1197 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-deleted")).pixmap(mIconSize, mIconSize))
1198 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-replied")).pixmap(mIconSize, mIconSize))
1199 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-forwarded-replied")).pixmap(mIconSize, mIconSize))
1200 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-queued")).pixmap(mIconSize, mIconSize)) // mail-queue ?
1201 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-task")).pixmap(mIconSize, mIconSize))
1202 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-sent")).pixmap(mIconSize, mIconSize))
1203 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-forwarded")).pixmap(mIconSize, mIconSize))
1204 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-important")).pixmap(mIconSize, mIconSize)) // "flag"
1205 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-thread-watch")).pixmap(mIconSize, mIconSize))
1206 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-thread-ignored")).pixmap(mIconSize, mIconSize))
1207 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-junk")).pixmap(mIconSize, mIconSize))
1208 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-mark-notjunk")).pixmap(mIconSize, mIconSize))
1209 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-signed-verified")).pixmap(mIconSize, mIconSize))
1210 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-signed-part")).pixmap(mIconSize, mIconSize))
1211 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-signed")).pixmap(mIconSize, mIconSize))
1212 << new QPixmap(QIcon::fromTheme(QStringLiteral("text-plain")).pixmap(mIconSize, mIconSize))
1213 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-encrypted-full")).pixmap(mIconSize, mIconSize))
1214 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-encrypted-part")).pixmap(mIconSize, mIconSize))
1215 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-encrypted")).pixmap(mIconSize, mIconSize))
1216 << new QPixmap(QIcon::fromTheme(QStringLiteral("text-plain")).pixmap(mIconSize, mIconSize))
1217 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-attachment")).pixmap(mIconSize, mIconSize))
1218 << new QPixmap(QIcon::fromTheme(QStringLiteral("view-pim-notes")).pixmap(mIconSize, mIconSize))
1219 << new QPixmap(QIcon::fromTheme(QStringLiteral("mail-invitation")).pixmap(mIconSize, mIconSize))
1220 << ((QApplication::isRightToLeft()) ? new QPixmap(QIcon::fromTheme(QStringLiteral("arrow-left")).pixmap(mIconSize, mIconSize))
1221 : new QPixmap(QIcon::fromTheme(QStringLiteral("arrow-right")).pixmap(mIconSize, mIconSize)))
1222 << new QPixmap(QIcon::fromTheme(QStringLiteral("arrow-down")).pixmap(mIconSize, mIconSize))
1223 << new QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("messagelist/pics/mail-vertical-separator-line.png")))
1224 << new QPixmap(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("messagelist/pics/mail-horizontal-space.png")));
1225}
A set of options that can be applied to the MessageList in one shot.
Definition optionset.h:33
A class which holds information about sorting, e.g.
Definition sortorder.h:23
static bool isValidMessageSorting(SortOrder::MessageSorting ms)
Returns true if the ms parameter specifies a valid MessageSorting option.
MessageSorting
The available message sorting options.
Definition sortorder.h:60
@ NoMessageSorting
Don't sort the messages at all.
Definition sortorder.h:61
@ SortMessagesByUnreadStatus
Sort the messages by the "Unread" flags of status.
Definition sortorder.h:70
double currentWidth() const
Returns the current width or -1 if the width is unspecified/invalid.
Definition theme.cpp:555
void setCurrentlyVisible(bool visible)
Sets the current visibility state.
Definition theme.cpp:550
void addReference()
Increments the reference count for this shared runtime data object.
Definition theme.cpp:528
int referenceCount() const
Returns the current number of reference counts, that is, the number of Theme::Column objects that use...
Definition theme.cpp:540
bool deleteReference()
Decrements the reference count for this shared runtime data object.
Definition theme.cpp:533
~SharedRuntimeData()
Destroy a shared runtime data object.
bool currentlyVisible() const
Returns the current visibility state.
Definition theme.cpp:545
void setCurrentWidth(double currentWidth)
Sets the current width of the column.
Definition theme.cpp:560
SharedRuntimeData(bool currentlyVisible, double currentWidth)
Create a shared runtime data object.
Definition theme.cpp:519
void save(QDataStream &stream) const
Saves this runtime data to the specified stream.
Definition theme.cpp:565
bool load(QDataStream &stream, int themeVersion)
Loads the shared runtime data from the specified stream assuming that it uses the specified theme ver...
Definition theme.cpp:571
The Column class defines a view column available inside this theme.
Definition theme.h:501
bool isSenderOrReceiver() const
Returns true if this column is marked as "sender/receiver" and we should update its label on-the-fly.
Definition theme.cpp:639
void removeGroupHeaderRow(Row *row)
Removes the specified group header row.
Definition theme.cpp:757
void removeMessageRow(Row *row)
Removes the specified message row.
Definition theme.cpp:738
void setPixmapName(const QString &pixmapName)
Sets the icon's name (used in SmallIcon) for this column.
Definition theme.cpp:634
double currentWidth() const
Returns the current shared width setting for this column or -1 if the width is not specified and shou...
Definition theme.cpp:690
const QList< Row * > & groupHeaderRows() const
Returns the list of rows visible in this column for a GroupHeaderItem.
Definition theme.cpp:743
void save(QDataStream &stream) const
Handles column saving (used by Theme::save())
Definition theme.cpp:777
void detach()
Detaches the shared runtime data object and makes this object totally independent.
Definition theme.cpp:659
void insertMessageRow(int idx, Row *row)
Inserts a message row to this theme column in the specified position.
Definition theme.cpp:729
SortOrder::MessageSorting messageSorting() const
Returns the sort order for messages that we should switch to when clicking on this column's header (i...
Definition theme.cpp:670
bool visibleByDefault() const
Returns true if this column has to be shown by default.
Definition theme.cpp:649
void setMessageSorting(SortOrder::MessageSorting ms)
Sets the sort order for messages that we should switch to when clicking on this column's header (if v...
Definition theme.cpp:675
void setVisibleByDefault(bool vbd)
Sets the "visible by default" tag for this column.
Definition theme.cpp:654
void setIsSenderOrReceiver(bool sor)
Marks this column as containing the "sender/receiver" field.
Definition theme.cpp:644
void addGroupHeaderRow(Row *row)
Appends a group header row to this theme.
Definition theme.cpp:724
void setCurrentWidth(double currentWidth)
Sets the current shared width setting for this column.
Definition theme.cpp:695
Column()
Create an empty column with default settings.
Definition theme.cpp:582
const QList< Row * > & messageRows() const
Returns the list of rows visible in this column for a MessageItem.
Definition theme.cpp:700
bool currentlyVisible() const
Returns the current shared visibility state for this column.
Definition theme.cpp:680
const QString & pixmapName() const
Returns the icon's name (used in SmallIcon) set for this column.
Definition theme.cpp:629
void setLabel(const QString &label)
Sets the label for this column.
Definition theme.cpp:624
void setCurrentlyVisible(bool currentlyVisible)
Sets the current shared visibility state for this column.
Definition theme.cpp:685
void insertGroupHeaderRow(int idx, Row *row)
Inserts a group header row to this theme column in the specified position.
Definition theme.cpp:748
const QString & label() const
Returns the label set for this column.
Definition theme.cpp:619
void removeAllGroupHeaderRows()
Removes all the group header rows from this column.
Definition theme.cpp:717
bool containsTextItems() const
Returns true if this column contains text items.
Definition theme.cpp:762
void removeAllMessageRows()
Removes all the message rows from this column.
Definition theme.cpp:705
~Column()
Kill a column object.
Definition theme.cpp:610
bool load(QDataStream &stream, int themeVersion)
Handles column loading (used by Theme::load())
Definition theme.cpp:806
void addMessageRow(Row *row)
Appends a message row to this theme column.
Definition theme.cpp:712
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 canBeDisabled() const
Returns true if this ContentItem can be in a "disabled" state.
Definition theme.cpp:67
void setSoftenByBlending(bool softenByBlending)
Sets the flag that causes this item to be painted "softly".
Definition theme.cpp:256
bool hideWhenDisabled() const
Returns true if this item should be hidden when in disabled state.
Definition theme.cpp:223
void setBold(bool isBold)
Makes this item use a bold font.
Definition theme.cpp:200
void setUseCustomColor(bool useCustomColor)
Makes this item use the custom color that can be set by setCustomColor().
Definition theme.cpp:186
static QString description(Type type)
Returns a descriptive name for the specified content item type.
Definition theme.cpp:102
static bool applicableToMessageItems(Type type)
Static test that returns true if an instance of ContentItem with the specified type makes sense in a ...
Definition theme.cpp:275
bool isSpacer() const
Returns true if this item is a small spacer.
Definition theme.cpp:97
void setSoftenByBlendingWhenDisabled(bool softenByBlendingWhenDisabled)
Sets the flag that causes this item to be painted "softly" when disabled.
Definition theme.cpp:242
bool isBold() const
Returns true if this item uses a bold text.
Definition theme.cpp:195
void setItalic(bool isItalic)
Makes this item use italic font.
Definition theme.cpp:214
void setCustomColor(const QColor &clr)
Sets the custom color for this item.
Definition theme.cpp:270
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
void save(QDataStream &stream) const
Handles content item saving (used by Theme::Row::save())
Definition theme.cpp:285
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
bool load(QDataStream &stream, int themeVersion)
Handles content item loading (used by Theme::Row::load())
Definition theme.cpp:292
bool isClickable() const
Returns true if clicking on this kind of item can perform an action.
Definition theme.cpp:92
Type
The available ContentItem types.
Definition theme.h:106
@ InvitationIcon
Whether the message is an invitation.
Definition theme.h:198
@ AttachmentStateIcon
The icon that displays the attachment state (may be disabled)
Definition theme.h:138
@ Subject
Display the subject of the message item.
Definition theme.h:110
void setHideWhenDisabled(bool hideWhenDisabled)
Sets the flag that causes this item to be hidden when disabled.
Definition theme.cpp:228
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
ContentItem(Type type)
Creates a ContentItem with the specified type.
Definition theme.cpp:52
static bool applicableToGroupHeaderItems(Type type)
Static test that returns true if an instance of ContentItem with the specified type makes sense in a ...
Definition theme.cpp:280
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
void removeLeftItem(ContentItem *item)
Removes the specified left aligned content item from this row.
Definition theme.cpp:393
void addRightItem(ContentItem *item)
Adds a right aligned item to this row.
Definition theme.cpp:379
void insertRightItem(int idx, ContentItem *item)
Adds a right aligned item at the specified position in this row.
Definition theme.cpp:403
bool containsTextItems() const
Returns true if this row contains text items.
Definition theme.cpp:417
void removeAllLeftItems()
Removes all the left items from this row: the items are deleted.
Definition theme.cpp:360
bool load(QDataStream &stream, int themeVersion)
Handles row loading (used by Theme::Column::load())
Definition theme.cpp:494
void insertLeftItem(int idx, ContentItem *item)
Adds a left aligned item at the specified position in this row.
Definition theme.cpp:384
void removeAllRightItems()
Removes all the right items from this row.
Definition theme.cpp:372
void removeRightItem(ContentItem *item)
Removes the specified right aligned content item from this row.
Definition theme.cpp:412
void save(QDataStream &stream) const
Handles row saving (used by Theme::Column::save())
Definition theme.cpp:432
void addLeftItem(ContentItem *item)
Adds a left aligned item to this row.
Definition theme.cpp:367
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
GroupHeaderBackgroundMode
Which color do we use to paint group header background ?
Definition theme.h:793
@ 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
void setGroupHeaderBackgroundStyle(GroupHeaderBackgroundStyle groupHeaderBackgroundStyle)
Sets the group header background style for this theme.
Definition theme.cpp:1022
void setGroupHeaderBackgroundColor(const QColor &clr)
Sets the group header background color for this theme.
Definition theme.cpp:1012
void setViewHeaderPolicy(ViewHeaderPolicy vhp)
Sets the ViewHeaderPolicy for this theme.
Definition theme.cpp:1049
ViewHeaderPolicy
How do we manage the QHeaderView attached to our View ?
Definition theme.h:816
void removeColumn(Column *col)
Removes the specified message row.
Definition theme.cpp:981
void setGroupHeaderBackgroundMode(GroupHeaderBackgroundMode bm)
Sets the group header background mode for this theme.
Definition theme.cpp:999
void setIconSize(int iconSize)
Sets the icon size for this theme.
Definition theme.cpp:1059
void detach()
Detaches this object from the shared runtime data for columns.
Definition theme.cpp:928
const QColor & groupHeaderBackgroundColor() const
Returns the group header background color for this theme.
Definition theme.cpp:1007
static QList< QPair< QString, int > > enumerateGroupHeaderBackgroundStyles()
Enumerates the available group header background styles.
Definition theme.cpp:1032
~Theme() override
Destroys this theme object.
Definition theme.cpp:922
Theme()
Creates a totally uninitialized theme object.
Definition theme.cpp:891
GroupHeaderBackgroundMode groupHeaderBackgroundMode() const
Returns the group header background mode for this theme.
Definition theme.cpp:986
void addColumn(Column *column)
Appends a column to this theme.
Definition theme.cpp:967
void insertColumn(int idx, Column *column)
Inserts a column to this theme at the specified position.
Definition theme.cpp:972
ViewHeaderPolicy viewHeaderPolicy() const
Returns the currently set ViewHeaderPolicy.
Definition theme.cpp:1044
void resetColumnSizes()
Resets the column sizes to "default" (subset of resetColumnState() above).
Definition theme.cpp:943
GroupHeaderBackgroundStyle groupHeaderBackgroundStyle() const
Returns the group header background style for this theme.
Definition theme.cpp:1017
static QList< QPair< QString, int > > enumerateViewHeaderPolicyOptions()
Enumerates the available view header policy options.
Definition theme.cpp:1027
bool load(QDataStream &stream) override
Pure virtual reimplemented from OptionSet.
Definition theme.cpp:1071
int iconSize() const
Returns the currently set icon size.
Definition theme.cpp:1054
const QList< Column * > & columns() const
Returns the list of columns available in this theme.
Definition theme.cpp:950
void save(QDataStream &stream) const override
Pure virtual reimplemented from OptionSet.
Definition theme.cpp:1162
void removeAllColumns()
Removes all columns from this theme.
Definition theme.cpp:960
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
void resetColumnState()
Resets the column state (visibility and width) to their default values (the "visible by default" ones...
Definition theme.cpp:935
GroupHeaderBackgroundStyle
How do we paint group header background ?
Definition theme.h:802
@ 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
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
The implementation independent part of the MessageList library.
Definition aggregation.h:22
bool isValid() const const
bool isRightToLeft()
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
void clear()
void reserve(qsizetype size)
value_type takeFirst()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:54:19 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.