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