X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fcontextmenuactionprovider.cpp;h=e5837f6979551c8577cdcbb2ddfdd29975e78a81;hp=8ab622e8c0f01b46620c82ca9e8054d2e4f3ec89;hb=cc6e7c08709c4e761e2fd9c2e322751015497003;hpb=a540a0285feef171e16fd6225b0e045fc5fc52e4 diff --git a/src/uisupport/contextmenuactionprovider.cpp b/src/uisupport/contextmenuactionprovider.cpp index 8ab622e8..e5837f69 100644 --- a/src/uisupport/contextmenuactionprovider.cpp +++ b/src/uisupport/contextmenuactionprovider.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 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 * @@ -15,669 +15,494 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include "contextmenuactionprovider.h" + #include +#include #include #include -#include "contextmenuactionprovider.h" - #include "buffermodel.h" #include "buffersettings.h" -#include "iconloader.h" -#include "clientidentity.h" +#include "client.h" +#include "clientignorelistmanager.h" +#include "icon.h" #include "network.h" #include "util.h" -ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) -: QObject(parent), - _actionCollection(new ActionCollection(this)), - _messageFilter(0), - _receiver(0) +ContextMenuActionProvider::ContextMenuActionProvider(QObject* parent) + : NetworkModelController(parent) { - registerAction(NetworkConnect, SmallIcon("network-connect"), tr("Connect")); - registerAction(NetworkDisconnect, SmallIcon("network-disconnect"), tr("Disconnect")); - - registerAction(BufferJoin, tr("Join")); - registerAction(BufferPart, tr("Part")); - registerAction(BufferRemove, tr("Delete Buffer(s)...")); - registerAction(BufferSwitchTo, tr("Show Buffer")); - - registerAction(HideJoin, tr("Joins"), true); - registerAction(HidePart, tr("Parts"), true); - registerAction(HideQuit, tr("Quits"), true); - registerAction(HideNick, tr("Nick Changes"), true); - registerAction(HideMode, tr("Mode Changes"), true); - registerAction(HideDayChange, tr("Day Changes"), true); - registerAction(HideApplyToAll, tr("Set as Default...")); - registerAction(HideUseDefaults, tr("Use Defaults...")); - - registerAction(JoinChannel, tr("Join Channel...")); - - registerAction(NickQuery, tr("Start Query")); - registerAction(NickSwitchTo, tr("Show Query")); - registerAction(NickWhois, tr("Whois")); - - registerAction(NickCtcpVersion, tr("Version")); - registerAction(NickCtcpTime, tr("Time")); - registerAction(NickCtcpPing, tr("Ping")); - registerAction(NickCtcpFinger, tr("Finger")); - - registerAction(NickOp, tr("Give Operator Status")); - registerAction(NickDeop, tr("Take Operator Status")); - registerAction(NickVoice, tr("Give Voice")); - registerAction(NickDevoice, tr("Take Voice")); - registerAction(NickKick, tr("Kick From Channel")); - registerAction(NickBan, tr("Ban From Channel")); - registerAction(NickKickBan, tr("Kick && Ban")); - - registerAction(HideBufferTemporarily, tr("Hide Buffer(s) Temporarily")); - registerAction(HideBufferPermanently, tr("Hide Buffer(s) Permanently")); - registerAction(ShowChannelList, SmallIcon("format-list-unordered"), tr("Show Channel List")); - registerAction(ShowIgnoreList, tr("Show Ignore List")); - - connect(_actionCollection, SIGNAL(actionTriggered(QAction *)), SLOT(actionTriggered(QAction *))); - - QMenu *hideEventsMenu = new QMenu(); - hideEventsMenu->addAction(action(HideJoin)); - hideEventsMenu->addAction(action(HidePart)); - hideEventsMenu->addAction(action(HideQuit)); - hideEventsMenu->addAction(action(HideNick)); - hideEventsMenu->addAction(action(HideMode)); - hideEventsMenu->addAction(action(HideDayChange)); - hideEventsMenu->addSeparator(); - hideEventsMenu->addAction(action(HideApplyToAll)); - hideEventsMenu->addAction(action(HideUseDefaults)); - _hideEventsMenuAction = new Action(tr("Hide Events"), 0); - _hideEventsMenuAction->setMenu(hideEventsMenu); - - QMenu *nickCtcpMenu = new QMenu(); - nickCtcpMenu->addAction(action(NickCtcpPing)); - nickCtcpMenu->addAction(action(NickCtcpVersion)); - nickCtcpMenu->addAction(action(NickCtcpTime)); - nickCtcpMenu->addAction(action(NickCtcpFinger)); - _nickCtcpMenuAction = new Action(tr("CTCP"), 0); - _nickCtcpMenuAction->setMenu(nickCtcpMenu); - - QMenu *nickModeMenu = new QMenu(); - nickModeMenu->addAction(action(NickOp)); - nickModeMenu->addAction(action(NickDeop)); - nickModeMenu->addAction(action(NickVoice)); - nickModeMenu->addAction(action(NickDevoice)); - nickModeMenu->addSeparator(); - nickModeMenu->addAction(action(NickKick)); - nickModeMenu->addAction(action(NickBan)); - nickModeMenu->addAction(action(NickKickBan)); - _nickModeMenuAction = new Action(tr("Actions"), 0); - _nickModeMenuAction->setMenu(nickModeMenu); -} - -ContextMenuActionProvider::~ContextMenuActionProvider() { - _hideEventsMenuAction->menu()->deleteLater(); - _hideEventsMenuAction->deleteLater(); - _nickCtcpMenuAction->menu()->deleteLater(); - _nickCtcpMenuAction->deleteLater(); - _nickModeMenuAction->menu()->deleteLater(); - _nickModeMenuAction->deleteLater(); -} - -void ContextMenuActionProvider::registerAction(ActionType type, const QString &text, bool checkable) { - registerAction(type, QPixmap(), text, checkable); -} - -void ContextMenuActionProvider::registerAction(ActionType type, const QPixmap &icon, const QString &text, bool checkable) { - Action *act; - if(icon.isNull()) - act = new Action(text, this); - else - act = new Action(icon, text, this); - - act->setCheckable(checkable); - act->setData(type); - - _actionCollection->addAction(QString::number(type, 16), act); - _actionByType[type] = act; -} - -void ContextMenuActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) { - if(!bufId.isValid()) - return; - addActions(menu, Client::networkModel()->bufferIndex(bufId), receiver, method); + registerAction(NetworkConnect, icon::get("network-connect"), tr("Connect")); + registerAction(NetworkDisconnect, icon::get("network-disconnect"), tr("Disconnect")); + + registerAction(BufferJoin, icon::get("irc-join-channel"), tr("Join")); + registerAction(BufferPart, icon::get("irc-close-channel"), tr("Part")); + registerAction(BufferRemove, tr("Delete Chat(s)...")); + registerAction(BufferSwitchTo, tr("Go to Chat")); + + registerAction(HideJoinPartQuit, tr("Joins/Parts/Quits")); + registerAction(HideJoin, tr("Joins"), true); + registerAction(HidePart, tr("Parts"), true); + registerAction(HideQuit, tr("Quits"), true); + registerAction(HideNick, tr("Nick Changes"), true); + registerAction(HideMode, tr("Mode Changes"), true); + registerAction(HideDayChange, tr("Day Changes"), true); + registerAction(HideTopic, tr("Topic Changes"), true); + registerAction(HideApplyToAll, tr("Set as Default...")); + registerAction(HideUseDefaults, tr("Use Defaults...")); + + registerAction(JoinChannel, icon::get("irc-join-channel"), tr("Join Channel...")); + + registerAction(NickQuery, tr("Start Query")); + registerAction(NickSwitchTo, tr("Show Query")); + registerAction(NickWhois, tr("Whois")); + + registerAction(NickCtcpVersion, tr("Version")); + registerAction(NickCtcpTime, tr("Time")); + registerAction(NickCtcpPing, tr("Ping")); + registerAction(NickCtcpClientinfo, tr("Client info")); + 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, icon::get("irc-operator"), tr("Give Operator Status")); + registerAction(NickDeop, icon::get("irc-remove-operator"), tr("Take Operator Status")); + registerAction(NickHalfop, icon::get("irc-voice"), tr("Give Half-Operator Status")); + registerAction(NickDehalfop, icon::get("irc-unvoice"), tr("Take Half-Operator Status")); + registerAction(NickVoice, icon::get("irc-voice"), tr("Give Voice")); + registerAction(NickDevoice, icon::get("irc-unvoice"), tr("Take Voice")); + registerAction(NickKick, icon::get("im-kick-user"), tr("Kick From Channel")); + registerAction(NickBan, icon::get("im-ban-user"), tr("Ban From Channel")); + registerAction(NickKickBan, icon::get("im-ban-kick-user"), tr("Kick && Ban")); + + registerAction(HideBufferTemporarily, tr("Hide Chat(s) Temporarily")); + registerAction(HideBufferPermanently, tr("Hide Chat(s) Permanently")); + registerAction(ShowChannelList, tr("Show Channel List")); + registerAction(ShowNetworkConfig, tr("Configure")); + registerAction(ShowIgnoreList, tr("Show Ignore List")); + + auto* hideEventsMenu = new QMenu(); + hideEventsMenu->addAction(action(HideJoinPartQuit)); + hideEventsMenu->addSeparator(); + hideEventsMenu->addAction(action(HideJoin)); + hideEventsMenu->addAction(action(HidePart)); + hideEventsMenu->addAction(action(HideQuit)); + hideEventsMenu->addAction(action(HideNick)); + hideEventsMenu->addAction(action(HideMode)); + hideEventsMenu->addAction(action(HideTopic)); + hideEventsMenu->addAction(action(HideDayChange)); + hideEventsMenu->addSeparator(); + hideEventsMenu->addAction(action(HideApplyToAll)); + hideEventsMenu->addAction(action(HideUseDefaults)); + _hideEventsMenuAction = new Action(tr("Hide Events"), nullptr); + _hideEventsMenuAction->setMenu(hideEventsMenu); + + auto* nickCtcpMenu = new QMenu(); + nickCtcpMenu->addAction(action(NickCtcpPing)); + nickCtcpMenu->addAction(action(NickCtcpVersion)); + nickCtcpMenu->addAction(action(NickCtcpTime)); + nickCtcpMenu->addAction(action(NickCtcpClientinfo)); + _nickCtcpMenuAction = new Action(tr("CTCP"), nullptr); + _nickCtcpMenuAction->setMenu(nickCtcpMenu); + + auto* nickModeMenu = new QMenu(); + nickModeMenu->addAction(action(NickOp)); + nickModeMenu->addAction(action(NickDeop)); + // this is where the halfops will be placed if available + nickModeMenu->addAction(action(NickHalfop)); + nickModeMenu->addAction(action(NickDehalfop)); + nickModeMenu->addAction(action(NickVoice)); + nickModeMenu->addAction(action(NickDevoice)); + nickModeMenu->addSeparator(); + nickModeMenu->addAction(action(NickKick)); + nickModeMenu->addAction(action(NickBan)); + nickModeMenu->addAction(action(NickKickBan)); + _nickModeMenuAction = new Action(tr("Actions"), nullptr); + _nickModeMenuAction->setMenu(nickModeMenu); + + auto* ignoreMenu = new QMenu(); + _nickIgnoreMenuAction = new Action(tr("Ignore"), nullptr); + _nickIgnoreMenuAction->setMenu(ignoreMenu); + + // These are disabled actions used as descriptions + // They don't need any of the Action fancyness so we use plain QActions + _ignoreDescriptions << new QAction(tr("Add Ignore Rule"), this); + _ignoreDescriptions << new QAction(tr("Existing Rules"), this); + foreach (QAction* act, _ignoreDescriptions) + act->setEnabled(false); +} + +ContextMenuActionProvider::~ContextMenuActionProvider() +{ + _hideEventsMenuAction->menu()->deleteLater(); + _hideEventsMenuAction->deleteLater(); + _nickCtcpMenuAction->menu()->deleteLater(); + _nickCtcpMenuAction->deleteLater(); + _nickModeMenuAction->menu()->deleteLater(); + _nickModeMenuAction->deleteLater(); + _nickIgnoreMenuAction->menu()->deleteLater(); + _nickIgnoreMenuAction->deleteLater(); + qDeleteAll(_ignoreDescriptions); + _ignoreDescriptions.clear(); +} + +void ContextMenuActionProvider::addActions(QMenu* menu, BufferId bufId, ActionSlot slot) +{ + if (!bufId.isValid()) + return; + addActions(menu, Client::networkModel()->bufferIndex(bufId), std::move(slot)); } -void ContextMenuActionProvider::addActions(QMenu *menu, const QModelIndex &index, QObject *receiver, const char *method, bool isCustomBufferView) { - if(!index.isValid()) - return; - addActions(menu, QList() << index, 0, QString(), receiver, method, isCustomBufferView); +void ContextMenuActionProvider::addActions(QMenu* menu, const QModelIndex& index, ActionSlot slot, bool isCustomBufferView) +{ + if (!index.isValid()) + return; + addActions(menu, QList() << index, nullptr, QString(), std::move(slot), isCustomBufferView); } -void ContextMenuActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, QObject *receiver, const char *slot) { - addActions(menu, filter, msgBuffer, QString(), receiver, slot); +void ContextMenuActionProvider::addActions(QMenu* menu, MessageFilter* filter, BufferId msgBuffer, ActionSlot slot) +{ + addActions(menu, filter, msgBuffer, QString(), std::move(slot)); } -void ContextMenuActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, const QString &chanOrNick, QObject *receiver, const char *method) { - if(!filter) - return; - addActions(menu, QList() << Client::networkModel()->bufferIndex(msgBuffer), filter, chanOrNick, receiver, method, false); +void ContextMenuActionProvider::addActions(QMenu* menu, MessageFilter* filter, BufferId msgBuffer, const QString& chanOrNick, ActionSlot slot) +{ + if (!filter) + return; + addActions(menu, QList() << Client::networkModel()->bufferIndex(msgBuffer), filter, chanOrNick, std::move(slot), false); } -void ContextMenuActionProvider::addActions(QMenu *menu, const QList &indexList, QObject *receiver, const char *method, bool isCustomBufferView) { - addActions(menu, indexList, 0, QString(), receiver, method, isCustomBufferView); +void ContextMenuActionProvider::addActions(QMenu* menu, const QList& indexList, ActionSlot slot, bool isCustomBufferView) +{ + addActions(menu, indexList, nullptr, QString(), std::move(slot), isCustomBufferView); } // add a list of actions sensible for the current item(s) -void ContextMenuActionProvider::addActions(QMenu *menu, - const QList &indexList, - MessageFilter *filter, - const QString &contextItem, - QObject *receiver, - const char *method, - bool isCustomBufferView) +void ContextMenuActionProvider::addActions(QMenu* menu, + const QList& indexList_, + MessageFilter* filter_, + const QString& contextItem_, + ActionSlot actionSlot, + bool isCustomBufferView) { - if(!indexList.count()) - return; - - _indexList = indexList; - _messageFilter = filter; - _contextItem = contextItem; - _receiver = receiver; - _method = method; - - if(!_messageFilter) { - // this means we are in a BufferView (or NickView) rather than a ChatView - - // first index in list determines the menu type (just in case we have both buffers and networks selected, for example) - QModelIndex index = _indexList.at(0); - NetworkModel::ItemType itemType = static_cast(index.data(NetworkModel::ItemTypeRole).toInt()); - - switch(itemType) { - case NetworkModel::NetworkItemType: - addNetworkItemActions(menu, index); - break; - case NetworkModel::BufferItemType: - addBufferItemActions(menu, index, isCustomBufferView); - break; - case NetworkModel::IrcUserItemType: - addIrcUserActions(menu, index); - break; - default: + if (!indexList_.count()) return; + setIndexList(indexList_); + setMessageFilter(filter_); + setContextItem(contextItem_); + setSlot(std::move(actionSlot)); + + if (!messageFilter()) { + // this means we are in a BufferView (or NickView) rather than a ChatView + + // first index in list determines the menu type (just in case we have both buffers and networks selected, for example) + QModelIndex index = indexList().at(0); + NetworkModel::ItemType itemType = static_cast(index.data(NetworkModel::ItemTypeRole).toInt()); + + switch (itemType) { + case NetworkModel::NetworkItemType: + addNetworkItemActions(menu, index); + break; + case NetworkModel::BufferItemType: + addBufferItemActions(menu, index, isCustomBufferView); + break; + case NetworkModel::IrcUserItemType: + addIrcUserActions(menu, index); + break; + default: + return; + } } - } else { - // ChatView actions - if(_contextItem.isEmpty()) { - // a) query buffer: handle like ircuser - // b) general chatview: handle like channel iff it displays a single buffer - // NOTE stuff breaks probably with merged buffers, need to rework a lot around here then - if(_messageFilter->containedBuffers().count() == 1) { - // we can handle this like a single bufferItem - QModelIndex index = Client::networkModel()->bufferIndex(_messageFilter->containedBuffers().values().at(0)); - _indexList = QList() << index; - addBufferItemActions(menu, index); - return; - } else { - // TODO: actions for merged buffers... _indexList contains the index of the message we clicked on - - } - } else { - // context item = chan or nick, _indexList = buf where the msg clicked on originated - if(isChannelName(_contextItem)) { - QModelIndex msgIdx = _indexList.at(0); - if(!msgIdx.isValid()) - return; - NetworkId networkId = msgIdx.data(NetworkModel::NetworkIdRole).value(); - BufferId bufId = Client::networkModel()->bufferId(networkId, _contextItem); - if(bufId.isValid()) { - QModelIndex targetIdx = Client::networkModel()->bufferIndex(bufId); - _indexList = QList() << targetIdx; - addAction(BufferJoin, menu, targetIdx, InactiveState); - addAction(BufferSwitchTo, menu, targetIdx, ActiveState); - } else - addAction(JoinChannel, menu); - } else { - // TODO: actions for a nick - } + else { + // ChatView actions + if (contextItem().isEmpty()) { + // a) query buffer: handle like ircuser + // b) general chatview: handle like channel iff it displays a single buffer + // NOTE stuff breaks probably with merged buffers, need to rework a lot around here then + if (messageFilter()->containedBuffers().count() == 1) { + // we can handle this like a single bufferItem + QModelIndex index = Client::networkModel()->bufferIndex(messageFilter()->containedBuffers().values().at(0)); + setIndexList(index); + addBufferItemActions(menu, index); + return; + } + else { + // TODO: actions for merged buffers... _indexList contains the index of the message we clicked on + } + } + else { + // context item = chan or nick, _indexList = buf where the msg clicked on originated + if (isChannelName(contextItem())) { + QModelIndex msgIdx = indexList().at(0); + if (!msgIdx.isValid()) + return; + NetworkId networkId = msgIdx.data(NetworkModel::NetworkIdRole).value(); + BufferId bufId = Client::networkModel()->bufferId(networkId, contextItem()); + if (bufId.isValid()) { + QModelIndex targetIdx = Client::networkModel()->bufferIndex(bufId); + setIndexList(targetIdx); + addAction(BufferJoin, menu, targetIdx, InactiveState); + addAction(BufferSwitchTo, menu, targetIdx, ActiveState); + } + else + addAction(JoinChannel, menu); + } + else { + // TODO: actions for a nick + } + } } - } } -void ContextMenuActionProvider::addNetworkItemActions(QMenu *menu, const QModelIndex &index) { - NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value(); - if(!networkId.isValid()) - return; - const Network *network = Client::network(networkId); - Q_CHECK_PTR(network); - if(!network) - return; - - addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected); - addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected); - menu->addSeparator(); - addAction(ShowChannelList, menu, index, ActiveState); - addAction(JoinChannel, menu, index, ActiveState); +void ContextMenuActionProvider::addNetworkItemActions(QMenu* menu, const QModelIndex& index) +{ + NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value(); + if (!networkId.isValid()) + return; + const Network* network = Client::network(networkId); + Q_CHECK_PTR(network); + if (!network) + return; + addAction(ShowNetworkConfig, menu, index); + menu->addSeparator(); + addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected); + addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected); + menu->addSeparator(); + addAction(ShowChannelList, menu, index, ActiveState); + addAction(JoinChannel, menu, index, ActiveState); } -void ContextMenuActionProvider::addBufferItemActions(QMenu *menu, const QModelIndex &index, bool isCustomBufferView) { - BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); +void ContextMenuActionProvider::addBufferItemActions(QMenu* menu, const QModelIndex& index, bool isCustomBufferView) +{ + BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); - menu->addSeparator(); - switch(bufferInfo.type()) { + menu->addSeparator(); + switch (bufferInfo.type()) { case BufferInfo::ChannelBuffer: - addAction(BufferJoin, menu, index, InactiveState); - addAction(BufferPart, menu, index, ActiveState); - menu->addSeparator(); - addHideEventsMenu(menu, bufferInfo.bufferId()); - menu->addSeparator(); - addAction(HideBufferTemporarily, menu, isCustomBufferView); - addAction(HideBufferPermanently, menu, isCustomBufferView); - addAction(BufferRemove, menu, index, InactiveState); - break; - - case BufferInfo::QueryBuffer: - { - //IrcUser *ircUser = qobject_cast(index.data(NetworkModel::IrcUserRole).value()); - //if(ircUser) { + addAction(BufferJoin, menu, index, InactiveState); + addAction(BufferPart, menu, index, ActiveState); + menu->addSeparator(); + addHideEventsMenu(menu, bufferInfo.bufferId()); + menu->addSeparator(); + addAction(HideBufferTemporarily, menu, isCustomBufferView); + addAction(HideBufferPermanently, menu, isCustomBufferView); + addAction(BufferRemove, menu, index, InactiveState); + break; + + case BufferInfo::QueryBuffer: { + // IrcUser *ircUser = qobject_cast(index.data(NetworkModel::IrcUserRole).value()); + // if(ircUser) { addIrcUserActions(menu, index); menu->addSeparator(); - //} - addHideEventsMenu(menu, bufferInfo.bufferId()); - menu->addSeparator(); - addAction(HideBufferTemporarily, menu, isCustomBufferView); - addAction(HideBufferPermanently, menu, isCustomBufferView); - addAction(BufferRemove, menu, index); - break; + //} + addHideEventsMenu(menu, bufferInfo.bufferId()); + menu->addSeparator(); + addAction(HideBufferTemporarily, menu, isCustomBufferView); + addAction(HideBufferPermanently, menu, isCustomBufferView); + addAction(BufferRemove, menu, index); + break; } default: - addAction(HideBufferTemporarily, menu, isCustomBufferView); - addAction(HideBufferPermanently, menu, isCustomBufferView); - } -} - -void ContextMenuActionProvider::addIrcUserActions(QMenu *menu, const QModelIndex &index) { - // this can be called: a) as a nicklist context menu (index has IrcUserItemType) - // b) as a query buffer context menu (index has BufferItemType and is a QueryBufferItem) - // c) right-click in a query chatview (same as b), index will be the corresponding QueryBufferItem) - // d) right-click on some nickname (_contextItem will be non-null, _filter -> chatview, index -> message buffer) - - if(_contextItem.isNull()) { - // cases a, b, c - bool haveQuery = _indexList.count() == 1 && findQueryBuffer(index).isValid(); - NetworkModel::ItemType itemType = static_cast(index.data(NetworkModel::ItemTypeRole).toInt()); - addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType); - addAction(_nickCtcpMenuAction, menu); - menu->addSeparator(); - addAction(NickQuery, menu, itemType == NetworkModel::IrcUserItemType && !haveQuery && _indexList.count() == 1); - addAction(NickSwitchTo, menu, itemType == NetworkModel::IrcUserItemType && haveQuery); - menu->addSeparator(); - addAction(NickWhois, menu, true); - - } else if(!_contextItem.isEmpty() && _messageFilter) { - // case d - // TODO - - } -} - -/******** Helper Functions ***********************************************************************/ - -bool ContextMenuActionProvider::checkRequirements(const QModelIndex &index, ItemActiveStates requiredActiveState) { - if(!index.isValid()) - return false; - - ItemActiveStates isActive = index.data(NetworkModel::ItemActiveRole).toBool() - ? ActiveState - : InactiveState; - - if(!(isActive & requiredActiveState)) - return false; - - return true; -} - -Action * ContextMenuActionProvider::addAction(ActionType type , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) { - return addAction(action(type), menu, checkRequirements(index, requiredActiveState)); -} - -Action * ContextMenuActionProvider::addAction(Action *action , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) { - return addAction(action, menu, checkRequirements(index, requiredActiveState)); -} - -Action * ContextMenuActionProvider::addAction(ActionType type , QMenu *menu, bool condition) { - return addAction(action(type), menu, condition); -} - -Action * ContextMenuActionProvider::addAction(Action *action , QMenu *menu, bool condition) { - if(condition) { - menu->addAction(action); - action->setVisible(true); - } else { - action->setVisible(false); - } - return action; -} - -void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, BufferId bufferId) { - if(BufferSettings(bufferId).hasFilter()) - addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter()); - else - addHideEventsMenu(menu); -} - -void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, MessageFilter *msgFilter) { - if(BufferSettings(msgFilter->idString()).hasFilter()) - addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter()); - else - addHideEventsMenu(menu); + addAction(HideBufferTemporarily, menu, isCustomBufferView); + addAction(HideBufferPermanently, menu, isCustomBufferView); + } } -void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, int filter) { - action(HideApplyToAll)->setEnabled(filter != -1); - action(HideUseDefaults)->setEnabled(filter != -1); - if(filter == -1) - filter = BufferSettings().messageFilter(); - - action(HideJoin)->setChecked(filter & Message::Join); - action(HidePart)->setChecked(filter & Message::Part); - action(HideQuit)->setChecked(filter & Message::Quit); - action(HideNick)->setChecked(filter & Message::Nick); - action(HideMode)->setChecked(filter & Message::Mode); - action(HideDayChange)->setChecked(filter & Message::DayChange); - - menu->addAction(_hideEventsMenuAction); +void ContextMenuActionProvider::addIrcUserActions(QMenu* menu, const QModelIndex& index) +{ + // this can be called: a) as a nicklist context menu (index has IrcUserItemType) + // b) as a query buffer context menu (index has BufferItemType and is a QueryBufferItem) + // c) right-click in a query chatview (same as b), index will be the corresponding QueryBufferItem) + // d) right-click on some nickname (_contextItem will be non-null, _filter -> chatview, index -> message buffer) + + if (contextItem().isNull()) { + // cases a, b, c + bool haveQuery = indexList().count() == 1 && findQueryBuffer(index).isValid(); + NetworkModel::ItemType itemType = static_cast(index.data(NetworkModel::ItemTypeRole).toInt()); + addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType); + addAction(_nickCtcpMenuAction, menu); + + auto* ircUser = qobject_cast(index.data(NetworkModel::IrcUserRole).value()); + if (ircUser) { + Network* network = ircUser->network(); + // only show entries for usermode +h if server supports it + if (network && network->prefixModes().contains('h')) { + action(NickHalfop)->setVisible(true); + action(NickDehalfop)->setVisible(true); + } + else { + action(NickHalfop)->setVisible(false); + action(NickDehalfop)->setVisible(false); + } + // 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); + menu->addSeparator(); + addAction(NickWhois, menu, true); + } + else if (!contextItem().isEmpty() && messageFilter()) { + // case d + // TODO + } } -QString ContextMenuActionProvider::nickName(const QModelIndex &index) const { - IrcUser *ircUser = qobject_cast(index.data(NetworkModel::IrcUserRole).value()); - if(ircUser) - return ircUser->nick(); - - BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); - if(!bufferInfo.isValid()) - return QString(); - if(!bufferInfo.type() == BufferInfo::QueryBuffer) - return QString(); - - return bufferInfo.bufferName(); // FIXME this might break with merged queries maybe +Action* ContextMenuActionProvider::addAction(ActionType type, QMenu* menu, const QModelIndex& index, ItemActiveStates requiredActiveState) +{ + return addAction(action(type), menu, checkRequirements(index, requiredActiveState)); } -BufferId ContextMenuActionProvider::findQueryBuffer(const QModelIndex &index, const QString &predefinedNick) const { - NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value(); - if(!networkId.isValid()) - return BufferId(); - - QString nick = predefinedNick.isEmpty() ? nickName(index) : predefinedNick; - if(nick.isEmpty()) - return BufferId(); - - return findQueryBuffer(networkId, nick); +Action* ContextMenuActionProvider::addAction(Action* action, QMenu* menu, const QModelIndex& index, ItemActiveStates requiredActiveState) +{ + return addAction(action, menu, checkRequirements(index, requiredActiveState)); } -BufferId ContextMenuActionProvider::findQueryBuffer(NetworkId networkId, const QString &nick) const { - return Client::networkModel()->bufferId(networkId, nick); +Action* ContextMenuActionProvider::addAction(ActionType type, QMenu* menu, bool condition) +{ + return addAction(action(type), menu, condition); } -void ContextMenuActionProvider::handleExternalAction(ActionType type, QAction *action) { - Q_UNUSED(type); - if(_receiver && _method) { - if(!QMetaObject::invokeMethod(_receiver, _method, Q_ARG(QAction *, action))) - qWarning() << "NetworkModelActionProvider::handleExternalAction(): Could not invoke slot" << _receiver << _method; - } +Action* ContextMenuActionProvider::addAction(Action* action, QMenu* menu, bool condition) +{ + if (condition) { + menu->addAction(action); + action->setVisible(true); + } + else { + action->setVisible(false); + } + return action; } -/******** Handle Actions *************************************************************************/ - -void ContextMenuActionProvider::actionTriggered(QAction *action) { - ActionType type = (ActionType)action->data().toInt(); - if(type > 0) { - if(type & NetworkMask) - handleNetworkAction(type, action); - else if(type & BufferMask) - handleBufferAction(type, action); - else if(type & HideMask) - handleHideAction(type, action); - else if(type & GeneralMask) - handleGeneralAction(type, action); - else if(type & NickMask) - handleNickAction(type, action); - else if(type & ExternalMask) - handleExternalAction(type, action); +void ContextMenuActionProvider::addHideEventsMenu(QMenu* menu, BufferId bufferId) +{ + if (BufferSettings(bufferId).hasFilter()) + addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter()); else - qWarning() << "NetworkModelActionProvider::actionTriggered(): Unhandled action!"; - } - _indexList.clear(); - _messageFilter = 0; - _receiver = 0; + addHideEventsMenu(menu); } -void ContextMenuActionProvider::handleNetworkAction(ActionType type, QAction *) { - if(!_indexList.count()) - return; - const Network *network = Client::network(_indexList.at(0).data(NetworkModel::NetworkIdRole).value()); - Q_CHECK_PTR(network); - if(!network) - return; - - switch(type) { - case NetworkConnect: - network->requestConnect(); - break; - case NetworkDisconnect: - network->requestDisconnect(); - break; - default: - break; - } +void ContextMenuActionProvider::addHideEventsMenu(QMenu* menu, MessageFilter* msgFilter) +{ + if (BufferSettings(msgFilter->idString()).hasFilter()) + addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter()); + else + addHideEventsMenu(menu); } -void ContextMenuActionProvider::handleBufferAction(ActionType type, QAction *) { - if(type == BufferRemove) { - removeBuffers(_indexList); - } else { - - foreach(QModelIndex index, _indexList) { - BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); - if(!bufferInfo.isValid()) - continue; - - switch(type) { - case BufferJoin: - Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName())); - break; - case BufferPart: - { - QString reason = Client::identity(Client::network(bufferInfo.networkId())->identity())->partReason(); - Client::userInput(bufferInfo, QString("/PART %1").arg(reason)); - break; - } - case BufferSwitchTo: - Client::bufferModel()->switchToBuffer(bufferInfo.bufferId()); - break; - default: - break; - } - } - } -} +void ContextMenuActionProvider::addHideEventsMenu(QMenu* menu, int filter) +{ + action(HideApplyToAll)->setEnabled(filter != -1); + action(HideUseDefaults)->setEnabled(filter != -1); + if (filter == -1) + filter = BufferSettings().messageFilter(); -void ContextMenuActionProvider::removeBuffers(const QModelIndexList &indexList) { - QList inactive; - foreach(QModelIndex index, indexList) { - BufferInfo info = index.data(NetworkModel::BufferInfoRole).value(); - if(info.isValid()) { - if(info.type() == BufferInfo::QueryBuffer - || (info.type() == BufferInfo::ChannelBuffer && !index.data(NetworkModel::ItemActiveRole).toBool())) - inactive << info; - } - } - QString msg; - if(inactive.count()) { - msg = tr("Do you want to delete the following buffer(s) permanently?", 0, inactive.count()); - msg += "
    "; - foreach(BufferInfo info, inactive) - msg += QString("
  • %1
  • ").arg(info.bufferName()); - msg += "
"; - msg += tr("Note: This will delete all related data, including all backlog data, from the core's database and cannot be undone."); - if(inactive.count() != indexList.count()) - msg += tr("
Active channel buffers cannot be deleted, please part the channel first."); - - if(QMessageBox::question(0, tr("Remove buffers permanently?"), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) { - foreach(BufferInfo info, inactive) - Client::removeBuffer(info.bufferId()); - } - } -} + action(HideJoin)->setChecked(filter & Message::Join); + action(HidePart)->setChecked(filter & Message::Part); + action(HideQuit)->setChecked(filter & Message::Quit); + action(HideNick)->setChecked(filter & Message::Nick); + action(HideMode)->setChecked(filter & Message::Mode); + action(HideDayChange)->setChecked(filter & Message::DayChange); + action(HideTopic)->setChecked(filter & Message::Topic); -void ContextMenuActionProvider::handleHideAction(ActionType type, QAction *action) { - Q_UNUSED(action) - - int filter = 0; - if(ContextMenuActionProvider::action(HideJoin)->isChecked()) - filter |= Message::Join; - if(ContextMenuActionProvider::action(HidePart)->isChecked()) - filter |= Message::Part; - if(ContextMenuActionProvider::action(HideQuit)->isChecked()) - filter |= Message::Quit; - if(ContextMenuActionProvider::action(HideNick)->isChecked()) - filter |= Message::Nick; - if(ContextMenuActionProvider::action(HideMode)->isChecked()) - filter |= Message::Mode; - if(ContextMenuActionProvider::action(HideDayChange)->isChecked()) - filter |= Message::DayChange; - - switch(type) { - case HideJoin: - case HidePart: - case HideQuit: - case HideNick: - case HideMode: - case HideDayChange: - if(_messageFilter) - BufferSettings(_messageFilter->idString()).setMessageFilter(filter); - else { - foreach(QModelIndex index, _indexList) { - BufferId bufferId = index.data(NetworkModel::BufferIdRole).value(); - if(!bufferId.isValid()) - continue; - BufferSettings(bufferId).setMessageFilter(filter); - } - } - return; - case HideApplyToAll: - BufferSettings().setMessageFilter(filter); - case HideUseDefaults: - if(_messageFilter) - BufferSettings(_messageFilter->idString()).removeFilter(); - else { - foreach(QModelIndex index, _indexList) { - BufferId bufferId = index.data(NetworkModel::BufferIdRole).value(); - if(!bufferId.isValid()) - continue; - BufferSettings(bufferId).removeFilter(); - } - } - return; - default: - return; - }; + menu->addAction(_hideEventsMenuAction); } -void ContextMenuActionProvider::handleGeneralAction(ActionType type, QAction *action) { - Q_UNUSED(action) - - if(!_indexList.count()) - return; - NetworkId networkId = _indexList.at(0).data(NetworkModel::NetworkIdRole).value(); - if(!networkId.isValid()) - return; - - switch(type) { - case JoinChannel: { - QString channelName = _contextItem; - if(channelName.isEmpty()) { - bool ok; - channelName = QInputDialog::getText(0, tr("Join Channel"), tr("Input channel name:"), QLineEdit::Normal, QString(), &ok); - if(!ok) - return; - } - if(!channelName.isEmpty()) { - Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId), QString("/JOIN %1").arg(channelName)); - } - break; +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(R"((\.[^.]+\.\w+\D)$)"); + 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(); + + // add "Add Ignore Rule" description + ignoreMenu->addAction(_ignoreDescriptions.at(0)); + + if (haveWhoData) { + QString text; + text = QString("*!%1@%2").arg(ident, host); + action(NickIgnoreUser)->setText(text); + action(NickIgnoreUser)->setProperty("ignoreRule", text); + + text = QString("*!*@%1").arg(host); + action(NickIgnoreHost)->setText(text); + action(NickIgnoreHost)->setProperty("ignoreRule", text); + + text = domain.at(0) == '.' ? QString("*!%1@*%2").arg(ident, domain) : QString("*!%1@%2").arg(ident, domain); + + action(NickIgnoreDomain)->setText(text); + action(NickIgnoreDomain)->setProperty("ignoreRule", text); + + if (!ignoreMap.contains(action(NickIgnoreUser)->property("ignoreRule").toString())) + ignoreMenu->addAction(action(NickIgnoreUser)); + if (!ignoreMap.contains(action(NickIgnoreHost)->property("ignoreRule").toString())) + ignoreMenu->addAction(action(NickIgnoreHost)); + // we only add that NickIgnoreDomain if it isn't the same as NickIgnoreUser + // as happens with @foobar.com hostmasks and ips + if (!ignoreMap.contains(action(NickIgnoreDomain)->property("ignoreRule").toString()) + && action(NickIgnoreUser)->property("ignoreRule").toString() != action(NickIgnoreDomain)->property("ignoreRule").toString()) + ignoreMenu->addAction(action(NickIgnoreDomain)); } - case ShowChannelList: - emit showChannelList(networkId); - break; - case ShowIgnoreList: - emit showIgnoreList(networkId); - break; - default: - break; - } -} -void ContextMenuActionProvider::handleNickAction(ActionType type, QAction *) { - foreach(QModelIndex index, _indexList) { - NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value(); - if(!networkId.isValid()) - continue; - QString nick = nickName(index); - if(nick.isEmpty()) - continue; - BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value(); - if(!bufferInfo.isValid()) - continue; - - switch(type) { - case NickWhois: - Client::userInput(bufferInfo, QString("/WHOIS %1 %1").arg(nick)); - break; - case NickCtcpVersion: - Client::userInput(bufferInfo, QString("/CTCP %1 VERSION").arg(nick)); - break; - case NickCtcpPing: - Client::userInput(bufferInfo, QString("/CTCP %1 PING").arg(nick)); - break; - case NickCtcpTime: - Client::userInput(bufferInfo, QString("/CTCP %1 TIME").arg(nick)); - break; - case NickCtcpFinger: - Client::userInput(bufferInfo, QString("/CTCP %1 FINGER").arg(nick)); - break; - case NickOp: - Client::userInput(bufferInfo, QString("/OP %1").arg(nick)); - break; - case NickDeop: - Client::userInput(bufferInfo, QString("/DEOP %1").arg(nick)); - break; - case NickVoice: - Client::userInput(bufferInfo, QString("/VOICE %1").arg(nick)); - break; - case NickDevoice: - Client::userInput(bufferInfo, QString("/DEVOICE %1").arg(nick)); - break; - case NickKick: - Client::userInput(bufferInfo, QString("/KICK %1").arg(nick)); - break; - case NickBan: - Client::userInput(bufferInfo, QString("/BAN %1").arg(nick)); - break; - case NickKickBan: - Client::userInput(bufferInfo, QString("/BAN %1").arg(nick)); - Client::userInput(bufferInfo, QString("/KICK %1").arg(nick)); - break; - case NickSwitchTo: - Client::bufferModel()->switchToBuffer(findQueryBuffer(networkId, nick)); - break; - case NickQuery: - Client::userInput(bufferInfo, QString("/QUERY %1").arg(nick)); - break; - default: - qWarning() << "Unhandled nick action"; + action(NickIgnoreCustom)->setProperty("ignoreRule", hostmask); + ignoreMenu->addAction(action(NickIgnoreCustom)); + + ignoreMenu->addSeparator(); + + if (haveWhoData) { + QMap::const_iterator ruleIter = ignoreMap.begin(); + int counter = 0; + if (!ignoreMap.isEmpty()) + // add "Existing Rules" description + ignoreMenu->addAction(_ignoreDescriptions.at(1)); + while (ruleIter != ignoreMap.constEnd()) { + if (counter < 5) { + auto type = static_cast(NickIgnoreToggleEnabled0 + counter * 0x100000); + Action* act = action(type); + act->setText(ruleIter.key()); + act->setProperty("ignoreRule", ruleIter.key()); + act->setChecked(ruleIter.value()); + ignoreMenu->addAction(act); + } + counter++; + ++ruleIter; + } + if (counter) + ignoreMenu->addSeparator(); } - } + ignoreMenu->addAction(action(ShowIgnoreList)); + addAction(_nickIgnoreMenuAction, menu); }