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