Implement sender matching for highlight rules
authorJanne Koschinski <janne@kuschku.de>
Tue, 5 Sep 2017 16:11:51 +0000 (18:11 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 20 Dec 2017 19:39:56 +0000 (20:39 +0100)
- Implements configuration, sync, and matching behavior for
  sender-based matching in highlight rules
- The match type (regexp or wildcard) is the same as configured for
  the message itself.
- The sender rule has to match exactly

src/common/highlightrulemanager.cpp
src/common/highlightrulemanager.h
src/core/corehighlightrulemanager.h
src/qtui/settingspages/corehighlightsettingspage.cpp
src/qtui/settingspages/corehighlightsettingspage.h
src/qtui/settingspages/corehighlightsettingspage.ui

index 7b24ed5..4d74deb 100644 (file)
@@ -57,6 +57,7 @@ QVariantMap HighlightRuleManager::initHighlightRuleList() const
     QVariantList isCaseSensitive;
     QVariantList isActive;
     QVariantList isInverse;
+    QStringList sender;
     QStringList channel;
 
     for (int i = 0; i < _highlightRuleList.count(); i++) {
@@ -65,6 +66,7 @@ QVariantMap HighlightRuleManager::initHighlightRuleList() const
         isCaseSensitive << _highlightRuleList[i].isCaseSensitive;
         isActive << _highlightRuleList[i].isEnabled;
         isInverse << _highlightRuleList[i].isInverse;
+        sender << _highlightRuleList[i].sender;
         channel << _highlightRuleList[i].chanName;
     }
 
@@ -73,6 +75,7 @@ QVariantMap HighlightRuleManager::initHighlightRuleList() const
     highlightRuleListMap["isCaseSensitive"] = isCaseSensitive;
     highlightRuleListMap["isEnabled"] = isActive;
     highlightRuleListMap["isInverse"] = isInverse;
+    highlightRuleListMap["sender"] = sender;
     highlightRuleListMap["channel"] = channel;
     highlightRuleListMap["highlightNick"] = _highlightNick;
     highlightRuleListMap["nicksCaseSensitive"] = _nicksCaseSensitive;
@@ -87,11 +90,12 @@ void HighlightRuleManager::initSetHighlightRuleList(const QVariantMap &highlight
     QVariantList isCaseSensitive = highlightRuleList["isCaseSensitive"].toList();
     QVariantList isActive = highlightRuleList["isEnabled"].toList();
     QVariantList isInverse = highlightRuleList["isInverse"].toList();
+    QStringList sender = highlightRuleList["sender"].toStringList();
     QStringList channel = highlightRuleList["channel"].toStringList();
 
     int count = name.count();
-    if (count != isRegEx.count() || count != isCaseSensitive.count() ||
-        count != isActive.count() || count != channel.count()) {
+    if (count != isRegEx.count() || count != isCaseSensitive.count() || count != isActive.count() ||
+        count != isInverse.count() || count != sender.count() || count != channel.count()) {
         qWarning() << "Corrupted HighlightRuleList settings! (Count mismatch)";
         return;
     }
@@ -99,23 +103,23 @@ void HighlightRuleManager::initSetHighlightRuleList(const QVariantMap &highlight
     _highlightRuleList.clear();
     for (int i = 0; i < name.count(); i++) {
         _highlightRuleList << HighlightRule(name[i], isRegEx[i].toBool(), isCaseSensitive[i].toBool(),
-                                            isActive[i].toBool(), isInverse[i].toBool(), channel[i]);
+                                            isActive[i].toBool(), isInverse[i].toBool(), sender[i], channel[i]);
     }
     _highlightNick = HighlightNickType(highlightRuleList["highlightNick"].toInt());
     _nicksCaseSensitive = highlightRuleList["nicksCaseSensitive"].toBool();
 }
 
 void HighlightRuleManager::addHighlightRule(const QString &name, bool isRegEx, bool isCaseSensitive, bool isActive,
-                                            bool isInverse, const QString &channel)
+                                            bool isInverse, const QString &sender, const QString &channel)
 {
     if (contains(name)) {
         return;
     }
 
-    HighlightRule newItem = HighlightRule(name, isRegEx, isCaseSensitive, isActive, isInverse, channel);
+    HighlightRule newItem = HighlightRule(name, isRegEx, isCaseSensitive, isActive, isInverse, sender, channel);
     _highlightRuleList << newItem;
 
-    SYNC(ARG(name), ARG(isRegEx), ARG(isCaseSensitive), ARG(isActive), ARG(isInverse), ARG(channel))
+    SYNC(ARG(name), ARG(isRegEx), ARG(isCaseSensitive), ARG(isActive), ARG(isInverse), ARG(sender), ARG(channel))
 }
 
 
@@ -148,12 +152,24 @@ bool HighlightRuleManager::_match(const QString &msgContents, const QString &msg
         QRegExp rx;
         if (rule.isRegEx) {
             rx = QRegExp(rule.name, rule.isCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
-        }
-        else {
+        } else {
             rx = QRegExp("(^|\\W)" + QRegExp::escape(rule.name) + "(\\W|$)", rule.isCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
         }
-        bool match = (rx.indexIn(stripFormatCodes(msgContents)) >= 0);
-        if (match) {
+        bool nameMatch = (rx.indexIn(stripFormatCodes(msgContents)) >= 0);
+
+        bool senderMatch;
+        if (rule.sender.isEmpty()) {
+            senderMatch = true;
+        } else {
+            if (rule.isRegEx) {
+                rx = QRegExp(rule.sender, rule.isCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
+            } else {
+                rx = QRegExp(rule.sender, Qt::CaseInsensitive, QRegExp::Wildcard);
+            }
+            senderMatch = rx.exactMatch(msgSender);
+        }
+
+        if (nameMatch && senderMatch) {
             // If an inverse rule matches, then we know that we never want to return a highlight.
             if (rule.isInverse) {
                 return false;
index b606a0a..427b658 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <QString>
 #include <QRegExp>
+#include <utility>
 
 #include "message.h"
 #include "syncableobject.h"
@@ -47,12 +48,13 @@ public:
         bool isCaseSensitive = false;
         bool isEnabled = true;
         bool isInverse = false;
+        QString sender;
         QString chanName;
         HighlightRule() {}
-        HighlightRule(const QString &name_, bool isRegEx_, bool isCaseSensitive_,
-                       bool isEnabled_, bool isInverse_, const QString &chanName_)
-            : name(name_), isRegEx(isRegEx_), isCaseSensitive(isCaseSensitive_), isEnabled(isEnabled_),
-              isInverse(isInverse_), chanName(chanName_) {
+        HighlightRule(QString name_, bool isRegEx_, bool isCaseSensitive_, bool isEnabled_, bool isInverse_,
+                      QString sender_, QString chanName_)
+            : name(std::move(name_)), isRegEx(isRegEx_), isCaseSensitive(isCaseSensitive_), isEnabled(isEnabled_),
+              isInverse(isInverse_), sender(std::move(sender_)), chanName(std::move(chanName_)) {
         }
         bool operator!=(const HighlightRule &other)
         {
@@ -61,6 +63,7 @@ public:
                     isCaseSensitive != other.isCaseSensitive ||
                     isEnabled != other.isEnabled ||
                     isInverse != other.isInverse ||
+                    sender != other.sender ||
                     chanName != other.chanName);
         }
     };
@@ -114,14 +117,14 @@ public slots:
       * @param chanName The channel in which the rule should apply
       */
     virtual inline void requestAddHighlightRule(const QString &name, bool isRegEx, bool isCaseSensitive, bool isEnabled,
-                                                bool isInverse, const QString &chanName)
+                                                bool isInverse, const QString &sender, const QString &chanName)
     {
-        REQUEST(ARG(name), ARG(isRegEx), ARG(isCaseSensitive), ARG(isEnabled), ARG(isInverse), ARG(chanName))
+        REQUEST(ARG(name), ARG(isRegEx), ARG(isCaseSensitive), ARG(isEnabled), ARG(isInverse), ARG(sender), ARG(chanName))
     }
 
 
-    virtual void addHighlightRule(const QString &name, bool isRegEx, bool isCaseSensitive,
-                                  bool isEnabled, bool isInverse, const QString &chanName);
+    virtual void addHighlightRule(const QString &name, bool isRegEx, bool isCaseSensitive, bool isEnabled,
+                                  bool isInverse, const QString &sender, const QString &chanName);
 
     virtual inline void requestSetHighlightNick(HighlightNickType highlightNick)
     {
@@ -141,7 +144,7 @@ protected:
     bool _match(const QString &msgContents, const QString &msgSender, Message::Type msgType, Message::Flags msgFlags, const QString &bufferName, const QString &currentNick, const QStringList identityNicks);
 
 signals:
-    void ruleAdded(QString name, bool isRegEx, bool isCaseSensitive, bool isEnabled, bool isInverse, QString chanName);
+    void ruleAdded(QString name, bool isRegEx, bool isCaseSensitive, bool isEnabled, bool isInverse, QString sender, QString chanName);
 
 private:
     HighlightRuleList _highlightRuleList;
index 9cb1b63..5f2db90 100644 (file)
@@ -40,10 +40,10 @@ public:
 public slots:
     virtual inline void requestToggleHighlightRule(const QString &highlightRule) { toggleHighlightRule(highlightRule); }
     virtual inline void requestRemoveHighlightRule(const QString &highlightRule) { removeHighlightRule(highlightRule); }
-    virtual inline void requestAddHighlightRule(const QString &name, bool isRegEx, bool isCaseSensitive,
-                                                 bool isEnabled, bool isInverse, const QString &chanName)
+    virtual inline void requestAddHighlightRule(const QString &name, bool isRegEx, bool isCaseSensitive, bool isEnabled,
+                                                bool isInverse, const QString &sender, const QString &chanName)
     {
-        addHighlightRule(name, isRegEx, isCaseSensitive, isEnabled, isInverse, chanName);
+        addHighlightRule(name, isRegEx, isCaseSensitive, isEnabled, isInverse, sender, chanName);
     }
 
 
index 467991f..8e9b852 100644 (file)
@@ -107,7 +107,8 @@ void CoreHighlightSettingsPage::defaults()
 }
 
 
-void CoreHighlightSettingsPage::addNewRow(QString name, bool regex, bool cs, bool enable, bool inverse, QString chanName, bool self)
+void CoreHighlightSettingsPage::addNewRow(const QString &name, bool regex, bool cs, bool enable, bool inverse, const QString &sender,
+                                          const QString &chanName, bool self)
 {
     ui.highlightTable->setRowCount(ui.highlightTable->rowCount()+1);
 
@@ -143,18 +144,21 @@ void CoreHighlightSettingsPage::addNewRow(QString name, bool regex, bool cs, boo
 
     auto *chanNameItem = new QTableWidgetItem(chanName);
 
+    auto *senderItem = new QTableWidgetItem(sender);
+
     int lastRow = ui.highlightTable->rowCount()-1;
     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::NameColumn, nameItem);
     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::RegExColumn, regexItem);
     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::CsColumn, csItem);
     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::EnableColumn, enableItem);
     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::InverseColumn, inverseItem);
+    ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::SenderColumn, senderItem);
     ui.highlightTable->setItem(lastRow, CoreHighlightSettingsPage::ChanColumn, chanNameItem);
 
     if (!self)
         ui.highlightTable->setCurrentItem(nameItem);
 
-    highlightList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, inverse, chanName);
+    highlightList << HighlightRuleManager::HighlightRule(name, regex, cs, enable, inverse, sender, chanName);
 }
 
 
@@ -227,6 +231,11 @@ void CoreHighlightSettingsPage::tableChanged(QTableWidgetItem *item)
     case CoreHighlightSettingsPage::InverseColumn:
         highlightRule.isInverse = (item->checkState() == Qt::Checked);
         break;
+        case CoreHighlightSettingsPage::SenderColumn:
+            if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
+                item->setText("");
+            highlightRule.sender = item->text();
+            break;
     case CoreHighlightSettingsPage::ChanColumn:
         if (!item->text().isEmpty() && item->text().trimmed().isEmpty())
             item->setText("");
@@ -244,7 +253,7 @@ void CoreHighlightSettingsPage::load()
 
     auto ruleManager = Client::highlightRuleManager();
     for (HighlightRuleManager::HighlightRule rule : ruleManager->highlightRuleList()) {
-        addNewRow(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, rule.isInverse, rule.chanName);
+        addNewRow(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, rule.isInverse, rule.sender, rule.chanName);
     }
 
     switch (ruleManager->highlightNick())
@@ -282,7 +291,8 @@ void CoreHighlightSettingsPage::save()
     clonedManager.clear();
 
     for (const HighlightRuleManager::HighlightRule &rule : highlightList) {
-        clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, rule.isInverse, rule.chanName);
+        clonedManager.addHighlightRule(rule.name, rule.isRegEx, rule.isCaseSensitive, rule.isEnabled, rule.isInverse,
+                                       rule.sender, rule.chanName);
     }
 
     HighlightRuleManager::HighlightNickType highlightNickType = HighlightRuleManager::NoNick;
index 915ea78..2820850 100644 (file)
@@ -47,7 +47,8 @@ public slots:
 
 private slots:
     void widgetHasChanged();
-    void addNewRow(QString name = tr("highlight rule"), bool regex = false, bool cs = false, bool enable = true, bool inverse = false, QString chanName = "", bool self = false);
+    void addNewRow(const QString &name = tr("highlight rule"), bool regex = false, bool cs = false, bool enable = true,
+                   bool inverse = false, const QString &sender = "", const QString &chanName = "", bool self = false);
     void removeSelectedRows();
     void selectRow(QTableWidgetItem *item);
     void tableChanged(QTableWidgetItem *item);
@@ -61,8 +62,9 @@ private:
         CsColumn = 2,
         EnableColumn = 3,
         InverseColumn = 4,
-        ChanColumn = 5,
-        ColumnCount = 6
+        SenderColumn = 5,
+        ChanColumn = 6,
+        ColumnCount = 7
     };
 
     void emptyTable();
index 6e18ecb..7abdcef 100644 (file)
           <string>Inverse</string>
          </property>
         </column>
+        <column>
+         <property name="text">
+          <string>Sender</string>
+         </property>
+        </column>
         <column>
          <property name="text">
           <string>Channel</string>