fixes to the new buffer views. also disabled the min-activity as it results in nasty...
[quassel.git] / src / qtui / settingspages / bufferviewsettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-08 by the Quassel IRC Team                         *
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 "bufferviewsettingspage.h"
22
23 #include <QMessageBox>
24
25 #include "client.h"
26 #include "network.h"
27 #include "bufferviewconfig.h"
28 #include "bufferviewfilter.h"
29 #include "bufferviewmanager.h"
30 #include "buffermodel.h"
31 #include "networkmodel.h"
32
33 BufferViewSettingsPage::BufferViewSettingsPage(QWidget *parent)
34   : SettingsPage(tr("General"), tr("Buffer Views"), parent),
35     _ignoreWidgetChanges(false)
36 {
37   ui.setupUi(this);
38   reset();
39
40   ui.bufferViewList->setSortingEnabled(true);
41   ui.settingsGroupBox->setEnabled(false);
42   ui.bufferViewPreview->setEnabled(false);
43
44   setEnabled(Client::isConnected());  // need a core connection!
45   connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
46   connect(ui.bufferViewList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
47           this, SLOT(bufferViewSelectionChanged(const QItemSelection &, const QItemSelection &)));
48
49   connect(ui.onlyStatusBuffers, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
50   connect(ui.onlyChannelBuffers, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
51   connect(ui.onlyQueryBuffers, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
52   connect(ui.addNewBuffersAutomatically, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
53   connect(ui.sortAlphabetically, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
54   connect(ui.hideInactiveBuffers, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
55   connect(ui.networkSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
56   connect(ui.minimumActivitySelector, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
57
58   // FIXME: (see FIXME in BufferViewFilter::filterAcceptBuffer())
59   ui.minimumActivitySelector->setEnabled(false);
60 }
61
62 BufferViewSettingsPage::~BufferViewSettingsPage() {
63   reset();
64 }
65
66 void BufferViewSettingsPage::reset() {
67   ui.bufferViewList->clear();
68
69   QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIter = _changedBufferViews.begin();
70   QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIterEnd = _changedBufferViews.end();
71   BufferViewConfig *config;
72   while(changedConfigIter != changedConfigIterEnd) {
73     config = changedConfigIter.value();
74     changedConfigIter = _changedBufferViews.erase(changedConfigIter);
75     config->deleteLater();
76   }
77
78   QList<BufferViewConfig *>::iterator newConfigIter = _newBufferViews.begin();
79   QList<BufferViewConfig *>::iterator newConfigIterEnd = _newBufferViews.end();
80   while(newConfigIter != newConfigIterEnd) {
81     config = *newConfigIter;
82     newConfigIter = _newBufferViews.erase(newConfigIter);
83     config->deleteLater();
84   }
85
86   _deleteBufferViews.clear();
87   
88   setChangedState(false);
89 }
90
91 void BufferViewSettingsPage::load() {
92   reset();
93
94   if(!Client::bufferViewManager())
95     return;
96
97   const QList<BufferViewConfig *> bufferViewConfigs = Client::bufferViewManager()->bufferViewConfigs();
98   foreach(BufferViewConfig *bufferViewConfig, bufferViewConfigs) {
99     addBufferView(bufferViewConfig);
100   }
101
102   _ignoreWidgetChanges = true;
103   // load network selector
104   ui.networkSelector->clear();
105   ui.networkSelector->addItem("All");
106   ui.networkSelector->setItemData(0, qVariantFromValue<NetworkId>(NetworkId()));
107   const Network *net;
108   foreach(NetworkId netId, Client::networkIds()) {
109     net = Client::network(netId);
110     ui.networkSelector->addItem(net->networkName());
111     ui.networkSelector->setItemData(ui.networkSelector->count() - 1, qVariantFromValue<NetworkId>(net->networkId()));
112   }
113   _ignoreWidgetChanges = false;
114   
115   ui.bufferViewList->setCurrentRow(0);
116 }
117
118 void BufferViewSettingsPage::save() {
119   setEnabled(false);
120   QVariantList newConfigs;
121   QVariantList deleteConfigs;
122   QVariantList changedConfigs;
123
124   foreach(int bufferId, _deleteBufferViews) {
125     deleteConfigs << bufferId;
126   }
127   _deleteBufferViews.clear();
128   if(Client::bufferViewManager()) {
129     Client::bufferViewManager()->requestDeleteBufferViews(deleteConfigs);
130   }
131   
132   QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIter = _changedBufferViews.begin();
133   QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIterEnd = _changedBufferViews.end();
134   BufferViewConfig *config, *changedConfig;
135   while(changedConfigIter != changedConfigIterEnd) {
136     config = changedConfigIter.key();
137     changedConfig = changedConfigIter.value();
138     changedConfigIter = _changedBufferViews.erase(changedConfigIter);
139     config->requestUpdate(changedConfig->toVariantMap());
140     changedConfig->deleteLater();
141   }
142
143   QList<BufferViewConfig *>::iterator newConfigIter = _newBufferViews.begin();
144   QList<BufferViewConfig *>::iterator newConfigIterEnd = _newBufferViews.end();
145   while(newConfigIter != newConfigIterEnd) {
146     config = *newConfigIter;
147     newConfigIter = _newBufferViews.erase(newConfigIter);
148     newConfigs << config->toVariantMap();
149     config->deleteLater();
150   }
151   if(Client::bufferViewManager()) {
152     Client::bufferViewManager()->requestCreateBufferViews(newConfigs);
153   }
154
155   load();
156   setEnabled(true);
157 }
158
159 void BufferViewSettingsPage::coreConnectionStateChanged(bool state) {
160   setEnabled(state);
161   if(state) {
162     load();
163     connect(Client::bufferViewManager(), SIGNAL(bufferViewConfigAdded(int)), this, SLOT(addBufferView(int)));
164   } else {
165     reset();
166   }
167 }
168
169 void BufferViewSettingsPage::addBufferView(BufferViewConfig *config) {
170   QListWidgetItem *item = new QListWidgetItem(config->bufferViewName(), ui.bufferViewList);
171   item->setData(Qt::UserRole, qVariantFromValue<QObject *>(qobject_cast<QObject *>(config)));
172   connect(config, SIGNAL(updatedRemotely()), this, SLOT(updateBufferView()));
173   connect(config, SIGNAL(destroyed()), this, SLOT(bufferViewDeleted()));
174 }
175
176 void BufferViewSettingsPage::addBufferView(int bufferViewId) {
177   Q_ASSERT(Client::bufferViewManager());
178   addBufferView(Client::bufferViewManager()->bufferViewConfig(bufferViewId));
179 }
180
181 void BufferViewSettingsPage::bufferViewDeleted() {
182   BufferViewConfig *config = static_cast<BufferViewConfig *>(sender());
183   QObject *obj;
184   for(int i = 0; i < ui.bufferViewList->count(); i++) {
185     obj = ui.bufferViewList->item(i)->data(Qt::UserRole).value<QObject *>();
186     if(config == static_cast<BufferViewConfig *>(obj)) {
187       QListWidgetItem *item = ui.bufferViewList->takeItem(i);
188       delete item;
189       return;
190     }
191   }
192 }
193
194 void BufferViewSettingsPage::newBufferView(const QString &bufferViewName) {
195   // id's of newly created bufferviews are negative (-1, -2... -n)
196   int fakeId = -1 * (_newBufferViews.count() + 1);
197   BufferViewConfig *config = new BufferViewConfig(fakeId);
198   config->setBufferViewName(bufferViewName);
199
200   QList<BufferId> bufferIds;
201   if(config->addNewBuffersAutomatically()) {
202     foreach(BufferInfo bufferInfo, Client::allBufferInfos()) {
203       bufferIds << bufferInfo.bufferId();
204     }
205     if(config->sortAlphabetically())
206       qSort(bufferIds.begin(), bufferIds.end(), bufferIdLessThan);
207   }
208   config->initSetBufferList(bufferIds);
209
210   _newBufferViews << config;
211   addBufferView(config);
212   ui.bufferViewList->setCurrentRow(listPos(config));
213 }
214       
215 int BufferViewSettingsPage::listPos(BufferViewConfig *config) {
216   QObject *obj;
217   for(int i = 0; i < ui.bufferViewList->count(); i++) {
218     obj = ui.bufferViewList->item(i)->data(Qt::UserRole).value<QObject *>();
219     if(config == qobject_cast<BufferViewConfig *>(obj))
220       return i;
221   }
222   return -1;
223 }
224
225 BufferViewConfig *BufferViewSettingsPage::bufferView(int listPos) {
226   if(listPos < ui.bufferViewList->count() && listPos >= 0) {
227     QObject *obj = ui.bufferViewList->item(listPos)->data(Qt::UserRole).value<QObject *>();
228     return qobject_cast<BufferViewConfig *>(obj);
229   } else {
230     return 0;
231   }
232 }
233
234 void BufferViewSettingsPage::updateBufferView() {
235   BufferViewConfig *config = qobject_cast<BufferViewConfig *>(sender());
236   if(!config)
237     return;
238
239   int itemPos = listPos(config);
240   if(itemPos == -1) {
241     qWarning() << "BufferViewSettingsPage::updateBufferView(): view is unknown:" << config->bufferViewId();
242     return;
243   }
244   ui.bufferViewList->item(itemPos)->setText(config->bufferViewName());
245   if(itemPos == ui.bufferViewList->currentRow())
246     loadConfig(config);
247 }
248
249 void BufferViewSettingsPage::on_addBufferView_clicked() {
250   if(!Client::bufferViewManager())
251     return;
252   
253   QStringList existing;
254   foreach(BufferViewConfig *bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
255     existing << bufferConfig->bufferViewName();
256   }
257
258   BufferViewEditDlg dlg(QString(), existing, this);
259   if(dlg.exec() == QDialog::Accepted) {
260     newBufferView(dlg.bufferViewName());
261     changed();
262   }
263 }
264
265 void BufferViewSettingsPage::on_renameBufferView_clicked() {
266   if(ui.bufferViewList->selectedItems().isEmpty())
267     return;
268
269   if(!Client::bufferViewManager())
270     return;
271   
272   BufferViewConfig *config = bufferView(ui.bufferViewList->currentRow());
273   if(!config)
274     return;
275
276   QStringList existing;
277   foreach(BufferViewConfig *bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
278     existing << bufferConfig->bufferViewName();
279   }
280
281   BufferViewEditDlg dlg(config->bufferViewName(), existing, this);
282   if(dlg.exec() == QDialog::Accepted) {
283     BufferViewConfig *changedConfig = cloneConfig(config);
284     changedConfig->setBufferViewName(dlg.bufferViewName());
285     ui.bufferViewList->item(listPos(config))->setText(dlg.bufferViewName());
286     changed();
287   }
288 }
289
290 void BufferViewSettingsPage::on_deleteBufferView_clicked() {
291   if(ui.bufferViewList->selectedItems().isEmpty())
292     return;
293
294   QListWidgetItem *currentItem = ui.bufferViewList->item(ui.bufferViewList->currentRow());
295   QString viewName = currentItem->text();
296   int viewId = bufferView(ui.bufferViewList->currentRow())->bufferViewId();
297   int ret = QMessageBox::question(this, tr("Delete Buffer View?"),
298                                     tr("Do you really want to delete the buffer view \"%1\"?").arg(viewName),
299                                     QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
300
301   if(ret == QMessageBox::Yes) {
302     ui.bufferViewList->removeItemWidget(currentItem);
303     delete currentItem;
304     if(viewId >= 0)
305       _deleteBufferViews << viewId;
306     changed();
307   }
308 }
309
310 void BufferViewSettingsPage::bufferViewSelectionChanged(const QItemSelection &current, const QItemSelection &previous) {
311   Q_UNUSED(previous)
312
313   if(!current.isEmpty()) {
314     ui.settingsGroupBox->setEnabled(true);
315     ui.bufferViewPreview->setEnabled(true);
316
317     loadConfig(configForDisplay(bufferView(ui.bufferViewList->currentRow())));
318   } else {
319     ui.settingsGroupBox->setEnabled(false);
320     ui.bufferViewPreview->setEnabled(false);
321   }
322 }
323
324 void BufferViewSettingsPage::loadConfig(BufferViewConfig *config) {
325   if(!config)
326     return;
327   
328   _ignoreWidgetChanges = true;
329   ui.onlyStatusBuffers->setChecked(BufferInfo::StatusBuffer & config->allowedBufferTypes());
330   ui.onlyChannelBuffers->setChecked(BufferInfo::ChannelBuffer & config->allowedBufferTypes());
331   ui.onlyQueryBuffers->setChecked(BufferInfo::QueryBuffer & config->allowedBufferTypes());
332   ui.addNewBuffersAutomatically->setChecked(config->addNewBuffersAutomatically());
333   ui.sortAlphabetically->setChecked(config->sortAlphabetically());
334   ui.hideInactiveBuffers->setChecked(config->hideInactiveBuffers());
335
336   int networkIndex = 0;
337   for(int i = 0; i < ui.networkSelector->count(); i++) {
338     if(ui.networkSelector->itemData(i).value<NetworkId>() == config->networkId()) {
339       networkIndex = i;
340       break;
341     }
342   }
343   ui.networkSelector->setCurrentIndex(networkIndex);
344
345   int activityIndex = 0;
346   int minimumActivity = config->minimumActivity();
347   while(minimumActivity) {
348     activityIndex++;
349     minimumActivity = minimumActivity >> 1;
350   }
351   ui.minimumActivitySelector->setCurrentIndex(activityIndex);
352
353   ui.bufferViewPreview->setFilteredModel(Client::bufferModel(), config);
354   
355   _ignoreWidgetChanges = false;
356 }
357
358 void BufferViewSettingsPage::saveConfig(BufferViewConfig *config) {
359   if(!config)
360     return;
361   
362   int allowedBufferTypes = 0;
363   if(ui.onlyStatusBuffers->isChecked())
364     allowedBufferTypes |= BufferInfo::StatusBuffer;
365   if(ui.onlyChannelBuffers->isChecked())
366     allowedBufferTypes |= BufferInfo::ChannelBuffer;
367   if(ui.onlyQueryBuffers->isChecked())
368     allowedBufferTypes |= BufferInfo::QueryBuffer;
369   config->setAllowedBufferTypes(allowedBufferTypes);
370
371   config->setAddNewBuffersAutomatically(ui.addNewBuffersAutomatically->isChecked());
372   config->setSortAlphabetically(ui.sortAlphabetically->isChecked());
373   config->setHideInactiveBuffers(ui.hideInactiveBuffers->isChecked());
374   config->setNetworkId(ui.networkSelector->itemData(ui.networkSelector->currentIndex()).value<NetworkId>());
375
376   int minimumActivity = 0;
377   if(ui.minimumActivitySelector->currentIndex() > 0)
378     minimumActivity = 1 << (ui.minimumActivitySelector->currentIndex() - 1);
379   config->setMinimumActivity(minimumActivity);
380
381   if(_newBufferViews.contains(config)) {
382     QList<BufferId> bufferIds;
383     if(config->addNewBuffersAutomatically()) {
384       foreach(BufferInfo bufferInfo, Client::allBufferInfos()) {
385         bufferIds << bufferInfo.bufferId();
386       }
387       if(config->sortAlphabetically())
388         qSort(bufferIds.begin(), bufferIds.end(), bufferIdLessThan);
389     }
390     config->initSetBufferList(bufferIds);
391   }
392 }
393
394 void BufferViewSettingsPage::widgetHasChanged() {
395   if(_ignoreWidgetChanges)
396     return;
397   setChangedState(testHasChanged());
398 }
399
400 bool BufferViewSettingsPage::testHasChanged() {
401   saveConfig(cloneConfig(bufferView(ui.bufferViewList->currentRow())));
402
403   if(!_newBufferViews.isEmpty())
404     return true;
405
406   bool changed = false;
407   QHash<BufferViewConfig *, BufferViewConfig *>::iterator iter = _changedBufferViews.begin();
408   QHash<BufferViewConfig *, BufferViewConfig *>::iterator iterEnd = _changedBufferViews.end();
409   while(iter != iterEnd) {
410     if(&(iter.key()) == &(iter.value())) {
411       iter.value()->deleteLater();
412       _changedBufferViews.erase(iter);
413     } else {
414       changed = true;
415       iter++;
416     }
417   }
418   return changed;
419 }
420
421 BufferViewConfig *BufferViewSettingsPage::cloneConfig(BufferViewConfig *config) {
422   if(!config || config->bufferViewId() < 0)
423     return config;
424   
425   if(_changedBufferViews.contains(config))
426     return _changedBufferViews[config];
427
428   BufferViewConfig *changedConfig = new BufferViewConfig(-1, this);
429   changedConfig->fromVariantMap(config->toVariantMap());
430   _changedBufferViews[config] = changedConfig;
431   connect(config, SIGNAL(bufferAdded(const BufferId &, int)), changedConfig, SLOT(addBuffer(const BufferId &, int)));
432   connect(config, SIGNAL(bufferMoved(const BufferId &, int)), changedConfig, SLOT(moveBuffer(const BufferId &, int)));
433   connect(config, SIGNAL(bufferRemoved(const BufferId &)), changedConfig, SLOT(removeBuffer(const BufferId &)));
434   connect(config, SIGNAL(addBufferRequested(const BufferId &, int)), changedConfig, SLOT(addBuffer(const BufferId &, int)));
435   connect(config, SIGNAL(moveBufferRequested(const BufferId &, int)), changedConfig, SLOT(moveBuffer(const BufferId &, int)));
436   connect(config, SIGNAL(removeBufferRequested(const BufferId &)), changedConfig, SLOT(removeBuffer(const BufferId &)));
437
438   // if this is the currently displayed view we have to change the config of the preview filter
439   BufferViewFilter *filter = qobject_cast<BufferViewFilter *>(ui.bufferViewPreview->model());
440   if(filter && filter->config() == config)
441     filter->setConfig(changedConfig);
442   ui.bufferViewPreview->setConfig(changedConfig);
443
444   return changedConfig;
445 }
446
447 BufferViewConfig *BufferViewSettingsPage::configForDisplay(BufferViewConfig *config) {
448   if(_changedBufferViews.contains(config))
449     return _changedBufferViews[config];
450   else
451     return config;
452 }
453
454
455 /**************************************************************************
456  * BufferViewEditDlg
457  *************************************************************************/
458 BufferViewEditDlg::BufferViewEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) {
459   ui.setupUi(this);
460
461   if(old.isEmpty()) {
462     // new buffer
463     setWindowTitle(tr("Add Buffer View"));
464     on_bufferViewEdit_textChanged(""); // disable ok button
465   } else {
466     ui.bufferViewEdit->setText(old);
467   }
468 }
469
470
471 void BufferViewEditDlg::on_bufferViewEdit_textChanged(const QString &text) {
472   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));
473 }
474