76e461e9a7f4633d80787f49946430e1ef7e0d08
[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           iter = _newBufferViews.erase(iter);
354           break;
355         } else {
356           iter++;
357         }
358       }
359       delete config;
360       if(_deleteBufferViews.isEmpty() && _changedBufferViews.isEmpty() && _newBufferViews.isEmpty())
361         setChangedState(false);
362     }
363   }
364 }
365
366 void BufferViewSettingsPage::bufferViewSelectionChanged(const QItemSelection &current, const QItemSelection &previous) {
367   Q_UNUSED(previous)
368
369   if(!current.isEmpty()) {
370     ui.settingsGroupBox->setEnabled(true);
371     ui.bufferViewPreview->setEnabled(true);
372
373     loadConfig(configForDisplay(bufferView(ui.bufferViewList->currentRow())));
374   } else {
375     ui.settingsGroupBox->setEnabled(false);
376     ui.bufferViewPreview->setEnabled(false);
377   }
378 }
379
380 void BufferViewSettingsPage::loadConfig(BufferViewConfig *config) {
381   if(!config)
382     return;
383
384   _ignoreWidgetChanges = true;
385   ui.onlyStatusBuffers->setChecked(BufferInfo::StatusBuffer & config->allowedBufferTypes());
386   ui.onlyChannelBuffers->setChecked(BufferInfo::ChannelBuffer & config->allowedBufferTypes());
387   ui.onlyQueryBuffers->setChecked(BufferInfo::QueryBuffer & config->allowedBufferTypes());
388   ui.addNewBuffersAutomatically->setChecked(config->addNewBuffersAutomatically());
389   ui.sortAlphabetically->setChecked(config->sortAlphabetically());
390   ui.hideInactiveBuffers->setChecked(config->hideInactiveBuffers());
391
392   int networkIndex = 0;
393   for(int i = 0; i < ui.networkSelector->count(); i++) {
394     if(ui.networkSelector->itemData(i).value<NetworkId>() == config->networkId()) {
395       networkIndex = i;
396       break;
397     }
398   }
399   ui.networkSelector->setCurrentIndex(networkIndex);
400
401   int activityIndex = 0;
402   int minimumActivity = config->minimumActivity();
403   while(minimumActivity) {
404     activityIndex++;
405     minimumActivity = minimumActivity >> 1;
406   }
407   ui.minimumActivitySelector->setCurrentIndex(activityIndex);
408
409   ui.bufferViewPreview->setFilteredModel(Client::bufferModel(), config);
410
411   _ignoreWidgetChanges = false;
412 }
413
414 void BufferViewSettingsPage::saveConfig(BufferViewConfig *config) {
415   if(!config)
416     return;
417
418   int allowedBufferTypes = 0;
419   if(ui.onlyStatusBuffers->isChecked())
420     allowedBufferTypes |= BufferInfo::StatusBuffer;
421   if(ui.onlyChannelBuffers->isChecked())
422     allowedBufferTypes |= BufferInfo::ChannelBuffer;
423   if(ui.onlyQueryBuffers->isChecked())
424     allowedBufferTypes |= BufferInfo::QueryBuffer;
425   config->setAllowedBufferTypes(allowedBufferTypes);
426
427   config->setAddNewBuffersAutomatically(ui.addNewBuffersAutomatically->isChecked());
428   config->setSortAlphabetically(ui.sortAlphabetically->isChecked());
429   config->setHideInactiveBuffers(ui.hideInactiveBuffers->isChecked());
430   config->setNetworkId(ui.networkSelector->itemData(ui.networkSelector->currentIndex()).value<NetworkId>());
431
432   int minimumActivity = 0;
433   if(ui.minimumActivitySelector->currentIndex() > 0)
434     minimumActivity = 1 << (ui.minimumActivitySelector->currentIndex() - 1);
435   config->setMinimumActivity(minimumActivity);
436
437   if(_newBufferViews.contains(config)) {
438     QList<BufferId> bufferIds;
439     if(config->addNewBuffersAutomatically()) {
440       if(config->sortAlphabetically())
441         bufferIds = Client::networkModel()->allBufferIdsSorted();
442       else
443         bufferIds = Client::networkModel()->allBufferIds();
444     }
445     config->initSetBufferList(bufferIds);
446   }
447 }
448
449 void BufferViewSettingsPage::widgetHasChanged() {
450   if(_ignoreWidgetChanges)
451     return;
452   setChangedState(testHasChanged());
453 }
454
455 bool BufferViewSettingsPage::testHasChanged() {
456   saveConfig(cloneConfig(bufferView(ui.bufferViewList->currentRow())));
457
458   if(!_newBufferViews.isEmpty())
459     return true;
460
461   bool changed = false;
462   QHash<BufferViewConfig *, BufferViewConfig *>::iterator iter = _changedBufferViews.begin();
463   QHash<BufferViewConfig *, BufferViewConfig *>::iterator iterEnd = _changedBufferViews.end();
464   while(iter != iterEnd) {
465     if(&(iter.key()) == &(iter.value())) {
466       iter.value()->deleteLater();
467       iter = _changedBufferViews.erase(iter);
468     } else {
469       changed = true;
470       iter++;
471     }
472   }
473   return changed;
474 }
475
476 BufferViewConfig *BufferViewSettingsPage::cloneConfig(BufferViewConfig *config) {
477   if(!config || config->bufferViewId() < 0)
478     return config;
479
480   if(_changedBufferViews.contains(config))
481     return _changedBufferViews[config];
482
483   BufferViewConfig *changedConfig = new BufferViewConfig(-1, this);
484   changedConfig->fromVariantMap(config->toVariantMap());
485   changedConfig->setInitialized();
486   _changedBufferViews[config] = changedConfig;
487   connect(config, SIGNAL(bufferAdded(const BufferId &, int)), changedConfig, SLOT(addBuffer(const BufferId &, int)));
488   connect(config, SIGNAL(bufferMoved(const BufferId &, int)), changedConfig, SLOT(moveBuffer(const BufferId &, int)));
489   connect(config, SIGNAL(bufferRemoved(const BufferId &)), changedConfig, SLOT(removeBuffer(const BufferId &)));
490   connect(config, SIGNAL(addBufferRequested(const BufferId &, int)), changedConfig, SLOT(addBuffer(const BufferId &, int)));
491   connect(config, SIGNAL(moveBufferRequested(const BufferId &, int)), changedConfig, SLOT(moveBuffer(const BufferId &, int)));
492   connect(config, SIGNAL(removeBufferRequested(const BufferId &)), changedConfig, SLOT(removeBuffer(const BufferId &)));
493
494   // if this is the currently displayed view we have to change the config of the preview filter
495   BufferViewFilter *filter = qobject_cast<BufferViewFilter *>(ui.bufferViewPreview->model());
496   if(filter && filter->config() == config)
497     filter->setConfig(changedConfig);
498   ui.bufferViewPreview->setConfig(changedConfig);
499
500   return changedConfig;
501 }
502
503 BufferViewConfig *BufferViewSettingsPage::configForDisplay(BufferViewConfig *config) {
504   if(_changedBufferViews.contains(config))
505     return _changedBufferViews[config];
506   else
507     return config;
508 }
509
510
511 /**************************************************************************
512  * BufferViewEditDlg
513  *************************************************************************/
514 BufferViewEditDlg::BufferViewEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) {
515   ui.setupUi(this);
516
517   if(old.isEmpty()) {
518     // new buffer
519     setWindowTitle(tr("Add Buffer View"));
520     on_bufferViewEdit_textChanged(""); // disable ok button
521   } else {
522     ui.bufferViewEdit->setText(old);
523   }
524 }
525
526
527 void BufferViewEditDlg::on_bufferViewEdit_textChanged(const QString &text) {
528   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));
529 }
530