introducing query merging (per drag & drop). needs a core update
[quassel.git] / src / client / messagefilter.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 "messagefilter.h"
22
23 #include "buffersettings.h"
24 #include "client.h"
25 #include "buffermodel.h"
26 #include "messagemodel.h"
27 #include "networkmodel.h"
28
29 MessageFilter::MessageFilter(QAbstractItemModel *source, QObject *parent)
30   : QSortFilterProxyModel(parent),
31     _messageTypeFilter(0)
32 {
33   init();
34   setSourceModel(source);
35 }
36
37 MessageFilter::MessageFilter(MessageModel *source, const QList<BufferId> &buffers, QObject *parent)
38   : QSortFilterProxyModel(parent),
39     _validBuffers(buffers.toSet()),
40     _messageTypeFilter(0)
41 {
42   init();
43   setSourceModel(source);
44 }
45
46 void MessageFilter::init() {
47   setDynamicSortFilter(true);
48
49   BufferSettings defaultSettings;
50   _messageTypeFilter = defaultSettings.messageFilter();
51   defaultSettings.notify("MessageTypeFilter", this, SLOT(messageTypeFilterChanged()));
52   defaultSettings.notify("UserNoticesInDefaultBuffer", this, SLOT(messageRedirectionChanged()));
53   defaultSettings.notify("UserNoticesInStatusBuffer", this, SLOT(messageRedirectionChanged()));
54   defaultSettings.notify("UserNoticesInCurrentBuffer", this, SLOT(messageRedirectionChanged()));
55
56   defaultSettings.notify("serverNoticesInDefaultBuffer", this, SLOT(messageRedirectionChanged()));
57   defaultSettings.notify("serverNoticesInStatusBuffer", this, SLOT(messageRedirectionChanged()));
58   defaultSettings.notify("serverNoticesInCurrentBuffer", this, SLOT(messageRedirectionChanged()));
59
60   defaultSettings.notify("ErrorMsgsInDefaultBuffer", this, SLOT(messageRedirectionChanged()));
61   defaultSettings.notify("ErrorMsgsInStatusBuffer", this, SLOT(messageRedirectionChanged()));
62   defaultSettings.notify("ErrorMsgsInCurrentBuffer", this, SLOT(messageRedirectionChanged()));
63   messageRedirectionChanged();
64
65   BufferSettings mySettings(idString());
66   if(mySettings.hasFilter())
67     _messageTypeFilter = mySettings.messageFilter();
68   mySettings.notify("MessageTypeFilter", this, SLOT(messageTypeFilterChanged()));
69 }
70
71 void MessageFilter::messageTypeFilterChanged() {
72   int newFilter;
73   BufferSettings defaultSettings;
74   newFilter = BufferSettings().messageFilter();
75
76   BufferSettings mySettings(idString());
77   if(mySettings.hasFilter())
78     newFilter = mySettings.messageFilter();
79
80   if(_messageTypeFilter != newFilter) {
81     _messageTypeFilter = newFilter;
82     _filteredQuitMsgs.clear();
83     invalidateFilter();
84   }
85 }
86
87 void MessageFilter::messageRedirectionChanged() {
88   BufferSettings bufferSettings;
89   _userNoticesInDefaultBuffer = bufferSettings.value("UserNoticesInDefaultBuffer", QVariant(true)).toBool();
90   _userNoticesInStatusBuffer = bufferSettings.value("UserNoticesInStatusBuffer", QVariant(false)).toBool();
91   _userNoticesInCurrentBuffer = bufferSettings.value("UserNoticesInCurrentBuffer", QVariant(false)).toBool();
92
93   _serverNoticesInDefaultBuffer = bufferSettings.value("ServerNoticesInDefaultBuffer", QVariant(false)).toBool();
94   _serverNoticesInStatusBuffer = bufferSettings.value("ServerNoticesInStatusBuffer", QVariant(true)).toBool();
95   _serverNoticesInCurrentBuffer = bufferSettings.value("ServerNoticesInCurrentBuffer", QVariant(false)).toBool();
96
97   _errorMsgsInDefaultBuffer = bufferSettings.value("ErrorMsgsInDefaultBuffer", QVariant(true)).toBool();
98   _errorMsgsInStatusBuffer = bufferSettings.value("ErrorMsgsInStatusBuffer", QVariant(false)).toBool();
99   _errorMsgsInCurrentBuffer = bufferSettings.value("ErrorMsgsInCurrentBuffer", QVariant(false)).toBool();
100
101   invalidateFilter();
102 }
103
104 QString MessageFilter::idString() const {
105   if(_validBuffers.isEmpty())
106     return "*";
107
108   QList<BufferId> bufferIds = _validBuffers.toList();
109   qSort(bufferIds);
110
111   QStringList bufferIdStrings;
112   foreach(BufferId id, bufferIds)
113     bufferIdStrings << QString::number(id.toInt());
114
115   return bufferIdStrings.join("|");
116 }
117
118 bool MessageFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
119   Q_UNUSED(sourceParent);
120   QModelIndex sourceIdx = sourceModel()->index(sourceRow, 2);
121   Message::Type messageType = (Message::Type)sourceModel()->data(sourceIdx, MessageModel::TypeRole).toInt();
122
123   // apply message type filter
124   if(_messageTypeFilter & messageType)
125     return false;
126
127   if(_validBuffers.isEmpty())
128     return true;
129
130   BufferId bufferId = sourceModel()->data(sourceIdx, MessageModel::BufferIdRole).value<BufferId>();
131   if(!bufferId.isValid()) {
132     return true;
133   }
134
135   MsgId msgId = sourceModel()->data(sourceIdx, MessageModel::MsgIdRole).value<MsgId>();
136   Message::Flags flags = (Message::Flags)sourceModel()->data(sourceIdx, MessageModel::FlagsRole).toInt();
137
138   NetworkId myNetworkId = networkId();
139   NetworkId msgNetworkId = Client::networkModel()->networkId(bufferId);
140   if(myNetworkId != msgNetworkId)
141     return false;
142
143   bool redirect = false;
144   bool inDefaultBuffer;
145   bool inStatusBuffer;
146   bool inCurrentBuffer;
147
148   switch(messageType) {
149   case Message::Notice:
150     if(Client::networkModel()->bufferType(bufferId) != BufferInfo::ChannelBuffer) {
151       redirect = true;
152       if(flags & Message::ServerMsg) {
153         // server notice
154         inDefaultBuffer = _serverNoticesInDefaultBuffer;
155         inStatusBuffer = _serverNoticesInStatusBuffer;
156         inCurrentBuffer = _serverNoticesInCurrentBuffer;
157       } else {
158         inDefaultBuffer = _userNoticesInDefaultBuffer;
159         inStatusBuffer = _userNoticesInStatusBuffer;
160         inCurrentBuffer = _userNoticesInCurrentBuffer;
161       }
162     }
163     break;
164   case Message::Error:
165     redirect = true;
166     inDefaultBuffer = _errorMsgsInDefaultBuffer;
167     inStatusBuffer = _errorMsgsInStatusBuffer;
168     inCurrentBuffer = _errorMsgsInCurrentBuffer;
169     break;
170   default:
171     break;
172   }
173
174   if(redirect) {
175     if(_redirectedMsgs.contains(msgId))
176       return true;
177
178     if(inDefaultBuffer && _validBuffers.contains(bufferId))
179       return true;
180
181     if(inCurrentBuffer && !(flags & Message::Backlog) && _validBuffers.contains(Client::bufferModel()->currentIndex().data(NetworkModel::BufferIdRole).value<BufferId>())) {
182       BufferId redirectedTo = sourceModel()->data(sourceIdx, MessageModel::RedirectedToRole).value<BufferId>();
183       if(!redirectedTo.isValid()) {
184         sourceModel()->setData(sourceIdx, QVariant::fromValue<BufferId>(singleBufferId()), MessageModel::RedirectedToRole);
185         _redirectedMsgs << msgId;
186         return true;
187       } else if(_validBuffers.contains(redirectedTo)) {
188         return true;
189       }
190     }
191
192     QSet<BufferId>::const_iterator idIter = _validBuffers.constBegin();
193     while(idIter != _validBuffers.constEnd()) {
194       if(inStatusBuffer && Client::networkModel()->bufferType(*idIter) == BufferInfo::StatusBuffer)
195         return true;
196       idIter++;
197     }
198
199     return false;
200   }
201
202
203   if(_validBuffers.contains(bufferId)) {
204     return true;
205   } else {
206     // show Quit messages in Query buffers:
207     if(bufferType() != BufferInfo::QueryBuffer)
208       return false;
209     if(!(messageType & Message::Quit))
210       return false;
211
212     if(myNetworkId != msgNetworkId)
213       return false;
214
215     uint messageTimestamp = sourceModel()->data(sourceIdx, MessageModel::TimestampRole).value<QDateTime>().toTime_t();
216     QString quiter = sourceModel()->data(sourceIdx, Qt::DisplayRole).toString().section(' ', 0, 0, QString::SectionSkipEmpty).toLower();
217     if(quiter != bufferName().toLower())
218       return false;
219
220     if(_filteredQuitMsgs.contains(quiter, messageTimestamp))
221       return false;
222
223     MessageFilter *that = const_cast<MessageFilter *>(this);
224     that->_filteredQuitMsgs.insert(quiter,  messageTimestamp);
225     return true;
226   }
227 }
228
229 void MessageFilter::requestBacklog() {
230   QSet<BufferId>::const_iterator bufferIdIter = _validBuffers.constBegin();
231   while(bufferIdIter != _validBuffers.constEnd()) {
232     Client::messageModel()->requestBacklog(*bufferIdIter);
233     bufferIdIter++;
234   }
235 }