modernize: Replace most remaining old-style connects by PMF ones
[quassel.git] / src / uisupport / qssparser.cpp
index 24032fb..495adc5 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2016 by the Quassel Project                        *
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -82,7 +82,7 @@ void QssParser::processStyleSheet(QString &ss)
         return;
 
     // Remove C-style comments /* */ or //
-    static QRegExp commentRx("(//.*(\\n|$)|/\\*.*\\*/)");
+    static QRegExp commentRx(R"((//.*(\n|$)|/\*.*\*/))");
     commentRx.setMinimal(true);
     ss.remove(commentRx);
 
@@ -200,7 +200,7 @@ std::pair<UiStyle::FormatType, UiStyle::MessageLabel> QssParser::parseFormatType
 
     const std::pair<UiStyle::FormatType, UiStyle::MessageLabel> invalid{FormatType::Invalid, MessageLabel::None};
 
-    static const QRegExp rx("ChatLine(?:::(\\w+))?(?:#([\\w\\-]+))?(?:\\[([=-,\\\"\\w\\s]+)\\])?");
+    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);
@@ -279,7 +279,7 @@ std::pair<UiStyle::FormatType, UiStyle::MessageLabel> QssParser::parseFormatType
     }
 
     // Next up: conditional (formats, labels, nickhash)
-    static const 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)) {
             if (!condRx.exactMatch(cond)) {
@@ -293,6 +293,8 @@ std::pair<UiStyle::FormatType, UiStyle::MessageLabel> QssParser::parseFormatType
                     label |= MessageLabel::Highlight;
                 else if (condValue == "selected")
                     label |= MessageLabel::Selected;
+                else if (condValue == "hovered")
+                    label |= MessageLabel::Hovered;
                 else {
                     qWarning() << Q_FUNC_INFO << tr("Invalid message label: %1").arg(condValue);
                     return invalid;
@@ -322,8 +324,8 @@ std::pair<UiStyle::FormatType, UiStyle::MessageLabel> QssParser::parseFormatType
                     fmtType |= FormatType::Italic;
                 else if (condValue == "underline")
                     fmtType |= FormatType::Underline;
-                else if (condValue == "reverse")
-                    fmtType |= FormatType::Reverse;
+                else if (condValue == "strikethrough")
+                    fmtType |= FormatType::Strikethrough;
                 else {
                     qWarning() << Q_FUNC_INFO << tr("Invalid format name: %1").arg(condValue);
                     return invalid;
@@ -357,7 +359,7 @@ UiStyle::ItemFormatType QssParser::parseItemFormatType(const QString &decl)
 {
     using ItemFormatType = UiStyle::ItemFormatType;
 
-    static const QRegExp rx("(Chat|Nick)ListItem(?:\\[([=-,\\\"\\w\\s]+)\\])?");
+    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);
@@ -372,7 +374,7 @@ UiStyle::ItemFormatType QssParser::parseItemFormatType(const QString &decl)
     QString type, state;
     if (!properties.isEmpty()) {
         QHash<QString, QString> props;
-        static const QRegExp propRx("\\s*([\\w\\-]+)\\s*=\\s*\"([\\w\\-]+)\"\\s*");
+        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);
@@ -451,6 +453,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<int>(UiStyle::FormatProperty::AllowForegroundOverride), v);
+        }
+        else if (property == "allow-background-override") {
+            bool ok;
+            bool v = parseBoolean(value, &ok);
+            if (ok)
+                format.setProperty(static_cast<int>(UiStyle::FormatProperty::AllowBackgroundOverride), v);
+        }
+
         // font-related properties
         else if (property.startsWith("font")) {
             if (property == "font")
@@ -477,6 +493,23 @@ 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 ********/
 
@@ -506,7 +539,7 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok)
         //   [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("palette\\s*\\(\\s*([a-z-0-9]+)\\s*\\)");
+        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();
@@ -519,8 +552,8 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok)
         return QBrush();
     }
     else if (str.startsWith("qlineargradient")) {
-        static const QString rxFloat("\\s*(-?\\s*[0-9]*\\.?[0-9]+)\\s*");
-        static const 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();
@@ -542,8 +575,8 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok)
         return QBrush(gradient);
     }
     else if (str.startsWith("qconicalgradient")) {
-        static const QString rxFloat("\\s*(-?\\s*[0-9]*\\.?[0-9]+)\\s*");
-        static const 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();
@@ -564,8 +597,8 @@ QBrush QssParser::parseBrush(const QString &str, bool *ok)
         return QBrush(gradient);
     }
     else if (str.startsWith("qradialgradient")) {
-        static const QString rxFloat("\\s*(-?\\s*[0-9]*\\.?[0-9]+)\\s*");
-        static const 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();
@@ -597,7 +630,7 @@ 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));
@@ -633,7 +666,7 @@ QColor QssParser::parseColor(const QString &str)
 QssParser::ColorTuple QssParser::parseColorTuple(const QString &str)
 {
     ColorTuple result;
-    static const 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();
     }
@@ -663,7 +696,7 @@ QGradientStops QssParser::parseGradientStops(const QString &str_)
     QString str = str_;
     QGradientStops result;
     static const QString rxFloat("(0?\\.[0-9]+|[01])"); // values between 0 and 1
-    static const QRegExp rx(QString("\\s*,?\\s*stop:\\s*(%1)\\s+([^:]+)(,\\s*stop:|$)").arg(rxFloat));
+    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();
@@ -684,21 +717,28 @@ QGradientStops QssParser::parseGradientStops(const QString &str_)
 
 void QssParser::parseFont(const QString &value, QTextCharFormat *format)
 {
-    static const 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")
+        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
@@ -724,8 +764,11 @@ 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);
     }