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