Introduce NetworkModelActionProvider
[quassel.git] / src / uisupport / networkmodelactionprovider.cpp
1 /***************************************************************************
2 *   Copyright (C) 2005-08 by the Quassel Project                          *
3 *   devel@quassel-irc.org                                                 *
4 *                                                                         *
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.                                           *
9 *                                                                         *
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.                          *
14 *                                                                         *
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 ***************************************************************************/
20
21 #include <QInputDialog>
22 #include <QMenu>
23 #include <QMessageBox>
24
25 #include "networkmodelactionprovider.h"
26
27 #include "buffersettings.h"
28 #include "iconloader.h"
29 #include "identity.h"
30 #include "network.h"
31
32 NetworkModelActionProvider::NetworkModelActionProvider(QObject *parent)
33 : AbstractActionProvider(parent),
34   _actionCollection(new ActionCollection(this)),
35   _messageFilter(0),
36   _receiver(0)
37 {
38   registerAction(NetworkConnect, SmallIcon("network-connect"), tr("Connect"));
39   registerAction(NetworkDisconnect, SmallIcon("network-disconnect"), tr("Disconnect"));
40
41   registerAction(BufferJoin, tr("Join"));
42   registerAction(BufferPart, tr("Part"));
43   registerAction(BufferRemove, tr("Delete Buffer..."));
44
45   registerAction(HideJoin, tr("Joins"), true);
46   registerAction(HidePart, tr("Parts"), true);
47   registerAction(HideQuit, tr("Quits"), true);
48   registerAction(HideNick, tr("Nick Changes"), true);
49   registerAction(HideMode, tr("Mode Changes"), true);
50   registerAction(HideDayChange, tr("Day Changes"), true);
51   registerAction(HideApplyToAll, tr("Apply to All Chat Views..."));
52
53   registerAction(JoinChannel, tr("Join Channel..."));
54
55   registerAction(NickCtcpWhois, tr("Whois"));
56   registerAction(NickCtcpVersion, tr("Version"));
57   registerAction(NickCtcpTime, tr("Time"));
58   registerAction(NickCtcpPing, tr("Ping"));
59   registerAction(NickCtcpFinger, tr("Finger"));
60
61   registerAction(NickOp, tr("Give Operator Status"));
62   registerAction(NickDeop, tr("Take Operator Status"));
63   registerAction(NickVoice, tr("Give Voice"));
64   registerAction(NickDevoice, tr("Take Voice"));
65   registerAction(NickKick, tr("Kick"));
66   registerAction(NickBan, tr("Ban"));
67   registerAction(NickKickBan, tr("Kickban"));
68   registerAction(NickQuery, tr("Query"));
69
70   registerAction(HideBufferTemporarily, tr("Hide Buffer(s) Temporarily"));
71   registerAction(HideBufferPermanently, tr("Hide Buffer(s) Permanently"));
72   registerAction(ShowChannelList, SmallIcon("format-list-unordered"), tr("Show Channel List"));
73   registerAction(ShowIgnoreList, tr("Show Ignore List"));
74
75   connect(_actionCollection, SIGNAL(actionTriggered(QAction *)), SLOT(actionTriggered(QAction *)));
76
77   action(HideApplyToAll)->setDisabled(true);
78
79   QMenu *hideEventsMenu = new QMenu();
80   hideEventsMenu->addAction(action(HideJoin));
81   hideEventsMenu->addAction(action(HidePart));
82   hideEventsMenu->addAction(action(HideQuit));
83   hideEventsMenu->addAction(action(HideNick));
84   hideEventsMenu->addAction(action(HideMode));
85   hideEventsMenu->addAction(action(HideDayChange));
86   hideEventsMenu->addSeparator();
87   hideEventsMenu->addAction(action(HideApplyToAll));
88   _hideEventsMenuAction = new Action(tr("Hide Events"), 0);
89   _hideEventsMenuAction->setMenu(hideEventsMenu);
90 }
91
92 NetworkModelActionProvider::~NetworkModelActionProvider() {
93   _hideEventsMenuAction->menu()->deleteLater();
94   _hideEventsMenuAction->deleteLater();
95 }
96
97 void NetworkModelActionProvider::registerAction(ActionType type, const QString &text, bool checkable) {
98   registerAction(type, QPixmap(), text, checkable);
99 }
100
101 void NetworkModelActionProvider::registerAction(ActionType type, const QPixmap &icon, const QString &text, bool checkable) {
102   Action *act;
103   if(icon.isNull())
104     act = new Action(text, this);
105   else
106     act = new Action(icon, text, this);
107
108   act->setCheckable(checkable);
109   act->setData(type);
110
111   _actionCollection->addAction(QString::number(type, 16), act);
112   _actionByType[type] = act;
113 }
114
115 void NetworkModelActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) {
116   if(!bufId.isValid())
117     return;
118   _messageFilter = 0;
119   addActions(menu, Client::networkModel()->bufferIndex(bufId), receiver, method);
120 }
121
122 void NetworkModelActionProvider::addActions(QMenu *menu, MessageFilter *filter, QObject *receiver, const char *method) {
123   if(!filter)
124     return;
125   _messageFilter = filter;
126   QList<QModelIndex> indexes;
127   foreach(BufferId bufId, filter->containedBuffers())
128     indexes << Client::networkModel()->bufferIndex(bufId);
129   addActions(menu, indexes, receiver, method);
130 }
131
132 void NetworkModelActionProvider::addActions(QMenu *menu, const QModelIndex &index, QObject *receiver, const char *method, bool isCustomBufferView) {
133   if(!index.isValid())
134     return;
135   _messageFilter = 0;
136   addActions(menu, QList<QModelIndex>() << index, receiver, method, isCustomBufferView);
137 }
138
139 // add a list of actions sensible for the current item(s)
140 void NetworkModelActionProvider::addActions(QMenu *menu,
141                                             const QList<QModelIndex> &indexList,
142                                             QObject *receiver,
143                                             const char *method,
144                                             bool isCustomBufferView)
145 {
146   if(!indexList.count())
147     return;
148
149   _indexList = indexList;
150   _receiver = receiver;
151   _method = method;
152
153   if(!_messageFilter) {
154     // this means we are in a BufferView (or NickView) rather than a ChatView
155
156     // first index in list determines the menu type (just in case we have both buffers and networks selected, for example)
157     QModelIndex index = _indexList.at(0);
158     NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
159
160     switch(itemType) {
161       case NetworkModel::NetworkItemType:
162         addNetworkItemActions(menu, index);
163         break;
164       case NetworkModel::BufferItemType:
165         addBufferItemActions(menu, index, isCustomBufferView);
166         break;
167
168       default:
169         return;
170
171     }
172   } else {
173     // ChatView actions
174
175
176   }
177 }
178
179 void NetworkModelActionProvider::addNetworkItemActions(QMenu *menu, const QModelIndex &index) {
180   NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
181   if(!networkId.isValid())
182     return;
183   const Network *network = Client::network(networkId);
184   Q_CHECK_PTR(network);
185   if(!network)
186     return;
187
188   addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected);
189   addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected);
190   menu->addSeparator();
191   addAction(ShowChannelList, menu, index, ActiveState);
192   addAction(JoinChannel, menu, index, ActiveState);
193
194 }
195
196 void NetworkModelActionProvider::addBufferItemActions(QMenu *menu, const QModelIndex &index, bool isCustomBufferView) {
197   BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
198
199   switch(bufferInfo.type()) {
200     case BufferInfo::ChannelBuffer:
201       addAction(BufferJoin, menu, index, InactiveState);
202       addAction(BufferPart, menu, index, ActiveState);
203       menu->addSeparator();
204       addHideEventsMenu(menu, bufferInfo.bufferId());
205       menu->addSeparator();
206       addAction(HideBufferTemporarily, menu, isCustomBufferView);
207       addAction(HideBufferPermanently, menu, isCustomBufferView);
208       addAction(BufferRemove, menu, index);
209       break;
210
211     case BufferInfo::QueryBuffer:
212     {
213       IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
214       if(ircUser) {
215         addIrcUserActions(menu, ircUser, false);
216         menu->addSeparator();
217       }
218       addHideEventsMenu(menu, bufferInfo.bufferId());
219       menu->addSeparator();
220       addAction(HideBufferTemporarily, menu, isCustomBufferView);
221       addAction(HideBufferPermanently, menu, isCustomBufferView);
222       addAction(BufferRemove, menu, index);
223       break;
224     }
225
226     default:
227       addAction(HideBufferTemporarily, menu, isCustomBufferView);
228       addAction(HideBufferPermanently, menu, isCustomBufferView);
229   }
230 }
231
232 void NetworkModelActionProvider::addIrcUserActions(QMenu *menu, IrcUser *ircUser, bool isNickView) {
233
234
235 }
236
237 /******** Helper Functions ***********************************************************************/
238
239 bool NetworkModelActionProvider::checkRequirements(const QModelIndex &index, ItemActiveStates requiredActiveState) {
240   if(!index.isValid())
241     return false;
242
243   ItemActiveStates isActive = index.data(NetworkModel::ItemActiveRole).toBool()
244   ? ActiveState
245   : InactiveState;
246
247   if(!(isActive & requiredActiveState))
248     return false;
249
250   return true;
251 }
252
253 Action * NetworkModelActionProvider::addAction(ActionType type , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
254   return addAction(action(type), menu, checkRequirements(index, requiredActiveState));
255 }
256
257 Action * NetworkModelActionProvider::addAction(Action *action , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
258   return addAction(action, menu, checkRequirements(index, requiredActiveState));
259 }
260
261 Action * NetworkModelActionProvider::addAction(ActionType type , QMenu *menu, bool condition) {
262   return addAction(action(type), menu, condition);
263 }
264
265 Action * NetworkModelActionProvider::addAction(Action *action , QMenu *menu, bool condition) {
266   if(condition) {
267     menu->addAction(action);
268     action->setVisible(true);
269   } else {
270     action->setVisible(false);
271   }
272   return action;
273 }
274
275 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, BufferId bufferId) {
276   addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter());
277 }
278
279 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, MessageFilter *msgFilter) {
280   addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter());
281 }
282
283 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, int filter) {
284   action(HideJoin)->setChecked(filter & Message::Join);
285   action(HidePart)->setChecked(filter & Message::Part);
286   action(HideQuit)->setChecked(filter & Message::Quit);
287   action(HideNick)->setChecked(filter & Message::Nick);
288   action(HideMode)->setChecked(filter & Message::Mode);
289   action(HideDayChange)->setChecked(filter & Message::DayChange);
290
291   menu->addAction(_hideEventsMenuAction);
292 }
293
294 /******** Handle Actions *************************************************************************/
295
296 void NetworkModelActionProvider::actionTriggered(QAction *action) {
297   ActionType type = (ActionType)action->data().toInt();
298   if(type > 0) {
299     if(type & NetworkMask)
300       handleNetworkAction(type, action);
301     else if(type & BufferMask)
302       handleBufferAction(type, action);
303     else if(type & HideMask)
304       handleHideAction(type, action);
305     else if(type & GeneralMask)
306       handleGeneralAction(type, action);
307     else if(type & NickMask)
308       handleNickAction(type, action);
309     else if(type & ExternalMask)
310       handleExternalAction(type, action);
311     else
312       qWarning() << "NetworkModelActionProvider::actionTriggered(): Unhandled action!";
313   }
314   _indexList.clear();
315   _messageFilter = 0;
316   _receiver = 0;
317 }
318
319 void NetworkModelActionProvider::handleNetworkAction(ActionType type, QAction *) {
320   if(!_indexList.count())
321     return;
322   const Network *network = Client::network(_indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>());
323   Q_CHECK_PTR(network);
324   if(!network)
325     return;
326
327   switch(type) {
328     case NetworkConnect:
329       network->requestConnect();
330       break;
331     case NetworkDisconnect:
332       network->requestDisconnect();
333       break;
334     default:
335       break;
336   }
337 }
338
339 void NetworkModelActionProvider::handleBufferAction(ActionType type, QAction *) {
340   foreach(QModelIndex index, _indexList) {
341     BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
342     if(!bufferInfo.isValid())
343       continue;
344
345     switch(type) {
346       case BufferJoin:
347         Client::instance()->userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName()));
348         break;
349       case BufferPart:
350       {
351         QString reason = Client::identity(Client::network(bufferInfo.networkId())->identity())->partReason();
352         Client::instance()->userInput(bufferInfo, QString("/PART %1").arg(reason));
353         break;
354       }
355       case BufferRemove:
356       {
357         int res = QMessageBox::question(0, tr("Remove buffer permanently?"),
358         tr("Do you want to delete the buffer \"%1\" permanently? This will delete all related data, including all backlog "
359         "data, from the core's database!").arg(bufferInfo.bufferName()),
360         QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
361         if(res == QMessageBox::Yes) {
362           Client::removeBuffer(bufferInfo.bufferId());
363         }
364         break;
365       }
366       default:
367         break;
368     }
369   }
370 }
371
372 void NetworkModelActionProvider::handleHideAction(ActionType type, QAction *action) {
373   Message::Type msgType;
374   switch(type) {
375     case HideJoin:
376       msgType = Message::Join; break;
377     case HidePart:
378       msgType = Message::Part; break;
379     case HideQuit:
380       msgType = Message::Quit; break;
381     case HideNick:
382       msgType = Message::Nick; break;
383     case HideMode:
384       msgType = Message::Mode; break;
385     case HideDayChange:
386       msgType = Message::DayChange; break;
387     case HideApplyToAll:
388       // TODO implement "apply to all" for hiding messages
389       break;
390     default:
391       return;
392   }
393
394   if(_messageFilter)
395     BufferSettings(_messageFilter->idString()).filterMessage(msgType, action->isChecked());
396   else {
397     foreach(QModelIndex index, _indexList) {
398       BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
399       if(!bufferId.isValid())
400         continue;
401       BufferSettings(bufferId).filterMessage(msgType, action->isChecked());
402     }
403   }
404 }
405
406 void NetworkModelActionProvider::handleGeneralAction(ActionType type, QAction *action) {
407   if(!_indexList.count())
408     return;
409   NetworkId networkId = _indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
410   if(!networkId.isValid())
411     return;
412
413   switch(type) {
414     case JoinChannel:
415     {
416     //  FIXME no QInputDialog in Qtopia
417 #   ifndef Q_WS_QWS
418       bool ok;
419       QString channelName = QInputDialog::getText(0, tr("Join Channel"), tr("Input channel name:"), QLineEdit::Normal, QString(), &ok);
420       if(ok && !channelName.isEmpty()) {
421         Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId),
422                                       QString("/JOIN %1").arg(channelName));
423       }
424 #   endif
425       break;
426     }
427     case ShowChannelList:
428       emit showChannelList(networkId);
429       break;
430     case ShowIgnoreList:
431       emit showIgnoreList(networkId);
432       break;
433     default:
434       break;
435   }
436 }
437
438 void NetworkModelActionProvider::handleNickAction(ActionType type, QAction *) {
439
440
441 }
442
443 void NetworkModelActionProvider::handleExternalAction(ActionType type, QAction *action) {
444   Q_UNUSED(type);
445   if(_receiver && _method) {
446     if(!QMetaObject::invokeMethod(_receiver, _method, Q_ARG(QAction *, action)))
447       qWarning() << "NetworkModelActionProvider::handleExternalAction(): Could not invoke slot" << _receiver << _method;
448   }
449 }