]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blobdiff - src/widgets/PrivacyWebEngineView.cpp
Make the Request Details dialog scrollable. https://redmine.stoutner.com/issues...
[PrivacyBrowserPC.git] / src / widgets / PrivacyWebEngineView.cpp
index 6080288e4f5b4238404e8e13795e305f2fd9c65e..ac543fadd9aa0f5924ac5ef5123ceb3a63d08d1f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2022-2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
  *
  * Privacy Browser PC is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 // Application headers.
+#include "GlobalVariables.h"
 #include "PrivacyWebEngineView.h"
+#include "PrivacyWebEnginePage.h"
 #include "Settings.h"
 #include "ui_HttpAuthenticationDialog.h"
 #include "databases/CookiesDatabase.h"
 #include "databases/DomainsDatabase.h"
 #include "dialogs/HttpAuthenticationDialog.h"
+#include "helpers/FilterListHelper.h"
 #include "interceptors/UrlRequestInterceptor.h"
 #include "windows/BrowserWindow.h"
 
@@ -38,13 +41,13 @@ PrivacyWebEngineView::PrivacyWebEngineView(QWidget *parentWidgetPointer) : QWebE
     webEngineProfilePointer = new QWebEngineProfile(QLatin1String(""));
 
     // Create a WebEngine page.
-    QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer);
+    PrivacyWebEnginePage *privacyWebEnginePagePointer = new PrivacyWebEnginePage(webEngineProfilePointer);
 
     // Set the WebEngine page.
-    setPage(webEnginePagePointer);
+    setPage(privacyWebEnginePagePointer);
 
     // Get handles for the various aspects of the WebEngine.
-    webEngineSettingsPointer = webEnginePagePointer->settings();
+    webEngineSettingsPointer = privacyWebEnginePagePointer->settings();
 
     // Instantiate the URL request interceptor.
     UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor(this);
@@ -52,14 +55,17 @@ PrivacyWebEngineView::PrivacyWebEngineView(QWidget *parentWidgetPointer) : QWebE
     // Set the URL request interceptor.
     webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
 
-    // Reapply the domain settings when the host changes.
+    // Connect the URL request interceptor signals.
     connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(const QString&)), this, SLOT(applyDomainSettingsWithoutReloading(const QString&)));
-
-    // Display HTTP Ping blocked dialogs.
+    connect(urlRequestInterceptorPointer, SIGNAL(newMainFrameResource()), this, SLOT(clearRequestsList()));
     connect(urlRequestInterceptorPointer, SIGNAL(displayHttpPingDialog(const QString&)), this, SLOT(displayHttpPingDialog(const QString&)));
+    connect(urlRequestInterceptorPointer, SIGNAL(requestProcessed(RequestStruct*)), this, SLOT(storeRequest(RequestStruct*)));
 
     // Handle HTTP authentication requests.
-    connect(webEnginePagePointer, SIGNAL(authenticationRequired(const QUrl&, QAuthenticator*)), this, SLOT(handleAuthenticationRequest(const QUrl&, QAuthenticator*)));
+    connect(privacyWebEnginePagePointer, SIGNAL(authenticationRequired(const QUrl&, QAuthenticator*)), this, SLOT(handleAuthenticationRequest(const QUrl&, QAuthenticator*)));
+
+    // Store the link URL whenever a link is hovered.
+    connect(privacyWebEnginePagePointer, SIGNAL(linkHovered(const QString)), this, SLOT(saveHoveredLink(const QString)));
 }
 
 void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const
@@ -74,7 +80,7 @@ void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const
         CookiesDatabase::updateCookie(cookie);
 
     // Update the cookies action.
-    emit updateCookiesAction(cookieListPointer->size());
+    emit numberOfCookiesChanged(cookieListPointer->size());
 }
 
 void PrivacyWebEngineView::applyDomainSettingsWithoutReloading(const QString &hostname)
@@ -97,89 +103,69 @@ void PrivacyWebEngineView::applyDomainSettings(const QString &hostname, const bo
         // Set the JavaScript status.
         switch (domainQuery.value(DomainsDatabase::JAVASCRIPT).toInt())
         {
-            // Set the default JavaScript status.
-            case (DomainsDatabase::SYSTEM_DEFAULT):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
-
-                break;
-            }
-
-            // Enable JavaScript.
-            case (DomainsDatabase::ENABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
-
-                break;
-            }
-
-            // Disable JavaScript.
-            case (DomainsDatabase::DISABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
-
-                break;
-            }
+            case (DomainsDatabase::SYSTEM_DEFAULT): webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled()); break;
+            case (DomainsDatabase::ENABLED): webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true); break;
+            case (DomainsDatabase::DISABLED): webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false); break;
         }
 
         // Set the local storage status.
         switch (domainQuery.value(DomainsDatabase::LOCAL_STORAGE).toInt())
         {
-            // Set the default local storage status.
-            case (DomainsDatabase::SYSTEM_DEFAULT):
-            {
-                localStorageEnabled = Settings::localStorageEnabled();
-
-                break;
-            }
-
-            // Enable local storage.
-            case (DomainsDatabase::ENABLED):
-            {
-                localStorageEnabled = true;
-
-                break;
-            }
-
-            // Disable local storage.
-            case (DomainsDatabase::DISABLED):
-            {
-                localStorageEnabled = false;
-
-                break;
-            }
+            case (DomainsDatabase::SYSTEM_DEFAULT): localStorageEnabled = Settings::localStorageEnabled(); break;
+            case (DomainsDatabase::ENABLED): localStorageEnabled = true; break;
+            case (DomainsDatabase::DISABLED): localStorageEnabled = false; break;
         }
 
-        // Set the DOM storage status.
+        // Set the DOM storage status.  QWebEngineSettings confusingly calls this local storage.
         switch (domainQuery.value(DomainsDatabase::DOM_STORAGE).toInt())
         {
-            // Set the default DOM storage status.  QWebEngineSettings confusingly calls this local storage.
-            case (DomainsDatabase::SYSTEM_DEFAULT):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
+            case (DomainsDatabase::SYSTEM_DEFAULT): webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled()); break;
+            case (DomainsDatabase::ENABLED): webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); break;
+            case (DomainsDatabase::DISABLED): webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); break;
+        }
 
-                break;
-            }
+        // Set the user agent.
+        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainQuery.value(DomainsDatabase::USER_AGENT).toString()));
 
-            // Enable DOM storage.  QWebEngineSettings confusingly calls this local storage.
-            case (DomainsDatabase::ENABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+        // Set the UltraPrivacy status.
+        switch (domainQuery.value(DomainsDatabase::ULTRAPRIVACY).toInt())
+        {
+            case (DomainsDatabase::SYSTEM_DEFAULT): ultraPrivacyEnabled = Settings::ultraPrivacyEnabled(); break;
+            case (DomainsDatabase::ENABLED): ultraPrivacyEnabled = true; break;
+            case (DomainsDatabase::DISABLED): ultraPrivacyEnabled = false; break;
+        }
 
-                break;
-            }
+        // Set the UltraList status.
+        switch (domainQuery.value(DomainsDatabase::ULTRALIST).toInt())
+        {
+            case (DomainsDatabase::SYSTEM_DEFAULT): ultraListEnabled = Settings::ultraListEnabled(); break;
+            case (DomainsDatabase::ENABLED): ultraListEnabled = true; break;
+            case (DomainsDatabase::DISABLED): ultraListEnabled = false; break;
+        }
 
-            // Disable DOM storage.  QWebEngineSettings confusingly calls this local storage.
-            case (DomainsDatabase::DISABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
+        // Set the EasyPrivacy status.
+        switch (domainQuery.value(DomainsDatabase::EASYPRIVACY).toInt())
+        {
+            case (DomainsDatabase::SYSTEM_DEFAULT): easyPrivacyEnabled = Settings::easyPrivacyEnabled(); break;
+            case (DomainsDatabase::ENABLED): easyPrivacyEnabled = true; break;
+            case (DomainsDatabase::DISABLED): easyPrivacyEnabled = false; break;
+        }
 
-                break;
-            }
+        // Set the EasyList status.
+        switch (domainQuery.value(DomainsDatabase::EASYLIST).toInt())
+        {
+            case (DomainsDatabase::SYSTEM_DEFAULT): easyListEnabled = Settings::easyListEnabled(); break;
+            case (DomainsDatabase::ENABLED): easyListEnabled = true; break;
+            case (DomainsDatabase::DISABLED): easyListEnabled = false; break;
         }
 
-        // Set the user agent.
-        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainQuery.value(DomainsDatabase::USER_AGENT).toString()));
+        // Set the Fanboy's Annoyance List status.
+        switch (domainQuery.value(DomainsDatabase::FANBOYS_ANNOYANCE_LIST).toInt())
+        {
+            case (DomainsDatabase::SYSTEM_DEFAULT): fanboysAnnoyanceListEnabled = Settings::fanboysAnnoyanceListEnabled(); break;
+            case (DomainsDatabase::ENABLED): fanboysAnnoyanceListEnabled = true; break;
+            case (DomainsDatabase::DISABLED): fanboysAnnoyanceListEnabled = false; break;
+        }
 
         // Check if a custom zoom factor is set.
         if (domainQuery.value(DomainsDatabase::ZOOM_FACTOR).toInt())
@@ -210,6 +196,13 @@ void PrivacyWebEngineView::applyDomainSettings(const QString &hostname, const bo
         // Set the user agent.
         webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()));
 
+        // Set the status for each filter list.
+        ultraPrivacyEnabled = Settings::ultraPrivacyEnabled();
+        ultraListEnabled = Settings::ultraListEnabled();
+        easyPrivacyEnabled = Settings::easyPrivacyEnabled();
+        easyListEnabled = Settings::easyListEnabled();
+        fanboysAnnoyanceListEnabled = Settings::fanboysAnnoyanceListEnabled();
+
         // Store the zoom factor.
         defaultZoomFactor = Settings::zoomFactor();
     }
@@ -221,10 +214,30 @@ 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);
 }
 
+void PrivacyWebEngineView::clearRequestsList()
+{
+    // Reset the number of blocked requests.
+    blockedRequestsVector[ULTRAPRIVACY] = 0;
+    blockedRequestsVector[ULTRALIST] = 0;
+    blockedRequestsVector[EASYPRIVACY] = 0;
+    blockedRequestsVector[EASYLIST] = 0;
+    blockedRequestsVector[FANBOYS_ANNOYANCE_LIST] = 0;
+    blockedRequestsVector[TOTAL] = 0;
+
+    // Clear the requests list.
+    requestsListPointer->clear();
+
+    // Update the blocked requests action.
+    emit(requestBlocked(blockedRequestsVector));
+}
+
 void PrivacyWebEngineView::contextMenuEvent(QContextMenuEvent *contextMenuEvent) {
     // Get a handle for the
     QWebEnginePage *webEnginePagePointer = page();
@@ -238,17 +251,50 @@ void PrivacyWebEngineView::contextMenuEvent(QContextMenuEvent *contextMenuEvent)
     // Add the open link in new background tab action if the context menu already contains the open link in new window action.
     if (contextMenuActionsList.contains(webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewWindow)))
     {
-        // Move the open in new tab action to the top of the list.
+        // Move the open in new tab action above the back action.
         contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewTab));
 
-        // Add the open link in background tab action below the open in new tab action.
+        // Add the open link in background tab action above the back action.
         contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewBackgroundTab));
 
-        // Move the open in new window action below the open in background tab action.
+        // Move the open in new window action above the back action.
         contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), webEnginePagePointer->action(QWebEnginePage::OpenLinkInNewWindow));
 
-        // Add a separator below the open in new window action.
+        // Add a separator above the back action.
         contextMenu->insertSeparator(webEnginePagePointer->action(QWebEnginePage::Back));
+
+        if (globalFirefoxInstalled || globalChromiumInstalled)
+        {
+            // Add the open with Firefox action if Firefox is installed.
+            if (globalFirefoxInstalled)
+            {
+                // Create an open with Firefox action.
+                QAction *openWithFirefoxActionPointer = new QAction(QIcon::fromTheme(QLatin1String("firefox-esr")), i18nc("Open with Firefox context menu action", "Open with Firefox"), contextMenu);
+
+                // Add the open with Firefox action above the back action.
+                contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), openWithFirefoxActionPointer);
+
+                // Connect the action.
+                connect(openWithFirefoxActionPointer, SIGNAL(triggered()), this, SLOT(openWithFirefox()));
+            }
+
+            // Add the open with Chromium action if Chromium is installed.
+            if (globalChromiumInstalled)
+            {
+                // Create an open with Chromium action.
+                QAction *openWithChromiumActionPointer = new QAction(QIcon::fromTheme(QLatin1String("chromium")), i18nc("Open with Chromium context menu action", "Open with Chromium"), contextMenu);
+
+                // Add the open with Chromium action above the back action.
+                contextMenu->insertAction(webEnginePagePointer->action(QWebEnginePage::Back), openWithChromiumActionPointer);
+
+                // Connect the action.
+                connect(openWithChromiumActionPointer, SIGNAL(triggered()), this, SLOT(openWithChromium()));
+            }
+
+
+            // Add a separator above the back action.
+            contextMenu->insertSeparator(webEnginePagePointer->action(QWebEnginePage::Back));
+        }
     }
 
     // Display the menu using the location in the context menu event.
@@ -305,11 +351,29 @@ 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();
+    }
+}
+
+void PrivacyWebEngineView::openWithChromium() const
+{
+    // Open the current URL in Chromium
+    QProcess::startDetached("chromium", QStringList(hoveredLinkString));
+}
 
-    // 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::openWithFirefox() const
+{
+    // Open the current URL in Firefox.
+    QProcess::startDetached("firefox-esr", QStringList(hoveredLinkString));
 }
 
 void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) const
@@ -320,5 +384,39 @@ void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) co
     cookieListPointer->remove(cookie);
 
     // Update the cookies action.
-    emit updateCookiesAction(cookieListPointer->size());
+    emit numberOfCookiesChanged(cookieListPointer->size());
+}
+
+void PrivacyWebEngineView::saveHoveredLink(const QString &hoveredLink)
+{
+    // Save the hovered link.
+    hoveredLinkString = hoveredLink;
+}
+
+void PrivacyWebEngineView::storeRequest(RequestStruct *requestStructPointer)
+{
+    // Store the request struct in the list.
+    requestsListPointer->append(requestStructPointer);
+
+    // Track blocked requests.
+    if (requestStructPointer->dispositionInt == FilterListHelper::BLOCKED)
+    {
+        // Update the individual filter list block counters.
+        if (requestStructPointer->filterListTitle == QLatin1String("UltraPrivacy"))
+            ++blockedRequestsVector[ULTRAPRIVACY];
+        else if (requestStructPointer->filterListTitle == QLatin1String("UltraList"))
+            ++blockedRequestsVector[ULTRALIST];
+        else if (requestStructPointer->filterListTitle == QLatin1String("EasyPrivacy"))
+            ++blockedRequestsVector[EASYPRIVACY];
+        else if (requestStructPointer->filterListTitle == QLatin1String("EasyList"))
+            ++blockedRequestsVector[EASYLIST];
+        else if (requestStructPointer->filterListTitle == QLatin1String("Fanboy's Annoyance List"))
+            ++blockedRequestsVector[FANBOYS_ANNOYANCE_LIST];
+
+        // Update the total requests blocked counter.
+        ++blockedRequestsVector[TOTAL];
+
+        // Update the blocked requests action.
+        emit(requestBlocked(blockedRequestsVector));
+    }
 }