From e5ec85accb02116b08c33b574805c132475d90bc Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Sat, 9 Dec 2023 11:48:36 -0700 Subject: [PATCH 01/16] Add DevTools. https://redmine.stoutner.com/issues/1126 --- src/ui.rcs/browserwindowui.rc | 1 + src/widgets/CMakeLists.txt | 1 + src/widgets/DevToolsWebEngineView.cpp | 37 ++++++++ src/widgets/DevToolsWebEngineView.h | 35 +++++++ src/widgets/PrivacyWebEngineView.cpp | 4 +- src/widgets/PrivacyWebEngineView.h | 2 +- src/widgets/TabWidget.cpp | 128 ++++++++++++++++++++------ src/widgets/TabWidget.h | 2 + src/windows/BrowserWindow.cpp | 18 +++- src/windows/BrowserWindow.h | 2 + 10 files changed, 198 insertions(+), 32 deletions(-) create mode 100644 src/widgets/DevToolsWebEngineView.cpp create mode 100644 src/widgets/DevToolsWebEngineView.h diff --git a/src/ui.rcs/browserwindowui.rc b/src/ui.rcs/browserwindowui.rc index ab3d503..f16913b 100644 --- a/src/ui.rcs/browserwindowui.rc +++ b/src/ui.rcs/browserwindowui.rc @@ -48,6 +48,7 @@ + diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index d237afb..f161dec 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -18,6 +18,7 @@ # List the sources to include in the executable. target_sources(privacybrowser PRIVATE + DevToolsWebEngineView.cpp DraggableTreeView.cpp PrivacyWebEngineView.cpp TabWidget.cpp diff --git a/src/widgets/DevToolsWebEngineView.cpp b/src/widgets/DevToolsWebEngineView.cpp new file mode 100644 index 0000000..a409584 --- /dev/null +++ b/src/widgets/DevToolsWebEngineView.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2022-2023 Soren Stoutner . + * + * This file is part of 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 . + */ + +// Application headers. +#include "DevToolsWebEngineView.h" + +// Qt toolkit headers. +#include + +// Construct the class. +DevToolsWebEngineView::DevToolsWebEngineView(QWidget *parentWidgetPointer) : QWebEngineView(parentWidgetPointer) +{ + // Create an off-the-record profile (the default when no profile name is specified). + QWebEngineProfile *webEngineProfilePointer = new QWebEngineProfile(QLatin1String("")); + + // Create a WebEngine page. + QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer); + + // Set the WebEngine page. + setPage(webEnginePagePointer); +} diff --git a/src/widgets/DevToolsWebEngineView.h b/src/widgets/DevToolsWebEngineView.h new file mode 100644 index 0000000..a694bd3 --- /dev/null +++ b/src/widgets/DevToolsWebEngineView.h @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2023 Soren Stoutner . + * + * This file is part of 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 . + */ + +#ifndef DEVTOOLSWEBENGINEVIEW_H +#define DEVTOOLSWEBENGINEVIEW_H + +// Qt toolkit headers. +#include + +class DevToolsWebEngineView : public QWebEngineView +{ + // Include the Q_OBJECT macro. + Q_OBJECT + +public: + // The default constructor. + explicit DevToolsWebEngineView(QWidget *parentWidgetPointer = nullptr); +}; +#endif diff --git a/src/widgets/PrivacyWebEngineView.cpp b/src/widgets/PrivacyWebEngineView.cpp index 38b03c3..8f61f91 100644 --- a/src/widgets/PrivacyWebEngineView.cpp +++ b/src/widgets/PrivacyWebEngineView.cpp @@ -30,7 +30,7 @@ #include // Construct the class. -PrivacyWebEngineView::PrivacyWebEngineView() : QWebEngineView(nullptr) +PrivacyWebEngineView::PrivacyWebEngineView(QWidget *parentWidgetPointer) : QWebEngineView(parentWidgetPointer) { // Create an off-the-record profile (the default when no profile name is specified). webEngineProfilePointer = new QWebEngineProfile(QLatin1String("")); @@ -45,7 +45,7 @@ PrivacyWebEngineView::PrivacyWebEngineView() : QWebEngineView(nullptr) webEngineSettingsPointer = webEnginePagePointer->settings(); // Instantiate the URL request interceptor. - UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor(); + UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor(this); // Set the URL request interceptor. webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer); diff --git a/src/widgets/PrivacyWebEngineView.h b/src/widgets/PrivacyWebEngineView.h index 3077681..171ca5e 100644 --- a/src/widgets/PrivacyWebEngineView.h +++ b/src/widgets/PrivacyWebEngineView.h @@ -33,7 +33,7 @@ class PrivacyWebEngineView : public QWebEngineView public: // The default constructor. - explicit PrivacyWebEngineView(); + explicit PrivacyWebEngineView(QWidget *parentWidgetPointer = nullptr); // The public variables. std::list *cookieListPointer = new std::list; diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index 4a6b11c..eb92333 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -18,9 +18,11 @@ */ // Application headers. +#include "DevToolsWebEngineView.h" #include "TabWidget.h" #include "Settings.h" #include "ui_AddTabWidget.h" +#include "ui_Tab.h" #include "ui_TabWidget.h" #include "databases/CookiesDatabase.h" #include "dialogs/SaveDialog.h" @@ -127,11 +129,16 @@ TabWidget::~TabWidget() // Manually delete each WebEngine page. for (int i = 0; i < numberOfTabs; ++i) { - // Get the privacy WebEngine view. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + // Get the tab splitter widget. + QWidget *tabSplitterWidgetPointer = qTabWidgetPointer->widget(i); - // Deletion the WebEngine page to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` + // Get the WebEngine views. + PrivacyWebEngineView *privacyWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); + DevToolsWebEngineView *devToolsWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); + + // Deletion the WebEngine pages to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` delete privacyWebEngineViewPointer->page(); + delete devToolsWebEngineViewPointer->page(); } } @@ -173,23 +180,47 @@ void TabWidget::addFirstTab() PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab, const QString urlString) { - // Create a privacy WebEngine view. + // Create a splitter widget. + QSplitter *splitterPointer = new QSplitter(); + + // Set the splitter to be vertical. + splitterPointer->setOrientation(Qt::Vertical); + + // Set the splitter handle size. + splitterPointer->setHandleWidth(5); + + // Create the WebEngines. PrivacyWebEngineView *privacyWebEngineViewPointer = new PrivacyWebEngineView(); + DevToolsWebEngineView *devToolsWebEngineViewPointer = new DevToolsWebEngineView(); + + // Add the WebEngines to the splitter. + splitterPointer->addWidget(privacyWebEngineViewPointer); + splitterPointer->addWidget(devToolsWebEngineViewPointer); // Add a new tab. - int newTabIndex = qTabWidgetPointer->addTab(privacyWebEngineViewPointer, i18nc("New tab label.", "New Tab")); + int newTabIndex = qTabWidgetPointer->addTab(splitterPointer, i18nc("New tab label.", "New Tab")); // Set the default tab icon. qTabWidgetPointer->setTabIcon(newTabIndex, defaultFavoriteIcon); - // Get handles for the WebEngine page and profile. + // Get handles for the WebEngine components. QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page(); QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile(); - - // Get handles for the web engine elements. QWebEngineCookieStore *webEngineCookieStorePointer = webEngineProfilePointer->cookieStore(); QWebEngineSettings *webEngineSettingsPointer = webEnginePagePointer->settings(); + // Set the development tools WebEngine. This must be done here to preserve the bottom half of the window as the initial development tools size. + webEnginePagePointer->setDevToolsPage(devToolsWebEngineViewPointer->page()); + + // Initially hide the development tools WebEngine. + devToolsWebEngineViewPointer->setVisible(false); + + // Initially disable the development tools WebEngine. + webEnginePagePointer->setDevToolsPage(nullptr); + + // Disable JavaScript on the development tools WebEngine to prevent error messages from being written to the console. + devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); + // Update the URL line edit when the URL changes. connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [this, privacyWebEngineViewPointer] (const QUrl &newUrl) { @@ -206,10 +237,10 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Update the title when it changes. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, privacyWebEngineViewPointer] (const QString &title) + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, splitterPointer] (const QString &title) { // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Update the title for this tab. qTabWidgetPointer->setTabText(tabIndex, title); @@ -220,10 +251,10 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Connect the loading favorite icon movie to the tab icon. - connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, privacyWebEngineViewPointer] + connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, splitterPointer, privacyWebEngineViewPointer] { // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Display the loading favorite icon if this tab is loading. if (privacyWebEngineViewPointer->isLoading) @@ -231,7 +262,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Update the icon when it changes. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon) + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, splitterPointer, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon) { // Store the favorite icon in the privacy web engine view. if (newFavoriteIcon.isNull()) @@ -240,7 +271,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const privacyWebEngineViewPointer->favoriteIcon = newFavoriteIcon; // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Update the icon for this tab. if (newFavoriteIcon.isNull()) @@ -278,7 +309,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Update the progress bar when a load finishes. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, privacyWebEngineViewPointer] () + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, splitterPointer, privacyWebEngineViewPointer] () { // Set the privacy web engine view to be not loading. privacyWebEngineViewPointer->isLoading = false; @@ -291,7 +322,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const emit hideProgressBar(); // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Display the current favorite icon qTabWidgetPointer->setTabIcon(tabIndex, privacyWebEngineViewPointer->favoriteIcon); @@ -306,7 +337,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const for (int i = 0; i < numberOfTabs; i++) { // Get the privacy WebEngine view for the tab. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Check to see if it is currently loading. If at least one tab is loading, this flag will end up being marked `false` when the for loop has finished. if (privacyWebEngineViewPointer->isLoading) @@ -475,7 +506,7 @@ void TabWidget::applyApplicationSettings() // Apply the spatial navigation settings to each WebEngine. for (int i = 0; i < numberOfTabs; ++i) { // Get the WebEngine view pointer. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Apply the spatial navigation settings to each page. privacyWebEngineViewPointer->page()->settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation()); @@ -496,7 +527,7 @@ void TabWidget::applyDomainSettingsAndReload() // Apply the domain settings to each WebEngine. for (int i = 0; i < numberOfTabs; ++i) { // Get the WebEngine view pointer. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Apply the spatial navigation settings to each page. privacyWebEngineViewPointer->applyDomainSettings(privacyWebEngineViewPointer->url().host(), true); @@ -551,7 +582,7 @@ void TabWidget::applySpellCheckLanguages() const for (int i = 0; i < numberOfTabs; ++i) { // Get the WebEngine view pointer. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Get the WebEngine page pointer. QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page(); @@ -584,20 +615,29 @@ void TabWidget::deleteCookieFromStore(const QNetworkCookie &cookie) const void TabWidget::deleteTab(const int tabIndex) { - // Get the privacy WebEngine view. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(tabIndex)); + // Get the tab splitter widget. + QWidget *tabSplitterWidgetPointer = qTabWidgetPointer->widget(tabIndex); + + // Get the WebEngine views. + PrivacyWebEngineView *privacyWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); + DevToolsWebEngineView *devToolsWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); // Process the tab delete according to the number of tabs. if (qTabWidgetPointer->count() > 1) // There is more than one tab. { - // Delete the tab. + // Remove the tab. qTabWidgetPointer->removeTab(tabIndex); - // Delete the WebEngine page to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` + // Delete the WebEngine pages to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` delete privacyWebEngineViewPointer->page(); + delete devToolsWebEngineViewPointer->page(); - // Delete the privacy WebEngine view. + // Delete the WebEngine views. delete privacyWebEngineViewPointer; + delete devToolsWebEngineViewPointer; + + // Delete the tab splitter widget. + delete tabSplitterWidgetPointer; } else // There is only one tab. { @@ -1064,6 +1104,38 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin savingArchive = false; } +void TabWidget::toggleDeveloperTools(const bool enabled) const +{ + // Get a handle for the current developer tools WebEngine. + DevToolsWebEngineView *devToolsWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild(); + + if (enabled) + { + // Set the zoom factor on the development tools WebEngine. + devToolsWebEngineViewPointer->setZoomFactor(currentWebEnginePagePointer->zoomFactor()); + + // Enable the development tools. + currentWebEnginePagePointer->setDevToolsPage(devToolsWebEngineViewPointer->page()); + + // Enable JavaScript on the development tools WebEngine. + devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + + // Display the developer tools. + devToolsWebEngineViewPointer->setVisible(true); + } + else + { + // Disable JavaScript on the development tools WebEngine to prevent error messages from being written to the console. + devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); + + // Disable the development tools. + currentWebEnginePagePointer->setDevToolsPage(nullptr); + + // Hide the developer tools. + devToolsWebEngineViewPointer->setVisible(false); + } +} + void TabWidget::toggleDomStorage() const { // Toggle DOM storage. @@ -1134,7 +1206,7 @@ void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWeb void TabWidget::updateUiWithTabSettings() { // Update the current WebEngine pointers. - currentPrivacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->currentWidget()); + currentPrivacyWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild(); currentWebEngineSettingsPointer = currentPrivacyWebEngineViewPointer->settings(); currentWebEnginePagePointer = currentPrivacyWebEngineViewPointer->page(); currentWebEngineProfilePointer = currentWebEnginePagePointer->profile(); @@ -1144,10 +1216,14 @@ void TabWidget::updateUiWithTabSettings() // Clear the URL line edit focus. emit clearUrlLineEditFocus(); + // Get a handle for the development tools WebEngine view. + DevToolsWebEngineView *devToolsWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild(); + // Update the actions. emit updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor); emit updateBackAction(currentWebEngineHistoryPointer->canGoBack()); emit updateCookiesAction(currentPrivacyWebEngineViewPointer->cookieListPointer->size()); + emit updateDeveloperToolsAction(devToolsWebEngineViewPointer->isVisible()); emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled)); emit updateForwardAction(currentWebEngineHistoryPointer->canGoForward()); emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled)); diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index ab61671..5b9f2f9 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -62,6 +62,7 @@ public: QString getCurrentTabUrl() const; QString& getDomainSettingsName() const; void setTabBarVisible(const bool visible) const; + void toggleDeveloperTools(const bool enabled) const; void toggleDomStorage() const; void toggleFindCaseSensitive(const QString &text); void toggleJavaScript() const; @@ -82,6 +83,7 @@ signals: void updateBackAction(const bool &isEnabled) const; void updateCookiesAction(const int numberOfCookies) const; void updateDefaultZoomFactor(const double newDefaultZoomFactor) const; + void updateDeveloperToolsAction(const bool &isEnabled) const; void updateDomStorageAction(const bool &isEnabled) const; void updateDomainSettingsIndicator(const bool status) const; void updateFindText(const QString &text, const bool findCaseSensitive) const; diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 214b0af..2eb4ab1 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -96,6 +96,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) QAction *reloadAndBypassCacheActionPointer = actionCollectionPointer->addAction(QLatin1String("reload_and_bypass_cache")); viewSourceActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source")); viewSourceInNewTabActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source_in_new_tab")); + developerToolsActionPointer = actionCollectionPointer->addAction(QLatin1String("developer_tools")); javaScriptActionPointer = actionCollectionPointer->addAction(QLatin1String("javascript")); localStorageActionPointer = actionCollectionPointer->addAction(QLatin1String("local_storage")); domStorageActionPointer = actionCollectionPointer->addAction(QLatin1String("dom_storage")); @@ -150,6 +151,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) domStorageActionPointer->setCheckable(true); findCaseSensitiveActionPointer->setCheckable(true); viewSourceActionPointer->setCheckable(true); + developerToolsActionPointer->setCheckable(true); userAgentPrivacyBrowserActionPointer->setCheckable(true); userAgentWebEngineDefaultActionPointer->setCheckable(true); userAgentFirefoxLinuxActionPointer->setCheckable(true); @@ -179,6 +181,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) reloadAndBypassCacheActionPointer->setText(i18nc("Reload and bypass cache action", "Reload and Bypass Cache")); viewSourceActionPointer->setText(i18nc("View source action", "View Source")); viewSourceInNewTabActionPointer->setText(i18nc("View source in new tab action", "View Source in New Tab")); + developerToolsActionPointer->setText(i18nc("Developer tools action", "Developer Tools")); javaScriptActionPointer->setText(i18nc("JavaScript action", "JavaScript")); localStorageActionPointer->setText(i18nc("The Local Storage action", "Local Storage")); domStorageActionPointer->setText(i18nc("DOM Storage action", "DOM Storage")); @@ -211,6 +214,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) reloadAndBypassCacheActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); viewSourceActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor")))); viewSourceInNewTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor")))); + developerToolsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("add-subtitle"), QIcon::fromTheme("system-run"))); domStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("code-class"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/gtk-unindent-ltr.png")))); userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg")); userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); @@ -246,6 +250,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) QKeySequence ctrlF5KeySequence = QKeySequence(i18nc("The reload and bypass cache key sequence.", "Ctrl+F5")); QKeySequence ctrlUKeySequence = QKeySequence(i18nc("The view source key sequence.", "Ctrl+U")); QKeySequence ctrlShiftUKeySequence = QKeySequence(i18nc("The view source in new tab key sequence.", "Ctrl+Shift+U")); + QKeySequence f12KeySequence = QKeySequence(i18nc("The developer tools key sequence.", "F12")); QKeySequence ctrlShiftPKeySequence = QKeySequence(i18nc("The print preview key sequence.", "Ctrl+Shift+P")); QKeySequence ctrlJKeySequence = QKeySequence(i18nc("The JavaScript key sequence.", "Ctrl+J")); QKeySequence ctrlLKeySequence = QKeySequence(i18nc("The local storage key sequence.", "Ctrl+L")); @@ -281,6 +286,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) actionCollectionPointer->setDefaultShortcut(reloadAndBypassCacheActionPointer, ctrlF5KeySequence); actionCollectionPointer->setDefaultShortcut(viewSourceActionPointer, ctrlUKeySequence); actionCollectionPointer->setDefaultShortcut(viewSourceInNewTabActionPointer, ctrlShiftUKeySequence); + actionCollectionPointer->setDefaultShortcut(developerToolsActionPointer, f12KeySequence); actionCollectionPointer->setDefaultShortcut(printPreviewActionPointer, ctrlShiftPKeySequence); actionCollectionPointer->setDefaultShortcut(javaScriptActionPointer, ctrlJKeySequence); actionCollectionPointer->setDefaultShortcut(localStorageActionPointer, ctrlLKeySequence); @@ -316,6 +322,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) connect(reloadAndBypassCacheActionPointer, SIGNAL(triggered()), this, SLOT(reloadAndBypassCache())); connect(viewSourceActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSource())); connect(viewSourceInNewTabActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSourceInNewTab())); + connect(developerToolsActionPointer, SIGNAL(triggered()), this, SLOT(toggleDeveloperTools())); connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser())); connect(viewBookmarksToolBarActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewBookmarksToolBar())); connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog())); @@ -341,7 +348,8 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) connect(localStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleLocalStorage())); connect(domStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleDomStorage())); - // Update the URL toolbar actions. + // Update the actions from the tab widget. + connect(tabWidgetPointer, SIGNAL(updateDeveloperToolsAction(bool)), developerToolsActionPointer, SLOT(setChecked(bool))); connect(tabWidgetPointer, SIGNAL(updateBackAction(bool)), backActionPointer, SLOT(setEnabled(bool))); connect(tabWidgetPointer, SIGNAL(updateForwardAction(bool)), forwardActionPointer, SLOT(setEnabled(bool))); connect(tabWidgetPointer, SIGNAL(updateJavaScriptAction(bool)), this, SLOT(updateJavaScriptAction(bool))); @@ -1026,8 +1034,6 @@ void BrowserWindow::populateBookmarksInAllWindows() const void BrowserWindow::populateBookmarksInThisWindow() { - qDebug() << "Populating bookmarks."; - // Remove all the final bookmark folder menu actions. for (QPair *finalBookmarkFolderMenuActionPair : finalBookmarkFolderMenuActionList) { @@ -1693,6 +1699,12 @@ void BrowserWindow::toggleBookmark() 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. diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index 6910f8a..e62b7b2 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -82,6 +82,7 @@ private Q_SLOTS: void showProgressBar(const int &progress) const; void showSettingsDialog(); void toggleBookmark(); + void toggleDeveloperTools() const; void toggleDomStorage() const; void toggleFindCaseSensitive() const; void toggleJavaScript() const; @@ -129,6 +130,7 @@ private: bool customSearchEngineEnabled; bool customUserAgentEnabled; double defaultZoomFactor; + QAction *developerToolsActionPointer; QAction *domStorageActionPointer; QComboBox *downloadLocationComboBoxPointer; QList *> finalBookmarkFolderMenuActionList; -- 2.43.0 From 37e86f9f1e43c3cf67d4d6a5f0f21a66e1df23fc Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Tue, 26 Dec 2023 15:28:24 -0700 Subject: [PATCH 02/16] Add an stop action. https://redmine.stoutner.com/issues/1141 --- src/ui.rcs/browserwindowui.rc | 2 ++ src/widgets/TabWidget.cpp | 6 ++++++ src/widgets/TabWidget.h | 1 + src/windows/BrowserWindow.cpp | 37 +++++++++++++++++++++++++++++++---- src/windows/BrowserWindow.h | 3 +++ 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/ui.rcs/browserwindowui.rc b/src/ui.rcs/browserwindowui.rc index f16913b..9953db6 100644 --- a/src/ui.rcs/browserwindowui.rc +++ b/src/ui.rcs/browserwindowui.rc @@ -43,6 +43,7 @@ + @@ -106,6 +107,7 @@ + diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index eb92333..a8f59b4 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -1104,6 +1104,12 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin savingArchive = false; } +void TabWidget::stop() const +{ + // Stop the loading of the current privacy WebEngine. + currentPrivacyWebEngineViewPointer->stop(); +} + void TabWidget::toggleDeveloperTools(const bool enabled) const { // Get a handle for the current developer tools WebEngine. diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index 5b9f2f9..4cbfe97 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -119,6 +119,7 @@ public Q_SLOTS: void refresh() const; void reloadAndBypassCache() const; void saveArchive(); + void stop() const; private Q_SLOTS: // The private slots. diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 2eb4ab1..99fc2fa 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -77,7 +77,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollectionPointer); zoomInActionPointer = KStandardAction::zoomIn(this, SLOT(incrementZoom()), actionCollectionPointer); zoomOutActionPointer = KStandardAction::zoomOut(this, SLOT(decrementZoom()), actionCollectionPointer); - KStandardAction::redisplay(this, SLOT(refresh()), actionCollectionPointer); + refreshActionPointer = KStandardAction::redisplay(this, SLOT(refresh()), actionCollectionPointer); fullScreenActionPointer = KStandardAction::fullScreen(this, SLOT(toggleFullScreen()), this, actionCollectionPointer); QAction *backActionPointer = KStandardAction::back(this, SLOT(back()), actionCollectionPointer); QAction *forwardActionPointer = KStandardAction::forward(this, SLOT(forward()), actionCollectionPointer); @@ -94,6 +94,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) QAction *saveArchiveActionPointer = actionCollectionPointer->addAction(QLatin1String("save_archive")); zoomDefaultActionPointer = actionCollectionPointer->addAction(QLatin1String("zoom_default")); QAction *reloadAndBypassCacheActionPointer = actionCollectionPointer->addAction(QLatin1String("reload_and_bypass_cache")); + stopActionPointer = actionCollectionPointer->addAction(QLatin1String("stop")); viewSourceActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source")); viewSourceInNewTabActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source_in_new_tab")); developerToolsActionPointer = actionCollectionPointer->addAction(QLatin1String("developer_tools")); @@ -179,6 +180,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) saveArchiveActionPointer->setText(i18nc("Save archive action", "Save Archive")); zoomDefaultActionPointer->setText(i18nc("Zoom default action", "Zoom Default")); reloadAndBypassCacheActionPointer->setText(i18nc("Reload and bypass cache action", "Reload and Bypass Cache")); + stopActionPointer->setText(i18nc("Stop action", "Stop")); viewSourceActionPointer->setText(i18nc("View source action", "View Source")); viewSourceInNewTabActionPointer->setText(i18nc("View source in new tab action", "View Source in New Tab")); developerToolsActionPointer->setText(i18nc("Developer tools action", "Developer Tools")); @@ -212,12 +214,14 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) saveArchiveActionPointer->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); zoomDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("zoom-fit-best"))); reloadAndBypassCacheActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); + stopActionPointer->setIcon(QIcon::fromTheme(QLatin1String("process-stop"))); viewSourceActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor")))); viewSourceInNewTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor")))); developerToolsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("add-subtitle"), QIcon::fromTheme("system-run"))); domStorageActionPointer->setIcon(QIcon::fromTheme(QLatin1String("code-class"), QIcon(QLatin1String("/usr/share/icons/gnome/32x32/actions/gtk-unindent-ltr.png")))); - userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg")); - userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); + userAgentPrivacyBrowserActionPointer->setIcon(QIcon(QLatin1String(":/icons/privacy-mode.svg"))); + userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), + QIcon::fromTheme(QLatin1String("contact-new"))))); userAgentFirefoxLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); userAgentChromiumLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); @@ -248,6 +252,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) QKeySequence ctrlAKeySequence = QKeySequence(i18nc("The save archive key sequence.", "Ctrl+A")); QKeySequence ctrl0KeySequence = QKeySequence(i18nc("The zoom default key sequence.", "Ctrl+0")); QKeySequence ctrlF5KeySequence = QKeySequence(i18nc("The reload and bypass cache key sequence.", "Ctrl+F5")); + QKeySequence ctrlShiftXKeySequence = QKeySequence(i18nc("The stop key sequence.", "Ctrl+Shift+X")); QKeySequence ctrlUKeySequence = QKeySequence(i18nc("The view source key sequence.", "Ctrl+U")); QKeySequence ctrlShiftUKeySequence = QKeySequence(i18nc("The view source in new tab key sequence.", "Ctrl+Shift+U")); QKeySequence f12KeySequence = QKeySequence(i18nc("The developer tools key sequence.", "F12")); @@ -284,6 +289,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) actionCollectionPointer->setDefaultShortcut(saveArchiveActionPointer, ctrlAKeySequence); actionCollectionPointer->setDefaultShortcut(zoomDefaultActionPointer, ctrl0KeySequence); actionCollectionPointer->setDefaultShortcut(reloadAndBypassCacheActionPointer, ctrlF5KeySequence); + actionCollectionPointer->setDefaultShortcut(stopActionPointer, ctrlShiftXKeySequence); actionCollectionPointer->setDefaultShortcut(viewSourceActionPointer, ctrlUKeySequence); actionCollectionPointer->setDefaultShortcut(viewSourceInNewTabActionPointer, ctrlShiftUKeySequence); actionCollectionPointer->setDefaultShortcut(developerToolsActionPointer, f12KeySequence); @@ -320,6 +326,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) connect(saveArchiveActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(saveArchive())); connect(zoomDefaultActionPointer, SIGNAL(triggered()), this, SLOT(zoomDefault())); connect(reloadAndBypassCacheActionPointer, SIGNAL(triggered()), this, SLOT(reloadAndBypassCache())); + connect(stopActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(stop())); connect(viewSourceActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSource())); connect(viewSourceInNewTabActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSourceInNewTab())); connect(developerToolsActionPointer, SIGNAL(triggered()), this, SLOT(toggleDeveloperTools())); @@ -501,7 +508,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) // Update the progress bar. connect(tabWidgetPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int))); - connect(tabWidgetPointer, SIGNAL(hideProgressBar()), progressBarPointer, SLOT(hide())); + connect(tabWidgetPointer, SIGNAL(hideProgressBar()), this, SLOT(hideProgressBar())); // Update the URL line edit focus. connect(tabWidgetPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus())); @@ -979,6 +986,20 @@ void BrowserWindow::home() const tabWidgetPointer->home(); } +void BrowserWindow::hideProgressBar() const +{ + // Hide the progress bar. + progressBarPointer->hide(); + + // Disable and hide the stop action. + stopActionPointer->setEnabled(false); + stopActionPointer->setVisible(false); + + // Enable and show the refresh action. + refreshActionPointer->setEnabled(true); + refreshActionPointer->setVisible(true); +} + void BrowserWindow::incrementZoom() { // Update the current zoom factor. @@ -1489,6 +1510,14 @@ void BrowserWindow::showProgressBar(const int &progress) const // 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() diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index e62b7b2..87297dc 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -67,6 +67,7 @@ private Q_SLOTS: void fullScreenRequested(const bool toggleOn); void getZoomFactorFromUser(); void hideFindTextActions() const; + void hideProgressBar() const; void home() const; void incrementZoom(); void loadUrlFromLineEdit(const QString &url) const; @@ -152,6 +153,7 @@ private: QPalette normalBackgroundPalette; QPalette positiveBackgroundPalette; QProgressBar *progressBarPointer; + QAction *refreshActionPointer; QLabel *searchEngineLabelPointer; QAction *searchEngineMenuActionPointer; QAction *searchEngineMojeekActionPointer; @@ -161,6 +163,7 @@ private: QAction *searchEngineBingActionPointer; QAction *searchEngineYahooActionPointer; QAction *searchEngineCustomActionPointer; + QAction *stopActionPointer; QLabel *userAgentLabelPointer; QAction *userAgentMenuActionPointer; QAction *userAgentPrivacyBrowserActionPointer; -- 2.43.0 From c443cca294f7b5b4c71ea55094dcfd685c9a2256 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 27 Dec 2023 15:15:53 -0700 Subject: [PATCH 03/16] Use the webpage title as the default archive name. https://redmine.stoutner.com/issues/1139 --- src/widgets/TabWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index a8f59b4..bd3882d 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -907,7 +907,7 @@ void TabWidget::reloadAndBypassCache() const void TabWidget::saveArchive() { // Get the suggested file name. - QString suggestedFileName = currentPrivacyWebEngineViewPointer->url().host() + ".mht"; + QString suggestedFileName = currentPrivacyWebEngineViewPointer->title() + ".mht"; // Get the download directory. QString downloadDirectory = Settings::downloadLocation(); -- 2.43.0 From a2737fd8ee243b19080acdda891efb44674808e3 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 27 Dec 2023 17:38:27 -0700 Subject: [PATCH 04/16] Open new tabs adjacent to the current tab. https://redmine.stoutner.com/issues/1110 --- src/widgets/PrivacyWebEngineView.cpp | 9 +++++---- src/widgets/TabWidget.cpp | 10 ++++++++-- src/widgets/TabWidget.h | 2 +- src/windows/BrowserWindow.cpp | 24 ++++++++++++------------ 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/widgets/PrivacyWebEngineView.cpp b/src/widgets/PrivacyWebEngineView.cpp index 8f61f91..05c7659 100644 --- a/src/widgets/PrivacyWebEngineView.cpp +++ b/src/widgets/PrivacyWebEngineView.cpp @@ -259,9 +259,9 @@ QWebEngineView* PrivacyWebEngineView::createWindow(QWebEnginePage::WebWindowType { case QWebEnginePage::WebBrowserTab: { - // Create the new tab and return the privacy WebEngine view pointer. `true` removes the focus from the blank URL line edit. + // Create the new tab and return the privacy WebEngine view pointer. `true` removes the focus from the blank URL line edit. `true` adds the new tab adjacent to the current tab. // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu. - return browserWindowPointer->tabWidgetPointer->addTab(true); + return browserWindowPointer->tabWidgetPointer->addTab(true, true); } case QWebEnginePage::WebBrowserWindow: @@ -278,9 +278,10 @@ QWebEngineView* PrivacyWebEngineView::createWindow(QWebEnginePage::WebWindowType case QWebEnginePage::WebBrowserBackgroundTab: { - // Create the new tab and return the privacy WebEngine view pointer. `false` does not clear the URL line edit. `true` creates a background tab. + // Create the new tab and return the privacy WebEngine view pointer. `false` does not clear the URL line edit. `true` adds the new tab adjacent to the current tab. + // `true` creates a background tab. // The new privacy WebEngine view pointer is returned so it can be populated with the link from the context menu. - return browserWindowPointer->tabWidgetPointer->addTab(false, true); + return browserWindowPointer->tabWidgetPointer->addTab(false, true, true); } default: diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index bd3882d..efd677d 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -178,7 +178,7 @@ void TabWidget::addFirstTab() qTabWidgetPointer->currentWidget()->setFocus(); } -PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab, const QString urlString) +PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool adjacent, const bool backgroundTab, const QString urlString) { // Create a splitter widget. QSplitter *splitterPointer = new QSplitter(); @@ -197,8 +197,14 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const splitterPointer->addWidget(privacyWebEngineViewPointer); splitterPointer->addWidget(devToolsWebEngineViewPointer); + // Initialize the new tab index. + int newTabIndex = 0; + // Add a new tab. - int newTabIndex = qTabWidgetPointer->addTab(splitterPointer, i18nc("New tab label.", "New Tab")); + if (adjacent) // Add the new tab adjacent to the current tab. + newTabIndex = qTabWidgetPointer->insertTab((qTabWidgetPointer->currentIndex() + 1), splitterPointer, i18nc("New tab label.", "New Tab")); + else // Add the new tab at the end of the list. + newTabIndex = qTabWidgetPointer->addTab(splitterPointer, i18nc("New tab label.", "New Tab")); // Set the default tab icon. qTabWidgetPointer->setTabIcon(newTabIndex, defaultFavoriteIcon); diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index 4cbfe97..e47370c 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -100,7 +100,7 @@ signals: public Q_SLOTS: // The public slots. void addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer = nullptr) const; - PrivacyWebEngineView* addTab(const bool removeUrlLineEditFocus = false, const bool backgroundTab = false, const QString urlString = nullptr); + PrivacyWebEngineView* addTab(const bool removeUrlLineEditFocus = false, const bool adjacent = false, const bool backgroundTab = false, const QString urlString = nullptr); void applyApplicationSettings(); void applyDomainSettingsAndReload(); void applyOnTheFlySearchEngine(QAction *searchEngineActionPointer); diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 99fc2fa..394340b 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -625,9 +625,9 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double // Get all the folder URLs. QList *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId); - // Open the URLs in new tabs. `true` removes the URL line edit focus, `false` does not load a background tab. + // Open the URLs in new tabs. `true` removes the URL line edit focus, `true` opens the new tabs in an adjacent tab. `false` does not load a background tab. for (QString url : *folderUrlsListPointer) - tabWidgetPointer->addTab(true, false, url); + tabWidgetPointer->addTab(true, true, false, url); } ); @@ -638,9 +638,9 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double // Get all the folder URLs. QList *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId); - // Open the URLs in new tabs. `true` removes the URL line edit focus, `true` loads a background tab. + // Open the URLs in new tabs. `true` removes the URL line edit focus, `true` opens the new tabs in an adjacent tab. `true` loads a background tab. for (QString url : *folderUrlsListPointer) - tabWidgetPointer->addTab(true, true, url); + tabWidgetPointer->addTab(true, true, true, url); } ); @@ -656,9 +656,9 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double // Get a count of the folder URLs. const int folderUrls = folderUrlsListPointer->count(); - // Load all the other URLs. `true` removes the URL line edit focus, `true` loads a background tab. + // Load all the other URLs. `true` removes the URL line edit focus, `false` does not load the new tabs in adjacent tabs. `true` loads a background tab. for (int i = 1; i < folderUrls; ++i) - browserWindowPointer->tabWidgetPointer->addTab(true, true, folderUrlsListPointer->value(i)); + browserWindowPointer->tabWidgetPointer->addTab(true, false, true, folderUrlsListPointer->value(i)); // Show the new browser window. browserWindowPointer->show(); @@ -1322,8 +1322,8 @@ void BrowserWindow::showBookmarkContextMenu(const QPoint &point) // Get the bookmark. BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId); - // Open the bookmark in a new tab. `true` removes the URL line edit focus, `false` does not load a background tab. - tabWidgetPointer->addTab(true, false, bookmarkStructPointer->url); + // Open the bookmark in a new tab. `true` removes the URL line edit focus, `true` opens the new tab in an adjacent tab. `false` does not load a background tab. + tabWidgetPointer->addTab(true, true, false, bookmarkStructPointer->url); } ); @@ -1333,8 +1333,8 @@ void BrowserWindow::showBookmarkContextMenu(const QPoint &point) // Get the bookmark. BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId); - // Open the bookmark in a new tab. `true` removes the URL line edit focus, `true` loads a background tab. - tabWidgetPointer->addTab(true, true, bookmarkStructPointer->url); + // Open the bookmark in a new tab. `true` removes the URL line edit focus, `true` opens the new tab in an adjacent tab. `true` loads a background tab. + tabWidgetPointer->addTab(true, true, true, bookmarkStructPointer->url); } ); @@ -1823,8 +1823,8 @@ void BrowserWindow::toggleViewSourceInNewTab() const url = url.prepend(QLatin1String("view-source:")); } - // Add the new tab. `true` removes the URL line edit focus, `false` does not open a background tab. - tabWidgetPointer->addTab(true, false, url); + // 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 -- 2.43.0 From 77398618a48027f56c9bbd95e8a02245d79f6884 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Thu, 28 Dec 2023 14:19:10 -0700 Subject: [PATCH 05/16] Add option to auto update the download directory. https://redmine.stoutner.com/issues/1103 --- src/settings/Settings.kcfg | 6 +- src/settings/Settings.kcfgc | 2 +- src/uis/SettingsGeneral.ui | 106 +++++++++++++++++++--------------- src/widgets/TabWidget.cpp | 35 +++++++++-- src/widgets/TabWidget.h | 3 + src/windows/BrowserWindow.cpp | 31 +++++----- src/windows/BrowserWindow.h | 4 +- 7 files changed, 117 insertions(+), 70 deletions(-) diff --git a/src/settings/Settings.kcfg b/src/settings/Settings.kcfg index 4216013..3607793 100644 --- a/src/settings/Settings.kcfg +++ b/src/settings/Settings.kcfg @@ -60,10 +60,14 @@ 1.00 - + System Download Directory + + true + + true diff --git a/src/settings/Settings.kcfgc b/src/settings/Settings.kcfgc index dce7cb8..3cb234c 100644 --- a/src/settings/Settings.kcfgc +++ b/src/settings/Settings.kcfgc @@ -29,4 +29,4 @@ ClassName=Settings Singleton=true # List of variables that can be manually changed. -Mutators=spellCheckLanguages +Mutators=spellCheckLanguages,downloadDirectory diff --git a/src/uis/SettingsGeneral.ui b/src/uis/SettingsGeneral.ui index 4c08bda..15f776f 100644 --- a/src/uis/SettingsGeneral.ui +++ b/src/uis/SettingsGeneral.ui @@ -146,52 +146,6 @@ - - - - - - - Download Location - - - - The default is System Download Directory. - - - - - - - - - 0 - 0 - - - - - true - - - - - System Download Directory - - - - - - - - - Browse - - - - - - @@ -213,8 +167,66 @@ - Spatial navigation allows the moving between links and input fields using the keyboard arrow keys. The default is enabled. + Allow moving between links and input fields using the keyboard arrow keys. The default is enabled. + + + + + + + + + Download Location + + + + + + + + + + 0 + 0 + + + + + true + + + + + System Download Directory + + + + + + + + + Browse + + + + + + + + + + + Auto update the download directory + + + + Automatically update the download directory to be whatever was used for the last download. The default is enabled. + + + + diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index efd677d..4f4a635 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -916,7 +916,7 @@ void TabWidget::saveArchive() QString suggestedFileName = currentPrivacyWebEngineViewPointer->title() + ".mht"; // Get the download directory. - QString downloadDirectory = Settings::downloadLocation(); + QString downloadDirectory = Settings::downloadDirectory(); // Resolve the system download directory if specified. if (downloadDirectory == QLatin1String("System Download Directory")) @@ -928,6 +928,10 @@ void TabWidget::saveArchive() // Save the webpage as an archive if the file save path is populated. if (!saveFilePath.isEmpty()) { + // Update the download directory if specified. + if (Settings::autoUpateDownloadDirectory()) + updateDownloadDirectory(saveFilePath); + // Set the saving archive flag. Otherwise, a second download tries to run. savingArchive = true; @@ -966,7 +970,7 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin if (saveDialogResult == QDialog::Accepted) // Save was selected. { // Get the download directory. - QString downloadDirectory = Settings::downloadLocation(); + QString downloadDirectory = Settings::downloadDirectory(); // Resolve the system download directory if specified. if (downloadDirectory == QLatin1String("System Download Directory")) @@ -978,6 +982,10 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin // Process the save file path. if (!saveFilePath.isEmpty()) // The file save path is populated. { + // Update the download directory if specified. + if (Settings::autoUpateDownloadDirectory()) + updateDownloadDirectory(saveFilePath); + // Create a save file path file info. QFileInfo saveFilePathFileInfo = QFileInfo(saveFilePath); @@ -1199,6 +1207,21 @@ void TabWidget::toggleLocalStorage() currentPrivacyWebEngineViewPointer->reload(); } +void TabWidget::updateDownloadDirectory(QString newDownloadDirectory) const +{ + // Remove the file name from the save file path. + newDownloadDirectory.truncate(newDownloadDirectory.lastIndexOf(QLatin1Char('/'))); + + // Update the download location. + Settings::setDownloadDirectory(newDownloadDirectory); + + // Get a handle for the KConfig skeleton. + KConfigSkeleton *kConfigSkeletonPointer = Settings::self(); + + // Write the settings to disk. + kConfigSkeletonPointer->save(); +} + void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWebEngineViewPointer) const { // Only update the UI if the signal was emitted from the current privacy WebEngine. @@ -1262,7 +1285,7 @@ void TabWidget::updateUiWithTabSettings() void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFileName) { // Get the download directory. - QString downloadDirectory = Settings::downloadLocation(); + QString downloadDirectory = Settings::downloadDirectory(); // Resolve the system download directory if specified. if (downloadDirectory == QLatin1String("System Download Directory")) @@ -1281,11 +1304,15 @@ void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFile saveFileDialogPointer->setWindowModality(Qt::WindowModal); // Process the saving of the file. The save file dialog pointer must be captured directly instead of by reference or nasty crashes occur. - auto saveFile = [saveFileDialogPointer, downloadUrl] () + auto saveFile = [saveFileDialogPointer, downloadUrl, this] () { // Get the save location. The dialog box should only allow the selecting of one file location. QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0); + // Update the download directory if specified. + if (Settings::autoUpateDownloadDirectory()) + updateDownloadDirectory(saveLocation.toLocalFile()); + // Create a file copy job. `-1` creates the file with default permissions. KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite); diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index e47370c..06676d6 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -136,6 +136,9 @@ private Q_SLOTS: void useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFileName); private: + // The private functions. + void updateDownloadDirectory(QString newDownloadDirectory) const; + // The private variables. PrivacyWebEngineView *currentPrivacyWebEngineViewPointer; QWebEngineCookieStore *currentWebEngineCookieStorePointer; diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 394340b..1513d1a 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -1446,28 +1446,29 @@ void BrowserWindow::showCookiesDialog() connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), tabWidgetPointer, SLOT(deleteCookieFromStore(QNetworkCookie))); } -void BrowserWindow::showDownloadLocationBrowseDialog() const +void BrowserWindow::showDownloadDirectoryBrowseDialog() const { - // Get the current download location. - QString currentDownloadLocation = downloadLocationComboBoxPointer->currentText(); + // Get the current download directory. + QString currentDownloadDirectory = downloadDirectoryComboBoxPointer->currentText(); // Resolve the system download directory if specified. - if (currentDownloadLocation == QStringLiteral("System Download Directory")) - currentDownloadLocation = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + if (currentDownloadDirectory == QStringLiteral("System Download Directory")) + currentDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); - // Get the new download location. - QString newDownloadLocation = QFileDialog::getExistingDirectory(configDialogPointer, i18nc("Select download location dialog caption", "Select Download Location"), currentDownloadLocation); + // Get the new download directory. + QString newDownloadDirectory = QFileDialog::getExistingDirectory(configDialogPointer, i18nc("Select download directory dialog caption", "Select Download Directory"), + currentDownloadDirectory); - // Populate the download location combo box according to the new download location. - if (newDownloadLocation == QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) // The default download location was selected. + // 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. - downloadLocationComboBoxPointer->setCurrentText("System Download Directory"); + downloadDirectoryComboBoxPointer->setCurrentText("System Download Directory"); } - else if (newDownloadLocation != QStringLiteral("")) // A different directory was selected. + else if (newDownloadDirectory != QStringLiteral("")) // A different directory was selected. { // Populate the download location. - downloadLocationComboBoxPointer->setCurrentText(newDownloadLocation); + downloadDirectoryComboBoxPointer->setCurrentText(newDownloadDirectory); } } @@ -1542,7 +1543,7 @@ void BrowserWindow::showSettingsDialog() userAgentLabelPointer = privacySettingsUi.userAgentLabel; QComboBox *searchEngineComboBoxPointer = generalSettingsUi.kcfg_searchEngine; searchEngineLabelPointer = generalSettingsUi.searchEngineLabel; - downloadLocationComboBoxPointer = generalSettingsUi.kcfg_downloadLocation; + downloadDirectoryComboBoxPointer = generalSettingsUi.kcfg_downloadDirectory; QPushButton *browseButtonPointer = generalSettingsUi.browseButton; QListWidget *spellCheckListWidgetPointer = spellCheckSettingsUi.spellCheckListWidget; @@ -1554,8 +1555,8 @@ void BrowserWindow::showSettingsDialog() 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 location directory browse button. - connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(showDownloadLocationBrowseDialog())); + // 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")); diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index 87297dc..143e35f 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -77,7 +77,7 @@ private Q_SLOTS: void reloadAndBypassCache() const; void showBookmarkContextMenu(const QPoint &point); void showCookiesDialog(); - void showDownloadLocationBrowseDialog() const; + void showDownloadDirectoryBrowseDialog() const; void showDomainSettingsDialog() const; void showFindTextActions() const; void showProgressBar(const int &progress) const; @@ -133,7 +133,7 @@ private: double defaultZoomFactor; QAction *developerToolsActionPointer; QAction *domStorageActionPointer; - QComboBox *downloadLocationComboBoxPointer; + QComboBox *downloadDirectoryComboBoxPointer; QList *> finalBookmarkFolderMenuActionList; QAction *findCaseSensitiveActionPointer; QAction *findNextActionPointer; -- 2.43.0 From 2e3b899634155bbbedf6cce0e3156fa00d4a16e8 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 29 Dec 2023 16:30:25 -0700 Subject: [PATCH 06/16] Focus the bookmark name when adding or editing bookmarks. https://redmine.stoutner.com/issues/1096 --- src/dialogs/AddBookmarkDialog.cpp | 6 ++++-- src/dialogs/EditBookmarkDialog.cpp | 6 ++++-- src/dialogs/EditFolderDialog.cpp | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/dialogs/AddBookmarkDialog.cpp b/src/dialogs/AddBookmarkDialog.cpp index 9f977af..4c91c2c 100644 --- a/src/dialogs/AddBookmarkDialog.cpp +++ b/src/dialogs/AddBookmarkDialog.cpp @@ -94,10 +94,12 @@ AddBookmarkDialog::AddBookmarkDialog(const QString &bookmarkName, const QString bookmarkNameLineEditPointer->setText(bookmarkName); bookmarkUrlLineEditPointer->setText(bookmarkUrl); - // Scroll to the beginning of the line edits. - bookmarkNameLineEditPointer->setCursorPosition(0); + // Scroll to the beginning of the bookmark URL line edit. bookmarkUrlLineEditPointer->setCursorPosition(0); + // Focus the bookmark name line edit. + bookmarkNameLineEditPointer->setFocus(); + // Add buttons to the dialog button box. addButtonPointer = dialogButtonBoxPointer->addButton(i18nc("The add bookmark button", "Add"), QDialogButtonBox::AcceptRole); diff --git a/src/dialogs/EditBookmarkDialog.cpp b/src/dialogs/EditBookmarkDialog.cpp index 3a4d770..a0c0c77 100644 --- a/src/dialogs/EditBookmarkDialog.cpp +++ b/src/dialogs/EditBookmarkDialog.cpp @@ -96,10 +96,12 @@ EditBookmarkDialog::EditBookmarkDialog(const int databaseId, QIcon ¤tWebsi bookmarkNameLineEditPointer->setText(bookmarkStructPointer->name); bookmarkUrlLineEditPointer->setText(bookmarkStructPointer->url); - // Scroll to the beginning of the line edits. - bookmarkNameLineEditPointer->setCursorPosition(0); + // Scroll to the beginning of the bookmark URL line edit. bookmarkUrlLineEditPointer->setCursorPosition(0); + // Focus the bookmark name line edit. + bookmarkNameLineEditPointer->setFocus(); + // Connect the buttons. connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(browse())); connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(save())); diff --git a/src/dialogs/EditFolderDialog.cpp b/src/dialogs/EditFolderDialog.cpp index eb2bdcf..4285444 100644 --- a/src/dialogs/EditFolderDialog.cpp +++ b/src/dialogs/EditFolderDialog.cpp @@ -93,8 +93,8 @@ EditFolderDialog::EditFolderDialog(const int databaseId, QIcon ¤tWebsiteFa // Populate the line edits. folderNameLineEditPointer->setText(bookmarkStructPointer->name); - // Scroll to the beginning of the line edits. - folderNameLineEditPointer->setCursorPosition(0); + // Focus the folder name line edit. + folderNameLineEditPointer->setFocus(); // Connect the buttons. connect(browseButtonPointer, SIGNAL(clicked()), this, SLOT(browse())); -- 2.43.0 From 03d1e9e85a1fc8c7f561d0c7d9492ef1bee292db Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 10 Jan 2024 14:55:25 -0700 Subject: [PATCH 07/16] Create new domain settings with the currently applied settings. https://redmine.stoutner.com/issues/1101 --- COPYING | 2 +- doc/index.docbook | 102 +++++++++++++++++++++--- src/databases/DomainsDatabase.cpp | 45 ++++++++++- src/databases/DomainsDatabase.h | 5 +- src/dialogs/DomainSettingsDialog.cpp | 79 +++++++------------ src/dialogs/DomainSettingsDialog.h | 3 +- src/helpers/UserAgentHelper.cpp | 16 +++- src/helpers/UserAgentHelper.h | 5 +- src/main.cpp | 4 +- src/widgets/TabWidget.cpp | 12 ++- src/widgets/TabWidget.h | 9 ++- src/windows/BrowserWindow.cpp | 111 ++++++++++++++++++--------- src/windows/BrowserWindow.h | 11 +-- 13 files changed, 282 insertions(+), 122 deletions(-) diff --git a/COPYING b/COPYING index 6e02237..7cf0ecb 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -Privacy Browser PC copyright 2016-2017,2021-2023 Soren Stoutner . +Privacy Browser PC copyright 2016-2017,2021-2024 Soren Stoutner . This file is part of Privacy Browser PC . diff --git a/doc/index.docbook b/doc/index.docbook index d061163..27ee1fc 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -1,7 +1,7 @@ - 2023-10-12 + 2024-01-06 &privacybrowser; version 0.5 @@ -394,6 +394,27 @@ + + + + + + &Ctrl;A + + + File + + Save Archive + + + + + + Save the webpage as an MHT (MIME encapsulation of aggregate HTML documents) archive. + + + + @@ -535,6 +556,27 @@ View + + + + + + &Ctrl;0 + + + View + + Zoom Default + + + + + + Return to either the app or the domain default zoom factor. + + + + @@ -594,7 +636,7 @@ - Reload the website in the current tab. + Reload the website in the current tab. When Refresh is visible, is hidden. @@ -620,6 +662,27 @@ + + + + + + &Ctrl;&Shift;X + + + View + + Stop + + + + + + Stop the loading of the website in the current tab. When Stop is visible, is hidden. + + + + @@ -663,6 +726,27 @@ + + + + + + F12 + + + View + + Developer Tools + + + + + + Display the developer tools, which are used to debug websites. + + + + @@ -1242,7 +1326,7 @@ - + @@ -1263,7 +1347,7 @@ - + @@ -1284,7 +1368,7 @@ - + @@ -1305,7 +1389,7 @@ - + @@ -1762,7 +1846,7 @@ Credits and License - Privacy Browser PC copyright 2016-2017,2021-2023 Soren Stoutner soren@stoutner.com. + Privacy Browser PC copyright 2016-2017,2021-2024 Soren Stoutner soren@stoutner.com. diff --git a/src/databases/DomainsDatabase.cpp b/src/databases/DomainsDatabase.cpp index 0553543..d52647c 100644 --- a/src/databases/DomainsDatabase.cpp +++ b/src/databases/DomainsDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -19,6 +19,7 @@ // Application headers. #include "DomainsDatabase.h" +#include "Settings.h" #include "helpers/UserAgentHelper.h" // Define the private static schema constants. @@ -266,11 +267,51 @@ void DomainsDatabase::addDatabase() } else // Opening the database failed. { - // Write the last database error message to the debug output. + // Write the last database error message to the debug output.Settings::zoom qDebug().noquote().nospace() << "Error opening database: " << domainsDatabase.lastError(); } }; +void DomainsDatabase::addDomain(const QString &domainName) +{ + // Add the domain: + addDomain(domainName, SYSTEM_DEFAULT, SYSTEM_DEFAULT, SYSTEM_DEFAULT, UserAgentHelper::SYSTEM_DEFAULT_DATABASE, SYSTEM_DEFAULT, Settings::zoomFactor()); +} + +void DomainsDatabase::addDomain(const QString &domainName, const int javaScriptInt, const int localStorageInt, const int domStorageInt, const QString &userAgentDatabaseString, + const int zoomFactorInt, const double currentZoomFactorDouble) +{ + // Get a handle for the domains database. + QSqlDatabase domainsDatabase = QSqlDatabase::database(CONNECTION_NAME); + + // Instantiate an add domain settings query. + QSqlQuery addDomainSettingsQuery(domainsDatabase); + + // Prepare the query. + addDomainSettingsQuery.prepare("INSERT INTO " + DomainsDatabase::DOMAINS_TABLE + " (" + + DomainsDatabase::DOMAIN_NAME + ", " + + DomainsDatabase::JAVASCRIPT + ", " + + DomainsDatabase::LOCAL_STORAGE + ", " + + DomainsDatabase::DOM_STORAGE + ", " + + DomainsDatabase::USER_AGENT + ", " + + DomainsDatabase::ZOOM_FACTOR + ", " + + DomainsDatabase::CUSTOM_ZOOM_FACTOR + ") " + + "VALUES (:domain_name, :javascript, :local_storage, :dom_storage, :user_agent, :zoom_factor, :custom_zoom_factor)" + ); + + // Bind the query values. + addDomainSettingsQuery.bindValue(":domain_name", domainName); + addDomainSettingsQuery.bindValue(":javascript", javaScriptInt); + addDomainSettingsQuery.bindValue(":local_storage", localStorageInt); + addDomainSettingsQuery.bindValue(":dom_storage", domStorageInt); + addDomainSettingsQuery.bindValue(":user_agent", userAgentDatabaseString); + addDomainSettingsQuery.bindValue(":zoom_factor", zoomFactorInt); + addDomainSettingsQuery.bindValue(":custom_zoom_factor", currentZoomFactorDouble); + + // Execute the query. + addDomainSettingsQuery.exec(); +} + QSqlQuery DomainsDatabase::getDomainQuery(const QString &hostname) { // Get a handle for the domains database. diff --git a/src/databases/DomainsDatabase.h b/src/databases/DomainsDatabase.h index cb7e09d..1e58d2e 100644 --- a/src/databases/DomainsDatabase.h +++ b/src/databases/DomainsDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -31,6 +31,9 @@ public: // The public functions. static void addDatabase(); + static void addDomain(const QString &domainName); + static void addDomain(const QString &domainName, const int javaScriptInt, const int localStorageInt, const int domStorageInt, const QString &userAgentDatabaseString, const int zoomFactorInt, + const double currentZoomFactorDouble); static QSqlQuery getDomainQuery(const QString &hostname); // The public int constants. diff --git a/src/dialogs/DomainSettingsDialog.cpp b/src/dialogs/DomainSettingsDialog.cpp index 82f0f64..59d7bdb 100644 --- a/src/dialogs/DomainSettingsDialog.cpp +++ b/src/dialogs/DomainSettingsDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -31,8 +31,7 @@ // Define the public static int constants. const int DomainSettingsDialog::SHOW_ALL_DOMAINS = 0; -const int DomainSettingsDialog::ADD_DOMAIN = 1; -const int DomainSettingsDialog::EDIT_DOMAIN = 2; +const int DomainSettingsDialog::EDIT_DOMAIN = 1; // Construct the class. DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &domainName) : QDialog(nullptr) @@ -133,17 +132,6 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString & break; } - case ADD_DOMAIN: - { - // Add the new domain. - addDomain(domainName); - - // 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. - QTimer::singleShot(100, [this] () { emit domainSettingsUpdated();}); - - break; - } - case EDIT_DOMAIN: { // Find the index for the new domain. `1` returns the first match. @@ -184,43 +172,6 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString & updateUi(); } -void DomainSettingsDialog::addDomain(const QString &domainName) const -{ - // Create a new domain record. - QSqlRecord newDomainRecord = QSqlDatabase::database(DomainsDatabase::CONNECTION_NAME).record(DomainsDatabase::DOMAINS_TABLE); - - // Set the values for the new domain. - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME), domainName); - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::JAVASCRIPT), DomainsDatabase::SYSTEM_DEFAULT); - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::LOCAL_STORAGE), DomainsDatabase::SYSTEM_DEFAULT); - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::DOM_STORAGE), DomainsDatabase::SYSTEM_DEFAULT); - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::USER_AGENT), UserAgentHelper::SYSTEM_DEFAULT_DATABASE); - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::ZOOM_FACTOR), DomainsDatabase::SYSTEM_DEFAULT); - newDomainRecord.setValue(domainsTableModelPointer->fieldIndex(DomainsDatabase::CUSTOM_ZOOM_FACTOR), 1.0); - - // Insert the new domain. `-1` appends it to the end. - domainsTableModelPointer->insertRecord(-1, newDomainRecord); - - // Submit all pending changes. - domainsTableModelPointer->submitAll(); - - // Find the index for the new domain. `-1` allows for multiple entries to be returned. - QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME)), - Qt::DisplayRole, domainName, -1, Qt::MatchWrap); - - // Move to the new domain. If there are multiple domains with the same name, the new one should be the last in the list. - domainsListViewPointer->setCurrentIndex(newDomainIndex[newDomainIndex.size() - 1]); - - // Populate the domain settings. - domainSelected(domainsSelectionModelPointer->currentIndex()); - - // Update the UI. - updateUi(); - - // Emit the domain settings updated signal. - emit domainSettingsUpdated(); -} - void DomainSettingsDialog::apply() const { // Get the current index. @@ -560,7 +511,31 @@ void DomainSettingsDialog::showAddMessageBox() QLineEdit::Normal, QString(), &okClicked); // Add the new domain if the user clicked OK. - if (okClicked) addDomain(newDomainName); + if (okClicked) + { + // Add the new domain. + DomainsDatabase::addDomain(newDomainName); + + // Submit all pending changes. This reloads the model from the database, getting the new domain added above. + domainsTableModelPointer->submitAll(); + + + // Find the index for the new domain. `-1` allows for multiple entries to be returned. + QModelIndexList newDomainIndex = domainsTableModelPointer->match(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME)), + Qt::DisplayRole, newDomainName, -1, Qt::MatchWrap); + + // Move to the new domain. If there are multiple domains with the same name, the new one should be the last in the list. + domainsListViewPointer->setCurrentIndex(newDomainIndex[newDomainIndex.size() - 1]); + + // Populate the domain settings. + domainSelected(domainsSelectionModelPointer->currentIndex()); + + // Update the UI. + updateUi(); + + // Emit the domain settings updated signal. + emit domainSettingsUpdated(); + } } void DomainSettingsDialog::showDeleteMessageBox() const diff --git a/src/dialogs/DomainSettingsDialog.h b/src/dialogs/DomainSettingsDialog.h index 7163458..543c1bb 100644 --- a/src/dialogs/DomainSettingsDialog.h +++ b/src/dialogs/DomainSettingsDialog.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Soren Stoutner . + * Copyright 2022,2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -96,7 +96,6 @@ private: QComboBox *zoomFactorComboBoxPointer; // The private functions. - void addDomain(const QString &domainName) const; void populateDomStorageLabel() const; void populateJavaScriptLabel() const; void populateLocalStorageLabel() const; diff --git a/src/helpers/UserAgentHelper.cpp b/src/helpers/UserAgentHelper.cpp index 1033c93..de58905 100644 --- a/src/helpers/UserAgentHelper.cpp +++ b/src/helpers/UserAgentHelper.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -74,6 +74,20 @@ QString UserAgentHelper::getDatabaseUserAgentNameFromTranslatedName(const QStrin else return translatedUserAgentName; // Return the custom user agent. } +QString UserAgentHelper::getDatabaseUserAgentNameFromUserAgent(const QString &userAgent) +{ + // Return the database user agent name. + if (userAgent == PRIVACY_BROWSER_USER_AGENT) return PRIVACY_BROWSER_DATABASE; // Privacy Browser. + else if (userAgent == TabWidget::webEngineDefaultUserAgent) return WEB_ENGINE_DEFAULT_DATABASE; // WebEngine default. + else if (userAgent == FIREFOX_LINUX_USER_AGENT) return FIREFOX_LINUX_DATABASE; // Firefox Linux. + else if (userAgent == CHROMIUM_LINUX_USER_AGENT) return CHROMIUM_LINUX_DATABASE; // Chromium Linux. + else if (userAgent == FIREFOX_WINDOWS_USER_AGENT) return FIREFOX_WINDOWS_DATABASE; // Firefox Windows. + else if (userAgent == CHROME_WINDOWS_USER_AGENT) return CHROME_WINDOWS_DATABASE; // Chrome Windows. + else if (userAgent == EDGE_WINDOWS_USER_AGENT) return EDGE_WINDOWS_DATABASE; // Edge Windows. + else if (userAgent == SAFARI_MACOS_USER_AGENT) return SAFARI_MACOS_DATABASE; // Safari macOS. + else return userAgent; // Return the custom user agent. +} + int UserAgentHelper::getDomainSettingsUserAgentIndex(const QString &userAgentName) { // Return the domain settings user agent index. diff --git a/src/helpers/UserAgentHelper.h b/src/helpers/UserAgentHelper.h index aee7bc9..60f9902 100644 --- a/src/helpers/UserAgentHelper.h +++ b/src/helpers/UserAgentHelper.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Soren Stoutner . + * Copyright 2022,2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -51,6 +51,7 @@ public: static const QString WEB_ENGINE_DEFAULT_DATABASE; // The public static functions. + static QString getDatabaseUserAgentNameFromUserAgent(const QString &userAgent); static int getDomainSettingsUserAgentIndex(const QString &userAgentName); static QString getUserAgentFromDatabaseName(const QString &userAgentDatabaseName); static QString getResultingDomainSettingsUserAgent(const QString &rawUserAgent); @@ -66,7 +67,7 @@ public: QString EDGE_WINDOWS_TRANSLATED; QString SAFARI_MACOS_TRANSLATED; - // The public functions. + // The public functions. Anything that accesses the translated user names must use an instantiated copy of the class. QString getDatabaseUserAgentNameFromTranslatedName(const QString &translatedUserAgentName); QString getUserAgentFromTranslatedName(const QString &userAgentTranslatedName); QString getTranslatedUserAgentNameFromDatabaseName(const QString &userAgentName); diff --git a/src/main.cpp b/src/main.cpp index 3cedc08..0c499f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) // Populate additional about data info. aboutData.setBugAddress("https://redmine.stoutner.com/projects/privacy-browser-pc/issues"); - aboutData.setCopyrightStatement(i18nc("Copyright", "Copyright 2016-2017,2021-2023 Soren Stoutner ")); + aboutData.setCopyrightStatement(i18nc("Copyright", "Copyright 2016-2017,2021-2024 Soren Stoutner ")); aboutData.setDesktopFileName(QStringLiteral("com.stoutner.privacybrowser")); aboutData.setHomepage(QStringLiteral("https://www.stoutner.com/privacy-browser-pc/")); //aboutData.setLicense(KAboutLicense::GPL_V3, KAboutLicense::OrLaterVersions); diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index 4f4a635..58ccfc6 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -573,10 +573,10 @@ void TabWidget::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const currentPrivacyWebEngineViewPointer->reload(); } -void TabWidget::applyOnTheFlyZoomFactor(const double &zoomFactor) const +void TabWidget::applyOnTheFlyZoomFactor(const double zoomFactorDouble) const { // Set the zoom factor. - currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactor); + currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactorDouble); } void TabWidget::applySpellCheckLanguages() const @@ -737,6 +737,12 @@ QString TabWidget::getCurrentTabUrl() const return currentPrivacyWebEngineViewPointer->url().toString(); } +QString TabWidget::getCurrentUserAgent() const +{ + // Return the current WebEngine user agent. + return currentWebEngineProfilePointer->httpUserAgent(); +} + QString& TabWidget::getDomainSettingsName() const { // Return the domain settings name. diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index 06676d6..7dbb581 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -51,7 +51,7 @@ public: ~TabWidget(); // The public functions. - void applyOnTheFlyZoomFactor(const double &zoomFactor) const; + void applyOnTheFlyZoomFactor(const double zoomFactorDouble) const; void applySpellCheckLanguages() const; PrivacyWebEngineView* loadBlankInitialWebsite(); void loadInitialWebsite(); @@ -60,6 +60,7 @@ public: QIcon getCurrentTabFavoritIcon() const; QString getCurrentTabTitle() const; QString getCurrentTabUrl() const; + QString getCurrentUserAgent() const; QString& getDomainSettingsName() const; void setTabBarVisible(const bool visible) const; void toggleDeveloperTools(const bool enabled) const; @@ -82,7 +83,7 @@ signals: void showProgressBar(const int &progress) const; void updateBackAction(const bool &isEnabled) const; void updateCookiesAction(const int numberOfCookies) const; - void updateDefaultZoomFactor(const double newDefaultZoomFactor) const; + void updateDefaultZoomFactor(const double newDefaultZoomFactorDouble) const; void updateDeveloperToolsAction(const bool &isEnabled) const; void updateDomStorageAction(const bool &isEnabled) const; void updateDomainSettingsIndicator(const bool status) const; @@ -95,7 +96,7 @@ signals: void updateUrlLineEdit(const QUrl &newUrl) const; void updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus) const; void updateWindowTitle(const QString &title) const; - void updateZoomActions(const double &zoomFactor) const; + void updateZoomActions(const double zoomFactorDouble) const; public Q_SLOTS: // The public slots. diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 1513d1a..13e3c51 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -24,6 +24,7 @@ #include "ui_SettingsPrivacy.h" #include "ui_SettingsSpellCheck.h" #include "databases/BookmarksDatabase.h" +#include "databases/DomainsDatabase.h" #include "dialogs/AddBookmarkDialog.h" #include "dialogs/AddFolderDialog.h" #include "dialogs/BookmarksDialog.h" @@ -773,24 +774,47 @@ void BrowserWindow::addOrEditDomainSettings() const // Remove the focus from the URL line edit. urlLineEditPointer->clearFocus(); - // Create the domain settings dialog pointer. - DomainSettingsDialog *domainSettingsDialogPointer; - // Get the current domain settings name. QString ¤tDomainSettingsName = tabWidgetPointer->getDomainSettingsName(); // Run the commands according to the current domain settings status. if (currentDomainSettingsName == QStringLiteral("")) // Domain settings are not currently applied. { - // Instruct the domain settings dialog to add a new domain. - domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::ADD_DOMAIN, currentUrl.host()); - } - else // Domain settings are currently applied. - { - // Instruct the domain settings dialog to edit the current domain. - domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName); + // Get the current settings status. + int javaScriptInt = calculateSettingsInt(javaScriptEnabled, Settings::javaScriptEnabled()); + int localStorageInt = calculateSettingsInt(localStorageActionPointer->isChecked(), Settings::localStorageEnabled()); + int domStorageInt = calculateSettingsInt(domStorageActionPointer->isChecked(), Settings::domStorageEnabled()); + + // Get the current user agent string. + QString currentUserAgentString = tabWidgetPointer->getCurrentUserAgent(); + + // Get the current user agent database string. + QString currentUserAgentDatabaseString = UserAgentHelper::getDatabaseUserAgentNameFromUserAgent(currentUserAgentString); + + // Initialize the user agent database string. + QString userAgentDatabaseString = UserAgentHelper::SYSTEM_DEFAULT_DATABASE; + + // Replace the user agent database string if the current user agent is not the default. + if (currentUserAgentDatabaseString != Settings::userAgent()) + userAgentDatabaseString = currentUserAgentDatabaseString; + + // Initialize the zoom factor variables. + int zoomFactorInt = DomainsDatabase::SYSTEM_DEFAULT; + + // Use a custom zoom factor if currently applied. Doubles cannot be reliably compared using `==`, so a mathematical workaround is used. + if (abs(currentZoomFactorDouble - defaultZoomFactorDouble ) > 0.01) + zoomFactorInt = DomainsDatabase::CUSTOM; + + // Add the domain. + DomainsDatabase::addDomain(currentUrl.host(), javaScriptInt, localStorageInt, domStorageInt, userAgentDatabaseString, zoomFactorInt, currentZoomFactorDouble); + + // Apply the domain settings. + tabWidgetPointer->applyDomainSettingsAndReload(); } + // Create the domain settings dialog pointer. + DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName); + // Reload the tabs when domain settings are updated. connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload())); @@ -807,6 +831,17 @@ void BrowserWindow::back() const tabWidgetPointer->back(); } +int BrowserWindow::calculateSettingsInt(const bool settingCurrentlyEnabled, const bool settingEnabledByDefault) const +{ + // Return the int that matches the current state. + if (settingCurrentlyEnabled == settingEnabledByDefault) // The current system default is used. + return DomainsDatabase::SYSTEM_DEFAULT; + else if (settingCurrentlyEnabled) // The setting is enabled, which is different from the system default. + return DomainsDatabase::ENABLED; + else // The setting is disabled, which is different from the system default. + return DomainsDatabase::DISABLED; +} + void BrowserWindow::clearUrlLineEditFocus() const { // Remove the focus from the URL line edit. @@ -816,17 +851,17 @@ void BrowserWindow::clearUrlLineEditFocus() const void BrowserWindow::decrementZoom() { // Update the current zoom factor. - currentZoomFactor = currentZoomFactor - 0.25; + currentZoomFactorDouble = currentZoomFactorDouble - 0.25; // Check to make sure the zoom factor is in the valid range (0.25 to 5.00). - if (currentZoomFactor < 0.25) - currentZoomFactor = 0.25; + if (currentZoomFactorDouble < 0.25) + currentZoomFactorDouble = 0.25; // Set the new zoom factor. - tabWidgetPointer->applyOnTheFlyZoomFactor(currentZoomFactor); + tabWidgetPointer->applyOnTheFlyZoomFactor(currentZoomFactorDouble); // Update the on-the-fly action text. - updateZoomActions(currentZoomFactor); + updateZoomActions(currentZoomFactorDouble); } void BrowserWindow::editBookmarks() const @@ -951,18 +986,18 @@ void BrowserWindow::getZoomFactorFromUser() bool okClicked; // Display a dialog to get the new zoom factor from the user. Format the double to display two decimals and have a 0.25 step. - double newZoomFactor = QInputDialog::getDouble(this, i18nc("The on-the-fly zoom factor dialog title", "On-The-Fly Zoom Factor"), + double newZoomFactorDouble = QInputDialog::getDouble(this, i18nc("The on-the-fly zoom factor dialog title", "On-The-Fly Zoom Factor"), i18nc("The instruction text of the on-the-fly zoom factor dialog", "Enter a zoom factor between 0.25 and 5.00"), - currentZoomFactor, .025, 5.00, 2, &okClicked, Qt::WindowFlags(), 0.25); + currentZoomFactorDouble, .025, 5.00, 2, &okClicked, Qt::WindowFlags(), 0.25); // Update the zoom factor if the user clicked OK. if (okClicked) { // Set the new zoom factor. - tabWidgetPointer->applyOnTheFlyZoomFactor(newZoomFactor); + tabWidgetPointer->applyOnTheFlyZoomFactor(newZoomFactorDouble); // Update the on-the-fly action text. - updateZoomActions(newZoomFactor); + updateZoomActions(newZoomFactorDouble); } } @@ -1003,17 +1038,17 @@ void BrowserWindow::hideProgressBar() const void BrowserWindow::incrementZoom() { // Update the current zoom factor. - currentZoomFactor = currentZoomFactor + 0.25; + currentZoomFactorDouble = currentZoomFactorDouble + 0.25; // Check to make sure the zoom factor is in the valid range (0.25 to 5.00). - if (currentZoomFactor > 5.0) - currentZoomFactor = 5.0; + if (currentZoomFactorDouble > 5.0) + currentZoomFactorDouble = 5.0; // Set the new zoom factor. - tabWidgetPointer->applyOnTheFlyZoomFactor(currentZoomFactor); + tabWidgetPointer->applyOnTheFlyZoomFactor(currentZoomFactorDouble); // Update the on-the-fly action text. - updateZoomActions(currentZoomFactor); + updateZoomActions(currentZoomFactorDouble); } void BrowserWindow::loadUrlFromLineEdit(const QString &url) const @@ -1843,10 +1878,10 @@ void BrowserWindow::updateCookiesAction(const int numberOfCookies) const cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies)); } -void BrowserWindow::updateDefaultZoomFactor(const double newDefaultZoomFactor) +void BrowserWindow::updateDefaultZoomFactor(const double newDefaultZoomFactorDouble) { // Store the new default zoom factor. - defaultZoomFactor = newDefaultZoomFactor; + defaultZoomFactorDouble = newDefaultZoomFactorDouble; } void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const @@ -2244,35 +2279,35 @@ void BrowserWindow::updateWindowTitle(const QString &title) setWindowTitle(title); } -void BrowserWindow::updateZoomActions(const double &zoomFactor) +void BrowserWindow::updateZoomActions(const double zoomFactorDouble) { // Set the current zoom factor. - currentZoomFactor = zoomFactor; + currentZoomFactorDouble = zoomFactorDouble; // Set the status of the default zoom action. - zoomDefaultActionPointer->setEnabled(currentZoomFactor != defaultZoomFactor); + zoomDefaultActionPointer->setEnabled(currentZoomFactorDouble != defaultZoomFactorDouble); // Set the status of the zoom in action and button. - zoomInActionPointer->setEnabled(currentZoomFactor <= 4.99); - zoomPlusButtonPointer->setEnabled(currentZoomFactor <= 4.99); + zoomInActionPointer->setEnabled(currentZoomFactorDouble <= 4.99); + zoomPlusButtonPointer->setEnabled(currentZoomFactorDouble <= 4.99); // Set the status of the zoom out action and button. - zoomMinusButtonPointer->setEnabled(currentZoomFactor > 0.25); - zoomOutActionPointer->setEnabled(currentZoomFactor > 0.25); + zoomMinusButtonPointer->setEnabled(currentZoomFactorDouble > 0.25); + zoomOutActionPointer->setEnabled(currentZoomFactorDouble > 0.25); // Update the zoom factor action text, formatting the double with 2 decimal places. `0` specifies no extra field width. `'0'` sets the format to not use scientific notation. - zoomFactorActionPointer->setText(ki18nc("The zoom factor action", "Zoom Factor - %1").subs(zoomFactor, 0, '0', 2).toString()); + zoomFactorActionPointer->setText(ki18nc("The zoom factor action", "Zoom Factor - %1").subs(zoomFactorDouble, 0, '0', 2).toString()); // Update the status bar zoom factor label. - currentZoomButtonPointer->setText(ki18nc("The status bar zoom, which is just the formatted zoom factor", "%1").subs(zoomFactor, 0, '0', 2).toString()); + currentZoomButtonPointer->setText(ki18nc("The status bar zoom, which is just the formatted zoom factor", "%1").subs(zoomFactorDouble, 0, '0', 2).toString()); } void BrowserWindow::zoomDefault() { // Set the new zoom factor. - tabWidgetPointer->applyOnTheFlyZoomFactor(defaultZoomFactor); + tabWidgetPointer->applyOnTheFlyZoomFactor(defaultZoomFactorDouble); // Update the on-the-fly action text. - updateZoomActions(defaultZoomFactor); + updateZoomActions(defaultZoomFactorDouble); } diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index 143e35f..eedc250 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -93,7 +93,7 @@ private Q_SLOTS: void toggleViewSource() const; void toggleViewSourceInNewTab() const; void updateCookiesAction(const int numberOfCookies) const; - void updateDefaultZoomFactor(const double newDefaultZoomFactor); + void updateDefaultZoomFactor(const double newDefaultZoomFactorDouble); void updateDomStorageAction(const bool &isEnabled) const; void updateDomainSettingsIndicator(const bool status); void updateFindText(const QString &text, const bool findCaseSensitive) const; @@ -102,7 +102,7 @@ private Q_SLOTS: void updateLocalStorageAction(const bool &isEnabled); void updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus); void updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus); - void updateZoomActions(const double &zoomFactor); + void updateZoomActions(const double zoomFactorDouble); void updateSearchEngineLabel(const QString &searchEngineString) const; void updateUrlLineEdit(const QUrl &newUrl); void updateUserAgentLabel(const QString &userAgentDatabaseName) const; @@ -127,10 +127,10 @@ private: QAction *cookiesActionPointer; QUrl currentUrl; QPushButton *currentZoomButtonPointer; - double currentZoomFactor; + double currentZoomFactorDouble; bool customSearchEngineEnabled; bool customUserAgentEnabled; - double defaultZoomFactor; + double defaultZoomFactorDouble; QAction *developerToolsActionPointer; QAction *domStorageActionPointer; QComboBox *downloadDirectoryComboBoxPointer; @@ -189,6 +189,7 @@ private: // The private functions. void addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double folderId); + int calculateSettingsInt(const bool settingCurrentlyEnabled, const bool settingEnabledByDefault) const; void populateBookmarksMenuSubfolders(const double folderId, QMenu *menuPointer); void populateBookmarksToolBar(); void populateBookmarksToolBarSubfolders(const double folderId, QMenu *menuPointer); -- 2.43.0 From ccb069f69e240c890f4f8b921e89c41d8e100589 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 10 Jan 2024 16:09:41 -0700 Subject: [PATCH 08/16] Fix moving a bookmark to a specific location in a different folder. https://redmine.stoutner.com/issues/1149 --- src/widgets/DraggableTreeView.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widgets/DraggableTreeView.cpp b/src/widgets/DraggableTreeView.cpp index 6471b08..b6a28da 100644 --- a/src/widgets/DraggableTreeView.cpp +++ b/src/widgets/DraggableTreeView.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -62,7 +62,7 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) // Process the move according to the drop position. switch (dropPosition) { - case QAbstractItemView::OnItem: + case QAbstractItemView::OnItem: // This will only ever be called for folders as `BookmarksDialog::populateSubfolders` creates bookmarks without `setDropEnabled`. { // Get the new parent folder ID. double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); @@ -109,7 +109,7 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt(); // Get the drop parent folder ID. - double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toInt(); + double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); // Get a list of all the items in the target folder except those selected. QList *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer); @@ -157,7 +157,7 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt(); // Get the drop parent folder ID. - double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toInt(); + double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); // Get a list of all the items in the target folder except those selected. QList *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer); -- 2.43.0 From 436c5cc7e3fd04cabfa07d6e76d38907a0dfbd0d Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Thu, 11 Jan 2024 09:36:58 -0700 Subject: [PATCH 09/16] Make dropping a bookmark under an open folder place it inside the folder. https://redmine.stoutner.com/issues/1150 --- src/widgets/DraggableTreeView.cpp | 165 ++++++++++++++++-------------- src/widgets/DraggableTreeView.h | 5 +- 2 files changed, 95 insertions(+), 75 deletions(-) diff --git a/src/widgets/DraggableTreeView.cpp b/src/widgets/DraggableTreeView.cpp index b6a28da..bbe0868 100644 --- a/src/widgets/DraggableTreeView.cpp +++ b/src/widgets/DraggableTreeView.cpp @@ -57,49 +57,16 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) QModelIndex dropModelIndex = indexAt(dropEvent->pos()); // Create a previous parent folder ID standard C++ list (which can be sorted and from which duplicates can be removed). - std::list previousParentFolderIdList; + std::list *previousParentFolderIdListPointer = new std::list; // Process the move according to the drop position. switch (dropPosition) { case QAbstractItemView::OnItem: // This will only ever be called for folders as `BookmarksDialog::populateSubfolders` creates bookmarks without `setDropEnabled`. { - // Get the new parent folder ID. - double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); + // Move everything to the beginning of the folder. + moveToBeginningOfFolder(dropModelIndex, selectedDatabaseIdsListPointer, rootSelectedDatabaseIdsListPointer, previousParentFolderIdListPointer); - // Get a list of all the items in the target folder except those selected. - QList *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(newParentFolderId, selectedDatabaseIdsListPointer); - - // Initialize a new display order tracker. - int newDisplayOrder = 0; - - // Move all the items to the top of the target folder. - for (const int databaseId : *rootSelectedDatabaseIdsListPointer) - { - // Get the item's current parent folder ID. - double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId); - - // Add the parent folder ID to the list of previous parent folders if the item is from a different folder. - if (currentParentFolderId != newParentFolderId) - previousParentFolderIdList.push_back(currentParentFolderId); - - // Update the parent folder and display order for each bookmark. - BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, newParentFolderId, newDisplayOrder); - - // Increment the new display order. - ++newDisplayOrder; - } - - // Update the display order of the existing items in the folder. - for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer) - { - // Set the bookmark's display order if it has changed. - if (bookmarkStruct.displayOrder != newDisplayOrder) - BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder); - - // Increment the new display order. - ++newDisplayOrder; - } break; } @@ -131,7 +98,7 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) // Add the parent folder ID to the list of previous parent folders if the item is from a different folder. if (currentParentFolderId != dropParentFolderId) - previousParentFolderIdList.push_back(currentParentFolderId); + previousParentFolderIdListPointer->push_back(currentParentFolderId); // Update the parent folder and display order for each bookmark. BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder); @@ -153,46 +120,55 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) case QAbstractItemView::BelowItem: { - // Get the drop display order. - int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt(); + // Check to see if the drop model index is an expanded folder. + if (dropModelIndex.siblingAtColumn(BookmarksDialog::IS_FOLDER_COLUMN).data().toBool() && isExpanded(dropModelIndex)) // The drop model index is an expanded folder. + { + // Move everything to the beginning of the folder. + moveToBeginningOfFolder(dropModelIndex, selectedDatabaseIdsListPointer, rootSelectedDatabaseIdsListPointer, previousParentFolderIdListPointer); + } + else // The drop model index is not an expanded folder. + { + // Get the drop display order. + int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt(); - // Get the drop parent folder ID. - double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); + // Get the drop parent folder ID. + double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); - // Get a list of all the items in the target folder except those selected. - QList *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer); + // Get a list of all the items in the target folder except those selected. + QList *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer); - // Initialize a new display order tracker. - int newDisplayOrder = 0; + // Initialize a new display order tracker. + int newDisplayOrder = 0; - // Process all the items in the target folder, moving in the new ones. - for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer) - { - // Set the bookmark's display order if it has changed. - if (bookmarkStruct.displayOrder != newDisplayOrder) - BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder); - - // Increment the new display order. - ++newDisplayOrder; - - // Check to see if this is the drop display order. - if (bookmarkStruct.displayOrder == dropDisplayOrder) + // Process all the items in the target folder, moving in the new ones. + for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer) { - // Add all of the bookmarks being moved to this point. - for (const int databaseId : *rootSelectedDatabaseIdsListPointer) - { - // Get the item's current parent folder ID. - double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId); + // Set the bookmark's display order if it has changed. + if (bookmarkStruct.displayOrder != newDisplayOrder) + BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder); - // Add the parent folder ID to the list of previous parent folders if the item is from a different folder. - if (currentParentFolderId != dropParentFolderId) - previousParentFolderIdList.push_back(currentParentFolderId); - - // Update the parent folder and display order for each bookmark. - BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder); + // Increment the new display order. + ++newDisplayOrder; - // Increment the new display order. - ++newDisplayOrder; + // Check to see if this is the drop display order. + if (bookmarkStruct.displayOrder == dropDisplayOrder) + { + // Add all of the bookmarks being moved to this point. + for (const int databaseId : *rootSelectedDatabaseIdsListPointer) + { + // Get the item's current parent folder ID. + double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId); + + // Add the parent folder ID to the list of previous parent folders if the item is from a different folder. + if (currentParentFolderId != dropParentFolderId) + previousParentFolderIdListPointer->push_back(currentParentFolderId); + + // Update the parent folder and display order for each bookmark. + BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder); + + // Increment the new display order. + ++newDisplayOrder; + } } } } @@ -229,7 +205,7 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) // Add the parent folder ID to the list of previous parent folders if the item is from a different folder. if (currentParentFolderId != dropParentFolderId) - previousParentFolderIdList.push_back(currentParentFolderId); + previousParentFolderIdListPointer->push_back(currentParentFolderId); // Update the parent folder and display order for each bookmark. BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder); @@ -242,13 +218,13 @@ void DraggableTreeView::dropEvent(QDropEvent *dropEvent) } // Sort the previous parent folder ID list. - previousParentFolderIdList.sort(); + previousParentFolderIdListPointer->sort(); // Remove duplicates from the parent folder ID list. - previousParentFolderIdList.unique(); + previousParentFolderIdListPointer->unique(); // Update the folder contents display order for each previous parent folder. - for (const double parentFolderId : previousParentFolderIdList) + for (const double parentFolderId : *previousParentFolderIdListPointer) BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId); // Emit the bookmarks moved signal. @@ -282,3 +258,44 @@ QList* DraggableTreeView::getRootSelectedDatabaseIds(QList *selectedDa // Return the root selected database IDs list. return rootSelectedDatabaseIdsListPointer; } + +void DraggableTreeView::moveToBeginningOfFolder(const QModelIndex &dropModelIndex, QList *selectedDatabaseIdsListPointer, QList *rootSelectedDatabaseIdsListPointer, + std::list *previousParentFolderIdListPointer) const +{ + // Get the new parent folder ID. + double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble(); + + // Get a list of all the items in the target folder except those selected. + QList *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(newParentFolderId, selectedDatabaseIdsListPointer); + + // Initialize a new display order tracker. + int newDisplayOrder = 0; + + // Move all the items to the top of the target folder. + for (const int databaseId : *rootSelectedDatabaseIdsListPointer) + { + // Get the item's current parent folder ID. + double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId); + + // Add the parent folder ID to the list of previous parent folders if the item is from a different folder. + if (currentParentFolderId != newParentFolderId) + previousParentFolderIdListPointer->push_back(currentParentFolderId); + + // Update the parent folder and display order for each bookmark. + BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, newParentFolderId, newDisplayOrder); + + // Increment the new display order. + ++newDisplayOrder; + } + + // Update the display order of the existing items in the folder. + for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer) + { + // Set the bookmark's display order if it has changed. + if (bookmarkStruct.displayOrder != newDisplayOrder) + BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder); + + // Increment the new display order. + ++newDisplayOrder; + } +} diff --git a/src/widgets/DraggableTreeView.h b/src/widgets/DraggableTreeView.h index 983ff1c..961d2fa 100644 --- a/src/widgets/DraggableTreeView.h +++ b/src/widgets/DraggableTreeView.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -40,6 +40,9 @@ protected: void dropEvent(QDropEvent *event) override; private: + // The private functions QList* getRootSelectedDatabaseIds(QList *selectedDatabaseIdsPointer) const; + void moveToBeginningOfFolder(const QModelIndex &dropModelIndex, QList *selectedDatabaseIdsListPointer, QList *rootSelectedDatabaseIdsListPointer, + std::list *previousParentFolderIdListPointer) const; }; #endif -- 2.43.0 From 2374794c9a71745376c9d2db0ee403e6b0969d39 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Thu, 11 Jan 2024 17:23:12 -0700 Subject: [PATCH 10/16] Ghost DOM storage in Settings and Domain Settings unless both JavaScript and local storage are enabled. https://redmine.stoutner.com/issues/1080 --- src/dialogs/DomainSettingsDialog.cpp | 90 ++++++++++++++++++++++++++-- src/dialogs/DomainSettingsDialog.h | 1 + src/uis/SettingsPrivacy.ui | 7 ++- src/windows/BrowserWindow.cpp | 14 +++++ 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/src/dialogs/DomainSettingsDialog.cpp b/src/dialogs/DomainSettingsDialog.cpp index 59d7bdb..13791f0 100644 --- a/src/dialogs/DomainSettingsDialog.cpp +++ b/src/dialogs/DomainSettingsDialog.cpp @@ -126,9 +126,6 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString & // Select the first entry in the list view. domainsListViewPointer->setCurrentIndex(domainsTableModelPointer->index(0, domainsTableModelPointer->fieldIndex(DomainsDatabase::DOMAIN_NAME))); - // Populate the domain settings. - domainSelected(domainsSelectionModelPointer->currentIndex()); - break; } @@ -141,13 +138,13 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString & // Move to the new domain. domainsListViewPointer->setCurrentIndex(newDomainIndex[0]); - // Populate the domain settings. - domainSelected(domainsSelectionModelPointer->currentIndex()); - break; } } + // Populate the domain settings. + domainSelected(domainsSelectionModelPointer->currentIndex()); + // Handle clicks on the domains. connect(domainsListViewPointer, SIGNAL(activated(QModelIndex)), this, SLOT(domainSelected(QModelIndex))); @@ -168,6 +165,9 @@ DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString & connect(applyButtonPointer, SIGNAL(clicked()), this, SLOT(apply())); connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(cancel())); + // Update the DOM storage status. + updateDomStorageStatus(); + // Update the UI. updateUi(); } @@ -307,6 +307,9 @@ void DomainSettingsDialog::javaScriptChanged(const int &newIndex) const // Populate the JavaScript label. populateJavaScriptLabel(); + // Update the DOM storage status. + updateDomStorageStatus(); + // Update the UI. updateUi(); } @@ -319,6 +322,9 @@ void DomainSettingsDialog::localStorageChanged(const int &newIndex) const // Populate the local storage label. populateLocalStorageLabel(); + // Update the DOM storage status. + updateDomStorageStatus(); + // Update the UI. updateUi(); } @@ -603,6 +609,78 @@ void DomainSettingsDialog::showDeleteMessageBox() const } } +void DomainSettingsDialog::updateDomStorageStatus() const +{ + // Instantiate tracking variables. + bool javaScriptEnabled; + bool localStorageEnabled; + + // Populate the JavaScript tracker. + switch (javaScriptComboBoxPointer->currentIndex()) + { + case (DomainsDatabase::SYSTEM_DEFAULT): + { + // Update the tracker according to the system default. + if (Settings::javaScriptEnabled()) + javaScriptEnabled = true; + else + javaScriptEnabled = false; + + break; + } + + case (DomainsDatabase::ENABLED): + { + // Update the tracker. + javaScriptEnabled = true; + + break; + } + + case (DomainsDatabase::DISABLED): + { + // Update the tracker. + javaScriptEnabled = false; + + break; + } + } + + // Populate the local storage tracker. + switch (localStorageComboBoxPointer->currentIndex()) + { + case (DomainsDatabase::SYSTEM_DEFAULT): + { + // Update the tracker according to the system default. + if (Settings::localStorageEnabled()) + localStorageEnabled = true; + else + localStorageEnabled = false; + + break; + } + + case (DomainsDatabase::ENABLED): + { + // Update the tracker. + localStorageEnabled = true; + + break; + } + + case (DomainsDatabase::DISABLED): + { + // Update the tracker. + localStorageEnabled = false; + + break; + } + } + + // Only enable DOM storage if both JavaScript and local storage are enabled. + domStorageComboBoxPointer->setEnabled(javaScriptEnabled && localStorageEnabled); +} + void DomainSettingsDialog::updateUi() const { // Update the delete button status. diff --git a/src/dialogs/DomainSettingsDialog.h b/src/dialogs/DomainSettingsDialog.h index 543c1bb..1537016 100644 --- a/src/dialogs/DomainSettingsDialog.h +++ b/src/dialogs/DomainSettingsDialog.h @@ -100,6 +100,7 @@ private: void populateJavaScriptLabel() const; void populateLocalStorageLabel() const; void populateUserAgentLabel(const QString &userAgentName) const; + void updateDomStorageStatus() const; void updateUi() const; }; #endif diff --git a/src/uis/SettingsPrivacy.ui b/src/uis/SettingsPrivacy.ui index 780a239..16c616e 100644 --- a/src/uis/SettingsPrivacy.ui +++ b/src/uis/SettingsPrivacy.ui @@ -1,7 +1,7 @@ + + false + diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 13e3c51..7533432 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -1574,6 +1574,9 @@ void BrowserWindow::showSettingsDialog() 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; @@ -1582,6 +1585,17 @@ void BrowserWindow::showSettingsDialog() 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()); -- 2.43.0 From 5e66d268d985552aeeae3e9ae7d0967d359a557f Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Sat, 13 Jan 2024 14:58:06 -0700 Subject: [PATCH 11/16] Move the Settings Dialog to its own class. https://redmine.stoutner.com/issues/1151 --- src/dialogs/AddBookmarkDialog.cpp | 5 +- src/dialogs/AddBookmarkDialog.h | 4 +- src/dialogs/AddFolderDialog.cpp | 4 +- src/dialogs/AddFolderDialog.h | 4 +- src/dialogs/AddOrEditCookieDialog.cpp | 4 +- src/dialogs/AddOrEditCookieDialog.h | 4 +- src/dialogs/BookmarksDialog.cpp | 18 +- src/dialogs/BookmarksDialog.h | 8 +- src/dialogs/CMakeLists.txt | 3 +- src/dialogs/CookiesDialog.cpp | 14 +- src/dialogs/CookiesDialog.h | 8 +- src/dialogs/DomainSettingsDialog.cpp | 2 +- src/dialogs/DomainSettingsDialog.h | 2 +- src/dialogs/DurableCookiesDialog.cpp | 4 +- src/dialogs/DurableCookiesDialog.h | 4 +- src/dialogs/EditBookmarkDialog.cpp | 4 +- src/dialogs/EditBookmarkDialog.h | 4 +- src/dialogs/EditFolderDialog.cpp | 4 +- src/dialogs/EditFolderDialog.h | 4 +- src/dialogs/SaveDialog.cpp | 6 +- src/dialogs/SaveDialog.h | 4 +- src/dialogs/SettingsDialog.cpp | 231 ++++++++++++++++++++++++ src/dialogs/SettingsDialog.h | 53 ++++++ src/widgets/TabWidget.cpp | 4 +- src/widgets/TabWidget.h | 2 +- src/windows/BrowserWindow.cpp | 244 +++----------------------- src/windows/BrowserWindow.h | 13 +- 27 files changed, 372 insertions(+), 289 deletions(-) create mode 100644 src/dialogs/SettingsDialog.cpp create mode 100644 src/dialogs/SettingsDialog.h diff --git a/src/dialogs/AddBookmarkDialog.cpp b/src/dialogs/AddBookmarkDialog.cpp index 4c91c2c..e35759b 100644 --- a/src/dialogs/AddBookmarkDialog.cpp +++ b/src/dialogs/AddBookmarkDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -30,7 +30,8 @@ #include // Construct the class. -AddBookmarkDialog::AddBookmarkDialog(const QString &bookmarkName, const QString &bookmarkUrl, const QIcon &favoriteIcon, const double parentFolderId) : QDialog(nullptr) +AddBookmarkDialog::AddBookmarkDialog(QWidget *parentWidgetPointer, const QString &bookmarkName, const QString &bookmarkUrl, const QIcon &favoriteIcon, const double parentFolderId) : + QDialog(parentWidgetPointer) { // Set the window title. setWindowTitle(i18nc("The add bookmark dialog window title.", "Add Bookmark")); diff --git a/src/dialogs/AddBookmarkDialog.h b/src/dialogs/AddBookmarkDialog.h index 311f139..7d38628 100644 --- a/src/dialogs/AddBookmarkDialog.h +++ b/src/dialogs/AddBookmarkDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -36,7 +36,7 @@ class AddBookmarkDialog : public QDialog public: // The primary constructor. - explicit AddBookmarkDialog(const QString &bookmarkName, const QString &bookmarkUrl, const QIcon &favoriteIcon, const double parentFolderId); + explicit AddBookmarkDialog(QWidget *parentWidgetPointer, const QString &bookmarkName, const QString &bookmarkUrl, const QIcon &favoriteIcon, const double parentFolderId); signals: // The signals. diff --git a/src/dialogs/AddFolderDialog.cpp b/src/dialogs/AddFolderDialog.cpp index ec41ce3..7462930 100644 --- a/src/dialogs/AddFolderDialog.cpp +++ b/src/dialogs/AddFolderDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -28,7 +28,7 @@ #include // Construct the class. -AddFolderDialog::AddFolderDialog(const QIcon ¤tWebsiteFavoriteIcon, const double parentFolderId) : QDialog(nullptr) +AddFolderDialog::AddFolderDialog(QWidget *parentWidgetPointer, const QIcon ¤tWebsiteFavoriteIcon, const double parentFolderId) : QDialog(parentWidgetPointer) { // Set the window title. setWindowTitle(i18nc("The add folder dialog window title.", "Add Folder")); diff --git a/src/dialogs/AddFolderDialog.h b/src/dialogs/AddFolderDialog.h index 3397b68..e0673a3 100644 --- a/src/dialogs/AddFolderDialog.h +++ b/src/dialogs/AddFolderDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -36,7 +36,7 @@ class AddFolderDialog : public QDialog public: // The primary constructor. - explicit AddFolderDialog(const QIcon ¤tWebsiteFavoriteIcon, const double parentFolderId); + explicit AddFolderDialog(QWidget *parentWidgetPointer, const QIcon ¤tWebsiteFavoriteIcon, const double parentFolderId); signals: // The signals. diff --git a/src/dialogs/AddOrEditCookieDialog.cpp b/src/dialogs/AddOrEditCookieDialog.cpp index eba44b8..bb07c42 100644 --- a/src/dialogs/AddOrEditCookieDialog.cpp +++ b/src/dialogs/AddOrEditCookieDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -34,7 +34,7 @@ const int AddOrEditCookieDialog::AddCookie = 0; const int AddOrEditCookieDialog::EditCookie = 1; // Construct the class. -AddOrEditCookieDialog::AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer, const bool &isDurable) : QDialog(nullptr) +AddOrEditCookieDialog::AddOrEditCookieDialog(QWidget *parentWidgetPointer, const int dialogType, const QNetworkCookie *cookiePointer, const bool isDurable) : QDialog(parentWidgetPointer) { // Set the dialog window title according to the dialog type. if (dialogType == AddCookie) diff --git a/src/dialogs/AddOrEditCookieDialog.h b/src/dialogs/AddOrEditCookieDialog.h index 895b14a..cb641c9 100644 --- a/src/dialogs/AddOrEditCookieDialog.h +++ b/src/dialogs/AddOrEditCookieDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 Soren Stoutner . + * Copyright 2022, 2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -33,7 +33,7 @@ class AddOrEditCookieDialog : public QDialog public: // The primary constructor. - explicit AddOrEditCookieDialog(const int &dialogType, const QNetworkCookie *cookiePointer = nullptr, const bool &isDurable = false); + explicit AddOrEditCookieDialog(QWidget *parentWidgetPointer, const int dialogType, const QNetworkCookie *cookiePointer = nullptr, const bool isDurable = false); // The public static constants. static const int AddCookie; diff --git a/src/dialogs/BookmarksDialog.cpp b/src/dialogs/BookmarksDialog.cpp index 0fa2b4f..683d240 100644 --- a/src/dialogs/BookmarksDialog.cpp +++ b/src/dialogs/BookmarksDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -34,8 +34,8 @@ #include // Construct the class. -BookmarksDialog::BookmarksDialog(QString currentWebsiteTitle, QString currentWebsiteUrl, QIcon currentWebsiteFavorieIcon) : - QDialog(nullptr), websiteFavoriteIcon(currentWebsiteFavorieIcon), websiteTitle(currentWebsiteTitle), websiteUrl(currentWebsiteUrl) +BookmarksDialog::BookmarksDialog(QWidget *parentWidgetPointer, QIcon currentWebsiteFavorieIcon, QString currentWebsiteTitle, QString currentWebsiteUrl) : + QDialog(parentWidgetPointer), websiteFavoriteIcon(currentWebsiteFavorieIcon), websiteTitle(currentWebsiteTitle), websiteUrl(currentWebsiteUrl) { // Set the dialog window title. setWindowTitle(i18nc("The bookmarks dialog window title", "Bookmarks")); @@ -301,7 +301,7 @@ void BookmarksDialog::selectSubfolderContents(const QModelIndex &parentModelInde } } -void BookmarksDialog::showAddBookmarkDialog() const +void BookmarksDialog::showAddBookmarkDialog() { // Return the most recently selected index. QModelIndex currentIndex = treeSelectionModelPointer->currentIndex(); @@ -322,7 +322,7 @@ void BookmarksDialog::showAddBookmarkDialog() const } // Instantiate an add bookmark dialog. - AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(websiteTitle, websiteUrl, websiteFavoriteIcon, parentFolderId); + AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(this, websiteTitle, websiteUrl, websiteFavoriteIcon, parentFolderId); // Update the displayed bookmarks when a new one is added. connect(addBookmarkDialogPointer, SIGNAL(bookmarkAdded()), this, SLOT(refreshBookmarks())); @@ -331,7 +331,7 @@ void BookmarksDialog::showAddBookmarkDialog() const addBookmarkDialogPointer->show(); } -void BookmarksDialog::showAddFolderDialog() const +void BookmarksDialog::showAddFolderDialog() { // Get the most recently selected index. QModelIndex currentIndex = treeSelectionModelPointer->currentIndex(); @@ -352,7 +352,7 @@ void BookmarksDialog::showAddFolderDialog() const } // Instantiate an add folder dialog. - AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(websiteFavoriteIcon, parentFolderId); + AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(this, websiteFavoriteIcon, parentFolderId); // Update the displayed bookmarks when a folder is added. connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(refreshBookmarks())); @@ -370,7 +370,7 @@ void BookmarksDialog::showEditDialog() if (currentIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toInt() == 1) // The selected item is a folder. { // Instantiate an edit folder dialog. - QDialog *editFolderDialogPointer = new EditFolderDialog(currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon); + QDialog *editFolderDialogPointer = new EditFolderDialog(this, currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon); // Show the dialog. editFolderDialogPointer->show(); @@ -381,7 +381,7 @@ void BookmarksDialog::showEditDialog() else // The selected item is a bookmark. { // Instantiate an edit bookmark dialog. - QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon); + QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(this, currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon); // Show the dialog. editBookmarkDialogPointer->show(); diff --git a/src/dialogs/BookmarksDialog.h b/src/dialogs/BookmarksDialog.h index 78a4896..0df0903 100644 --- a/src/dialogs/BookmarksDialog.h +++ b/src/dialogs/BookmarksDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -36,7 +36,7 @@ class BookmarksDialog : public QDialog public: // The primary constructor. - explicit BookmarksDialog(QString currentWebsiteTitle, QString currentWebsiteUrl, QIcon currentWebsiteFavoriteIcon); + BookmarksDialog(QWidget *parentWidgetPointer, QIcon currentWebsiteFavorieIcon, QString currentWebsiteTitle, QString currentWebsiteUrl); // The public constants. static const int NAME_COLUMN = 0; @@ -54,8 +54,8 @@ private Q_SLOTS: // The private slots. void deleteItems() const; void refreshBookmarks() const; - void showAddBookmarkDialog() const; - void showAddFolderDialog() const; + void showAddBookmarkDialog(); + void showAddFolderDialog(); void showEditDialog(); void updateBookmarkFromTree(QStandardItem *modifiedStandardItem); void updateSelection() const; diff --git a/src/dialogs/CMakeLists.txt b/src/dialogs/CMakeLists.txt index 4b72f5c..32ac523 100644 --- a/src/dialogs/CMakeLists.txt +++ b/src/dialogs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2022-2023 Soren Stoutner . +# Copyright 2022-2024 Soren Stoutner . # # This file is part of Privacy Browser PC . # @@ -28,4 +28,5 @@ target_sources(privacybrowser PRIVATE EditBookmarkDialog.cpp EditFolderDialog.cpp SaveDialog.cpp + SettingsDialog.cpp ) diff --git a/src/dialogs/CookiesDialog.cpp b/src/dialogs/CookiesDialog.cpp index 4ca8c1c..57e5ed7 100644 --- a/src/dialogs/CookiesDialog.cpp +++ b/src/dialogs/CookiesDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -594,10 +594,10 @@ void CookiesDialog::deleteCookieFromDialog(const QNetworkCookie &cookie) const emit deleteCookie(cookie); } -void CookiesDialog::showAddCookieDialog() const +void CookiesDialog::showAddCookieDialog() { // Instantiate an add cookie dialog. - QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::AddCookie); + QDialog *addCookieDialogPointer = new AddOrEditCookieDialog(this, AddOrEditCookieDialog::AddCookie); // Show the dialog. addCookieDialogPointer->show(); @@ -744,10 +744,10 @@ void CookiesDialog::showDeleteCookieMessageBox() const } } -void CookiesDialog::showDurableCookiesDialog() const +void CookiesDialog::showDurableCookiesDialog() { // Instantiate a durable cookies dialog. - QDialog *durableCookiesDialogPointer = new DurableCookiesDialog(); + QDialog *durableCookiesDialogPointer = new DurableCookiesDialog(this); // Show the dialog. durableCookiesDialogPointer->show(); @@ -758,7 +758,7 @@ void CookiesDialog::showDurableCookiesDialog() const connect(durableCookiesDialogPointer, SIGNAL(updateParentUi()), this, SLOT(updateUi())); } -void CookiesDialog::showEditCookieDialog() const +void CookiesDialog::showEditCookieDialog() { // Get the current model index. QModelIndex currentIndex = treeSelectionModelPointer->currentIndex(); @@ -783,7 +783,7 @@ void CookiesDialog::showEditCookieDialog() const } // Instantiate an edit cookie dialog. - QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(AddOrEditCookieDialog::EditCookie, &cookieToEdit, currentIndex.siblingAtColumn(1).data().toString() == i18n("yes")); + QDialog *editCookieDialogPointer = new AddOrEditCookieDialog(this, AddOrEditCookieDialog::EditCookie, &cookieToEdit, currentIndex.siblingAtColumn(1).data().toString() == i18n("yes")); // Show the dialog. editCookieDialogPointer->show(); diff --git a/src/dialogs/CookiesDialog.h b/src/dialogs/CookiesDialog.h index be4acda..5319897 100644 --- a/src/dialogs/CookiesDialog.h +++ b/src/dialogs/CookiesDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -50,11 +50,11 @@ private Q_SLOTS: void addCookieFromDialog(const QNetworkCookie &cookie, const bool &isDurable) const; void deleteCookieFromDatabase(const QNetworkCookie &cookie) const; void deleteCookieFromDialog(const QNetworkCookie &cookie) const; - void showAddCookieDialog() const; + void showAddCookieDialog(); void showDeleteAllMessageBox() const; void showDeleteCookieMessageBox() const; - void showDurableCookiesDialog() const; - void showEditCookieDialog() const; + void showDurableCookiesDialog(); + void showEditCookieDialog(); void updateUi() const; private: diff --git a/src/dialogs/DomainSettingsDialog.cpp b/src/dialogs/DomainSettingsDialog.cpp index 13791f0..0907a18 100644 --- a/src/dialogs/DomainSettingsDialog.cpp +++ b/src/dialogs/DomainSettingsDialog.cpp @@ -34,7 +34,7 @@ const int DomainSettingsDialog::SHOW_ALL_DOMAINS = 0; const int DomainSettingsDialog::EDIT_DOMAIN = 1; // Construct the class. -DomainSettingsDialog::DomainSettingsDialog(const int &startType, const QString &domainName) : QDialog(nullptr) +DomainSettingsDialog::DomainSettingsDialog(QWidget *parentWidgetPointer, const int &startType, const QString &domainName) : QDialog(parentWidgetPointer) { // Set the window title. setWindowTitle(i18nc("The domain settings dialog window title", "Domain Settings")); diff --git a/src/dialogs/DomainSettingsDialog.h b/src/dialogs/DomainSettingsDialog.h index 1537016..a78d6e3 100644 --- a/src/dialogs/DomainSettingsDialog.h +++ b/src/dialogs/DomainSettingsDialog.h @@ -39,7 +39,7 @@ class DomainSettingsDialog : public QDialog public: // The primary constructor. - explicit DomainSettingsDialog(const int &startType = SHOW_ALL_DOMAINS, const QString &domainName = QStringLiteral("")); + explicit DomainSettingsDialog(QWidget *parentWidgetPointer, const int &startType = SHOW_ALL_DOMAINS, const QString &domainName = QStringLiteral("")); // The public static int constants. static const int SHOW_ALL_DOMAINS; diff --git a/src/dialogs/DurableCookiesDialog.cpp b/src/dialogs/DurableCookiesDialog.cpp index abc21e9..f076985 100644 --- a/src/dialogs/DurableCookiesDialog.cpp +++ b/src/dialogs/DurableCookiesDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -26,7 +26,7 @@ // KDE Frameworks headers. #include -DurableCookiesDialog::DurableCookiesDialog() : QDialog(nullptr) +DurableCookiesDialog::DurableCookiesDialog(QWidget *parentWidgetPointer) : QDialog(parentWidgetPointer) { // Set the dialog window title. setWindowTitle(i18nc("The durable cookies dialog window title", "Durable Cookies")); diff --git a/src/dialogs/DurableCookiesDialog.h b/src/dialogs/DurableCookiesDialog.h index e611d58..64294f8 100644 --- a/src/dialogs/DurableCookiesDialog.h +++ b/src/dialogs/DurableCookiesDialog.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Soren Stoutner . + * Copyright 2022, 2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -33,7 +33,7 @@ class DurableCookiesDialog : public QDialog public: // The default constructor. - explicit DurableCookiesDialog(); + explicit DurableCookiesDialog(QWidget *parentWidgetPointer); signals: // The signals. diff --git a/src/dialogs/EditBookmarkDialog.cpp b/src/dialogs/EditBookmarkDialog.cpp index a0c0c77..bad010e 100644 --- a/src/dialogs/EditBookmarkDialog.cpp +++ b/src/dialogs/EditBookmarkDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -26,7 +26,7 @@ #include // Construct the class. -EditBookmarkDialog::EditBookmarkDialog(const int databaseId, QIcon ¤tWebsiteFavoriteIcon) : QDialog(nullptr), bookmarkDatabaseId(databaseId) +EditBookmarkDialog::EditBookmarkDialog(QWidget *parentWidgetPointer, const int databaseId, QIcon ¤tWebsiteFavoriteIcon) : QDialog(parentWidgetPointer), bookmarkDatabaseId(databaseId) { // Set the window title. setWindowTitle(i18nc("The edit bookmark dialog window title.", "Edit Bookmark")); diff --git a/src/dialogs/EditBookmarkDialog.h b/src/dialogs/EditBookmarkDialog.h index bbba43e..f862bc0 100644 --- a/src/dialogs/EditBookmarkDialog.h +++ b/src/dialogs/EditBookmarkDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -36,7 +36,7 @@ class EditBookmarkDialog : public QDialog public: // The primary constructor. - explicit EditBookmarkDialog(const int databaseId, QIcon ¤tWebsiteFavoriteIcon); + explicit EditBookmarkDialog(QWidget *parentWidgetPointer, const int databaseId, QIcon ¤tWebsiteFavoriteIcon); signals: // The signals. diff --git a/src/dialogs/EditFolderDialog.cpp b/src/dialogs/EditFolderDialog.cpp index 4285444..950e502 100644 --- a/src/dialogs/EditFolderDialog.cpp +++ b/src/dialogs/EditFolderDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -26,7 +26,7 @@ #include // Construct the class. -EditFolderDialog::EditFolderDialog(const int databaseId, QIcon ¤tWebsiteFavoriteIcon) : QDialog(nullptr), folderDatabaseId(databaseId) +EditFolderDialog::EditFolderDialog(QWidget *parentWidgetPointer, const int databaseId, QIcon ¤tWebsiteFavoriteIcon) : QDialog(parentWidgetPointer), folderDatabaseId(databaseId) { // Set the window title. setWindowTitle(i18nc("The edit folder dialog window title.", "Edit Folder")); diff --git a/src/dialogs/EditFolderDialog.h b/src/dialogs/EditFolderDialog.h index ac203d8..8f38324 100644 --- a/src/dialogs/EditFolderDialog.h +++ b/src/dialogs/EditFolderDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -35,7 +35,7 @@ class EditFolderDialog : public QDialog public: // The primary constructor. - explicit EditFolderDialog(const int databaseId, QIcon ¤tWebsiteFavoriteIcon); + explicit EditFolderDialog(QWidget *parentWidgetPointer, const int databaseId, QIcon ¤tWebsiteFavoriteIcon); signals: // The signals. diff --git a/src/dialogs/SaveDialog.cpp b/src/dialogs/SaveDialog.cpp index 5e96916..dac011c 100644 --- a/src/dialogs/SaveDialog.cpp +++ b/src/dialogs/SaveDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -30,7 +30,8 @@ #include #include -SaveDialog::SaveDialog(QUrl &url, QString &mimeTypeString, int totalBytes, QString fileName, bool nativeDownloader): downloadUrl(url), suggestedFileName(fileName) +SaveDialog::SaveDialog(QWidget *parentWidgetPointer, QUrl &url, QString &mimeTypeString, int totalBytes, QString fileName, bool nativeDownloader) : + QDialog(parentWidgetPointer), downloadUrl(url), suggestedFileName(fileName) { // Set the dialog window title. setWindowTitle(i18nc("The save dialog window title", "Save")); @@ -118,4 +119,3 @@ void SaveDialog::showFilePicker() // Close the dialog. reject(); } - diff --git a/src/dialogs/SaveDialog.h b/src/dialogs/SaveDialog.h index a3ce841..a994d18 100644 --- a/src/dialogs/SaveDialog.h +++ b/src/dialogs/SaveDialog.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 Soren Stoutner . + * Copyright 2022, 2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -32,7 +32,7 @@ class SaveDialog : public QDialog public: // The primary constructor. - explicit SaveDialog(QUrl &url, QString &mimeTypeString, int totalBytes, QString fileName = QString(), bool nativeDownloader = false); + explicit SaveDialog(QWidget *parentWidgetPointer, QUrl &url, QString &mimeTypeString, int totalBytes, QString fileName = QString(), bool nativeDownloader = false); signals: // The signals. diff --git a/src/dialogs/SettingsDialog.cpp b/src/dialogs/SettingsDialog.cpp new file mode 100644 index 0000000..1f3fb79 --- /dev/null +++ b/src/dialogs/SettingsDialog.cpp @@ -0,0 +1,231 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of 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 . + */ + +// 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 +#include + +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(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)); +} diff --git a/src/dialogs/SettingsDialog.h b/src/dialogs/SettingsDialog.h new file mode 100644 index 0000000..bf56e18 --- /dev/null +++ b/src/dialogs/SettingsDialog.h @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of 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 . + */ + +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +// KDE Framework headers. +#include + +// Qt toolkit headers. +#include +#include + +class SettingsDialog : public KConfigDialog +{ + // Include the Q_OBJECT macro. + Q_OBJECT + +public: + // The primary constructor. + explicit SettingsDialog(QWidget *parentWidgetPointer, KCoreConfigSkeleton *coreConfigSkeletonPointer); + +signals: + void spellCheckLanguagesUpdated() const; + +private Q_SLOTS: + void showDownloadDirectoryBrowseDialog(); + void updateSearchEngineLabel(const QString &searchEngineString) const; + void updateUserAgentLabel(const QString &userAgentDatabaseName) const; + +private: + // The private variables. + QComboBox *downloadDirectoryComboBoxPointer; + QLabel *searchEngineLabelPointer; + QLabel *userAgentLabelPointer; +}; +#endif diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index 58ccfc6..bdc541c 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -967,7 +967,7 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin if (!isRunningKde || currentPrivacyWebEngineViewPointer->localStorageEnabled) // KDE is not running or local storage (cookies) is enabled. Use WebEngine's downloader. { // Instantiate the save dialog. - SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes); + SaveDialog *saveDialogPointer = new SaveDialog(this, downloadUrl, mimeTypeString, totalBytes); // Display the save dialog. int saveDialogResult = saveDialogPointer->exec(); @@ -1110,7 +1110,7 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin // This must use the show command to launch a separate dialog which cancels WebEngine's automatic background download of the file to a temporary location. { // Instantiate the save dialog. `true` instructs it to use the native downloader - SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true); + SaveDialog *saveDialogPointer = new SaveDialog(this, downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true); // Connect the save button. connect(saveDialogPointer, SIGNAL(useNativeKdeDownloader(QUrl &, QString &)), this, SLOT(useNativeKdeDownloader(QUrl &, QString &))); diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index 7dbb581..4b06c64 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -52,7 +52,6 @@ public: // The public functions. void applyOnTheFlyZoomFactor(const double zoomFactorDouble) const; - void applySpellCheckLanguages() const; PrivacyWebEngineView* loadBlankInitialWebsite(); void loadInitialWebsite(); void findPrevious(const QString &text) const; @@ -106,6 +105,7 @@ public Q_SLOTS: void applyDomainSettingsAndReload(); void applyOnTheFlySearchEngine(QAction *searchEngineActionPointer); void applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const; + void applySpellCheckLanguages() const; void back() const; void deleteAllCookies() const; void deleteCookieFromStore(const QNetworkCookie &cookie) const; diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 7533432..88f9894 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -20,9 +20,6 @@ // Application headers. #include "BrowserWindow.h" #include "Settings.h" -#include "ui_SettingsGeneral.h" -#include "ui_SettingsPrivacy.h" -#include "ui_SettingsSpellCheck.h" #include "databases/BookmarksDatabase.h" #include "databases/DomainsDatabase.h" #include "dialogs/AddBookmarkDialog.h" @@ -32,6 +29,7 @@ #include "dialogs/DomainSettingsDialog.h" #include "dialogs/EditBookmarkDialog.h" #include "dialogs/EditFolderDialog.h" +#include "dialogs/SettingsDialog.h" #include "helpers/SearchEngineHelper.h" #include "helpers/UserAgentHelper.h" #include "structs/BookmarkStruct.h" @@ -39,6 +37,7 @@ // KDE Frameworks headers. #include #include +#include #include // Qt toolkit headers. @@ -47,8 +46,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -592,7 +592,7 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double QAction *addBookmarkActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("bookmark-new")), i18nc("The add bookmark action", "Add Bookmark"), [=] { // Instantiate an add bookmark dialog. - AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(), + AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(this, tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(), tabWidgetPointer->getCurrentTabFavoritIcon(), folderId); // Update the displayed bookmarks when a new one is added. @@ -607,7 +607,7 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double QAction *addFolderActionPointer = menuPointer->addAction(QIcon::fromTheme(QLatin1String("folder-add")), i18nc("The add folder action", "Add Folder"), [=] { // Instantiate an add folder dialog. - AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(tabWidgetPointer->getCurrentTabFavoritIcon(), folderId); + AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(this, tabWidgetPointer->getCurrentTabFavoritIcon(), folderId); // Update the displayed bookmarks when a folder is added. connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(populateBookmarksInAllWindows())); @@ -678,7 +678,7 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon(); // Instantiate an edit folder dialog. - QDialog *editFolderDialogPointer = new EditFolderDialog(folderDatabaseId, currentTabFavoriteIcon); + QDialog *editFolderDialogPointer = new EditFolderDialog(this, folderDatabaseId, currentTabFavoriteIcon); // Show the dialog. editFolderDialogPointer->show(); @@ -769,7 +769,7 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, deleteFolderActionPointer)); } -void BrowserWindow::addOrEditDomainSettings() const +void BrowserWindow::addOrEditDomainSettings() { // Remove the focus from the URL line edit. urlLineEditPointer->clearFocus(); @@ -813,7 +813,7 @@ void BrowserWindow::addOrEditDomainSettings() const } // Create the domain settings dialog pointer. - DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName); + DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog(this, DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName); // Reload the tabs when domain settings are updated. connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload())); @@ -864,10 +864,10 @@ void BrowserWindow::decrementZoom() updateZoomActions(currentZoomFactorDouble); } -void BrowserWindow::editBookmarks() const +void BrowserWindow::editBookmarks() { // Instantiate an edit bookmarks dialog. - BookmarksDialog *bookmarksDialogPointer = new BookmarksDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(), tabWidgetPointer->getCurrentTabFavoritIcon()); + BookmarksDialog *bookmarksDialogPointer = new BookmarksDialog(this, tabWidgetPointer->getCurrentTabFavoritIcon(), tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl()); // Update the displayed bookmarks when edited. connect(bookmarksDialogPointer, SIGNAL(bookmarkUpdated()), this, SLOT(populateBookmarksInAllWindows())); @@ -1397,7 +1397,7 @@ void BrowserWindow::showBookmarkContextMenu(const QPoint &point) QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon(); // Instantiate an edit bookmark dialog. - QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(databaseId, currentTabFavoriteIcon); + QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(this, databaseId, currentTabFavoriteIcon); // Show the dialog. editBookmarkDialogPointer->show(); @@ -1481,39 +1481,13 @@ void BrowserWindow::showCookiesDialog() 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 +void BrowserWindow::showDomainSettingsDialog() { // Remove the focus from the URL line edit. urlLineEditPointer->clearFocus(); // Instantiate the domain settings dialog. - DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog(); + DomainSettingsDialog *domainSettingsDialogPointer = new DomainSettingsDialog(this); // Reload the tabs when domain settings are updated. connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload())); @@ -1558,186 +1532,28 @@ void BrowserWindow::showProgressBar(const int &progress) const 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. - 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); - } - // 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); + // Instantiate a settings dialog. + SettingsDialog *settingsDialogPointer = new SettingsDialog(this, 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(); + // Show the dialog + settingsDialogPointer->show(); // TODO. KConfigDialog does not respect expanding size policies. - //configDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + //settingsDialogPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //privacySettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //generalSettingsWidgetPointer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - //configDialogPointer->adjustSize(); + //settingsDialogPointer->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(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); + settingsDialogPointer->resize(1000, 500); // Apply the settings handled by KConfig. - connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings())); - connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload())); + connect(settingsDialogPointer, SIGNAL(spellCheckLanguagesUpdated()), tabWidgetPointer, SLOT(applySpellCheckLanguages())); + connect(settingsDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings())); + connect(settingsDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload())); } QSize BrowserWindow::sizeHint() const @@ -2081,12 +1897,6 @@ void BrowserWindow::updateSearchEngineActions(const QString &searchEngine, const } } -void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) const -{ - // Update the search engine label. - searchEngineLabelPointer->setText(SearchEngineHelper::getSearchUrl(searchEngineString)); -} - void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl) { // Get the new URL string in encoded form, which displays punycode. @@ -2265,12 +2075,6 @@ void BrowserWindow::updateUserAgentActions(const QString &userAgent, const bool } } -void BrowserWindow::updateUserAgentLabel(const QString &userAgentDatabaseName) const -{ - // Update the user agent label. - userAgentLabelPointer->setText(UserAgentHelper::getUserAgentFromDatabaseName(userAgentDatabaseName)); -} - void BrowserWindow::updateViewBookmarksToolBarCheckbox(const bool visible) { // Update the view bookmarks toolbar checkbox. diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index eedc250..74e31b8 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -55,11 +55,11 @@ public Q_SLOTS: private Q_SLOTS: // The private slots. - void addOrEditDomainSettings() const; + void addOrEditDomainSettings(); void back() const; void clearUrlLineEditFocus() const; void decrementZoom(); - void editBookmarks() const; + void editBookmarks(); void escape() const; void findNext() const; void findPrevious() const; @@ -77,8 +77,7 @@ private Q_SLOTS: void reloadAndBypassCache() const; void showBookmarkContextMenu(const QPoint &point); void showCookiesDialog(); - void showDownloadDirectoryBrowseDialog() const; - void showDomainSettingsDialog() const; + void showDomainSettingsDialog(); void showFindTextActions() const; void showProgressBar(const int &progress) const; void showSettingsDialog(); @@ -103,9 +102,7 @@ private Q_SLOTS: void updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus); void updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus); void updateZoomActions(const double zoomFactorDouble); - void updateSearchEngineLabel(const QString &searchEngineString) const; void updateUrlLineEdit(const QUrl &newUrl); - void updateUserAgentLabel(const QString &userAgentDatabaseName) const; void updateViewBookmarksToolBarCheckbox(const bool visible); void updateWindowTitle(const QString &title); void zoomDefault(); @@ -123,7 +120,6 @@ private: QList *> bookmarksToolBarSubfolderActionList; bool bookmarksToolBarIsVisible = false; bool bookmarksToolBarUninitialized = true; - KConfigDialog *configDialogPointer; QAction *cookiesActionPointer; QUrl currentUrl; QPushButton *currentZoomButtonPointer; @@ -133,7 +129,6 @@ private: double defaultZoomFactorDouble; QAction *developerToolsActionPointer; QAction *domStorageActionPointer; - QComboBox *downloadDirectoryComboBoxPointer; QList *> finalBookmarkFolderMenuActionList; QAction *findCaseSensitiveActionPointer; QAction *findNextActionPointer; @@ -154,7 +149,6 @@ private: QPalette positiveBackgroundPalette; QProgressBar *progressBarPointer; QAction *refreshActionPointer; - QLabel *searchEngineLabelPointer; QAction *searchEngineMenuActionPointer; QAction *searchEngineMojeekActionPointer; QAction *searchEngineMonoclesActionPointer; @@ -164,7 +158,6 @@ private: QAction *searchEngineYahooActionPointer; QAction *searchEngineCustomActionPointer; QAction *stopActionPointer; - QLabel *userAgentLabelPointer; QAction *userAgentMenuActionPointer; QAction *userAgentPrivacyBrowserActionPointer; QAction *userAgentWebEngineDefaultActionPointer; -- 2.43.0 From cc59ec7b2c1ad4d7832b2c05f7245e8387379e66 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 19 Jan 2024 17:33:20 -0700 Subject: [PATCH 12/16] Disable the current folder in the edit folder dialog. https://redmine.stoutner.com/issues/1092 --- src/dialogs/EditFolderDialog.cpp | 24 +++++++++------- src/dialogs/EditFolderDialog.h | 2 +- src/helpers/FolderHelper.cpp | 47 +++++++++++++++++--------------- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/dialogs/EditFolderDialog.cpp b/src/dialogs/EditFolderDialog.cpp index 950e502..cabcf5d 100644 --- a/src/dialogs/EditFolderDialog.cpp +++ b/src/dialogs/EditFolderDialog.cpp @@ -50,11 +50,11 @@ EditFolderDialog::EditFolderDialog(QWidget *parentWidgetPointer, const int datab QDialogButtonBox *dialogButtonBoxPointer = editFolderDialogUi.dialogButtonBox; saveButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Save); - // Get the bookmark struct. - bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId); + // Get the folder bookmark struct. + folderBookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId); // Set the folder icons. - currentFolderIconRadioButtonPointer->setIcon(bookmarkStructPointer->favoriteIcon); + currentFolderIconRadioButtonPointer->setIcon(folderBookmarkStructPointer->favoriteIcon); currentWebsiteFavoriteIconRadioButtonPointer->setIcon(currentWebsiteFavoriteIcon); // Instantiate a folder helper. @@ -81,17 +81,17 @@ EditFolderDialog::EditFolderDialog(QWidget *parentWidgetPointer, const int datab parentFolderTreeWidgetPointer->addTopLevelItem(bookmarksTreeWidgetItemPointer); // Select the root bookmarks folder if it is the initial parent folder. - if (bookmarkStructPointer->parentFolderId == 0) + if (folderBookmarkStructPointer->parentFolderId == 0) bookmarksTreeWidgetItemPointer->setSelected(true); // Populate the subfolders, except for the one being edited. - folderHelperPointer->populateSubfoldersExcept(databaseId, bookmarksTreeWidgetItemPointer, bookmarkStructPointer->parentFolderId); + folderHelperPointer->populateSubfoldersExcept(databaseId, bookmarksTreeWidgetItemPointer, folderBookmarkStructPointer->parentFolderId); // Open all the folders. parentFolderTreeWidgetPointer->expandAll(); // Populate the line edits. - folderNameLineEditPointer->setText(bookmarkStructPointer->name); + folderNameLineEditPointer->setText(folderBookmarkStructPointer->name); // Focus the folder name line edit. folderNameLineEditPointer->setFocus(); @@ -136,11 +136,14 @@ void EditFolderDialog::save() // Get the parent folder ID. double parentFolderId = selectedFolderPointer->text(folderHelperPointer->FOLDER_ID_COLUMN).toDouble(); + // Determine if it has moved to a new folder. + bool movedToNewFolder = parentFolderId != folderBookmarkStructPointer->parentFolderId; + // Get the original display order. - int displayOrder = bookmarkStructPointer->displayOrder; + int displayOrder = folderBookmarkStructPointer->displayOrder; // Get the new display order if the parent folder has changed. - if (parentFolderId != bookmarkStructPointer->parentFolderId) + if (movedToNewFolder) displayOrder = BookmarksDatabase::getFolderItemCount(parentFolderId); // Create a favorite icon. @@ -167,8 +170,9 @@ void EditFolderDialog::save() // Update the folder. BookmarksDatabase::updateBookmark(updatedBookmarkStructPointer); - // Update the display order of all the items in the previous folder. - BookmarksDatabase::updateFolderContentsDisplayOrder(bookmarkStructPointer->parentFolderId); + // Update the display order of all the items in the previous folder if it has moved to a new folder. + if (movedToNewFolder) + BookmarksDatabase::updateFolderContentsDisplayOrder(folderBookmarkStructPointer->parentFolderId); // Emit the folder saved signal. emit folderSaved(); diff --git a/src/dialogs/EditFolderDialog.h b/src/dialogs/EditFolderDialog.h index 8f38324..d585b15 100644 --- a/src/dialogs/EditFolderDialog.h +++ b/src/dialogs/EditFolderDialog.h @@ -52,10 +52,10 @@ private: FolderHelper *folderHelperPointer; // The private widgets. - BookmarkStruct *bookmarkStructPointer; QRadioButton *currentFolderIconRadioButtonPointer; QRadioButton *currentWebsiteFavoriteIconRadioButtonPointer; QRadioButton *customFolderIconRadioButtonPointer; + BookmarkStruct *folderBookmarkStructPointer; int folderDatabaseId; QLineEdit *folderNameLineEditPointer; QTreeWidget *parentFolderTreeWidgetPointer; diff --git a/src/helpers/FolderHelper.cpp b/src/helpers/FolderHelper.cpp index 01a45da..01e1b22 100644 --- a/src/helpers/FolderHelper.cpp +++ b/src/helpers/FolderHelper.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Soren Stoutner . + * Copyright 2023-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -61,26 +61,29 @@ void FolderHelper::populateSubfoldersExcept(const double exceptSubfolderDatabase // Populate each subfolder. for (BookmarkStruct bookmarkStruct : *subfoldersList) { - // Only populate the subfolder if it is not excepted. - if (bookmarkStruct.databaseId != exceptSubfolderDatabaseId) - { - // Create a tree widget item. - QTreeWidgetItem *subfolderWidgetItemPointer = new QTreeWidgetItem(); - - // Populate the tree widget item. - subfolderWidgetItemPointer->setText(FOLDER_NAME_COLUMN, bookmarkStruct.name); - subfolderWidgetItemPointer->setIcon(FOLDER_NAME_COLUMN, bookmarkStruct.favoriteIcon); - subfolderWidgetItemPointer->setText(FOLDER_ID_COLUMN, QString::number(bookmarkStruct.folderId, 'f', 0)); // Format the folder ID as a floating point with no trailing zeros. - - // Add the subfolder to the tree widget item. - treeWidgetItemPointer->addChild(subfolderWidgetItemPointer); - - // Select the folder if it is the initial parent folder. - if (bookmarkStruct.folderId == initialParentFolderId) - subfolderWidgetItemPointer->setSelected(true); - - // Add any subfolders. - populateSubfoldersExcept(exceptSubfolderDatabaseId, subfolderWidgetItemPointer, initialParentFolderId); - } + // Determine if this is an excepted folder. + bool exceptedFolder = bookmarkStruct.databaseId == exceptSubfolderDatabaseId; + + // Create a tree widget item. + QTreeWidgetItem *subfolderWidgetItemPointer = new QTreeWidgetItem(); + + // Populate the tree widget item. + subfolderWidgetItemPointer->setText(FOLDER_NAME_COLUMN, bookmarkStruct.name); + subfolderWidgetItemPointer->setIcon(FOLDER_NAME_COLUMN, bookmarkStruct.favoriteIcon); + subfolderWidgetItemPointer->setText(FOLDER_ID_COLUMN, QString::number(bookmarkStruct.folderId, 'f', 0)); // Format the folder ID as a floating point with no trailing zeros. + + // Disable the folder widget if it is excepted. All subfolders will automatically be disabled. + if (exceptedFolder) + subfolderWidgetItemPointer->setDisabled(true); + + // Add the subfolder to the tree widget item. + treeWidgetItemPointer->addChild(subfolderWidgetItemPointer); + + // Select the folder if it is the initial parent folder. + if (bookmarkStruct.folderId == initialParentFolderId) + subfolderWidgetItemPointer->setSelected(true); + + // Add any subfolders. + populateSubfoldersExcept(exceptSubfolderDatabaseId, subfolderWidgetItemPointer, initialParentFolderId); } } -- 2.43.0 From f7522adfac888208a7006eb7e67a7173e995ec48 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 21 Feb 2024 11:11:07 -0700 Subject: [PATCH 13/16] Add URL syntax highlighting. https://redmine.stoutner.com/issues/1024 --- src/helpers/UserAgentHelper.cpp | 8 +-- src/widgets/CMakeLists.txt | 3 +- src/widgets/UrlLineEdit.cpp | 108 ++++++++++++++++++++++++++++++++ src/widgets/UrlLineEdit.h | 43 +++++++++++++ src/windows/BrowserWindow.cpp | 2 +- src/windows/BrowserWindow.h | 3 +- 6 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 src/widgets/UrlLineEdit.cpp create mode 100644 src/widgets/UrlLineEdit.h diff --git a/src/helpers/UserAgentHelper.cpp b/src/helpers/UserAgentHelper.cpp index de58905..891702d 100644 --- a/src/helpers/UserAgentHelper.cpp +++ b/src/helpers/UserAgentHelper.cpp @@ -39,10 +39,10 @@ const QString UserAgentHelper::SAFARI_MACOS_DATABASE = QLatin1String("Safari mac // Define the public user agent constants. const QString UserAgentHelper::PRIVACY_BROWSER_USER_AGENT = QLatin1String("PrivacyBrowser/1.0"); const QString UserAgentHelper::FIREFOX_LINUX_USER_AGENT = QLatin1String("Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0"); -const QString UserAgentHelper::CHROMIUM_LINUX_USER_AGENT = QLatin1String("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"); -const QString UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"); -const QString UserAgentHelper::CHROME_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"); -const QString UserAgentHelper::EDGE_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"); +const QString UserAgentHelper::CHROMIUM_LINUX_USER_AGENT = QLatin1String("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"); +const QString UserAgentHelper::FIREFOX_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0"); +const QString UserAgentHelper::CHROME_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"); +const QString UserAgentHelper::EDGE_WINDOWS_USER_AGENT = QLatin1String("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0"); const QString UserAgentHelper::SAFARI_MACOS_USER_AGENT = QLatin1String("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15"); // Construct the class. diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index f161dec..9fe904f 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2022-2023 Soren Stoutner . +# Copyright 2022-2024 Soren Stoutner . # # This file is part of Privacy Browser PC . # @@ -22,4 +22,5 @@ target_sources(privacybrowser PRIVATE DraggableTreeView.cpp PrivacyWebEngineView.cpp TabWidget.cpp + UrlLineEdit.cpp ) diff --git a/src/widgets/UrlLineEdit.cpp b/src/widgets/UrlLineEdit.cpp new file mode 100644 index 0000000..a06cf97 --- /dev/null +++ b/src/widgets/UrlLineEdit.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of 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 . + */ + +// Application headers. +#include "UrlLineEdit.h" + +// Qt toolkit headers. +#include + +// Construct the class. +UrlLineEdit::UrlLineEdit(QWidget *parentWidgetPointer) : KLineEdit(parentWidgetPointer) {} + +void UrlLineEdit::focusInEvent(QFocusEvent *focusEventPointer) +{ + // Create an input method event attribute list. + QList inputMethodEventAttributeList; + + // Create an input method event with no formatting. + QInputMethodEvent inputMethodEvent(QString(QLatin1String("")), inputMethodEventAttributeList); + + // Apply the empty formatting to remove the URL highlighting. + event(&inputMethodEvent); + + // Run the default commands. + KLineEdit::focusInEvent(focusEventPointer); +} + +void UrlLineEdit::focusOutEvent(QFocusEvent *focusEventPointer) +{ + // Reapply the highlight to the current text. + setText(text()); + + // Run the default commands. + KLineEdit::focusOutEvent(focusEventPointer); +} + +void UrlLineEdit::setText(const QString &urlString) +{ + // Wipe the currently displayed text. + KLineEdit::setText(QLatin1String("")); + + // Create an input method event attribute list. + QList inputMethodEventAttributeList; + + // Calculate the URL string length. + int urlStringLength = urlString.length(); + + // Get the index of end of the schema. + int endOfSchemaIndex = urlString.indexOf(QLatin1String("//")) + 2; + + // Get the index of the last `.` in the domain. + int lastDotIndex = urlString.lastIndexOf(QLatin1Char('.')); + + // Get the index of the penultimate `.` in the domain. If this doesn't exist it will be set to `-1`. + int penultimateDotIndex = urlString.lastIndexOf(QLatin1Char('.'), lastDotIndex - urlStringLength - 1); + + // Get the index of the `/` immediately after the domain name. If this doesn't exit it will be set to `-1`. + int endOfDomainNameIndex = urlString.indexOf(QLatin1Char('/'), endOfSchemaIndex); + + // Create the text character formats. + QTextCharFormat grayTextCharFormat; + QTextCharFormat schemaTextCharFormat; + + // Set the text character format colors. + grayTextCharFormat.setForeground(Qt::darkGray); + + // Set the schema text character format color. + if (urlString.startsWith(QLatin1String("http://")) || urlString.startsWith(QLatin1String("view-source:http://"))) + schemaTextCharFormat.setForeground(Qt::red); + else + schemaTextCharFormat = grayTextCharFormat; + + // Append the schema text format format. + inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, endOfSchemaIndex, schemaTextCharFormat)); + + // Append the subdomain format if the subdomain exists. If it doesn't, the penultimate dot index will be `-1`. + if (penultimateDotIndex > 0) + inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, endOfSchemaIndex, penultimateDotIndex + 1 - endOfSchemaIndex, grayTextCharFormat)); + + // Append the post domain formatting if text exists after the domain name. If it doesn't, the end of domain name index will be `-1`. + if (endOfDomainNameIndex > 0) + inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, endOfDomainNameIndex, urlStringLength - endOfDomainNameIndex, grayTextCharFormat)); + + // Create an input method event with an empty pre-edit string. + QInputMethodEvent inputMethodEvent(QString(""), inputMethodEventAttributeList); + + // Apply the URL highlighting. + event(&inputMethodEvent); + + // Run the default commands. + KLineEdit::setText(urlString); +} diff --git a/src/widgets/UrlLineEdit.h b/src/widgets/UrlLineEdit.h new file mode 100644 index 0000000..f57232a --- /dev/null +++ b/src/widgets/UrlLineEdit.h @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of 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 . + */ + +#ifndef URLLINEEDIT_H +#define URLLINEEDIT_H + +// KDE Framework headers. +#include + +class UrlLineEdit : public KLineEdit +{ + // Include the Q_OBJECT macro. + Q_OBJECT + +public: + // The default constructor. + explicit UrlLineEdit(QWidget *parentWidgetPointer = nullptr); + + // The public functions. + void setText(const QString &urlString) override; + +protected: + // The protected functions. + void focusInEvent(QFocusEvent *focusEventPointer) override; + void focusOutEvent(QFocusEvent *focusEventPointer) override; +}; +#endif diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index 88f9894..f0cd4df 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -398,7 +398,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) connect(bookmarksToolBarPointer, SIGNAL(visibilityChanged(bool)), this, SLOT(updateViewBookmarksToolBarCheckbox(bool))); // Create the line edits. - urlLineEditPointer = new KLineEdit(); + urlLineEditPointer = new UrlLineEdit(); findTextLineEditPointer = new KLineEdit(); // Get the line edit size policies. diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index 74e31b8..29c8d60 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -22,6 +22,7 @@ // Application headers. #include "widgets/TabWidget.h" +#include "widgets/UrlLineEdit.h" // KDE Frameworks headers. #include @@ -168,7 +169,7 @@ private: QAction *userAgentEdgeWindowsActionPointer; QAction *userAgentSafariMacosActionPointer; QAction *userAgentCustomActionPointer; - KLineEdit *urlLineEditPointer; + UrlLineEdit *urlLineEditPointer; KToolBar *urlToolBarPointer; QAction *viewBookmarksToolBarActionPointer; QAction *viewSourceActionPointer; -- 2.43.0 From 3ea5ede1fd0721bea6813f36388ba6387bdbfcfe Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Mon, 11 Mar 2024 15:03:14 -0700 Subject: [PATCH 14/16] Handle HTTP authentication. https://redmine.stoutner.com/issues/898 --- src/CMakeLists.txt | 3 +- src/dialogs/AddBookmarkDialog.cpp | 2 +- src/dialogs/CMakeLists.txt | 1 + src/dialogs/HttpAuthenticationDialog.cpp | 91 +++++++++++++++++ src/dialogs/HttpAuthenticationDialog.h | 54 ++++++++++ src/uis/HttpAuthenticationDialog.ui | 119 +++++++++++++++++++++++ src/widgets/PrivacyWebEngineView.cpp | 16 ++- src/widgets/PrivacyWebEngineView.h | 8 +- src/widgets/UrlLineEdit.cpp | 72 +++++++------- 9 files changed, 328 insertions(+), 38 deletions(-) create mode 100644 src/dialogs/HttpAuthenticationDialog.cpp create mode 100644 src/dialogs/HttpAuthenticationDialog.h create mode 100644 src/uis/HttpAuthenticationDialog.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 16bf76c..837e42a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2022-2023 Soren Stoutner . +# Copyright 2022-2024 Soren Stoutner . # # This file is part of Privacy Browser PC . # @@ -45,6 +45,7 @@ ki18n_wrap_ui(privacybrowser uis/DurableCookiesDialog.ui uis/EditBookmarkDialog.ui uis/EditFolderDialog.ui + uis/HttpAuthenticationDialog.ui uis/SaveDialog.ui uis/SettingsGeneral.ui uis/SettingsPrivacy.ui diff --git a/src/dialogs/AddBookmarkDialog.cpp b/src/dialogs/AddBookmarkDialog.cpp index e35759b..041ca3d 100644 --- a/src/dialogs/AddBookmarkDialog.cpp +++ b/src/dialogs/AddBookmarkDialog.cpp @@ -169,7 +169,7 @@ void AddBookmarkDialog::browse() void AddBookmarkDialog::updateUi() { - // Determine if both line edits are populated. + // Update the add button status if (bookmarkNameLineEditPointer->text().isEmpty() || bookmarkUrlLineEditPointer->text().isEmpty()) // At least one of the line edits is empty. { // Disable the add button. diff --git a/src/dialogs/CMakeLists.txt b/src/dialogs/CMakeLists.txt index 32ac523..94b84aa 100644 --- a/src/dialogs/CMakeLists.txt +++ b/src/dialogs/CMakeLists.txt @@ -27,6 +27,7 @@ target_sources(privacybrowser PRIVATE DurableCookiesDialog.cpp EditBookmarkDialog.cpp EditFolderDialog.cpp + HttpAuthenticationDialog.cpp SaveDialog.cpp SettingsDialog.cpp ) diff --git a/src/dialogs/HttpAuthenticationDialog.cpp b/src/dialogs/HttpAuthenticationDialog.cpp new file mode 100644 index 0000000..650ce99 --- /dev/null +++ b/src/dialogs/HttpAuthenticationDialog.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of 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 . + */ + +// Application headers. +#include "HttpAuthenticationDialog.h" +#include "ui_HttpAuthenticationDialog.h" + +// Qt toolkit headers. +#include +#include + +// Construct the class. +HttpAuthenticationDialog::HttpAuthenticationDialog(QWidget *parentWidgetPointer, const QUrl &requestUrl, QAuthenticator *authenticatorPointer) : + QDialog(parentWidgetPointer), authenticatorPointer(authenticatorPointer) +{ + // Set the window title. + setWindowTitle(i18nc("The HTTP authentication dialog window title.", "HTTP Authentication")); + + // Set the window modality. + setWindowModality(Qt::WindowModality::ApplicationModal); + + // Instantiate the HTTP authentication dialog UI. + Ui::HttpAuthenticationDialog httpAuthenticationDialogUi; + + // Setup the UI. + httpAuthenticationDialogUi.setupUi(this); + + // Get handles for the widgets. + QLabel *realmLabelPointer = httpAuthenticationDialogUi.realmLabel; + QLabel *hostLabelPointer = httpAuthenticationDialogUi.hostLabel; + usernameLineEditPointer = httpAuthenticationDialogUi.usernameLineEdit; + passwordLineEditPointer = httpAuthenticationDialogUi.passwordLineEdit; + QDialogButtonBox *dialogButtonBoxPointer = httpAuthenticationDialogUi.dialogButtonBox; + okButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Ok); + + // Display the labels. + realmLabelPointer->setText(authenticatorPointer->realm()); + hostLabelPointer->setText(requestUrl.host()); + + // Connect the buttons. + connect(dialogButtonBoxPointer, SIGNAL(accepted()), this, SLOT(authenticate())); + connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject())); + + // Update the UI when the line edits change. + connect(usernameLineEditPointer, SIGNAL(textEdited(const QString&)), this, SLOT(updateUi())); + connect(passwordLineEditPointer, SIGNAL(passwordChanged(const QString&)), this, SLOT(updateUi())); + + // Initially disable the OK button. + okButtonPointer->setEnabled(false); +} + +void HttpAuthenticationDialog::authenticate() +{ + // Populate the authenticator. + authenticatorPointer->setUser(usernameLineEditPointer->text()); + authenticatorPointer->setPassword(passwordLineEditPointer->password()); + + // Close the dialog. + close(); +} + +void HttpAuthenticationDialog::updateUi() +{ + // Update the OK button status + if (usernameLineEditPointer->text().isEmpty() || passwordLineEditPointer->password().isEmpty()) // At least one of the line edits is empty. + { + // Disable the OK button. + okButtonPointer->setEnabled(false); + } + else // Both of the line edits are populated. + { + // Enable the OK button. + okButtonPointer->setEnabled(true); + } +} diff --git a/src/dialogs/HttpAuthenticationDialog.h b/src/dialogs/HttpAuthenticationDialog.h new file mode 100644 index 0000000..201067d --- /dev/null +++ b/src/dialogs/HttpAuthenticationDialog.h @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of 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 . + */ + +#ifndef HTTPAUTHENTICATIONDIALOG_H +#define HTTPAUTHENTICATIONDIALOG_H + +// KDE framework headers. +#include +#include + +// Qt toolkit headers. +#include +#include + +class HttpAuthenticationDialog : public QDialog +{ + // Include the Q_OBJECT macro. + Q_OBJECT + +public: + // The primary constructor. + explicit HttpAuthenticationDialog(QWidget *parentWidgetPointer, const QUrl &requestUrl, QAuthenticator *authenticatorPointer); + +private Q_SLOTS: + // The private slots. + void authenticate(); + void updateUi(); + +private: + // The private variables. + QAuthenticator *authenticatorPointer; + + // The private widgets. + QPushButton *okButtonPointer; + KPasswordLineEdit *passwordLineEditPointer; + KLineEdit *usernameLineEditPointer; +}; +#endif diff --git a/src/uis/HttpAuthenticationDialog.ui b/src/uis/HttpAuthenticationDialog.ui new file mode 100644 index 0000000..d5d9de0 --- /dev/null +++ b/src/uis/HttpAuthenticationDialog.ui @@ -0,0 +1,119 @@ + + + + + + HttpAuthenticationDialog + + + + + + + + + 24 + true + + + + + Qt::AlignCenter + + + + + + + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + Host: + + + + + + + + + + + + + + + + + Username + + + + + + + + + 300 + 0 + + + + + + + + + + Password + + + + + + + + + + + + + + + Qt::Vertical + + + + + + + + + QDialogButtonBox::Ok | QDialogButtonBox::Cancel + + + + + + diff --git a/src/widgets/PrivacyWebEngineView.cpp b/src/widgets/PrivacyWebEngineView.cpp index 05c7659..6080288 100644 --- a/src/widgets/PrivacyWebEngineView.cpp +++ b/src/widgets/PrivacyWebEngineView.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -20,8 +20,10 @@ // Application headers. #include "PrivacyWebEngineView.h" #include "Settings.h" +#include "ui_HttpAuthenticationDialog.h" #include "databases/CookiesDatabase.h" #include "databases/DomainsDatabase.h" +#include "dialogs/HttpAuthenticationDialog.h" #include "interceptors/UrlRequestInterceptor.h" #include "windows/BrowserWindow.h" @@ -55,6 +57,9 @@ PrivacyWebEngineView::PrivacyWebEngineView(QWidget *parentWidgetPointer) : QWebE // Display HTTP Ping blocked dialogs. connect(urlRequestInterceptorPointer, SIGNAL(displayHttpPingDialog(const QString&)), this, SLOT(displayHttpPingDialog(const QString&))); + + // Handle HTTP authentication requests. + connect(webEnginePagePointer, SIGNAL(authenticationRequired(const QUrl&, QAuthenticator*)), this, SLOT(handleAuthenticationRequest(const QUrl&, QAuthenticator*))); } void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const @@ -298,6 +303,15 @@ void PrivacyWebEngineView::displayHttpPingDialog(const QString &httpPingUrl) con emit displayHttpPingBlockedDialog(httpPingUrl); } +void PrivacyWebEngineView::handleAuthenticationRequest(const QUrl &requestUrl, QAuthenticator *authenticatorPointer) +{ + // Instantiate an HTTP authentication dialog. + HttpAuthenticationDialog *httpAuthenticationDialogPointer = new HttpAuthenticationDialog(parentWidget(), requestUrl, authenticatorPointer); + + // Display the dialog. This must be `exec()` instead of `show()` so that the website doesn't proceed before populating the authentication pointer. + httpAuthenticationDialogPointer->exec(); +} + void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) const { //qDebug() << "Remove cookie: " << cookie.toRawForm(); diff --git a/src/widgets/PrivacyWebEngineView.h b/src/widgets/PrivacyWebEngineView.h index 171ca5e..4f621ce 100644 --- a/src/widgets/PrivacyWebEngineView.h +++ b/src/widgets/PrivacyWebEngineView.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -20,6 +20,9 @@ #ifndef PRIVACYWEBENGINEVIEW_H #define PRIVACYWEBENGINEVIEW_H +// KDE framework headers. +#include + // Qt toolkit headers. #include #include @@ -65,9 +68,12 @@ private Q_SLOTS: // The private slots. void applyDomainSettingsWithoutReloading(const QString &hostname); void displayHttpPingDialog(const QString &httpPingUrl) const; + void handleAuthenticationRequest(const QUrl &requestUrl, QAuthenticator *authenticatorPointer); private: // The private variables. + KLineEdit *passwordLineEditPointer; + KLineEdit *usernameLineEditPointer; QWebEngineProfile *webEngineProfilePointer; QWebEngineSettings *webEngineSettingsPointer; diff --git a/src/widgets/UrlLineEdit.cpp b/src/widgets/UrlLineEdit.cpp index a06cf97..04de23b 100644 --- a/src/widgets/UrlLineEdit.cpp +++ b/src/widgets/UrlLineEdit.cpp @@ -55,53 +55,57 @@ void UrlLineEdit::setText(const QString &urlString) // Wipe the currently displayed text. KLineEdit::setText(QLatin1String("")); - // Create an input method event attribute list. - QList inputMethodEventAttributeList; + // Only highlight the URL if it starts with a known schema. + if (urlString.startsWith(QLatin1String("https://")) || urlString.startsWith(QLatin1String("http://")) || urlString.startsWith(QLatin1String("view-source:"))) + { + // Create an input method event attribute list. + QList inputMethodEventAttributeList; - // Calculate the URL string length. - int urlStringLength = urlString.length(); + // Calculate the URL string length. + int urlStringLength = urlString.length(); - // Get the index of end of the schema. - int endOfSchemaIndex = urlString.indexOf(QLatin1String("//")) + 2; + // Get the index of end of the schema. + int endOfSchemaIndex = urlString.indexOf(QLatin1String("//")) + 2; - // Get the index of the last `.` in the domain. - int lastDotIndex = urlString.lastIndexOf(QLatin1Char('.')); + // Get the index of the `/` immediately after the domain name. If this doesn't exit it will be set to `-1`. + int endOfDomainNameIndex = urlString.indexOf(QLatin1Char('/'), endOfSchemaIndex); - // Get the index of the penultimate `.` in the domain. If this doesn't exist it will be set to `-1`. - int penultimateDotIndex = urlString.lastIndexOf(QLatin1Char('.'), lastDotIndex - urlStringLength - 1); + // Get the index of the last `.` in the domain. + int lastDotIndex = urlString.lastIndexOf(QLatin1Char('.'), endOfDomainNameIndex - urlStringLength); - // Get the index of the `/` immediately after the domain name. If this doesn't exit it will be set to `-1`. - int endOfDomainNameIndex = urlString.indexOf(QLatin1Char('/'), endOfSchemaIndex); + // Get the index of the penultimate `.` in the domain. If this doesn't exist it will be set to `-1`. + int penultimateDotIndex = urlString.lastIndexOf(QLatin1Char('.'), lastDotIndex - urlStringLength - 1); - // Create the text character formats. - QTextCharFormat grayTextCharFormat; - QTextCharFormat schemaTextCharFormat; + // Create the text character formats. + QTextCharFormat grayTextCharFormat; + QTextCharFormat schemaTextCharFormat; - // Set the text character format colors. - grayTextCharFormat.setForeground(Qt::darkGray); + // Set the text character format colors. + grayTextCharFormat.setForeground(Qt::darkGray); - // Set the schema text character format color. - if (urlString.startsWith(QLatin1String("http://")) || urlString.startsWith(QLatin1String("view-source:http://"))) - schemaTextCharFormat.setForeground(Qt::red); - else - schemaTextCharFormat = grayTextCharFormat; + // Set the schema text character format color. + if (urlString.startsWith(QLatin1String("http://")) || urlString.startsWith(QLatin1String("view-source:http://"))) + schemaTextCharFormat.setForeground(Qt::red); + else + schemaTextCharFormat = grayTextCharFormat; - // Append the schema text format format. - inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, endOfSchemaIndex, schemaTextCharFormat)); + // Append the schema text format format. + inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, endOfSchemaIndex, schemaTextCharFormat)); - // Append the subdomain format if the subdomain exists. If it doesn't, the penultimate dot index will be `-1`. - if (penultimateDotIndex > 0) - inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, endOfSchemaIndex, penultimateDotIndex + 1 - endOfSchemaIndex, grayTextCharFormat)); + // Append the subdomain format if the subdomain exists. If it doesn't, the penultimate dot index will be `-1`. + if (penultimateDotIndex > 0) + inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, endOfSchemaIndex, penultimateDotIndex + 1 - endOfSchemaIndex, grayTextCharFormat)); - // Append the post domain formatting if text exists after the domain name. If it doesn't, the end of domain name index will be `-1`. - if (endOfDomainNameIndex > 0) - inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, endOfDomainNameIndex, urlStringLength - endOfDomainNameIndex, grayTextCharFormat)); + // Append the post domain formatting if text exists after the domain name. If it doesn't, the end of domain name index will be `-1`. + if (endOfDomainNameIndex > 0) + inputMethodEventAttributeList.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, endOfDomainNameIndex, urlStringLength - endOfDomainNameIndex, grayTextCharFormat)); - // Create an input method event with an empty pre-edit string. - QInputMethodEvent inputMethodEvent(QString(""), inputMethodEventAttributeList); + // Create an input method event with an empty pre-edit string. + QInputMethodEvent inputMethodEvent(QString(""), inputMethodEventAttributeList); - // Apply the URL highlighting. - event(&inputMethodEvent); + // Apply the URL highlighting. + event(&inputMethodEvent); + } // Run the default commands. KLineEdit::setText(urlString); -- 2.43.0 From ce90749b5fc2c4a3fcee6daee60c0d6e2aa0e1d6 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 22 Mar 2024 13:31:39 -0700 Subject: [PATCH 15/16] Fix HTTP authentication dialogs displaying indefinitely. https://redmine.stoutner.com/issues/1180 --- src/widgets/PrivacyWebEngineView.cpp | 17 +++++++++++++---- src/widgets/PrivacyWebEngineView.h | 1 + src/widgets/TabWidget.cpp | 3 +++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/widgets/PrivacyWebEngineView.cpp b/src/widgets/PrivacyWebEngineView.cpp index 6080288..42c331f 100644 --- a/src/widgets/PrivacyWebEngineView.cpp +++ b/src/widgets/PrivacyWebEngineView.cpp @@ -221,6 +221,9 @@ void PrivacyWebEngineView::applyDomainSettings(const QString &hostname, const bo if (reloadWebsite) reload(); + // Reset the HTTP authentication dialog counter. + httpAuthenticationDialogsDisplayed = 0; + // Update the UI. emit updateUi(this); } @@ -305,11 +308,17 @@ void PrivacyWebEngineView::displayHttpPingDialog(const QString &httpPingUrl) con void PrivacyWebEngineView::handleAuthenticationRequest(const QUrl &requestUrl, QAuthenticator *authenticatorPointer) { - // Instantiate an HTTP authentication dialog. - HttpAuthenticationDialog *httpAuthenticationDialogPointer = new HttpAuthenticationDialog(parentWidget(), requestUrl, authenticatorPointer); + // Only display the HTTP authentication dialog if it hasn't already been displayed three times for this URL. + if (httpAuthenticationDialogsDisplayed < 3) { + // Increment the HTTP authentication dialog display counter. + ++httpAuthenticationDialogsDisplayed; + + // Instantiate an HTTP authentication dialog. + HttpAuthenticationDialog *httpAuthenticationDialogPointer = new HttpAuthenticationDialog(parentWidget(), requestUrl, authenticatorPointer); - // Display the dialog. This must be `exec()` instead of `show()` so that the website doesn't proceed before populating the authentication pointer. - httpAuthenticationDialogPointer->exec(); + // Display the dialog. This must be `exec()` instead of `show()` so that the website doesn't proceed before populating the authentication pointer. + httpAuthenticationDialogPointer->exec(); + } } void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) const diff --git a/src/widgets/PrivacyWebEngineView.h b/src/widgets/PrivacyWebEngineView.h index 4f621ce..95cc69f 100644 --- a/src/widgets/PrivacyWebEngineView.h +++ b/src/widgets/PrivacyWebEngineView.h @@ -46,6 +46,7 @@ public: bool findCaseSensitive = false; QString findString = QLatin1String(""); QWebEngineFindTextResult findTextResult = QWebEngineFindTextResult(); + int httpAuthenticationDialogsDisplayed = 0; bool isLoading = false; int loadProgressInt = -1; bool localStorageEnabled = false; diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index bdc541c..f65c79e 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -906,6 +906,9 @@ void TabWidget::printWebpage(QPrinter *printerPointer) const void TabWidget::refresh() const { + // Reset the HTTP authentication dialog counter. + currentPrivacyWebEngineViewPointer->httpAuthenticationDialogsDisplayed = 0; + // Reload the website. currentPrivacyWebEngineViewPointer->reload(); } -- 2.43.0 From c5706a6ff3fbc42418e60b79fbe3f5c19396f7d2 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Wed, 27 Mar 2024 16:03:36 -0700 Subject: [PATCH 16/16] Add a default folder icon to the edit folder dialog. https://redmine.stoutner.com/issues/1179 --- src/dialogs/EditFolderDialog.cpp | 3 ++ src/dialogs/EditFolderDialog.h | 1 + src/uis/EditFolderDialog.ui | 28 +++++++++++++++--- src/windows/BrowserWindow.cpp | 51 ++++++++++++++++++-------------- src/windows/BrowserWindow.h | 4 +-- 5 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/dialogs/EditFolderDialog.cpp b/src/dialogs/EditFolderDialog.cpp index cabcf5d..bae0965 100644 --- a/src/dialogs/EditFolderDialog.cpp +++ b/src/dialogs/EditFolderDialog.cpp @@ -42,6 +42,7 @@ EditFolderDialog::EditFolderDialog(QWidget *parentWidgetPointer, const int datab // Get handles for the widgets. currentFolderIconRadioButtonPointer = editFolderDialogUi.currentFolderIconRadioButton; + defaultFolderIconRadioButtonPointer = editFolderDialogUi.defaultFolderIconRadioButton; currentWebsiteFavoriteIconRadioButtonPointer = editFolderDialogUi.currentWebsiteFavoriteIconRadioButton; customFolderIconRadioButtonPointer = editFolderDialogUi.customFolderIconRadioButton; parentFolderTreeWidgetPointer = editFolderDialogUi.parentFolderTreeWidget; @@ -152,6 +153,8 @@ void EditFolderDialog::save() // Get the favorite icon. if (currentFolderIconRadioButtonPointer->isChecked()) // The current folder icon is checked. favoriteIcon = currentFolderIconRadioButtonPointer->icon(); + else if (defaultFolderIconRadioButtonPointer->isChecked()) // The default folder icon is checked. + favoriteIcon = defaultFolderIconRadioButtonPointer->icon(); else if (currentWebsiteFavoriteIconRadioButtonPointer->isChecked()) // The current website favorite icon is checked. favoriteIcon = currentWebsiteFavoriteIconRadioButtonPointer->icon(); else // The custom favorite icon is checked. diff --git a/src/dialogs/EditFolderDialog.h b/src/dialogs/EditFolderDialog.h index d585b15..899d5af 100644 --- a/src/dialogs/EditFolderDialog.h +++ b/src/dialogs/EditFolderDialog.h @@ -55,6 +55,7 @@ private: QRadioButton *currentFolderIconRadioButtonPointer; QRadioButton *currentWebsiteFavoriteIconRadioButtonPointer; QRadioButton *customFolderIconRadioButtonPointer; + QRadioButton *defaultFolderIconRadioButtonPointer; BookmarkStruct *folderBookmarkStructPointer; int folderDatabaseId; QLineEdit *folderNameLineEditPointer; diff --git a/src/uis/EditFolderDialog.ui b/src/uis/EditFolderDialog.ui index 545ed3c..efebd2a 100644 --- a/src/uis/EditFolderDialog.ui +++ b/src/uis/EditFolderDialog.ui @@ -1,7 +1,7 @@ + + + + + Default folder icon + + + + + + + + + 32 + 32 + + + + + + @@ -69,7 +89,7 @@ - + diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index f0cd4df..fe3b593 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -543,12 +543,12 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) // Add a separator to the bookmarks menu. bookmarksMenuPointer->addSeparator(); - // Initialize the current bookmarks lists. - finalBookmarkFolderMenuActionList = QList *>(); + // Initialize the bookmark action lists. + bookmarkFolderFinalActionList = QList *>(); bookmarksMenuActionList = QList *>(); bookmarksMenuSubmenuList = QList *>(); bookmarksToolBarActionList = QList(); - bookmarksToolBarSubfolderActionList = QList *>(); + bookmarksToolBarSubfolderActionList = QList *>(); // Set the bookmarks toolbar context menu policy. bookmarksToolBarPointer->setContextMenuPolicy(Qt::CustomContextMenu); @@ -580,7 +580,8 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer) } } -void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double folderId) +// If actions are part of a context menu they do not need to be added to the list as they will be deleted automatically when the context menu closes. +void BrowserWindow::addBookmarkFolderFinalActions(QMenu *menuPointer, const double folderId, const bool addToList) { // Get the database ID. int folderDatabaseId = BookmarksDatabase::getFolderDatabaseId(folderId); @@ -688,8 +689,9 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double } ); - // Add the action to the beginning of the final bookmark folder menu action list. - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, editFolderActionPointer)); + // Add the action to the beginning of the bookmark folder final action list if requsted. + if (addToList) + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, editFolderActionPointer)); } // Add the delete folder action to the menu. @@ -760,13 +762,15 @@ void BrowserWindow::addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double actionCollectionPointer->setDefaultShortcut(addFolderActionPointer, metaFKeySequence); } - // Add the actions to the beginning of the final bookmark folder menu action list. - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, addBookmarkActionPointer)); - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, addFolderActionPointer)); - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, openFolderInNewTabsActionPointer)); - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, openFolderInBackgroundTabsActionPointer)); - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, openFolderInNewWindowActionPointer)); - finalBookmarkFolderMenuActionList.prepend(new QPair(menuPointer, deleteFolderActionPointer)); + // Add the actions to the beginning of the bookmark folder final action list if requested. + if (addToList) { + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, addBookmarkActionPointer)); + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, addFolderActionPointer)); + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, openFolderInNewTabsActionPointer)); + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, openFolderInBackgroundTabsActionPointer)); + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, openFolderInNewWindowActionPointer)); + bookmarkFolderFinalActionList.prepend(new QPair(menuPointer, deleteFolderActionPointer)); + } } void BrowserWindow::addOrEditDomainSettings() @@ -1091,10 +1095,10 @@ void BrowserWindow::populateBookmarksInAllWindows() const void BrowserWindow::populateBookmarksInThisWindow() { // Remove all the final bookmark folder menu actions. - for (QPair *finalBookmarkFolderMenuActionPair : finalBookmarkFolderMenuActionList) + for (QPair *bookmarkFolderFinalActionPairPointer : bookmarkFolderFinalActionList) { // Remove the action. - finalBookmarkFolderMenuActionPair->first->removeAction(finalBookmarkFolderMenuActionPair->second); + bookmarkFolderFinalActionPairPointer->first->removeAction(bookmarkFolderFinalActionPairPointer->second); } // Remove all the current menu bookmarks. @@ -1125,11 +1129,12 @@ void BrowserWindow::populateBookmarksInThisWindow() bookmarksToolBarPointer->removeAction(bookmarkAction); } - // Clear the current bookmark lists. + // Clear the action lists. + bookmarkFolderFinalActionList.clear(); bookmarksMenuActionList.clear(); bookmarksMenuSubmenuList.clear(); - bookmarksToolBarActionList.clear(); bookmarksToolBarSubfolderActionList.clear(); + bookmarksToolBarActionList.clear(); // Populate the bookmarks subfolders, beginning with the root folder (`0`); populateBookmarksMenuSubfolders(0, bookmarksMenuPointer); @@ -1189,8 +1194,8 @@ void BrowserWindow::populateBookmarksMenuSubfolders(const double folderId, QMenu } } - // Add the extra items at the bottom of the menu. - addFinalBookmarkFolderMenuActions(menuPointer, folderId); + // Add the extra items at the bottom of the menu. `true` adds them to the list of actions to be deleted on repopulate. + addBookmarkFolderFinalActions(menuPointer, folderId, true); } void BrowserWindow::populateBookmarksToolBar() @@ -1252,8 +1257,8 @@ void BrowserWindow::populateBookmarksToolBar() // Add the extra items to the toolbar folder menus. The first item in the pair is the menu pointer. The second is the folder ID. for (QPair *menuAndFolderIdPairPointer : bookmarksToolBarMenuList) { - // Populate the final bookmarks menu entries. - addFinalBookmarkFolderMenuActions(menuAndFolderIdPairPointer->first, menuAndFolderIdPairPointer->second); + // Populate the final bookmarks menu entries. `true` adds them to the list of actions to be deleted on repopulate. + addBookmarkFolderFinalActions(menuAndFolderIdPairPointer->first, menuAndFolderIdPairPointer->second, true); } } @@ -1346,8 +1351,8 @@ void BrowserWindow::showBookmarkContextMenu(const QPoint &point) // Create the menu according to the type. if (BookmarksDatabase::isFolder(databaseId)) // A folder was clicked. { - // Populate the final bookmarks menu entries. - addFinalBookmarkFolderMenuActions(bookmarkContextMenuPointer, BookmarksDatabase::getFolderId(databaseId)); + // Populate the final bookmarks menu entries. `false` does not add the actions to the delete list, as they will be automatically deleted when the menu closes. + addBookmarkFolderFinalActions(bookmarkContextMenuPointer, BookmarksDatabase::getFolderId(databaseId), false); } else // A bookmark was clicked. { diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index 29c8d60..85af5a2 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -112,6 +112,7 @@ private: // The private variables. KActionCollection *actionCollectionPointer; QAction *bookmarkedActionPointer; + QList *> bookmarkFolderFinalActionList; QList *> bookmarksMenuActionList; QMenu *bookmarksMenuPointer; QList *> bookmarksMenuSubmenuList; @@ -130,7 +131,6 @@ private: double defaultZoomFactorDouble; QAction *developerToolsActionPointer; QAction *domStorageActionPointer; - QList *> finalBookmarkFolderMenuActionList; QAction *findCaseSensitiveActionPointer; QAction *findNextActionPointer; QAction *findPreviousActionPointer; @@ -182,7 +182,7 @@ private: QPushButton *zoomPlusButtonPointer; // The private functions. - void addFinalBookmarkFolderMenuActions(QMenu *menuPointer, double folderId); + void addBookmarkFolderFinalActions(QMenu *menuPointer, const double folderId, const bool addToList); int calculateSettingsInt(const bool settingCurrentlyEnabled, const bool settingEnabledByDefault) const; void populateBookmarksMenuSubfolders(const double folderId, QMenu *menuPointer); void populateBookmarksToolBar(); -- 2.43.0