1 /***************************************************************************
2 * Copyright (C) 2005-2020 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"
26 #include <QMessageBox>
28 #include "buffermodel.h"
29 #include "bufferviewconfig.h"
30 #include "bufferviewfilter.h"
32 #include "clientbufferviewmanager.h"
35 #include "networkmodel.h"
38 BufferViewSettingsPage::BufferViewSettingsPage(QWidget* parent)
39 : SettingsPage(tr("Interface"), tr("Custom Chat Lists"), parent)
42 // Hide the hide inactive networks feature on older cores (which won't save the setting)
43 if (!Client::isCoreFeatureEnabled(Quassel::Feature::HideInactiveNetworks))
44 ui.hideInactiveNetworks->hide();
46 ui.renameBufferView->setIcon(icon::get("edit-rename"));
47 ui.addBufferView->setIcon(icon::get("list-add"));
48 ui.deleteBufferView->setIcon(icon::get("edit-delete"));
52 ui.bufferViewList->setSortingEnabled(true);
53 ui.settingsGroupBox->setEnabled(false);
54 ui.bufferViewPreview->setEnabled(false);
56 coreConnectionStateChanged(Client::isConnected()); // need a core connection!
57 connect(Client::instance(), &Client::coreConnectionStateChanged, this, &BufferViewSettingsPage::coreConnectionStateChanged);
58 connect(ui.bufferViewList->selectionModel(),
59 &QItemSelectionModel::selectionChanged,
61 &BufferViewSettingsPage::bufferViewSelectionChanged);
63 connect(ui.onlyStatusBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
64 connect(ui.onlyChannelBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
65 connect(ui.onlyQueryBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
66 connect(ui.addNewBuffersAutomatically, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
67 connect(ui.sortAlphabetically, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
68 connect(ui.hideInactiveBuffers, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
69 connect(ui.hideInactiveNetworks, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
70 connect(ui.networkSelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::widgetHasChanged);
71 connect(ui.minimumActivitySelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::widgetHasChanged);
72 connect(ui.showSearch, &QAbstractButton::clicked, this, &BufferViewSettingsPage::widgetHasChanged);
74 connect(ui.networkSelector, selectOverload<int>(&QComboBox::currentIndexChanged), this, &BufferViewSettingsPage::enableStatusBuffers);
77 BufferViewSettingsPage::~BufferViewSettingsPage()
82 void BufferViewSettingsPage::reset()
84 ui.bufferViewList->clear();
85 ui.deleteBufferView->setEnabled(false);
87 QHash<BufferViewConfig*, BufferViewConfig*>::iterator changedConfigIter = _changedBufferViews.begin();
88 QHash<BufferViewConfig*, BufferViewConfig*>::iterator changedConfigIterEnd = _changedBufferViews.end();
89 BufferViewConfig* config;
90 while (changedConfigIter != changedConfigIterEnd) {
91 config = changedConfigIter.value();
92 changedConfigIter = _changedBufferViews.erase(changedConfigIter);
93 config->deleteLater();
96 QList<BufferViewConfig*>::iterator newConfigIter = _newBufferViews.begin();
97 QList<BufferViewConfig*>::iterator newConfigIterEnd = _newBufferViews.end();
98 while (newConfigIter != newConfigIterEnd) {
99 config = *newConfigIter;
100 newConfigIter = _newBufferViews.erase(newConfigIter);
101 config->deleteLater();
104 _deleteBufferViews.clear();
106 _useBufferViewHint = false;
108 setChangedState(false);
111 void BufferViewSettingsPage::load()
113 bool useBufferViewHint = _useBufferViewHint;
114 int bufferViewHint = _bufferViewHint;
117 if (!Client::bufferViewManager())
120 const QList<BufferViewConfig*> bufferViewConfigs = Client::bufferViewManager()->bufferViewConfigs();
121 foreach (BufferViewConfig* bufferViewConfig, bufferViewConfigs) {
122 addBufferView(bufferViewConfig);
125 _ignoreWidgetChanges = true;
126 // load network selector
127 ui.networkSelector->clear();
128 ui.networkSelector->addItem(tr("All"));
129 ui.networkSelector->setItemData(0, QVariant::fromValue(NetworkId()));
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, QVariant::fromValue(net->networkId()));
136 _ignoreWidgetChanges = false;
138 if (!useBufferViewHint || !selectBufferViewById(bufferViewHint))
139 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);
191 void BufferViewSettingsPage::coreConnectionStateChanged(bool state)
196 connect(Client::bufferViewManager(),
197 selectOverload<int>(&BufferViewManager::bufferViewConfigAdded),
199 selectOverload<int>(&BufferViewSettingsPage::addBufferView));
206 void BufferViewSettingsPage::addBufferView(BufferViewConfig* config)
208 auto* item = new QListWidgetItem(config->bufferViewName(), ui.bufferViewList);
209 item->setData(Qt::UserRole, QVariant::fromValue(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);
215 void BufferViewSettingsPage::addBufferView(int bufferViewId)
217 // we are informed about a new bufferview from Client::bufferViewManager()
218 Q_ASSERT(Client::bufferViewManager());
219 addBufferView(Client::bufferViewManager()->bufferViewConfig(bufferViewId));
220 selectBufferViewById(bufferViewId);
223 void BufferViewSettingsPage::bufferViewDeleted()
225 auto* config = static_cast<BufferViewConfig*>(sender());
227 for (int i = 0; i < ui.bufferViewList->count(); i++) {
228 obj = ui.bufferViewList->item(i)->data(Qt::UserRole).value<QObject*>();
229 if (config == static_cast<BufferViewConfig*>(obj)) {
230 QListWidgetItem* item = ui.bufferViewList->takeItem(i);
235 ui.deleteBufferView->setEnabled(ui.bufferViewList->count() > 1);
238 void BufferViewSettingsPage::newBufferView(const QString& bufferViewName)
240 // id's of newly created bufferviews are negative (-1, -2... -n)
241 int fakeId = -1 * (_newBufferViews.count() + 1);
242 auto* config = new BufferViewConfig(fakeId);
243 config->setBufferViewName(bufferViewName);
244 config->setInitialized();
245 QList<BufferId> bufferIds;
246 if (config->addNewBuffersAutomatically()) {
247 if (config->sortAlphabetically()) {
248 bufferIds = Client::networkModel()->allBufferIdsSorted();
251 bufferIds = Client::networkModel()->allBufferIds();
252 std::sort(bufferIds.begin(), bufferIds.end());
253 config->setProperty("OriginalBufferList", toVariantList<BufferId>(bufferIds));
256 config->setBufferList(bufferIds);
258 _newBufferViews << config;
259 addBufferView(config);
260 ui.bufferViewList->setCurrentRow(listPos(config));
263 int BufferViewSettingsPage::listPos(BufferViewConfig* config)
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))
274 BufferViewConfig* BufferViewSettingsPage::bufferView(int listPos)
276 if (listPos < ui.bufferViewList->count() && listPos >= 0) {
277 auto* obj = ui.bufferViewList->item(listPos)->data(Qt::UserRole).value<QObject*>();
278 return qobject_cast<BufferViewConfig*>(obj);
285 bool BufferViewSettingsPage::selectBufferViewById(int bufferViewId)
287 BufferViewConfig* config;
288 for (int i = 0; i < ui.bufferViewList->count(); i++) {
289 config = qobject_cast<BufferViewConfig*>(ui.bufferViewList->item(i)->data(Qt::UserRole).value<QObject*>());
290 if (config && config->bufferViewId() == bufferViewId) {
291 ui.bufferViewList->setCurrentRow(i);
298 void BufferViewSettingsPage::updateBufferView()
300 auto* config = qobject_cast<BufferViewConfig*>(sender());
304 int itemPos = listPos(config);
306 qWarning() << "BufferViewSettingsPage::updateBufferView(): view is unknown:" << config->bufferViewId();
309 ui.bufferViewList->item(itemPos)->setText(config->bufferViewName());
310 if (itemPos == ui.bufferViewList->currentRow())
314 void BufferViewSettingsPage::enableStatusBuffers(int networkIdx)
316 // we don't show a status buffer if we show multiple networks as selecting
317 // the network is the same as selecting the status buffer.
318 ui.onlyStatusBuffers->setEnabled(networkIdx != 0);
321 void BufferViewSettingsPage::on_addBufferView_clicked()
323 if (!Client::bufferViewManager())
326 QStringList existing;
327 foreach (BufferViewConfig* bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
328 existing << bufferConfig->bufferViewName();
331 BufferViewEditDlg dlg(QString(), existing, this);
332 if (dlg.exec() == QDialog::Accepted) {
333 newBufferView(dlg.bufferViewName());
334 setChangedState(true);
338 void BufferViewSettingsPage::on_renameBufferView_clicked()
340 if (ui.bufferViewList->selectedItems().isEmpty())
343 if (!Client::bufferViewManager())
346 BufferViewConfig* config = bufferView(ui.bufferViewList->currentRow());
350 QStringList existing;
351 foreach (BufferViewConfig* bufferConfig, Client::bufferViewManager()->bufferViewConfigs()) {
352 existing << bufferConfig->bufferViewName();
355 BufferViewEditDlg dlg(config->bufferViewName(), existing, this);
356 if (dlg.exec() == QDialog::Accepted) {
357 BufferViewConfig* changedConfig = cloneConfig(config);
358 changedConfig->setBufferViewName(dlg.bufferViewName());
359 ui.bufferViewList->item(listPos(config))->setText(dlg.bufferViewName());
360 setChangedState(true);
364 void BufferViewSettingsPage::on_deleteBufferView_clicked()
366 if (ui.bufferViewList->selectedItems().isEmpty())
369 QListWidgetItem* currentItem = ui.bufferViewList->item(ui.bufferViewList->currentRow());
370 QString viewName = currentItem->text();
371 int viewId = bufferView(ui.bufferViewList->currentRow())->bufferViewId();
372 int ret = QMessageBox::question(this,
373 tr("Delete Chat List?"),
374 tr("Do you really want to delete the chat list \"%1\"?").arg(viewName),
375 QMessageBox::Yes | QMessageBox::No,
378 if (ret == QMessageBox::Yes) {
379 ui.bufferViewList->removeItemWidget(currentItem);
380 auto* config = qobject_cast<BufferViewConfig*>(currentItem->data(Qt::UserRole).value<QObject*>());
383 _deleteBufferViews << viewId;
384 setChangedState(true);
387 QList<BufferViewConfig*>::iterator iter = _newBufferViews.begin();
388 while (iter != _newBufferViews.end()) {
389 if (*iter == config) {
390 iter = _newBufferViews.erase(iter);
398 if (_deleteBufferViews.isEmpty() && _changedBufferViews.isEmpty() && _newBufferViews.isEmpty())
399 setChangedState(false);
404 void BufferViewSettingsPage::bufferViewSelectionChanged(const QItemSelection& current, const QItemSelection& previous)
408 if (!current.isEmpty()) {
409 ui.settingsGroupBox->setEnabled(true);
410 ui.bufferViewPreview->setEnabled(true);
412 loadConfig(configForDisplay(bufferView(ui.bufferViewList->currentRow())));
415 ui.settingsGroupBox->setEnabled(false);
416 ui.bufferViewPreview->setEnabled(false);
420 void BufferViewSettingsPage::loadConfig(BufferViewConfig* config)
425 _ignoreWidgetChanges = true;
426 ui.onlyStatusBuffers->setChecked(BufferInfo::StatusBuffer & config->allowedBufferTypes());
427 ui.onlyChannelBuffers->setChecked(BufferInfo::ChannelBuffer & config->allowedBufferTypes());
428 ui.onlyQueryBuffers->setChecked(BufferInfo::QueryBuffer & config->allowedBufferTypes());
429 ui.addNewBuffersAutomatically->setChecked(config->addNewBuffersAutomatically());
430 ui.sortAlphabetically->setChecked(config->sortAlphabetically());
431 ui.hideInactiveBuffers->setChecked(config->hideInactiveBuffers());
432 ui.hideInactiveNetworks->setChecked(config->hideInactiveNetworks());
433 ui.showSearch->setChecked(config->showSearch());
435 int networkIndex = 0;
436 for (int i = 0; i < ui.networkSelector->count(); i++) {
437 if (ui.networkSelector->itemData(i).value<NetworkId>() == config->networkId()) {
442 ui.networkSelector->setCurrentIndex(networkIndex);
444 int activityIndex = 0;
445 int minimumActivity = config->minimumActivity();
446 while (minimumActivity) {
448 minimumActivity = minimumActivity >> 1;
450 ui.minimumActivitySelector->setCurrentIndex(activityIndex);
452 ui.bufferViewPreview->setFilteredModel(Client::bufferModel(), config);
454 _ignoreWidgetChanges = false;
457 void BufferViewSettingsPage::saveConfig(BufferViewConfig* config)
462 int allowedBufferTypes = 0;
463 if (ui.onlyStatusBuffers->isChecked())
464 allowedBufferTypes |= BufferInfo::StatusBuffer;
465 if (ui.onlyChannelBuffers->isChecked())
466 allowedBufferTypes |= BufferInfo::ChannelBuffer;
467 if (ui.onlyQueryBuffers->isChecked())
468 allowedBufferTypes |= BufferInfo::QueryBuffer;
469 config->setAllowedBufferTypes(allowedBufferTypes);
471 config->setAddNewBuffersAutomatically(ui.addNewBuffersAutomatically->isChecked());
472 config->setSortAlphabetically(ui.sortAlphabetically->isChecked());
473 config->setHideInactiveBuffers(ui.hideInactiveBuffers->isChecked());
474 config->setHideInactiveNetworks(ui.hideInactiveNetworks->isChecked());
475 config->setNetworkId(ui.networkSelector->itemData(ui.networkSelector->currentIndex()).value<NetworkId>());
476 config->setShowSearch(ui.showSearch->isChecked());
478 int minimumActivity = 0;
479 if (ui.minimumActivitySelector->currentIndex() > 0)
480 minimumActivity = 1 << (ui.minimumActivitySelector->currentIndex() - 1);
481 config->setMinimumActivity(minimumActivity);
483 QList<BufferId> bufferIds = fromVariantList<BufferId>(config->property("OriginalBufferList").toList());
484 if (config->sortAlphabetically())
485 Client::networkModel()->sortBufferIds(bufferIds);
487 if (!_newBufferViews.contains(config) || config->addNewBuffersAutomatically())
488 config->setBufferList(bufferIds);
491 void BufferViewSettingsPage::widgetHasChanged()
493 if (_ignoreWidgetChanges)
495 setChangedState(testHasChanged());
498 bool BufferViewSettingsPage::testHasChanged()
500 saveConfig(cloneConfig(bufferView(ui.bufferViewList->currentRow())));
502 if (!_newBufferViews.isEmpty())
505 bool changed = false;
506 QHash<BufferViewConfig*, BufferViewConfig*>::iterator iter = _changedBufferViews.begin();
507 QHash<BufferViewConfig*, BufferViewConfig*>::iterator iterEnd = _changedBufferViews.end();
508 while (iter != iterEnd) {
509 if (&(iter.key()) == &(iter.value())) {
510 iter.value()->deleteLater();
511 iter = _changedBufferViews.erase(iter);
521 BufferViewConfig* BufferViewSettingsPage::cloneConfig(BufferViewConfig* config)
523 if (!config || config->bufferViewId() < 0)
526 if (_changedBufferViews.contains(config))
527 return _changedBufferViews[config];
529 auto* changedConfig = new BufferViewConfig(-1, this);
530 changedConfig->fromVariantMap(config->toVariantMap());
531 changedConfig->setInitialized();
532 _changedBufferViews[config] = changedConfig;
533 connect(config, &BufferViewConfig::bufferAdded, changedConfig, &BufferViewConfig::addBuffer);
534 connect(config, &BufferViewConfig::bufferMoved, changedConfig, &BufferViewConfig::moveBuffer);
535 connect(config, &BufferViewConfig::bufferRemoved, changedConfig, &BufferViewConfig::removeBuffer);
536 // connect(config, &BufferViewConfig::addBufferRequested, changedConfig, &BufferViewConfig::addBuffer);
537 // connect(config, &BufferViewConfig::moveBufferRequested, changedConfig, &BufferViewConfig::moveBuffer);
538 // connect(config, &BufferViewconfig::removeBufferRequested, changedConfig, &BufferViewConfig::removeBuffer);
540 changedConfig->setProperty("OriginalBufferList", toVariantList<BufferId>(config->bufferList()));
541 // if this is the currently displayed view we have to change the config of the preview filter
542 auto* filter = qobject_cast<BufferViewFilter*>(ui.bufferViewPreview->model());
543 if (filter && filter->config() == config)
544 filter->setConfig(changedConfig);
545 ui.bufferViewPreview->setConfig(changedConfig);
547 return changedConfig;
550 BufferViewConfig* BufferViewSettingsPage::configForDisplay(BufferViewConfig* config)
552 if (_changedBufferViews.contains(config))
553 return _changedBufferViews[config];
558 /**************************************************************************
560 *************************************************************************/
561 BufferViewEditDlg::BufferViewEditDlg(const QString& old, QStringList exist, QWidget* parent)
563 , existing(std::move(exist))
569 setWindowTitle(tr("Add Chat List"));
570 on_bufferViewEdit_textChanged(""); // disable ok button
573 ui.bufferViewEdit->setText(old);
577 void BufferViewEditDlg::on_bufferViewEdit_textChanged(const QString& text)
579 ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));