1 /***************************************************************************
2 * Copyright (C) 2005-2019 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"
25 #include <QMessageBox>
27 #include "buffermodel.h"
28 #include "bufferviewconfig.h"
29 #include "bufferviewfilter.h"
31 #include "clientbufferviewmanager.h"
34 #include "networkmodel.h"
37 BufferViewSettingsPage::BufferViewSettingsPage(QWidget* parent)
38 : SettingsPage(tr("Interface"), tr("Custom Chat Lists"), parent)
41 // Hide the hide inactive networks feature on older cores (which won't save the setting)
42 if (!Client::isCoreFeatureEnabled(Quassel::Feature::HideInactiveNetworks))
43 ui.hideInactiveNetworks->hide();
45 ui.renameBufferView->setIcon(icon::get("edit-rename"));
46 ui.addBufferView->setIcon(icon::get("list-add"));
47 ui.deleteBufferView->setIcon(icon::get("edit-delete"));
51 ui.bufferViewList->setSortingEnabled(true);
52 ui.settingsGroupBox->setEnabled(false);
53 ui.bufferViewPreview->setEnabled(false);
55 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
56 connect(Client::instance(), &Client::coreConnectionStateChanged, this, &BufferViewSettingsPage::coreConnectionStateChanged);
57 connect(ui.bufferViewList->selectionModel(),
58 &QItemSelectionModel::selectionChanged,
60 &BufferViewSettingsPage::bufferViewSelectionChanged);
62 connect(ui.onlyStatusBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
63 connect(ui.onlyChannelBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
64 connect(ui.onlyQueryBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
65 connect(ui.addNewBuffersAutomatically, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
66 connect(ui.sortAlphabetically, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
67 connect(ui.hideInactiveBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
68 connect(ui.hideInactiveNetworks, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
69 connect(ui.networkSelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::widgetHasChanged);
70 connect(ui.minimumActivitySelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::widgetHasChanged);
71 connect(ui.showSearch, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
73 connect(ui.networkSelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::enableStatusBuffers);
76 BufferViewSettingsPage::~BufferViewSettingsPage()
81 void BufferViewSettingsPage::reset()
83 ui.bufferViewList->clear();
84 ui.deleteBufferView->setEnabled(false);
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();
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();
103 _deleteBufferViews.clear();
105 _useBufferViewHint = false;
107 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);
141 void BufferViewSettingsPage::save()
145 BufferViewConfig* currentConfig = bufferView(ui.bufferViewList->currentRow());
147 _useBufferViewHint = true;
148 _bufferViewHint = currentConfig->bufferViewId();
151 QVariantList newConfigs;
152 QVariantList deleteConfigs;
153 QVariantList changedConfigs;
155 foreach (int bufferId, _deleteBufferViews) {
156 deleteConfigs << bufferId;
158 _deleteBufferViews.clear();
159 if (Client::bufferViewManager()) {
160 Client::bufferViewManager()->requestDeleteBufferViews(deleteConfigs);
163 QHash<BufferViewConfig*, BufferViewConfig*>::iterator changedConfigIter = _changedBufferViews.begin();
164 QHash<BufferViewConfig*, BufferViewConfig*>::iterator changedConfigIterEnd = _changedBufferViews.end();
165 BufferViewConfig *config, *changedConfig;
166 while (changedConfigIter != changedConfigIterEnd) {
167 config = changedConfigIter.key();
168 changedConfig = changedConfigIter.value();
169 changedConfigIter = _changedBufferViews.erase(changedConfigIter);
170 config->requestUpdate(changedConfig->toVariantMap());
171 changedConfig->deleteLater();
174 QList<BufferViewConfig*>::iterator newConfigIter = _newBufferViews.begin();
175 QList<BufferViewConfig*>::iterator newConfigIterEnd = _newBufferViews.end();
176 while (newConfigIter != newConfigIterEnd) {
177 config = *newConfigIter;
178 newConfigIter = _newBufferViews.erase(newConfigIter);
179 newConfigs << config->toVariantMap();
180 config->deleteLater();
182 if (Client::bufferViewManager()) {
183 Client::bufferViewManager()->requestCreateBufferViews(newConfigs);
190 void BufferViewSettingsPage::coreConnectionStateChanged(bool state)
195 connect(Client::bufferViewManager(),
196 selectOverload<int>(&BufferViewManager::bufferViewConfigAdded),
198 selectOverload<int>(&BufferViewSettingsPage::addBufferView));
205 void BufferViewSettingsPage::addBufferView(BufferViewConfig* config)
207 auto* item = new QListWidgetItem(config->bufferViewName(), ui.bufferViewList);
208 item->setData(Qt::UserRole, qVariantFromValue<QObject*>(qobject_cast<QObject*>(config)));
209 connect(config, &SyncableObject::updatedRemotely, this, &BufferViewSettingsPage::updateBufferView);
210 connect(config, &QObject::destroyed, this, &BufferViewSettingsPage::bufferViewDeleted);
211 ui.deleteBufferView->setEnabled(ui.bufferViewList->count() > 1);
214 void BufferViewSettingsPage::addBufferView(int bufferViewId)
216 // we are informed about a new bufferview from Client::bufferViewManager()
217 Q_ASSERT(Client::bufferViewManager());
218 addBufferView(Client::bufferViewManager()->bufferViewConfig(bufferViewId));
219 selectBufferViewById(bufferViewId);
222 void BufferViewSettingsPage::bufferViewDeleted()
224 auto* config = static_cast<BufferViewConfig*>(sender());
226 for (int i = 0; i < ui.bufferViewList->count(); i++) {
227 obj = ui.bufferViewList->item(i)->data(Qt::UserRole).value<QObject*>();
228 if (config == static_cast<BufferViewConfig*>(obj)) {
229 QListWidgetItem* item = ui.bufferViewList->takeItem(i);
234 ui.deleteBufferView->setEnabled(ui.bufferViewList->count() > 1);
237 void BufferViewSettingsPage::newBufferView(const QString& bufferViewName)
239 // id's of newly created bufferviews are negative (-1, -2... -n)
240 int fakeId = -1 * (_newBufferViews.count() + 1);
241 auto* 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();
250 bufferIds = Client::networkModel()->allBufferIds();
252 config->setProperty("OriginalBufferList", toVariantList<BufferId>(bufferIds));
255 config->setBufferList(bufferIds);
257 _newBufferViews << config;
258 addBufferView(config);
259 ui.bufferViewList->setCurrentRow(listPos(config));
262 int BufferViewSettingsPage::listPos(BufferViewConfig* config)
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))
273 BufferViewConfig* BufferViewSettingsPage::bufferView(int listPos)
275 if (listPos < ui.bufferViewList->count() && listPos >= 0) {
276 auto* obj = ui.bufferViewList->item(listPos)->data(Qt::UserRole).value<QObject*>();
277 return qobject_cast<BufferViewConfig*>(obj);
284 bool BufferViewSettingsPage::selectBufferViewById(int bufferViewId)
286 BufferViewConfig* config;
287 for (int i = 0; i < ui.bufferViewList->count(); i++) {
288 config = qobject_cast<BufferViewConfig*>(ui.bufferViewList->item(i)->data(Qt::UserRole).value<QObject*>());
289 if (config && config->bufferViewId() == bufferViewId) {
290 ui.bufferViewList->setCurrentRow(i);
297 void BufferViewSettingsPage::updateBufferView()
299 auto* config = qobject_cast<BufferViewConfig*>(sender());
303 int itemPos = listPos(config);
305 qWarning() << "BufferViewSettingsPage::updateBufferView(): view is unknown:" << config->bufferViewId();
308 ui.bufferViewList->item(itemPos)->setText(config->bufferViewName());
309 if (itemPos == ui.bufferViewList->currentRow())
313 void BufferViewSettingsPage::enableStatusBuffers(int networkIdx)
315 // we don't show a status buffer if we show multiple networks as selecting
316 // the network is the same as selecting the status buffer.
317 ui.onlyStatusBuffers->setEnabled(networkIdx != 0);
320 void BufferViewSettingsPage::on_addBufferView_clicked()
322 if (!Client::bufferViewManager())
325 QStringList existing;
326 foreach (BufferViewConfig* bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
327 existing << bufferConfig->bufferViewName();
330 BufferViewEditDlg dlg(QString(), existing, this);
331 if (dlg.exec() == QDialog::Accepted) {
332 newBufferView(dlg.bufferViewName());
333 setChangedState(true);
337 void BufferViewSettingsPage::on_renameBufferView_clicked()
339 if (ui.bufferViewList->selectedItems().isEmpty())
342 if (!Client::bufferViewManager())
345 BufferViewConfig* config = bufferView(ui.bufferViewList->currentRow());
349 QStringList existing;
350 foreach (BufferViewConfig* bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
351 existing << bufferConfig->bufferViewName();
354 BufferViewEditDlg dlg(config->bufferViewName(), existing, this);
355 if (dlg.exec() == QDialog::Accepted) {
356 BufferViewConfig* changedConfig = cloneConfig(config);
357 changedConfig->setBufferViewName(dlg.bufferViewName());
358 ui.bufferViewList->item(listPos(config))->setText(dlg.bufferViewName());
359 setChangedState(true);
363 void BufferViewSettingsPage::on_deleteBufferView_clicked()
365 if (ui.bufferViewList->selectedItems().isEmpty())
368 QListWidgetItem* currentItem = ui.bufferViewList->item(ui.bufferViewList->currentRow());
369 QString viewName = currentItem->text();
370 int viewId = bufferView(ui.bufferViewList->currentRow())->bufferViewId();
371 int ret = QMessageBox::question(this,
372 tr("Delete Chat List?"),
373 tr("Do you really want to delete the chat list \"%1\"?").arg(viewName),
374 QMessageBox::Yes | QMessageBox::No,
377 if (ret == QMessageBox::Yes) {
378 ui.bufferViewList->removeItemWidget(currentItem);
379 auto* config = qobject_cast<BufferViewConfig*>(currentItem->data(Qt::UserRole).value<QObject*>());
382 _deleteBufferViews << viewId;
383 setChangedState(true);
386 QList<BufferViewConfig*>::iterator iter = _newBufferViews.begin();
387 while (iter != _newBufferViews.end()) {
388 if (*iter == config) {
389 iter = _newBufferViews.erase(iter);
397 if (_deleteBufferViews.isEmpty() && _changedBufferViews.isEmpty() && _newBufferViews.isEmpty())
398 setChangedState(false);
403 void BufferViewSettingsPage::bufferViewSelectionChanged(const QItemSelection& current, const QItemSelection& previous)
407 if (!current.isEmpty()) {
408 ui.settingsGroupBox->setEnabled(true);
409 ui.bufferViewPreview->setEnabled(true);
411 loadConfig(configForDisplay(bufferView(ui.bufferViewList->currentRow())));
414 ui.settingsGroupBox->setEnabled(false);
415 ui.bufferViewPreview->setEnabled(false);
419 void BufferViewSettingsPage::loadConfig(BufferViewConfig* config)
424 _ignoreWidgetChanges = true;
425 ui.onlyStatusBuffers->setChecked(BufferInfo::StatusBuffer & config->allowedBufferTypes());
426 ui.onlyChannelBuffers->setChecked(BufferInfo::ChannelBuffer & config->allowedBufferTypes());
427 ui.onlyQueryBuffers->setChecked(BufferInfo::QueryBuffer & config->allowedBufferTypes());
428 ui.addNewBuffersAutomatically->setChecked(config->addNewBuffersAutomatically());
429 ui.sortAlphabetically->setChecked(config->sortAlphabetically());
430 ui.hideInactiveBuffers->setChecked(config->hideInactiveBuffers());
431 ui.hideInactiveNetworks->setChecked(config->hideInactiveNetworks());
432 ui.showSearch->setChecked(config->showSearch());
434 int networkIndex = 0;
435 for (int i = 0; i < ui.networkSelector->count(); i++) {
436 if (ui.networkSelector->itemData(i).value<NetworkId>() == config->networkId()) {
441 ui.networkSelector->setCurrentIndex(networkIndex);
443 int activityIndex = 0;
444 int minimumActivity = config->minimumActivity();
445 while (minimumActivity) {
447 minimumActivity = minimumActivity >> 1;
449 ui.minimumActivitySelector->setCurrentIndex(activityIndex);
451 ui.bufferViewPreview->setFilteredModel(Client::bufferModel(), config);
453 _ignoreWidgetChanges = false;
456 void BufferViewSettingsPage::saveConfig(BufferViewConfig* config)
461 int allowedBufferTypes = 0;
462 if (ui.onlyStatusBuffers->isChecked())
463 allowedBufferTypes |= BufferInfo::StatusBuffer;
464 if (ui.onlyChannelBuffers->isChecked())
465 allowedBufferTypes |= BufferInfo::ChannelBuffer;
466 if (ui.onlyQueryBuffers->isChecked())
467 allowedBufferTypes |= BufferInfo::QueryBuffer;
468 config->setAllowedBufferTypes(allowedBufferTypes);
470 config->setAddNewBuffersAutomatically(ui.addNewBuffersAutomatically->isChecked());
471 config->setSortAlphabetically(ui.sortAlphabetically->isChecked());
472 config->setHideInactiveBuffers(ui.hideInactiveBuffers->isChecked());
473 config->setHideInactiveNetworks(ui.hideInactiveNetworks->isChecked());
474 config->setNetworkId(ui.networkSelector->itemData(ui.networkSelector->currentIndex()).value<NetworkId>());
475 config->setShowSearch(ui.showSearch->isChecked());
477 int minimumActivity = 0;
478 if (ui.minimumActivitySelector->currentIndex() > 0)
479 minimumActivity = 1 << (ui.minimumActivitySelector->currentIndex() - 1);
480 config->setMinimumActivity(minimumActivity);
482 QList<BufferId> bufferIds = fromVariantList<BufferId>(config->property("OriginalBufferList").toList());
483 if (config->sortAlphabetically())
484 Client::networkModel()->sortBufferIds(bufferIds);
486 if (!_newBufferViews.contains(config) || config->addNewBuffersAutomatically())
487 config->setBufferList(bufferIds);
490 void BufferViewSettingsPage::widgetHasChanged()
492 if (_ignoreWidgetChanges)
494 setChangedState(testHasChanged());
497 bool BufferViewSettingsPage::testHasChanged()
499 saveConfig(cloneConfig(bufferView(ui.bufferViewList->currentRow())));
501 if (!_newBufferViews.isEmpty())
504 bool changed = false;
505 QHash<BufferViewConfig*, BufferViewConfig*>::iterator iter = _changedBufferViews.begin();
506 QHash<BufferViewConfig*, BufferViewConfig*>::iterator iterEnd = _changedBufferViews.end();
507 while (iter != iterEnd) {
508 if (&(iter.key()) == &(iter.value())) {
509 iter.value()->deleteLater();
510 iter = _changedBufferViews.erase(iter);
520 BufferViewConfig* BufferViewSettingsPage::cloneConfig(BufferViewConfig* config)
522 if (!config || config->bufferViewId() < 0)
525 if (_changedBufferViews.contains(config))
526 return _changedBufferViews[config];
528 auto* changedConfig = new BufferViewConfig(-1, this);
529 changedConfig->fromVariantMap(config->toVariantMap());
530 changedConfig->setInitialized();
531 _changedBufferViews[config] = changedConfig;
532 connect(config, &BufferViewConfig::bufferAdded, changedConfig, &BufferViewConfig::addBuffer);
533 connect(config, &BufferViewConfig::bufferMoved, changedConfig, &BufferViewConfig::moveBuffer);
534 connect(config, &BufferViewConfig::bufferRemoved, changedConfig, &BufferViewConfig::removeBuffer);
535 // connect(config, &BufferViewConfig::addBufferRequested, changedConfig, &BufferViewConfig::addBuffer);
536 // connect(config, &BufferViewConfig::moveBufferRequested, changedConfig, &BufferViewConfig::moveBuffer);
537 // connect(config, &BufferViewconfig::removeBufferRequested, changedConfig, &BufferViewConfig::removeBuffer);
539 changedConfig->setProperty("OriginalBufferList", toVariantList<BufferId>(config->bufferList()));
540 // if this is the currently displayed view we have to change the config of the preview filter
541 auto* filter = qobject_cast<BufferViewFilter*>(ui.bufferViewPreview->model());
542 if (filter && filter->config() == config)
543 filter->setConfig(changedConfig);
544 ui.bufferViewPreview->setConfig(changedConfig);
546 return changedConfig;
549 BufferViewConfig* BufferViewSettingsPage::configForDisplay(BufferViewConfig* config)
551 if (_changedBufferViews.contains(config))
552 return _changedBufferViews[config];
557 /**************************************************************************
559 *************************************************************************/
560 BufferViewEditDlg::BufferViewEditDlg(const QString& old, QStringList exist, QWidget* parent)
562 , existing(std::move(exist))
568 setWindowTitle(tr("Add Chat List"));
569 on_bufferViewEdit_textChanged(""); // disable ok button
572 ui.bufferViewEdit->setText(old);
576 void BufferViewEditDlg::on_bufferViewEdit_textChanged(const QString& text)
578 ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));