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