8d72131bad65b553ee15f8b70b63d37c47fbc5dd
[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 "buffermodel.h"
28 #include "buffersettings.h"
29 #include "iconloader.h"
30 #include "clientidentity.h"
31 #include "network.h"
32 #include "util.h"
33
34 NetworkModelActionProvider::NetworkModelActionProvider(QObject *parent)
35 : AbstractActionProvider(parent),
36   _actionCollection(new ActionCollection(this)),
37   _messageFilter(0),
38   _receiver(0)
39 {
40   registerAction(NetworkConnect, SmallIcon("network-connect"), tr("Connect"));
41   registerAction(NetworkDisconnect, SmallIcon("network-disconnect"), tr("Disconnect"));
42
43   registerAction(BufferJoin, tr("Join"));
44   registerAction(BufferPart, tr("Part"));
45   registerAction(BufferRemove, tr("Delete Buffer(s)..."));
46   registerAction(BufferSwitchTo, tr("Show Buffer"));
47
48   registerAction(HideJoin, tr("Joins"), true);
49   registerAction(HidePart, tr("Parts"), true);
50   registerAction(HideQuit, tr("Quits"), true);
51   registerAction(HideNick, tr("Nick Changes"), true);
52   registerAction(HideMode, tr("Mode Changes"), true);
53   registerAction(HideDayChange, tr("Day Changes"), true);
54   registerAction(HideApplyToAll, tr("Apply to All Chat Views..."));
55
56   registerAction(JoinChannel, tr("Join Channel..."));
57
58   registerAction(NickQuery, tr("Start Query"));
59   registerAction(NickSwitchTo, tr("Show Query"));
60   registerAction(NickWhois, tr("Whois"));
61
62   registerAction(NickCtcpVersion, tr("Version"));
63   registerAction(NickCtcpTime, tr("Time"));
64   registerAction(NickCtcpPing, tr("Ping"));
65   registerAction(NickCtcpFinger, tr("Finger"));
66
67   registerAction(NickOp, tr("Give Operator Status"));
68   registerAction(NickDeop, tr("Take Operator Status"));
69   registerAction(NickVoice, tr("Give Voice"));
70   registerAction(NickDevoice, tr("Take Voice"));
71   registerAction(NickKick, tr("Kick From Channel"));
72   registerAction(NickBan, tr("Ban From Channel"));
73   registerAction(NickKickBan, tr("Kick && Ban"));
74
75   registerAction(HideBufferTemporarily, tr("Hide Buffer(s) Temporarily"));
76   registerAction(HideBufferPermanently, tr("Hide Buffer(s) Permanently"));
77   registerAction(ShowChannelList, SmallIcon("format-list-unordered"), tr("Show Channel List"));
78   registerAction(ShowIgnoreList, tr("Show Ignore List"));
79
80   connect(_actionCollection, SIGNAL(actionTriggered(QAction *)), SLOT(actionTriggered(QAction *)));
81
82   action(HideApplyToAll)->setDisabled(true);
83
84   QMenu *hideEventsMenu = new QMenu();
85   hideEventsMenu->addAction(action(HideJoin));
86   hideEventsMenu->addAction(action(HidePart));
87   hideEventsMenu->addAction(action(HideQuit));
88   hideEventsMenu->addAction(action(HideNick));
89   hideEventsMenu->addAction(action(HideMode));
90   hideEventsMenu->addAction(action(HideDayChange));
91   hideEventsMenu->addSeparator();
92   hideEventsMenu->addAction(action(HideApplyToAll));
93   _hideEventsMenuAction = new Action(tr("Hide Events"), 0);
94   _hideEventsMenuAction->setMenu(hideEventsMenu);
95
96   QMenu *nickCtcpMenu = new QMenu();
97   nickCtcpMenu->addAction(action(NickCtcpPing));
98   nickCtcpMenu->addAction(action(NickCtcpVersion));
99   nickCtcpMenu->addAction(action(NickCtcpTime));
100   nickCtcpMenu->addAction(action(NickCtcpFinger));
101   _nickCtcpMenuAction = new Action(tr("CTCP"), 0);
102   _nickCtcpMenuAction->setMenu(nickCtcpMenu);
103
104   QMenu *nickModeMenu = new QMenu();
105   nickModeMenu->addAction(action(NickOp));
106   nickModeMenu->addAction(action(NickDeop));
107   nickModeMenu->addAction(action(NickVoice));
108   nickModeMenu->addAction(action(NickDevoice));
109   nickModeMenu->addSeparator();
110   nickModeMenu->addAction(action(NickKick));
111   nickModeMenu->addAction(action(NickBan));
112   nickModeMenu->addAction(action(NickKickBan));
113   _nickModeMenuAction = new Action(tr("Actions"), 0);
114   _nickModeMenuAction->setMenu(nickModeMenu);
115 }
116
117 NetworkModelActionProvider::~NetworkModelActionProvider() {
118   _hideEventsMenuAction->menu()->deleteLater();
119   _hideEventsMenuAction->deleteLater();
120   _nickCtcpMenuAction->menu()->deleteLater();
121   _nickCtcpMenuAction->deleteLater();
122   _nickModeMenuAction->menu()->deleteLater();
123   _nickModeMenuAction->deleteLater();
124 }
125
126 void NetworkModelActionProvider::registerAction(ActionType type, const QString &text, bool checkable) {
127   registerAction(type, QPixmap(), text, checkable);
128 }
129
130 void NetworkModelActionProvider::registerAction(ActionType type, const QPixmap &icon, const QString &text, bool checkable) {
131   Action *act;
132   if(icon.isNull())
133     act = new Action(text, this);
134   else
135     act = new Action(icon, text, this);
136
137   act->setCheckable(checkable);
138   act->setData(type);
139
140   _actionCollection->addAction(QString::number(type, 16), act);
141   _actionByType[type] = act;
142 }
143
144 void NetworkModelActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) {
145   if(!bufId.isValid())
146     return;
147   _messageFilter = 0;
148   _contextItem = QString();
149   addActions(menu, Client::networkModel()->bufferIndex(bufId), receiver, method);
150 }
151
152 void NetworkModelActionProvider::addActions(QMenu *menu, const QModelIndex &index, QObject *receiver, const char *method, bool isCustomBufferView) {
153   if(!index.isValid())
154     return;
155   _messageFilter = 0;
156   _contextItem = QString();
157   addActions(menu, QList<QModelIndex>() << index, receiver, method, isCustomBufferView);
158 }
159
160 void NetworkModelActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, QObject *receiver, const char *slot) {
161   addActions(menu, filter, msgBuffer, QString(), receiver, slot);
162 }
163
164 void NetworkModelActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, const QString &chanOrNick, QObject *receiver, const char *method) {
165   if(!filter)
166     return;
167   _messageFilter = filter;
168   _contextItem = chanOrNick;
169   addActions(menu, QList<QModelIndex>() << Client::networkModel()->bufferIndex(msgBuffer), receiver, method);
170 }
171
172 // add a list of actions sensible for the current item(s)
173 void NetworkModelActionProvider::addActions(QMenu *menu,
174                                             const QList<QModelIndex> &indexList,
175                                             QObject *receiver,
176                                             const char *method,
177                                             bool isCustomBufferView)
178 {
179   if(!indexList.count())
180     return;
181
182   _indexList = indexList;
183   _receiver = receiver;
184   _method = method;
185
186   if(!_messageFilter) {
187     // this means we are in a BufferView (or NickView) rather than a ChatView
188
189     // first index in list determines the menu type (just in case we have both buffers and networks selected, for example)
190     QModelIndex index = _indexList.at(0);
191     NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
192
193     switch(itemType) {
194       case NetworkModel::NetworkItemType:
195         addNetworkItemActions(menu, index);
196         break;
197       case NetworkModel::BufferItemType:
198         addBufferItemActions(menu, index, isCustomBufferView);
199         break;
200       case NetworkModel::IrcUserItemType:
201         addIrcUserActions(menu, index);
202         break;
203       default:
204         return;
205
206     }
207   } else {
208     // ChatView actions
209     if(_contextItem.isEmpty()) {
210       // a) query buffer: handle like ircuser
211       // b) general chatview: handle like channel iff it displays a single buffer
212       // NOTE stuff breaks probably with merged buffers, need to rework a lot around here then
213       if(_messageFilter->containedBuffers().count() == 1) {
214         // we can handle this like a single bufferItem
215         QModelIndex index = Client::networkModel()->bufferIndex(_messageFilter->containedBuffers().values().at(0));
216         _indexList = QList<QModelIndex>() << index;
217         addBufferItemActions(menu, index);
218         return;
219       } else {
220         // TODO: actions for merged buffers... _indexList contains the index of the message we clicked on
221
222       }
223     } else {
224       // context item = chan or nick, _indexList = buf where the msg clicked on originated
225       if(isChannelName(_contextItem)) {
226         QModelIndex msgIdx = _indexList.at(0);
227         if(!msgIdx.isValid())
228           return;
229         NetworkId networkId = msgIdx.data(NetworkModel::NetworkIdRole).value<NetworkId>();
230         BufferId bufId = Client::networkModel()->bufferId(networkId, _contextItem);
231         if(bufId.isValid()) {
232           QModelIndex targetIdx = Client::networkModel()->bufferIndex(bufId);
233           _indexList = QList<QModelIndex>() << targetIdx;
234           addAction(BufferJoin, menu, targetIdx, InactiveState);
235           addAction(BufferSwitchTo, menu, targetIdx, ActiveState);
236         } else
237           addAction(JoinChannel, menu);
238       } else {
239         // TODO: actions for a nick
240       }
241     }
242   }
243 }
244
245 void NetworkModelActionProvider::addNetworkItemActions(QMenu *menu, const QModelIndex &index) {
246   NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
247   if(!networkId.isValid())
248     return;
249   const Network *network = Client::network(networkId);
250   Q_CHECK_PTR(network);
251   if(!network)
252     return;
253
254   addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected);
255   addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected);
256   menu->addSeparator();
257   addAction(ShowChannelList, menu, index, ActiveState);
258   addAction(JoinChannel, menu, index, ActiveState);
259
260 }
261
262 void NetworkModelActionProvider::addBufferItemActions(QMenu *menu, const QModelIndex &index, bool isCustomBufferView) {
263   BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
264
265   switch(bufferInfo.type()) {
266     case BufferInfo::ChannelBuffer:
267       addAction(BufferJoin, menu, index, InactiveState);
268       addAction(BufferPart, menu, index, ActiveState);
269       menu->addSeparator();
270       addHideEventsMenu(menu, bufferInfo.bufferId());
271       menu->addSeparator();
272       addAction(HideBufferTemporarily, menu, isCustomBufferView);
273       addAction(HideBufferPermanently, menu, isCustomBufferView);
274       addAction(BufferRemove, menu, index, InactiveState);
275       break;
276
277     case BufferInfo::QueryBuffer:
278     {
279       //IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
280       //if(ircUser) {
281         addIrcUserActions(menu, index);
282         menu->addSeparator();
283       //}
284       addHideEventsMenu(menu, bufferInfo.bufferId());
285       menu->addSeparator();
286       addAction(HideBufferTemporarily, menu, isCustomBufferView);
287       addAction(HideBufferPermanently, menu, isCustomBufferView);
288       addAction(BufferRemove, menu, index);
289       break;
290     }
291
292     default:
293       addAction(HideBufferTemporarily, menu, isCustomBufferView);
294       addAction(HideBufferPermanently, menu, isCustomBufferView);
295   }
296 }
297
298 void NetworkModelActionProvider::addIrcUserActions(QMenu *menu, const QModelIndex &index) {
299   // this can be called: a) as a nicklist context menu (index has IrcUserItemType)
300   //                     b) as a query buffer context menu (index has BufferItemType and is a QueryBufferItem)
301   //                     c) right-click in a query chatview (same as b), index will be the corresponding QueryBufferItem)
302   //                     d) right-click on some nickname (_contextItem will be non-null, _filter -> chatview, index -> message buffer)
303
304   if(_contextItem.isNull()) {
305     // cases a, b, c
306     bool haveQuery = _indexList.count() == 1 && findQueryBuffer(index).isValid();
307     NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
308     addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType);
309     addAction(_nickCtcpMenuAction, menu);
310     menu->addSeparator();
311     addAction(NickQuery, menu, itemType == NetworkModel::IrcUserItemType && !haveQuery && _indexList.count() == 1);
312     addAction(NickSwitchTo, menu, itemType == NetworkModel::IrcUserItemType && haveQuery);
313     menu->addSeparator();
314     addAction(NickWhois, menu, true);
315
316   } else if(!_contextItem.isEmpty() && _messageFilter) {
317     // case d
318     // TODO
319
320   }
321 }
322
323 /******** Helper Functions ***********************************************************************/
324
325 bool NetworkModelActionProvider::checkRequirements(const QModelIndex &index, ItemActiveStates requiredActiveState) {
326   if(!index.isValid())
327     return false;
328
329   ItemActiveStates isActive = index.data(NetworkModel::ItemActiveRole).toBool()
330   ? ActiveState
331   : InactiveState;
332
333   if(!(isActive & requiredActiveState))
334     return false;
335
336   return true;
337 }
338
339 Action * NetworkModelActionProvider::addAction(ActionType type , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
340   return addAction(action(type), menu, checkRequirements(index, requiredActiveState));
341 }
342
343 Action * NetworkModelActionProvider::addAction(Action *action , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
344   return addAction(action, menu, checkRequirements(index, requiredActiveState));
345 }
346
347 Action * NetworkModelActionProvider::addAction(ActionType type , QMenu *menu, bool condition) {
348   return addAction(action(type), menu, condition);
349 }
350
351 Action * NetworkModelActionProvider::addAction(Action *action , QMenu *menu, bool condition) {
352   if(condition) {
353     menu->addAction(action);
354     action->setVisible(true);
355   } else {
356     action->setVisible(false);
357   }
358   return action;
359 }
360
361 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, BufferId bufferId) {
362   addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter());
363 }
364
365 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, MessageFilter *msgFilter) {
366   addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter());
367 }
368
369 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, int filter) {
370   action(HideJoin)->setChecked(filter & Message::Join);
371   action(HidePart)->setChecked(filter & Message::Part);
372   action(HideQuit)->setChecked(filter & Message::Quit);
373   action(HideNick)->setChecked(filter & Message::Nick);
374   action(HideMode)->setChecked(filter & Message::Mode);
375   action(HideDayChange)->setChecked(filter & Message::DayChange);
376
377   menu->addAction(_hideEventsMenuAction);
378 }
379
380 QString NetworkModelActionProvider::nickName(const QModelIndex &index) const {
381   IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
382   if(ircUser)
383     return ircUser->nick();
384
385   BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
386   if(!bufferInfo.isValid())
387     return QString();
388   if(!bufferInfo.type() == BufferInfo::QueryBuffer)
389     return QString();
390
391   return bufferInfo.bufferName(); // FIXME this might break with merged queries maybe
392 }
393
394 BufferId NetworkModelActionProvider::findQueryBuffer(const QModelIndex &index, const QString &predefinedNick) const {
395   NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
396   if(!networkId.isValid())
397     return BufferId();
398
399   QString nick = predefinedNick.isEmpty() ? nickName(index) : predefinedNick;
400   if(nick.isEmpty())
401     return BufferId();
402
403   return findQueryBuffer(networkId, nick);
404 }
405
406 BufferId NetworkModelActionProvider::findQueryBuffer(NetworkId networkId, const QString &nick) const {
407   return Client::networkModel()->bufferId(networkId, nick);
408 }
409
410 void NetworkModelActionProvider::handleExternalAction(ActionType type, QAction *action) {
411   Q_UNUSED(type);
412   if(_receiver && _method) {
413     if(!QMetaObject::invokeMethod(_receiver, _method, Q_ARG(QAction *, action)))
414       qWarning() << "NetworkModelActionProvider::handleExternalAction(): Could not invoke slot" << _receiver << _method;
415   }
416 }
417
418 /******** Handle Actions *************************************************************************/
419
420 void NetworkModelActionProvider::actionTriggered(QAction *action) {
421   ActionType type = (ActionType)action->data().toInt();
422   if(type > 0) {
423     if(type & NetworkMask)
424       handleNetworkAction(type, action);
425     else if(type & BufferMask)
426       handleBufferAction(type, action);
427     else if(type & HideMask)
428       handleHideAction(type, action);
429     else if(type & GeneralMask)
430       handleGeneralAction(type, action);
431     else if(type & NickMask)
432       handleNickAction(type, action);
433     else if(type & ExternalMask)
434       handleExternalAction(type, action);
435     else
436       qWarning() << "NetworkModelActionProvider::actionTriggered(): Unhandled action!";
437   }
438   _indexList.clear();
439   _messageFilter = 0;
440   _receiver = 0;
441 }
442
443 void NetworkModelActionProvider::handleNetworkAction(ActionType type, QAction *) {
444   if(!_indexList.count())
445     return;
446   const Network *network = Client::network(_indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>());
447   Q_CHECK_PTR(network);
448   if(!network)
449     return;
450
451   switch(type) {
452     case NetworkConnect:
453       network->requestConnect();
454       break;
455     case NetworkDisconnect:
456       network->requestDisconnect();
457       break;
458     default:
459       break;
460   }
461 }
462
463 void NetworkModelActionProvider::handleBufferAction(ActionType type, QAction *) {
464   if(type == BufferRemove) {
465     removeBuffers(_indexList);
466   } else {
467
468     foreach(QModelIndex index, _indexList) {
469       BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
470       if(!bufferInfo.isValid())
471         continue;
472
473       switch(type) {
474         case BufferJoin:
475           Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName()));
476           break;
477         case BufferPart:
478         {
479           QString reason = Client::identity(Client::network(bufferInfo.networkId())->identity())->partReason();
480           Client::userInput(bufferInfo, QString("/PART %1").arg(reason));
481           break;
482         }
483         case BufferSwitchTo:
484           Client::bufferModel()->switchToBuffer(bufferInfo.bufferId());
485           break;
486         default:
487           break;
488       }
489     }
490   }
491 }
492
493 void NetworkModelActionProvider::removeBuffers(const QModelIndexList &indexList) {
494   QList<BufferInfo> inactive;
495   foreach(QModelIndex index, indexList) {
496     if(!index.data(NetworkModel::ItemActiveRole).toBool()) {
497       BufferInfo info = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
498       if(info.isValid())
499         inactive << info;
500     }
501   }
502   QString msg;
503   if(inactive.count()) {
504     msg = tr("Do you want to delete the following buffer(s) permanently?", 0, inactive.count());
505     msg += "<ul>";
506     foreach(BufferInfo info, inactive)
507       msg += QString("<li>%1</li>").arg(info.bufferName());
508     msg += "</ul>";
509     msg += tr("<b>Note:</b> This will delete all related data, including all backlog data, from the core's database and cannot be undone.");
510     if(inactive.count() != indexList.count())
511       msg += tr("<br>Active channel buffers cannot be deleted, please part the channel first.");
512
513     if(QMessageBox::question(0, tr("Remove buffers permanently?"), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
514       foreach(BufferInfo info, inactive)
515         Client::removeBuffer(info.bufferId());
516     }
517   }
518 }
519
520 void NetworkModelActionProvider::handleHideAction(ActionType type, QAction *action) {
521   Message::Type msgType;
522   switch(type) {
523     case HideJoin:
524       msgType = Message::Join; break;
525     case HidePart:
526       msgType = Message::Part; break;
527     case HideQuit:
528       msgType = Message::Quit; break;
529     case HideNick:
530       msgType = Message::Nick; break;
531     case HideMode:
532       msgType = Message::Mode; break;
533     case HideDayChange:
534       msgType = Message::DayChange; break;
535     case HideApplyToAll:
536       // TODO implement "apply to all" for hiding messages
537       return;
538       break;
539     default:
540       return;
541   }
542
543   if(_messageFilter)
544     BufferSettings(_messageFilter->idString()).filterMessage(msgType, action->isChecked());
545   else {
546     foreach(QModelIndex index, _indexList) {
547       BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
548       if(!bufferId.isValid())
549         continue;
550       BufferSettings(bufferId).filterMessage(msgType, action->isChecked());
551     }
552   }
553 }
554
555 void NetworkModelActionProvider::handleGeneralAction(ActionType type, QAction *action) {
556   Q_UNUSED(action)
557
558   if(!_indexList.count())
559     return;
560   NetworkId networkId = _indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
561   if(!networkId.isValid())
562     return;
563
564   switch(type) {
565     case JoinChannel: {
566       QString channelName = _contextItem;
567       if(channelName.isEmpty()) {
568         bool ok;
569         channelName = QInputDialog::getText(0, tr("Join Channel"), tr("Input channel name:"), QLineEdit::Normal, QString(), &ok);
570         if(!ok)
571           return;
572       }
573       if(!channelName.isEmpty()) {
574         Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId), QString("/JOIN %1").arg(channelName));
575       }
576       break;
577     }
578     case ShowChannelList:
579       emit showChannelList(networkId);
580       break;
581     case ShowIgnoreList:
582       emit showIgnoreList(networkId);
583       break;
584     default:
585       break;
586   }
587 }
588
589 void NetworkModelActionProvider::handleNickAction(ActionType type, QAction *) {
590   foreach(QModelIndex index, _indexList) {
591     NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
592     if(!networkId.isValid())
593       continue;
594     QString nick = nickName(index);
595     if(nick.isEmpty())
596       continue;
597     BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
598     if(!bufferInfo.isValid())
599       continue;
600
601     switch(type) {
602       case NickWhois:
603         Client::userInput(bufferInfo, QString("/WHOIS %1 %1").arg(nick));
604         break;
605       case NickCtcpVersion:
606         Client::userInput(bufferInfo, QString("/CTCP %1 VERSION").arg(nick));
607         break;
608       case NickCtcpPing:
609         Client::userInput(bufferInfo, QString("/CTCP %1 PING").arg(nick));
610         break;
611       case NickCtcpTime:
612         Client::userInput(bufferInfo, QString("/CTCP %1 TIME").arg(nick));
613         break;
614       case NickCtcpFinger:
615         Client::userInput(bufferInfo, QString("/CTCP %1 FINGER").arg(nick));
616         break;
617       case NickOp:
618         Client::userInput(bufferInfo, QString("/OP %1").arg(nick));
619         break;
620       case NickDeop:
621         Client::userInput(bufferInfo, QString("/DEOP %1").arg(nick));
622         break;
623       case NickVoice:
624         Client::userInput(bufferInfo, QString("/VOICE %1").arg(nick));
625         break;
626       case NickDevoice:
627         Client::userInput(bufferInfo, QString("/DEVOICE %1").arg(nick));
628         break;
629       case NickKick:
630         Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
631         break;
632       case NickBan:
633         Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
634         break;
635       case NickKickBan:
636         Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
637         Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
638         break;
639       case NickSwitchTo:
640         Client::bufferModel()->switchToBuffer(findQueryBuffer(networkId, nick));
641         break;
642       case NickQuery:
643         Client::userInput(bufferInfo, QString("/QUERY %1").arg(nick));
644         break;
645       default:
646         qWarning() << "Unhandled nick action";
647     }
648   }
649 }