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