Merge pull request #1 from sandsmark/master
[quassel.git] / src / client / bufferviewoverlay.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2013 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  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "bufferviewoverlay.h"
22
23 #include <QEvent>
24
25 #include "bufferviewconfig.h"
26 #include "client.h"
27 #include "clientbacklogmanager.h"
28 #include "clientbufferviewmanager.h"
29 #include "networkmodel.h"
30
31 const int BufferViewOverlay::_updateEventId = QEvent::registerEventType();
32
33 BufferViewOverlay::BufferViewOverlay(QObject *parent)
34     : QObject(parent),
35     _aboutToUpdate(false),
36     _uninitializedViewCount(0),
37     _allowedBufferTypes(0),
38     _minimumActivity(0)
39 {
40 }
41
42
43 void BufferViewOverlay::reset()
44 {
45     _aboutToUpdate = false;
46
47     _bufferViewIds.clear();
48     _uninitializedViewCount = 0;
49
50     _networkIds.clear();
51     _allowedBufferTypes = 0;
52     _minimumActivity = 0;
53
54     _buffers.clear();
55     _removedBuffers.clear();
56     _tempRemovedBuffers.clear();
57 }
58
59
60 void BufferViewOverlay::save()
61 {
62     CoreAccountSettings().setBufferViewOverlay(_bufferViewIds);
63 }
64
65
66 void BufferViewOverlay::restore()
67 {
68     QSet<int> currentIds = _bufferViewIds;
69     reset();
70     currentIds += CoreAccountSettings().bufferViewOverlay();
71
72     QSet<int>::const_iterator iter;
73     for (iter = currentIds.constBegin(); iter != currentIds.constEnd(); iter++) {
74         addView(*iter);
75     }
76 }
77
78
79 void BufferViewOverlay::addView(int viewId)
80 {
81     if (_bufferViewIds.contains(viewId))
82         return;
83
84     BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId);
85     if (!config) {
86         qDebug() << "BufferViewOverlay::addView(): no such buffer view:" << viewId;
87         return;
88     }
89
90     _bufferViewIds << viewId;
91     bool wasInitialized = isInitialized();
92     _uninitializedViewCount++;
93
94     if (config->isInitialized()) {
95         viewInitialized(config);
96
97         if (wasInitialized) {
98             BufferIdList buffers;
99             if (config->networkId().isValid()) {
100                 foreach(BufferId bufferId, config->bufferList()) {
101                     if (Client::networkModel()->networkId(bufferId) == config->networkId())
102                         buffers << bufferId;
103                 }
104                 foreach(BufferId bufferId, config->temporarilyRemovedBuffers().toList()) {
105                     if (Client::networkModel()->networkId(bufferId) == config->networkId())
106                         buffers << bufferId;
107                 }
108             }
109             else {
110                 buffers = BufferIdList::fromSet(config->bufferList().toSet() + config->temporarilyRemovedBuffers());
111             }
112             Client::backlogManager()->checkForBacklog(buffers);
113         }
114     }
115     else {
116         disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
117         // we use a queued connection here since manipulating the connection list of a sending object
118         // doesn't seem to be such a good idea while executing a connected slots.
119         connect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()), Qt::QueuedConnection);
120     }
121     save();
122 }
123
124
125 void BufferViewOverlay::removeView(int viewId)
126 {
127     if (!_bufferViewIds.contains(viewId))
128         return;
129
130     _bufferViewIds.remove(viewId);
131     BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId);
132     if (config)
133         disconnect(config, 0, this, 0);
134
135     // update initialized State:
136     bool wasInitialized = isInitialized();
137     _uninitializedViewCount = 0;
138     QSet<int>::iterator viewIter = _bufferViewIds.begin();
139     while (viewIter != _bufferViewIds.end()) {
140         config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
141         if (!config) {
142             viewIter = _bufferViewIds.erase(viewIter);
143         }
144         else {
145             if (!config->isInitialized())
146                 _uninitializedViewCount++;
147             viewIter++;
148         }
149     }
150
151     update();
152     if (!wasInitialized && isInitialized())
153         emit initDone();
154     save();
155 }
156
157
158 void BufferViewOverlay::viewInitialized(BufferViewConfig *config)
159 {
160     if (!config) {
161         qWarning() << "BufferViewOverlay::viewInitialized() received invalid view!";
162         return;
163     }
164     disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
165
166     connect(config, SIGNAL(configChanged()), this, SLOT(update()));
167
168     // check if the view was removed in the meantime...
169     if (_bufferViewIds.contains(config->bufferViewId()))
170         update();
171
172     _uninitializedViewCount--;
173     if (isInitialized())
174         emit initDone();
175 }
176
177
178 void BufferViewOverlay::viewInitialized()
179 {
180     BufferViewConfig *config = qobject_cast<BufferViewConfig *>(sender());
181     Q_ASSERT(config);
182
183     viewInitialized(config);
184 }
185
186
187 void BufferViewOverlay::update()
188 {
189     if (_aboutToUpdate) {
190         return;
191     }
192     _aboutToUpdate = true;
193     QCoreApplication::postEvent(this, new QEvent((QEvent::Type)_updateEventId));
194 }
195
196
197 void BufferViewOverlay::updateHelper()
198 {
199     if (!_aboutToUpdate)
200         return;
201
202     bool changed = false;
203
204     int allowedBufferTypes = 0;
205     int minimumActivity = -1;
206     QSet<NetworkId> networkIds;
207     QSet<BufferId> buffers;
208     QSet<BufferId> removedBuffers;
209     QSet<BufferId> tempRemovedBuffers;
210
211     if (Client::bufferViewManager()) {
212         BufferViewConfig *config = 0;
213         QSet<int>::const_iterator viewIter;
214         for (viewIter = _bufferViewIds.constBegin(); viewIter != _bufferViewIds.constEnd(); viewIter++) {
215             config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
216             if (!config)
217                 continue;
218
219             allowedBufferTypes |= config->allowedBufferTypes();
220             if (minimumActivity == -1 || config->minimumActivity() < minimumActivity)
221                 minimumActivity = config->minimumActivity();
222
223             networkIds << config->networkId();
224
225             // we have to apply several filters before we can add a buffer to a category (visible, removed, ...)
226             buffers += filterBuffersByConfig(config->bufferList(), config);
227             tempRemovedBuffers += filterBuffersByConfig(config->temporarilyRemovedBuffers().toList(), config);
228             removedBuffers += config->removedBuffers();
229         }
230
231         // prune the sets from overlap
232         QSet<BufferId> availableBuffers = Client::networkModel()->allBufferIds().toSet();
233
234         buffers.intersect(availableBuffers);
235
236         tempRemovedBuffers.intersect(availableBuffers);
237         tempRemovedBuffers.subtract(buffers);
238
239         removedBuffers.intersect(availableBuffers);
240         removedBuffers.subtract(tempRemovedBuffers);
241         removedBuffers.subtract(buffers);
242     }
243
244     changed |= (allowedBufferTypes != _allowedBufferTypes);
245     changed |= (minimumActivity != _minimumActivity);
246     changed |= (networkIds != _networkIds);
247     changed |= (buffers != _buffers);
248     changed |= (removedBuffers != _removedBuffers);
249     changed |= (tempRemovedBuffers != _tempRemovedBuffers);
250
251     _allowedBufferTypes = allowedBufferTypes;
252     _minimumActivity = minimumActivity;
253     _networkIds = networkIds;
254     _buffers = buffers;
255     _removedBuffers = removedBuffers;
256     _tempRemovedBuffers = tempRemovedBuffers;
257
258     _aboutToUpdate = false;
259
260     if (changed)
261         emit hasChanged();
262 }
263
264
265 QSet<BufferId> BufferViewOverlay::filterBuffersByConfig(const QList<BufferId> &buffers, const BufferViewConfig *config)
266 {
267     Q_ASSERT(config);
268
269     QSet<BufferId> bufferIds;
270     BufferInfo bufferInfo;
271     foreach(BufferId bufferId, buffers) {
272         bufferInfo = Client::networkModel()->bufferInfo(bufferId);
273         if (!(bufferInfo.type() & config->allowedBufferTypes()))
274             continue;
275         if (config->networkId().isValid() && bufferInfo.networkId() != config->networkId())
276             continue;
277         bufferIds << bufferId;
278     }
279
280     return bufferIds;
281 }
282
283
284 void BufferViewOverlay::customEvent(QEvent *event)
285 {
286     if (event->type() == _updateEventId) {
287         updateHelper();
288     }
289 }
290
291
292 bool BufferViewOverlay::allNetworks()
293 {
294     updateHelper();
295     return _networkIds.contains(NetworkId());
296 }
297
298
299 const QSet<NetworkId> &BufferViewOverlay::networkIds()
300 {
301     updateHelper();
302     return _networkIds;
303 }
304
305
306 const QSet<BufferId> &BufferViewOverlay::bufferIds()
307 {
308     updateHelper();
309     return _buffers;
310 }
311
312
313 const QSet<BufferId> &BufferViewOverlay::removedBufferIds()
314 {
315     updateHelper();
316     return _removedBuffers;
317 }
318
319
320 const QSet<BufferId> &BufferViewOverlay::tempRemovedBufferIds()
321 {
322     updateHelper();
323     return _tempRemovedBuffers;
324 }
325
326
327 int BufferViewOverlay::allowedBufferTypes()
328 {
329     updateHelper();
330     return _allowedBufferTypes;
331 }
332
333
334 int BufferViewOverlay::minimumActivity()
335 {
336     updateHelper();
337     return _minimumActivity;
338 }