1/***************************************************************************
2 * Copyright (C) 2005-2014 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
31const int BufferViewOverlay::_updateEventId = QEvent::registerEventType();
32
33BufferViewOverlay::BufferViewOverlay(QObject *parent)
34 : QObject(parent),
35 _aboutToUpdate(false),
36 _uninitializedViewCount(0),
37 _allowedBufferTypes(0),
38 _minimumActivity(0)
39{
40}
41
42
43void 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
60void BufferViewOverlay::save()
61{
62 CoreAccountSettings().setBufferViewOverlay(_bufferViewIds);
63}
64
65
66void 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
79void 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
125void 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
158void 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
178void BufferViewOverlay::viewInitialized()
179{
180 BufferViewConfig *config = qobject_cast<BufferViewConfig *>(sender());
181 Q_ASSERT(config);
182
183 viewInitialized(config);
184}
185
186
187void BufferViewOverlay::update()
188{
189 if (_aboutToUpdate) {
190 return;
191 }
192 _aboutToUpdate = true;
193 QCoreApplication::postEvent(this, new QEvent((QEvent::Type)_updateEventId));
194}
195
196
197void 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
265QSet<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
284void BufferViewOverlay::customEvent(QEvent *event)
285{
286 if (event->type() == _updateEventId) {
287 updateHelper();
288 }
289}
290
291
292bool BufferViewOverlay::allNetworks()
293{
294 updateHelper();
295 return _networkIds.contains(NetworkId());
296}
297
298
299const QSet<NetworkId> &BufferViewOverlay::networkIds()
300{
301 updateHelper();
302 return _networkIds;
303}
304
305
306const QSet<BufferId> &BufferViewOverlay::bufferIds()
307{
308 updateHelper();
309 return _buffers;
310}
311
312
313const QSet<BufferId> &BufferViewOverlay::removedBufferIds()
314{
315 updateHelper();
316 return _removedBuffers;
317}
318
319
320const QSet<BufferId> &BufferViewOverlay::tempRemovedBufferIds()
321{
322 updateHelper();
323 return _tempRemovedBuffers;
324}
325
326
327int BufferViewOverlay::allowedBufferTypes()
328{
329 updateHelper();
330 return _allowedBufferTypes;
331}
332
333
334int BufferViewOverlay::minimumActivity()
335{
336 updateHelper();
337 return _minimumActivity;
338}
339