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