X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fqssparser.cpp;h=057044c511f72772da623a1cf9ff479bd7706be8;hp=e02bf4680281ebe2d4a0121d9e4fe313a887217e;hb=93f36a585e19397a4c68734b45ea59798d1f2ed1;hpb=9d54503555534a2c554f09a33df6afa33d6308ec diff --git a/src/uisupport/qssparser.cpp b/src/uisupport/qssparser.cpp index e02bf468..057044c5 100644 --- a/src/uisupport/qssparser.cpp +++ b/src/uisupport/qssparser.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2014 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -18,23 +18,26 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include - #include "qssparser.h" +#include +#include + +#include + QssParser::QssParser() { _palette = QApplication::palette(); // Init palette color roles _paletteColorRoles["alternate-base"] = QPalette::AlternateBase; - _paletteColorRoles["background"] = QPalette::Background; + _paletteColorRoles["background"] = QPalette::Window; _paletteColorRoles["base"] = QPalette::Base; _paletteColorRoles["bright-text"] = QPalette::BrightText; _paletteColorRoles["button"] = QPalette::Button; _paletteColorRoles["button-text"] = QPalette::ButtonText; _paletteColorRoles["dark"] = QPalette::Dark; - _paletteColorRoles["foreground"] = QPalette::Foreground; + _paletteColorRoles["foreground"] = QPalette::WindowText; _paletteColorRoles["highlight"] = QPalette::Highlight; _paletteColorRoles["highlighted-text"] = QPalette::HighlightedText; _paletteColorRoles["light"] = QPalette::Light; @@ -49,24 +52,41 @@ QssParser::QssParser() _paletteColorRoles["window"] = QPalette::Window; _paletteColorRoles["window-text"] = QPalette::WindowText; - _uiStylePalette = QVector(UiStyle::NumRoles, QBrush()); - - _uiStyleColorRoles["marker-line"] = UiStyle::MarkerLine; + _uiStylePalette = QVector(static_cast(UiStyle::ColorRole::NumRoles), QBrush()); + + _uiStyleColorRoles["marker-line"] = UiStyle::ColorRole::MarkerLine; + // Sender colors + _uiStyleColorRoles["sender-color-self"] = UiStyle::ColorRole::SenderColorSelf; + _uiStyleColorRoles["sender-color-00"] = UiStyle::ColorRole::SenderColor00; + _uiStyleColorRoles["sender-color-01"] = UiStyle::ColorRole::SenderColor01; + _uiStyleColorRoles["sender-color-02"] = UiStyle::ColorRole::SenderColor02; + _uiStyleColorRoles["sender-color-03"] = UiStyle::ColorRole::SenderColor03; + _uiStyleColorRoles["sender-color-04"] = UiStyle::ColorRole::SenderColor04; + _uiStyleColorRoles["sender-color-05"] = UiStyle::ColorRole::SenderColor05; + _uiStyleColorRoles["sender-color-06"] = UiStyle::ColorRole::SenderColor06; + _uiStyleColorRoles["sender-color-07"] = UiStyle::ColorRole::SenderColor07; + _uiStyleColorRoles["sender-color-08"] = UiStyle::ColorRole::SenderColor08; + _uiStyleColorRoles["sender-color-09"] = UiStyle::ColorRole::SenderColor09; + _uiStyleColorRoles["sender-color-0a"] = UiStyle::ColorRole::SenderColor0a; + _uiStyleColorRoles["sender-color-0b"] = UiStyle::ColorRole::SenderColor0b; + _uiStyleColorRoles["sender-color-0c"] = UiStyle::ColorRole::SenderColor0c; + _uiStyleColorRoles["sender-color-0d"] = UiStyle::ColorRole::SenderColor0d; + _uiStyleColorRoles["sender-color-0e"] = UiStyle::ColorRole::SenderColor0e; + _uiStyleColorRoles["sender-color-0f"] = UiStyle::ColorRole::SenderColor0f; } - -void QssParser::processStyleSheet(QString &ss) +void QssParser::processStyleSheet(QString& ss) { if (ss.isEmpty()) return; // Remove C-style comments /* */ or // - QRegExp commentRx("(//.*(\\n|$)|/\\*.*\\*/)"); + static QRegExp commentRx(R"((//.*(\n|$)|/\*.*\*/))"); commentRx.setMinimal(true); ss.remove(commentRx); // Palette definitions first, so we can apply roles later on - QRegExp paletterx("(Palette[^{]*)\\{([^}]+)\\}"); + static const QRegExp paletterx("(Palette[^{]*)\\{([^}]+)\\}"); int pos = 0; while ((pos = paletterx.indexIn(ss, pos)) >= 0) { parsePaletteBlock(paletterx.cap(1).trimmed(), paletterx.cap(2).trimmed()); @@ -74,10 +94,10 @@ void QssParser::processStyleSheet(QString &ss) } // Now we can parse the rest of our custom blocks - QRegExp blockrx("((?:ChatLine|ChatListItem|NickListItem)[^{]*)\\{([^}]+)\\}"); + static const QRegExp blockrx("((?:ChatLine|ChatListItem|NickListItem)[^{]*)\\{([^}]+)\\}"); pos = 0; while ((pos = blockrx.indexIn(ss, pos)) >= 0) { - //qDebug() << blockrx.cap(1) << blockrx.cap(2); + // qDebug() << blockrx.cap(1) << blockrx.cap(2); QString declaration = blockrx.cap(1).trimmed(); QString contents = blockrx.cap(2).trimmed(); @@ -85,52 +105,51 @@ void QssParser::processStyleSheet(QString &ss) parseChatLineBlock(declaration, contents); else if (declaration.startsWith("ChatListItem") || declaration.startsWith("NickListItem")) parseListItemBlock(declaration, contents); - //else + // else // TODO: add moar here ss.remove(pos, blockrx.matchedLength()); } } - /******** Parse a whole block: declaration { contents } *******/ -void QssParser::parseChatLineBlock(const QString &decl, const QString &contents) +void QssParser::parseChatLineBlock(const QString& decl, const QString& contents) { - quint64 fmtType = parseFormatType(decl); - if (fmtType == UiStyle::Invalid) + UiStyle::FormatType fmtType; + UiStyle::MessageLabel label; + std::tie(fmtType, label) = parseFormatType(decl); + if (fmtType == UiStyle::FormatType::Invalid) return; - _formats[fmtType].merge(parseFormat(contents)); + _formats[fmtType | label].merge(parseFormat(contents)); } - -void QssParser::parseListItemBlock(const QString &decl, const QString &contents) +void QssParser::parseListItemBlock(const QString& decl, const QString& contents) { - quint32 fmtType = parseItemFormatType(decl); - if (fmtType == UiStyle::Invalid) + UiStyle::ItemFormatType fmtType = parseItemFormatType(decl); + if (fmtType == UiStyle::ItemFormatType::Invalid) return; _listItemFormats[fmtType].merge(parseFormat(contents)); } - // Palette { ... } specifies the application palette // ColorGroups can be specified like pseudo states, chaining is OR (contrary to normal CSS handling): // Palette:inactive:disabled { ... } applies to both the Inactive and the Disabled state -void QssParser::parsePaletteBlock(const QString &decl, const QString &contents) +void QssParser::parsePaletteBlock(const QString& decl, const QString& contents) { QList colorGroups; // Check if we want to apply this palette definition for particular ColorGroups - QRegExp rx("Palette((:(normal|active|inactive|disabled))*)"); + static const QRegExp rx("Palette((:(normal|active|inactive|disabled))*)"); if (!rx.exactMatch(decl)) { qWarning() << Q_FUNC_INFO << tr("Invalid block declaration: %1").arg(decl); return; } if (!rx.cap(1).isEmpty()) { QStringList groups = rx.cap(1).split(':', QString::SkipEmptyParts); - foreach(QString g, groups) { + foreach (QString g, groups) { if ((g == "normal" || g == "active") && !colorGroups.contains(QPalette::Active)) colorGroups.append(QPalette::Active); else if (g == "inactive" && !colorGroups.contains(QPalette::Inactive)) @@ -141,7 +160,7 @@ void QssParser::parsePaletteBlock(const QString &decl, const QString &contents) } // Now let's go through the roles - foreach(QString line, contents.split(';', QString::SkipEmptyParts)) { + foreach (QString line, contents.split(';', QString::SkipEmptyParts)) { int idx = line.indexOf(':'); if (idx <= 0) { qWarning() << Q_FUNC_INFO << tr("Invalid palette role assignment: %1").arg(line.trimmed()); @@ -153,201 +172,207 @@ void QssParser::parsePaletteBlock(const QString &decl, const QString &contents) if (_paletteColorRoles.contains(rolestr)) { QBrush brush = parseBrush(brushstr); if (colorGroups.count()) { - foreach(QPalette::ColorGroup group, colorGroups) - _palette.setBrush(group, _paletteColorRoles.value(rolestr), brush); + foreach (QPalette::ColorGroup group, colorGroups) + _palette.setBrush(group, _paletteColorRoles.value(rolestr), brush); } else _palette.setBrush(_paletteColorRoles.value(rolestr), brush); } else if (_uiStyleColorRoles.contains(rolestr)) { - _uiStylePalette[_uiStyleColorRoles.value(rolestr)] = parseBrush(brushstr); + _uiStylePalette[static_cast(_uiStyleColorRoles.value(rolestr))] = parseBrush(brushstr); } else qWarning() << Q_FUNC_INFO << tr("Unknown palette role name: %1").arg(rolestr); } } - /******** Determine format types from a block declaration ********/ -quint64 QssParser::parseFormatType(const QString &decl) +std::pair QssParser::parseFormatType(const QString& decl) { - QRegExp rx("ChatLine(?:::(\\w+))?(?:#([\\w\\-]+))?(?:\\[([=-,\\\"\\w\\s]+)\\])?"); + using FormatType = UiStyle::FormatType; + using MessageLabel = UiStyle::MessageLabel; + + const std::pair invalid{FormatType::Invalid, MessageLabel::None}; + + static const QRegExp rx(R"(ChatLine(?:::(\w+))?(?:#([\w\-]+))?(?:\[([=-,\"\w\s]+)\])?)"); // $1: subelement; $2: msgtype; $3: conditionals if (!rx.exactMatch(decl)) { qWarning() << Q_FUNC_INFO << tr("Invalid block declaration: %1").arg(decl); - return UiStyle::Invalid; + return invalid; } QString subElement = rx.cap(1); QString msgType = rx.cap(2); QString conditions = rx.cap(3); - quint64 fmtType = 0; + FormatType fmtType{FormatType::Base}; + MessageLabel label{MessageLabel::None}; // First determine the subelement if (!subElement.isEmpty()) { if (subElement == "timestamp") - fmtType |= UiStyle::Timestamp; + fmtType |= FormatType::Timestamp; else if (subElement == "sender") - fmtType |= UiStyle::Sender; + fmtType |= FormatType::Sender; else if (subElement == "nick") - fmtType |= UiStyle::Nick; + fmtType |= FormatType::Nick; else if (subElement == "contents") - fmtType |= UiStyle::Contents; + fmtType |= FormatType::Contents; else if (subElement == "hostmask") - fmtType |= UiStyle::Hostmask; + fmtType |= FormatType::Hostmask; else if (subElement == "modeflags") - fmtType |= UiStyle::ModeFlags; + fmtType |= FormatType::ModeFlags; else if (subElement == "url") - fmtType |= UiStyle::Url; + fmtType |= FormatType::Url; else { qWarning() << Q_FUNC_INFO << tr("Invalid subelement name in %1").arg(decl); - return UiStyle::Invalid; + return invalid; } } // Now, figure out the message type if (!msgType.isEmpty()) { if (msgType == "plain") - fmtType |= UiStyle::PlainMsg; + fmtType |= FormatType::PlainMsg; else if (msgType == "notice") - fmtType |= UiStyle::NoticeMsg; + fmtType |= FormatType::NoticeMsg; else if (msgType == "action") - fmtType |= UiStyle::ActionMsg; + fmtType |= FormatType::ActionMsg; else if (msgType == "nick") - fmtType |= UiStyle::NickMsg; + fmtType |= FormatType::NickMsg; else if (msgType == "mode") - fmtType |= UiStyle::ModeMsg; + fmtType |= FormatType::ModeMsg; else if (msgType == "join") - fmtType |= UiStyle::JoinMsg; + fmtType |= FormatType::JoinMsg; else if (msgType == "part") - fmtType |= UiStyle::PartMsg; + fmtType |= FormatType::PartMsg; else if (msgType == "quit") - fmtType |= UiStyle::QuitMsg; + fmtType |= FormatType::QuitMsg; else if (msgType == "kick") - fmtType |= UiStyle::KickMsg; + fmtType |= FormatType::KickMsg; else if (msgType == "kill") - fmtType |= UiStyle::KillMsg; + fmtType |= FormatType::KillMsg; else if (msgType == "server") - fmtType |= UiStyle::ServerMsg; + fmtType |= FormatType::ServerMsg; else if (msgType == "info") - fmtType |= UiStyle::InfoMsg; + fmtType |= FormatType::InfoMsg; else if (msgType == "error") - fmtType |= UiStyle::ErrorMsg; + fmtType |= FormatType::ErrorMsg; else if (msgType == "daychange") - fmtType |= UiStyle::DayChangeMsg; + fmtType |= FormatType::DayChangeMsg; else if (msgType == "topic") - fmtType |= UiStyle::TopicMsg; + fmtType |= FormatType::TopicMsg; else if (msgType == "netsplit-join") - fmtType |= UiStyle::NetsplitJoinMsg; + fmtType |= FormatType::NetsplitJoinMsg; else if (msgType == "netsplit-quit") - fmtType |= UiStyle::NetsplitQuitMsg; + fmtType |= FormatType::NetsplitQuitMsg; else if (msgType == "invite") - fmtType |= UiStyle::InviteMsg; + fmtType |= FormatType::InviteMsg; else { qWarning() << Q_FUNC_INFO << tr("Invalid message type in %1").arg(decl); } } // Next up: conditional (formats, labels, nickhash) - QRegExp condRx("\\s*([\\w\\-]+)\\s*=\\s*\"(\\w+)\"\\s*"); + static const QRegExp condRx(R"lit(\s*([\w\-]+)\s*=\s*"(\w+)"\s*)lit"); if (!conditions.isEmpty()) { - foreach(const QString &cond, conditions.split(',', QString::SkipEmptyParts)) { + foreach (const QString& cond, conditions.split(',', QString::SkipEmptyParts)) { if (!condRx.exactMatch(cond)) { qWarning() << Q_FUNC_INFO << tr("Invalid condition %1").arg(cond); - return UiStyle::Invalid; + return invalid; } QString condName = condRx.cap(1); QString condValue = condRx.cap(2); if (condName == "label") { - quint64 labeltype = 0; if (condValue == "highlight") - labeltype = UiStyle::Highlight; + label |= MessageLabel::Highlight; else if (condValue == "selected") - labeltype = UiStyle::Selected; + label |= MessageLabel::Selected; + else if (condValue == "hovered") + label |= MessageLabel::Hovered; else { qWarning() << Q_FUNC_INFO << tr("Invalid message label: %1").arg(condValue); - return UiStyle::Invalid; + return invalid; } - fmtType |= (labeltype << 32); } else if (condName == "sender") { if (condValue == "self") - fmtType |= (quint64) UiStyle::OwnMsg << 32; // sender="self" is actually treated as a label + label |= MessageLabel::OwnMsg; // sender="self" is actually treated as a label else { bool ok = true; - quint64 val = condValue.toUInt(&ok, 16); + quint32 val = condValue.toUInt(&ok, 16); if (!ok) { qWarning() << Q_FUNC_INFO << tr("Invalid senderhash specification: %1").arg(condValue); - return UiStyle::Invalid; + return invalid; } if (val >= 16) { qWarning() << Q_FUNC_INFO << tr("Senderhash can be at most \"0x0f\"!"); - return UiStyle::Invalid; + return invalid; } - fmtType |= ++val << 48; + label |= static_cast(++val << 16); } } else if (condName == "format") { if (condValue == "bold") - fmtType |= UiStyle::Bold; + fmtType |= FormatType::Bold; else if (condValue == "italic") - fmtType |= UiStyle::Italic; + fmtType |= FormatType::Italic; else if (condValue == "underline") - fmtType |= UiStyle::Underline; - else if (condValue == "reverse") - fmtType |= UiStyle::Reverse; + fmtType |= FormatType::Underline; + else if (condValue == "strikethrough") + fmtType |= FormatType::Strikethrough; else { qWarning() << Q_FUNC_INFO << tr("Invalid format name: %1").arg(condValue); - return UiStyle::Invalid; + return invalid; } } else if (condName == "fg-color" || condName == "bg-color") { bool ok; - quint8 col = condValue.toUInt(&ok, 16); + quint32 col = condValue.toUInt(&ok, 16); if (!ok || col > 0x0f) { qWarning() << Q_FUNC_INFO << tr("Illegal IRC color specification (must be between 00 and 0f): %1").arg(condValue); - return UiStyle::Invalid; + return invalid; } if (condName == "fg-color") - fmtType |= 0x00400000 | (quint32)(col << 24); + fmtType |= 0x00400000 | (col << 24); else - fmtType |= 0x00800000 | (quint32)(col << 28); + fmtType |= 0x00800000 | (col << 28); } else { qWarning() << Q_FUNC_INFO << tr("Unhandled condition: %1").arg(condName); - return UiStyle::Invalid; + return invalid; } } } - return fmtType; + return std::make_pair(fmtType, label); } - // FIXME: Code duplication -quint32 QssParser::parseItemFormatType(const QString &decl) +UiStyle::ItemFormatType QssParser::parseItemFormatType(const QString& decl) { - QRegExp rx("(Chat|Nick)ListItem(?:\\[([=-,\\\"\\w\\s]+)\\])?"); + using ItemFormatType = UiStyle::ItemFormatType; + + static const QRegExp rx(R"((Chat|Nick)ListItem(?:\[([=-,\"\w\s]+)\])?)"); // $1: item type; $2: properties if (!rx.exactMatch(decl)) { qWarning() << Q_FUNC_INFO << tr("Invalid block declaration: %1").arg(decl); - return UiStyle::Invalid; + return ItemFormatType::Invalid; } QString mainItemType = rx.cap(1); QString properties = rx.cap(2); - quint32 fmtType = 0; + ItemFormatType fmtType{ItemFormatType::None}; // Next up: properties QString type, state; if (!properties.isEmpty()) { QHash props; - QRegExp propRx("\\s*([\\w\\-]+)\\s*=\\s*\"([\\w\\-]+)\"\\s*"); - foreach(const QString &prop, properties.split(',', QString::SkipEmptyParts)) { + static const QRegExp propRx(R"lit(\s*([\w\-]+)\s*=\s*"([\w\-]+)"\s*)lit"); + foreach (const QString& prop, properties.split(',', QString::SkipEmptyParts)) { if (!propRx.exactMatch(prop)) { qWarning() << Q_FUNC_INFO << tr("Invalid proplist %1").arg(prop); - return UiStyle::Invalid; + return ItemFormatType::Invalid; } props[propRx.cap(1)] = propRx.cap(2); } @@ -356,59 +381,58 @@ quint32 QssParser::parseItemFormatType(const QString &decl) } if (mainItemType == "Chat") { - fmtType |= UiStyle::BufferViewItem; + fmtType |= ItemFormatType::BufferViewItem; if (!type.isEmpty()) { if (type == "network") - fmtType |= UiStyle::NetworkItem; + fmtType |= ItemFormatType::NetworkItem; else if (type == "channel") - fmtType |= UiStyle::ChannelBufferItem; + fmtType |= ItemFormatType::ChannelBufferItem; else if (type == "query") - fmtType |= UiStyle::QueryBufferItem; + fmtType |= ItemFormatType::QueryBufferItem; else { qWarning() << Q_FUNC_INFO << tr("Invalid chatlist item type %1").arg(type); - return UiStyle::Invalid; + return ItemFormatType::Invalid; } } if (!state.isEmpty()) { if (state == "inactive") - fmtType |= UiStyle::InactiveBuffer; + fmtType |= ItemFormatType::InactiveBuffer; else if (state == "channel-event") - fmtType |= UiStyle::ActiveBuffer; + fmtType |= ItemFormatType::ActiveBuffer; else if (state == "unread-message") - fmtType |= UiStyle::UnreadBuffer; + fmtType |= ItemFormatType::UnreadBuffer; else if (state == "highlighted") - fmtType |= UiStyle::HighlightedBuffer; + fmtType |= ItemFormatType::HighlightedBuffer; else if (state == "away") - fmtType |= UiStyle::UserAway; + fmtType |= ItemFormatType::UserAway; else { qWarning() << Q_FUNC_INFO << tr("Invalid chatlist state %1").arg(state); - return UiStyle::Invalid; + return ItemFormatType::Invalid; } } } - else { // NickList - fmtType |= UiStyle::NickViewItem; + else { // NickList + fmtType |= ItemFormatType::NickViewItem; if (!type.isEmpty()) { if (type == "user") { - fmtType |= UiStyle::IrcUserItem; + fmtType |= ItemFormatType::IrcUserItem; if (state == "away") - fmtType |= UiStyle::UserAway; + fmtType |= ItemFormatType::UserAway; } else if (type == "category") - fmtType |= UiStyle::UserCategoryItem; + fmtType |= ItemFormatType::UserCategoryItem; } } return fmtType; } - /******** Parse a whole format attribute block ********/ -QTextCharFormat QssParser::parseFormat(const QString &qss) +QTextCharFormat QssParser::parseFormat(const QString& qss) { QTextCharFormat format; - foreach(QString line, qss.split(';', QString::SkipEmptyParts)) { + foreach (QString line, qss.split(';', QString::SkipEmptyParts)) { int idx = line.indexOf(':'); if (idx <= 0) { qWarning() << Q_FUNC_INFO << tr("Invalid property declaration: %1").arg(line.trimmed()); @@ -422,6 +446,20 @@ QTextCharFormat QssParser::parseFormat(const QString &qss) else if (property == "foreground" || property == "color") format.setForeground(parseBrush(value)); + // Color code overrides + else if (property == "allow-foreground-override") { + bool ok; + bool v = parseBoolean(value, &ok); + if (ok) + format.setProperty(static_cast(UiStyle::FormatProperty::AllowForegroundOverride), v); + } + else if (property == "allow-background-override") { + bool ok; + bool v = parseBoolean(value, &ok); + if (ok) + format.setProperty(static_cast(UiStyle::FormatProperty::AllowBackgroundOverride), v); + } + // font-related properties else if (property.startsWith("font")) { if (property == "font") @@ -448,10 +486,27 @@ QTextCharFormat QssParser::parseFormat(const QString &qss) return format; } +/******** Boolean value ********/ + +bool QssParser::parseBoolean(const QString& str, bool* ok) const +{ + if (ok) + *ok = true; + + if (str == "true") + return true; + if (str == "false") + return false; + + qWarning() << Q_FUNC_INFO << tr("Invalid boolean value: %1").arg(str); + if (ok) + *ok = false; + return false; +} /******** Brush ********/ -QBrush QssParser::parseBrush(const QString &str, bool *ok) +QBrush QssParser::parseBrush(const QString& str, bool* ok) { if (ok) *ok = false; @@ -462,8 +517,22 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok) return QBrush(c); } - if (str.startsWith("palette")) { // Palette color role - QRegExp rx("palette\\s*\\(\\s*([a-z-]+)\\s*\\)"); + if (str.startsWith("palette")) { // Palette color role + // Does the palette follow the expected format? For example: + // palette(marker-line) + // palette ( system-color-0f ) + // + // Match the palette marker, grabbing the name inside in case-sensitive manner + // palette\s*\(\s*([a-z-0-9]+)\s*\) + // palette Match the string 'palette' + // \s* Match any amount of whitespace + // \(, \) Match literal '(' or ')' marks + // (...+) Match contents between 1 and unlimited number of times + // [a-z-] Match any character from a-z, case sensitive + // [0-9] Match any digit from 0-9 + // Note that '\' must be escaped as '\\' + // Helpful interactive website for debugging and explaining: https://regex101.com/ + static const QRegExp rx(R"(palette\s*\(\s*([a-z-0-9]+)\s*\))"); if (!rx.exactMatch(str)) { qWarning() << Q_FUNC_INFO << tr("Invalid palette color role specification: %1").arg(str); return QBrush(); @@ -471,13 +540,13 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok) if (_paletteColorRoles.contains(rx.cap(1))) return QBrush(_palette.brush(_paletteColorRoles.value(rx.cap(1)))); if (_uiStyleColorRoles.contains(rx.cap(1))) - return QBrush(_uiStylePalette.at(_uiStyleColorRoles.value(rx.cap(1)))); + return QBrush(_uiStylePalette.at(static_cast(_uiStyleColorRoles.value(rx.cap(1))))); qWarning() << Q_FUNC_INFO << tr("Unknown palette color role: %1").arg(rx.cap(1)); return QBrush(); } else if (str.startsWith("qlineargradient")) { - static QString rxFloat("\\s*(-?\\s*[0-9]*\\.?[0-9]+)\\s*"); - QRegExp rx(QString("qlineargradient\\s*\\(\\s*x1:%1,\\s*y1:%1,\\s*x2:%1,\\s*y2:%1,(.+)\\)").arg(rxFloat)); + static const QString rxFloat(R"(\s*(-?\s*[0-9]*\.?[0-9]+)\s*)"); + static const QRegExp rx(QString(R"(qlineargradient\s*\(\s*x1:%1,\s*y1:%1,\s*x2:%1,\s*y2:%1,(.+)\))").arg(rxFloat)); if (!rx.exactMatch(str)) { qWarning() << Q_FUNC_INFO << tr("Invalid gradient declaration: %1").arg(str); return QBrush(); @@ -499,8 +568,8 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok) return QBrush(gradient); } else if (str.startsWith("qconicalgradient")) { - static QString rxFloat("\\s*(-?\\s*[0-9]*\\.?[0-9]+)\\s*"); - QRegExp rx(QString("qconicalgradient\\s*\\(\\s*cx:%1,\\s*cy:%1,\\s*angle:%1,(.+)\\)").arg(rxFloat)); + static const QString rxFloat(R"(\s*(-?\s*[0-9]*\.?[0-9]+)\s*)"); + static const QRegExp rx(QString(R"(qconicalgradient\s*\(\s*cx:%1,\s*cy:%1,\s*angle:%1,(.+)\))").arg(rxFloat)); if (!rx.exactMatch(str)) { qWarning() << Q_FUNC_INFO << tr("Invalid gradient declaration: %1").arg(str); return QBrush(); @@ -521,8 +590,8 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok) return QBrush(gradient); } else if (str.startsWith("qradialgradient")) { - static QString rxFloat("\\s*(-?\\s*[0-9]*\\.?[0-9]+)\\s*"); - QRegExp rx(QString("qradialgradient\\s*\\(\\s*cx:%1,\\s*cy:%1,\\s*radius:%1,\\s*fx:%1,\\s*fy:%1,(.+)\\)").arg(rxFloat)); + static const QString rxFloat(R"(\s*(-?\s*[0-9]*\.?[0-9]+)\s*)"); + static const QRegExp rx(QString(R"(qradialgradient\s*\(\s*cx:%1,\s*cy:%1,\s*radius:%1,\s*fx:%1,\s*fy:%1,(.+)\))").arg(rxFloat)); if (!rx.exactMatch(str)) { qWarning() << Q_FUNC_INFO << tr("Invalid gradient declaration: %1").arg(str); return QBrush(); @@ -548,13 +617,12 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok) return QBrush(); } - -QColor QssParser::parseColor(const QString &str) +QColor QssParser::parseColor(const QString& str) { if (str.startsWith("rgba")) { ColorTuple tuple = parseColorTuple(str.mid(4)); if (tuple.count() == 4) - return QColor(tuple.at(0), tuple.at(1), tuple.at(2), tuple.at(3)); + return QColor(tuple.at(0), tuple.at(1), tuple.at(2), tuple.at(3)); // NOLINT(modernize-return-braced-init-list) } else if (str.startsWith("rgb")) { ColorTuple tuple = parseColorTuple(str.mid(3)); @@ -578,24 +646,23 @@ QColor QssParser::parseColor(const QString &str) } } else { - QRegExp rx("#?[0-9A-Fa-z]+"); + static const QRegExp rx("#?[0-9A-Fa-z]+"); if (rx.exactMatch(str)) return QColor(str); } return QColor(); } - // get a list of comma-separated int values or percentages (rel to 0-255) -QssParser::ColorTuple QssParser::parseColorTuple(const QString &str) +QssParser::ColorTuple QssParser::parseColorTuple(const QString& str) { ColorTuple result; - QRegExp rx("\\(((\\s*[0-9]{1,3}%?\\s*)(,\\s*[0-9]{1,3}%?\\s*)*)\\)"); + static const QRegExp rx(R"(\(((\s*[0-9]{1,3}%?\s*)(,\s*[0-9]{1,3}%?\s*)*)\))"); if (!rx.exactMatch(str.trimmed())) { return ColorTuple(); } QStringList values = rx.cap(1).split(','); - foreach(QString v, values) { + foreach (QString v, values) { qreal val; bool perc = false; bool ok; @@ -608,19 +675,18 @@ QssParser::ColorTuple QssParser::parseColorTuple(const QString &str) if (!ok) return ColorTuple(); if (perc) - val = 255 * val/100; + val = 255 * val / 100; result.append(val); } return result; } - -QGradientStops QssParser::parseGradientStops(const QString &str_) +QGradientStops QssParser::parseGradientStops(const QString& str_) { QString str = str_; QGradientStops result; - static QString rxFloat("(0?\\.[0-9]+|[01])"); // values between 0 and 1 - QRegExp rx(QString("\\s*,?\\s*stop:\\s*(%1)\\s+([^:]+)(,\\s*stop:|$)").arg(rxFloat)); + static const QString rxFloat("(0?\\.[0-9]+|[01])"); // values between 0 and 1 + static const QRegExp rx(QString(R"(\s*,?\s*stop:\s*(%1)\s+([^:]+)(,\s*stop:|$))").arg(rxFloat)); int idx; while ((idx = rx.indexIn(str)) == 0) { qreal x = rx.cap(1).toDouble(); @@ -636,31 +702,38 @@ QGradientStops QssParser::parseGradientStops(const QString &str_) return result; } - /******** Font Properties ********/ -void QssParser::parseFont(const QString &value, QTextCharFormat *format) +void QssParser::parseFont(const QString& value, QTextCharFormat* format) { - QRegExp rx("((?:(?:normal|italic|oblique|underline|bold|100|200|300|400|500|600|700|800|900) ){0,2}) ?(\\d+)(pt|px)? \"(.*)\""); + static const QRegExp rx( + "((?:(?:normal|italic|oblique|underline|strikethrough|bold|100|200|300|400|500|600|700|800|900) ){0,2}) ?(\\d+)(pt|px)? \"(.*)\""); if (!rx.exactMatch(value)) { qWarning() << Q_FUNC_INFO << tr("Invalid font specification: %1").arg(value); return; } format->setFontItalic(false); + format->setFontUnderline(false); + format->setFontStrikeOut(false); format->setFontWeight(QFont::Normal); QStringList proplist = rx.cap(1).split(' ', QString::SkipEmptyParts); - foreach(QString prop, proplist) { - if (prop == "italic") + foreach (QString prop, proplist) { + if (prop == "normal") + ; // pass + else if (prop == "italic") format->setFontItalic(true); else if (prop == "underline") format->setFontUnderline(true); - //else if(prop == "oblique") - // format->setStyle(QFont::StyleOblique); + else if (prop == "strikethrough") + format->setFontStrikeOut(true); + else if (prop == "oblique") + // Oblique is not a property supported by QTextCharFormat + format->setFontItalic(true); else if (prop == "bold") format->setFontWeight(QFont::Bold); - else { // number + else { // number int w = prop.toInt(); - format->setFontWeight(qMin(w / 8, 99)); // taken from Qt's qss parser + format->setFontWeight(qMin(w / 8, 99)); // taken from Qt's qss parser } } @@ -672,8 +745,7 @@ void QssParser::parseFont(const QString &value, QTextCharFormat *format) format->setFontFamily(rx.cap(4)); } - -void QssParser::parseFontStyle(const QString &value, QTextCharFormat *format) +void QssParser::parseFontStyle(const QString& value, QTextCharFormat* format) { if (value == "normal") format->setFontItalic(false); @@ -681,15 +753,17 @@ void QssParser::parseFontStyle(const QString &value, QTextCharFormat *format) format->setFontItalic(true); else if (value == "underline") format->setFontUnderline(true); - //else if(value == "oblique") - // format->setStyle(QFont::StyleOblique); + else if (value == "strikethrough") + format->setFontStrikeOut(true); + else if (value == "oblique") + // Oblique is not a property supported by QTextCharFormat + format->setFontItalic(true); else { qWarning() << Q_FUNC_INFO << tr("Invalid font style specification: %1").arg(value); } } - -void QssParser::parseFontWeight(const QString &value, QTextCharFormat *format) +void QssParser::parseFontWeight(const QString& value, QTextCharFormat* format) { if (value == "normal") format->setFontWeight(QFont::Normal); @@ -702,14 +776,13 @@ void QssParser::parseFontWeight(const QString &value, QTextCharFormat *format) qWarning() << Q_FUNC_INFO << tr("Invalid font weight specification: %1").arg(value); return; } - format->setFontWeight(qMin(w / 8, 99)); // taken from Qt's qss parser + format->setFontWeight(qMin(w / 8, 99)); // taken from Qt's qss parser } } - -void QssParser::parseFontSize(const QString &value, QTextCharFormat *format) +void QssParser::parseFontSize(const QString& value, QTextCharFormat* format) { - QRegExp rx("(\\d+)(pt|px)"); + static const QRegExp rx("(\\d+)(pt|px)"); if (!rx.exactMatch(value)) { qWarning() << Q_FUNC_INFO << tr("Invalid font size specification: %1").arg(value); return; @@ -720,8 +793,7 @@ void QssParser::parseFontSize(const QString &value, QTextCharFormat *format) format->setFontPointSize(rx.cap(1).toInt()); } - -void QssParser::parseFontFamily(const QString &value, QTextCharFormat *format) +void QssParser::parseFontFamily(const QString& value, QTextCharFormat* format) { QString family = value; if (family.startsWith('"') && family.endsWith('"')) {