Provide a contextmenu for the ignore list
authorSebastian Goth <seezer@roath.org>
Sat, 12 Sep 2009 16:54:46 +0000 (18:54 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 13 Sep 2009 19:18:48 +0000 (21:18 +0200)
This will not work without updating the core too :/

15 files changed:
src/client/clientignorelistmanager.cpp
src/client/clientignorelistmanager.h
src/common/ignorelistmanager.cpp
src/common/ignorelistmanager.h
src/core/coreignorelistmanager.h
src/qtui/mainwin.cpp
src/qtui/mainwin.h
src/qtui/settingspages/ignorelistmodel.cpp
src/qtui/settingspages/ignorelistmodel.h
src/qtui/settingspages/ignorelistsettingspage.cpp
src/qtui/settingspages/ignorelistsettingspage.h
src/uisupport/contextmenuactionprovider.cpp
src/uisupport/contextmenuactionprovider.h
src/uisupport/networkmodelcontroller.cpp
src/uisupport/networkmodelcontroller.h

index e54eeb7..f146313 100644 (file)
 
 #include "clientignorelistmanager.h"
 
+#include <QRegExp>
+
 INIT_SYNCABLE_OBJECT(ClientIgnoreListManager)
 
 ClientIgnoreListManager::ClientIgnoreListManager(QObject *parent)
     : IgnoreListManager(parent)
 {
-  connect(this, SIGNAL(updated()), SIGNAL(ignoreListChanged()));
+  connect(this, SIGNAL(updatedRemotely()), SIGNAL(ignoreListChanged()));
+}
+
+bool ClientIgnoreListManager::pureMatch(const IgnoreListItem &item, const QString &string) const {
+  QRegExp ruleRx = QRegExp(item.ignoreRule);
+  ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
+  if(!item.isRegEx)
+    ruleRx.setPatternSyntax(QRegExp::Wildcard);
+
+  if((!item.isRegEx && ruleRx.exactMatch(string)) ||
+     (item.isRegEx && ruleRx.indexIn(string) != -1))
+    return true;
+  return false;
+}
+
+QMap<QString, bool> ClientIgnoreListManager::matchingRulesForHostmask(const QString &hostmask, const QString &network, const QString &channel) const {
+  QMap<QString, bool> result;
+  foreach(IgnoreListItem item, ignoreList()) {
+    if(item.type == SenderIgnore && pureMatch(item, hostmask)
+      && ((network.isEmpty() && channel.isEmpty()) || item.scope == GlobalScope || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network))
+          || (item.scope == ChannelScope && scopeMatch(item.scopeRule, channel)))) {
+      result[item.ignoreRule] = item.isActive;
+//      qDebug() << "matchingRulesForHostmask found: " << item.ignoreRule << "is active: " << item.isActive;
+    }
+
+  }
+  return result;
 }
index eac7c72..51f0203 100644 (file)
@@ -22,6 +22,7 @@
 #define CLIENTIGNORELISTMANAGER_H
 
 #include "ignorelistmanager.h"
+#include <QMap>
 
 class ClientIgnoreListManager : public IgnoreListManager
 {
@@ -32,8 +33,20 @@ public:
   explicit ClientIgnoreListManager(QObject *parent = 0);
   inline virtual const QMetaObject *syncMetaObject() const { return &IgnoreListManager::staticMetaObject; }
 
+  //! Fetch all matching ignore rules for a given hostmask
+  /** \param hostmask The hostmask of the user
+    * \param network The network name
+    * \param channel The channel name
+    * \return Returns a QMap with the rule as key and a bool, representing if the rule is enabled or not, as value
+    */
+  QMap<QString, bool> matchingRulesForHostmask(const QString &hostmask, const QString &network, const QString &channel) const;
+
 signals:
   void ignoreListChanged();
+
+private:
+  // matches an ignore rule against a given string
+  bool pureMatch(const IgnoreListItem &item, const QString &string) const;
 };
 
 #endif // CLIENTIGNORELISTMANAGER_H
index d6164b8..dfd9ae2 100644 (file)
@@ -99,19 +99,22 @@ void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) {
   }
 }
 
+/* since overloaded methods aren't syncable (yet?) we can't use that anymore
 void IgnoreListManager::addIgnoreListItem(const IgnoreListItem &item) {
   addIgnoreListItem(item.type, item.ignoreRule, item.isRegEx, item.strictness, item.scope, item.scopeRule, item.isActive);
 }
-
-void IgnoreListManager::addIgnoreListItem(IgnoreType type, const QString &ignoreRule, bool isRegEx, StrictnessType strictness,
-                                      ScopeType scope, const QString &scopeRule, bool isActive) {
+*/
+void IgnoreListManager::addIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness,
+                                      int scope, const QString &scopeRule, bool isActive) {
   if(contains(ignoreRule)) {
     return;
   }
 
-  _ignoreList << IgnoreListItem(type, ignoreRule, isRegEx, strictness, scope, scopeRule, isActive);
+  IgnoreListItem newItem = IgnoreListItem(static_cast<IgnoreType>(type), ignoreRule, isRegEx, static_cast<StrictnessType>(strictness),
+                                          static_cast<ScopeType>(scope), scopeRule, isActive);
+  _ignoreList << newItem;
 
-  emit ignoreAdded(type, ignoreRule, isRegEx, strictness, scope, scopeRule, isActive);
+  SYNC(ARG(type), ARG(ignoreRule), ARG(isRegEx), ARG(strictness), ARG(scope), ARG(scopeRule), ARG(isActive))
 }
 
 IgnoreListManager::StrictnessType IgnoreListManager::match(const Message &msg, const QString &network) {
@@ -151,7 +154,7 @@ IgnoreListManager::StrictnessType IgnoreListManager::match(const Message &msg, c
   return UnmatchedStrictness;
 }
 
-bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &string) {
+bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &string) const {
   foreach(QString rule, scopeRule.split(";")) {
     QRegExp ruleRx = QRegExp(rule.trimmed());
     ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
@@ -162,3 +165,16 @@ bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &stri
   }
   return false;
 }
+
+void IgnoreListManager::removeIgnoreListItem(const QString &ignoreRule) {
+  removeAt(indexOf(ignoreRule));
+  SYNC(ARG(ignoreRule))
+}
+
+void IgnoreListManager::toggleIgnoreRule(const QString &ignoreRule) {
+  int idx = indexOf(ignoreRule);
+  if(idx == -1)
+    return;
+  _ignoreList[idx].isActive = !_ignoreList[idx].isActive;
+  SYNC(ARG(ignoreRule))
+}
index 1d44b0b..d6ab6ec 100644 (file)
@@ -93,23 +93,55 @@ public:
     */
   StrictnessType match(const Message &msg, const QString &network = QString());
 
-  virtual void addIgnoreListItem(IgnoreType type, const QString &ignoreRule, bool isRegEx, StrictnessType strictness,
-                                 ScopeType scope, const QString &scopeRule, bool isActive);
-  virtual void addIgnoreListItem(const IgnoreListItem &item);
+
+//  virtual void addIgnoreListItem(const IgnoreListItem &item);
 
 public slots:
   virtual QVariantMap initIgnoreList() const;
   virtual void initSetIgnoreList(const QVariantMap &ignoreList);
 
+  //! Request removal of an ignore rule based on the rule itself.
+  /** Use this method if you want to remove a single ignore rule
+    * and get that synced with the core immediately.
+    * \param ignoreRule A valid ignore rule
+    */
+  virtual inline void requestRemoveIgnoreListItem(const QString &ignoreRule) { REQUEST(ARG(ignoreRule)) }
+  virtual void removeIgnoreListItem(const QString &ignoreRule);
+
+  //! Request toggling of "isActive" flag of a given ignore rule.
+  /** Use this method if you want to toggle the "isActive" flag of a single ignore rule
+    * and get that synced with the core immediately.
+    * \param ignoreRule A valid ignore rule
+    */
+  virtual inline void requestToggleIgnoreRule(const QString &ignoreRule) { REQUEST(ARG(ignoreRule)) }
+  virtual void toggleIgnoreRule(const QString &ignoreRule);
+
+  //! Request an IgnoreListItem to be added to the ignore list
+  /** Items added to the list with this method, get immediately synced with the core
+    * \param type The IgnoreType of the new rule
+    * \param ignoreRule The rule itself
+    * \param isRegEx Signals if the rule should be interpreted as a regular expression
+    * \param strictness Th StrictnessType that should be applied
+    * \param scope The ScopeType that should be set
+    * \param scopeRule A string of semi-colon separated network- or channelnames
+    * \param isActive Signals if the rule is enabled or not
+    */
+  virtual inline void requestAddIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness,
+                                               int scope, const QString &scopeRule, bool isActive) {
+    REQUEST(ARG(type), ARG(ignoreRule), ARG(isRegEx), ARG(strictness), ARG(scope), ARG(scopeRule), ARG(isActive))
+  }
+  virtual void addIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness,
+                                 int scope, const QString &scopeRule, bool isActive);
+
 protected:
   void setIgnoreList(const QList<IgnoreListItem> &ignoreList) { _ignoreList = ignoreList; }
+  // scopeRule is a ; separated list, string is a network/channel-name
+  bool scopeMatch(const QString &scopeRule, const QString &string) const;
 
 signals:
   void ignoreAdded(IgnoreType type, const QString &ignoreRule, bool isRegex, StrictnessType strictness, ScopeType scope, const QVariant &scopeRule, bool isActive);
 
 private:
-  // scopeRule is a ; separated list, string is a network/channel-name
-  bool scopeMatch(const QString &scopeRule, const QString &string);
   IgnoreList _ignoreList;
 };
 
index d455d2c..e53124b 100644 (file)
@@ -35,6 +35,14 @@ public:
 
   inline virtual const QMetaObject *syncMetaObject() const { return &IgnoreListManager::staticMetaObject; }
 
+public slots:
+  virtual inline void requestToggleIgnoreRule(const QString &ignoreRule) { toggleIgnoreRule(ignoreRule); }
+  virtual inline void requestRemoveIgnoreListItem(const QString &ignoreRule) { removeIgnoreListItem(ignoreRule); }
+  virtual inline void requestAddIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness,
+                                               int scope, const QString &scopeRule, bool isActive) {
+    addIgnoreListItem(type, ignoreRule, isRegEx, strictness, scope, scopeRule, isActive);
+  }
+
 //private:
 //  void loadDefaults();
 
index 1f6d17e..98ecdd3 100644 (file)
@@ -148,6 +148,7 @@ void MainWin::init() {
   connect(Client::messageModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
            SLOT(messagesInserted(const QModelIndex &, int, int)));
   connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showChannelList(NetworkId)), SLOT(showChannelList(NetworkId)));
+  connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showIgnoreList(QString)), SLOT(showIgnoreList(QString)));
 
   // Setup Dock Areas
   setDockNestingEnabled(true);
@@ -812,6 +813,14 @@ void MainWin::showChannelList(NetworkId netId) {
   channelListDlg->show();
 }
 
+void MainWin::showIgnoreList(QString newRule) {
+  SettingsPageDlg dlg(new IgnoreListSettingsPage(this), this);
+  // prepare config dialog for new rule
+  if(!newRule.isEmpty())
+    qobject_cast<IgnoreListSettingsPage *>(dlg.currentPage())->editIgnoreRule(newRule);
+  dlg.exec();
+}
+
 void MainWin::showCoreInfoDlg() {
   CoreInfoDlg(this).exec();
 }
index 361467a..c22d32d 100644 (file)
@@ -123,6 +123,7 @@ class MainWin
     void showAwayLog();
     void showSettingsDlg();
     void showNotificationsDlg();
+    void showIgnoreList(QString newRule = QString());
 #ifdef HAVE_KDE
     void showShortcutsDlg();
 #endif
index ec09dec..b6b44bf 100644 (file)
@@ -141,7 +141,9 @@ bool IgnoreListModel::newIgnoreRule(const IgnoreListManager::IgnoreListItem &ite
   if(manager.contains(item.ignoreRule))
     return false;
   beginInsertRows(QModelIndex(), rowCount(), rowCount());
-  manager.addIgnoreListItem(item);
+  // manager.addIgnoreListItem(item);
+  manager.addIgnoreListItem(item.type, item.ignoreRule, item.isRegEx, item.strictness, item.scope,
+                            item.scopeRule, item.isActive);
   endInsertRows();
   return true;
 }
@@ -277,3 +279,7 @@ void IgnoreListModel::setIgnoreListItemAt(int row, const IgnoreListManager::Igno
   cloneIgnoreListManager()[row] = item;
   emit dataChanged(createIndex(row, 0), createIndex(row, 2));
 }
+
+const QModelIndex IgnoreListModel::indexOf(const QString &rule) {
+  return createIndex(ignoreListManager().indexOf(rule), 2);
+}
index de3eb06..f6a3ead 100644 (file)
@@ -52,6 +52,7 @@ public:
   const IgnoreListManager::IgnoreListItem &ignoreListItemAt(int row) const;
   void setIgnoreListItemAt(int row, const IgnoreListManager::IgnoreListItem &item);
   bool newIgnoreRule(const IgnoreListManager::IgnoreListItem &item);
+  const QModelIndex indexOf(const QString &rule);
 
 public slots:
   void loadDefaults();
index 8ee11d4..61f0864 100644 (file)
@@ -27,7 +27,7 @@
 #include <QMessageBox>
 #include <QString>
 #include <QEvent>
-
+#include <QDebug>
 #include "iconloader.h"
 
 IgnoreListSettingsPage::IgnoreListSettingsPage(QWidget *parent)
@@ -72,6 +72,8 @@ IgnoreListSettingsPage::~IgnoreListSettingsPage() {
 void IgnoreListSettingsPage::load() {
   if(_ignoreListModel.configChanged())
     _ignoreListModel.revert();
+  ui.ignoreListView->selectionModel()->reset();
+  ui.editIgnoreRuleButton->setEnabled(false);
 }
 
 void IgnoreListSettingsPage::defaults() {
@@ -83,6 +85,7 @@ void IgnoreListSettingsPage::save() {
     _ignoreListModel.commit();
   }
   ui.ignoreListView->selectionModel()->reset();
+  ui.editIgnoreRuleButton->setEnabled(false);
 }
 
 void IgnoreListSettingsPage::enableDialog(bool enabled) {
@@ -103,8 +106,18 @@ void IgnoreListSettingsPage::deleteSelectedIgnoreRule() {
   _ignoreListModel.removeIgnoreRule(ui.ignoreListView->selectionModel()->selectedIndexes()[0].row());
 }
 
-void IgnoreListSettingsPage::newIgnoreRule() {
-  IgnoreListEditDlg *dlg = new IgnoreListEditDlg(-1, IgnoreListManager::IgnoreListItem(), this);
+void IgnoreListSettingsPage::newIgnoreRule(QString rule) {
+  IgnoreListManager::IgnoreListItem newItem = IgnoreListManager::IgnoreListItem();
+  newItem.isActive = true;
+  bool enableOkButton = false;
+  if(!rule.isEmpty()) {
+    // we're called from contextmenu
+    newItem.ignoreRule = rule;
+    enableOkButton = true;
+  }
+
+  IgnoreListEditDlg *dlg = new IgnoreListEditDlg(newItem, this, enableOkButton);
+  dlg->enableOkButton(enableOkButton);
 
   while(dlg->exec() == QDialog::Accepted) {
     if(!_ignoreListModel.newIgnoreRule(dlg->ignoreListItem())) {
@@ -118,7 +131,7 @@ void IgnoreListSettingsPage::newIgnoreRule() {
 
       IgnoreListManager::IgnoreListItem item = dlg->ignoreListItem();
       delete dlg;
-      dlg = new IgnoreListEditDlg(-1, item, this);
+      dlg = new IgnoreListEditDlg(item, this);
     }
     else {
       break;
@@ -131,13 +144,24 @@ void IgnoreListSettingsPage::editSelectedIgnoreRule() {
   if(!ui.ignoreListView->selectionModel()->hasSelection())
     return;
   int row = ui.ignoreListView->selectionModel()->selectedIndexes()[0].row();
-  IgnoreListEditDlg dlg(row, _ignoreListModel.ignoreListItemAt(row), this);
+  IgnoreListEditDlg dlg(_ignoreListModel.ignoreListItemAt(row), this);
   dlg.setAttribute(Qt::WA_DeleteOnClose, false);
   if(dlg.exec() == QDialog::Accepted) {
     _ignoreListModel.setIgnoreListItemAt(row, dlg.ignoreListItem());
   }
 }
 
+void IgnoreListSettingsPage::editIgnoreRule(const QString &ignoreRule) {
+  ui.ignoreListView->selectionModel()->select(_ignoreListModel.indexOf(ignoreRule), QItemSelectionModel::Select);
+  if(ui.ignoreListView->selectionModel()->hasSelection())// && ui.ignoreListView->selectionModel()->selectedIndexes()[0].row() != -1)
+    editSelectedIgnoreRule();
+  else
+    newIgnoreRule(ignoreRule);
+}
+
+/*
+  IgnoreListDelegate
+*/
 void IgnoreListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
   if(index.column() == 0) {
     QStyle *style = QApplication::style();
@@ -156,8 +180,27 @@ void IgnoreListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
     QStyledItemDelegate::paint(painter, option, index);
 }
 
-IgnoreListEditDlg::IgnoreListEditDlg(int row, const IgnoreListManager::IgnoreListItem &item, QWidget *parent)
-    : QDialog(parent), _selectedRow(row), _ignoreListItem(item), _hasChanged(false) {
+// provide interactivity for the checkboxes
+bool IgnoreListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
+                                     const QStyleOptionViewItem &option, const QModelIndex &index) {
+  Q_UNUSED(option)
+  switch(event->type()) {
+    case QEvent::MouseButtonRelease:
+      model->setData(index, !index.data().toBool());
+      return true;
+      // don't show the default editor for the column
+    case QEvent::MouseButtonDblClick:
+      return true;
+    default:
+      return false;
+  }
+}
+
+/*
+  IgnoreListEditDlg
+*/
+IgnoreListEditDlg::IgnoreListEditDlg(const IgnoreListManager::IgnoreListItem &item, QWidget *parent, bool enabled)
+    : QDialog(parent), _ignoreListItem(item), _hasChanged(enabled) {
   ui.setupUi(this);
   setAttribute(Qt::WA_DeleteOnClose, false);
   setModal(true);
@@ -266,18 +309,6 @@ void IgnoreListEditDlg::widgetHasChanged() {
   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(_hasChanged);
 }
 
-// provide interactivity for the checkboxes
-bool IgnoreListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
-                                     const QStyleOptionViewItem &option, const QModelIndex &index) {
-  Q_UNUSED(option)
-  switch(event->type()) {
-    case QEvent::MouseButtonRelease:
-      model->setData(index, !index.data().toBool());
-      return true;
-      // don't show the default editor for the column
-    case QEvent::MouseButtonDblClick:
-      return true;
-    default:
-      return false;
-  }
+void IgnoreListEditDlg::enableOkButton(bool state) {
+  ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(state);
 }
index 4e2e85c..251018c 100644 (file)
@@ -50,14 +50,15 @@ class IgnoreListEditDlg : public QDialog {
   Q_OBJECT
 
 public:
-  IgnoreListEditDlg(int row, const IgnoreListManager::IgnoreListItem &item, QWidget *parent = 0);
+  IgnoreListEditDlg(const IgnoreListManager::IgnoreListItem &item, QWidget *parent = 0, bool enabled = false);
   inline IgnoreListManager::IgnoreListItem ignoreListItem() { return _ignoreListItem; }
+  void enableOkButton(bool state);
 
 private slots:
   void widgetHasChanged();
   void aboutToAccept() { _ignoreListItem = _clonedIgnoreListItem; }
+
 private:
-  int _selectedRow;
   IgnoreListManager::IgnoreListItem _ignoreListItem;
   IgnoreListManager::IgnoreListItem _clonedIgnoreListItem;
   bool _hasChanged;
@@ -73,18 +74,19 @@ class IgnoreListSettingsPage : public SettingsPage {
 public:
   IgnoreListSettingsPage(QWidget *parent = 0);
   ~IgnoreListSettingsPage();
-  virtual inline bool hasDefaults() const { return true; }
+  virtual inline bool hasDefaults() const { return false; }
+  void editIgnoreRule(const QString &ignoreRule);
 
 public slots:
   void save();
   void load();
   void defaults();
+  void newIgnoreRule(QString rule = QString());
 
 private slots:
   void enableDialog(bool);
   void deleteSelectedIgnoreRule();
   void editSelectedIgnoreRule();
-  void newIgnoreRule();
   void selectionChanged(const QItemSelection &selection, const QItemSelection &);
 
 private:
index 84fa10b..03c2de6 100644 (file)
@@ -21,6 +21,7 @@
 #include <QInputDialog>
 #include <QMenu>
 #include <QMessageBox>
+#include <QMap>
 
 #include "contextmenuactionprovider.h"
 
@@ -30,6 +31,8 @@
 #include "clientidentity.h"
 #include "network.h"
 #include "util.h"
+#include "client.h"
+#include "clientignorelistmanager.h"
 
 ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) : NetworkModelController(parent) {
   registerAction(NetworkConnect, SmallIcon("network-connect"), tr("Connect"));
@@ -60,6 +63,17 @@ ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) : NetworkM
   registerAction(NickCtcpTime, tr("Time"));
   registerAction(NickCtcpPing, tr("Ping"));
   registerAction(NickCtcpFinger, tr("Finger"));
+  registerAction(NickIgnoreCustom, tr("Custom..."));
+
+  // these texts are only dummies! don't think about tr() here!
+  registerAction(NickIgnoreUser, "*!ident@host.domain.tld");
+  registerAction(NickIgnoreHost, "*!*@host.domain.tld");
+  registerAction(NickIgnoreDomain, "*!ident@*.domain.tld");
+  registerAction(NickIgnoreToggleEnabled0, "Enable", true);
+  registerAction(NickIgnoreToggleEnabled1, "Enable", true);
+  registerAction(NickIgnoreToggleEnabled2, "Enable", true);
+  registerAction(NickIgnoreToggleEnabled3, "Enable", true);
+  registerAction(NickIgnoreToggleEnabled4, "Enable", true);
 
   registerAction(NickOp, SmallIcon("irc-operator"), tr("Give Operator Status"));
   registerAction(NickDeop, SmallIcon("irc-remove-operator"), tr("Take Operator Status"));
@@ -107,6 +121,10 @@ ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) : NetworkM
   nickModeMenu->addAction(action(NickKickBan));
   _nickModeMenuAction = new Action(tr("Actions"), 0);
   _nickModeMenuAction->setMenu(nickModeMenu);
+
+  QMenu *ignoreMenu = new QMenu();
+  _nickIgnoreMenuAction = new Action(tr("Ignore"), 0);
+  _nickIgnoreMenuAction->setMenu(ignoreMenu);
 }
 
 ContextMenuActionProvider::~ContextMenuActionProvider() {
@@ -116,6 +134,8 @@ ContextMenuActionProvider::~ContextMenuActionProvider() {
   _nickCtcpMenuAction->deleteLater();
   _nickModeMenuAction->menu()->deleteLater();
   _nickModeMenuAction->deleteLater();
+  _nickIgnoreMenuAction->menu()->deleteLater();
+  _nickIgnoreMenuAction->deleteLater();
 }
 
 void ContextMenuActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) {
@@ -286,6 +306,18 @@ void ContextMenuActionProvider::addIrcUserActions(QMenu *menu, const QModelIndex
     NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
     addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType);
     addAction(_nickCtcpMenuAction, menu);
+
+    IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
+    if(ircUser) {
+      // ignoreliststuff
+      QString bufferName;
+      BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
+      if(bufferInfo.type() == BufferInfo::ChannelBuffer)
+        bufferName = bufferInfo.bufferName();
+      QMap<QString, bool> ignoreMap = Client::ignoreListManager()->matchingRulesForHostmask(ircUser->hostmask(), ircUser->network()->networkName(), bufferName);
+      addIgnoreMenu(menu, ircUser->hostmask(), ignoreMap);
+      // end of ignoreliststuff
+    }
     menu->addSeparator();
     addAction(NickQuery, menu, itemType == NetworkModel::IrcUserItemType && !haveQuery && indexList().count() == 1);
     addAction(NickSwitchTo, menu, itemType == NetworkModel::IrcUserItemType && haveQuery);
@@ -351,3 +383,59 @@ void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, int filter) {
 
   menu->addAction(_hideEventsMenuAction);
 }
+
+void ContextMenuActionProvider::addIgnoreMenu(QMenu *menu, const QString &hostmask, const QMap<QString, bool> &ignoreMap) {
+  QMenu *ignoreMenu = _nickIgnoreMenuAction->menu();
+  ignoreMenu->clear();
+  QString nick = nickFromMask(hostmask);
+  QString ident = userFromMask(hostmask);
+  QString host = hostFromMask(hostmask);
+  QString domain = host;
+  QRegExp domainRx = QRegExp("(\\.[^.]+\\.\\w+)$");
+  if(domainRx.indexIn(host) != -1)
+    domain = domainRx.cap(1);
+  // we can't rely on who-data
+  // if we don't have the data, we skip actions where we would need it
+  bool haveWhoData = !ident.isEmpty() && !host.isEmpty();
+
+
+  ignoreMenu->addAction(tr("Add Ignore Rule"))->setEnabled(false);
+
+  if(haveWhoData) {
+    action(NickIgnoreUser)->setText(QString("*!%1@%2").arg(ident, host));
+    action(NickIgnoreHost)->setText(QString("*!*@%1").arg(host));
+    action(NickIgnoreDomain)->setText(domain.at(0) == '.' ? QString("*!%1@*%2").arg(ident, domain)
+                                      : QString("*!%1@%2").arg(ident, domain));
+
+    if(!ignoreMap.contains(action(NickIgnoreUser)->text()))
+      ignoreMenu->addAction(action(NickIgnoreUser));
+    if(!ignoreMap.contains(action(NickIgnoreHost)->text()))
+      ignoreMenu->addAction(action(NickIgnoreHost));
+    if(!ignoreMap.contains(action(NickIgnoreDomain)->text()))
+      ignoreMenu->addAction(action(NickIgnoreDomain));
+  }
+  ignoreMenu->addAction(action(NickIgnoreCustom));
+  ignoreMenu->addSeparator();
+
+  if(haveWhoData) {
+    QMap<QString, bool>::const_iterator ruleIter = ignoreMap.begin();
+    int counter = 0;
+    if(!ignoreMap.isEmpty())
+      ignoreMenu->addAction(tr("Existing Rules"))->setEnabled(false);
+    while(ruleIter != ignoreMap.constEnd()) {
+      if(counter < 5) {
+        ActionType type = static_cast<ActionType>(NickIgnoreToggleEnabled0 + counter*0x100000);
+        Action *act = action(type);
+        act->setText(ruleIter.key());
+        act->setChecked(ruleIter.value());
+        ignoreMenu->addAction(act);
+      }
+      counter++;
+      ruleIter++;
+    }
+    if(counter)
+      ignoreMenu->addSeparator();
+  }
+  ignoreMenu->addAction(action(ShowIgnoreList));
+  addAction(_nickIgnoreMenuAction, menu);
+}
index bdac641..c6753fa 100644 (file)
@@ -61,6 +61,7 @@ private:
   void addHideEventsMenu(QMenu *, BufferId bufferId);
   void addHideEventsMenu(QMenu *, MessageFilter *msgFilter);
   void addHideEventsMenu(QMenu *, int filter = -1);
+  void addIgnoreMenu(QMenu *menu, const QString &hostmask, const QMap<QString, bool> &ignoreMap);
 
   void addNetworkItemActions(QMenu *, const QModelIndex &);
   void addBufferItemActions(QMenu *, const QModelIndex &, bool isCustomBufferView = false);
@@ -69,6 +70,7 @@ private:
   Action *_hideEventsMenuAction;
   Action *_nickCtcpMenuAction;
   Action *_nickModeMenuAction;
+  Action *_nickIgnoreMenuAction;
 };
 
 #endif
index 58db561..cb882f8 100644 (file)
@@ -35,6 +35,8 @@
 #include "clientidentity.h"
 #include "network.h"
 #include "util.h"
+#include "clientignorelistmanager.h"
+#include "client.h"
 
 NetworkModelController::NetworkModelController(QObject *parent)
 : QObject(parent),
@@ -345,14 +347,14 @@ void NetworkModelController::handleGeneralAction(ActionType type, QAction *actio
       break;
     case ShowIgnoreList:
       if(networkId.isValid())
-        emit showIgnoreList(networkId);
+        emit showIgnoreList(QString());
       break;
     default:
       break;
   }
 }
 
-void NetworkModelController::handleNickAction(ActionType type, QAction *) {
+void NetworkModelController::handleNickAction(ActionType type, QAction *action) {
   foreach(QModelIndex index, indexList()) {
     NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
     if(!networkId.isValid())
@@ -364,6 +366,9 @@ void NetworkModelController::handleNickAction(ActionType type, QAction *) {
     if(!bufferInfo.isValid())
       continue;
 
+    // the validity of that cast is checked on contextmenu creation, take care
+    IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
+
     switch(type) {
       case NickWhois:
         Client::userInput(bufferInfo, QString("/WHOIS %1 %1").arg(nick));
@@ -408,6 +413,38 @@ void NetworkModelController::handleNickAction(ActionType type, QAction *) {
       case NickQuery:
         Client::userInput(bufferInfo, QString("/QUERY %1").arg(nick));
         break;
+      case NickIgnoreUser:
+        Client::ignoreListManager()->requestAddIgnoreListItem(IgnoreListManager::SenderIgnore,
+                                                       action->text(),
+                                                       false, IgnoreListManager::SoftStrictness,
+                                                       IgnoreListManager::NetworkScope,
+                                                       ircUser->network()->networkName(), true);
+        break;
+      case NickIgnoreHost:
+        Client::ignoreListManager()->requestAddIgnoreListItem(IgnoreListManager::SenderIgnore,
+                                                       action->text(),
+                                                       false, IgnoreListManager::SoftStrictness,
+                                                       IgnoreListManager::NetworkScope,
+                                                       ircUser->network()->networkName(), true);
+        break;
+      case NickIgnoreDomain:
+        Client::ignoreListManager()->requestAddIgnoreListItem(IgnoreListManager::SenderIgnore,
+                                                       action->text(),
+                                                       false, IgnoreListManager::SoftStrictness,
+                                                       IgnoreListManager::NetworkScope,
+                                                       ircUser->network()->networkName(), true);
+        break;
+      case NickIgnoreCustom:
+        // forward that to mainwin since we can access the settingspage only from there
+        emit showIgnoreList(ircUser->hostmask());
+        break;
+      case NickIgnoreToggleEnabled0:
+      case NickIgnoreToggleEnabled1:
+      case NickIgnoreToggleEnabled2:
+      case NickIgnoreToggleEnabled3:
+      case NickIgnoreToggleEnabled4:
+        Client::ignoreListManager()->requestToggleIgnoreRule(action->text());
+        break;
       default:
         qWarning() << "Unhandled nick action";
     }
index 3d91ef9..268e783 100644 (file)
@@ -88,6 +88,17 @@ public:
     NickKick = 0x0c0000,
     NickBan = 0x0d0000,
     NickKickBan = 0x0e0000,
+    NickIgnoreUser = 0x0f0000,
+    NickIgnoreHost = 0x100000,
+    NickIgnoreDomain = 0x200000,
+    NickIgnoreCustom = 0x300000,
+    // The next 5 types have stay together
+    // Don't change without reading ContextMenuActionProvider::addIgnoreMenu!
+    NickIgnoreToggleEnabled0 = 0x400000,
+    NickIgnoreToggleEnabled1 = 0x500000,
+    NickIgnoreToggleEnabled2 = 0x600000,
+    NickIgnoreToggleEnabled3 = 0x700000,
+    NickIgnoreToggleEnabled4 = 0x800000,
 
     // Actions that are handled externally
     // These emit a signal to the action requester, rather than being handled here
@@ -133,13 +144,13 @@ protected slots:
 
 signals:
   void showChannelList(NetworkId);
-  void showIgnoreList(NetworkId);
+  void showIgnoreList(QString);
 
 protected:
   virtual void handleNetworkAction(ActionType, QAction *);
   virtual void handleBufferAction(ActionType, QAction *);
   virtual void handleHideAction(ActionType, QAction *);
-  virtual void handleNickAction(ActionType, QAction *);
+  virtual void handleNickAction(ActionType, QAction *action);
   virtual void handleGeneralAction(ActionType, QAction *);
   virtual void handleExternalAction(ActionType, QAction *);