1 /***************************************************************************
2 * Copyright (C) 2005-09 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include <QInputDialog>
23 #include <QMessageBox>
25 #include "contextmenuactionprovider.h"
27 #include "buffermodel.h"
28 #include "buffersettings.h"
29 #include "iconloader.h"
30 #include "clientidentity.h"
34 ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) : NetworkModelController(parent) {
35 registerAction(NetworkConnect, SmallIcon("network-connect"), tr("Connect"));
36 registerAction(NetworkDisconnect, SmallIcon("network-disconnect"), tr("Disconnect"));
38 registerAction(BufferJoin, SmallIcon("irc-join-channel"), tr("Join"));
39 registerAction(BufferPart, SmallIcon("irc-close-channel"), tr("Part"));
40 registerAction(BufferRemove, tr("Delete Chat(s)..."));
41 registerAction(BufferSwitchTo, tr("Go to Chat"));
43 registerAction(HideJoin, tr("Joins"), true);
44 registerAction(HidePart, tr("Parts"), true);
45 registerAction(HideQuit, tr("Quits"), true);
46 registerAction(HideNick, tr("Nick Changes"), true);
47 registerAction(HideMode, tr("Mode Changes"), true);
48 registerAction(HideDayChange, tr("Day Changes"), true);
49 registerAction(HideTopic, tr("Topic Changes"), true);
50 registerAction(HideApplyToAll, tr("Set as Default..."));
51 registerAction(HideUseDefaults, tr("Use Defaults..."));
53 registerAction(JoinChannel, SmallIcon("irc-join-channel"), tr("Join Channel..."));
55 registerAction(NickQuery, tr("Start Query"));
56 registerAction(NickSwitchTo, tr("Show Query"));
57 registerAction(NickWhois, tr("Whois"));
59 registerAction(NickCtcpVersion, tr("Version"));
60 registerAction(NickCtcpTime, tr("Time"));
61 registerAction(NickCtcpPing, tr("Ping"));
62 registerAction(NickCtcpFinger, tr("Finger"));
64 registerAction(NickOp, SmallIcon("irc-operator"), tr("Give Operator Status"));
65 registerAction(NickDeop, SmallIcon("irc-remove-operator"), tr("Take Operator Status"));
66 registerAction(NickVoice, SmallIcon("irc-voice"), tr("Give Voice"));
67 registerAction(NickDevoice, SmallIcon("irc-unvoice"), tr("Take Voice"));
68 registerAction(NickKick, SmallIcon("im-kick-user"), tr("Kick From Channel"));
69 registerAction(NickBan, SmallIcon("im-ban-user"), tr("Ban From Channel"));
70 registerAction(NickKickBan, SmallIcon("im-ban-kick-user"), tr("Kick && Ban"));
72 registerAction(HideBufferTemporarily, tr("Hide Chat(s) Temporarily"));
73 registerAction(HideBufferPermanently, tr("Hide Chat(s) Permanently"));
74 registerAction(ShowChannelList, tr("Show Channel List"));
75 registerAction(ShowIgnoreList, tr("Show Ignore List"));
77 QMenu *hideEventsMenu = new QMenu();
78 hideEventsMenu->addAction(action(HideJoin));
79 hideEventsMenu->addAction(action(HidePart));
80 hideEventsMenu->addAction(action(HideQuit));
81 hideEventsMenu->addAction(action(HideNick));
82 hideEventsMenu->addAction(action(HideMode));
83 hideEventsMenu->addAction(action(HideTopic));
84 hideEventsMenu->addAction(action(HideDayChange));
85 hideEventsMenu->addSeparator();
86 hideEventsMenu->addAction(action(HideApplyToAll));
87 hideEventsMenu->addAction(action(HideUseDefaults));
88 _hideEventsMenuAction = new Action(tr("Hide Events"), 0);
89 _hideEventsMenuAction->setMenu(hideEventsMenu);
91 QMenu *nickCtcpMenu = new QMenu();
92 nickCtcpMenu->addAction(action(NickCtcpPing));
93 nickCtcpMenu->addAction(action(NickCtcpVersion));
94 nickCtcpMenu->addAction(action(NickCtcpTime));
95 nickCtcpMenu->addAction(action(NickCtcpFinger));
96 _nickCtcpMenuAction = new Action(tr("CTCP"), 0);
97 _nickCtcpMenuAction->setMenu(nickCtcpMenu);
99 QMenu *nickModeMenu = new QMenu();
100 nickModeMenu->addAction(action(NickOp));
101 nickModeMenu->addAction(action(NickDeop));
102 nickModeMenu->addAction(action(NickVoice));
103 nickModeMenu->addAction(action(NickDevoice));
104 nickModeMenu->addSeparator();
105 nickModeMenu->addAction(action(NickKick));
106 nickModeMenu->addAction(action(NickBan));
107 nickModeMenu->addAction(action(NickKickBan));
108 _nickModeMenuAction = new Action(tr("Actions"), 0);
109 _nickModeMenuAction->setMenu(nickModeMenu);
112 ContextMenuActionProvider::~ContextMenuActionProvider() {
113 _hideEventsMenuAction->menu()->deleteLater();
114 _hideEventsMenuAction->deleteLater();
115 _nickCtcpMenuAction->menu()->deleteLater();
116 _nickCtcpMenuAction->deleteLater();
117 _nickModeMenuAction->menu()->deleteLater();
118 _nickModeMenuAction->deleteLater();
121 void ContextMenuActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) {
124 addActions(menu, Client::networkModel()->bufferIndex(bufId), receiver, method);
127 void ContextMenuActionProvider::addActions(QMenu *menu, const QModelIndex &index, QObject *receiver, const char *method, bool isCustomBufferView) {
130 addActions(menu, QList<QModelIndex>() << index, 0, QString(), receiver, method, isCustomBufferView);
133 void ContextMenuActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, QObject *receiver, const char *slot) {
134 addActions(menu, filter, msgBuffer, QString(), receiver, slot);
137 void ContextMenuActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, const QString &chanOrNick, QObject *receiver, const char *method) {
140 addActions(menu, QList<QModelIndex>() << Client::networkModel()->bufferIndex(msgBuffer), filter, chanOrNick, receiver, method, false);
143 void ContextMenuActionProvider::addActions(QMenu *menu, const QList<QModelIndex> &indexList, QObject *receiver, const char *method, bool isCustomBufferView) {
144 addActions(menu, indexList, 0, QString(), receiver, method, isCustomBufferView);
147 // add a list of actions sensible for the current item(s)
148 void ContextMenuActionProvider::addActions(QMenu *menu,
149 const QList<QModelIndex> &indexList_,
150 MessageFilter *filter_,
151 const QString &contextItem_,
154 bool isCustomBufferView)
156 if(!indexList_.count())
159 setIndexList(indexList_);
160 setMessageFilter(filter_);
161 setContextItem(contextItem_);
162 setSlot(receiver_, method_);
164 if(!messageFilter()) {
165 // this means we are in a BufferView (or NickView) rather than a ChatView
167 // first index in list determines the menu type (just in case we have both buffers and networks selected, for example)
168 QModelIndex index = indexList().at(0);
169 NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
172 case NetworkModel::NetworkItemType:
173 addNetworkItemActions(menu, index);
175 case NetworkModel::BufferItemType:
176 addBufferItemActions(menu, index, isCustomBufferView);
178 case NetworkModel::IrcUserItemType:
179 addIrcUserActions(menu, index);
187 if(contextItem().isEmpty()) {
188 // a) query buffer: handle like ircuser
189 // b) general chatview: handle like channel iff it displays a single buffer
190 // NOTE stuff breaks probably with merged buffers, need to rework a lot around here then
191 if(messageFilter()->containedBuffers().count() == 1) {
192 // we can handle this like a single bufferItem
193 QModelIndex index = Client::networkModel()->bufferIndex(messageFilter()->containedBuffers().values().at(0));
195 addBufferItemActions(menu, index);
198 // TODO: actions for merged buffers... _indexList contains the index of the message we clicked on
202 // context item = chan or nick, _indexList = buf where the msg clicked on originated
203 if(isChannelName(contextItem())) {
204 QModelIndex msgIdx = indexList().at(0);
205 if(!msgIdx.isValid())
207 NetworkId networkId = msgIdx.data(NetworkModel::NetworkIdRole).value<NetworkId>();
208 BufferId bufId = Client::networkModel()->bufferId(networkId, contextItem());
209 if(bufId.isValid()) {
210 QModelIndex targetIdx = Client::networkModel()->bufferIndex(bufId);
211 setIndexList(targetIdx);
212 addAction(BufferJoin, menu, targetIdx, InactiveState);
213 addAction(BufferSwitchTo, menu, targetIdx, ActiveState);
215 addAction(JoinChannel, menu);
217 // TODO: actions for a nick
223 void ContextMenuActionProvider::addNetworkItemActions(QMenu *menu, const QModelIndex &index) {
224 NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
225 if(!networkId.isValid())
227 const Network *network = Client::network(networkId);
228 Q_CHECK_PTR(network);
232 addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected);
233 addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected);
234 menu->addSeparator();
235 addAction(ShowChannelList, menu, index, ActiveState);
236 addAction(JoinChannel, menu, index, ActiveState);
240 void ContextMenuActionProvider::addBufferItemActions(QMenu *menu, const QModelIndex &index, bool isCustomBufferView) {
241 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
243 menu->addSeparator();
244 switch(bufferInfo.type()) {
245 case BufferInfo::ChannelBuffer:
246 addAction(BufferJoin, menu, index, InactiveState);
247 addAction(BufferPart, menu, index, ActiveState);
248 menu->addSeparator();
249 addHideEventsMenu(menu, bufferInfo.bufferId());
250 menu->addSeparator();
251 addAction(HideBufferTemporarily, menu, isCustomBufferView);
252 addAction(HideBufferPermanently, menu, isCustomBufferView);
253 addAction(BufferRemove, menu, index, InactiveState);
256 case BufferInfo::QueryBuffer:
258 //IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
260 addIrcUserActions(menu, index);
261 menu->addSeparator();
263 addHideEventsMenu(menu, bufferInfo.bufferId());
264 menu->addSeparator();
265 addAction(HideBufferTemporarily, menu, isCustomBufferView);
266 addAction(HideBufferPermanently, menu, isCustomBufferView);
267 addAction(BufferRemove, menu, index);
272 addAction(HideBufferTemporarily, menu, isCustomBufferView);
273 addAction(HideBufferPermanently, menu, isCustomBufferView);
277 void ContextMenuActionProvider::addIrcUserActions(QMenu *menu, const QModelIndex &index) {
278 // this can be called: a) as a nicklist context menu (index has IrcUserItemType)
279 // b) as a query buffer context menu (index has BufferItemType and is a QueryBufferItem)
280 // c) right-click in a query chatview (same as b), index will be the corresponding QueryBufferItem)
281 // d) right-click on some nickname (_contextItem will be non-null, _filter -> chatview, index -> message buffer)
283 if(contextItem().isNull()) {
285 bool haveQuery = indexList().count() == 1 && findQueryBuffer(index).isValid();
286 NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
287 addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType);
288 addAction(_nickCtcpMenuAction, menu);
289 menu->addSeparator();
290 addAction(NickQuery, menu, itemType == NetworkModel::IrcUserItemType && !haveQuery && indexList().count() == 1);
291 addAction(NickSwitchTo, menu, itemType == NetworkModel::IrcUserItemType && haveQuery);
292 menu->addSeparator();
293 addAction(NickWhois, menu, true);
295 } else if(!contextItem().isEmpty() && messageFilter()) {
302 Action * ContextMenuActionProvider::addAction(ActionType type , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
303 return addAction(action(type), menu, checkRequirements(index, requiredActiveState));
306 Action * ContextMenuActionProvider::addAction(Action *action , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
307 return addAction(action, menu, checkRequirements(index, requiredActiveState));
310 Action * ContextMenuActionProvider::addAction(ActionType type , QMenu *menu, bool condition) {
311 return addAction(action(type), menu, condition);
314 Action * ContextMenuActionProvider::addAction(Action *action , QMenu *menu, bool condition) {
316 menu->addAction(action);
317 action->setVisible(true);
319 action->setVisible(false);
324 void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, BufferId bufferId) {
325 if(BufferSettings(bufferId).hasFilter())
326 addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter());
328 addHideEventsMenu(menu);
331 void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, MessageFilter *msgFilter) {
332 if(BufferSettings(msgFilter->idString()).hasFilter())
333 addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter());
335 addHideEventsMenu(menu);
338 void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, int filter) {
339 action(HideApplyToAll)->setEnabled(filter != -1);
340 action(HideUseDefaults)->setEnabled(filter != -1);
342 filter = BufferSettings().messageFilter();
344 action(HideJoin)->setChecked(filter & Message::Join);
345 action(HidePart)->setChecked(filter & Message::Part);
346 action(HideQuit)->setChecked(filter & Message::Quit);
347 action(HideNick)->setChecked(filter & Message::Nick);
348 action(HideMode)->setChecked(filter & Message::Mode);
349 action(HideDayChange)->setChecked(filter & Message::DayChange);
350 action(HideTopic)->setChecked(filter & Message::Topic);
352 menu->addAction(_hideEventsMenuAction);