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