Fix initial backlog for buffers with no new messages
[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     // we use a queued connection here since manipulating the connection list of a sending object
60     // doesn't seem to be such a good idea while executing a connected slots.
61     connect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()), Qt::QueuedConnection);
62   }
63 }
64
65 void BufferViewOverlay::removeView(int viewId) {
66   if(!_bufferViewIds.contains(viewId))
67     return;
68
69   _bufferViewIds.remove(viewId);
70   BufferViewConfig *config = Client::bufferViewManager()->bufferViewConfig(viewId);
71   if(config)
72     disconnect(config, 0, this, 0);
73
74   // update initialized State:
75   bool wasInitialized = isInitialized();
76   _uninitializedViewCount = 0;
77   QSet<int>::iterator viewIter = _bufferViewIds.begin();
78   while(viewIter != _bufferViewIds.end()) {
79     config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
80     if(!config) {
81       viewIter = _bufferViewIds.erase(viewIter);
82     } else {
83       if(!config->isInitialized())
84         _uninitializedViewCount++;
85       viewIter++;
86     }
87   }
88
89   update();
90   if(!wasInitialized && isInitialized())
91     emit initDone();
92 }
93
94 void BufferViewOverlay::viewInitialized(BufferViewConfig *config) {
95   if(!config) {
96     qWarning() << "BufferViewOverlay::viewInitialized() received invalid view!";
97     return;
98   }
99   disconnect(config, SIGNAL(initDone()), this, SLOT(viewInitialized()));
100
101   connect(config, SIGNAL(configChanged()), this, SLOT(update()));  
102 //   connect(config, SIGNAL(networkIdSet(const NetworkId &)), this, SLOT(update()));
103 //   connect(config, SIGNAL(addNewBuffersAutomaticallySet(bool)), this, SLOT(update()));
104 //   connect(config, SIGNAL(sortAlphabeticallySet(bool)), this, SLOT(update()));
105 //   connect(config, SIGNAL(hideInactiveBuffersSet(bool)), this, SLOT(update()));
106 //   connect(config, SIGNAL(allowedBufferTypesSet(int)), this, SLOT(update()));
107 //   connect(config, SIGNAL(minimumActivitySet(int)), this, SLOT(update()));
108 //   connect(config, SIGNAL(bufferListSet()), this, SLOT(update()));
109 //   connect(config, SIGNAL(bufferAdded(const BufferId &, int)), this, SLOT(update()));
110 //   connect(config, SIGNAL(bufferRemoved(const BufferId &)), this, SLOT(update()));
111 //   connect(config, SIGNAL(bufferPermanentlyRemoved(const BufferId &)), this, SLOT(update()));
112
113   // check if the view was removed in the meantime...
114   if(_bufferViewIds.contains(config->bufferViewId()))
115     update();
116
117   _uninitializedViewCount--;
118   if(isInitialized())
119     emit initDone();
120 }
121
122 void BufferViewOverlay::viewInitialized() {
123   BufferViewConfig *config = qobject_cast<BufferViewConfig *>(sender());
124   Q_ASSERT(config);
125
126   viewInitialized(config);
127 }
128
129 void BufferViewOverlay::update() {
130   if(_aboutToUpdate) {
131     return;
132   }
133   _aboutToUpdate = true;
134   QCoreApplication::postEvent(this, new QEvent((QEvent::Type)_updateEventId));
135 }
136
137 void BufferViewOverlay::updateHelper() {
138   if(!_aboutToUpdate)
139     return;
140
141   bool changed = false;
142
143   bool addBuffersAutomatically = false;
144   bool hideInactiveBuffers = true;
145   int allowedBufferTypes = 0;
146   int minimumActivity = -1;
147   QSet<NetworkId> networkIds;
148   QSet<BufferId> buffers;
149   QSet<BufferId> removedBuffers;
150   QSet<BufferId> tempRemovedBuffers;
151
152   if(Client::bufferViewManager()) {
153     BufferViewConfig *config = 0;
154     QSet<int>::const_iterator viewIter;
155     for(viewIter = _bufferViewIds.constBegin(); viewIter != _bufferViewIds.constEnd(); viewIter++) {
156       config = Client::bufferViewManager()->bufferViewConfig(*viewIter);
157       if(!config)
158         continue;
159
160       networkIds << config->networkId();
161       if(config->networkId().isValid()) {
162         NetworkId networkId = config->networkId();
163         // we have to filter out all the buffers that don't belong to this net... :/
164         QSet<BufferId> bufferIds;
165         foreach(BufferId bufferId, config->bufferList()) {
166           if(Client::networkModel()->networkId(bufferId) == networkId)
167             bufferIds << bufferId;
168         }
169         buffers += bufferIds;
170
171         bufferIds.clear();
172         foreach(BufferId bufferId, config->temporarilyRemovedBuffers()) {
173           if(Client::networkModel()->networkId(bufferId) == networkId)
174             bufferIds << bufferId;
175         }
176         tempRemovedBuffers += bufferIds;
177       } else {
178         buffers += config->bufferList().toSet();
179         tempRemovedBuffers += config->temporarilyRemovedBuffers();
180       }
181
182       // in the overlay a buffer is removed it is removed from all views
183       if(removedBuffers.isEmpty())
184         removedBuffers = config->removedBuffers();
185       else
186         removedBuffers.intersect(config->removedBuffers());
187
188
189       addBuffersAutomatically |= config->addNewBuffersAutomatically();
190       hideInactiveBuffers &= config->hideInactiveBuffers();
191       allowedBufferTypes |= config->allowedBufferTypes();
192       if(minimumActivity == -1 || config->minimumActivity() < minimumActivity)
193         minimumActivity = config->minimumActivity();
194     }
195     QSet<BufferId> availableBuffers = Client::networkModel()->allBufferIds().toSet();
196     buffers.intersect(availableBuffers);
197     tempRemovedBuffers.intersect(availableBuffers);
198   }
199
200   changed |= (addBuffersAutomatically != _addBuffersAutomatically);
201   changed |= (hideInactiveBuffers != _hideInactiveBuffers);
202   changed |= (allowedBufferTypes != _allowedBufferTypes);
203   changed |= (minimumActivity != _minimumActivity);
204   changed |= (networkIds != _networkIds);
205   changed |= (buffers != _buffers);
206   changed |= (removedBuffers != _removedBuffers);
207   changed |= (tempRemovedBuffers != _tempRemovedBuffers);
208
209   _addBuffersAutomatically = addBuffersAutomatically;
210   _hideInactiveBuffers = hideInactiveBuffers;
211   _allowedBufferTypes = allowedBufferTypes;
212   _minimumActivity = minimumActivity;
213   _networkIds = networkIds;
214   _buffers = buffers;
215   _removedBuffers = removedBuffers;
216   _tempRemovedBuffers = tempRemovedBuffers;
217
218   _aboutToUpdate = false;
219
220   if(changed)
221     emit hasChanged();
222 }
223
224 void BufferViewOverlay::customEvent(QEvent *event) {
225   if(event->type() == _updateEventId) {
226     updateHelper();
227   }
228 }
229
230 bool BufferViewOverlay::allNetworks() {
231   updateHelper();
232   return _networkIds.contains(NetworkId());
233 }
234
235 const QSet<NetworkId> &BufferViewOverlay::networkIds() {
236   updateHelper();
237   return _networkIds;
238 }
239
240 const QSet<BufferId> &BufferViewOverlay::bufferIds() {
241   updateHelper();
242   return _buffers;
243 }
244
245 const QSet<BufferId> &BufferViewOverlay::removedBufferIds() {
246   updateHelper();
247   return _removedBuffers;
248 }
249
250 const QSet<BufferId> &BufferViewOverlay::tempRemovedBufferIds() {
251   updateHelper();
252   return _tempRemovedBuffers;
253 }
254
255 bool BufferViewOverlay::addBuffersAutomatically() {
256   updateHelper();
257   return _addBuffersAutomatically;
258 }
259
260 bool BufferViewOverlay::hideInactiveBuffers() {
261   updateHelper();
262   return _hideInactiveBuffers;
263 }
264
265 int BufferViewOverlay::allowedBufferTypes() {
266   updateHelper();
267   return _allowedBufferTypes;
268 }
269
270 int BufferViewOverlay::minimumActivity() {
271   updateHelper();
272   return _minimumActivity;
273 }