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