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