+ // Display the context menu.
+ bookmarkContextMenuPointer->popup(bookmarksToolBarPointer->mapToGlobal(point));
+ }
+ else // The toolbar background was clicked.
+ {
+ // Temporarily set the context menu policy to the default.
+ bookmarksToolBarPointer->setContextMenuPolicy(Qt::DefaultContextMenu);
+
+ // Create a context menu event with the same position.
+ QContextMenuEvent *contextMenuEventPointer = new QContextMenuEvent(QContextMenuEvent::Mouse, point);
+
+ // Send the context menu event to the toolbar.
+ QCoreApplication::sendEvent(bookmarksToolBarPointer, contextMenuEventPointer);
+
+ // Reset the context menu policy.
+ bookmarksToolBarPointer->setContextMenuPolicy(Qt::CustomContextMenu);
+ }
+}
+
+void BrowserWindow::showCookiesDialog()
+{
+ // Remove the focus from the URL line edit.
+ urlLineEditPointer->clearFocus();
+
+ // Instantiate the cookie settings dialog.
+ CookiesDialog *cookiesDialogPointer = new CookiesDialog(tabWidgetPointer->getCookieList());
+
+ // Show the dialog.
+ cookiesDialogPointer->show();
+
+ // Connect the dialog signals.
+ connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), tabWidgetPointer, SLOT(addCookieToStore(QNetworkCookie)));
+ connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), tabWidgetPointer, SLOT(deleteAllCookies()));
+ connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), tabWidgetPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
+}
+
+void BrowserWindow::showDownloadDirectoryBrowseDialog() const
+{
+ // 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(configDialogPointer, 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 BrowserWindow::showDomainSettingsDialog() const
+{
+ // Remove the focus from the URL line edit.
+ urlLineEditPointer->clearFocus();
+
+ // Instantiate the domain settings dialog.
+ DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog();
+
+ // Reload the tabs when domain settings are updated.
+ connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
+
+ // Show the dialog.
+ domainSettingsDialogPointer->show();
+}
+
+void BrowserWindow::showFindTextActions() const
+{
+ // Show the find text actions.
+ findTextLineEditActionPointer->setVisible(true);
+ findTextLabelActionPointer->setVisible(true);
+ findNextActionPointer->setVisible(true);
+ findPreviousActionPointer->setVisible(true);
+ findCaseSensitiveActionPointer->setVisible(true);
+ hideFindTextActionPointer->setVisible(true);
+
+ // Set the focus on the find line edit.
+ findTextLineEditPointer->setFocus();
+
+ // Select all the text in the find line edit.
+ findTextLineEditPointer->selectAll();
+}
+
+void BrowserWindow::showProgressBar(const int &progress) const
+{
+ // Set the progress bar value.
+ progressBarPointer->setValue(progress);
+
+ // Show the progress bar.
+ progressBarPointer->show();
+
+ // Disable and hide the refresh action.
+ refreshActionPointer->setEnabled(false);
+ refreshActionPointer->setVisible(false);
+
+ // Enable and show the stop action.
+ stopActionPointer->setEnabled(true);
+ stopActionPointer->setVisible(true);
+}
+
+void BrowserWindow::showSettingsDialog()
+{
+ // Create the settings widgets.
+ QWidget *privacySettingsWidgetPointer = new QWidget;
+ QWidget *generalSettingsWidgetPointer = new QWidget;
+ QWidget *spellCheckSettingsWidgetPointer = new QWidget;
+
+ // Instantiate the settings UI.
+ Ui::PrivacySettings privacySettingsUi;
+ Ui::GeneralSettings generalSettingsUi;
+ Ui::SpellCheckSettings spellCheckSettingsUi;
+
+ // Setup the UI to display the settings widgets.
+ privacySettingsUi.setupUi(privacySettingsWidgetPointer);
+ generalSettingsUi.setupUi(generalSettingsWidgetPointer);
+ spellCheckSettingsUi.setupUi(spellCheckSettingsWidgetPointer);
+
+ // Get handles for the widgets.
+ 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;
+
+ // 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);
+ }
+
+ // Get a handle for the KConfig skeleton.
+ KConfigSkeleton *kConfigSkeletonPointer = Settings::self();
+
+ // Instantiate a settings config dialog from the settings.kcfg file.
+ configDialogPointer = new KConfigDialog(this, QLatin1String("settings"), kConfigSkeletonPointer);
+
+ // 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.
+ configDialogPointer->addPage(privacySettingsWidgetPointer, i18nc("Settings tab title", "Privacy"), QLatin1String("privacybrowser"));
+ configDialogPointer->addPage(generalSettingsWidgetPointer, i18nc("Settings tab title", "General"), settingsIconString);
+ configDialogPointer->addPage(spellCheckSettingsWidgetPointer, i18nc("Settings tab title", "Spell Check"), QLatin1String("tools-check-spelling"));
+
+ // Get handles for the buttons.
+ QPushButton *applyButtonPointer = configDialogPointer->button(QDialogButtonBox::Apply);
+ QPushButton *okButtonPointer = configDialogPointer->button(QDialogButtonBox::Ok);
+
+ // Prevent interaction with the parent window while the dialog is open.
+ configDialogPointer->setWindowModality(Qt::WindowModal);
+
+ // Make it so.
+ configDialogPointer->show();
+
+ // TODO. KConfigDialog does not respect expanding size policies. <https://redmine.stoutner.com/issues/823>
+ //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ //configDialogPointer->adjustSize();
+
+ // Expand the config dialog.
+ configDialogPointer->resize(1000, 500);
+
+ // Create a save spell check languages lambda.
+ auto saveSpellCheckLanguages = [spellCheckListWidgetPointer, kConfigSkeletonPointer, 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.
+ kConfigSkeletonPointer->save();
+ }
+
+ // Apply the spell check languages.
+ tabWidgetPointer->applySpellCheckLanguages();
+ };
+
+ // Process
+ connect(applyButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
+ connect(okButtonPointer, &QPushButton::clicked, this, saveSpellCheckLanguages);
+
+ // Apply the settings handled by KConfig.
+ connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings()));
+ connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
+}
+
+QSize BrowserWindow::sizeHint() const
+{
+ // Return the default window size.
+ return QSize(1500, 1200);
+}
+
+void BrowserWindow::toggleBookmark()
+{
+ // Remove the focus from the URL line edit, which will have been focused when the user clicked on the bookmarked icon.
+ urlLineEditPointer->clearFocus();
+
+ // Create or delete the bookmark
+ if (bookmarkedActionPointer->isChecked()) // The user checked the toggle. Create a bookmark.
+ {
+ // Create a bookmark struct.
+ BookmarkStruct *bookmarkStructPointer = new BookmarkStruct;
+
+ // Populate the bookmark struct.
+ bookmarkStructPointer->name = tabWidgetPointer->getCurrentTabTitle();
+ bookmarkStructPointer->url = tabWidgetPointer->getCurrentTabUrl();
+ bookmarkStructPointer->parentFolderId = 0;
+ bookmarkStructPointer->favoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
+
+ // Add the bookmark.
+ BookmarksDatabase::addBookmark(bookmarkStructPointer);
+ }
+ else // The user unchecked the toggle. Delete all related bookmarks.
+ {
+ // Delete the bookmarks.
+ BookmarksDatabase::deleteBookmarks(urlLineEditPointer->text());
+
+
+ }
+
+ // Repopulate the bookmarks.
+ populateBookmarksInAllWindows();
+}
+
+void BrowserWindow::toggleDeveloperTools() const
+{
+ // Toggle the developer tools.
+ tabWidgetPointer->toggleDeveloperTools(developerToolsActionPointer->isChecked());
+}
+
+void BrowserWindow::toggleDomStorage() const
+{
+ // Remove the focus from the URL line edit.
+ urlLineEditPointer->clearFocus();
+
+ // Toggle DOM storage.
+ tabWidgetPointer->toggleDomStorage();
+}
+
+void BrowserWindow::toggleFindCaseSensitive() const
+{
+ // Get the current find string.
+ const QString findString = findTextLineEditPointer->text();
+
+ // Toggle find case sensitive.
+ tabWidgetPointer->toggleFindCaseSensitive(findString);
+}
+
+void BrowserWindow::toggleJavaScript() const
+{
+ // Remove the focus from the URL line edit.
+ urlLineEditPointer->clearFocus();
+
+ // Toggle JavaScript.
+ tabWidgetPointer->toggleJavaScript();
+}
+
+void BrowserWindow::toggleLocalStorage() const
+{
+ // Remove the focus from the URL line edit.
+ urlLineEditPointer->clearFocus();
+
+ // Toggle local storage.
+ tabWidgetPointer->toggleLocalStorage();
+}
+
+void BrowserWindow::toggleFullScreen()
+{
+ // Toggle the full screen status.
+ fullScreenRequested(fullScreenActionPointer->isChecked());
+}
+
+void BrowserWindow::toggleViewSource() const
+{
+ // Get the current URL.
+ QString url = urlLineEditPointer->text();
+
+ // Toggle the URL.
+ if (url.startsWith(QLatin1String("view-source:"))) // The source is currently being viewed.
+ {
+ // Remove `view-source:` from the URL.
+ url = url.remove(0, 12);
+ }
+ else // The source is not currently being viewed.
+ {
+ // Prepend `view-source:` from the URL.
+ url = url.prepend(QLatin1String("view-source:"));
+ }
+
+ // Make it so.
+ loadUrlFromLineEdit(url);
+}
+
+void BrowserWindow::toggleViewBookmarksToolBar()
+{
+ // Store the current status of the bookmarks toolbar, which is used when exiting full screen browsing.
+ bookmarksToolBarIsVisible = viewBookmarksToolBarActionPointer->isChecked();
+
+ // Update the visibility of the bookmarks toolbar.
+ bookmarksToolBarPointer->setVisible(bookmarksToolBarIsVisible);
+}
+
+void BrowserWindow::toggleViewSourceInNewTab() const
+{
+ // Get the current URL.
+ QString url = urlLineEditPointer->text();
+
+ // Toggle the URL.
+ if (url.startsWith(QLatin1String("view-source:"))) // The source is currently being viewed.
+ {
+ // Remove `view-source:` from the URL.
+ url = url.remove(0, 12);
+ }
+ else // The source is not currently being viewed.
+ {
+ // Prepend `view-source:` from the URL.
+ url = url.prepend(QLatin1String("view-source:"));
+ }
+
+ // Add the new tab. `true` removes the URL line edit focus, `true` opens the new tab in an adjacent tab. `false` does not open a background tab.
+ tabWidgetPointer->addTab(true, true, false, url);
+}
+
+void BrowserWindow::updateBookmarkedAction() const
+{
+ // Update the bookmarked action to reflect the current state.
+ if (bookmarkedActionPointer->isChecked())
+ bookmarkedActionPointer->setIcon(QIcon::fromTheme("starred-symbolic"));
+ else
+ bookmarkedActionPointer->setIcon(QIcon::fromTheme("non-starred-symbolic"));
+}
+
+void BrowserWindow::updateCookiesAction(const int numberOfCookies) const
+{
+ // Update the action text.
+ cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
+}
+
+void BrowserWindow::updateDefaultZoomFactor(const double newDefaultZoomFactor)
+{
+ // Store the new default zoom factor.
+ defaultZoomFactor = newDefaultZoomFactor;
+}
+
+void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
+{
+ // Set the action checked status.
+ domStorageActionPointer->setChecked(isEnabled);
+}
+
+void BrowserWindow::updateDomainSettingsIndicator(const bool status)
+{
+ // Set the domain palette according to the status.
+ if (status)
+ urlLineEditPointer->setPalette(positiveBackgroundPalette);
+ else
+ urlLineEditPointer->setPalette(normalBackgroundPalette);
+}
+
+void BrowserWindow::updateFindText(const QString &text, const bool findCaseSensitive) const
+{
+ // Set the text.
+ findTextLineEditPointer->setText(text);
+
+ // Set the find case sensitive action checked status.
+ findCaseSensitiveActionPointer->setChecked(findCaseSensitive);
+}
+
+void BrowserWindow::updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const
+{
+ // Update the find text label.
+ findTextLabelPointer->setText(QStringLiteral(" %1/%2 ").arg(findTextResult.activeMatch()).arg(findTextResult.numberOfMatches()));
+
+ // Set the background color according to the find status.
+ if (findTextLineEditPointer->text().isEmpty())
+ findTextLineEditPointer->setPalette(normalBackgroundPalette);
+ else if (findTextResult.numberOfMatches() == 0)
+ findTextLineEditPointer->setPalette(negativeBackgroundPalette);
+ else
+ findTextLineEditPointer->setPalette(positiveBackgroundPalette);
+}
+
+void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)