Split action handling and helper stuff from ContextMenuActionProvider
[quassel.git] / src / uisupport / networkmodelcontroller.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-09 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 <QMessageBox>
23
24 #include "networkmodelcontroller.h"
25
26 #include "buffermodel.h"
27 #include "buffersettings.h"
28 #include "iconloader.h"
29 #include "clientidentity.h"
30 #include "network.h"
31 #include "util.h"
32
33 NetworkModelController::NetworkModelController(QObject *parent)
34 : QObject(parent),
35   _actionCollection(new ActionCollection(this)),
36   _messageFilter(0),
37   _receiver(0)
38 {
39
40   connect(_actionCollection, SIGNAL(actionTriggered(QAction *)), SLOT(actionTriggered(QAction *)));
41
42 }
43
44 NetworkModelController::~NetworkModelController() {
45
46 }
47
48 void NetworkModelController::registerAction(ActionType type, const QString &text, bool checkable) {
49   registerAction(type, QPixmap(), text, checkable);
50 }
51
52 void NetworkModelController::registerAction(ActionType type, const QPixmap &icon, const QString &text, bool checkable) {
53   Action *act;
54   if(icon.isNull())
55     act = new Action(text, this);
56   else
57     act = new Action(icon, text, this);
58
59   act->setCheckable(checkable);
60   act->setData(type);
61
62   _actionCollection->addAction(QString::number(type, 16), act);
63   _actionByType[type] = act;
64 }
65
66 /******** Helper Functions ***********************************************************************/
67
68 void NetworkModelController::setIndexList(const QModelIndex &index) {
69   _indexList = QList<QModelIndex>() << index;
70 }
71
72 void NetworkModelController::setIndexList(const QList<QModelIndex> &list) {
73   _indexList = list;
74 }
75
76 void NetworkModelController::setMessageFilter(MessageFilter *filter) {
77   _messageFilter = filter;
78 }
79
80 void NetworkModelController::setContextItem(const QString &contextItem) {
81   _contextItem = contextItem;
82 }
83
84 void NetworkModelController::setSlot(QObject *receiver, const char *method) {
85   _receiver = receiver;
86   _method = method;
87 }
88
89 bool NetworkModelController::checkRequirements(const QModelIndex &index, ItemActiveStates requiredActiveState) {
90   if(!index.isValid())
91     return false;
92
93   ItemActiveStates isActive = index.data(NetworkModel::ItemActiveRole).toBool()
94   ? ActiveState
95   : InactiveState;
96
97   if(!(isActive & requiredActiveState))
98     return false;
99
100   return true;
101 }
102
103 QString NetworkModelController::nickName(const QModelIndex &index) const {
104   IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
105   if(ircUser)
106     return ircUser->nick();
107
108   BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
109   if(!bufferInfo.isValid())
110     return QString();
111   if(!bufferInfo.type() == BufferInfo::QueryBuffer)
112     return QString();
113
114   return bufferInfo.bufferName(); // FIXME this might break with merged queries maybe
115 }
116
117 BufferId NetworkModelController::findQueryBuffer(const QModelIndex &index, const QString &predefinedNick) const {
118   NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
119   if(!networkId.isValid())
120     return BufferId();
121
122   QString nick = predefinedNick.isEmpty() ? nickName(index) : predefinedNick;
123   if(nick.isEmpty())
124     return BufferId();
125
126   return findQueryBuffer(networkId, nick);
127 }
128
129 BufferId NetworkModelController::findQueryBuffer(NetworkId networkId, const QString &nick) const {
130   return Client::networkModel()->bufferId(networkId, nick);
131 }
132
133 void NetworkModelController::removeBuffers(const QModelIndexList &indexList) {
134   QList<BufferInfo> inactive;
135   foreach(QModelIndex index, indexList) {
136     BufferInfo info = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
137     if(info.isValid()) {
138       if(info.type() == BufferInfo::QueryBuffer
139         || (info.type() == BufferInfo::ChannelBuffer && !index.data(NetworkModel::ItemActiveRole).toBool()))
140         inactive << info;
141     }
142   }
143   QString msg;
144   if(inactive.count()) {
145     msg = tr("Do you want to delete the following buffer(s) permanently?", 0, inactive.count());
146     msg += "<ul>";
147     foreach(BufferInfo info, inactive)
148       msg += QString("<li>%1</li>").arg(info.bufferName());
149     msg += "</ul>";
150     msg += tr("<b>Note:</b> This will delete all related data, including all backlog data, from the core's database and cannot be undone.");
151     if(inactive.count() != indexList.count())
152       msg += tr("<br>Active channel buffers cannot be deleted, please part the channel first.");
153     
154     if(QMessageBox::question(0, tr("Remove buffers permanently?"), msg, QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
155       foreach(BufferInfo info, inactive)
156         Client::removeBuffer(info.bufferId());
157     }
158   }
159 }
160
161 void NetworkModelController::handleExternalAction(ActionType type, QAction *action) {
162   Q_UNUSED(type);
163   if(receiver() && method()) {
164     if(!QMetaObject::invokeMethod(receiver(), method(), Q_ARG(QAction *, action)))
165       qWarning() << "NetworkModelActionController::handleExternalAction(): Could not invoke slot" << receiver() << method();
166   }
167 }
168
169 /******** Handle Actions *************************************************************************/
170
171 void NetworkModelController::actionTriggered(QAction *action) {
172   ActionType type = (ActionType)action->data().toInt();
173   if(type > 0) {
174     if(type & NetworkMask)
175       handleNetworkAction(type, action);
176     else if(type & BufferMask)
177       handleBufferAction(type, action);
178     else if(type & HideMask)
179       handleHideAction(type, action);
180     else if(type & GeneralMask)
181       handleGeneralAction(type, action);
182     else if(type & NickMask)
183       handleNickAction(type, action);
184     else if(type & ExternalMask)
185       handleExternalAction(type, action);
186     else
187       qWarning() << "NetworkModelController::actionTriggered(): Unhandled action!";
188   }
189 }
190
191 void NetworkModelController::handleNetworkAction(ActionType type, QAction *) {
192   if(!indexList().count())
193     return;
194   const Network *network = Client::network(indexList().at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>());
195   Q_CHECK_PTR(network);
196   if(!network)
197     return;
198
199   switch(type) {
200     case NetworkConnect:
201       network->requestConnect();
202       break;
203     case NetworkDisconnect:
204       network->requestDisconnect();
205       break;
206     default:
207       break;
208   }
209 }
210
211 void NetworkModelController::handleBufferAction(ActionType type, QAction *) {
212   if(type == BufferRemove) {
213     removeBuffers(indexList());
214   } else {
215
216     foreach(QModelIndex index, indexList()) {
217       BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
218       if(!bufferInfo.isValid())
219         continue;
220
221       switch(type) {
222         case BufferJoin:
223           Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName()));
224           break;
225         case BufferPart:
226         {
227           QString reason = Client::identity(Client::network(bufferInfo.networkId())->identity())->partReason();
228           Client::userInput(bufferInfo, QString("/PART %1").arg(reason));
229           break;
230         }
231         case BufferSwitchTo:
232           Client::bufferModel()->switchToBuffer(bufferInfo.bufferId());
233           break;
234         default:
235           break;
236       }
237     }
238   }
239 }
240
241 void NetworkModelController::handleHideAction(ActionType type, QAction *action) {
242   Q_UNUSED(action)
243
244   int filter = 0;
245   if(NetworkModelController::action(HideJoin)->isChecked())
246     filter |= Message::Join;
247   if(NetworkModelController::action(HidePart)->isChecked())
248     filter |= Message::Part;
249   if(NetworkModelController::action(HideQuit)->isChecked())
250     filter |= Message::Quit;
251   if(NetworkModelController::action(HideNick)->isChecked())
252     filter |= Message::Nick;
253   if(NetworkModelController::action(HideMode)->isChecked())
254     filter |= Message::Mode;
255   if(NetworkModelController::action(HideDayChange)->isChecked())
256     filter |= Message::DayChange;
257
258   switch(type) {
259   case HideJoin:
260   case HidePart:
261   case HideQuit:
262   case HideNick:
263   case HideMode:
264   case HideDayChange:
265     if(_messageFilter)
266       BufferSettings(_messageFilter->idString()).setMessageFilter(filter);
267     else {
268       foreach(QModelIndex index, _indexList) {
269         BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
270         if(!bufferId.isValid())
271           continue;
272         BufferSettings(bufferId).setMessageFilter(filter);
273       }
274     }
275     return;
276   case HideApplyToAll:
277     BufferSettings().setMessageFilter(filter);
278   case HideUseDefaults:
279     if(_messageFilter)
280       BufferSettings(_messageFilter->idString()).removeFilter();
281     else {
282       foreach(QModelIndex index, _indexList) {
283         BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
284         if(!bufferId.isValid())
285           continue;
286         BufferSettings(bufferId).removeFilter();
287       }
288     }
289     return;
290   default:
291     return;
292   };
293 }
294
295 void NetworkModelController::handleGeneralAction(ActionType type, QAction *action) {
296   Q_UNUSED(action)
297
298   if(!indexList().count())
299     return;
300   NetworkId networkId = indexList().at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
301   if(!networkId.isValid())
302     return;
303
304   switch(type) {
305     case JoinChannel: {
306       QString channelName = contextItem();
307       if(channelName.isEmpty()) {
308         bool ok;
309         channelName = QInputDialog::getText(0, tr("Join Channel"), tr("Input channel name:"), QLineEdit::Normal, QString(), &ok);
310         if(!ok)
311           return;
312       }
313       if(!channelName.isEmpty()) {
314         Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId), QString("/JOIN %1").arg(channelName));
315       }
316       break;
317     }
318     case ShowChannelList:
319       emit showChannelList(networkId);
320       break;
321     case ShowIgnoreList:
322       emit showIgnoreList(networkId);
323       break;
324     default:
325       break;
326   }
327 }
328
329 void NetworkModelController::handleNickAction(ActionType type, QAction *) {
330   foreach(QModelIndex index, indexList()) {
331     NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
332     if(!networkId.isValid())
333       continue;
334     QString nick = nickName(index);
335     if(nick.isEmpty())
336       continue;
337     BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
338     if(!bufferInfo.isValid())
339       continue;
340
341     switch(type) {
342       case NickWhois:
343         Client::userInput(bufferInfo, QString("/WHOIS %1 %1").arg(nick));
344         break;
345       case NickCtcpVersion:
346         Client::userInput(bufferInfo, QString("/CTCP %1 VERSION").arg(nick));
347         break;
348       case NickCtcpPing:
349         Client::userInput(bufferInfo, QString("/CTCP %1 PING").arg(nick));
350         break;
351       case NickCtcpTime:
352         Client::userInput(bufferInfo, QString("/CTCP %1 TIME").arg(nick));
353         break;
354       case NickCtcpFinger:
355         Client::userInput(bufferInfo, QString("/CTCP %1 FINGER").arg(nick));
356         break;
357       case NickOp:
358         Client::userInput(bufferInfo, QString("/OP %1").arg(nick));
359         break;
360       case NickDeop:
361         Client::userInput(bufferInfo, QString("/DEOP %1").arg(nick));
362         break;
363       case NickVoice:
364         Client::userInput(bufferInfo, QString("/VOICE %1").arg(nick));
365         break;
366       case NickDevoice:
367         Client::userInput(bufferInfo, QString("/DEVOICE %1").arg(nick));
368         break;
369       case NickKick:
370         Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
371         break;
372       case NickBan:
373         Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
374         break;
375       case NickKickBan:
376         Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
377         Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
378         break;
379       case NickSwitchTo:
380         Client::bufferModel()->switchToBuffer(findQueryBuffer(networkId, nick));
381         break;
382       case NickQuery:
383         Client::userInput(bufferInfo, QString("/QUERY %1").arg(nick));
384         break;
385       default:
386         qWarning() << "Unhandled nick action";
387     }
388   }
389 }