BufferViewOverlay now correctly respects filtering of buffer types
[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 "clientbufferviewmanager.h"
28 #include "networkmodel.h"
29
30 const int BufferViewOverlay::_updateEventId = QEvent::registerEventType();
31
32 BufferViewOverlay::BufferViewOverlay(QObject *parent)
33   : QObject(parent),
34     _aboutToUpdate(false),
35     _uninitializedViewCount(0),
36     _allowedBufferTypes(0),
37     _minimumActivity(0)
38 {
39 }
40
41 void BufferViewOverlay::addView(int viewId) {
42   if(_bufferViewIds.contains(viewId))
43     return;
44
45   BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId);
46   if(!config) {
47     qDebug() << "BufferViewOverlay::addView(): no such buffer view:" << viewId;
48     return;
49   }
50
51   _bufferViewIds << viewId;
52   _uninitializedViewCount++;
53   if(config->isInitialized()) {
54     viewInitialized(config);
55   } else {
56     disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
57     // we use a queued connection here since manipulating the connection list of a sending object
58     // doesn't seem to be such a good idea while executing a connected slots.
59     connect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()), Qt::QueuedConnection);
60   }
61 }
62
63 void BufferViewOverlay::removeView(int viewId) {
64   if(!_bufferViewIds.contains(viewId))
65     return;
66
67   _bufferViewIds.remove(viewId);
68   BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId);
69   if(config)
70     disconnect(config, 0, this, 0);
71
72   // update initialized State:
73   bool wasInitialized = isInitialized();
74   _uninitializedViewCount = 0;
75   QSet<int>::iterator viewIter = _bufferViewIds.begin();
76   while(viewIter != _bufferViewIds.end()) {
77     config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
78     if(!config) {
79       viewIter = _bufferViewIds.erase(viewIter);
80     } else {
81       if(!config->isInitialized())
82         _uninitializedViewCount++;
83       viewIter++;
84     }
85   }
86
87   update();
88   if(!wasInitialized && isInitialized())
89     emit initDone();
90 }
91
92 void BufferViewOverlay::viewInitialized(BufferViewConfig *config) {
93   if(!config) {
94     qWarning() << "BufferViewOverlay::viewInitialized() received invalid view!";
95     return;
96   }
97   disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
98
99   connect(config, SIGNAL(configChanged()), this, SLOT(update()));
100 //   connect(config, SIGNAL(networkIdSet(const NetworkId &)), this, SLOT(update()));
101 //   connect(config, SIGNAL(sortAlphabeticallySet(bool)), this, SLOT(update()));
102 //   connect(config, SIGNAL(allowedBufferTypesSet(int)), this, SLOT(update()));
103 //   connect(config, SIGNAL(minimumActivitySet(int)), this, SLOT(update()));
104 //   connect(config, SIGNAL(bufferListSet()), this, SLOT(update()));
105 //   connect(config, SIGNAL(bufferAdded(const BufferId &, int)), this, SLOT(update()));
106 //   connect(config, SIGNAL(bufferRemoved(const BufferId &)), this, SLOT(update()));
107 //   connect(config, SIGNAL(bufferPermanentlyRemoved(const BufferId &)), this, SLOT(update()));
108
109   // check if the view was removed in the meantime...
110   if(_bufferViewIds.contains(config->bufferViewId()))
111     update();
112
113   _uninitializedViewCount--;
114   if(isInitialized())
115     emit initDone();
116 }
117
118 void BufferViewOverlay::viewInitialized() {
119   BufferViewConfig *config = qobject_cast<BufferViewConfig *>(sender());
120   Q_ASSERT(config);
121
122   viewInitialized(config);
123 }
124
125 void BufferViewOverlay::update() {
126   if(_aboutToUpdate) {
127     return;
128   }
129   _aboutToUpdate = true;
130   QCoreApplication::postEvent(this, new QEvent((QEvent::Type)_updateEventId));
131 }
132
133 void BufferViewOverlay::updateHelper() {
134   if(!_aboutToUpdate)
135     return;
136
137   bool changed = false;
138
139   int allowedBufferTypes = 0;
140   int minimumActivity = -1;
141   QSet<NetworkId> networkIds;
142   QSet<BufferId> buffers;
143   QSet<BufferId> removedBuffers;
144   QSet<BufferId> tempRemovedBuffers;
145
146   if(Client::bufferViewManager()) {
147     BufferViewConfig *config = 0;
148     QSet<int>::const_iterator viewIter;
149     for(viewIter = _bufferViewIds.constBegin(); viewIter != _bufferViewIds.constEnd(); viewIter++) {
150       config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
151       if(!config)
152         continue;
153
154       allowedBufferTypes |= config->allowedBufferTypes();
155       if(minimumActivity == -1 || config->minimumActivity() < minimumActivity)
156         minimumActivity = config->minimumActivity();
157
158       networkIds << config->networkId();
159
160
161       // we have to apply several filters before we can add a buffer to a category (visible, removed, ...)
162       buffers += filterBuffersByConfig(config->bufferList(), config);
163       tempRemovedBuffers += filterBuffersByConfig(config->temporarilyRemovedBuffers().toList(), config);
164       removedBuffers += config->removedBuffers();
165     }
166
167     // prune the sets from overlap
168     QSet<BufferId> availableBuffers = Client::networkModel()->allBufferIds().toSet();
169
170     buffers.intersect(availableBuffers);
171
172     tempRemovedBuffers.intersect(availableBuffers);
173     tempRemovedBuffers.subtract(buffers);
174
175     removedBuffers.intersect(availableBuffers);
176     removedBuffers.subtract(tempRemovedBuffers);
177     removedBuffers.subtract(buffers);
178   }
179
180   changed |= (allowedBufferTypes != _allowedBufferTypes);
181   changed |= (minimumActivity != _minimumActivity);
182   changed |= (networkIds != _networkIds);
183   changed |= (buffers != _buffers);
184   changed |= (removedBuffers != _removedBuffers);
185   changed |= (tempRemovedBuffers != _tempRemovedBuffers);
186
187   _allowedBufferTypes = allowedBufferTypes;
188   _minimumActivity = minimumActivity;
189   _networkIds = networkIds;
190   _buffers = buffers;
191   _removedBuffers = removedBuffers;
192   _tempRemovedBuffers = tempRemovedBuffers;
193
194   _aboutToUpdate = false;
195
196   if(changed)
197     emit hasChanged();
198 }
199
200 QSet<BufferId> BufferViewOverlay::filterBuffersByConfig(const QList<BufferId> &buffers, const BufferViewConfig *config) {
201   Q_ASSERT(config);
202
203   QSet<BufferId> bufferIds;
204   BufferInfo bufferInfo;
205   foreach(BufferId bufferId, buffers) {
206     bufferInfo = Client::networkModel()->bufferInfo(bufferId);
207     if(!(bufferInfo.type() & config->allowedBufferTypes()))
208       continue;
209     if(config->networkId().isValid() && bufferInfo.networkId() != config->networkId())
210       continue;
211     bufferIds << bufferId;
212   }
213
214   return bufferIds;
215 }
216
217
218 void BufferViewOverlay::customEvent(QEvent *event) {
219   if(event->type() == _updateEventId) {
220     updateHelper();
221   }
222 }
223
224 bool BufferViewOverlay::allNetworks() {
225   updateHelper();
226   return _networkIds.contains(NetworkId());
227 }
228
229 const QSet<NetworkId> &BufferViewOverlay::networkIds() {
230   updateHelper();
231   return _networkIds;
232 }
233
234 const QSet<BufferId> &BufferViewOverlay::bufferIds() {
235   updateHelper();
236   return _buffers;
237 }
238
239 const QSet<BufferId> &BufferViewOverlay::removedBufferIds() {
240   updateHelper();
241   return _removedBuffers;
242 }
243
244 const QSet<BufferId> &BufferViewOverlay::tempRemovedBufferIds() {
245   updateHelper();
246   return _tempRemovedBuffers;
247 }
248
249 int BufferViewOverlay::allowedBufferTypes() {
250   updateHelper();
251   return _allowedBufferTypes;
252 }
253
254 int BufferViewOverlay::minimumActivity() {
255   updateHelper();
256   return _minimumActivity;
257 }