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