030c1ac145314d02bb1b01d1f6565709fb821f60
[quassel.git] / src / uisupport / uistyle.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2016 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #ifndef UISTYLE_H_
22 #define UISTYLE_H_
23
24 #include <QDataStream>
25 #include <QFontMetricsF>
26 #include <QHash>
27 #include <QIcon>
28 #include <QTextCharFormat>
29 #include <QTextLayout>
30 #include <QPalette>
31 #include <QVector>
32
33 #include "bufferinfo.h"
34 #include "message.h"
35 #include "networkmodel.h"
36 #include "settings.h"
37
38 class UiStyle : public QObject
39 {
40     Q_OBJECT
41
42 public:
43     UiStyle(QObject *parent = 0);
44     virtual ~UiStyle();
45
46     typedef QList<QPair<quint16, quint32> > FormatList;
47
48     //! This enumerates the possible formats a text element may have. */
49     /** These formats are ordered on increasing importance, in cases where a given property is specified
50      *  by multiple active formats.
51      *  \NOTE: Do not change/add values here without also adapting the relevant
52      *         methods in this class (in particular mergedFormat())!
53      *         Also, we _do_ rely on certain properties of these values in styleString() and friends!
54      */
55     enum FormatType {
56         Base            = 0x00000000,
57         Invalid         = 0xffffffff,
58
59         // Message Formats (mutually exclusive!)
60         PlainMsg        = 0x00000001,
61         NoticeMsg       = 0x00000002,
62         ActionMsg       = 0x00000003,
63         NickMsg         = 0x00000004,
64         ModeMsg         = 0x00000005,
65         JoinMsg         = 0x00000006,
66         PartMsg         = 0x00000007,
67         QuitMsg         = 0x00000008,
68         KickMsg         = 0x00000009,
69         KillMsg         = 0x0000000a,
70         ServerMsg       = 0x0000000b,
71         InfoMsg         = 0x0000000c,
72         ErrorMsg        = 0x0000000d,
73         DayChangeMsg    = 0x0000000e,
74         TopicMsg        = 0x0000000f,
75         NetsplitJoinMsg = 0x00000010,
76         NetsplitQuitMsg = 0x00000020,
77         InviteMsg       = 0x00000030,
78
79         // Standard Formats
80         Bold            = 0x00000100,
81         Italic          = 0x00000200,
82         Underline       = 0x00000400,
83         Reverse         = 0x00000800,
84
85         // Individual parts of a message
86         Timestamp       = 0x00001000,
87         Sender          = 0x00002000,
88         Contents        = 0x00004000,
89         Nick            = 0x00008000,
90         Hostmask        = 0x00010000,
91         ChannelName     = 0x00020000,
92         ModeFlags       = 0x00040000,
93
94         // URL is special, we want that to take precedence over the rest...
95         Url             = 0x00080000
96
97                           // mIRC Colors - we assume those to be present only in plain contents
98                           // foreground: 0x0.400000
99                           // background: 0x.0800000
100     };
101
102     enum MessageLabel {
103         OwnMsg          = 0x00000001,
104         Highlight       = 0x00000002,
105         Selected        = 0x00000004 // must be last!
106     };
107
108     enum ItemFormatType {
109         BufferViewItem    = 0x00000001,
110         NickViewItem      = 0x00000002,
111
112         NetworkItem       = 0x00000010,
113         ChannelBufferItem = 0x00000020,
114         QueryBufferItem   = 0x00000040,
115         IrcUserItem       = 0x00000080,
116         UserCategoryItem  = 0x00000100,
117
118         InactiveBuffer    = 0x00001000,
119         ActiveBuffer      = 0x00002000,
120         UnreadBuffer      = 0x00004000,
121         HighlightedBuffer = 0x00008000,
122         UserAway          = 0x00010000
123     };
124
125     enum ColorRole {
126         MarkerLine,
127         // Sender colors (16 + self)
128         // These aren't used directly to avoid having storing all of the sender color options in the
129         // rendering routine of each item.  Also, I couldn't figure out how to do that.
130         // It would be nice to have the UseSenderColors preference also toggle sender colors set by
131         // themes, so hopefully this can be extended in the future.
132         // Furthermore, using this palette directly would mean separate sets of colors couldn't be
133         // used for different message types.
134         SenderColorSelf,
135         SenderColor00,
136         SenderColor01,
137         SenderColor02,
138         SenderColor03,
139         SenderColor04,
140         SenderColor05,
141         SenderColor06,
142         SenderColor07,
143         SenderColor08,
144         SenderColor09,
145         SenderColor0a,
146         SenderColor0b,
147         SenderColor0c,
148         SenderColor0d,
149         SenderColor0e,
150         SenderColor0f,
151         NumRoles // must be last!
152     };
153
154     struct StyledString {
155         QString plainText;
156         FormatList formatList; // starting pos, ftypes
157     };
158
159     class StyledMessage;
160
161     /**
162      * List of default sender colors
163      *
164      * In order from 1 - 16, matching the Sender## format in the settings file.
165      * Don't change the length or values of the colors without updating the UI and color roles, too.
166      *
167      * @see ../qtui/settingspages/chatviewsettingspage.ui
168      * @see UiStyle::ColorRole
169      */
170     const QList<QColor> defaultSenderColors = QList<QColor> {
171         QColor(204,   0,   0),  /// Sender00
172         QColor(  0, 108, 173),  /// Sender01
173         QColor( 77, 153,   0),  /// Sender02
174         QColor(102,   0, 204),  /// Sender03
175         QColor(166, 125,   0),  /// Sender04
176         QColor(  0, 153,  39),  /// Sender05
177         QColor(  0,  48, 192),  /// Sender06
178         QColor(204,   0, 154),  /// Sender07
179         QColor(185,  70,   0),  /// Sender08
180         QColor(134, 153,   0),  /// Sender09
181         QColor( 20, 153,   0),  /// Sender10
182         QColor(  0, 153,  96),  /// Sender11
183         QColor(  0, 108, 173),  /// Sender12
184         QColor(  0, 153, 204),  /// Sender13
185         QColor(179,   0, 204),  /// Sender14
186         QColor(204,   0,  77),  /// Sender15
187     };
188     // Explicitly declare QList<QColor> type for defaultSenderColors, otherwise error C2797
189     // "list initialization inside member initializer list" will occur in Windows builds with Visual
190     // Studio's compiler.
191     //
192     // See https://blogs.msdn.microsoft.com/vcblog/2014/08/19/the-future-of-non-static-data-member-initialization/
193     // Note: Qt Creator flags this as invalid unless you set Clang in
194     // Settings -> C++ -> Code Model -> Code Completion and Semantic Highlighting -> C
195     //
196     // See https://bugreports.qt.io/browse/QTCREATORBUG-1902
197
198     /**
199      * Default sender color for sent messages
200      */
201     const QColor defaultSenderColorSelf = QColor(0, 0, 0);
202
203     static FormatType formatType(Message::Type msgType);
204     static StyledString styleString(const QString &string, quint32 baseFormat = Base);
205     static QString mircToInternal(const QString &);
206
207     /**
208      * Gets if a custom timestamp format is used.
209      *
210      * @return True if custom timestamp format used, otherwise false
211      */
212     static inline bool useCustomTimestampFormat() { return _useCustomTimestampFormat; }
213
214     /**
215      * Gets the format string for chat log timestamps according to the system locale.
216      *
217      * This will return " hh:mm:ss" for system locales with 24-hour time or " h:mm:ss AP" for
218      * systems with 12-hour time.
219      *
220      * @return String representing timestamp format according to system locale, e.g. " hh:mm:ss"
221      */
222     static QString systemTimestampFormatString();
223
224     /**
225      * Gets the format string for chat log timestamps, either system locale or custom.
226      *
227      * Depending on useCustomTimestampFormat(), this will return either the system locale based
228      * time format, or the custom user-specified string.
229      *
230      * @return String representing timestamp format, e.g. "[hh:mm:ss]" or " hh:mm:ss"
231      */
232     static QString timestampFormatString();
233
234     QTextCharFormat format(quint32 formatType, quint32 messageLabel) const;
235     QFontMetricsF *fontMetrics(quint32 formatType, quint32 messageLabel) const;
236
237     QList<QTextLayout::FormatRange> toTextLayoutList(const FormatList &, int textLength, quint32 messageLabel) const;
238
239     inline const QBrush &brush(ColorRole role) const { return _uiStylePalette.at((int)role); }
240     inline void setBrush(ColorRole role, const QBrush &brush) { _uiStylePalette[(int)role] = brush; }
241
242     QVariant bufferViewItemData(const QModelIndex &networkModelIndex, int role) const;
243     QVariant nickViewItemData(const QModelIndex &networkModelIndex, int role) const;
244
245 public slots:
246     void reload();
247
248 signals:
249     void changed();
250
251 protected:
252     void loadStyleSheet();
253     QString loadStyleSheet(const QString &name, bool shouldExist = false);
254
255     QTextCharFormat format(quint64 key) const;
256     QTextCharFormat cachedFormat(quint32 formatType, quint32 messageLabel) const;
257     void setCachedFormat(const QTextCharFormat &format, quint32 formatType, quint32 messageLabel) const;
258     void mergeFormat(QTextCharFormat &format, quint32 formatType, quint64 messageLabel) const;
259     void mergeSubElementFormat(QTextCharFormat &format, quint32 formatType, quint64 messageLabel) const;
260
261     static FormatType formatType(const QString &code);
262     static QString formatCode(FormatType);
263
264     /**
265      * Cache the system locale timestamp format string
266      *
267      * Based on whether or not AM/PM designators are used in the QLocale::system().timeFormat(),
268      * this extends the system locale timestamp format string to include seconds.
269      *
270      * @see UiStyle::systemTimestampFormatString()
271      */
272     static void updateSystemTimestampFormat();
273
274     /**
275      * Updates the local setting cache of whether or not to use the custom timestamp format
276      *
277      * @param[in] enabled  If true, custom timestamp format used, otherwise false
278      */
279     static void setUseCustomTimestampFormat(bool enabled);
280
281     /**
282      * Updates the local setting cache of the timestamp format string
283      *
284      * @param[in] format   Timestamp format string
285      */
286     static void setTimestampFormatString(const QString &format);
287
288     /**
289      * Updates the local setting cache of whether or not to show sender brackets
290      *
291      * @param[in] enabled  If true, sender brackets are enabled, otherwise false.
292      */
293     static void enableSenderBrackets(bool enabled);
294
295     QVariant itemData(int role, const QTextCharFormat &format) const;
296
297 private slots:
298     void allowMircColorsChanged(const QVariant &);
299     void showItemViewIconsChanged(const QVariant &);
300
301 private:
302     QVector<QBrush> _uiStylePalette;
303     QBrush _markerLineBrush;
304     QHash<quint64, QTextCharFormat> _formats;
305     mutable QHash<quint64, QTextCharFormat> _formatCache;
306     mutable QHash<quint64, QFontMetricsF *> _metricsCache;
307     QHash<quint32, QTextCharFormat> _listItemFormats;
308     static QHash<QString, FormatType> _formatCodes;
309     static bool _useCustomTimestampFormat;        /// If true, use the custom timestamp format
310     static QString _systemTimestampFormatString;  /// Cached copy of system locale timestamp format
311     static QString _timestampFormatString;        /// Timestamp format string
312     static bool _showSenderBrackets;              /// If true, show brackets around sender names
313
314     QIcon _channelJoinedIcon;
315     QIcon _channelPartedIcon;
316     QIcon _userOfflineIcon;
317     QIcon _userOnlineIcon;
318     QIcon _userAwayIcon;
319     QIcon _categoryOpIcon;
320     QIcon _categoryVoiceIcon;
321     int _opIconLimit;
322     int _voiceIconLimit;
323     bool _showNickViewIcons;
324     bool _showBufferViewIcons;
325     bool _allowMircColors;
326 };
327
328
329 class UiStyle::StyledMessage : public Message
330 {
331     Q_DECLARE_TR_FUNCTIONS(UiStyle::StyledMessage)
332
333 public:
334     explicit StyledMessage(const Message &message);
335
336     QString decoratedTimestamp() const;
337     QString plainSender() const;           //!< Nickname (no decorations) for Plain and Notice, empty else
338     QString decoratedSender() const;
339     const QString &plainContents() const;
340
341     const FormatList &contentsFormatList() const;
342
343     quint8 senderHash() const;
344
345 protected:
346     void style() const;
347
348 private:
349     mutable StyledString _contents;
350     mutable quint8 _senderHash;
351 };
352
353
354 QDataStream &operator<<(QDataStream &out, const UiStyle::FormatList &formatList);
355 QDataStream &operator>>(QDataStream &in, UiStyle::FormatList &formatList);
356
357 Q_DECLARE_METATYPE(UiStyle::FormatList)
358
359 #endif