1 /***************************************************************************
2 * Copyright (C) 2005-08 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 "networkmodelactionprovider.h"
27 #include "buffermodel.h"
28 #include "buffersettings.h"
29 #include "iconloader.h"
33 NetworkModelActionProvider::NetworkModelActionProvider(QObject *parent)
34 : AbstractActionProvider(parent),
35 _actionCollection(new ActionCollection(this)),
39 registerAction(NetworkConnect, SmallIcon("network-connect"), tr("Connect"));
40 registerAction(NetworkDisconnect, SmallIcon("network-disconnect"), tr("Disconnect"));
42 registerAction(BufferJoin, tr("Join"));
43 registerAction(BufferPart, tr("Part"));
44 registerAction(BufferRemove, tr("Delete Buffer..."));
45 registerAction(BufferSwitchTo, tr("Show Buffer"));
47 registerAction(HideJoin, tr("Joins"), true);
48 registerAction(HidePart, tr("Parts"), true);
49 registerAction(HideQuit, tr("Quits"), true);
50 registerAction(HideNick, tr("Nick Changes"), true);
51 registerAction(HideMode, tr("Mode Changes"), true);
52 registerAction(HideDayChange, tr("Day Changes"), true);
53 registerAction(HideApplyToAll, tr("Apply to All Chat Views..."));
55 registerAction(JoinChannel, tr("Join Channel..."));
57 registerAction(NickQuery, tr("Start Query"));
58 registerAction(NickSwitchTo, tr("Show Query"));
59 registerAction(NickWhois, tr("Whois"));
61 registerAction(NickCtcpVersion, tr("Version"));
62 registerAction(NickCtcpTime, tr("Time"));
63 registerAction(NickCtcpPing, tr("Ping"));
64 registerAction(NickCtcpFinger, tr("Finger"));
66 registerAction(NickOp, tr("Give Operator Status"));
67 registerAction(NickDeop, tr("Take Operator Status"));
68 registerAction(NickVoice, tr("Give Voice"));
69 registerAction(NickDevoice, tr("Take Voice"));
70 registerAction(NickKick, tr("Kick From Channel"));
71 registerAction(NickBan, tr("Ban From Channel"));
72 registerAction(NickKickBan, tr("Kick && Ban"));
74 registerAction(HideBufferTemporarily, tr("Hide Buffer(s) Temporarily"));
75 registerAction(HideBufferPermanently, tr("Hide Buffer(s) Permanently"));
76 registerAction(ShowChannelList, SmallIcon("format-list-unordered"), tr("Show Channel List"));
77 registerAction(ShowIgnoreList, tr("Show Ignore List"));
79 connect(_actionCollection, SIGNAL(actionTriggered(QAction *)), SLOT(actionTriggered(QAction *)));
81 action(HideApplyToAll)->setDisabled(true);
83 QMenu *hideEventsMenu = new QMenu();
84 hideEventsMenu->addAction(action(HideJoin));
85 hideEventsMenu->addAction(action(HidePart));
86 hideEventsMenu->addAction(action(HideQuit));
87 hideEventsMenu->addAction(action(HideNick));
88 hideEventsMenu->addAction(action(HideMode));
89 hideEventsMenu->addAction(action(HideDayChange));
90 hideEventsMenu->addSeparator();
91 hideEventsMenu->addAction(action(HideApplyToAll));
92 _hideEventsMenuAction = new Action(tr("Hide Events"), 0);
93 _hideEventsMenuAction->setMenu(hideEventsMenu);
95 QMenu *nickCtcpMenu = new QMenu();
96 nickCtcpMenu->addAction(action(NickCtcpPing));
97 nickCtcpMenu->addAction(action(NickCtcpVersion));
98 nickCtcpMenu->addAction(action(NickCtcpTime));
99 nickCtcpMenu->addAction(action(NickCtcpFinger));
100 _nickCtcpMenuAction = new Action(tr("CTCP"), 0);
101 _nickCtcpMenuAction->setMenu(nickCtcpMenu);
103 QMenu *nickModeMenu = new QMenu();
104 nickModeMenu->addAction(action(NickOp));
105 nickModeMenu->addAction(action(NickDeop));
106 nickModeMenu->addAction(action(NickVoice));
107 nickModeMenu->addAction(action(NickDevoice));
108 nickModeMenu->addSeparator();
109 nickModeMenu->addAction(action(NickKick));
110 nickModeMenu->addAction(action(NickBan));
111 nickModeMenu->addAction(action(NickKickBan));
112 _nickModeMenuAction = new Action(tr("Actions"), 0);
113 _nickModeMenuAction->setMenu(nickModeMenu);
116 NetworkModelActionProvider::~NetworkModelActionProvider() {
117 _hideEventsMenuAction->menu()->deleteLater();
118 _hideEventsMenuAction->deleteLater();
119 _nickCtcpMenuAction->menu()->deleteLater();
120 _nickCtcpMenuAction->deleteLater();
121 _nickModeMenuAction->menu()->deleteLater();
122 _nickModeMenuAction->deleteLater();
125 void NetworkModelActionProvider::registerAction(ActionType type, const QString &text, bool checkable) {
126 registerAction(type, QPixmap(), text, checkable);
129 void NetworkModelActionProvider::registerAction(ActionType type, const QPixmap &icon, const QString &text, bool checkable) {
132 act = new Action(text, this);
134 act = new Action(icon, text, this);
136 act->setCheckable(checkable);
139 _actionCollection->addAction(QString::number(type, 16), act);
140 _actionByType[type] = act;
143 void NetworkModelActionProvider::addActions(QMenu *menu, BufferId bufId, QObject *receiver, const char *method) {
147 _contextItem = QString();
148 addActions(menu, Client::networkModel()->bufferIndex(bufId), receiver, method);
151 void NetworkModelActionProvider::addActions(QMenu *menu, const QModelIndex &index, QObject *receiver, const char *method, bool isCustomBufferView) {
155 _contextItem = QString();
156 addActions(menu, QList<QModelIndex>() << index, receiver, method, isCustomBufferView);
159 void NetworkModelActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, QObject *receiver, const char *slot) {
160 addActions(menu, filter, msgBuffer, QString(), receiver, slot);
163 void NetworkModelActionProvider::addActions(QMenu *menu, MessageFilter *filter, BufferId msgBuffer, const QString &chanOrNick, QObject *receiver, const char *method) {
166 _messageFilter = filter;
167 _contextItem = chanOrNick;
168 addActions(menu, QList<QModelIndex>() << Client::networkModel()->bufferIndex(msgBuffer), receiver, method);
171 // add a list of actions sensible for the current item(s)
172 void NetworkModelActionProvider::addActions(QMenu *menu,
173 const QList<QModelIndex> &indexList,
176 bool isCustomBufferView)
178 if(!indexList.count())
181 _indexList = indexList;
182 _receiver = receiver;
185 if(!_messageFilter) {
186 // this means we are in a BufferView (or NickView) rather than a ChatView
188 // first index in list determines the menu type (just in case we have both buffers and networks selected, for example)
189 QModelIndex index = _indexList.at(0);
190 NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
193 case NetworkModel::NetworkItemType:
194 addNetworkItemActions(menu, index);
196 case NetworkModel::BufferItemType:
197 addBufferItemActions(menu, index, isCustomBufferView);
199 case NetworkModel::IrcUserItemType:
200 addIrcUserActions(menu, index);
208 if(_contextItem.isEmpty()) {
209 // a) query buffer: handle like ircuser
210 // b) general chatview: handle like channel iff it displays a single buffer
211 // NOTE stuff breaks probably with merged buffers, need to rework a lot around here then
212 if(_messageFilter->containedBuffers().count() == 1) {
213 // we can handle this like a single bufferItem
214 QModelIndex index = Client::networkModel()->bufferIndex(_messageFilter->containedBuffers().values().at(0));
215 _indexList = QList<QModelIndex>() << index;
216 addBufferItemActions(menu, index);
219 // TODO: actions for merged buffers... _indexList contains the index of the message we clicked on
226 void NetworkModelActionProvider::addNetworkItemActions(QMenu *menu, const QModelIndex &index) {
227 NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
228 if(!networkId.isValid())
230 const Network *network = Client::network(networkId);
231 Q_CHECK_PTR(network);
235 addAction(NetworkConnect, menu, network->connectionState() == Network::Disconnected);
236 addAction(NetworkDisconnect, menu, network->connectionState() != Network::Disconnected);
237 menu->addSeparator();
238 addAction(ShowChannelList, menu, index, ActiveState);
239 addAction(JoinChannel, menu, index, ActiveState);
243 void NetworkModelActionProvider::addBufferItemActions(QMenu *menu, const QModelIndex &index, bool isCustomBufferView) {
244 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
246 switch(bufferInfo.type()) {
247 case BufferInfo::ChannelBuffer:
248 addAction(BufferJoin, menu, index, InactiveState);
249 addAction(BufferPart, menu, index, ActiveState);
250 menu->addSeparator();
251 addHideEventsMenu(menu, bufferInfo.bufferId());
252 menu->addSeparator();
253 addAction(HideBufferTemporarily, menu, isCustomBufferView);
254 addAction(HideBufferPermanently, menu, isCustomBufferView);
255 addAction(BufferRemove, menu, index);
258 case BufferInfo::QueryBuffer:
260 //IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
262 addIrcUserActions(menu, index);
263 menu->addSeparator();
265 addHideEventsMenu(menu, bufferInfo.bufferId());
266 menu->addSeparator();
267 addAction(HideBufferTemporarily, menu, isCustomBufferView);
268 addAction(HideBufferPermanently, menu, isCustomBufferView);
269 addAction(BufferRemove, menu, index);
274 addAction(HideBufferTemporarily, menu, isCustomBufferView);
275 addAction(HideBufferPermanently, menu, isCustomBufferView);
279 void NetworkModelActionProvider::addIrcUserActions(QMenu *menu, const QModelIndex &index) {
280 // this can be called: a) as a nicklist context menu (index has IrcUserItemType)
281 // b) as a query buffer context menu (index has BufferItemType and is a QueryBufferItem)
282 // c) right-click in a query chatview (same as b), index will be the corresponding QueryBufferItem)
283 // d) right-click on some nickname (_contextItem will be non-null, _filter -> chatview, index -> message buffer)
285 if(_contextItem.isNull()) {
287 bool haveQuery = findQueryBuffer(index).isValid();
288 NetworkModel::ItemType itemType = static_cast<NetworkModel::ItemType>(index.data(NetworkModel::ItemTypeRole).toInt());
289 addAction(_nickModeMenuAction, menu, itemType == NetworkModel::IrcUserItemType);
290 addAction(_nickCtcpMenuAction, menu);
291 menu->addSeparator();
292 addAction(NickQuery, menu, itemType == NetworkModel::IrcUserItemType && !haveQuery);
293 addAction(NickSwitchTo, menu, itemType == NetworkModel::IrcUserItemType && haveQuery);
294 menu->addSeparator();
295 addAction(NickWhois, menu, true);
297 } else if(!_contextItem.isEmpty() && _messageFilter) {
304 /******** Helper Functions ***********************************************************************/
306 bool NetworkModelActionProvider::checkRequirements(const QModelIndex &index, ItemActiveStates requiredActiveState) {
310 ItemActiveStates isActive = index.data(NetworkModel::ItemActiveRole).toBool()
314 if(!(isActive & requiredActiveState))
320 Action * NetworkModelActionProvider::addAction(ActionType type , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
321 return addAction(action(type), menu, checkRequirements(index, requiredActiveState));
324 Action * NetworkModelActionProvider::addAction(Action *action , QMenu *menu, const QModelIndex &index, ItemActiveStates requiredActiveState) {
325 return addAction(action, menu, checkRequirements(index, requiredActiveState));
328 Action * NetworkModelActionProvider::addAction(ActionType type , QMenu *menu, bool condition) {
329 return addAction(action(type), menu, condition);
332 Action * NetworkModelActionProvider::addAction(Action *action , QMenu *menu, bool condition) {
334 menu->addAction(action);
335 action->setVisible(true);
337 action->setVisible(false);
342 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, BufferId bufferId) {
343 addHideEventsMenu(menu, BufferSettings(bufferId).messageFilter());
346 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, MessageFilter *msgFilter) {
347 addHideEventsMenu(menu, BufferSettings(msgFilter->idString()).messageFilter());
350 void NetworkModelActionProvider::addHideEventsMenu(QMenu *menu, int filter) {
351 action(HideJoin)->setChecked(filter & Message::Join);
352 action(HidePart)->setChecked(filter & Message::Part);
353 action(HideQuit)->setChecked(filter & Message::Quit);
354 action(HideNick)->setChecked(filter & Message::Nick);
355 action(HideMode)->setChecked(filter & Message::Mode);
356 action(HideDayChange)->setChecked(filter & Message::DayChange);
358 menu->addAction(_hideEventsMenuAction);
361 QString NetworkModelActionProvider::nickName(const QModelIndex &index) const {
362 IrcUser *ircUser = qobject_cast<IrcUser *>(index.data(NetworkModel::IrcUserRole).value<QObject *>());
364 return ircUser->nick();
366 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
367 if(!bufferInfo.isValid())
370 return bufferInfo.bufferName(); // FIXME this might break with merged queries maybe
373 BufferId NetworkModelActionProvider::findQueryBuffer(const QModelIndex &index, const QString &predefinedNick) const {
374 NetworkId networkId = _indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
375 if(!networkId.isValid())
378 QString nick = predefinedNick.isEmpty() ? nickName(index) : predefinedNick;
382 return findQueryBuffer(networkId, nick);
385 BufferId NetworkModelActionProvider::findQueryBuffer(NetworkId networkId, const QString &nick) const {
386 return Client::networkModel()->bufferId(networkId, nick);
389 void NetworkModelActionProvider::handleExternalAction(ActionType type, QAction *action) {
391 if(_receiver && _method) {
392 if(!QMetaObject::invokeMethod(_receiver, _method, Q_ARG(QAction *, action)))
393 qWarning() << "NetworkModelActionProvider::handleExternalAction(): Could not invoke slot" << _receiver << _method;
397 /******** Handle Actions *************************************************************************/
399 void NetworkModelActionProvider::actionTriggered(QAction *action) {
400 ActionType type = (ActionType)action->data().toInt();
402 if(type & NetworkMask)
403 handleNetworkAction(type, action);
404 else if(type & BufferMask)
405 handleBufferAction(type, action);
406 else if(type & HideMask)
407 handleHideAction(type, action);
408 else if(type & GeneralMask)
409 handleGeneralAction(type, action);
410 else if(type & NickMask)
411 handleNickAction(type, action);
412 else if(type & ExternalMask)
413 handleExternalAction(type, action);
415 qWarning() << "NetworkModelActionProvider::actionTriggered(): Unhandled action!";
422 void NetworkModelActionProvider::handleNetworkAction(ActionType type, QAction *) {
423 if(!_indexList.count())
425 const Network *network = Client::network(_indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>());
426 Q_CHECK_PTR(network);
432 network->requestConnect();
434 case NetworkDisconnect:
435 network->requestDisconnect();
442 void NetworkModelActionProvider::handleBufferAction(ActionType type, QAction *) {
443 foreach(QModelIndex index, _indexList) {
444 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
445 if(!bufferInfo.isValid())
450 Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName()));
454 QString reason = Client::identity(Client::network(bufferInfo.networkId())->identity())->partReason();
455 Client::userInput(bufferInfo, QString("/PART %1").arg(reason));
459 Client::bufferModel()->switchToBuffer(bufferInfo.bufferId());
463 int res = QMessageBox::question(0, tr("Remove buffer permanently?"),
464 tr("Do you want to delete the buffer \"%1\" permanently? This will delete all related data, including all backlog "
465 "data, from the core's database!").arg(bufferInfo.bufferName()),
466 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
467 if(res == QMessageBox::Yes) {
468 Client::removeBuffer(bufferInfo.bufferId());
478 void NetworkModelActionProvider::handleHideAction(ActionType type, QAction *action) {
479 Message::Type msgType;
482 msgType = Message::Join; break;
484 msgType = Message::Part; break;
486 msgType = Message::Quit; break;
488 msgType = Message::Nick; break;
490 msgType = Message::Mode; break;
492 msgType = Message::DayChange; break;
494 // TODO implement "apply to all" for hiding messages
502 BufferSettings(_messageFilter->idString()).filterMessage(msgType, action->isChecked());
504 foreach(QModelIndex index, _indexList) {
505 BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
506 if(!bufferId.isValid())
508 BufferSettings(bufferId).filterMessage(msgType, action->isChecked());
513 void NetworkModelActionProvider::handleGeneralAction(ActionType type, QAction *action) {
516 if(!_indexList.count())
518 NetworkId networkId = _indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
519 if(!networkId.isValid())
525 // FIXME no QInputDialog in Qtopia
528 QString channelName = QInputDialog::getText(0, tr("Join Channel"), tr("Input channel name:"), QLineEdit::Normal, QString(), &ok);
529 if(ok && !channelName.isEmpty()) {
530 Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId),
531 QString("/JOIN %1").arg(channelName));
536 case ShowChannelList:
537 emit showChannelList(networkId);
540 emit showIgnoreList(networkId);
547 void NetworkModelActionProvider::handleNickAction(ActionType type, QAction *) {
548 if(!_indexList.count())
550 NetworkId networkId = _indexList.at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
551 if(!networkId.isValid())
553 QString nick = nickName(_indexList.at(0));
556 BufferInfo bufferInfo = _indexList.at(0).data(NetworkModel::BufferInfoRole).value<BufferInfo>();
557 if(!bufferInfo.isValid())
562 Client::userInput(bufferInfo, QString("/WHOIS %1 %1").arg(nick));
564 case NickCtcpVersion:
565 Client::userInput(bufferInfo, QString("/CTCP %1 VERSION").arg(nick));
568 Client::userInput(bufferInfo, QString("/CTCP %1 PING").arg(nick));
571 Client::userInput(bufferInfo, QString("/CTCP %1 TIME").arg(nick));
574 Client::userInput(bufferInfo, QString("/CTCP %1 FINGER").arg(nick));
577 Client::userInput(bufferInfo, QString("/OP %1").arg(nick));
580 Client::userInput(bufferInfo, QString("/DEOP %1").arg(nick));
583 Client::userInput(bufferInfo, QString("/VOICE %1").arg(nick));
586 Client::userInput(bufferInfo, QString("/DEVOICE %1").arg(nick));
589 Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
592 Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
595 Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
596 Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
599 Client::bufferModel()->switchToBuffer(findQueryBuffer(networkId, nick));
602 Client::userInput(bufferInfo, QString("/QUERY %1").arg(nick));
605 qWarning() << "Unhandled nick action";