1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
21 #include "bufferviewsettingspage.h"
23 #include <QMessageBox>
26 #include "buffermodel.h"
27 #include "bufferviewconfig.h"
28 #include "bufferviewfilter.h"
30 #include "clientbufferviewmanager.h"
33 #include "networkmodel.h"
36 BufferViewSettingsPage::BufferViewSettingsPage(QWidget *parent)
37 : SettingsPage(tr("Interface"), tr("Custom Chat Lists"), parent)
40 //Hide the hide inactive networks feature on older cores (which won't save the setting)
41 if (!Client::isCoreFeatureEnabled(Quassel::Feature::HideInactiveNetworks))
42 ui.hideInactiveNetworks->hide();
44 ui.renameBufferView->setIcon(icon::get("edit-rename"));
45 ui.addBufferView->setIcon(icon::get("list-add"));
46 ui.deleteBufferView->setIcon(icon::get("edit-delete"));
50 ui.bufferViewList->setSortingEnabled(true);
51 ui.settingsGroupBox->setEnabled(false);
52 ui.bufferViewPreview->setEnabled(false);
54 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
55 connect(Client::instance(), &Client::coreConnectionStateChanged, this, &BufferViewSettingsPage::coreConnectionStateChanged);
56 connect(ui.bufferViewList->selectionModel(), &QItemSelectionModel::selectionChanged,
57 this, &BufferViewSettingsPage::bufferViewSelectionChanged);
59 connect(ui.onlyStatusBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
60 connect(ui.onlyChannelBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
61 connect(ui.onlyQueryBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
62 connect(ui.addNewBuffersAutomatically, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
63 connect(ui.sortAlphabetically, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
64 connect(ui.hideInactiveBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
65 connect(ui.hideInactiveNetworks, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
66 connect(ui.networkSelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::widgetHasChanged);
67 connect(ui.minimumActivitySelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::widgetHasChanged);
68 connect(ui.showSearch, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
70 connect(ui.networkSelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::enableStatusBuffers);
74 BufferViewSettingsPage::~BufferViewSettingsPage()
80 void BufferViewSettingsPage::reset()
82 ui.bufferViewList->clear();
83 ui.deleteBufferView->setEnabled(false);
85 QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIter = _changedBufferViews.begin();
86 QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIterEnd = _changedBufferViews.end();
87 BufferViewConfig *config;
88 while (changedConfigIter != changedConfigIterEnd) {
89 config = changedConfigIter.value();
90 changedConfigIter = _changedBufferViews.erase(changedConfigIter);
91 config->deleteLater();
94 QList<BufferViewConfig *>::iterator newConfigIter = _newBufferViews.begin();
95 QList<BufferViewConfig *>::iterator newConfigIterEnd = _newBufferViews.end();
96 while (newConfigIter != newConfigIterEnd) {
97 config = *newConfigIter;
98 newConfigIter = _newBufferViews.erase(newConfigIter);
99 config->deleteLater();
102 _deleteBufferViews.clear();
104 _useBufferViewHint = false;
106 setChangedState(false);
110 void BufferViewSettingsPage::load()
112 bool useBufferViewHint = _useBufferViewHint;
113 int bufferViewHint = _bufferViewHint;
116 if (!Client::bufferViewManager())
119 const QList<BufferViewConfig *> bufferViewConfigs = Client::bufferViewManager()->bufferViewConfigs();
120 foreach(BufferViewConfig *bufferViewConfig, bufferViewConfigs) {
121 addBufferView(bufferViewConfig);
124 _ignoreWidgetChanges = true;
125 // load network selector
126 ui.networkSelector->clear();
127 ui.networkSelector->addItem(tr("All"));
128 ui.networkSelector->setItemData(0, qVariantFromValue<NetworkId>(NetworkId()));
130 foreach(NetworkId netId, Client::networkIds()) {
131 net = Client::network(netId);
132 ui.networkSelector->addItem(net->networkName());
133 ui.networkSelector->setItemData(ui.networkSelector->count() - 1, qVariantFromValue<NetworkId>(net->networkId()));
135 _ignoreWidgetChanges = false;
137 if (!useBufferViewHint || !selectBufferViewById(bufferViewHint))
138 ui.bufferViewList->setCurrentRow(0);
142 void BufferViewSettingsPage::save()
146 BufferViewConfig *currentConfig = bufferView(ui.bufferViewList->currentRow());
148 _useBufferViewHint = true;
149 _bufferViewHint = currentConfig->bufferViewId();
152 QVariantList newConfigs;
153 QVariantList deleteConfigs;
154 QVariantList changedConfigs;
156 foreach(int bufferId, _deleteBufferViews) {
157 deleteConfigs << bufferId;
159 _deleteBufferViews.clear();
160 if (Client::bufferViewManager()) {
161 Client::bufferViewManager()->requestDeleteBufferViews(deleteConfigs);
164 QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIter = _changedBufferViews.begin();
165 QHash<BufferViewConfig *, BufferViewConfig *>::iterator changedConfigIterEnd = _changedBufferViews.end();
166 BufferViewConfig *config, *changedConfig;
167 while (changedConfigIter != changedConfigIterEnd) {
168 config = changedConfigIter.key();
169 changedConfig = changedConfigIter.value();
170 changedConfigIter = _changedBufferViews.erase(changedConfigIter);
171 config->requestUpdate(changedConfig->toVariantMap());
172 changedConfig->deleteLater();
175 QList<BufferViewConfig *>::iterator newConfigIter = _newBufferViews.begin();
176 QList<BufferViewConfig *>::iterator newConfigIterEnd = _newBufferViews.end();
177 while (newConfigIter != newConfigIterEnd) {
178 config = *newConfigIter;
179 newConfigIter = _newBufferViews.erase(newConfigIter);
180 newConfigs << config->toVariantMap();
181 config->deleteLater();
183 if (Client::bufferViewManager()) {
184 Client::bufferViewManager()->requestCreateBufferViews(newConfigs);
192 void BufferViewSettingsPage::coreConnectionStateChanged(bool state)
197 connect(Client::bufferViewManager(), selectOverload<int>(&BufferViewManager::bufferViewConfigAdded),
198 this, selectOverload<int>(&BufferViewSettingsPage::addBufferView));
206 void BufferViewSettingsPage::addBufferView(BufferViewConfig *config)
208 auto *item = new QListWidgetItem(config->bufferViewName(), ui.bufferViewList);
209 item->setData(Qt::UserRole, qVariantFromValue<QObject *>(qobject_cast<QObject *>(config)));
210 connect(config, &SyncableObject::updatedRemotely, this, &BufferViewSettingsPage::updateBufferView);
211 connect(config, &QObject::destroyed, this, &BufferViewSettingsPage::bufferViewDeleted);
212 ui.deleteBufferView->setEnabled(ui.bufferViewList->count() > 1);
216 void BufferViewSettingsPage::addBufferView(int bufferViewId)
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);
225 void BufferViewSettingsPage::bufferViewDeleted()
227 auto *config = static_cast<BufferViewConfig *>(sender());
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);
237 ui.deleteBufferView->setEnabled(ui.bufferViewList->count() > 1);
241 void BufferViewSettingsPage::newBufferView(const QString &bufferViewName)
243 // id's of newly created bufferviews are negative (-1, -2... -n)
244 int fakeId = -1 * (_newBufferViews.count() + 1);
245 auto *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();
254 bufferIds = Client::networkModel()->allBufferIds();
256 config->setProperty("OriginalBufferList", toVariantList<BufferId>(bufferIds));
259 config->initSetBufferList(bufferIds);
261 _newBufferViews << config;
262 addBufferView(config);
263 ui.bufferViewList->setCurrentRow(listPos(config));
267 int BufferViewSettingsPage::listPos(BufferViewConfig *config)
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))
279 BufferViewConfig *BufferViewSettingsPage::bufferView(int listPos)
281 if (listPos < ui.bufferViewList->count() && listPos >= 0) {
282 auto *obj = ui.bufferViewList->item(listPos)->data(Qt::UserRole).value<QObject *>();
283 return qobject_cast<BufferViewConfig *>(obj);
291 bool BufferViewSettingsPage::selectBufferViewById(int bufferViewId)
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);
305 void BufferViewSettingsPage::updateBufferView()
307 auto *config = qobject_cast<BufferViewConfig *>(sender());
311 int itemPos = listPos(config);
313 qWarning() << "BufferViewSettingsPage::updateBufferView(): view is unknown:" << config->bufferViewId();
316 ui.bufferViewList->item(itemPos)->setText(config->bufferViewName());
317 if (itemPos == ui.bufferViewList->currentRow())
322 void BufferViewSettingsPage::enableStatusBuffers(int networkIdx)
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);
330 void BufferViewSettingsPage::on_addBufferView_clicked()
332 if (!Client::bufferViewManager())
335 QStringList existing;
336 foreach(BufferViewConfig *bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
337 existing << bufferConfig->bufferViewName();
340 BufferViewEditDlg dlg(QString(), existing, this);
341 if (dlg.exec() == QDialog::Accepted) {
342 newBufferView(dlg.bufferViewName());
343 setChangedState(true);
348 void BufferViewSettingsPage::on_renameBufferView_clicked()
350 if (ui.bufferViewList->selectedItems().isEmpty())
353 if (!Client::bufferViewManager())
356 BufferViewConfig *config = bufferView(ui.bufferViewList->currentRow());
360 QStringList existing;
361 foreach(BufferViewConfig *bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
362 existing << bufferConfig->bufferViewName();
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 setChangedState(true);
375 void BufferViewSettingsPage::on_deleteBufferView_clicked()
377 if (ui.bufferViewList->selectedItems().isEmpty())
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);
387 if (ret == QMessageBox::Yes) {
388 ui.bufferViewList->removeItemWidget(currentItem);
389 auto *config = qobject_cast<BufferViewConfig *>(currentItem->data(Qt::UserRole).value<QObject *>());
392 _deleteBufferViews << viewId;
393 setChangedState(true);
396 QList<BufferViewConfig *>::iterator iter = _newBufferViews.begin();
397 while (iter != _newBufferViews.end()) {
398 if (*iter == config) {
399 iter = _newBufferViews.erase(iter);
407 if (_deleteBufferViews.isEmpty() && _changedBufferViews.isEmpty() && _newBufferViews.isEmpty())
408 setChangedState(false);
414 void BufferViewSettingsPage::bufferViewSelectionChanged(const QItemSelection ¤t, const QItemSelection &previous)
418 if (!current.isEmpty()) {
419 ui.settingsGroupBox->setEnabled(true);
420 ui.bufferViewPreview->setEnabled(true);
422 loadConfig(configForDisplay(bufferView(ui.bufferViewList->currentRow())));
425 ui.settingsGroupBox->setEnabled(false);
426 ui.bufferViewPreview->setEnabled(false);
431 void BufferViewSettingsPage::loadConfig(BufferViewConfig *config)
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 ui.showSearch->setChecked(config->showSearch());
446 int networkIndex = 0;
447 for (int i = 0; i < ui.networkSelector->count(); i++) {
448 if (ui.networkSelector->itemData(i).value<NetworkId>() == config->networkId()) {
453 ui.networkSelector->setCurrentIndex(networkIndex);
455 int activityIndex = 0;
456 int minimumActivity = config->minimumActivity();
457 while (minimumActivity) {
459 minimumActivity = minimumActivity >> 1;
461 ui.minimumActivitySelector->setCurrentIndex(activityIndex);
463 ui.bufferViewPreview->setFilteredModel(Client::bufferModel(), config);
465 _ignoreWidgetChanges = false;
469 void BufferViewSettingsPage::saveConfig(BufferViewConfig *config)
474 int allowedBufferTypes = 0;
475 if (ui.onlyStatusBuffers->isChecked())
476 allowedBufferTypes |= BufferInfo::StatusBuffer;
477 if (ui.onlyChannelBuffers->isChecked())
478 allowedBufferTypes |= BufferInfo::ChannelBuffer;
479 if (ui.onlyQueryBuffers->isChecked())
480 allowedBufferTypes |= BufferInfo::QueryBuffer;
481 config->setAllowedBufferTypes(allowedBufferTypes);
483 config->setAddNewBuffersAutomatically(ui.addNewBuffersAutomatically->isChecked());
484 config->setSortAlphabetically(ui.sortAlphabetically->isChecked());
485 config->setHideInactiveBuffers(ui.hideInactiveBuffers->isChecked());
486 config->setHideInactiveNetworks(ui.hideInactiveNetworks->isChecked());
487 config->setNetworkId(ui.networkSelector->itemData(ui.networkSelector->currentIndex()).value<NetworkId>());
488 config->setShowSearch(ui.showSearch->isChecked());
490 int minimumActivity = 0;
491 if (ui.minimumActivitySelector->currentIndex() > 0)
492 minimumActivity = 1 << (ui.minimumActivitySelector->currentIndex() - 1);
493 config->setMinimumActivity(minimumActivity);
495 QList<BufferId> bufferIds = fromVariantList<BufferId>(config->property("OriginalBufferList").toList());
496 if (config->sortAlphabetically())
497 Client::networkModel()->sortBufferIds(bufferIds);
499 if (!_newBufferViews.contains(config) || config->addNewBuffersAutomatically())
500 config->initSetBufferList(bufferIds);
504 void BufferViewSettingsPage::widgetHasChanged()
506 if (_ignoreWidgetChanges)
508 setChangedState(testHasChanged());
512 bool BufferViewSettingsPage::testHasChanged()
514 saveConfig(cloneConfig(bufferView(ui.bufferViewList->currentRow())));
516 if (!_newBufferViews.isEmpty())
519 bool changed = false;
520 QHash<BufferViewConfig *, BufferViewConfig *>::iterator iter = _changedBufferViews.begin();
521 QHash<BufferViewConfig *, BufferViewConfig *>::iterator iterEnd = _changedBufferViews.end();
522 while (iter != iterEnd) {
523 if (&(iter.key()) == &(iter.value())) {
524 iter.value()->deleteLater();
525 iter = _changedBufferViews.erase(iter);
536 BufferViewConfig *BufferViewSettingsPage::cloneConfig(BufferViewConfig *config)
538 if (!config || config->bufferViewId() < 0)
541 if (_changedBufferViews.contains(config))
542 return _changedBufferViews[config];
544 auto *changedConfig = new BufferViewConfig(-1, this);
545 changedConfig->fromVariantMap(config->toVariantMap());
546 changedConfig->setInitialized();
547 _changedBufferViews[config] = changedConfig;
548 connect(config, &BufferViewConfig::bufferAdded, changedConfig, &BufferViewConfig::addBuffer);
549 connect(config, &BufferViewConfig::bufferMoved, changedConfig, &BufferViewConfig::moveBuffer);
550 connect(config, &BufferViewConfig::bufferRemoved, changedConfig, &BufferViewConfig::removeBuffer);
551 // connect(config, &BufferViewConfig::addBufferRequested, changedConfig, &BufferViewConfig::addBuffer);
552 // connect(config, &BufferViewConfig::moveBufferRequested, changedConfig, &BufferViewConfig::moveBuffer);
553 // connect(config, &BufferViewconfig::removeBufferRequested, changedConfig, &BufferViewConfig::removeBuffer);
555 changedConfig->setProperty("OriginalBufferList", toVariantList<BufferId>(config->bufferList()));
556 // if this is the currently displayed view we have to change the config of the preview filter
557 auto *filter = qobject_cast<BufferViewFilter *>(ui.bufferViewPreview->model());
558 if (filter && filter->config() == config)
559 filter->setConfig(changedConfig);
560 ui.bufferViewPreview->setConfig(changedConfig);
562 return changedConfig;
566 BufferViewConfig *BufferViewSettingsPage::configForDisplay(BufferViewConfig *config)
568 if (_changedBufferViews.contains(config))
569 return _changedBufferViews[config];
575 /**************************************************************************
577 *************************************************************************/
578 BufferViewEditDlg::BufferViewEditDlg(const QString &old, QStringList exist, QWidget *parent) : QDialog(parent), existing(std::move(exist))
584 setWindowTitle(tr("Add Chat List"));
585 on_bufferViewEdit_textChanged(""); // disable ok button
588 ui.bufferViewEdit->setText(old);
593 void BufferViewEditDlg::on_bufferViewEdit_textChanged(const QString &text)
595 ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));