eb43fb560ec7431b94dd1e1bbbf2721af5a604d0
[PrivacyBrowserPC.git] / src / dialogs / DomainSettingsDialog.cpp
1 /*
2  * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
5  *
6  * Privacy Browser PC is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser PC is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 // Application headers.
21 #include "DomainSettingsDialog.h"
22 #include "Settings.h"
23 #include "ui_DomainSettingsDialog.h"
24 #include "helpers/DomainsDatabaseHelper.h"
25 #include "helpers/UserAgentHelper.h"
26
27 // Qt toolkit headers.
28 #include <QInputDialog>
29 #include <QMessageBox>
30 #include <QPushButton>
31
32 // Define the public static int constants.
33 const int DomainSettingsDialog::SHOW_ALL_DOMAINS = 0;
34 const int DomainSettingsDialog::ADD_DOMAIN = 1;
35 const int DomainSettingsDialog::EDIT_DOMAIN = 2;
36
37 // Construct the class.
38 DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &domainName) : QDialog(nullptr)
39 {
40     // Set the window title.
41     setWindowTitle(i18nc("The domain settings dialog window title", "Domain Settings"));
42
43     // Set the window modality.
44     setWindowModality(Qt::WindowModality::ApplicationModal);;
45
46     // Instantiate the domain settings dialog UI.
47     Ui::DomainSettingsDialog domainSettingsDialogUi;
48
49     // Setup the UI.
50     domainSettingsDialogUi.setupUi(this);
51
52     // Get handles for the widgets.
53     domainsListViewPointer = domainSettingsDialogUi.domainsListView;
54     domainSettingsWidgetPointer = domainSettingsDialogUi.domainSettingsWidget;
55     domainNameLineEditPointer = domainSettingsDialogUi.domainNameLineEdit;
56     javaScriptComboBoxPointer = domainSettingsDialogUi.javaScriptComboBox;
57     javaScriptLabelPointer = domainSettingsDialogUi.javaScriptLabel;
58     domStorageComboBoxPointer = domainSettingsDialogUi.domStorageComboBox;
59     domStorageLabelPointer = domainSettingsDialogUi.domStorageLabel;
60     userAgentComboBoxPointer = domainSettingsDialogUi.userAgentComboBox;
61     userAgentLabelPointer = domainSettingsDialogUi.userAgentLabel;
62     zoomFactorComboBoxPointer = domainSettingsDialogUi.zoomFactorComboBox;
63     customZoomFactorSpinBoxPointer = domainSettingsDialogUi.customZoomFactorSpinBox;
64     QPushButton *addDomainButtonPointer = domainSettingsDialogUi.addDomainButton;
65     deleteDomainButtonPointer = domainSettingsDialogUi.deleteDomainButton;
66     QDialogButtonBox *dialogButtonBoxPointer = domainSettingsDialogUi.dialogButtonBox;
67     applyButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Apply);
68     resetButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Reset);
69
70     // Create a table model.
71     domainsTableModelPointer = new QSqlTableModel(nullptr, QSqlDatabase::database(DomainsDatabaseHelper::CONNECTION_NAME));
72
73     // Set the table for the model.
74     domainsTableModelPointer->setTable(DomainsDatabaseHelper::DOMAINS_TABLE);
75
76     // Set the edit strategy to be manual.
77     domainsTableModelPointer->setEditStrategy(QSqlTableModel::EditStrategy::OnManualSubmit);
78
79     // Sort the output alphabetically.
80     domainsTableModelPointer->setSort(1, Qt::SortOrder::AscendingOrder);
81
82     // Set the model for the list view.
83     domainsListViewPointer->setModel(domainsTableModelPointer);
84
85     // Set the visible column to be the domain name.
86     domainsListViewPointer->setModelColumn(1);
87
88     // Disable editing of the list view.
89     domainsListViewPointer->setEditTriggers(QAbstractItemView::NoEditTriggers);
90
91     // Read the data from the database and apply it to the table model.
92     domainsTableModelPointer->select();
93
94     // Setup the dialog according to the start type.
95     switch (startType)
96     {
97         case SHOW_ALL_DOMAINS:
98         {
99             // Select the first entry in the list view.
100             domainsListViewPointer->setCurrentIndex(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)));
101
102             // Populate the domain settings.
103             domainSelected(domainsListViewPointer->selectionModel()->currentIndex());
104
105             break;
106         }
107
108         case ADD_DOMAIN:
109         {
110             // Add the new domain.
111             addDomain(domainName);
112
113             break;
114         }
115
116         case EDIT_DOMAIN:
117         {
118             // Find the index for the new domain.  `1` returns the first match.
119             QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)),
120                                                                         Qt::DisplayRole, domainName, 1, Qt::MatchWrap);
121
122             // Move to the new domain.
123             domainsListViewPointer->setCurrentIndex(newDomainIndex[0]);
124
125             // Populate the domain settings.
126             domainSelected(domainsListViewPointer->selectionModel()->currentIndex());
127         }
128     }
129
130     // Handle clicks on the domains.
131     connect(domainsListViewPointer, SIGNAL(activated(QModelIndex)), this, SLOT(domainSelected(QModelIndex)));
132
133     // Process changes to the domain settings.
134     connect(domainNameLineEditPointer, SIGNAL(textEdited(QString)), this, SLOT(domainNameChanged(QString)));
135     connect(javaScriptComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(javaScriptChanged(int)));
136     connect(domStorageComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(domStorageChanged(int)));
137     connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(QString)), this, SLOT(userAgentChanged(QString)));
138     connect(zoomFactorComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(zoomFactorComboBoxChanged(int)));
139     connect(customZoomFactorSpinBoxPointer, SIGNAL(valueChanged(double)), this, SLOT(customZoomFactorChanged(double)));
140
141     // Connect the buttons.
142     connect(addDomainButtonPointer, SIGNAL(clicked()), this, SLOT(showAddMessageBox()));
143     connect(deleteDomainButtonPointer, SIGNAL(clicked()), this, SLOT(showDeleteMessageBox()));
144     connect(resetButtonPointer, SIGNAL(clicked()), this, SLOT(reset()));
145     connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(ok()));
146     connect(applyButtonPointer, SIGNAL(clicked()), this, SLOT(apply()));
147     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(cancel()));
148
149     // Update the UI.
150     updateUi();
151 }
152
153 void DomainSettingsDialog::addDomain(const QString &domainName) const
154 {
155     // Create a new domain record.
156     QSqlRecord newDomainRecord = QSqlDatabase::database(DomainsDatabaseHelper::CONNECTION_NAME).record(DomainsDatabaseHelper::DOMAINS_TABLE);
157
158     // Set the values for the new domain.
159     newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME), domainName);
160     newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT), DomainsDatabaseHelper::SYSTEM_DEFAULT);
161     newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOM_STORAGE), DomainsDatabaseHelper::SYSTEM_DEFAULT);
162     newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::USER_AGENT), UserAgentHelper::SYSTEM_DEFAULT_DATABASE);
163     newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::ZOOM_FACTOR), DomainsDatabaseHelper::SYSTEM_DEFAULT);
164     newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR), 1.0);
165
166     // Insert the new domain.  `-1` appends it to the end.
167     domainsTableModelPointer->insertRecord(-1, newDomainRecord);
168
169     // Submit all pending changes.
170     domainsTableModelPointer->submitAll();
171
172     // Find the index for the new domain.  `-1` allows for multiple entries to be returned.
173     QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)),
174                                                                         Qt::DisplayRole, domainName, -1, Qt::MatchWrap);
175
176     // Move to the new domain.  If there are multiple domains with the same name, the new one should be the last in the list.
177     domainsListViewPointer->setCurrentIndex(newDomainIndex[newDomainIndex.size() - 1]);
178
179     // Populate the domain settings.
180     domainSelected(domainsListViewPointer->selectionModel()->currentIndex());
181
182     // Update the UI.
183     updateUi();
184 }
185
186
187 void DomainSettingsDialog::apply() const
188 {
189     // Get the current index.
190     QModelIndex currentIndex = domainsListViewPointer->currentIndex();
191
192     // Get the ID of the current index row.
193     QVariant currentId = currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::_ID)).data();
194
195     // Submit all pending changes.
196     domainsTableModelPointer->submitAll();
197
198     // Find the new index for the selected id.  The `1` keeps searching after the first match.
199     QModelIndexList newIndexList = domainsTableModelPointer->match(currentIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::_ID)), Qt::DisplayRole, currentId,
200                                                                    1, Qt::MatchWrap);
201
202     // Select the new index.
203     domainsListViewPointer->setCurrentIndex(newIndexList[0].siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOMAIN_NAME)));
204
205     // Update the UI.
206     updateUi();
207
208     // Emit the domain settings updated signal.
209     emit domainSettingsUpdated();
210 }
211
212 void DomainSettingsDialog::cancel()
213 {
214     // Revert all pending changes.
215     domainsTableModelPointer->revertAll();
216
217     // Close the dialog.
218     reject();
219 }
220
221 void DomainSettingsDialog::customZoomFactorChanged(const double &newValue) const
222 {
223     // Update the domains table model.
224     domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR)),
225                                       newValue);
226
227     // Update the UI.
228     updateUi();
229 }
230
231 void DomainSettingsDialog::domainNameChanged(const QString &updatedDomainName) const
232 {
233     // Update the domains table model.
234     domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex(), updatedDomainName);
235
236     // Update the UI.
237     updateUi();
238 }
239
240 void DomainSettingsDialog::domainSelected(const QModelIndex &modelIndex) const
241 {
242     // Populate the domain name line edit pointer.
243     domainNameLineEditPointer->setText(modelIndex.data().toString());
244
245     // Populate the JavaScript combo box.
246     javaScriptComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT)).data().toInt());
247
248     // Populate the DOM storage combo box.
249     domStorageComboBoxPointer->setCurrentIndex(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOM_STORAGE)).data().toInt());
250
251     // Get the user agent string.
252     QString userAgent = modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::USER_AGENT)).data().toString();
253
254     // Get the user agent index.
255     int userAgentIndex = UserAgentHelper::getDomainSettingsUserAgentIndex(userAgent);
256
257     // Set the user agent combo box index.
258     userAgentComboBoxPointer->setCurrentIndex(userAgentIndex);
259
260     // Set the custom user agent if specified.
261     if (userAgentIndex == -1) userAgentComboBoxPointer->setCurrentText(userAgent);
262
263     // Get the zoom factor combo box index.
264     int zoomFactorComboBoxIndex = modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::ZOOM_FACTOR)).data().toInt();
265
266     // Populate the zoom factor combo box.
267     zoomFactorComboBoxPointer->setCurrentIndex(zoomFactorComboBoxIndex);
268
269     // Populate the custom zoom factor spin box according to the zoom factor combo box.
270     if (zoomFactorComboBoxIndex == 0)  // System default zoom factor is selected.
271     {
272         // Display the default zoom factor.
273         customZoomFactorSpinBoxPointer->setValue(Settings::zoomFactor());
274     }
275     else  // Custom zoom factor is selected.
276     {
277         // Display the custom zoom factor from the domain settings.
278         customZoomFactorSpinBoxPointer->setValue(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR)).data().toDouble());
279     }
280
281     // Set the initial status of the custom zoom factor spin box.
282     customZoomFactorSpinBoxPointer->setEnabled(zoomFactorComboBoxIndex);
283
284     // Populate the labels.
285     populateJavaScriptLabel();
286     populateDomStorageLabel();
287     populateUserAgentLabel(userAgentComboBoxPointer->currentText());
288
289     // Update the UI.
290     updateUi();
291 }
292
293 void DomainSettingsDialog::javaScriptChanged(const int &newIndex) const
294 {
295     // Update the domains table model.
296     domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::JAVASCRIPT)),
297                                       newIndex);
298
299     // Populate the JavaScript label.
300     populateJavaScriptLabel();
301
302     // Update the UI.
303     updateUi();
304 }
305
306 void DomainSettingsDialog::domStorageChanged(const int &newIndex) const
307 {
308     // Update the domains table model.
309     domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::DOM_STORAGE)),
310                                       newIndex);
311
312     // Populate the DOM storage label.
313     populateDomStorageLabel();
314
315     // Update the UI.
316     updateUi();
317 }
318
319 void DomainSettingsDialog::ok()
320 {
321     // Submit all pending changes.
322     domainsTableModelPointer->submitAll();
323
324     // Emit the domain settings updated signal.
325     domainSettingsUpdated();
326
327     // Close the dialog.
328     accept();
329 }
330
331 void DomainSettingsDialog::populateJavaScriptLabel() const
332 {
333     // Populate the label according to the currently selected index.
334     switch (javaScriptComboBoxPointer->currentIndex())
335     {
336         case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
337         {
338             // Set the text according to the system default.
339             if (Settings::javaScriptEnabled())
340                 javaScriptLabelPointer->setText(i18nc("Domains settings label", "JavaScript enabled"));
341             else
342                 javaScriptLabelPointer->setText(i18nc("Domain settings label", "JavaScript disabled"));
343
344             break;
345         }
346
347         case (DomainsDatabaseHelper::DISABLED):
348         {
349             // Set the label text in bold.
350             javaScriptLabelPointer->setText(i18nc("Domain settings label.  The <b> tags should be retained.", "<b>JavaScript disabled</b>"));
351
352             break;
353         }
354
355         case (DomainsDatabaseHelper::ENABLED):
356         {
357             // Set the label text in bold.
358             javaScriptLabelPointer->setText(i18nc("Domains settings label.  The <b> tags should be retained.", "<b>JavaScript enabled</b>"));
359
360             break;
361         }
362     }
363 }
364
365 void DomainSettingsDialog::populateDomStorageLabel() const
366 {
367     // Populate the label according to the currently selected index.
368     switch (domStorageComboBoxPointer->currentIndex())
369     {
370         case (DomainsDatabaseHelper::SYSTEM_DEFAULT):
371         {
372             // Set the text according to the system default.
373             if (Settings::domStorageEnabled())
374                 domStorageLabelPointer->setText(i18nc("DOM storage label", "DOM storage enabled"));
375             else
376                 domStorageLabelPointer->setText(i18nc("DOM storage label", "DOM storage disabled"));
377
378             break;
379         }
380
381         case (DomainsDatabaseHelper::DISABLED):
382         {
383             // Set the label text in bold.
384             domStorageLabelPointer->setText(i18nc("DOM storage label.  The <b> tags should be retained.", "<b>DOM storage disabled</b>"));
385
386             break;
387         }
388
389         case (DomainsDatabaseHelper::ENABLED):
390         {
391             // Set the label text in bold.
392             domStorageLabelPointer->setText(i18nc("DOM storage label.  The <b> tags should be retained.", "<b>DOM storage enabled</b>"));
393
394             break;
395         }
396     }
397 }
398
399 void DomainSettingsDialog::populateUserAgentLabel(const QString &userAgentName) const
400 {
401     // Populate the label according to the type.
402     if (userAgentName == UserAgentHelper::SYSTEM_DEFAULT_TRANSLATED)
403     {
404         // Display the system default user agent name.
405         userAgentLabelPointer->setText(UserAgentHelper::getTranslatedUserAgentNameFromDatabaseName(Settings::userAgent()));
406     }
407     else
408     {
409         // Display the user agent name in bold.
410         userAgentLabelPointer->setText("<strong>" + userAgentName + "</strong>");
411     }
412 }
413
414 void DomainSettingsDialog::reset() const
415 {
416     // Cancel all pending changes.
417     domainsTableModelPointer->revertAll();
418
419     // Repopulate the domain settings.
420     domainSelected(domainsListViewPointer->currentIndex());
421
422     // Update the UI.
423     updateUi();
424 }
425
426 void DomainSettingsDialog::showAddMessageBox()
427 {
428     // Create an OK flag.
429     bool okClicked;
430
431     // Display a dialog to request the new domain name from the user.
432     QString newDomainName = QInputDialog::getText(this, i18nc("Add domain dialog title", "Add Domain"),
433                                                   i18nc("Add domain message.  The \n\n are newline codes that should be retained",
434                                                         "Add a new domain.  Doing so will also save any pending changes that have been made to other domains.\n\n"
435                                                         "*. may be prepended to a domain to include all subdomains (eg. *.stoutner.com)."),
436                                                   QLineEdit::Normal, QString(), &okClicked);
437
438     // Add the new domain if the user clicked OK.
439     if (okClicked) addDomain(newDomainName);
440 }
441
442 void DomainSettingsDialog::showDeleteMessageBox() const
443 {
444     // Instantiate a delete dialog message box.
445     QMessageBox deleteDialogMessageBox;
446
447     // Set the icon.
448     deleteDialogMessageBox.setIcon(QMessageBox::Warning);
449
450     // Set the window title.
451     deleteDialogMessageBox.setWindowTitle(i18nc("Delete domain dialog title", "Delete Domain"));
452
453     // Set the text.
454     deleteDialogMessageBox.setText(i18nc("Delete domain dialog main message", "Delete the current domain?"));
455
456     // Set the informative text.
457     deleteDialogMessageBox.setInformativeText(i18nc("Delete domain dialog secondary message", "Doing so will also save any pending changes that have been made to other domains."));
458
459     // Set the standard buttons.
460     deleteDialogMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
461
462     // Set the default button.
463     deleteDialogMessageBox.setDefaultButton(QMessageBox::No);
464
465     // Display the dialog and capture the return value.
466     int returnValue = deleteDialogMessageBox.exec();
467
468     // Delete the domain if instructed.
469     if (returnValue == QMessageBox::Yes)
470     {
471         // Get the current index.
472         QModelIndex currentIndex = domainsListViewPointer->currentIndex();
473
474         // Delete the current row.
475         domainsTableModelPointer->removeRow(domainsListViewPointer->selectionModel()->currentIndex().row());
476
477         // Submit all pending changes.
478         domainsTableModelPointer->submitAll();
479
480         // Select the row next to the deleted item if one exists.
481         if (domainsTableModelPointer->rowCount() > 0)
482         {
483             // Check the row of the deleted item.
484             if (currentIndex.row() == 0)  // The first row was deleted.
485             {
486                 // Reselect the current index.
487                 domainsListViewPointer->setCurrentIndex(currentIndex);
488             }
489             else  // A subsequent row was deleted.
490             {
491                 // Select the crow above the deleted itemm.
492                 domainsListViewPointer->setCurrentIndex(currentIndex.siblingAtRow(currentIndex.row() - 1));
493             }
494
495             // Populate the domain settings.
496             domainSelected(domainsListViewPointer->currentIndex());
497         }
498
499         // Update the Ui.
500         updateUi();
501     }
502 }
503
504 void DomainSettingsDialog::updateUi() const
505 {
506     // Update the delete button status.
507     deleteDomainButtonPointer->setEnabled(domainsListViewPointer->selectionModel()->hasSelection());
508
509     // Update the apply button status.
510     applyButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
511
512     // Update the reset button status.
513     resetButtonPointer->setEnabled(domainsTableModelPointer->isDirty());
514
515     // Display the domain settings if there is at least one domain.
516     domainSettingsWidgetPointer->setVisible(domainsTableModelPointer->rowCount() > 0);
517 }
518
519 void DomainSettingsDialog::userAgentChanged(const QString &updatedUserAgent) const
520 {
521     // Update the domains table model.
522     domainsTableModelPointer->setData(domainsListViewPointer->selectionModel()->currentIndex().siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::USER_AGENT)),
523                                       UserAgentHelper::getDatabaseUserAgentNameFromTranslatedName(updatedUserAgent));
524
525     // Populate the user agent label.
526     populateUserAgentLabel(updatedUserAgent);
527
528     // Update the UI.
529     updateUi();
530 }
531
532 void DomainSettingsDialog::zoomFactorComboBoxChanged(const int &newIndex) const
533 {
534     // Get the current model index.
535     QModelIndex modelIndex = domainsListViewPointer->selectionModel()->currentIndex();
536
537     // Update the domains table model.
538     domainsTableModelPointer->setData(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::ZOOM_FACTOR)), newIndex);
539
540     // Populate the custom zoom factor spin box according to the zoom factor combo box.
541     if (newIndex == 0)  // System default zoom factor is selected.
542     {
543         // Display the default zoom factor.
544         customZoomFactorSpinBoxPointer->setValue(Settings::zoomFactor());
545     }
546     else  // Custom zoom factor is selected.
547     {
548         // Display the custom zoom factor from the domain settings.
549         customZoomFactorSpinBoxPointer->setValue(modelIndex.siblingAtColumn(domainsTableModelPointer->fieldIndex(DomainsDatabaseHelper::CUSTOM_ZOOM_FACTOR)).data().toDouble());
550     }
551
552     // Update the status of the custom zoom factor spin box.
553     customZoomFactorSpinBoxPointer->setEnabled(newIndex);
554
555     // Update the UI.
556     updateUi();
557 }