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