From f19fea582ace1d8f3dfe29c1096c48758079e56e Mon Sep 17 00:00:00 2001 From: Sebastian Goth Date: Sat, 12 Sep 2009 18:54:46 +0200 Subject: [PATCH 1/1] Provide a contextmenu for the ignore list This will not work without updating the core too :/ --- src/client/clientignorelistmanager.cpp | 30 ++++++- src/client/clientignorelistmanager.h | 13 +++ src/common/ignorelistmanager.cpp | 28 ++++-- src/common/ignorelistmanager.h | 42 +++++++-- src/core/coreignorelistmanager.h | 8 ++ src/qtui/mainwin.cpp | 9 ++ src/qtui/mainwin.h | 1 + src/qtui/settingspages/ignorelistmodel.cpp | 8 +- src/qtui/settingspages/ignorelistmodel.h | 1 + .../settingspages/ignorelistsettingspage.cpp | 73 ++++++++++----- .../settingspages/ignorelistsettingspage.h | 10 ++- src/uisupport/contextmenuactionprovider.cpp | 88 +++++++++++++++++++ src/uisupport/contextmenuactionprovider.h | 2 + src/uisupport/networkmodelcontroller.cpp | 41 ++++++++- src/uisupport/networkmodelcontroller.h | 15 +++- 15 files changed, 327 insertions(+), 42 deletions(-) diff --git a/src/client/clientignorelistmanager.cpp b/src/client/clientignorelistmanager.cpp index e54eeb76..f146313f 100644 --- a/src/client/clientignorelistmanager.cpp +++ b/src/client/clientignorelistmanager.cpp @@ -20,10 +20,38 @@ #include "clientignorelistmanager.h" +#include + 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 ClientIgnoreListManager::matchingRulesForHostmask(const QString &hostmask, const QString &network, const QString &channel) const { + QMap 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; } diff --git a/src/client/clientignorelistmanager.h b/src/client/clientignorelistmanager.h index eac7c721..51f02030 100644 --- a/src/client/clientignorelistmanager.h +++ b/src/client/clientignorelistmanager.h @@ -22,6 +22,7 @@ #define CLIENTIGNORELISTMANAGER_H #include "ignorelistmanager.h" +#include 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 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 diff --git a/src/common/ignorelistmanager.cpp b/src/common/ignorelistmanager.cpp index d6164b85..dfd9ae2d 100644 --- a/src/common/ignorelistmanager.cpp +++ b/src/common/ignorelistmanager.cpp @@ -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(type), ignoreRule, isRegEx, static_cast(strictness), + static_cast(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)) +} diff --git a/src/common/ignorelistmanager.h b/src/common/ignorelistmanager.h index 1d44b0b4..d6ab6eca 100644 --- a/src/common/ignorelistmanager.h +++ b/src/common/ignorelistmanager.h @@ -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 &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; }; diff --git a/src/core/coreignorelistmanager.h b/src/core/coreignorelistmanager.h index d455d2c3..e53124b9 100644 --- a/src/core/coreignorelistmanager.h +++ b/src/core/coreignorelistmanager.h @@ -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(); diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index 1f6d17e0..98ecdd38 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -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(dlg.currentPage())->editIgnoreRule(newRule); + dlg.exec(); +} + void MainWin::showCoreInfoDlg() { CoreInfoDlg(this).exec(); } diff --git a/src/qtui/mainwin.h b/src/qtui/mainwin.h index 361467aa..c22d32d2 100644 --- a/src/qtui/mainwin.h +++ b/src/qtui/mainwin.h @@ -123,6 +123,7 @@ class MainWin void showAwayLog(); void showSettingsDlg(); void showNotificationsDlg(); + void showIgnoreList(QString newRule = QString()); #ifdef HAVE_KDE void showShortcutsDlg(); #endif diff --git a/src/qtui/settingspages/ignorelistmodel.cpp b/src/qtui/settingspages/ignorelistmodel.cpp index ec09dec4..b6b44bf3 100644 --- a/src/qtui/settingspages/ignorelistmodel.cpp +++ b/src/qtui/settingspages/ignorelistmodel.cpp @@ -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); +} diff --git a/src/qtui/settingspages/ignorelistmodel.h b/src/qtui/settingspages/ignorelistmodel.h index de3eb061..f6a3eadf 100644 --- a/src/qtui/settingspages/ignorelistmodel.h +++ b/src/qtui/settingspages/ignorelistmodel.h @@ -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(); diff --git a/src/qtui/settingspages/ignorelistsettingspage.cpp b/src/qtui/settingspages/ignorelistsettingspage.cpp index 8ee11d40..61f08645 100644 --- a/src/qtui/settingspages/ignorelistsettingspage.cpp +++ b/src/qtui/settingspages/ignorelistsettingspage.cpp @@ -27,7 +27,7 @@ #include #include #include - +#include #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); } diff --git a/src/qtui/settingspages/ignorelistsettingspage.h b/src/qtui/settingspages/ignorelistsettingspage.h index 4e2e85c6..251018c4 100644 --- a/src/qtui/settingspages/ignorelistsettingspage.h +++ b/src/qtui/settingspages/ignorelistsettingspage.h @@ -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: diff --git a/src/uisupport/contextmenuactionprovider.cpp b/src/uisupport/contextmenuactionprovider.cpp index 84fa10bc..03c2de60 100644 --- a/src/uisupport/contextmenuactionprovider.cpp +++ b/src/uisupport/contextmenuactionprovider.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #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(index.data(NetworkModel::ItemTypeRole).toInt()); addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType); addAction(_nickCtcpMenuAction, menu); + + IrcUser *ircUser = qobject_cast(index.data(NetworkModel::IrcUserRole).value()); + if(ircUser) { + // ignoreliststuff + QString bufferName; + BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); + if(bufferInfo.type() == BufferInfo::ChannelBuffer) + bufferName = bufferInfo.bufferName(); + QMap 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 &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::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(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); +} diff --git a/src/uisupport/contextmenuactionprovider.h b/src/uisupport/contextmenuactionprovider.h index bdac641d..c6753fa6 100644 --- a/src/uisupport/contextmenuactionprovider.h +++ b/src/uisupport/contextmenuactionprovider.h @@ -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 &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 diff --git a/src/uisupport/networkmodelcontroller.cpp b/src/uisupport/networkmodelcontroller.cpp index 58db5617..cb882f81 100644 --- a/src/uisupport/networkmodelcontroller.cpp +++ b/src/uisupport/networkmodelcontroller.cpp @@ -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(); 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(index.data(NetworkModel::IrcUserRole).value()); + 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"; } diff --git a/src/uisupport/networkmodelcontroller.h b/src/uisupport/networkmodelcontroller.h index 3d91ef93..268e783a 100644 --- a/src/uisupport/networkmodelcontroller.h +++ b/src/uisupport/networkmodelcontroller.h @@ -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 *); -- 2.20.1