File indexing completed on 2024-05-12 04:02:18
0001 /* 0002 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org> 0003 SPDX-FileCopyrightText: 2020 Jonathan Poelen <jonathan.poelen@gmail.com> 0004 0005 SPDX-License-Identifier: MIT 0006 */ 0007 0008 #include "format.h" 0009 #include "definition.h" 0010 #include "definitionref_p.h" 0011 #include "format_p.h" 0012 #include "textstyledata_p.h" 0013 #include "themedata_p.h" 0014 #include "xml_p.h" 0015 0016 #include <QColor> 0017 #include <QMetaEnum> 0018 #include <QXmlStreamReader> 0019 0020 using namespace KSyntaxHighlighting; 0021 0022 static Theme::TextStyle stringToDefaultFormat(QStringView str) 0023 { 0024 if (!str.startsWith(QLatin1String("ds"))) { 0025 return Theme::Normal; 0026 } 0027 0028 const auto metaEnum = QMetaEnum::fromType<Theme::TextStyle>(); 0029 0030 bool ok = false; 0031 const auto value = metaEnum.keyToValue(str.mid(2).toLatin1().constData(), &ok); 0032 if (!ok || value < 0) { 0033 return Theme::Normal; 0034 } 0035 return static_cast<Theme::TextStyle>(value); 0036 } 0037 0038 FormatPrivate *FormatPrivate::detachAndGet(Format &format) 0039 { 0040 format.d.detach(); 0041 return format.d.data(); 0042 } 0043 0044 TextStyleData FormatPrivate::styleOverride(const Theme &theme) const 0045 { 0046 return ThemeData::get(theme)->textStyleOverride(definitionName, name); 0047 } 0048 0049 QColor FormatPrivate::color(const Theme &theme, StyleColor styleColor, ThemeColor themeColor) const 0050 { 0051 const auto overrideStyle = styleOverride(theme); 0052 if (overrideStyle.*styleColor) { 0053 return QColor::fromRgb(overrideStyle.*styleColor); 0054 } 0055 // use QColor::fromRgba for QRgb => QColor conversion to avoid unset colors == black! 0056 return QColor::fromRgba(style.*styleColor ? style.*styleColor : (theme.*themeColor)(defaultStyle)); 0057 } 0058 0059 bool FormatPrivate::hasColor(const Theme &theme, StyleColor styleColor, ThemeColor themeColor) const 0060 { 0061 // use QColor::fromRgba for background QRgb => QColor conversion to avoid unset colors == black! 0062 return color(theme, styleColor, themeColor) != QColor::fromRgba((theme.*themeColor)(Theme::Normal)) && (style.*styleColor || (theme.*themeColor)(defaultStyle) || styleOverride(theme).*styleColor); 0063 } 0064 0065 static QExplicitlySharedDataPointer<FormatPrivate> &sharedDefaultPrivate() 0066 { 0067 static QExplicitlySharedDataPointer<FormatPrivate> def(new FormatPrivate); 0068 return def; 0069 } 0070 0071 Format::Format() 0072 : d(sharedDefaultPrivate()) 0073 { 0074 } 0075 0076 Format::Format(const Format &other) 0077 : d(other.d) 0078 { 0079 } 0080 0081 Format::~Format() 0082 { 0083 } 0084 0085 Format &Format::operator=(const Format &other) 0086 { 0087 d = other.d; 0088 return *this; 0089 } 0090 0091 bool Format::isValid() const 0092 { 0093 return !d->name.isEmpty(); 0094 } 0095 0096 QString Format::name() const 0097 { 0098 return d->name; 0099 } 0100 0101 int Format::id() const 0102 { 0103 return d->id; 0104 } 0105 0106 Theme::TextStyle Format::textStyle() const 0107 { 0108 return d->defaultStyle; 0109 } 0110 0111 bool Format::isDefaultTextStyle(const Theme &theme) const 0112 { 0113 // use QColor::fromRgba for background QRgb => QColor conversion to avoid unset colors == black! 0114 return (!hasTextColor(theme)) && (!hasBackgroundColor(theme)) && (selectedTextColor(theme).rgba() == theme.selectedTextColor(Theme::Normal)) 0115 && (selectedBackgroundColor(theme).rgba() == (theme.selectedBackgroundColor(Theme::Normal))) && (isBold(theme) == theme.isBold(Theme::Normal)) 0116 && (isItalic(theme) == theme.isItalic(Theme::Normal)) && (isUnderline(theme) == theme.isUnderline(Theme::Normal)) 0117 && (isStrikeThrough(theme) == theme.isStrikeThrough(Theme::Normal)); 0118 } 0119 0120 bool Format::hasTextColor(const Theme &theme) const 0121 { 0122 return d->hasColor(theme, &TextStyleData::textColor, &Theme::textColor); 0123 } 0124 0125 QColor Format::textColor(const Theme &theme) const 0126 { 0127 return d->color(theme, &TextStyleData::textColor, &Theme::textColor); 0128 } 0129 0130 QColor Format::selectedTextColor(const Theme &theme) const 0131 { 0132 return d->color(theme, &TextStyleData::selectedTextColor, &Theme::selectedTextColor); 0133 } 0134 0135 bool Format::hasBackgroundColor(const Theme &theme) const 0136 { 0137 return d->hasColor(theme, &TextStyleData::backgroundColor, &Theme::backgroundColor); 0138 } 0139 0140 QColor Format::backgroundColor(const Theme &theme) const 0141 { 0142 return d->color(theme, &TextStyleData::backgroundColor, &Theme::backgroundColor); 0143 } 0144 0145 QColor Format::selectedBackgroundColor(const Theme &theme) const 0146 { 0147 return d->color(theme, &TextStyleData::selectedBackgroundColor, &Theme::selectedBackgroundColor); 0148 } 0149 0150 bool Format::isBold(const Theme &theme) const 0151 { 0152 const auto overrideStyle = d->styleOverride(theme); 0153 if (overrideStyle.hasBold) { 0154 return overrideStyle.bold; 0155 } 0156 return d->style.hasBold ? d->style.bold : theme.isBold(d->defaultStyle); 0157 } 0158 0159 bool Format::isItalic(const Theme &theme) const 0160 { 0161 const auto overrideStyle = d->styleOverride(theme); 0162 if (overrideStyle.hasItalic) { 0163 return overrideStyle.italic; 0164 } 0165 return d->style.hasItalic ? d->style.italic : theme.isItalic(d->defaultStyle); 0166 } 0167 0168 bool Format::isUnderline(const Theme &theme) const 0169 { 0170 const auto overrideStyle = d->styleOverride(theme); 0171 if (overrideStyle.hasUnderline) { 0172 return overrideStyle.underline; 0173 } 0174 return d->style.hasUnderline ? d->style.underline : theme.isUnderline(d->defaultStyle); 0175 } 0176 0177 bool Format::isStrikeThrough(const Theme &theme) const 0178 { 0179 const auto overrideStyle = d->styleOverride(theme); 0180 if (overrideStyle.hasStrikeThrough) { 0181 return overrideStyle.strikeThrough; 0182 } 0183 return d->style.hasStrikeThrough ? d->style.strikeThrough : theme.isStrikeThrough(d->defaultStyle); 0184 } 0185 0186 bool Format::spellCheck() const 0187 { 0188 return d->spellCheck; 0189 } 0190 0191 bool Format::hasBoldOverride() const 0192 { 0193 return d->style.hasBold; 0194 } 0195 0196 bool Format::hasItalicOverride() const 0197 { 0198 return d->style.hasItalic; 0199 } 0200 0201 bool Format::hasUnderlineOverride() const 0202 { 0203 return d->style.hasUnderline; 0204 } 0205 0206 bool Format::hasStrikeThroughOverride() const 0207 { 0208 return d->style.hasStrikeThrough; 0209 } 0210 0211 bool Format::hasTextColorOverride() const 0212 { 0213 return d->style.textColor; 0214 } 0215 0216 bool Format::hasBackgroundColorOverride() const 0217 { 0218 return d->style.backgroundColor; 0219 } 0220 0221 bool Format::hasSelectedTextColorOverride() const 0222 { 0223 return d->style.selectedTextColor; 0224 } 0225 0226 bool Format::hasSelectedBackgroundColorOverride() const 0227 { 0228 return d->style.selectedBackgroundColor; 0229 } 0230 0231 void FormatPrivate::load(QXmlStreamReader &reader) 0232 { 0233 name = reader.attributes().value(QLatin1String("name")).toString(); 0234 defaultStyle = stringToDefaultFormat(reader.attributes().value(QLatin1String("defStyleNum"))); 0235 0236 QStringView attribute = reader.attributes().value(QLatin1String("color")); 0237 if (!attribute.isEmpty()) { 0238 style.textColor = QColor(attribute).rgba(); 0239 } 0240 0241 attribute = reader.attributes().value(QLatin1String("selColor")); 0242 if (!attribute.isEmpty()) { 0243 style.selectedTextColor = QColor(attribute).rgba(); 0244 } 0245 0246 attribute = reader.attributes().value(QLatin1String("backgroundColor")); 0247 if (!attribute.isEmpty()) { 0248 style.backgroundColor = QColor(attribute).rgba(); 0249 } 0250 0251 attribute = reader.attributes().value(QLatin1String("selBackgroundColor")); 0252 if (!attribute.isEmpty()) { 0253 style.selectedBackgroundColor = QColor(attribute).rgba(); 0254 } 0255 0256 attribute = reader.attributes().value(QLatin1String("italic")); 0257 if (!attribute.isEmpty()) { 0258 style.hasItalic = true; 0259 style.italic = Xml::attrToBool(attribute); 0260 } 0261 0262 attribute = reader.attributes().value(QLatin1String("bold")); 0263 if (!attribute.isEmpty()) { 0264 style.hasBold = true; 0265 style.bold = Xml::attrToBool(attribute); 0266 } 0267 0268 attribute = reader.attributes().value(QLatin1String("underline")); 0269 if (!attribute.isEmpty()) { 0270 style.hasUnderline = true; 0271 style.underline = Xml::attrToBool(attribute); 0272 } 0273 0274 attribute = reader.attributes().value(QLatin1String("strikeOut")); 0275 if (!attribute.isEmpty()) { 0276 style.hasStrikeThrough = true; 0277 style.strikeThrough = Xml::attrToBool(attribute); 0278 } 0279 0280 attribute = reader.attributes().value(QLatin1String("spellChecking")); 0281 if (!attribute.isEmpty()) { 0282 spellCheck = Xml::attrToBool(attribute); 0283 } 0284 }