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