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 #pragma once
10 
11 #include <QColor>
12 #include <QList>
13 #include <QPair>
14 #include <QString>
15 #include <QVector>
16 
17 #include <core/optionset.h>
18 #include <core/sortorder.h>
19 
20 class QPixmap;
21 
22 namespace MessageList
23 {
24 namespace Core
25 {
26 /**
27  * The Theme class defines the visual appearance of the MessageList.
28  *
29  * The core structure of the theme is made up of Column objects which
30  * are mapped to View (QTreeView) columns. Each theme must provide at least one column.
31  *
32  * Each column contains a set of Row objects dedicated to message items
33  * and a set of Row objects dedicated to group header items. There must be at least
34  * one message row and one group header row in each column. Rows are visually
35  * ordered from top to bottom.
36  *
37  * Each Row contains a set of left aligned and a set of right aligned ContentItem objects.
38  * The right aligned items are painted from right to left while the left aligned
39  * ones are painted from left to right. In Right-To-Left mode the ThemeDelegate
40  * follows the exact opposite convention.
41  *
42  * Each ContentItem object specifies a visual element to be displayed in a View
43  * row. The visual elements may be pieces of text (Subject, Date) or icons.
44  *
45  * The Theme is designed to strictly interoperate with the ThemeDelegate class
46  * which takes care of rendering the contents when attached to an QAbstractItemView.
47  */
48 class Theme : public OptionSet
49 {
50 public:
51     /**
52      * The ContentItem class defines a content item inside a Row.
53      * Content items are data items extracted from a message or a group header:
54      * they can be text, spacers, separators or icons.
55      */
56     class ContentItem
57     {
58     private:
59         /**
60          * Bits for composing the Type enumeration members.
61          * We'll be able to test these bits to quickly figure out item properties.
62          */
63         enum TypePropertyBits {
64             /**
65              * Item can use the custom color property
66              */
67             CanUseCustomColor = (1 << 16),
68             /**
69              * Item can be in a disabled state (for example the attachment icon when there is no attachment)
70              */
71             CanBeDisabled = (1 << 17),
72             /**
73              * Item displays some sort of text
74              */
75             DisplaysText = (1 << 18),
76             /**
77              * Item makes sense (and can be applied) for messages
78              */
79             ApplicableToMessageItems = (1 << 19),
80             /**
81              * Item makes sense (and can be applied) for group headers
82              */
83             ApplicableToGroupHeaderItems = (1 << 20),
84             /**
85              * The item takes more horizontal space than the other text items (at the time of writing it's only the subject)
86              */
87             LongText = (1 << 21),
88             /**
89              * The item displays an icon
90              */
91             IsIcon = (1 << 22),
92             /**
93              * The item is a small spacer
94              */
95             IsSpacer = (1 << 23),
96             /**
97              * The item is clickable
98              */
99             IsClickable = (1 << 24)
100         };
101 
102     public:
103         /**
104          * The available ContentItem types.
105          * Note that the values in this enum are unique values or'ed with the TypePropertyBits above.
106          */
107         enum Type {
108             /**
109              * Display the subject of the message item. This is a long text.
110              */
111             Subject = 1 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems | LongText,
112             /**
113              * Formatted date time of the message/group
114              */
115             Date = 2 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems | ApplicableToGroupHeaderItems,
116             /**
117              * From: or To: strip, depending on the folder settings
118              */
119             SenderOrReceiver = 3 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems,
120             /**
121              * From: strip, always
122              */
123             Sender = 4 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems,
124             /**
125              * To: strip, always
126              */
127             Receiver = 5 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems,
128             /**
129              * Formatted size of the message
130              */
131             Size = 6 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems,
132             /**
133              * The icon that displays the unread/read state (never disabled)
134              */
135             ReadStateIcon = 7 | ApplicableToMessageItems | IsIcon,
136             /**
137              * The icon that displays the attachment state (may be disabled)
138              */
139             AttachmentStateIcon = 8 | CanBeDisabled | ApplicableToMessageItems | IsIcon,
140             /**
141              * The icon that displays the replied/forwarded state (may be disabled)
142              */
143             RepliedStateIcon = 9 | CanBeDisabled | ApplicableToMessageItems | IsIcon,
144             /**
145              * The group header label
146              */
147             GroupHeaderLabel = 10 | DisplaysText | CanUseCustomColor | ApplicableToGroupHeaderItems,
148             /**
149              * The ActionItem state icon. May be disabled. Clickable (cycles todo->nothing)
150              */
151             ActionItemStateIcon = 11 | CanBeDisabled | ApplicableToMessageItems | IsIcon | IsClickable,
152             /**
153              * The Important tag icon. May be disabled. Clickable (cycles important->nothing)
154              */
155             ImportantStateIcon = 12 | CanBeDisabled | ApplicableToMessageItems | IsIcon | IsClickable,
156             /**
157              * The Spam/Ham state icon. May be disabled. Clickable (cycles spam->ham->nothing)
158              */
159             SpamHamStateIcon = 13 | CanBeDisabled | ApplicableToMessageItems | IsIcon | IsClickable,
160             /**
161              * The Watched/Ignored state icon. May be disabled. Clickable (cycles watched->ignored->nothing)
162              */
163             WatchedIgnoredStateIcon = 14 | CanBeDisabled | ApplicableToMessageItems | IsIcon | IsClickable,
164             /**
165              * The Expanded state icon for group headers. May be disabled. Clickable (expands/collapses the group)
166              */
167             ExpandedStateIcon = 15 | CanBeDisabled | ApplicableToGroupHeaderItems | IsIcon | IsClickable,
168             /**
169              * The Encryption state icon for messages. May be disabled (no encryption).
170              */
171             EncryptionStateIcon = 16 | CanBeDisabled | ApplicableToMessageItems | IsIcon,
172             /**
173              * The Signature state icon for messages. May be disabled (no signature)
174              */
175             SignatureStateIcon = 17 | CanBeDisabled | ApplicableToMessageItems | IsIcon,
176             /**
177              * A vertical separation line.
178              */
179             VerticalLine = 18 | CanUseCustomColor | ApplicableToMessageItems | ApplicableToGroupHeaderItems | IsSpacer,
180             /**
181              * A small empty spacer usable as separator.
182              */
183             HorizontalSpacer = 19 | ApplicableToMessageItems | ApplicableToGroupHeaderItems | IsSpacer,
184             /**
185              * The date of the most recent message in subtree
186              */
187             MostRecentDate = 20 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems | ApplicableToGroupHeaderItems,
188             /**
189              * The combined icon that displays the unread/read/replied/forwarded state (never disabled)
190              */
191             CombinedReadRepliedStateIcon = 21 | ApplicableToMessageItems | IsIcon,
192             /**
193              * The list of MessageItem::Tag entries
194              */
195             TagList = 22 | ApplicableToMessageItems | IsIcon,
196             /**
197              * Whether the message has a annotation/note
198              */
199             AnnotationIcon = 23 | ApplicableToMessageItems | IsIcon | CanBeDisabled | IsClickable,
200 
201             /**
202              * Whether the message is an invitation
203              */
204             InvitationIcon = 24 | ApplicableToMessageItems | IsIcon,
205             /**
206              * Folder of the message
207              */
208             Folder = 25 | DisplaysText | CanUseCustomColor | ApplicableToMessageItems
209 #if 0
210                      TotalMessageCount
211                      UnreadMessageCount
212                      NewMessageCount
213 #endif
214         };
215 
216         enum Flags {
217             HideWhenDisabled = 1, ///< In disabled state the icon should take no space (overrides SoftenByBlendingWhenDisabled)
218             SoftenByBlendingWhenDisabled = (1 << 1), ///< In disabled state the icon should be still shown, but made very soft by alpha blending
219             UseCustomColor = (1 << 2), ///< For text and vertical line. If set then always use a custom color, otherwise use default text color
220             IsBold = (1 << 3), ///< For text items. If set then always show as bold, otherwise use the default font weight
221             IsItalic = (1 << 4), ///< Fot text items. If set then always show as italic, otherwise use the default font style
222             SoftenByBlending = (1 << 5) ///< For text items: use 60% opacity.
223         };
224 
225     private:
226         Type mType; ///< The type of item
227         unsigned int mFlags; ///< The flags of the item
228 
229         QColor mCustomColor; ///< The color to use with this content item, meaningful only if canUseCustomColor() return true.
230 
231     public:
232         /**
233          * Creates a ContentItem with the specified type.
234          * A content item must be added to a theme Row.
235          */
236         explicit ContentItem(Type type);
237         /**
238          * Creates a ContentItem that is a copy of the content item src.
239          * A content item must be added to a theme Row.
240          */
241         explicit ContentItem(const ContentItem &src);
242 
243     public:
244         /**
245          * Returns the type of this content item
246          */
247         Type type() const;
248 
249         /**
250          * Returns true if this ContentItem can be in a "disabled" state.
251          * The attachment state icon, for example, can be disabled when the related
252          * message has no attachments. For such items the HideWhenDisabled
253          * and SoftenByBlendingWhenDisabled flags are meaningful.
254          */
255         bool canBeDisabled() const;
256 
257         /**
258          * Returns true if this ContentItem can make use of a custom color.
259          */
260         bool canUseCustomColor() const;
261 
262         /**
263          * Returns true if this item displays some kind of text.
264          * Items that display text make use of the customFont() setting.
265          */
266         bool displaysText() const;
267 
268         /**
269          * Returns true if this item displays a long text.
270          * The returned value makes sense only if displaysText() returned true.
271          */
272         bool displaysLongText() const;
273 
274         /**
275          * Returns true if this item displays an icon.
276          */
277         bool isIcon() const;
278         /**
279          * Returns true if clicking on this kind of item can perform an action
280          */
281         bool isClickable() const;
282 
283         /**
284          * Returns true if this item is a small spacer
285          */
286         bool isSpacer() const;
287 
288         /**
289          * Static test that returns true if an instance of ContentItem with the
290          * specified type makes sense in a Row for message items.
291          */
292         static bool applicableToMessageItems(Type type);
293 
294         /**
295          * Static test that returns true if an instance of ContentItem with the
296          * specified type makes sense in a Row for group header items.
297          */
298         static bool applicableToGroupHeaderItems(Type type);
299 
300         /**
301          * Returns a descriptive name for the specified content item type
302          */
303         static QString description(Type type);
304 
305         /**
306          * Returns true if this item uses a custom color.
307          * The return value of this function is valid only if canUseCustomColor() returns true.
308          */
309         bool useCustomColor() const;
310 
311         /**
312          * Makes this item use the custom color that can be set by setCustomColor().
313          * The custom color is meaningful only if canUseCustomColor() returns true.
314          */
315         void setUseCustomColor(bool useCustomColor);
316 
317         /**
318          * Returns true if this item uses a bold text.
319          * The return value of this function is valid only if displaysText() returns true.
320          */
321         bool isBold() const;
322 
323         /**
324          * Makes this item use a bold font.
325          */
326         void setBold(bool isBold);
327 
328         /**
329          * Returns true if this item uses an italic text.
330          * The return value of this function is valid only if displaysText() returns true.
331          */
332         bool isItalic() const;
333 
334         /**
335          * Makes this item use italic font.
336          */
337         void setItalic(bool isItalic);
338 
339         /**
340          * Returns true if this item should be hidden when in disabled state.
341          * Hidden content items simply aren't painted and take no space.
342          * This flag has meaning only on items for that canBeDisabled() returns true.
343          */
344         bool hideWhenDisabled() const;
345 
346         /**
347          * Sets the flag that causes this item to be hidden when disabled.
348          * Hidden content items simply aren't painted and take no space.
349          * This flag overrides the setSoftenByBlendingWhenDisabled() setting.
350          * This flag has meaning only on items for that canBeDisabled() returns true.
351          */
352         void setHideWhenDisabled(bool hideWhenDisabled);
353 
354         /**
355          * Returns true if this item should be painted in a "soft" fashion when
356          * in disabled state. Soft icons are painted with very low opacity.
357          * This flag has meaning only on items for that canBeDisabled() returns true.
358          */
359         bool softenByBlendingWhenDisabled() const;
360 
361         /**
362          * Sets the flag that causes this item to be painted "softly" when disabled.
363          * Soft icons are painted with very low opacity.
364          * This flag may be overridden by the setHideWhenDisabled() setting.
365          * This flag has meaning only on items for that canBeDisabled() returns true.
366          */
367         void setSoftenByBlendingWhenDisabled(bool softenByBlendingWhenDisabled);
368 
369         /**
370          * Returns true if this item should be always painted in a "soft" fashion.
371          * Meaningful only for text items.
372          */
373         bool softenByBlending() const;
374 
375         /**
376          * Sets the flag that causes this item to be painted "softly".
377          * Meaningful only for text items.
378          */
379         void setSoftenByBlending(bool softenByBlending);
380 
381         /**
382          * Returns the custom color set for this item.
383          * The return value is meaningful only if canUseCustomColor() returns true
384          * returns true and setUseCustomColor( true ) has been called.
385          */
386         const QColor &customColor() const;
387 
388         /**
389          * Sets the custom color for this item. Meaningful only if canUseCustomColor()
390          * returns true and you call setUseCustomColor( true )
391          */
392         void setCustomColor(const QColor &clr);
393 
394         // Stuff used by ThemeDelegate. This section should be protected but some gcc
395         // versions seem to get confused with nested class and friend declarations
396         // so for portability we're using a public interface also here.
397 
398         /**
399          * Handles content item saving (used by Theme::Row::save())
400          */
401         void save(QDataStream &stream) const;
402 
403         /**
404          * Handles content item loading (used by Theme::Row::load())
405          */
406         bool load(QDataStream &stream, int themeVersion);
407     };
408 
409     /**
410      * The Row class defines a row of items inside a Column.
411      * The Row has a list of left aligned and a list of right aligned ContentItems.
412      */
413     class Row
414     {
415     public:
416         explicit Row();
417         explicit Row(const Row &src);
418         ~Row();
419 
420     private:
421         QList<ContentItem *> mLeftItems; ///< The list of left aligned items
422         QList<ContentItem *> mRightItems; ///< The list of right aligned items
423 
424         bool LoadContentItem(int val, QDataStream &stream, int themeVersion, bool leftItem);
425 
426     public:
427         /**
428          * Returns the list of left aligned items for this row
429          */
430         const QList<ContentItem *> &leftItems() const;
431 
432         /**
433          * Removes all the left items from this row: the items are deleted.
434          */
435         void removeAllLeftItems();
436 
437         /**
438          * Adds a left aligned item to this row. The row takes the ownership
439          * of the ContentItem pointer.
440          */
441         void addLeftItem(ContentItem *item);
442 
443         /**
444          * Adds a left aligned item at the specified position in this row. The row takes the ownership
445          * of the ContentItem pointer.
446          */
447         void insertLeftItem(int idx, ContentItem *item);
448 
449         /**
450          * Removes the specified left aligned content item from this row.
451          * The item is NOT deleted.
452          */
453         void removeLeftItem(ContentItem *item);
454 
455         /**
456          * Returns the list of right aligned items for this row
457          */
458         const QList<ContentItem *> &rightItems() const;
459 
460         /**
461          * Removes all the right items from this row. The items are deleted.
462          */
463         void removeAllRightItems();
464 
465         /**
466          * Adds a right aligned item to this row. The row takes the ownership
467          * of the ContentItem pointer. Please note that the first right aligned item
468          * will start at the right edge, the second right aligned item will come after it etc...
469          */
470         void addRightItem(ContentItem *item);
471 
472         /**
473          * Adds a right aligned item at the specified position in this row. The row takes the ownership
474          * of the ContentItem pointer. Remember that right item positions go from right to left.
475          */
476         void insertRightItem(int idx, ContentItem *item);
477 
478         /**
479          * Removes the specified right aligned content item from this row.
480          * The item is NOT deleted.
481          */
482         void removeRightItem(ContentItem *item);
483 
484         /**
485          * Returns true if this row contains text items.
486          * This is useful if you want to know if the column should just get
487          * its minimum allowable space or it should get more.
488          */
489         bool containsTextItems() const;
490 
491         /**
492          * Handles row saving (used by Theme::Column::save())
493          */
494         void save(QDataStream &stream) const;
495 
496         /**
497          * Handles row loading (used by Theme::Column::load())
498          */
499         bool load(QDataStream &stream, int themeVersion);
500     };
501 
502     /**
503      * The Column class defines a view column available inside this theme.
504      * Each Column has a list of Row items that define the visible rows.
505      */
506     class Column
507     {
508     public:
509         /**
510          * A set of shared runtime data. This is used to store a set of "override" settings
511          * at runtime. For instance, the width of the visible columns of a skin are stored here.
512          */
513         class SharedRuntimeData
514         {
515         private:
516             int mReferences; ///< The number of external references to this shared data object
517 
518             int mCurrentlyVisible; ///< Is this column currently visible ? always valid (eventually set from default)
519             double mCurrentWidth; ///< The current width of this column, -1 if not valid (never set)
520         public:
521             /**
522              * Create a shared runtime data object
523              */
524             explicit SharedRuntimeData(bool currentlyVisible, double currentWidth);
525 
526             /**
527              * Destroy a shared runtime data object
528              */
529             ~SharedRuntimeData();
530 
531         public:
532             /**
533              * Increments the reference count for this shared runtime data object.
534              */
535             void addReference();
536 
537             /**
538              * Decrements the reference count for this shared runtime data object.
539              * Returns true if there are other references and false otherwise (so the data can be safely deleted)
540              */
541             bool deleteReference();
542 
543             /**
544              * Returns the current number of reference counts, that is, the number of
545              * Theme::Column objects that use this SharedRuntimeData instance.
546              */
547             int referenceCount() const;
548 
549             /**
550              * Returns the current visibility state
551              */
552             bool currentlyVisible() const;
553 
554             /**
555              * Sets the current visibility state
556              */
557             void setCurrentlyVisible(bool visible);
558 
559             /**
560              * Returns the current width or -1 if the width is unspecified/invalid
561              */
562             double currentWidth() const;
563 
564             /**
565              * Sets the current width of the column
566              */
567             void setCurrentWidth(double currentWidth);
568 
569             /**
570              * Saves this runtime data to the specified stream
571              */
572             void save(QDataStream &stream) const;
573 
574             /**
575              * Loads the shared runtime data from the specified stream
576              * assuming that it uses the specified theme version.
577              * Returns true on success and false if the data can't be loaded.
578              */
579             bool load(QDataStream &stream, int themeVersion);
580         };
581 
582     public:
583         /**
584          * Create an empty column with default settings
585          */
586         explicit Column();
587         /**
588          * Create an exact copy of the column src.
589          * The shared runtime data is not copied (only a reference is added).
590          * If you need to create an independent clone then please use detach()
591          * after the construction.
592          */
593         explicit Column(const Column &src);
594         /**
595          * Kill a column object
596          */
597         ~Column();
598 
599     private:
600         QString mLabel; ///< The label visible in the column header
601         QString mPixmapName; ///< The icon's name visible in the column header if it was set
602         bool mVisibleByDefault; ///< Is this column visible by default ?
603         bool mIsSenderOrReceiver; ///< If this column displays the sender/receiver field then we will update its label on the fly
604         SortOrder::MessageSorting mMessageSorting; ///< The message sort order we switch to when clicking on this column
605         QList<Row *> mGroupHeaderRows; ///< The list of rows we display in this column for a GroupHeaderItem
606         QList<Row *> mMessageRows; ///< The list of rows we display in this column for a MessageItem
607 
608         SharedRuntimeData *mSharedRuntimeData = nullptr; ///< A pointer to the shared runtime data: shared between all instances of a theme with the same id
609     public:
610         /**
611          * Returns the label set for this column
612          */
613         const QString &label() const;
614 
615         /**
616          * Sets the label for this column
617          */
618         void setLabel(const QString &label);
619 
620         /**
621          * Returns the icon's name (used in SmallIcon) set for this column
622          */
623         const QString &pixmapName() const;
624 
625         /**
626          * Sets the icon's name (used in SmallIcon) for this column
627          */
628         void setPixmapName(const QString &pixmapName);
629 
630         /**
631          * Returns true if this column is marked as "sender/receiver" and we should
632          * update its label on-the-fly.
633          */
634         bool isSenderOrReceiver() const;
635 
636         /**
637          * Marks this column as containing the "sender/receiver" field.
638          * Such columns will have the label automatically updated.
639          */
640         void setIsSenderOrReceiver(bool sor);
641 
642         /**
643          * Returns true if this column has to be shown by default
644          */
645         bool visibleByDefault() const;
646 
647         /**
648          * Sets the "visible by default" tag for this column.
649          */
650         void setVisibleByDefault(bool vbd);
651 
652         /**
653          * Detaches the shared runtime data object and makes this object
654          * totally independent. The shared runtime data is initialized to default values.
655          */
656         void detach();
657 
658         /**
659          * Returns the sort order for messages that we should switch to
660          * when clicking on this column's header (if visible at all).
661          */
662         SortOrder::MessageSorting messageSorting() const;
663 
664         /**
665          * Sets the sort order for messages that we should switch to
666          * when clicking on this column's header (if visible at all).
667          */
668         void setMessageSorting(SortOrder::MessageSorting ms);
669 
670         /**
671          * Returns the current shared visibility state for this column.
672          * This state is shared between all the instances of this theme.
673          */
674         bool currentlyVisible() const;
675 
676         /**
677          * Sets the current shared visibility state for this column.
678          * This state is shared between all the instances of this theme.
679          */
680         void setCurrentlyVisible(bool currentlyVisible);
681 
682         /**
683          * Returns the current shared width setting for this column
684          * or -1 if the width is not specified and should be auto-determined.
685          * This state is shared between all the instances of this theme.
686          */
687         double currentWidth() const;
688 
689         /**
690          * Sets the current shared width setting for this column.
691          * This state is shared between all the instances of this theme.
692          */
693         void setCurrentWidth(double currentWidth);
694 
695         /**
696          * Returns the list of rows visible in this column for a MessageItem
697          */
698         const QList<Row *> &messageRows() const;
699 
700         /**
701          * Removes all the message rows from this column.
702          */
703         void removeAllMessageRows();
704 
705         /**
706          * Appends a message row to this theme column. The Theme takes
707          * the ownership of the Row pointer.
708          */
709         void addMessageRow(Row *row);
710 
711         /**
712          * Inserts a message row to this theme column in the specified position. The Theme takes
713          * the ownership of the Row pointer.
714          */
715         void insertMessageRow(int idx, Row *row);
716 
717         /**
718          * Removes the specified message row. The row is NOT deleted.
719          */
720         void removeMessageRow(Row *row);
721 
722         /**
723          * Returns the list of rows visible in this column for a GroupHeaderItem
724          */
725         const QList<Row *> &groupHeaderRows() const;
726 
727         /**
728          * Removes all the group header rows from this column.
729          */
730         void removeAllGroupHeaderRows();
731 
732         /**
733          * Appends a group header row to this theme. The Theme takes
734          * the ownership of the Row pointer.
735          */
736         void addGroupHeaderRow(Row *row);
737 
738         /**
739          * Inserts a group header row to this theme column in the specified position. The Theme takes
740          * the ownership of the Row pointer.
741          */
742         void insertGroupHeaderRow(int idx, Row *row);
743 
744         /**
745          * Removes the specified group header row. The row is NOT deleted.
746          */
747         void removeGroupHeaderRow(Row *row);
748 
749         /**
750          * Returns true if this column contains text items.
751          * This is useful if you want to know if the column should just get
752          * its minimum allowable space or it should get more.
753          */
754         bool containsTextItems() const;
755 
756         /**
757          * Handles column saving (used by Theme::save())
758          */
759         void save(QDataStream &stream) const;
760 
761         /**
762          * Handles column loading (used by Theme::load())
763          */
764         bool load(QDataStream &stream, int themeVersion);
765     };
766 
767 public:
768     /**
769      * Creates a totally uninitialized theme object.
770      */
771     explicit Theme();
772 
773     /**
774      * Creates a theme object with the specified name and description.
775      */
776     explicit Theme(const QString &name, const QString &description, bool readOnly = false);
777 
778     /**
779      * Creates an exact copy of the theme sharing the same runtime data.
780      * If you need an exact clone please use detach() and generateUniqueId() just
781      * after creation.
782      */
783     explicit Theme(const Theme &src);
784 
785     /**
786      * Destroys this theme object.
787      */
788     ~Theme() override;
789 
compareName(Theme * theme1,Theme * theme2)790     static bool compareName(Theme *theme1, Theme *theme2)
791     {
792         return theme1->name() < theme2->name();
793     }
794 
795 public:
796     /**
797      * Which color do we use to paint group header background ?
798      */
799     enum GroupHeaderBackgroundMode {
800         Transparent, ///< No background at all: use style default
801         AutoColor, ///< Automatically determine the color (somewhere in the middle between background and text)
802         CustomColor ///< Use a custom color
803     };
804 
805     /**
806      * How do we paint group header background ?
807      */
808     enum GroupHeaderBackgroundStyle {
809         PlainRect, ///< One plain rect per column
810         PlainJoinedRect, ///< One big plain rect for all the columns
811         RoundedRect, ///< One rounded rect per column
812         RoundedJoinedRect, ///< One big rounded rect for all the columns
813         GradientRect, ///< One rounded gradient filled rect per column
814         GradientJoinedRect, ///< One big rounded gradient rect for all the columns
815         StyledRect, ///< One styled rect per column
816         StyledJoinedRect ///< One big styled rect per column
817     };
818 
819     /**
820      * How do we manage the QHeaderView attached to our View ?
821      */
822     enum ViewHeaderPolicy {
823         ShowHeaderAlways,
824         NeverShowHeader
825         // ShowWhenMoreThanOneColumn,  ///< This doesn't work at the moment (since without header we don't have means for showing columns back)
826     };
827 
828     enum ThemeIcon {
829         IconNew,
830         IconUnread,
831         IconRead,
832         IconDeleted,
833         IconReplied,
834         IconRepliedAndForwarded,
835         IconQueued,
836         IconActionItem,
837         IconSent,
838         IconForwarded,
839         IconImportant,
840         IconWatched,
841         IconIgnored,
842         IconSpam,
843         IconHam,
844         IconFullySigned,
845         IconPartiallySigned,
846         IconUndefinedSigned,
847         IconNotSigned,
848         IconFullyEncrypted,
849         IconPartiallyEncrypted,
850         IconUndefinedEncrypted,
851         IconNotEncrypted,
852         IconAttachment,
853         IconAnnotation,
854         IconInvitation,
855         IconShowMore,
856         IconShowLess,
857         IconVerticalLine,
858         IconHorizontalSpacer,
859 
860         _IconCount
861     };
862 
863 private:
864     QList<Column *> mColumns; ///< The list of columns available in this theme
865 
866     // pixmaps cache. Mutable, so it can be lazily populated from const methods
867     mutable QVector<QPixmap *> mPixmaps;
868 
869     GroupHeaderBackgroundMode mGroupHeaderBackgroundMode; ///< How do we paint group header background ?
870     QColor mGroupHeaderBackgroundColor; ///< The background color of the message group, used only if CustomColor
871     GroupHeaderBackgroundStyle mGroupHeaderBackgroundStyle; ///< How do we paint group header background ?
872     ViewHeaderPolicy mViewHeaderPolicy; ///< Do we show the header or not ?
873     int mIconSize; ///< The icon size for this theme, 16 is the default
874 public:
875     /**
876      * Detaches this object from the shared runtime data for columns.
877      */
878     void detach();
879 
880     /**
881      * Resets the column state (visibility and width) to their default values (the "visible by default" ones).
882      */
883     void resetColumnState();
884 
885     /**
886      * Resets the column sizes to "default" (subset of resetColumnState() above).
887      */
888     void resetColumnSizes();
889 
890     /**
891      * Returns the list of columns available in this theme
892      */
893     const QList<Column *> &columns() const;
894 
895     /**
896      * Returns a pointer to the column at the specified index or 0 if there is no such column
897      */
898     Column *column(int idx) const;
899 
900     void moveColumn(int idx, int newPosition);
901 
902     /**
903      * Removes all columns from this theme
904      */
905     void removeAllColumns();
906 
907     /**
908      * Appends a column to this theme
909      */
910     void addColumn(Column *column);
911 
912     /**
913      * Inserts a column to this theme at the specified position.
914      */
915     void insertColumn(int idx, Column *column);
916 
917     /**
918      * Removes the specified message row. The row is NOT deleted.
919      */
920     void removeColumn(Column *col);
921 
922     /**
923      * Returns the group header background mode for this theme.
924      */
925     GroupHeaderBackgroundMode groupHeaderBackgroundMode() const;
926 
927     /**
928      * Sets the group header background mode for this theme.
929      * If you set it to CustomColor then please also setGroupHeaderBackgroundColor()
930      */
931     void setGroupHeaderBackgroundMode(GroupHeaderBackgroundMode bm);
932 
933     /**
934      * Returns the group header background color for this theme.
935      * This color is used only if groupHeaderBackgroundMode() is set to CustomColor.
936      */
937     const QColor &groupHeaderBackgroundColor() const;
938 
939     /**
940      * Sets the group header background color for this theme.
941      * This color is used only if groupHeaderBackgroundMode() is set to CustomColor.
942      */
943     void setGroupHeaderBackgroundColor(const QColor &clr);
944 
945     /**
946      * Returns the group header background style for this theme.
947      * The group header background style makes sense only if groupHeaderBackgroundMode() is
948      * set to something different than Transparent.
949      */
950     GroupHeaderBackgroundStyle groupHeaderBackgroundStyle() const;
951 
952     /**
953      * Sets the group header background style for this theme.
954      * The group header background style makes sense only if groupHeaderBackgroundMode() is
955      * set to something different than Transparent.
956      */
957     void setGroupHeaderBackgroundStyle(GroupHeaderBackgroundStyle groupHeaderBackgroundStyle);
958 
959     /**
960      * Enumerates the available group header background styles.
961      * The returned descriptors are pairs in that the first item is the localized description
962      * of the option value and the second item is the integer option value itself.
963      */
964     static QVector<QPair<QString, int>> enumerateGroupHeaderBackgroundStyles();
965 
966     /**
967      * Returns the currently set ViewHeaderPolicy
968      */
969     ViewHeaderPolicy viewHeaderPolicy() const;
970 
971     /**
972      * Sets the ViewHeaderPolicy for this theme
973      */
974     void setViewHeaderPolicy(ViewHeaderPolicy vhp);
975 
976     /**
977      * Returns the currently set icon size
978      */
979     int iconSize() const;
980 
981     /**
982      * Sets the icon size for this theme.
983      * Please note that the function will not let you set insane values.
984      * The allowable range is [8,64]
985      */
986     void setIconSize(int iconSize);
987 
988     /**
989      * Enumerates the available view header policy options.
990      * The returned descriptors are pairs in that the first item is the localized description
991      * of the option value and the second item is the integer option value itself.
992      */
993     static QVector<QPair<QString, int>> enumerateViewHeaderPolicyOptions();
994 
pixmap(ThemeIcon icon)995     inline const QPixmap *pixmap(ThemeIcon icon) const
996     {
997         if (Q_UNLIKELY(mPixmaps.isEmpty())) {
998             populatePixmapCache();
999         }
1000         return mPixmaps[icon];
1001     }
1002 
1003 protected:
1004     /**
1005      * Pure virtual reimplemented from OptionSet.
1006      */
1007     void save(QDataStream &stream) const override;
1008 
1009     /**
1010      * Pure virtual reimplemented from OptionSet.
1011      */
1012     bool load(QDataStream &stream) override;
1013 
1014     void clearPixmapCache() const;
1015     void populatePixmapCache() const;
1016 };
1017 } // namespace Core
1018 } // namespace MessageList
1019 
1020