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