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 Buffer(s)..."));
41 registerAction(BufferSwitchTo, tr("Show Buffer"));
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(HideApplyToAll, tr("Set as Default..."));
50 registerAction(HideUseDefaults, tr("Use Defaults..."));
52 registerAction(JoinChannel, SmallIcon("irc-join-channel"), tr("Join Channel..."));
54 registerAction(NickQuery, tr("Start Query"));
55 registerAction(NickSwitchTo, tr("Show Query"));
56 registerAction(NickWhois, tr("Whois"));
58 registerAction(NickCtcpVersion, tr("Version"));
59 registerAction(NickCtcpTime, tr("Time"));
60 registerAction(NickCtcpPing, tr("Ping"));
61 registerAction(NickCtcpFinger, tr("Finger"));
63 registerAction(NickOp, SmallIcon("irc-operator"), tr("Give Operator Status"));
64 registerAction(NickDeop, SmallIcon("irc-remove-operator"), tr("Take Operator Status"));
65 registerAction(NickVoice, SmallIcon("irc-voice"), tr("Give Voice"));
66 registerAction(NickDevoice, SmallIcon("irc-unvoice"), tr("Take Voice"));
67 registerAction(NickKick, SmallIcon("im-kick-user"), tr("Kick From Channel"));
68 registerAction(NickBan, SmallIcon("im-ban-user"), tr("Ban From Channel"));
69 registerAction(NickKickBan, SmallIcon("im-ban-kick-user"), tr("Kick && Ban"));
71 registerAction(HideBufferTemporarily, tr("Hide Buffer(s) Temporarily"));
72 registerAction(HideBufferPermanently, tr("Hide Buffer(s) Permanently"));
73 registerAction(ShowChannelList, tr("Show Channel List"));
74 registerAction(ShowIgnoreList, tr("Show Ignore List"));
76 QMenu *hideEventsMenu = new QMenu();
77 hideEventsMenu->addAction(action(HideJoin));
78 hideEventsMenu->addAction(action(HidePart));
79 hideEventsMenu->addAction(action(HideQuit));
80 hideEventsMenu->addAction(action(HideNick));
81 hideEventsMenu->addAction(action(HideMode));
82 hideEventsMenu->addAction(action(HideDayChange));
83 hideEventsMenu->addSeparator();
84 hideEventsMenu->addAction(action(HideApplyToAll));
85 hideEventsMenu->addAction(action(HideUseDefaults));
86 _hideEventsMenuAction = new Action(tr("Hide Events"), 0);
87 _hideEventsMenuAction->setMenu(hideEventsMenu);
89 QMenu *nickCtcpMenu = new QMenu();
90 nickCtcpMenu->addAction(action(NickCtcpPing));
91 nickCtcpMenu->addAction(action(NickCtcpVersion));
92 nickCtcpMenu->addAction(action(NickCtcpTime));
93 nickCtcpMenu->addAction(action(NickCtcpFinger));
94 _nickCtcpMenuAction = new Action(tr("CTCP"), 0);
95 _nickCtcpMenuAction->setMenu(nickCtcpMenu);
97 QMenu *nickModeMenu = new QMenu();
98 nickModeMenu->addAction(action(NickOp));
99 nickModeMenu->addAction(action(NickDeop));
100 nickModeMenu->addAction(action(NickVoice));
101 nickModeMenu->addAction(action(NickDevoice));
102 nickModeMenu->addSeparator();
103 nickModeMenu->addAction(action(NickKick));
104 nickModeMenu->addAction(action(NickBan));
105 nickModeMenu->addAction(action(NickKickBan));
106 _nickModeMenuAction = new Action(tr("Actions"), 0);
107 _nickModeMenuAction->setMenu(nickModeMenu);
110 ContextMenuActionProvider::~ContextMenuActionProvider() {
111 _hideEventsMenuAction->menu()->deleteLater();
112 _hideEventsMenuAction->deleteLater();
113 _nickCtcpMenuAction->menu()->deleteLater();
114 _nickCtcpMenuAction->deleteLater();
115 _nickModeMenuAction->menu()->deleteLater();
116 _nickModeMenuAction->deleteLater();
119 void ContextMenuActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) {
122 addActions(menu, Client::networkModel()->bufferIndex(bufId), receiver, method);
125 void ContextMenuActionProvider::addActions(QMenu *menu, const QModelIndex &index, QObject *receiver, const char *method, bool isCustomBufferView) {
128 addActions(menu, QList<QModelIndex>() << index, 0, QString(), receiver, method, isCustomBufferView);
131 void ContextMenuActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, QObject *receiver, const char *slot) {
132 addActions(menu, filter, msgBuffer, QString(), receiver, slot);
135 void ContextMenuActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, const QString &chanOrNick, QObject *receiver, const char *method) {
138 addActions(menu, QList<QModelIndex>() << Client::networkModel()->bufferIndex(msgBuffer), filter, chanOrNick, receiver, method, false);
141 void ContextMenuActionProvider::addActions(QMenu *menu, const QList<QModelIndex> &indexList, QObject *receiver, const char *method, bool isCustomBufferView) {
142 addActions(menu, indexList, 0, QString(), receiver, method, isCustomBufferView);
145 // add a list of actions sensible for the current item(s)
146 void ContextMenuActionProvider::addActions(QMenu *menu,
147 const QList<QModelIndex> &indexList_,
148 MessageFilter *filter_,
149 const QString &contextItem_,
152 bool isCustomBufferView)
154 if(!indexList_.count())
157 setIndexList(indexList_);
158 setMessageFilter(filter_);
159 setContextItem(contextItem_);
160 setSlot(receiver_, method_);
162 if(!messageFilter()) {
163 // this means we are in a BufferView (or NickView) rather than a ChatView
165 // first index in list determines the menu type (just in case we have both buffers and networks selected, for example)
166 QModelIndex index = indexList().at(0);
167 NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
170 case NetworkModel::NetworkItemType:
171 addNetworkItemActions(menu, index);
173 case NetworkModel::BufferItemType:
174 addBufferItemActions(menu, index, isCustomBufferView);
176 case NetworkModel::IrcUserItemType:
177 addIrcUserActions(menu, index);
185 if(contextItem().isEmpty()) {
186 // a) query buffer: handle like ircuser
187 // b) general chatview: handle like channel iff it displays a single buffer
188 // NOTE stuff breaks probably with merged buffers, need to rework a lot around here then
189 if(messageFilter()->containedBuffers().count() == 1) {
190 // we can handle this like a single bufferItem
191 QModelIndex index = Client::networkModel()->bufferIndex(messageFilter()->containedBuffers().values().at(0));
193 addBufferItemActions(menu, index);
196 // TODO: actions for merged buffers... _indexList contains the index of the message we clicked on
200 // context item = chan or nick, _indexList = buf where the msg clicked on originated
201 if(isChannelName(contextItem())) {
202 QModelIndex msgIdx = indexList().at(0);
203 if(!msgIdx.isValid())
205 NetworkId networkId = msgIdx.data(NetworkModel::NetworkIdRole).value<NetworkId>();
206 BufferId bufId = Client::networkModel()->bufferId(networkId, contextItem());
207 if(bufId.isValid()) {
208 QModelIndex targetIdx = Client::networkModel()->bufferIndex(bufId);
209 setIndexList(targetIdx);
210 addAction(BufferJoin, menu, targetIdx, InactiveState);
211 addAction(BufferSwitchTo, menu, targetIdx, ActiveState);
213 addAction(JoinChannel, menu);
215 // TODO: actions for a nick
221 void ContextMenuActionProvider::addNetworkItemActions(QMenu *menu, const QModelIndex &index) {
222 NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
223 if(!networkId.isValid())
225 const Network *network = Client::network(networkId);
226 Q_CHECK_PTR(network);
230 addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected);
231 addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected);
232 menu->addSeparator();
233 addAction(ShowChannelList, menu, index, ActiveState);
234 addAction(JoinChannel, menu, index, ActiveState);
238 void ContextMenuActionProvider::addBufferItemActions(QMenu *menu, const QModelIndex &index, bool isCustomBufferView) {
239 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
241 menu->addSeparator();
242 switch(bufferInfo.type()) {
243 case BufferInfo::ChannelBuffer:
244 addAction(BufferJoin, menu, index, InactiveState);
245 addAction(BufferPart, menu, index, ActiveState);
246 menu->addSeparator();
247 addHideEventsMenu(menu, bufferInfo.bufferId());
248 menu->addSeparator();
249 addAction(HideBufferTemporarily, menu, isCustomBufferView);
250 addAction(HideBufferPermanently, menu, isCustomBufferView);
251 addAction(BufferRemove, menu, index, InactiveState);
254 case BufferInfo::QueryBuffer:
256 //IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
258 addIrcUserActions(menu, index);
259 menu->addSeparator();
261 addHideEventsMenu(menu, bufferInfo.bufferId());
262 menu->addSeparator();
263 addAction(HideBufferTemporarily, menu, isCustomBufferView);
264 addAction(HideBufferPermanently, menu, isCustomBufferView);
265 addAction(BufferRemove, menu, index);
270 addAction(HideBufferTemporarily, menu, isCustomBufferView);
271 addAction(HideBufferPermanently, menu, isCustomBufferView);
275 void ContextMenuActionProvider::addIrcUserActions(QMenu *menu, const QModelIndex &index) {
276 // this can be called: a) as a nicklist context menu (index has IrcUserItemType)
277 // b) as a query buffer context menu (index has BufferItemType and is a QueryBufferItem)
278 // c) right-click in a query chatview (same as b), index will be the corresponding QueryBufferItem)
279 // d) right-click on some nickname (_contextItem will be non-null, _filter -> chatview, index -> message buffer)
281 if(contextItem().isNull()) {
283 bool haveQuery = indexList().count() == 1 && findQueryBuffer(index).isValid();
284 NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
285 addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType);
286 addAction(_nickCtcpMenuAction, menu);
287 menu->addSeparator();
288 addAction(NickQuery, menu, itemType == NetworkModel::IrcUserItemType && !haveQuery && indexList().count() == 1);
289 addAction(NickSwitchTo, menu, itemType == NetworkModel::IrcUserItemType && haveQuery);
290 menu->addSeparator();
291 addAction(NickWhois, menu, true);
293 } else if(!contextItem().isEmpty() && messageFilter()) {
300 Action * ContextMenuActionProvider::addAction(ActionType type , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
301 return addAction(action(type), menu, checkRequirements(index, requiredActiveState));
304 Action * ContextMenuActionProvider::addAction(Action *action , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
305 return addAction(action, menu, checkRequirements(index, requiredActiveState));
308 Action * ContextMenuActionProvider::addAction(ActionType type , QMenu *menu, bool condition) {
309 return addAction(action(type), menu, condition);
312 Action * ContextMenuActionProvider::addAction(Action *action , QMenu *menu, bool condition) {
314 menu->addAction(action);
315 action->setVisible(true);
317 action->setVisible(false);
322 void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, BufferId bufferId) {
323 if(BufferSettings(bufferId).hasFilter())
324 addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter());
326 addHideEventsMenu(menu);
329 void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, MessageFilter *msgFilter) {
330 if(BufferSettings(msgFilter->idString()).hasFilter())
331 addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter());
333 addHideEventsMenu(menu);
336 void ContextMenuActionProvider::addHideEventsMenu(QMenu *menu, int filter) {
337 action(HideApplyToAll)->setEnabled(filter != -1);
338 action(HideUseDefaults)->setEnabled(filter != -1);
340 filter = BufferSettings().messageFilter();
342 action(HideJoin)->setChecked(filter & Message::Join);
343 action(HidePart)->setChecked(filter & Message::Part);
344 action(HideQuit)->setChecked(filter & Message::Quit);
345 action(HideNick)->setChecked(filter & Message::Nick);
346 action(HideMode)->setChecked(filter & Message::Mode);
347 action(HideDayChange)->setChecked(filter & Message::DayChange);
349 menu->addAction(_hideEventsMenuAction);