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