Fixes #682 - Core crashes on client connection
[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     _addBuffersAutomatically(false),
37     _hideInactiveBuffers(false),
38     _allowedBufferTypes(0),
39     _minimumActivity(0)
40 {
41 }
42
43 void BufferViewOverlay::addView(int viewId) {
44   if(_bufferViewIds.contains(viewId))
45     return;
46
47   BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId);
48   if(!config) {
49     qDebug() << "BufferViewOverlay::addView(): no such buffer view:" << viewId;
50     return;
51   }
52
53   _bufferViewIds << viewId;
54   _uninitializedViewCount++;
55   if(config->isInitialized()) {
56     viewInitialized(config);
57   } else {
58     disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
59     connect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
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(networkIdSet(const NetworkId &)), this, SLOT(update()));
100   connect(config, SIGNAL(addNewBuffersAutomaticallySet(bool)), this, SLOT(update()));
101   connect(config, SIGNAL(sortAlphabeticallySet(bool)), this, SLOT(update()));
102   connect(config, SIGNAL(hideInactiveBuffersSet(bool)), this, SLOT(update()));
103   connect(config, SIGNAL(allowedBufferTypesSet(int)), this, SLOT(update()));
104   connect(config, SIGNAL(minimumActivitySet(int)), this, SLOT(update()));
105   connect(config, SIGNAL(bufferListSet()), this, SLOT(update()));
106   connect(config, SIGNAL(bufferAdded(const BufferId &, int)), this, SLOT(update()));
107   connect(config, SIGNAL(bufferRemoved(const BufferId &)), this, SLOT(update()));
108   connect(config, SIGNAL(bufferPermanentlyRemoved(const BufferId &)), this, SLOT(update()));
109
110   // check if the view was removed in the meantime...
111   if(_bufferViewIds.contains(config->bufferViewId()))
112     update();
113
114   _uninitializedViewCount--;
115   if(isInitialized())
116     emit initDone();
117 }
118
119 void BufferViewOverlay::viewInitialized() {
120   BufferViewConfig *config = qobject_cast<BufferViewConfig *>(sender());
121   Q_ASSERT(config);
122
123   viewInitialized(config);
124 }
125
126 void BufferViewOverlay::update() {
127   if(_aboutToUpdate) {
128     return;
129   }
130   _aboutToUpdate = true;
131   QCoreApplication::postEvent(this, new QEvent((QEvent::Type)_updateEventId));
132 }
133
134 void BufferViewOverlay::updateHelper() {
135   if(!_aboutToUpdate)
136     return;
137
138   bool changed = false;
139
140   bool addBuffersAutomatically = false;
141   bool hideInactiveBuffers = true;
142   int allowedBufferTypes = 0;
143   int minimumActivity = -1;
144   QSet<NetworkId> networkIds;
145   QSet<BufferId> buffers;
146   QSet<BufferId> removedBuffers;
147   QSet<BufferId> tempRemovedBuffers;
148
149   if(Client::bufferViewManager()) {
150     BufferViewConfig *config = 0;
151     QSet<int>::const_iterator viewIter;
152     for(viewIter = _bufferViewIds.constBegin(); viewIter != _bufferViewIds.constEnd(); viewIter++) {
153       config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
154       if(!config)
155         continue;
156
157       networkIds << config->networkId();
158       if(config->networkId().isValid()) {
159         NetworkId networkId = config->networkId();
160         // we have to filter out all the buffers that don't belong to this net... :/
161         QSet<BufferId> bufferIds;
162         foreach(BufferId bufferId, config->bufferList()) {
163           if(Client::networkModel()->networkId(bufferId) == networkId)
164             bufferIds << bufferId;
165         }
166         buffers += bufferIds;
167
168         bufferIds.clear();
169         foreach(BufferId bufferId, config->temporarilyRemovedBuffers()) {
170           if(Client::networkModel()->networkId(bufferId) == networkId)
171             bufferIds << bufferId;
172         }
173         tempRemovedBuffers += bufferIds;
174       } else {
175         buffers += config->bufferList().toSet();
176         tempRemovedBuffers += config->temporarilyRemovedBuffers();
177       }
178
179       // in the overlay a buffer is removed it is removed from all views
180       if(removedBuffers.isEmpty())
181         removedBuffers = config->removedBuffers();
182       else
183         removedBuffers.intersect(config->removedBuffers());
184
185
186       addBuffersAutomatically |= config->addNewBuffersAutomatically();
187       hideInactiveBuffers &= config->hideInactiveBuffers();
188       allowedBufferTypes |= config->allowedBufferTypes();
189       if(minimumActivity == -1 || config->minimumActivity() < minimumActivity)
190         minimumActivity = config->minimumActivity();
191     }
192     QSet<BufferId> availableBuffers = Client::networkModel()->allBufferIds().toSet();
193     buffers.intersect(availableBuffers);
194     tempRemovedBuffers.intersect(availableBuffers);
195   }
196
197   changed |= (addBuffersAutomatically != _addBuffersAutomatically);
198   changed |= (hideInactiveBuffers != _hideInactiveBuffers);
199   changed |= (allowedBufferTypes != _allowedBufferTypes);
200   changed |= (minimumActivity != _minimumActivity);
201   changed |= (networkIds != _networkIds);
202   changed |= (buffers != _buffers);
203   changed |= (removedBuffers != _removedBuffers);
204   changed |= (tempRemovedBuffers != _tempRemovedBuffers);
205
206   _addBuffersAutomatically = addBuffersAutomatically;
207   _hideInactiveBuffers = hideInactiveBuffers;
208   _allowedBufferTypes = allowedBufferTypes;
209   _minimumActivity = minimumActivity;
210   _networkIds = networkIds;
211   _buffers = buffers;
212   _removedBuffers = removedBuffers;
213   _tempRemovedBuffers = tempRemovedBuffers;
214
215   _aboutToUpdate = false;
216
217   if(changed)
218     emit hasChanged();
219 }
220
221 void BufferViewOverlay::customEvent(QEvent *event) {
222   if(event->type() == _updateEventId) {
223     updateHelper();
224   }
225 }
226
227 bool BufferViewOverlay::allNetworks() {
228   updateHelper();
229   return _networkIds.contains(NetworkId());
230 }
231
232 const QSet<NetworkId> &BufferViewOverlay::networkIds() {
233   updateHelper();
234   return _networkIds;
235 }
236
237 const QSet<BufferId> &BufferViewOverlay::bufferIds() {
238   updateHelper();
239   return _buffers;
240 }
241
242 const QSet<BufferId> &BufferViewOverlay::removedBufferIds() {
243   updateHelper();
244   return _removedBuffers;
245 }
246
247 const QSet<BufferId> &BufferViewOverlay::tempRemovedBufferIds() {
248   updateHelper();
249   return _tempRemovedBuffers;
250 }
251
252 bool BufferViewOverlay::addBuffersAutomatically() {
253   updateHelper();
254   return _addBuffersAutomatically;
255 }
256
257 bool BufferViewOverlay::hideInactiveBuffers() {
258   updateHelper();
259   return _hideInactiveBuffers;
260 }
261
262 int BufferViewOverlay::allowedBufferTypes() {
263   updateHelper();
264   return _allowedBufferTypes;
265 }
266
267 int BufferViewOverlay::minimumActivity() {
268   updateHelper();
269   return _minimumActivity;
270 }