--- /dev/null
+/*
+ * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "Settings.h"
+#include "SettingsDialog.h"
+#include "helpers/SearchEngineHelper.h"
+#include "helpers/UserAgentHelper.h"
+#include "ui_SettingsGeneral.h"
+#include "ui_SettingsPrivacy.h"
+#include "ui_SettingsSpellCheck.h"
+
+// Qt toolkit headers.
+#include <QDir>
+#include <QFileDialog>
+
+SettingsDialog::SettingsDialog(QWidget *parentWidgetPointer, KCoreConfigSkeleton *coreConfigSkeletonPointer) :
+ KConfigDialog(parentWidgetPointer, QLatin1String("settings"), coreConfigSkeletonPointer)
+{
+ // Instantiate the settings UI.
+ Ui::PrivacySettings privacySettingsUi;
+ Ui::GeneralSettings generalSettingsUi;
+ Ui::SpellCheckSettings spellCheckSettingsUi;
+
+ // Create the settings widgets.
+ QWidget *privacySettingsWidgetPointer = new QWidget;
+ QWidget *generalSettingsWidgetPointer = new QWidget;
+ QWidget *spellCheckSettingsWidgetPointer = new QWidget;
+
+ // Setup the UI to display the settings widgets.
+ privacySettingsUi.setupUi(privacySettingsWidgetPointer);
+ generalSettingsUi.setupUi(generalSettingsWidgetPointer);
+ spellCheckSettingsUi.setupUi(spellCheckSettingsWidgetPointer);
+
+ // Get handles for the widgets.
+ QCheckBox *javaScriptCheckBoxPointer = privacySettingsUi.kcfg_javaScriptEnabled;
+ QCheckBox *localStorageCheckBoxPointer = privacySettingsUi.kcfg_localStorageEnabled;
+ QCheckBox *domStorageCheckBoxPointer = privacySettingsUi.kcfg_domStorageEnabled;
+ QComboBox *userAgentComboBoxPointer = privacySettingsUi.kcfg_userAgent;
+ userAgentLabelPointer = privacySettingsUi.userAgentLabel;
+ QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine;
+ searchEngineLabelPointer = generalSettingsUi.searchEngineLabel;
+ downloadDirectoryComboBoxPointer = generalSettingsUi.kcfg_downloadDirectory;
+ QPushButton *browseButtonPointer = generalSettingsUi.browseButton;
+ QListWidget *spellCheckListWidgetPointer = spellCheckSettingsUi.spellCheckListWidget;
+
+ // Create a save spell check languages lambda.
+ auto updateCheckBoxes = [javaScriptCheckBoxPointer, localStorageCheckBoxPointer, domStorageCheckBoxPointer] ()
+ {
+ // Only enable the DOM storage check box if both JavaScript and local storage are checked.
+ domStorageCheckBoxPointer->setEnabled(javaScriptCheckBoxPointer->isChecked() && localStorageCheckBoxPointer->isChecked());
+ };
+
+ // Update the status of the DOM storage check box when either JavaScript or local storage are changed.
+ connect(javaScriptCheckBoxPointer, &QCheckBox::stateChanged, this, updateCheckBoxes);
+ connect(localStorageCheckBoxPointer, &QCheckBox::stateChanged, this, updateCheckBoxes);
+
+ // Populate the combo box labels.
+ updateUserAgentLabel(userAgentComboBoxPointer->currentText());
+ updateSearchEngineLabel(searchEngineComboBoxPointer->currentText());
+
+ // Update the labels when the combo boxes change.
+ connect(userAgentComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateUserAgentLabel(const QString)));
+ connect(searchEngineComboBoxPointer, SIGNAL(currentTextChanged(const QString)), this, SLOT(updateSearchEngineLabel(const QString)));
+
+ // Connect the download directory directory browse button.
+ connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(showDownloadDirectoryBrowseDialog()));
+
+ // Create a dictionaries QDir from the `QTWEBENGINE_DICTIONARIES_PATH` environment variable.
+ QDir dictionariesDir = QDir(qEnvironmentVariable("QTWEBENGINE_DICTIONARIES_PATH"));
+
+ // Get a dictionaries string list.
+ QStringList dictionariesStringList = dictionariesDir.entryList(QStringList(QLatin1String("*.bdic")), QDir::Files | QDir::NoSymLinks);
+
+ // Remove the `.bdic` file extensions from the dictionaries list.
+ dictionariesStringList.replaceInStrings(QLatin1String(".bdic"), QLatin1String(""));
+
+ // Get a list of the enabled spell check languages.
+ QStringList enabledSpellCheckLanguagesList = Settings::spellCheckLanguages();
+
+ // Add each dictionary to the spell check list widget.
+ foreach(QString dictionaryString, dictionariesStringList)
+ {
+ // Create a new list widget item pointer.
+ QListWidgetItem *listWidgetItemPointer = new QListWidgetItem();
+
+ // Create a dictionary check box widget with the name of the dictionary string.
+ QCheckBox *dictionaryCheckBoxWidget = new QCheckBox(dictionaryString);
+
+ // Check the language if it is currently enabled.
+ if (enabledSpellCheckLanguagesList.contains(dictionaryString))
+ dictionaryCheckBoxWidget->setCheckState(Qt::Checked);
+ else
+ dictionaryCheckBoxWidget->setCheckState(Qt::Unchecked);
+
+ // Add the list widget item to the spell check list widget.
+ spellCheckListWidgetPointer->addItem(listWidgetItemPointer);
+
+ // Set the list widget item check box widget.
+ spellCheckListWidgetPointer->setItemWidget(listWidgetItemPointer, dictionaryCheckBoxWidget);
+ }
+
+ // Create a settings icon string.
+ QString settingsIconString;
+
+ // Get a settings icon that matches the theme.
+ if (QIcon::hasThemeIcon("breeze-settings"))
+ {
+ // KDE uses breeze-settings.
+ settingsIconString = QLatin1String("breeze-settings");
+ }
+ else
+ {
+ // Gnome uses preferences-desktop.
+ settingsIconString = QLatin1String("preferences-desktop");
+ }
+
+ // Add the settings widgets as config dialog pages.
+ addPage(privacySettingsWidgetPointer, i18nc("Settings tab title", "Privacy"), QLatin1String("privacybrowser"));
+ addPage(generalSettingsWidgetPointer, i18nc("Settings tab title", "General"), settingsIconString);
+ addPage(spellCheckSettingsWidgetPointer, i18nc("Settings tab title", "Spell Check"), QLatin1String("tools-check-spelling"));
+
+ // Get handles for the buttons.
+ QPushButton *applyButtonPointer = button(QDialogButtonBox::Apply);
+ QPushButton *okButtonPointer = button(QDialogButtonBox::Ok);
+
+ // Prevent interaction with the parent window while the dialog is open.
+ setWindowModality(Qt::WindowModal);
+
+ // Create a save spell check languages lambda.
+ auto saveSpellCheckLanguages = [spellCheckListWidgetPointer, coreConfigSkeletonPointer, this] ()
+ {
+ // Create a list of enabled languages.
+ QStringList newSpellCheckLanguages = QStringList();
+
+ // Get a count of all the languages.
+ int allLanguagesCount = spellCheckListWidgetPointer->count();
+
+ // Get a list of all the checked languages.
+ for (int i = 0; i < allLanguagesCount; ++i) {
+ // Get the language item.
+ QListWidgetItem *languageItemPointer = spellCheckListWidgetPointer->item(i);
+
+ // Get the language check box.
+ QCheckBox *languageCheckBoxPointer = qobject_cast<QCheckBox*>(spellCheckListWidgetPointer->itemWidget(languageItemPointer));
+
+ // Add the item to the enabled languages if it is checked.
+ if (languageCheckBoxPointer->checkState() == Qt::Checked)
+ {
+ // Get the text.
+ QString languageString = languageCheckBoxPointer->text();
+
+ // Remove all instances of `&`, which may have been added automatically when creating the check box text.
+ languageString.remove(QChar('&'));
+
+ // Add the language string to the list.
+ newSpellCheckLanguages.append(languageString);
+ }
+ }
+
+ // Update the spell check languages.
+ if (Settings::spellCheckLanguages() != newSpellCheckLanguages)
+ {
+ // Update the spell check languages.
+ Settings::setSpellCheckLanguages(newSpellCheckLanguages);
+
+ // Write the settings to disk.
+ coreConfigSkeletonPointer->save();
+
+ // Emit the spell check languages updated signal.
+ emit spellCheckLanguagesUpdated();
+ }
+ };
+
+ // Process clicks on the buttons.
+ connect(applyButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
+ connect(okButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
+}
+
+void SettingsDialog::showDownloadDirectoryBrowseDialog()
+{
+ // Get the current download directory.
+ QString currentDownloadDirectory = downloadDirectoryComboBoxPointer->currentText();
+
+ // Resolve the system download directory if specified.
+ if (currentDownloadDirectory == QStringLiteral("System Download Directory"))
+ currentDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
+
+ // Get the new download directory.
+ QString newDownloadDirectory = QFileDialog::getExistingDirectory(this, i18nc("Select download directory dialog caption", "Select Download Directory"), currentDownloadDirectory);
+
+ // Populate the download directory combo box according to the new download location.
+ if (newDownloadDirectory == QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) // The default download location was selected.
+ {
+ // Populate the download location with the default text.
+ downloadDirectoryComboBoxPointer->setCurrentText("System Download Directory");
+ }
+ else if (newDownloadDirectory != QStringLiteral("")) // A different directory was selected.
+ {
+ // Populate the download location.
+ downloadDirectoryComboBoxPointer->setCurrentText(newDownloadDirectory);
+ }
+}
+
+void SettingsDialog::updateSearchEngineLabel(const QString &searchEngineString) const
+{
+ // Update the search engine label.
+ searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString));
+}
+
+void SettingsDialog::updateUserAgentLabel(const QString &userAgentDatabaseName) const
+{
+ // Update the user agent label.
+ userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName));
+}