KSyntaxHighlighting

themedata.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Volker Krause <[email protected]>
3  SPDX-FileCopyrightText: 2016 Dominik Haumann <[email protected]>
4  SPDX-FileCopyrightText: 2020 Jonathan Poelen <[email protected]>
5 
6  SPDX-License-Identifier: MIT
7 */
8 
9 #include "ksyntaxhighlighting_logging.h"
10 #include "themedata_p.h"
11 
12 #include <QFile>
13 #include <QFileInfo>
14 #include <QJsonDocument>
15 #include <QJsonObject>
16 #include <QJsonValue>
17 #include <QMetaEnum>
18 
19 using namespace KSyntaxHighlighting;
20 
21 ThemeData *ThemeData::get(const Theme &theme)
22 {
23  return theme.m_data.data();
24 }
25 
26 ThemeData::ThemeData()
27 {
28  memset(m_editorColors, 0, sizeof(m_editorColors));
29  m_textStyles.resize(QMetaEnum::fromType<Theme::TextStyle>().keyCount());
30 }
31 
32 /**
33  * Convert QJsonValue @p val into a color, if possible. Valid colors are only
34  * in hex format: #aarrggbb. On error, returns 0x00000000.
35  */
36 static inline QRgb readColor(const QJsonValue &val)
37 {
38  const QRgb unsetColor = 0;
39  if (!val.isString()) {
40  return unsetColor;
41  }
42  const QString str = val.toString();
43  if (str.isEmpty() || str[0] != QLatin1Char('#')) {
44  return unsetColor;
45  }
46  const QColor color(str);
47  return color.isValid() ? color.rgba() : unsetColor;
48 }
49 
50 static inline TextStyleData readThemeData(const QJsonObject &obj)
51 {
52  TextStyleData td;
53 
54  td.textColor = readColor(obj.value(QLatin1String("text-color")));
55  td.backgroundColor = readColor(obj.value(QLatin1String("background-color")));
56  td.selectedTextColor = readColor(obj.value(QLatin1String("selected-text-color")));
57  td.selectedBackgroundColor = readColor(obj.value(QLatin1String("selected-background-color")));
58 
59  auto val = obj.value(QLatin1String("bold"));
60  if (val.isBool()) {
61  td.bold = val.toBool();
62  td.hasBold = true;
63  }
64  val = obj.value(QLatin1String("italic"));
65  if (val.isBool()) {
66  td.italic = val.toBool();
67  td.hasItalic = true;
68  }
69  val = obj.value(QLatin1String("underline"));
70  if (val.isBool()) {
71  td.underline = val.toBool();
72  td.hasUnderline = true;
73  }
74  val = obj.value(QLatin1String("strike-through"));
75  if (val.isBool()) {
76  td.strikeThrough = val.toBool();
77  td.hasStrikeThrough = true;
78  }
79 
80  return td;
81 }
82 
83 bool ThemeData::load(const QString &filePath)
84 {
85  QFile loadFile(filePath);
86  if (!loadFile.open(QIODevice::ReadOnly)) {
87  return false;
88  }
89  const QByteArray jsonData = loadFile.readAll();
90 
91  QJsonParseError parseError;
92  QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
93  if (parseError.error != QJsonParseError::NoError) {
94  qCWarning(Log) << "Failed to parse theme file" << filePath << ":" << parseError.errorString();
95  return false;
96  }
97 
98  m_filePath = filePath;
99 
100  QJsonObject obj = jsonDoc.object();
101 
102  // read metadata
103  const QJsonObject metadata = obj.value(QLatin1String("metadata")).toObject();
104  m_name = metadata.value(QLatin1String("name")).toString();
105  m_revision = metadata.value(QLatin1String("revision")).toInt();
106 
107  // read text styles
108  const auto metaEnumStyle = QMetaEnum::fromType<Theme::TextStyle>();
109  const QJsonObject textStyles = obj.value(QLatin1String("text-styles")).toObject();
110  for (int i = 0; i < metaEnumStyle.keyCount(); ++i) {
111  Q_ASSERT(i == metaEnumStyle.value(i));
112  m_textStyles[i] = readThemeData(textStyles.value(QLatin1String(metaEnumStyle.key(i))).toObject());
113  }
114 
115  // read editor colors
116  const auto metaEnumColor = QMetaEnum::fromType<Theme::EditorColorRole>();
117  const QJsonObject editorColors = obj.value(QLatin1String("editor-colors")).toObject();
118  for (int i = 0; i < metaEnumColor.keyCount(); ++i) {
119  Q_ASSERT(i == metaEnumColor.value(i));
120  m_editorColors[i] = readColor(editorColors.value(QLatin1String(metaEnumColor.key(i))));
121  }
122 
123  // if we have no new key around for Theme::BackgroundColor => use old variants to be compatible
124  if (!editorColors.contains(QLatin1String(metaEnumColor.key(Theme::BackgroundColor)))) {
125  m_editorColors[Theme::BackgroundColor] = readColor(editorColors.value(QLatin1String("background-color")));
126  m_editorColors[Theme::TextSelection] = readColor(editorColors.value(QLatin1String("selection")));
127  m_editorColors[Theme::CurrentLine] = readColor(editorColors.value(QLatin1String("current-line")));
128  m_editorColors[Theme::SearchHighlight] = readColor(editorColors.value(QLatin1String("search-highlight")));
129  m_editorColors[Theme::ReplaceHighlight] = readColor(editorColors.value(QLatin1String("replace-highlight")));
130  m_editorColors[Theme::BracketMatching] = readColor(editorColors.value(QLatin1String("bracket-matching")));
131  m_editorColors[Theme::TabMarker] = readColor(editorColors.value(QLatin1String("tab-marker")));
132  m_editorColors[Theme::SpellChecking] = readColor(editorColors.value(QLatin1String("spell-checking")));
133  m_editorColors[Theme::IndentationLine] = readColor(editorColors.value(QLatin1String("indentation-line")));
134  m_editorColors[Theme::IconBorder] = readColor(editorColors.value(QLatin1String("icon-border")));
135  m_editorColors[Theme::CodeFolding] = readColor(editorColors.value(QLatin1String("code-folding")));
136  m_editorColors[Theme::LineNumbers] = readColor(editorColors.value(QLatin1String("line-numbers")));
137  m_editorColors[Theme::CurrentLineNumber] = readColor(editorColors.value(QLatin1String("current-line-number")));
138  m_editorColors[Theme::WordWrapMarker] = readColor(editorColors.value(QLatin1String("word-wrap-marker")));
139  m_editorColors[Theme::ModifiedLines] = readColor(editorColors.value(QLatin1String("modified-lines")));
140  m_editorColors[Theme::SavedLines] = readColor(editorColors.value(QLatin1String("saved-lines")));
141  m_editorColors[Theme::Separator] = readColor(editorColors.value(QLatin1String("separator")));
142  m_editorColors[Theme::MarkBookmark] = readColor(editorColors.value(QLatin1String("mark-bookmark")));
143  m_editorColors[Theme::MarkBreakpointActive] = readColor(editorColors.value(QLatin1String("mark-breakpoint-active")));
144  m_editorColors[Theme::MarkBreakpointReached] = readColor(editorColors.value(QLatin1String("mark-breakpoint-reached")));
145  m_editorColors[Theme::MarkBreakpointDisabled] = readColor(editorColors.value(QLatin1String("mark-breakpoint-disabled")));
146  m_editorColors[Theme::MarkExecution] = readColor(editorColors.value(QLatin1String("mark-execution")));
147  m_editorColors[Theme::MarkWarning] = readColor(editorColors.value(QLatin1String("mark-warning")));
148  m_editorColors[Theme::MarkError] = readColor(editorColors.value(QLatin1String("mark-error")));
149  m_editorColors[Theme::TemplateBackground] = readColor(editorColors.value(QLatin1String("template-background")));
150  m_editorColors[Theme::TemplatePlaceholder] = readColor(editorColors.value(QLatin1String("template-placeholder")));
151  m_editorColors[Theme::TemplateFocusedPlaceholder] = readColor(editorColors.value(QLatin1String("template-focused-placeholder")));
152  m_editorColors[Theme::TemplateReadOnlyPlaceholder] = readColor(editorColors.value(QLatin1String("template-read-only-placeholder")));
153  }
154 
155  // read per-definition style overrides
156  const auto customStyles = obj.value(QLatin1String("custom-styles")).toObject();
157  for (auto it = customStyles.begin(); it != customStyles.end(); ++it) {
158  const auto obj = it.value().toObject();
159  auto &overrideStyle = m_textStyleOverrides[it.key()];
160  for (auto it2 = obj.begin(); it2 != obj.end(); ++it2) {
161  overrideStyle.insert(it2.key(), readThemeData(it2.value().toObject()));
162  }
163  }
164 
165  return true;
166 }
167 
168 QString ThemeData::name() const
169 {
170  return m_name;
171 }
172 
173 int ThemeData::revision() const
174 {
175  return m_revision;
176 }
177 
178 bool ThemeData::isReadOnly() const
179 {
180  return !QFileInfo(m_filePath).isWritable();
181 }
182 
183 QString ThemeData::filePath() const
184 {
185  return m_filePath;
186 }
187 
188 TextStyleData ThemeData::textStyle(Theme::TextStyle style) const
189 {
190  return m_textStyles[style];
191 }
192 
193 QRgb ThemeData::textColor(Theme::TextStyle style) const
194 {
195  return textStyle(style).textColor;
196 }
197 
198 QRgb ThemeData::selectedTextColor(Theme::TextStyle style) const
199 {
200  return textStyle(style).selectedTextColor;
201 }
202 
203 QRgb ThemeData::backgroundColor(Theme::TextStyle style) const
204 {
205  return textStyle(style).backgroundColor;
206 }
207 
208 QRgb ThemeData::selectedBackgroundColor(Theme::TextStyle style) const
209 {
210  return textStyle(style).selectedBackgroundColor;
211 }
212 
213 bool ThemeData::isBold(Theme::TextStyle style) const
214 {
215  return textStyle(style).bold;
216 }
217 
218 bool ThemeData::isItalic(Theme::TextStyle style) const
219 {
220  return textStyle(style).italic;
221 }
222 
223 bool ThemeData::isUnderline(Theme::TextStyle style) const
224 {
225  return textStyle(style).underline;
226 }
227 
228 bool ThemeData::isStrikeThrough(Theme::TextStyle style) const
229 {
230  return textStyle(style).strikeThrough;
231 }
232 
233 QRgb ThemeData::editorColor(Theme::EditorColorRole role) const
234 {
235  Q_ASSERT(static_cast<int>(role) >= 0 && static_cast<int>(role) <= static_cast<int>(Theme::TemplateReadOnlyPlaceholder));
236  return m_editorColors[role];
237 }
238 
239 TextStyleData ThemeData::textStyleOverride(const QString &definitionName, const QString &attributeName) const
240 {
241  auto it = m_textStyleOverrides.find(definitionName);
242  if (it != m_textStyleOverrides.end()) {
243  return it->value(attributeName);
244  }
245  return TextStyleData();
246 }
@ SearchHighlight
Background color for matching text while searching.
Definition: theme.h:171
bool toBool(bool defaultValue) const const
QJsonObject toObject() const const
QJsonObject object() const const
@ MarkWarning
Background color for general warning marks.
Definition: theme.h:215
@ BracketMatching
Background color for matching bracket pairs (including quotes)
Definition: theme.h:175
@ SpellChecking
Color used to underline spell check errors.
Definition: theme.h:179
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
@ TemplateReadOnlyPlaceholder
Background color for read-only placeholders in text templates.
Definition: theme.h:226
@ CurrentLineNumber
Foreground color for drawing the current line number.
Definition: theme.h:192
int toInt(int defaultValue) const const
@ IconBorder
Background color for the icon border.
Definition: theme.h:183
@ TextSelection
Background color for selected text.
Definition: theme.h:167
@ MarkBreakpointActive
Background color for active breakpoints.
Definition: theme.h:207
QString toString() const const
TextStyle
Default styles that can be referenced from syntax definition XML files.
Definition: theme.h:80
@ TabMarker
Foreground color for visualizing tabs and trailing spaces.
Definition: theme.h:177
@ TemplatePlaceholder
Background color for all editable placeholders in text templates.
Definition: theme.h:221
@ ModifiedLines
Color used to draw a vertical line for marking changed lines.
Definition: theme.h:198
bool contains(const QString &key) const const
@ SavedLines
Color used to draw a vertical line for marking saved lines.
Definition: theme.h:200
QJsonObject::iterator insert(const QString &key, const QJsonValue &value)
@ MarkError
Background color for general error marks.
Definition: theme.h:217
@ IndentationLine
Color used to draw vertical indentation levels, typically a line.
Definition: theme.h:181
QJsonObject::iterator end()
@ LineNumbers
Foreground color for drawing the line numbers.
Definition: theme.h:189
bool isEmpty() const const
@ MarkBreakpointDisabled
Background color for inactive (disabled) breakpoints.
Definition: theme.h:211
QJsonValue value(const QString &key) const const
QString errorString() const const
bool isBool() const const
@ Separator
Line color used to draw separator lines, e.g.
Definition: theme.h:203
@ CurrentLine
Background color for the line of the current text cursor.
Definition: theme.h:169
@ TemplateFocusedPlaceholder
Background color for the currently active placeholder in text templates.
Definition: theme.h:224
bool isString() const const
EditorColorRole
Editor color roles, used to paint line numbers, editor background etc.
Definition: theme.h:163
@ TemplateBackground
Background color for text templates (snippets).
Definition: theme.h:219
@ MarkBookmark
Background color for bookmarks.
Definition: theme.h:205
QJsonObject::iterator begin()
bool isWritable() const const
@ MarkBreakpointReached
Background color for a reached breakpoint.
Definition: theme.h:209
@ WordWrapMarker
Color used in the icon border to indicate dynamically wrapped lines.
Definition: theme.h:196
@ MarkExecution
Background color for marking the current execution position.
Definition: theme.h:213
@ BackgroundColor
Background color for the editing area.
Definition: theme.h:165
@ CodeFolding
Background colors for code folding regions in the text area, as well as code folding indicators in th...
Definition: theme.h:186
@ ReplaceHighlight
Background color for replaced text for a search & replace action.
Definition: theme.h:173
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
Color theme definition used for highlighting.
Definition: theme.h:64
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Mar 26 2023 04:09:17 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.