]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/commitdiff
Implement tabbed browsing.
authorSoren Stoutner <soren@stoutner.com>
Thu, 14 Jul 2022 22:42:29 +0000 (15:42 -0700)
committerSoren Stoutner <soren@stoutner.com>
Thu, 14 Jul 2022 22:42:29 +0000 (15:42 -0700)
22 files changed:
src/CMakeLists.txt
src/databases/CookiesDatabase.cpp
src/helpers/UserAgentHelper.cpp
src/settings/Settings.kcfg
src/structs/CMakeLists.txt [deleted file]
src/structs/PrivacyWebEngine.cpp [deleted file]
src/structs/PrivacyWebEngine.h [deleted file]
src/uis/AddTabWidget.ui [new file with mode: 0644]
src/uis/BrowserView.ui [deleted file]
src/uis/CookiesDialog.ui
src/uis/SettingsGeneral.ui
src/uis/TabWidget.ui [new file with mode: 0644]
src/views/BrowserView.cpp [deleted file]
src/views/BrowserView.h [deleted file]
src/views/CMakeLists.txt [deleted file]
src/widgets/CMakeLists.txt [new file with mode: 0644]
src/widgets/PrivacyWebEngineView.cpp [new file with mode: 0644]
src/widgets/PrivacyWebEngineView.h [new file with mode: 0644]
src/widgets/TabWidget.cpp [new file with mode: 0644]
src/widgets/TabWidget.h [new file with mode: 0644]
src/windows/BrowserWindow.cpp
src/windows/BrowserWindow.h

index 499230e852b4d80e134a01072e17c90d07a11f71..d80c89d7ca56e3fde102f18fe7c8ab14a0ff5d9a 100644 (file)
@@ -36,13 +36,14 @@ kconfig_add_kcfg_files(privacy-browser settings/Settings.kcfgc)
 # Use KDE Frameworks to handle internationalization of the following UI files.
 ki18n_wrap_ui(privacy-browser
     uis/AddOrEditCookieDialog.ui
-    uis/BrowserView.ui
+    uis/AddTabWidget.ui
     uis/CookiesDialog.ui
     uis/DomainSettingsDialog.ui
     uis/DurableCookiesDialog.ui
     uis/SaveDialog.ui
     uis/SettingsGeneral.ui
     uis/SettingsPrivacy.ui
+    uis/TabWidget.ui
 )
 
 # Link the following libraries.
@@ -72,9 +73,8 @@ add_subdirectory(dialogs)
 add_subdirectory(filters)
 add_subdirectory(helpers)
 add_subdirectory(interceptors)
-add_subdirectory(structs)
 add_subdirectory(ui.rcs)
-add_subdirectory(views)
+add_subdirectory(widgets)
 add_subdirectory(windows)
 
 # Install Privacy Browser using the default KDE arguments.
index 8464c0624a4f728c4532efa33eacb93f2bbda18e..207f45b89795c3ead31d00313cb78654890056c7 100644 (file)
@@ -163,15 +163,15 @@ int CookiesDatabase::cookieCount()
     // Execute the query.
     countCookiesQuery.exec();
 
+    // Move to the last row.
+    countCookiesQuery.last();
+
     // Initialize a number of cookies variable.
     int numberOfCookies = 0;
 
     // Check to see if the query is valid (there is at least one cookie).
     if (countCookiesQuery.isValid())
     {
-        // Move to the last row.
-        countCookiesQuery.last();
-
         // Get the number of rows (which is zero based) and add one to calculate the number of cookies.
         numberOfCookies = countCookiesQuery.at() + 1;
     }
index 634f16b65cd42e08de0d80a7c72bf328b60e4a50..9727c31aa13f5c3e6a1635e4b80374d81edcb259 100644 (file)
@@ -20,7 +20,7 @@
 // Application headers.
 #include "Settings.h"
 #include "UserAgentHelper.h"
-#include "views/BrowserView.h"
+#include "widgets/TabWidget.h"
 
 // KDE Framework headers.
 #include <KLocalizedString>
@@ -92,7 +92,7 @@ int UserAgentHelper::getDomainSettingsUserAgentIndex(const QString &userAgentNam
 QString UserAgentHelper::getUserAgentFromDatabaseName(const QString &userAgentDatabaseName)
 {
     if (userAgentDatabaseName == PRIVACY_BROWSER_DATABASE) return PRIVACY_BROWSER_USER_AGENT;  // Privacy Browser.
-    else if (userAgentDatabaseName == WEB_ENGINE_DEFAULT_DATABASE) return BrowserView::webEngineDefaultUserAgent;  // WebEngine default.
+    else if (userAgentDatabaseName == WEB_ENGINE_DEFAULT_DATABASE) return TabWidget::webEngineDefaultUserAgent;  // WebEngine default.
     else if (userAgentDatabaseName == FIREFOX_LINUX_DATABASE) return FIREFOX_LINUX_USER_AGENT;  // Firefox Linux.
     else if (userAgentDatabaseName == CHROMIUM_LINUX_DATABASE) return CHROMIUM_LINUX_USER_AGENT;  // Chromium Linux.
     else if (userAgentDatabaseName == FIREFOX_WINDOWS_DATABASE) return FIREFOX_WINDOWS_USER_AGENT;  // Firefox Windows.
@@ -105,7 +105,7 @@ QString UserAgentHelper::getUserAgentFromDatabaseName(const QString &userAgentDa
 QString UserAgentHelper::getUserAgentFromTranslatedName(const QString &userAgentTranslatedName)
 {
     if (userAgentTranslatedName == PRIVACY_BROWSER_TRANSLATED) return PRIVACY_BROWSER_USER_AGENT;  // Privacy Browser.
-    else if (userAgentTranslatedName == WEB_ENGINE_DEFAULT_TRANSLATED) return BrowserView::webEngineDefaultUserAgent;  // WebEngine default.
+    else if (userAgentTranslatedName == WEB_ENGINE_DEFAULT_TRANSLATED) return TabWidget::webEngineDefaultUserAgent;  // WebEngine default.
     else if (userAgentTranslatedName == FIREFOX_LINUX_TRANSLATED) return FIREFOX_LINUX_USER_AGENT;  // Firefox on Linux.
     else if (userAgentTranslatedName == CHROMIUM_LINUX_TRANSLATED) return CHROMIUM_LINUX_USER_AGENT;  // Chromium on Linux.
     else if (userAgentTranslatedName == FIREFOX_WINDOWS_TRANSLATED) return FIREFOX_WINDOWS_USER_AGENT;  // Firefox on Windows.
index 80726d2277373fb628e5f700c9632539b2cb4779..04a74ca534d9f62a8de0e50560fed339115ea144 100644 (file)
             <default>System Download Directory</default>
         </entry>
 
+        <entry name="tabsOnTop" type="Bool">
+            <default>true</default>
+        </entry>
+
         <entry name="fullScreenHideMenuBar" type="Bool">
             <default>true</default>
         </entry>
             <default>true</default>
         </entry>
 
+        <entry name="fullScreenHideTabBar" type="Bool">
+            <default>true</default>
+        </entry>
+
         <entry name="fullScreenHideStatusBar" type="Bool">
             <default>true</default>
         </entry>
diff --git a/src/structs/CMakeLists.txt b/src/structs/CMakeLists.txt
deleted file mode 100644 (file)
index 9e6e2cb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
-#
-# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
-#
-# Privacy Browser PC is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Privacy Browser PC is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
-
-
-# List the sources to include in the executable.
-target_sources(privacy-browser PRIVATE
-    PrivacyWebEngine.cpp
-)
diff --git a/src/structs/PrivacyWebEngine.cpp b/src/structs/PrivacyWebEngine.cpp
deleted file mode 100644 (file)
index 411ac93..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
- *
- * Privacy Browser PC is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser PC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Application headers.
-#include "PrivacyWebEngine.h"
-
-// Construct the struct.
-PrivacyWebEngine::PrivacyWebEngine(QWebEngineView *inputWebEngineViewPointer) : webEngineViewPointer(inputWebEngineViewPointer)
-{
-    // Initialize the local storage status.
-    localStorageEnabled = false;
-}
diff --git a/src/structs/PrivacyWebEngine.h b/src/structs/PrivacyWebEngine.h
deleted file mode 100644 (file)
index 2d5035a..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
- *
- * Privacy Browser PC is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser PC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PRIVACYWEBENGINE_H
-#define PRIVACYWEBENGINE_H
-
-// Qt toolkit headers.
-#include <QWebEngineView>
-
-struct PrivacyWebEngine
-{
-public:
-    // The primary constructor.
-    PrivacyWebEngine(QWebEngineView *inputWebEngineViewPointer);
-
-    // The public variables.
-    bool localStorageEnabled;
-    QWebEngineView *webEngineViewPointer;
-};
-#endif
diff --git a/src/uis/AddTabWidget.ui b/src/uis/AddTabWidget.ui
new file mode 100644 (file)
index 0000000..1a7177f
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+
+  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-android>.
+
+  Privacy Browser PC is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Privacy Browser PC is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
+
+<ui version="4.0">
+    <class>AddTabWidget</class>
+
+    <!-- Base widget. -->
+    <widget class="QWidget">
+        <layout class="QHBoxLayout">
+
+
+            <!-- Add tab widget. -->
+            <item>
+                <widget class="QWidget" name="addTabQWidget">
+                    <layout class="QHBoxLayout">
+                        <!-- Set the margins to 0. -->
+                        <property name="topMargin">
+                            <number>5</number>
+                        </property>
+
+                        <property name="bottomMargin">
+                            <number>5</number>
+                        </property>
+
+                        <property name="leftMargin">
+                            <number>5</number>
+                        </property>
+
+                        <property name="rightMargin">
+                            <number>5</number>
+                        </property>
+
+                        <!-- Add tab button. -->
+                        <item>
+                            <widget class="QPushButton" name="addTabButton">
+                                <property name="icon">
+                                    <iconset theme="list-add-symbolic" />
+                                </property>
+                            </widget>
+                        </item>
+                    </layout>
+                </widget>
+            </item>
+        </layout>
+    </widget>
+</ui>
diff --git a/src/uis/BrowserView.ui b/src/uis/BrowserView.ui
deleted file mode 100644 (file)
index 26ba072..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
-
-  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-android>.
-
-  Privacy Browser PC is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  Privacy Browser PC is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
-
-<ui version="4.0">
-    <class>BrowserView</class>
-    <!-- Main widget. -->
-    <widget class="QWidget">
-        <!-- Main layout. -->
-        <layout class="QVBoxLayout">
-            <!-- Set the spacing between items to 0. -->
-            <property name="spacing">
-                <number>0</number>
-            </property>
-
-            <!-- Set the margins to 0. -->
-            <property name="topMargin">
-                <number>0</number>
-            </property>
-
-            <property name="bottomMargin">
-                <number>0</number>
-            </property>
-
-            <property name="leftMargin">
-                <number>0</number>
-            </property>
-
-            <property name="rightMargin">
-                <number>0</number>
-            </property>
-
-            <!-- WebEngine view. -->
-            <item>
-                <widget class="QWebEngineView" name="webEngineView" />
-            </item>
-        </layout>
-    </widget>
-</ui>
index d182c03e28a3622e27c4d0662638f4c932d933f9..bd2c24fce32202929ab759140c3708909162e67e 100644 (file)
@@ -45,7 +45,7 @@
                     <item>
                         <widget class="QPushButton" name="addCookieButton">
                             <property name="text">
-                                <string>&amp;Add cookie</string>
+                                <string>Add cookie</string>
                             </property>
 
                             <property name="icon">
@@ -58,7 +58,7 @@
                     <item>
                         <widget class="QPushButton" name="editCookieButton">
                             <property name="text">
-                                <string>&amp;Edit cookie</string>
+                                <string>Edit cookie</string>
                             </property>
 
                             <property name="icon">
@@ -71,7 +71,7 @@
                     <item>
                         <widget class="QPushButton" name="deleteCookieButton">
                             <property name="text">
-                                <string>&amp;Delete cookie</string>
+                                <string>Delete cookie</string>
                             </property>
 
                             <property name="icon">
@@ -84,7 +84,7 @@
                     <item>
                         <widget class="QPushButton" name="deleteAllCookiesButton">
                             <property name="text">
-                                <string>Delete &amp;all</string>
+                                <string>Delete all</string>
                             </property>
 
                             <property name="icon">
index acd345c4db96547b5776dea827d07c3289f84e85..223ec5b355781170960ff04b55b5221be1e69da4 100644 (file)
                 </layout>
             </item>
 
+            <!-- Tabs on top. -->
+            <item>
+                <widget class="QCheckBox" name="kcfg_tabsOnTop">
+                    <property name="text">
+                        <string>Tabs on top</string>
+                    </property>
+
+                    <property name="toolTip">
+                        <string>Display the tabs at the top of the screen.  The default is enabled.</string>
+                    </property>
+                </widget>
+            </item>
+
             <!-- Full screen browsing. -->
             <item>
                 <widget class="QGroupBox">
                             </widget>
                         </item>
 
+                        <!-- Hide tab bar. -->
+                        <item>
+                            <widget class="QCheckBox" name="kcfg_fullScreenHideTabBar">
+                                <property name="text">
+                                    <string>Hide tab bar</string>
+                                </property>
+
+                                <property name="toolTip">
+                                    <string>Hide the tab bar when browsing full screen.  The default is enabled.</string>
+                                </property>
+                            </widget>
+                        </item>
+
                         <!-- Hide status bar. -->
                         <item>
                             <widget class="QCheckBox" name="kcfg_fullScreenHideStatusBar">
diff --git a/src/uis/TabWidget.ui b/src/uis/TabWidget.ui
new file mode 100644 (file)
index 0000000..375f4d5
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+
+  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-android>.
+
+  Privacy Browser PC is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Privacy Browser PC is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
+
+<ui version="4.0">
+    <class>TabWidget</class>
+
+    <!-- Tab QWidget. -->
+    <widget class="QWidget">
+
+        <!-- Main layout. -->
+        <layout class="QVBoxLayout">
+            <!-- Set the margins to 0. -->
+            <property name="topMargin">
+                <number>0</number>
+            </property>
+
+            <property name="bottomMargin">
+                <number>0</number>
+            </property>
+
+            <property name="leftMargin">
+                <number>0</number>
+            </property>
+
+            <property name="rightMargin">
+                <number>0</number>
+            </property>
+
+            <!-- Tab widget. -->
+            <item>
+                <widget class="QTabWidget" name="tabWidget" >
+                    <property name="iconSize">
+                        <size>
+                            <width>24</width>
+                            <height>24</height>
+                        </size>
+                    </property>
+
+                    <property name="documentMode">
+                        <bool>true</bool>
+                    </property>
+
+                    <property name="tabsClosable">
+                        <bool>true</bool>
+                    </property>
+
+                    <property name="movable">
+                        <bool>true</bool>
+                    </property>
+
+                    <property name="elideMode">
+                        <enum>Qt::ElideRight</enum>
+                    </property>
+                </widget>
+            </item>
+        </layout>
+    </widget>
+</ui>
diff --git a/src/views/BrowserView.cpp b/src/views/BrowserView.cpp
deleted file mode 100644 (file)
index f17a237..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
- *
- * Privacy Browser PC is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser PC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Application headers.
-#include "BrowserView.h"
-#include "Settings.h"
-#include "ui_BrowserView.h"
-#include "databases/CookiesDatabase.h"
-#include "databases/DomainsDatabase.h"
-#include "dialogs/SaveDialog.h"
-#include "filters/MouseEventFilter.h"
-#include "helpers/SearchEngineHelper.h"
-#include "helpers/UserAgentHelper.h"
-#include "interceptors/UrlRequestInterceptor.h"
-#include "windows/BrowserWindow.h"
-
-// KDE Framework headers.
-#include <KIO/FileCopyJob>
-#include <KIO/JobUiDelegate>
-
-// Qt toolkit headers.
-#include <QAction>
-#include <QFileDialog>
-#include <QPrintDialog>
-#include <QPrintPreviewDialog>
-#include <QPrinter>
-
-// Initialize the public static variables.
-QString BrowserView::webEngineDefaultUserAgent = QStringLiteral("");
-
-// Construct the class.
-BrowserView::BrowserView(QWidget *parent) : QWidget(parent)
-{
-    // Initialize the variables.
-    privacyWebEngineListPointer = new QList<PrivacyWebEngine*>;
-
-    // Instantiate the browser view UI.
-    Ui::BrowserView browserViewUi;
-
-    // Setup the UI.
-    browserViewUi.setupUi(this);
-
-    // Get handles for the views.
-    webEngineViewPointer = browserViewUi.webEngineView;
-
-    // Create an off-the-record profile (the default when no profile name is specified).
-    webEngineProfilePointer = new QWebEngineProfile(QStringLiteral(""));
-
-    // Create a WebEngine page.
-    webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer);
-
-    // Set the WebEngine page.
-    webEngineViewPointer->setPage(webEnginePagePointer);
-
-    // Handle full screen requests.
-    connect(webEnginePagePointer, SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest)));
-
-    // Get handles for the aspects of the WebEngine.
-    webEngineHistoryPointer = webEnginePagePointer->history();
-    webEngineSettingsPointer = webEngineViewPointer->settings();
-    webEngineCookieStorePointer = webEngineProfilePointer->cookieStore();
-
-    // Initialize the current privacy web engine pointer.
-    currentPrivacyWebEnginePointer = new PrivacyWebEngine(webEngineViewPointer);
-
-    // Populate the privacy web engine list.
-    privacyWebEngineListPointer->append(currentPrivacyWebEnginePointer);
-
-    // Set the local storage filter.
-    webEngineCookieStorePointer->setCookieFilter([this](const QWebEngineCookieStore::FilterRequest &filterRequest)
-    {
-        //qDebug().noquote().nospace() << "Page URL:  " << filterRequest.firstPartyUrl << ", Local storage URL:  " << filterRequest.origin << ",  Is third-party:  " << filterRequest.thirdParty;
-
-        // Block all third party local storage requests, including the sneaky ones that don't register a first party URL.
-        if (filterRequest.thirdParty || (filterRequest.firstPartyUrl == QStringLiteral("")))
-        {
-            //qDebug() << "Request blocked.";
-
-            // Return false.
-            return false;
-        }
-
-        /*  TODO.  Waiting for a solution to <https://redmine.stoutner.com/issues/857>.
-        // Check each tab to see if this local storage request should be allowed.
-        for (PrivacyWebEngine *privacyWebEnginePointer : *privacyWebEngineListPointer)
-        {
-            //qDebug().noquote().nospace() << "Local storage:  " << privacyWebEnginePointer->localStorageEnabled << ".  WebEngine URL:  " << webEngineViewPointer->url().host() << ".  Request Host:  " << filterRequest.firstPartyUrl.host();
-
-            // Allow this local storage request if it comes from a tab with local storage enabled.
-            if (privacyWebEnginePointer->localStorageEnabled && (webEngineViewPointer->url().host() == filterRequest.firstPartyUrl.host()))
-            {
-                //qDebug() << "Request allowed.";
-
-                // Return true.
-                return true;
-            }
-        }
-        */
-
-        // Allow the request if it is first party and local storage is enabled.
-        if (!filterRequest.thirdParty && currentPrivacyWebEnginePointer->localStorageEnabled)
-        {
-            // Return true.
-            return true;
-        }
-
-        //qDebug() << "Request blocked.";
-
-        // Block any remaining local storage requests.
-        return false;
-    });
-
-    // Process cookie changes.
-    connect(webEngineCookieStorePointer, SIGNAL(cookieAdded(QNetworkCookie)), this, SLOT(cookieAdded(QNetworkCookie)));
-    connect(webEngineCookieStorePointer, SIGNAL(cookieRemoved(QNetworkCookie)), this, SLOT(cookieRemoved(QNetworkCookie)));
-
-    // Get a list of durable cookies.
-    QList<QNetworkCookie*> *durableCookiesListPointer = CookiesDatabase::getCookies();
-
-    // Add the durable cookies to the store.
-    for (QNetworkCookie *cookiePointer : *durableCookiesListPointer)
-        addCookieToStore(*cookiePointer);
-
-    // Store a copy of the WebEngine default user agent.
-    webEngineDefaultUserAgent = webEngineProfilePointer->httpUserAgent();
-
-    // Update the URL line edit when the URL changes.
-    connect(webEngineViewPointer, SIGNAL(urlChanged(const QUrl)), this, SLOT(updateUrl(const QUrl)));
-
-    // Update the progress bar.
-    connect(webEngineViewPointer, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
-    connect(webEngineViewPointer, SIGNAL(loadProgress(const int)), this, SLOT(loadProgress(const int)));
-    connect(webEngineViewPointer, SIGNAL(loadFinished(const bool)), this, SLOT(loadFinished()));
-
-    // Instantiate the mouse event filter pointer.
-    MouseEventFilter *mouseEventFilterPointer = new MouseEventFilter();
-
-    // Install the mouse event filter.
-    qApp->installEventFilter(mouseEventFilterPointer);
-
-    // Process mouse forward and back commands.
-    connect(mouseEventFilterPointer, SIGNAL(mouseBack()), this, SLOT(mouseBack()));
-    connect(mouseEventFilterPointer, SIGNAL(mouseForward()), this, SLOT(mouseForward()));
-
-    // Listen for hovered link URLs.
-    connect(webEnginePagePointer, SIGNAL(linkHovered(const QString)), this, SLOT(pageLinkHovered(const QString)));
-
-    // Instantiate the URL request interceptor.
-    UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor();
-
-    // Set the URL request interceptor.
-    webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
-
-    // Handle file downloads.
-    connect(webEngineProfilePointer, SIGNAL(downloadRequested(QWebEngineDownloadItem *)), this, SLOT(showSaveDialog(QWebEngineDownloadItem *)));
-
-    // Reapply the domain settings when the host changes.
-    connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(QString)), this, SLOT(applyDomainSettingsWithoutReloading(QString)));
-
-    // Don't allow JavaScript to open windows.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
-
-    // Allow keyboard navigation.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, true);
-
-    // Enable full screen support.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
-
-    // Require user interaction to play media.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, true);
-
-    // Limit WebRTC to public IP addresses.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, true);
-
-    // Set the focus on the WebEngine view.
-    webEngineViewPointer->setFocus();
-}
-
-BrowserView::~BrowserView()
-{
-    // Delay the deletion of the WebEngine page to prevent the following error:  `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
-    webEnginePagePointer->deleteLater();
-}
-
-// The cookie is copied instead of referenced so that changes made to the cookie do not create a race condition with the display of the cookie in the dialog.
-void BrowserView::addCookieToStore(QNetworkCookie cookie) const
-{
-    // Create a url.
-    QUrl url;
-
-    // Check to see if the domain does not start with a `.` because Qt makes this harder than it should be.  <https://doc.qt.io/qt-5/qwebenginecookiestore.html#setCookie>
-    if (!cookie.domain().startsWith(QStringLiteral(".")))
-    {
-        // Populate the URL.
-        url.setHost(cookie.domain());
-        url.setScheme(QStringLiteral("https"));
-
-        // Clear the domain from the cookie.
-        cookie.setDomain(QStringLiteral(""));
-    }
-
-    // Add the cookie to the store.
-    webEngineCookieStorePointer->setCookie(cookie, url);
-}
-
-void BrowserView::applyApplicationSettings()
-{
-    // Set the search engine URL.
-    searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
-
-    // Emit the update search engine actions signal.
-    emit updateSearchEngineActions(Settings::searchEngine(), true);
-}
-
-// This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
-// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
-void BrowserView::applyDomainSettingsAndReload()
-{
-    // Apply the domain settings.  `true` reloads the website.
-    applyDomainSettings(webEngineViewPointer->url().host(), true);
-}
-
-// This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
-// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
-void BrowserView::applyDomainSettingsWithoutReloading(const QString &hostname)
-{
-    // Apply the domain settings  `false` does not reload the website.
-    applyDomainSettings(hostname, false);
-}
-
-// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
-void BrowserView::applyDomainSettings(const QString &hostname, const bool reloadWebsite)
-{
-    // Get the record for the hostname.
-    QSqlQuery domainQuery = DomainsDatabase::getDomainQuery(hostname);
-
-    // Check if the hostname has domain settings.
-    if (domainQuery.isValid())  // The hostname has domain settings.
-    {
-        // Get the domain record.
-        QSqlRecord domainRecord = domainQuery.record();
-
-        // Set the JavaScript status.
-        switch (domainRecord.field(DomainsDatabase::JAVASCRIPT).value().toInt())
-        {
-            // Set the default JavaScript status.
-            case (DomainsDatabase::SYSTEM_DEFAULT):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
-
-                break;
-            }
-
-            // Disable JavaScript.
-            case (DomainsDatabase::DISABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
-
-                break;
-            }
-
-            // Enable JavaScript.
-            case (DomainsDatabase::ENABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
-
-                break;
-            }
-        }
-
-        // Set the local storage status.
-        switch (domainRecord.field(DomainsDatabase::LOCAL_STORAGE).value().toInt())
-        {
-            // Set the default local storage status.
-            case (DomainsDatabase::SYSTEM_DEFAULT):
-            {
-                currentPrivacyWebEnginePointer->localStorageEnabled = Settings::localStorageEnabled();
-
-                break;
-            }
-
-            // Disable local storage.
-            case (DomainsDatabase::DISABLED):
-            {
-                currentPrivacyWebEnginePointer->localStorageEnabled = false;
-
-                break;
-            }
-
-            // Enable local storage.
-            case (DomainsDatabase::ENABLED):
-            {
-                currentPrivacyWebEnginePointer->localStorageEnabled = true;
-
-                break;
-            }
-        }
-
-        // Set the DOM storage status.
-        switch (domainRecord.field(DomainsDatabase::DOM_STORAGE).value().toInt())
-        {
-            // Set the default DOM storage status.
-            case (DomainsDatabase::SYSTEM_DEFAULT):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
-
-                break;
-            }
-
-            // Disable DOM storage.
-            case (DomainsDatabase::DISABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
-
-                break;
-            }
-
-            // Enable DOM storage.
-            case (DomainsDatabase::ENABLED):
-            {
-                webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
-
-                break;
-            }
-        }
-
-        // Set the user agent.
-        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainRecord.field(DomainsDatabase::USER_AGENT).value().toString()));
-
-        // Check if a custom zoom factor is set.
-        if (domainRecord.field(DomainsDatabase::ZOOM_FACTOR).value().toInt())
-        {
-            // Store the current zoom factor.
-            currentZoomFactor = domainRecord.field(DomainsDatabase::CUSTOM_ZOOM_FACTOR).value().toDouble();
-        }
-        else
-        {
-            // Reset the current zoom factor.
-            currentZoomFactor = Settings::zoomFactor();
-        }
-
-        // Set the zoom factor.    The use of `currentZoomFactor` can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
-        webEngineViewPointer->setZoomFactor(currentZoomFactor);
-
-        // Apply the domain settings palette to the URL line edit.
-        emit updateDomainSettingsIndicator(true, domainRecord.field(DomainsDatabase::DOMAIN_NAME).value().toString());
-    }
-    else  // The hostname does not have domain settings.
-    {
-        // Set the JavaScript status.
-        webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
-
-        // Set the local storage status.
-        currentPrivacyWebEnginePointer->localStorageEnabled = Settings::localStorageEnabled();
-
-        // Set DOM storage.
-        webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
-
-        // Set the user agent.
-        webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()));
-
-        // Store the current zoom factor.  This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
-        currentZoomFactor = Settings::zoomFactor();
-
-        // Set the zoom factor.
-        webEngineViewPointer->setZoomFactor(Settings::zoomFactor());
-
-        // Apply the no domain settings palette to the URL line edit.
-        emit updateDomainSettingsIndicator(false, QStringLiteral(""));
-    }
-
-    // Emit the update actions signals.
-    emit updateJavaScriptAction(webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
-    emit updateLocalStorageAction(currentPrivacyWebEnginePointer->localStorageEnabled);
-    emit updateDomStorageAction(webEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
-    emit updateUserAgentActions(webEngineProfilePointer->httpUserAgent(), true);
-    emit updateZoomFactorAction(webEngineViewPointer->zoomFactor());
-
-    // Reload the website if requested.
-    if (reloadWebsite)
-        webEngineViewPointer->reload();
-}
-
-void BrowserView::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
-{
-    // Store the search engine name.
-    QString searchEngineName = searchEngineActionPointer->text();
-
-    // Strip out any `&` characters.
-    searchEngineName.remove('&');
-
-    // Store the search engine string.
-    searchEngineUrl = SearchEngineHelper::getSearchUrl(searchEngineName);
-
-    // Update the search engine actionas.
-    emit updateSearchEngineActions(searchEngineName, false);
-}
-
-void BrowserView::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const
-{
-    // Get the user agent name.
-    QString userAgentName = userAgentActionPointer->text();
-
-    // Strip out any `&` characters.
-    userAgentName.remove('&');
-
-    // Apply the user agent.
-    webEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromTranslatedName(userAgentName));
-
-    // Update the user agent actions.
-    emit updateUserAgentActions(webEngineProfilePointer->httpUserAgent(), false);
-
-    // Reload the website.
-    webEngineViewPointer->reload();
-}
-
-// This can be const once <https://redmine.stoutner.com/issues/799> has been resolved.
-void BrowserView::applyOnTheFlyZoomFactor(const double &zoomFactor)
-{
-    // Update the current zoom factor.  This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
-    currentZoomFactor = zoomFactor;
-
-    // Set the zoom factor.
-    webEngineViewPointer->setZoomFactor(zoomFactor);
-}
-
-void BrowserView::back() const
-{
-    // Go back.
-    webEngineViewPointer->back();
-}
-
-void BrowserView::cookieAdded(const QNetworkCookie &cookie) const
-{
-    // Add the cookie to the cookie list.
-    emit addCookie(cookie);
-}
-
-void BrowserView::cookieRemoved(const QNetworkCookie &cookie) const
-{
-    // Remove the cookie from the cookie list.
-    emit removeCookie(cookie);
-}
-
-void BrowserView::deleteAllCookies() const
-{
-    // Delete all the cookies.
-    webEngineCookieStorePointer->deleteAllCookies();
-}
-
-void BrowserView::deleteCookieFromStore(const QNetworkCookie &cookie) const
-{
-    // Delete the cookie.
-    webEngineCookieStorePointer->deleteCookie(cookie);
-}
-
-void BrowserView::forward() const
-{
-    // Go forward.
-    webEngineViewPointer->forward();
-}
-
-void BrowserView::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const
-{
-    // Make it so.
-    emit fullScreenRequested(fullScreenRequest.toggleOn());
-
-    // Accept the request.
-    fullScreenRequest.accept();
-}
-
-void BrowserView::home() const
-{
-    // Load the homepage.
-    webEngineViewPointer->load(QUrl::fromUserInput(Settings::homepage()));
-}
-
-void BrowserView::loadFinished() const
-{
-    // Hide the progress bar.
-    emit hideProgressBar();
-}
-
-void BrowserView::loadInitialWebsite()
-{
-    // Apply the application settings.
-    applyApplicationSettings();
-
-    // Get the arguments.
-    QStringList argumentsStringList = qApp->arguments();
-
-    // Check to see if the arguments lists contains a URL.
-    if (argumentsStringList.size() > 1)
-    {
-        // Load the URL from the arguments list.
-        webEngineViewPointer->load(QUrl::fromUserInput(argumentsStringList.at(1)));
-    }
-    else
-    {
-        // Load the homepage.
-        home();
-    }
-}
-
-void BrowserView::loadProgress(const int &progress) const
-{
-    // Show the progress bar.
-    emit showProgressBar(progress);
-}
-
-void BrowserView::loadStarted() const
-{
-    // Show the progress bar.
-    emit showProgressBar(0);
-}
-
-void BrowserView::loadUrlFromLineEdit(QString url) const
-{
-    // Decide if the text is more likely to be a URL or a search.
-    if (url.startsWith("file://"))  // The text is likely a file URL.
-    {
-        // Load the URL.
-        webEngineViewPointer->load(QUrl::fromUserInput(url));
-    }
-    else if (url.contains("."))  // The text is likely a URL.
-    {
-        // Check if the URL does not start with a valid protocol.
-        if (!url.startsWith("http"))
-        {
-            // Add `https://` to the beginning of the URL.
-            url = "https://" + url;
-        }
-
-        // Load the URL.
-        webEngineViewPointer->load(QUrl::fromUserInput(url));
-    }
-    else  // The text is likely a search.
-    {
-        // Load the search.
-        webEngineViewPointer->load(QUrl::fromUserInput(searchEngineUrl + url));
-    }
-}
-
-void BrowserView::mouseBack() const
-{
-    // Go back if possible.
-    if (webEngineViewPointer->isActiveWindow() && webEngineHistoryPointer->canGoBack())
-    {
-        // Clear the URL line edit focus.
-        emit clearUrlLineEditFocus();
-
-        // Go back.
-        webEngineViewPointer->back();
-    }
-}
-
-void BrowserView::mouseForward() const
-{
-    // Go forward if possible.
-    if (webEngineViewPointer->isActiveWindow() && webEngineHistoryPointer->canGoForward())
-    {
-        // Clear the URL line edit focus.
-        emit clearUrlLineEditFocus();
-
-        // Go forward.
-        webEngineViewPointer->forward();
-    }
-}
-
-void BrowserView::pageLinkHovered(const QString &linkUrl) const
-{
-    // Emit a signal so that the browser window can update the status bar.
-    emit linkHovered(linkUrl);
-}
-
-void BrowserView::print() const
-{
-    // Create a printer.
-    QPrinter printer;
-
-    // Set the resolution to be 300 dpi.
-    printer.setResolution(300);
-
-    // Create a printer dialog.
-    QPrintDialog printDialog(&printer, webEngineViewPointer);
-
-    // Display the dialog and print the page if instructed.
-    if (printDialog.exec() == QDialog::Accepted)
-        printWebpage(&printer);
-}
-
-void BrowserView::printPreview() const
-{
-    // Create a printer.
-    QPrinter printer;
-
-    // Set the resolution to be 300 dpi.
-    printer.setResolution(300);
-
-    // Create a print preview dialog.
-    QPrintPreviewDialog printPreviewDialog(&printer, webEngineViewPointer);
-
-    // Generate the print preview.
-    connect(&printPreviewDialog, SIGNAL(paintRequested(QPrinter *)), this, SLOT(printWebpage(QPrinter *)));
-
-    // Display the dialog.
-    printPreviewDialog.exec();
-}
-
-void BrowserView::printWebpage(QPrinter *printerPointer) const
-{
-    // Create an event loop.  For some reason, the print preview doesn't produce any output unless it is run inside an event loop.
-    QEventLoop eventLoop;
-
-    // Print the webpage, converting the callback above into a `QWebEngineCallback<bool>`.
-    // Printing requires that the printer be a pointer, not a reference, or it will crash with much cursing.
-    webEnginePagePointer->print(printerPointer, [&eventLoop](bool printSuccess)
-    {
-        // Instruct the compiler to ignore the unused parameter.
-        (void) printSuccess;
-
-        // Quit the loop.
-        eventLoop.quit();
-    });
-
-    // Execute the loop.
-    eventLoop.exec();
-}
-
-void BrowserView::refresh() const
-{
-    // Reload the website.
-    webEngineViewPointer->reload();
-}
-
-void BrowserView::showSaveDialog(QWebEngineDownloadItem *downloadItemPointer) const
-{
-    // Instantiate the save dialog.
-    SaveDialog *saveDialogPointer = new SaveDialog(downloadItemPointer);
-
-    // Connect the save button.
-    connect(saveDialogPointer, SIGNAL(showSaveFilePickerDialog(QUrl &, QString &)), this, SLOT(showSaveFilePickerDialog(QUrl &, QString &)));
-
-    // Show the dialog.
-    saveDialogPointer->show();
-}
-
-void BrowserView::showSaveFilePickerDialog(QUrl &downloadUrl, QString &suggestedFileName)
-{
-    // Get the download location.
-    QString downloadDirectory = Settings::downloadLocation();
-
-    // Resolve the system download directory if specified.
-    if (downloadDirectory == QStringLiteral("System Download Directory"))
-        downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
-
-    // Create a save file dialog.
-    QFileDialog *saveFileDialogPointer = new QFileDialog(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory);
-
-    // Tell the dialog to use a save button.
-    saveFileDialogPointer->setAcceptMode(QFileDialog::AcceptSave);
-
-    // Populate the file name from the download item pointer.
-    saveFileDialogPointer->selectFile(suggestedFileName);
-
-    // Prevent interaction with the parent window while the dialog is open.
-    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] () {
-        // Get the save location.  The dialog box should only allow the selecting of one file location.
-        QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0);
-
-        // Create a file copy job.  `-1` creates the file with default permissions.
-        KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite);
-
-        // Set the download job to display any error messages.
-        fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true);
-
-        // Start the download.
-        fileCopyJobPointer->start();
-    };
-
-    // Handle clicks on the save button.
-    connect(saveFileDialogPointer, &QDialog::accepted, this, saveFile);
-
-    // Show the dialog.
-    saveFileDialogPointer->show();
-}
-
-void BrowserView::toggleDomStorage() const
-{
-    // Toggle DOM storage.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, !webEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
-
-    // Update the DOM storage action.
-    emit updateDomStorageAction(webEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
-
-    // Reload the website.
-    webEngineViewPointer->reload();
-}
-
-void BrowserView::toggleJavaScript() const
-{
-    // Toggle JavaScript.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, !webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
-
-    // Update the JavaScript action.
-    emit updateJavaScriptAction(webEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
-
-    // Reload the website.
-    webEngineViewPointer->reload();
-}
-
-void BrowserView::toggleLocalStorage()
-{
-    // Toggle local storeage.
-    currentPrivacyWebEnginePointer->localStorageEnabled = !currentPrivacyWebEnginePointer->localStorageEnabled;
-
-    // Update the local storage action.
-    emit updateLocalStorageAction(currentPrivacyWebEnginePointer->localStorageEnabled);
-
-    // Reload the website.
-    webEngineViewPointer->reload();
-}
-
-void BrowserView::updateUrl(const QUrl &url) const
-{
-    // Update the URL line edit.
-    emit updateUrlLineEdit(url);
-
-    // Update the status of the forward and back buttons.
-    emit updateBackAction(webEngineHistoryPointer->canGoBack());
-    emit updateForwardAction(webEngineHistoryPointer->canGoForward());
-
-    // Reapply the zoom factor.  This is a bug in QWebEngineView that resets the zoom with every load.  <https://redmine.stoutner.com/issues/799>
-    webEngineViewPointer->setZoomFactor(currentZoomFactor);
-}
diff --git a/src/views/BrowserView.h b/src/views/BrowserView.h
deleted file mode 100644 (file)
index 8007aa7..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
- *
- * Privacy Browser PC is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser PC is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BROWSERVIEW_H
-#define BROWSERVIEW_H
-
-// Application headers.
-#include "structs/PrivacyWebEngine.h"
-
-// KDE Framework headers.
-#include <KLineEdit>
-
-// Qt toolkit headers.
-#include <QPushButton>
-#include <QWebEngineFullScreenRequest>
-#include <QWebEngineHistory>
-#include <QWebEngineProfile>
-#include <QWebEngineSettings>
-#include <QWebEngineView>
-
-class BrowserView : public QWidget
-{
-    // Include the Q_OBJECT macro.
-    Q_OBJECT
-
-public:
-    // The primary contructor.
-    explicit BrowserView(QWidget *parent);
-
-    // The destructor.
-    ~BrowserView();
-
-    // The public functions.
-    void applyOnTheFlyZoomFactor(const double &zoomFactor);
-    void loadInitialWebsite();
-    void toggleDomStorage() const;
-    void toggleJavaScript() const;
-    void toggleLocalStorage();
-
-    // The public static variables.
-    static QString webEngineDefaultUserAgent;
-
-signals:
-    // The signals.
-    void addCookie(const QNetworkCookie &cookie) const;
-    void removeCookie(const QNetworkCookie &cookie) const;
-    void clearUrlLineEditFocus() const;
-    void fullScreenRequested(const bool toggleOn) const;
-    void hideProgressBar() const;
-    void linkHovered(const QString &linkUrl) const;
-    void showProgressBar(const int &progress) const;
-    void updateBackAction(const bool &isEnabled) const;
-    void updateDomStorageAction(const bool &isEnabled) const;
-    void updateDomainSettingsIndicator(const bool &status, const QString &domainSettingsDomain) const;
-    void updateForwardAction(const bool &isEnabled) const;
-    void updateJavaScriptAction(const bool &isEnabled) const;
-    void updateLocalStorageAction(const bool &isEnabled) const;
-    void updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus) const;
-    void updateUrlLineEdit(const QUrl &newUrl) const;
-    void updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus) const;
-    void updateZoomFactorAction(const double &zoomFactor) const;
-
-public Q_SLOTS:
-    // The public slots.
-    void addCookieToStore(QNetworkCookie cookie) const;
-    void applyApplicationSettings();
-    void applyDomainSettingsAndReload();
-    void applyDomainSettingsWithoutReloading(const QString &hostname);
-    void applyOnTheFlySearchEngine(QAction *searchEngineActionPointer);
-    void applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const;
-    void back() const;
-    void deleteAllCookies() const;
-    void deleteCookieFromStore(const QNetworkCookie &cookie) const;
-    void forward() const;
-    void home() const;
-    void loadUrlFromLineEdit(QString url) const;
-    void mouseBack() const;
-    void mouseForward() const;
-    void print() const;
-    void printPreview() const;
-    void refresh() const;
-
-private Q_SLOTS:
-    // The private slots.
-    void cookieAdded(const QNetworkCookie &cookie) const;
-    void cookieRemoved(const QNetworkCookie &cookie) const;
-    void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const;
-    void loadFinished() const;
-    void loadProgress(const int &progress) const;
-    void loadStarted() const;
-    void pageLinkHovered(const QString &linkUrl) const;
-    void printWebpage(QPrinter *printerPointer) const;
-    void showSaveDialog(QWebEngineDownloadItem *downloadItemPointer) const;
-    void showSaveFilePickerDialog(QUrl &downloadUrl, QString &suggestedFileName);
-    void updateUrl(const QUrl &url) const;
-
-private:
-    // The private variables.
-    double currentZoomFactor;  // This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
-    PrivacyWebEngine *currentPrivacyWebEnginePointer;
-    QList<PrivacyWebEngine*> *privacyWebEngineListPointer;
-    QString searchEngineUrl;
-    QWebEngineCookieStore *webEngineCookieStorePointer;
-    QWebEngineHistory *webEngineHistoryPointer;
-    QWebEnginePage *webEnginePagePointer;
-    QWebEngineProfile *webEngineProfilePointer;
-    QWebEngineSettings *webEngineSettingsPointer;
-    QWebEngineView *webEngineViewPointer;
-
-    // The private functions.
-    void applyDomainSettings(const QString &hostname, const bool reloadWebsite);
-};
-#endif
diff --git a/src/views/CMakeLists.txt b/src/views/CMakeLists.txt
deleted file mode 100644 (file)
index 2929781..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
-#
-# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
-#
-# Privacy Browser PC is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Privacy Browser PC is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
-
-
-# List the sources to include in the executable.
-target_sources(privacy-browser PRIVATE
-    BrowserView.cpp
-)
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
new file mode 100644 (file)
index 0000000..afbc0de
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+#
+# This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+#
+# Privacy Browser PC is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Privacy Browser PC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# List the sources to include in the executable.
+target_sources(privacy-browser PRIVATE
+    TabWidget.cpp
+    PrivacyWebEngineView.cpp
+)
diff --git a/src/widgets/PrivacyWebEngineView.cpp b/src/widgets/PrivacyWebEngineView.cpp
new file mode 100644 (file)
index 0000000..28fb66d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "PrivacyWebEngineView.h"
+#include "databases/CookiesDatabase.h"
+
+// Construct the class.
+PrivacyWebEngineView::PrivacyWebEngineView() : QWebEngineView(nullptr) {}
+
+void PrivacyWebEngineView::addCookieToList(const QNetworkCookie &cookie) const
+{
+    //qDebug() << "Add cookie:  " << cookie.toRawForm();
+
+    // Add the new cookie to the list.
+    cookieListPointer->push_front(cookie);
+
+    // Update the cookie if it is durable and has new data.
+    if (CookiesDatabase::isUpdate(cookie))
+        CookiesDatabase::updateCookie(cookie);
+
+    // Update the cookies action.
+    emit updateCookiesAction(cookieListPointer->size());
+}
+
+void PrivacyWebEngineView::removeCookieFromList(const QNetworkCookie &cookie) const
+{
+    //qDebug() << "Remove cookie:  " << cookie.toRawForm();
+
+    // Remove the cookie from the list.
+    cookieListPointer->remove(cookie);
+
+    // Update the cookies action.
+    emit updateCookiesAction(cookieListPointer->size());
+}
diff --git a/src/widgets/PrivacyWebEngineView.h b/src/widgets/PrivacyWebEngineView.h
new file mode 100644 (file)
index 0000000..3869fc3
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PRIVACYWEBENGINEVIEW_H
+#define PRIVACYWEBENGINEVIEW_H
+
+// Qt toolkit headers.
+#include <QNetworkCookie>
+#include <QWebEngineView>
+
+class PrivacyWebEngineView : public QWebEngineView
+{
+    // Include the Q_OBJECT macro.
+    Q_OBJECT
+
+public:
+    // The default constructor.
+    explicit PrivacyWebEngineView();
+
+    // The public variables.
+    std::list<QNetworkCookie> *cookieListPointer = new std::list<QNetworkCookie>;
+    QString domainSettingsName = QStringLiteral("");
+    bool localStorageEnabled = false;
+
+signals:
+    // The signals.
+    void updateCookiesAction(const int numberOfCookies) const;
+
+public Q_SLOTS:
+    // The public slots.
+    void addCookieToList(const QNetworkCookie &cookie) const;
+    void removeCookieFromList(const QNetworkCookie &cookie) const;
+};
+#endif
diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp
new file mode 100644 (file)
index 0000000..3b0ce08
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Application headers.
+#include "TabWidget.h"
+#include "Settings.h"
+#include "ui_AddTabWidget.h"
+#include "ui_TabWidget.h"
+#include "databases/CookiesDatabase.h"
+#include "databases/DomainsDatabase.h"
+#include "dialogs/SaveDialog.h"
+#include "filters/MouseEventFilter.h"
+#include "helpers/SearchEngineHelper.h"
+#include "helpers/UserAgentHelper.h"
+#include "interceptors/UrlRequestInterceptor.h"
+#include "windows/BrowserWindow.h"
+
+// KDE Framework headers.
+#include <KIO/FileCopyJob>
+#include <KIO/JobUiDelegate>
+
+// Qt toolkit headers.
+#include <QAction>
+#include <QFileDialog>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QPrintDialog>
+#include <QPrintPreviewDialog>
+#include <QPrinter>
+
+// Initialize the public static variables.
+QString TabWidget::webEngineDefaultUserAgent = QStringLiteral("");
+
+// Construct the class.
+TabWidget::TabWidget(QWidget *parent) : QWidget(parent)
+{
+    // Instantiate the UIs.
+    Ui::TabWidget tabWidgetUi;
+    Ui::AddTabWidget addTabWidgetUi;
+
+    // Setup the main UI.
+    tabWidgetUi.setupUi(this);
+
+    // Get a handle for the tab widget.
+    tabWidgetPointer = tabWidgetUi.tabWidget;
+
+    // Setup the add tab UI.
+    addTabWidgetUi.setupUi(tabWidgetPointer);
+
+    // Get handles for the add tab widgets.
+    QWidget *addTabWidgetPointer = addTabWidgetUi.addTabQWidget;
+    QPushButton *addTabButtonPointer = addTabWidgetUi.addTabButton;
+
+    // Display the add tab widget.
+    tabWidgetPointer->setCornerWidget(addTabWidgetPointer);
+
+    // Add the first tab.
+    addFirstTab();
+
+    // Process tab events.
+    connect(tabWidgetPointer, SIGNAL(currentChanged(int)), this, SLOT(updateUiWithTabSettings()));
+    connect(addTabButtonPointer, SIGNAL(clicked()), this, SLOT(addTab()));
+    connect(tabWidgetPointer, SIGNAL(tabCloseRequested(int)), this, SLOT(deleteTab(int)));
+
+    // Store a copy of the WebEngine default user agent.
+    webEngineDefaultUserAgent = currentWebEngineProfilePointer->httpUserAgent();
+
+    // Instantiate the mouse event filter pointer.
+    MouseEventFilter *mouseEventFilterPointer = new MouseEventFilter();
+
+    // Install the mouse event filter.
+    qApp->installEventFilter(mouseEventFilterPointer);
+
+    // Process mouse forward and back commands.
+    connect(mouseEventFilterPointer, SIGNAL(mouseBack()), this, SLOT(mouseBack()));
+    connect(mouseEventFilterPointer, SIGNAL(mouseForward()), this, SLOT(mouseForward()));
+}
+
+TabWidget::~TabWidget()
+{
+    // Manually delete each WebEngine page.
+    for (int i = 0; i < tabWidgetPointer->count(); ++i)
+    {
+        // Get the privacy WebEngine view.
+        PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(tabWidgetPointer->widget(i));
+
+        // Deletion the WebEngine page to prevent the following error:  `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
+        delete privacyWebEngineViewPointer->page();
+    }
+}
+
+// The cookie is copied instead of referenced so that changes made to the cookie do not create a race condition with the display of the cookie in the dialog.
+void TabWidget::addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer) const
+{
+    // Create a url.
+    QUrl url;
+
+    // Check to see if the domain does not start with a `.` because Qt makes this harder than it should be.  <https://doc.qt.io/qt-5/qwebenginecookiestore.html#setCookie>
+    if (!cookie.domain().startsWith(QStringLiteral(".")))
+    {
+        // Populate the URL.
+        url.setHost(cookie.domain());
+        url.setScheme(QStringLiteral("https"));
+
+        // Clear the domain from the cookie.
+        cookie.setDomain(QStringLiteral(""));
+    }
+
+    // Add the cookie to the store.
+    if (webEngineCookieStorePointer == nullptr)
+        currentWebEngineCookieStorePointer->setCookie(cookie, url);
+    else
+        webEngineCookieStorePointer->setCookie(cookie, url);
+}
+
+void TabWidget::addFirstTab()
+{
+    // Create the first tab.
+    addTab();
+
+    // Update the UI with the tab settings.
+    updateUiWithTabSettings();
+
+    // Set the focus on the current tab widget.  This prevents the tab bar from showing a blue bar under the label of the first tab.
+    tabWidgetPointer->currentWidget()->setFocus();
+}
+
+void TabWidget::addTab()
+{
+    // Create a privacy WebEngine view.
+    PrivacyWebEngineView *privacyWebEngineViewPointer = new PrivacyWebEngineView();
+
+    // Add a new tab.
+    int newTabIndex = tabWidgetPointer->addTab(privacyWebEngineViewPointer, i18nc("New tab label.", "New Tab"));
+
+    // Set the default tab icon.
+    tabWidgetPointer->setTabIcon(newTabIndex, defaultTabIcon);
+
+    // Create an off-the-record profile (the default when no profile name is specified).
+    QWebEngineProfile *webEngineProfilePointer = new QWebEngineProfile(QStringLiteral(""));
+
+    // Create a WebEngine page.
+    QWebEnginePage *webEnginePagePointer = new QWebEnginePage(webEngineProfilePointer);
+
+    // Set the WebEngine page.
+    privacyWebEngineViewPointer->setPage(webEnginePagePointer);
+
+    // Get handles for the web engine elements.
+    QWebEngineCookieStore *webEngineCookieStorePointer = webEngineProfilePointer->cookieStore();
+    QWebEngineSettings *webEngineSettingsPointer = webEnginePagePointer->settings();
+
+    // Update the URL line edit when the URL changes.
+    connect(privacyWebEngineViewPointer, SIGNAL(urlChanged(const QUrl)), this, SLOT(updateUrl(const QUrl)));
+
+
+    // Update the progress bar.
+    connect(privacyWebEngineViewPointer, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
+    connect(privacyWebEngineViewPointer, SIGNAL(loadProgress(const int)), this, SLOT(loadProgress(const int)));
+    connect(privacyWebEngineViewPointer, SIGNAL(loadFinished(const bool)), this, SLOT(loadFinished()));
+
+    // Handle full screen requests.
+    connect(webEnginePagePointer, SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest)));
+
+    // Listen for hovered link URLs.
+    connect(webEnginePagePointer, SIGNAL(linkHovered(const QString)), this, SLOT(pageLinkHovered(const QString)));
+
+    // Handle file downloads.
+    connect(webEngineProfilePointer, SIGNAL(downloadRequested(QWebEngineDownloadItem *)), this, SLOT(showSaveDialog(QWebEngineDownloadItem *)));
+
+    // Instantiate the URL request interceptor.
+    UrlRequestInterceptor *urlRequestInterceptorPointer = new UrlRequestInterceptor();
+
+    // Set the URL request interceptor.
+    webEngineProfilePointer->setUrlRequestInterceptor(urlRequestInterceptorPointer);
+
+    // Reapply the domain settings when the host changes.
+    connect(urlRequestInterceptorPointer, SIGNAL(applyDomainSettings(QString)), this, SLOT(applyDomainSettingsWithoutReloading(QString)));
+
+    // Set the local storage filter.
+    webEngineCookieStorePointer->setCookieFilter([privacyWebEngineViewPointer](const QWebEngineCookieStore::FilterRequest &filterRequest)
+    {
+        // Block all third party local storage requests, including the sneaky ones that don't register a first party URL.
+        if (filterRequest.thirdParty || (filterRequest.firstPartyUrl == QStringLiteral("")))
+        {
+            //qDebug().noquote().nospace() << "Third-party request blocked:  " << filterRequest.origin;
+
+            // Return false.
+            return false;
+        }
+
+        // Allow the request if local storage is enabled.
+        if (privacyWebEngineViewPointer->localStorageEnabled)
+        {
+            //qDebug().noquote().nospace() << "Request allowed by local storage:  " << filterRequest.origin;
+
+            // Return true.
+            return true;
+        }
+
+        //qDebug().noquote().nospace() << "Request blocked by default:  " << filterRequest.origin;
+
+        // Block any remaining local storage requests.
+        return false;
+    });
+
+    // Disable JavaScript by default (this prevetns JavaScript from being enabled on a new tab before domain settings are loaded).
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
+
+    // Don't allow JavaScript to open windows.
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
+
+    // Allow keyboard navigation.
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, true);
+
+    // Enable full screen support.
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
+
+    // Require user interaction to play media.
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, true);
+
+    // Limit WebRTC to public IP addresses.
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, true);
+
+    // Define an update cookie count lambda.
+    auto updateCookieCount = [privacyWebEngineViewPointer, this] (const int numberOfCookies)
+    {
+        // Update the cookie action if the specified privacy WebEngine view is the current privacy WebEngine view.
+        if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
+            emit updateCookiesAction(numberOfCookies);
+    };
+
+    // Update the cookies action.
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::updateCookiesAction, this, updateCookieCount);
+
+    // Process cookie changes.
+    connect(webEngineCookieStorePointer, SIGNAL(cookieAdded(QNetworkCookie)), privacyWebEngineViewPointer, SLOT(addCookieToList(QNetworkCookie)));
+    connect(webEngineCookieStorePointer, SIGNAL(cookieRemoved(QNetworkCookie)), privacyWebEngineViewPointer, SLOT(removeCookieFromList(QNetworkCookie)));
+
+    // Get a list of durable cookies.
+    QList<QNetworkCookie*> *durableCookiesListPointer = CookiesDatabase::getCookies();
+
+    // Add the durable cookies to the store.
+    for (QNetworkCookie *cookiePointer : *durableCookiesListPointer)
+        addCookieToStore(*cookiePointer, webEngineCookieStorePointer);
+
+    // Define an update tab title lambda.
+    auto updateTabTitle = [privacyWebEngineViewPointer, this] (const QString &title)
+    {
+        // Get the index for this tab.
+        int tabIndex = tabWidgetPointer->indexOf(privacyWebEngineViewPointer);
+
+        // Update the title for this tab.
+        tabWidgetPointer->setTabText(tabIndex, title);
+    };
+
+    // Update the title when it changes.
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, this, updateTabTitle);
+
+    // Define an update tab icon lambda.
+    auto updateTabIcon = [privacyWebEngineViewPointer, this] (const QIcon &icon)
+    {
+        // Get the index for this tab.
+        int tabIndex = tabWidgetPointer->indexOf(privacyWebEngineViewPointer);
+
+        // Update the icon for this tab.
+        if (icon.isNull())
+            tabWidgetPointer->setTabIcon(tabIndex, defaultTabIcon);
+        else
+            tabWidgetPointer->setTabIcon(tabIndex, icon);
+    };
+
+    // Update the icon when it changes.
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, this, updateTabIcon);
+
+    // Move to the new tab.
+    tabWidgetPointer->setCurrentIndex(newTabIndex);
+}
+
+void TabWidget::applyApplicationSettings()
+{
+    // Set the tab position.
+    if (Settings::tabsOnTop())
+        tabWidgetPointer->setTabPosition(QTabWidget::North);
+    else
+        tabWidgetPointer->setTabPosition(QTabWidget::South);
+
+    // Set the search engine URL.
+    searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
+
+    // Emit the update search engine actions signal.
+    emit updateSearchEngineActions(Settings::searchEngine(), true);
+}
+
+// This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
+// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
+void TabWidget::applyDomainSettingsAndReload()
+{
+    // Apply the domain settings.  `true` reloads the website.
+    applyDomainSettings(currentPrivacyWebEngineViewPointer->url().host(), true);
+}
+
+// This exists as a separate function from `applyDomainSettings()` so it can be listed as a slot and function without the need for a boolean argument.
+// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
+void TabWidget::applyDomainSettingsWithoutReloading(const QString &hostname)
+{
+    // Apply the domain settings  `false` does not reload the website.
+    applyDomainSettings(hostname, false);
+}
+
+// Once <https://redmine.stoutner.com/issues/799> has been resolved this can be `const`.
+void TabWidget::applyDomainSettings(const QString &hostname, const bool reloadWebsite)
+{
+    // Get the record for the hostname.
+    QSqlQuery domainQuery = DomainsDatabase::getDomainQuery(hostname);
+
+    // Check if the hostname has domain settings.
+    if (domainQuery.isValid())  // The hostname has domain settings.
+    {
+        // Get the domain record.
+        QSqlRecord domainRecord = domainQuery.record();
+
+        // Store the domain settings name.
+        currentPrivacyWebEngineViewPointer->domainSettingsName = domainRecord.field(DomainsDatabase::DOMAIN_NAME).value().toString();
+
+        // Set the JavaScript status.
+        switch (domainRecord.field(DomainsDatabase::JAVASCRIPT).value().toInt())
+        {
+            // Set the default JavaScript status.
+            case (DomainsDatabase::SYSTEM_DEFAULT):
+            {
+                currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
+
+                break;
+            }
+
+            // Disable JavaScript.
+            case (DomainsDatabase::DISABLED):
+            {
+                currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
+
+                break;
+            }
+
+            // Enable JavaScript.
+            case (DomainsDatabase::ENABLED):
+            {
+                currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
+
+                break;
+            }
+        }
+
+        // Set the local storage status.
+        switch (domainRecord.field(DomainsDatabase::LOCAL_STORAGE).value().toInt())
+        {
+            // Set the default local storage status.
+            case (DomainsDatabase::SYSTEM_DEFAULT):
+            {
+                currentPrivacyWebEngineViewPointer->localStorageEnabled = Settings::localStorageEnabled();
+
+                break;
+            }
+
+            // Disable local storage.
+            case (DomainsDatabase::DISABLED):
+            {
+                currentPrivacyWebEngineViewPointer->localStorageEnabled = false;
+
+                break;
+            }
+
+            // Enable local storage.
+            case (DomainsDatabase::ENABLED):
+            {
+                currentPrivacyWebEngineViewPointer->localStorageEnabled = true;
+
+                break;
+            }
+        }
+
+        // Set the DOM storage status.
+        switch (domainRecord.field(DomainsDatabase::DOM_STORAGE).value().toInt())
+        {
+            // Set the default DOM storage status.
+            case (DomainsDatabase::SYSTEM_DEFAULT):
+            {
+                currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
+
+                break;
+            }
+
+            // Disable DOM storage.
+            case (DomainsDatabase::DISABLED):
+            {
+                currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, false);
+
+                break;
+            }
+
+            // Enable DOM storage.
+            case (DomainsDatabase::ENABLED):
+            {
+                currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
+
+                break;
+            }
+        }
+
+        // Set the user agent.
+        currentWebEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getResultingDomainSettingsUserAgent(domainRecord.field(DomainsDatabase::USER_AGENT).value().toString()));
+
+        // Check if a custom zoom factor is set.
+        if (domainRecord.field(DomainsDatabase::ZOOM_FACTOR).value().toInt())
+        {
+            // Store the current zoom factor.
+            currentZoomFactor = domainRecord.field(DomainsDatabase::CUSTOM_ZOOM_FACTOR).value().toDouble();
+        }
+        else
+        {
+            // Reset the current zoom factor.
+            currentZoomFactor = Settings::zoomFactor();
+        }
+
+        // Set the zoom factor.    The use of `currentZoomFactor` can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
+        currentPrivacyWebEngineViewPointer->setZoomFactor(currentZoomFactor);
+    }
+    else  // The hostname does not have domain settings.
+    {
+        // Reset the domain settings name.
+        currentPrivacyWebEngineViewPointer->domainSettingsName = QStringLiteral("");
+
+        // Set the JavaScript status.
+        currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, Settings::javaScriptEnabled());
+
+        // Set the local storage status.
+        //currentPrivacyWebEngineViewPointer->localStorageEnabled = Settings::localStorageEnabled();
+
+        // Set DOM storage.
+        currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, Settings::domStorageEnabled());
+
+        // Set the user agent.
+        currentWebEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromDatabaseName(Settings::userAgent()));
+
+        // Store the current zoom factor.  This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
+        currentZoomFactor = Settings::zoomFactor();
+
+        // Set the zoom factor.
+        currentPrivacyWebEngineViewPointer->setZoomFactor(Settings::zoomFactor());
+    }
+
+    // Update the UI.
+    emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral(""));
+    emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
+    emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
+    emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
+    emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
+    emit updateZoomFactorAction(currentPrivacyWebEngineViewPointer->zoomFactor());
+
+    // Reload the website if requested.
+    if (reloadWebsite)
+        currentPrivacyWebEngineViewPointer->reload();
+}
+
+void TabWidget::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
+{
+    // Store the search engine name.
+    QString searchEngineName = searchEngineActionPointer->text();
+
+    // Strip out any `&` characters.
+    searchEngineName.remove('&');
+
+    // Store the search engine string.
+    searchEngineUrl = SearchEngineHelper::getSearchUrl(searchEngineName);
+
+    // Update the search engine actionas.
+    emit updateSearchEngineActions(searchEngineName, false);
+}
+
+void TabWidget::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const
+{
+    // Get the user agent name.
+    QString userAgentName = userAgentActionPointer->text();
+
+    // Strip out any `&` characters.
+    userAgentName.remove('&');
+
+    // Apply the user agent.
+    currentWebEngineProfilePointer->setHttpUserAgent(UserAgentHelper::getUserAgentFromTranslatedName(userAgentName));
+
+    // Update the user agent actions.
+    emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), false);
+
+    // Reload the website.
+    currentPrivacyWebEngineViewPointer->reload();
+}
+
+// This can be const once <https://redmine.stoutner.com/issues/799> has been resolved.
+void TabWidget::applyOnTheFlyZoomFactor(const double &zoomFactor)
+{
+    // Update the current zoom factor.  This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
+    currentZoomFactor = zoomFactor;
+
+    // Set the zoom factor.
+    currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactor);
+}
+
+void TabWidget::back() const
+{
+    // Go back.
+    currentPrivacyWebEngineViewPointer->back();
+}
+
+void TabWidget::deleteAllCookies() const
+{
+    // Delete all the cookies.
+    currentWebEngineCookieStorePointer->deleteAllCookies();
+}
+
+void TabWidget::deleteCookieFromStore(const QNetworkCookie &cookie) const
+{
+    // Delete the cookie.
+    currentWebEngineCookieStorePointer->deleteCookie(cookie);
+}
+
+void TabWidget::deleteTab(const int tabIndex)
+{
+    // Get the privacy WebEngine view.
+    PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(tabWidgetPointer->widget(tabIndex));
+
+    // Proccess the tab delete according to the number of tabs.
+    if (tabWidgetPointer->count() > 1)  // There is more than one tab.
+    {
+        // Delete the tab.
+        tabWidgetPointer->removeTab(tabIndex);
+
+        // Delete the WebEngine page to prevent the following error:  `Release of profile requested but WebEnginePage still not deleted. Expect troubles !`
+        delete privacyWebEngineViewPointer->page();
+
+        // Delete the privacy WebEngine view.
+        delete privacyWebEngineViewPointer;
+    }
+    else  // There is only one tab.
+    {
+        // Close Privacy Browser.
+        window()->close();
+    }
+}
+
+void TabWidget::forward() const
+{
+    // Go forward.
+    currentPrivacyWebEngineViewPointer->forward();
+}
+
+void TabWidget::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const
+{
+    // Make it so.
+    emit fullScreenRequested(fullScreenRequest.toggleOn());
+
+    // Accept the request.
+    fullScreenRequest.accept();
+}
+
+std::list<QNetworkCookie>* TabWidget::getCookieList() const
+{
+    // Return the current cookie list.
+    return currentPrivacyWebEngineViewPointer->cookieListPointer;
+}
+
+QString& TabWidget::getDomainSettingsName() const
+{
+    // Return the domain settings name.
+    return currentPrivacyWebEngineViewPointer->domainSettingsName;
+}
+
+void TabWidget::home() const
+{
+    // Load the homepage.
+    currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(Settings::homepage()));
+}
+
+void TabWidget::loadFinished() const
+{
+    // Hide the progress bar.
+    emit hideProgressBar();
+}
+
+void TabWidget::loadInitialWebsite()
+{
+    // Apply the application settings.
+    applyApplicationSettings();
+
+    // Get the arguments.
+    QStringList argumentsStringList = qApp->arguments();
+
+    // Check to see if the arguments lists contains a URL.
+    if (argumentsStringList.size() > 1)
+    {
+        // Load the URL from the arguments list.
+        currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(argumentsStringList.at(1)));
+    }
+    else
+    {
+        // Load the homepage.
+        home();
+    }
+}
+
+void TabWidget::loadProgress(const int &progress) const
+{
+    // Show the progress bar.
+    emit showProgressBar(progress);
+}
+
+void TabWidget::loadStarted() const
+{
+    // Show the progress bar.
+    emit showProgressBar(0);
+}
+
+void TabWidget::loadUrlFromLineEdit(QString url) const
+{
+    // Decide if the text is more likely to be a URL or a search.
+    if (url.startsWith("file://"))  // The text is likely a file URL.
+    {
+        // Load the URL.
+        currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(url));
+    }
+    else if (url.contains("."))  // The text is likely a URL.
+    {
+        // Check if the URL does not start with a valid protocol.
+        if (!url.startsWith("http"))
+        {
+            // Add `https://` to the beginning of the URL.
+            url = "https://" + url;
+        }
+
+        // Load the URL.
+        currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(url));
+    }
+    else  // The text is likely a search.
+    {
+        // Load the search.
+        currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(searchEngineUrl + url));
+    }
+}
+
+void TabWidget::mouseBack() const
+{
+    // Go back if possible.
+    if (currentPrivacyWebEngineViewPointer->isActiveWindow() && currentWebEngineHistoryPointer->canGoBack())
+    {
+        // Clear the URL line edit focus.
+        emit clearUrlLineEditFocus();
+
+        // Go back.
+        currentPrivacyWebEngineViewPointer->back();
+    }
+}
+
+void TabWidget::mouseForward() const
+{
+    // Go forward if possible.
+    if (currentPrivacyWebEngineViewPointer->isActiveWindow() && currentWebEngineHistoryPointer->canGoForward())
+    {
+        // Clear the URL line edit focus.
+        emit clearUrlLineEditFocus();
+
+        // Go forward.
+        currentPrivacyWebEngineViewPointer->forward();
+    }
+}
+
+void TabWidget::pageLinkHovered(const QString &linkUrl) const
+{
+    // Emit a signal so that the browser window can update the status bar.
+    emit linkHovered(linkUrl);
+}
+
+void TabWidget::print() const
+{
+    // Create a printer.
+    QPrinter printer;
+
+    // Set the resolution to be 300 dpi.
+    printer.setResolution(300);
+
+    // Create a printer dialog.
+    QPrintDialog printDialog(&printer, currentPrivacyWebEngineViewPointer);
+
+    // Display the dialog and print the page if instructed.
+    if (printDialog.exec() == QDialog::Accepted)
+        printWebpage(&printer);
+}
+
+void TabWidget::printPreview() const
+{
+    // Create a printer.
+    QPrinter printer;
+
+    // Set the resolution to be 300 dpi.
+    printer.setResolution(300);
+
+    // Create a print preview dialog.
+    QPrintPreviewDialog printPreviewDialog(&printer, currentPrivacyWebEngineViewPointer);
+
+    // Generate the print preview.
+    connect(&printPreviewDialog, SIGNAL(paintRequested(QPrinter *)), this, SLOT(printWebpage(QPrinter *)));
+
+    // Display the dialog.
+    printPreviewDialog.exec();
+}
+
+void TabWidget::printWebpage(QPrinter *printerPointer) const
+{
+    // Create an event loop.  For some reason, the print preview doesn't produce any output unless it is run inside an event loop.
+    QEventLoop eventLoop;
+
+    // Print the webpage, converting the callback above into a `QWebEngineCallback<bool>`.
+    // Printing requires that the printer be a pointer, not a reference, or it will crash with much cursing.
+    currentWebEnginePagePointer->print(printerPointer, [&eventLoop](bool printSuccess)
+    {
+        // Instruct the compiler to ignore the unused parameter.
+        (void) printSuccess;
+
+        // Quit the loop.
+        eventLoop.quit();
+    });
+
+    // Execute the loop.
+    eventLoop.exec();
+}
+
+void TabWidget::refresh() const
+{
+    // Reload the website.
+    currentPrivacyWebEngineViewPointer->reload();
+}
+
+void TabWidget::setTabBarVisible(const bool visible) const
+{
+    // Set the tab bar visibility.
+    tabWidgetPointer->tabBar()->setVisible(visible);
+}
+
+void TabWidget::showSaveDialog(QWebEngineDownloadItem *downloadItemPointer) const
+{
+    // Instantiate the save dialog.
+    SaveDialog *saveDialogPointer = new SaveDialog(downloadItemPointer);
+
+    // Connect the save button.
+    connect(saveDialogPointer, SIGNAL(showSaveFilePickerDialog(QUrl &, QString &)), this, SLOT(showSaveFilePickerDialog(QUrl &, QString &)));
+
+    // Show the dialog.
+    saveDialogPointer->show();
+}
+
+void TabWidget::showSaveFilePickerDialog(QUrl &downloadUrl, QString &suggestedFileName)
+{
+    // Get the download location.
+    QString downloadDirectory = Settings::downloadLocation();
+
+    // Resolve the system download directory if specified.
+    if (downloadDirectory == QStringLiteral("System Download Directory"))
+        downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
+
+    // Create a save file dialog.
+    QFileDialog *saveFileDialogPointer = new QFileDialog(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory);
+
+    // Tell the dialog to use a save button.
+    saveFileDialogPointer->setAcceptMode(QFileDialog::AcceptSave);
+
+    // Populate the file name from the download item pointer.
+    saveFileDialogPointer->selectFile(suggestedFileName);
+
+    // Prevent interaction with the parent window while the dialog is open.
+    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] () {
+        // Get the save location.  The dialog box should only allow the selecting of one file location.
+        QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0);
+
+        // Create a file copy job.  `-1` creates the file with default permissions.
+        KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite);
+
+        // Set the download job to display any error messages.
+        fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true);
+
+        // Start the download.
+        fileCopyJobPointer->start();
+    };
+
+    // Handle clicks on the save button.
+    connect(saveFileDialogPointer, &QDialog::accepted, this, saveFile);
+
+    // Show the dialog.
+    saveFileDialogPointer->show();
+}
+
+void TabWidget::toggleDomStorage() const
+{
+    // Toggle DOM storage.
+    currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::LocalStorageEnabled, !currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
+
+    // Update the DOM storage action.
+    emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
+
+    // Reload the website.
+    currentPrivacyWebEngineViewPointer->reload();
+}
+
+void TabWidget::toggleJavaScript() const
+{
+    // Toggle JavaScript.
+    currentWebEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptEnabled, !currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
+
+    // Update the JavaScript action.
+    emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
+
+    // Reload the website.
+    currentPrivacyWebEngineViewPointer->reload();
+}
+
+void TabWidget::toggleLocalStorage()
+{
+    // Toggle local storeage.
+    currentPrivacyWebEngineViewPointer->localStorageEnabled = !currentPrivacyWebEngineViewPointer->localStorageEnabled;
+
+    // Update the local storage action.
+    emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
+
+    // Reload the website.
+    currentPrivacyWebEngineViewPointer->reload();
+}
+
+void TabWidget::updateUiWithTabSettings()
+{
+    // Update the current WebEngine pointers.
+    currentPrivacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(tabWidgetPointer->currentWidget());
+    currentWebEngineSettingsPointer = currentPrivacyWebEngineViewPointer->settings();
+    currentWebEnginePagePointer = currentPrivacyWebEngineViewPointer->page();
+    currentWebEngineProfilePointer = currentWebEnginePagePointer->profile();
+    currentWebEngineHistoryPointer = currentWebEnginePagePointer->history();
+    currentWebEngineCookieStorePointer = currentWebEngineProfilePointer->cookieStore();
+
+    // Clear the URL line edit focus.
+    emit clearUrlLineEditFocus();
+
+    // Update the UI.
+    emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral(""));
+    emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
+    emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
+    emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
+    emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
+    emit updateZoomFactorAction(currentPrivacyWebEngineViewPointer->zoomFactor());
+    emit updateUrlLineEdit(currentPrivacyWebEngineViewPointer->url());
+    emit updateCookiesAction(currentPrivacyWebEngineViewPointer->cookieListPointer->size());
+}
+
+void TabWidget::updateUrl(const QUrl &url) const
+{
+    // Update the URL line edit.
+    emit updateUrlLineEdit(url);
+
+    // Update the status of the forward and back buttons.
+    emit updateBackAction(currentWebEngineHistoryPointer->canGoBack());
+    emit updateForwardAction(currentWebEngineHistoryPointer->canGoForward());
+
+    // Reapply the zoom factor.  This is a bug in QWebEngineView that resets the zoom with every load.  <https://redmine.stoutner.com/issues/799>
+    currentPrivacyWebEngineViewPointer->setZoomFactor(currentZoomFactor);
+}
diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h
new file mode 100644 (file)
index 0000000..525c81a
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
+ *
+ * Privacy Browser PC is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser PC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+// Application headers.
+#include "PrivacyWebEngineView.h"
+
+// KDE Framework headers.
+#include <KLineEdit>
+
+// Qt toolkit headers.
+#include <QPushButton>
+#include <QTabWidget>
+#include <QWebEngineCookieStore>
+#include <QWebEngineFullScreenRequest>
+#include <QWebEngineHistory>
+#include <QWebEngineProfile>
+#include <QWebEngineSettings>
+#include <QWebEngineView>
+
+class TabWidget : public QWidget
+{
+    // Include the Q_OBJECT macro.
+    Q_OBJECT
+
+public:
+    // The primary contructor.
+    explicit TabWidget(QWidget *parent);
+
+    // The destructor.
+    ~TabWidget();
+
+    // The public functions.
+    void applyOnTheFlyZoomFactor(const double &zoomFactor);
+    void loadInitialWebsite();
+    std::list<QNetworkCookie>* getCookieList() const;
+    QString& getDomainSettingsName() const;
+    void setTabBarVisible(const bool visible) const;
+    void toggleDomStorage() const;
+    void toggleJavaScript() const;
+    void toggleLocalStorage();
+
+    // The public static variables.
+    static QString webEngineDefaultUserAgent;
+
+signals:
+    // The signals.
+    void addCookie(const QNetworkCookie &cookie) const;
+    void removeCookie(const QNetworkCookie &cookie) const;
+    void clearUrlLineEditFocus() const;
+    void fullScreenRequested(const bool toggleOn) const;
+    void hideProgressBar() const;
+    void linkHovered(const QString &linkUrl) const;
+    void showProgressBar(const int &progress) const;
+    void updateBackAction(const bool &isEnabled) const;
+    void updateCookiesAction(const int numberOfCookies) const;
+    void updateDomStorageAction(const bool &isEnabled) const;
+    void updateDomainSettingsIndicator(const bool status) const;
+    void updateForwardAction(const bool &isEnabled) const;
+    void updateJavaScriptAction(const bool &isEnabled) const;
+    void updateLocalStorageAction(const bool &isEnabled) const;
+    void updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus) const;
+    void updateUrlLineEdit(const QUrl &newUrl) const;
+    void updateUserAgentActions(const QString &userAgent, const bool &updateCustomUserAgentStatus) const;
+    void updateZoomFactorAction(const double &zoomFactor) const;
+
+public Q_SLOTS:
+    // The public slots.
+    void addTab();
+    void addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer = nullptr) const;
+    void applyApplicationSettings();
+    void applyDomainSettingsAndReload();
+    void applyDomainSettingsWithoutReloading(const QString &hostname);
+    void applyOnTheFlySearchEngine(QAction *searchEngineActionPointer);
+    void applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const;
+    void back() const;
+    void deleteAllCookies() const;
+    void deleteCookieFromStore(const QNetworkCookie &cookie) const;
+    void forward() const;
+    void home() const;
+    void loadUrlFromLineEdit(QString url) const;
+    void mouseBack() const;
+    void mouseForward() const;
+    void print() const;
+    void printPreview() const;
+    void refresh() const;
+
+private Q_SLOTS:
+    // The private slots.
+    void addFirstTab();
+    void deleteTab(const int tabIndex);
+    void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const;
+    void loadFinished() const;
+    void loadProgress(const int &progress) const;
+    void loadStarted() const;
+    void pageLinkHovered(const QString &linkUrl) const;
+    void printWebpage(QPrinter *printerPointer) const;
+    void showSaveDialog(QWebEngineDownloadItem *downloadItemPointer) const;
+    void showSaveFilePickerDialog(QUrl &downloadUrl, QString &suggestedFileName);
+    void updateUiWithTabSettings();
+    void updateUrl(const QUrl &url) const;
+
+private:
+    // The private variables.
+    double currentZoomFactor;  // This can be removed once <https://redmine.stoutner.com/issues/799> has been resolved.
+    PrivacyWebEngineView *currentPrivacyWebEngineViewPointer;
+    QWebEngineCookieStore *currentWebEngineCookieStorePointer;
+    QWebEngineHistory *currentWebEngineHistoryPointer;
+    QWebEnginePage *currentWebEnginePagePointer;
+    QWebEngineProfile *currentWebEngineProfilePointer;
+    QWebEngineSettings *currentWebEngineSettingsPointer;
+    QIcon defaultTabIcon = QIcon::fromTheme(QStringLiteral("globe"));
+    QString searchEngineUrl;
+    QTabWidget *tabWidgetPointer;
+
+    // The private functions.
+    void applyDomainSettings(const QString &hostname, const bool reloadWebsite);
+};
+#endif
index e44357f25c042bb264ac7384baa00b6ab4b3793c..8d2417179119626908faa1576bb8df5bd41643fd 100644 (file)
@@ -22,7 +22,6 @@
 #include "Settings.h"
 #include "ui_SettingsPrivacy.h"
 #include "ui_SettingsGeneral.h"
-#include "databases/CookiesDatabase.h"
 #include "dialogs/CookiesDialog.h"
 #include "dialogs/DomainSettingsDialog.h"
 #include "helpers/SearchEngineHelper.h"
 BrowserWindow::BrowserWindow() : KXmlGuiWindow()
 {
     // Initialize the variables.
-    cookieListPointer = new std::list<QNetworkCookie>;
     javaScriptEnabled = false;
     localStorageEnabled = false;
 
-    // Instantiate the main view pointer.
-    browserViewPointer = new BrowserView(this);
+    // Instantiate the privacy tab widget pointer.
+    tabWidgetPointer = new TabWidget(this);
 
-    // Set the main view as the central widget.
-    setCentralWidget(browserViewPointer);
+    // Set the privacy tab widget as the central widget.
+    setCentralWidget(tabWidgetPointer);
 
     // Get a handle for the action collection.
     KActionCollection *actionCollectionPointer = this->actionCollection();
 
     // Add the standard actions.
     KStandardAction::openNew(this, SLOT(fileNew()), actionCollectionPointer);
-    KStandardAction::print(browserViewPointer, SLOT(print()), actionCollectionPointer);
-    KStandardAction::printPreview(browserViewPointer, SLOT(printPreview()), actionCollectionPointer);
+    KStandardAction::print(tabWidgetPointer, SLOT(print()), actionCollectionPointer);
+    KStandardAction::printPreview(tabWidgetPointer, SLOT(printPreview()), actionCollectionPointer);
     KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollectionPointer);
     KStandardAction::redisplay(this, SLOT(refresh()), actionCollectionPointer);
     fullScreenActionPointer = KStandardAction::fullScreen(this, SLOT(toggleFullScreen()), this, actionCollectionPointer);
@@ -152,7 +150,7 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     searchEngineBingActionPointer->setText(i18nc("Search engine", "Bing"));
     searchEngineYahooActionPointer->setText(i18nc("Search engine", "Yahoo"));
     domainSettingsActionPointer->setText(i18nc("Domain Settings action", "Domain Settings"));
-    cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", cookieListPointer->size()));
+    cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", 0));
     javaScriptActionPointer->setText(i18nc("JavaScript action", "JavaScript"));
     localStorageActionPointer->setText(i18nc("The Local Storage action", "Local Storage"));
     domStorageActionPointer->setText(i18nc("DOM Storage action", "DOM Storage"));
@@ -180,13 +178,16 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     domStorageActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("view-web-browser-dom-tree")));
 
     // Update the on-the-fly menus.
-    connect(browserViewPointer, SIGNAL(updateUserAgentActions(QString, bool)), this, SLOT(updateUserAgentActions(QString, bool)));
-    connect(browserViewPointer, SIGNAL(updateZoomFactorAction(double)), this, SLOT(updateZoomFactorAction(double)));
-    connect(browserViewPointer, SIGNAL(updateSearchEngineActions(QString, bool)), this, SLOT(updateSearchEngineActions(QString, bool)));
+    connect(tabWidgetPointer, SIGNAL(updateUserAgentActions(QString, bool)), this, SLOT(updateUserAgentActions(QString, bool)));
+    connect(tabWidgetPointer, SIGNAL(updateZoomFactorAction(double)), this, SLOT(updateZoomFactorAction(double)));
+    connect(tabWidgetPointer, SIGNAL(updateSearchEngineActions(QString, bool)), this, SLOT(updateSearchEngineActions(QString, bool)));
 
     // Apply the on-the-fly settings when selected.
-    connect(userAgentActionGroupPointer, SIGNAL(triggered(QAction*)), browserViewPointer, SLOT(applyOnTheFlyUserAgent(QAction*)));
-    connect(searchEngineActionGroupPointer, SIGNAL(triggered(QAction*)), browserViewPointer, SLOT(applyOnTheFlySearchEngine(QAction*)));
+    connect(userAgentActionGroupPointer, SIGNAL(triggered(QAction*)), tabWidgetPointer, SLOT(applyOnTheFlyUserAgent(QAction*)));
+    connect(searchEngineActionGroupPointer, SIGNAL(triggered(QAction*)), tabWidgetPointer, SLOT(applyOnTheFlySearchEngine(QAction*)));
+
+    // Process cookie changes.
+    connect(tabWidgetPointer, SIGNAL(updateCookiesAction(int)), this, SLOT(updateCookiesAction(int)));
 
     // Display dialogs.
     connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
@@ -199,11 +200,11 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     connect(domStorageActionPointer, SIGNAL(triggered()), this, SLOT(toggleDomStorage()));
 
     // Update the URL toolbar actions.
-    connect(browserViewPointer, SIGNAL(updateBackAction(bool)), backActionPointer, SLOT(setEnabled(bool)));
-    connect(browserViewPointer, SIGNAL(updateForwardAction(bool)), forwardActionPointer, SLOT(setEnabled(bool)));
-    connect(browserViewPointer, SIGNAL(updateJavaScriptAction(bool)), this, SLOT(updateJavaScriptAction(bool)));
-    connect(browserViewPointer, SIGNAL(updateLocalStorageAction(bool)), this, SLOT(updateLocalStorageAction(bool)));
-    connect(browserViewPointer, SIGNAL(updateDomStorageAction(bool)), this, SLOT(updateDomStorageAction(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)));
+    connect(tabWidgetPointer, SIGNAL(updateLocalStorageAction(bool)), this, SLOT(updateLocalStorageAction(bool)));
+    connect(tabWidgetPointer, SIGNAL(updateDomStorageAction(bool)), this, SLOT(updateDomStorageAction(bool)));
 
     // Setup the GUI based on the browser_ui.rc file.
     setupGUI(StandardWindowOption::Default, ("browser_ui.rc"));
@@ -244,7 +245,7 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromLineEdit(const QString)));
 
     // Update the URL line edit on page loads.
-    connect(browserViewPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
+    connect(tabWidgetPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
 
     // Get a handle for the status bar.
     QStatusBar *statusBarPointer = statusBar();
@@ -256,14 +257,14 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     statusBarPointer->addPermanentWidget(progressBarPointer);
 
     // Update the status bar with the URL when a link is hovered.
-    connect(browserViewPointer, SIGNAL(linkHovered(QString)), statusBarPointer, SLOT(showMessage(QString)));
+    connect(tabWidgetPointer, SIGNAL(linkHovered(QString)), statusBarPointer, SLOT(showMessage(QString)));
 
     // Update the progress bar.
-    connect(browserViewPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int)));
-    connect(browserViewPointer, SIGNAL(hideProgressBar()), progressBarPointer, SLOT(hide()));
+    connect(tabWidgetPointer, SIGNAL(showProgressBar(const int)), this, SLOT(showProgressBar(const int)));
+    connect(tabWidgetPointer, SIGNAL(hideProgressBar()), progressBarPointer, SLOT(hide()));
 
-    // Clear the URL line edit focus when requested.
-    connect(browserViewPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
+    // Update the URL line edit focus.
+    connect(tabWidgetPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
 
     // Get the URL line edit palettes.
     noDomainSettingsPalette = urlLineEditPointer->palette();
@@ -273,40 +274,23 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow()
     domainSettingsPalette.setColor(QPalette::Base, QColor("#C8E6C9"));
 
     // Update the applied palette.
-    connect(browserViewPointer, SIGNAL(updateDomainSettingsIndicator(bool, QString)), this, SLOT(updateDomainSettingsIndicator(bool, QString)));
-
-    // Process cookie changes.
-    connect(browserViewPointer, SIGNAL(addCookie(QNetworkCookie)), this, SLOT(addCookieToList(QNetworkCookie)));
-    connect(browserViewPointer, SIGNAL(removeCookie(QNetworkCookie)), this, SLOT(removeCookieFromList(QNetworkCookie)));
+    connect(tabWidgetPointer, SIGNAL(updateDomainSettingsIndicator(const bool)), this, SLOT(updateDomainSettingsIndicator(const bool)));
 
     // Process full screen requests.
-    connect(browserViewPointer, SIGNAL(fullScreenRequested(bool)), this, SLOT(fullScreenRequested(bool)));
+    connect(tabWidgetPointer, SIGNAL(fullScreenRequested(bool)), this, SLOT(fullScreenRequested(bool)));
 
     // Create keyboard shortcuts.
+    QShortcut *ctrlTShortcutPointer = new QShortcut(QKeySequence(i18nc("The open new tab shortcut.", "Ctrl+t")), this);
     QShortcut *f11ShortcutPointer = new QShortcut(QKeySequence(i18nc("The toggle full screen shortcut.", "F11")), this);
     QShortcut *escapeShortcutPointer = new QShortcut(QKeySequence::Cancel, this);
 
     // Connect the keyboard shortcuts to the actions.
+    connect(ctrlTShortcutPointer, SIGNAL(activated()), tabWidgetPointer, SLOT(addTab()));
     connect(f11ShortcutPointer, SIGNAL(activated()), fullScreenActionPointer, SLOT(trigger()));
     connect(escapeShortcutPointer, SIGNAL(activated()), this, SLOT(escape()));
 
     // Load the initial website.
-    browserViewPointer->loadInitialWebsite();
-}
-
-void BrowserWindow::addCookieToList(const QNetworkCookie &newCookie) const
-{
-    //qDebug() << "Add cookie:  " << newCookie.toRawForm();
-
-    // Add the new cookie to the list.
-    cookieListPointer->push_front(newCookie);
-
-    // Update the action text.
-    cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", cookieListPointer->size()));
-
-    // Update the cookie if it is durable and has new data.
-    if (CookiesDatabase::isUpdate(newCookie))
-        CookiesDatabase::updateCookie(newCookie);
+    tabWidgetPointer->loadInitialWebsite();
 }
 
 void BrowserWindow::addOrEditDomainSettings() const
@@ -317,8 +301,11 @@ void BrowserWindow::addOrEditDomainSettings() const
     // Create the domain settings dialog pointer.
     DomainSettingsDialog *domainSettingsDialogPointer;
 
+    // Get the current domain settings name.
+    QString &currentDomainSettingsName = tabWidgetPointer->getDomainSettingsName();
+
     // Run the commands according to the current domain settings status.
-    if (currentDomainSettingsDomain == "")  // Domain settings are not currently applied.
+    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());
@@ -326,7 +313,7 @@ void BrowserWindow::addOrEditDomainSettings() const
     else  // Domain settings are currently applied.
     {
         // Instruct the domain settings dialog to edit the current domain.
-        domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsDomain);
+        domainSettingsDialogPointer = new DomainSettingsDialog(DomainSettingsDialog::EDIT_DOMAIN, currentDomainSettingsName);
     }
 
     // Set the dialog window title.
@@ -339,7 +326,7 @@ void BrowserWindow::addOrEditDomainSettings() const
     domainSettingsDialogPointer->show();
 
     // Reload the tabs when domain settings are updated.
-    connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), browserViewPointer, SLOT(applyDomainSettingsAndReload()));
+    connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
 }
 
 void BrowserWindow::back() const
@@ -348,7 +335,7 @@ void BrowserWindow::back() const
     urlLineEditPointer->clearFocus();
 
     // Go back.
-    browserViewPointer->back();
+    tabWidgetPointer->back();
 }
 
 void BrowserWindow::clearUrlLineEditFocus() const
@@ -376,7 +363,7 @@ void BrowserWindow::forward() const
     urlLineEditPointer->clearFocus();
 
     // Go forward.
-    browserViewPointer->forward();
+    tabWidgetPointer->forward();
 }
 
 void BrowserWindow::fullScreenRequested(const bool toggleOn)
@@ -391,6 +378,7 @@ void BrowserWindow::fullScreenRequested(const bool toggleOn)
         menuBar()->setVisible(false);
         navigationToolBarPointer->setVisible(false);
         urlToolBarPointer->setVisible(false);
+        tabWidgetPointer->setTabBarVisible(false);
         statusBar()->setVisible(false);
     }
     else  // Turn full screen mode off.
@@ -402,6 +390,7 @@ void BrowserWindow::fullScreenRequested(const bool toggleOn)
         menuBar()->setVisible(true);
         navigationToolBarPointer->setVisible(true);
         urlToolBarPointer->setVisible(true);
+        tabWidgetPointer->setTabBarVisible(true);
         statusBar()->setVisible(true);
     }
 }
@@ -423,7 +412,7 @@ void BrowserWindow::getZoomFactorFromUser()
         currentZoomFactor = newZoomFactor;
 
         // Set the new zoom factor.
-        browserViewPointer->applyOnTheFlyZoomFactor(newZoomFactor);
+        tabWidgetPointer->applyOnTheFlyZoomFactor(newZoomFactor);
 
         // Update the on-the-fly action text.
         updateZoomFactorAction(newZoomFactor);
@@ -436,7 +425,7 @@ void BrowserWindow::home() const
     urlLineEditPointer->clearFocus();
 
     // Go home.
-    browserViewPointer->home();
+    tabWidgetPointer->home();
 }
 
 void BrowserWindow::loadUrlFromLineEdit(const QString &url) const
@@ -445,7 +434,7 @@ void BrowserWindow::loadUrlFromLineEdit(const QString &url) const
     urlLineEditPointer->clearFocus();
 
     // Load the URL.
-    browserViewPointer->loadUrlFromLineEdit(url);
+    tabWidgetPointer->loadUrlFromLineEdit(url);
 }
 
 void BrowserWindow::refresh() const
@@ -454,18 +443,7 @@ void BrowserWindow::refresh() const
     urlLineEditPointer->clearFocus();
 
     // Refresh the web page.
-    browserViewPointer->refresh();
-}
-
-void BrowserWindow::removeCookieFromList(const QNetworkCookie &cookie) const
-{
-    //qDebug() << "Remove cookie:  " << cookie.toRawForm();
-
-    // Remove the cookie from the list.
-    cookieListPointer->remove(cookie);
-
-    // Update the action text.
-    cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", cookieListPointer->size()));
+    tabWidgetPointer->refresh();
 }
 
 void BrowserWindow::showCookiesDialog()
@@ -474,15 +452,15 @@ void BrowserWindow::showCookiesDialog()
     urlLineEditPointer->clearFocus();
 
     // Instantiate the cookie settings dialog.
-    CookiesDialog *cookiesDialogPointer = new CookiesDialog(cookieListPointer);
+    CookiesDialog *cookiesDialogPointer = new CookiesDialog(tabWidgetPointer->getCookieList());
 
     // Show the dialog.
     cookiesDialogPointer->show();
 
     // Connect the dialog signals.
-    connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), browserViewPointer, SLOT(addCookieToStore(QNetworkCookie)));
-    connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), browserViewPointer, SLOT(deleteAllCookies()));
-    connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), browserViewPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
+    connect(cookiesDialogPointer, SIGNAL(addCookie(QNetworkCookie)), tabWidgetPointer, SLOT(addCookieToStore(QNetworkCookie)));
+    connect(cookiesDialogPointer, SIGNAL(deleteAllCookies()), tabWidgetPointer, SLOT(deleteAllCookies()));
+    connect(cookiesDialogPointer, SIGNAL(deleteCookie(QNetworkCookie)), tabWidgetPointer, SLOT(deleteCookieFromStore(QNetworkCookie)));
 }
 
 void BrowserWindow::showDownloadLocationBrowseDialog() const
@@ -522,7 +500,7 @@ void BrowserWindow::showDomainSettingsDialog() const
     domainSettingsDialogPointer->show();
 
     // Reload the tabs when domain settings are updated.
-    connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), browserViewPointer, SLOT(applyDomainSettingsAndReload()));
+    connect(domainSettingsDialogPointer, SIGNAL(domainSettingsUpdated()), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
 }
 
 void BrowserWindow::showProgressBar(const int &progress) const
@@ -590,8 +568,8 @@ void BrowserWindow::showSettingsDialog()
     configDialogPointer->resize(1000, 500);
 
     // Apply the settings when they are updated.
-    connect(configDialogPointer, SIGNAL(settingsChanged(QString)), browserViewPointer, SLOT(applyApplicationSettings()));
-    connect(configDialogPointer, SIGNAL(settingsChanged(QString)), browserViewPointer, SLOT(applyDomainSettingsAndReload()));
+    connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyApplicationSettings()));
+    connect(configDialogPointer, SIGNAL(settingsChanged(QString)), tabWidgetPointer, SLOT(applyDomainSettingsAndReload()));
 }
 
 QSize BrowserWindow::sizeHint() const
@@ -606,7 +584,7 @@ void BrowserWindow::toggleDomStorage() const
     urlLineEditPointer->clearFocus();
 
     // Toggle DOM storage.
-    browserViewPointer->toggleDomStorage();
+    tabWidgetPointer->toggleDomStorage();
 }
 
 void BrowserWindow::toggleJavaScript() const
@@ -615,7 +593,7 @@ void BrowserWindow::toggleJavaScript() const
     urlLineEditPointer->clearFocus();
 
     // Toggle JavaScript.
-    browserViewPointer->toggleJavaScript();
+    tabWidgetPointer->toggleJavaScript();
 }
 
 void BrowserWindow::toggleLocalStorage() const
@@ -624,7 +602,7 @@ void BrowserWindow::toggleLocalStorage() const
     urlLineEditPointer->clearFocus();
 
     // Toggle local storage.
-    browserViewPointer->toggleLocalStorage();
+    tabWidgetPointer->toggleLocalStorage();
 }
 
 void BrowserWindow::toggleFullScreen()
@@ -646,6 +624,10 @@ void BrowserWindow::toggleFullScreen()
             urlToolBarPointer->setVisible(false);
         }
 
+        // Hide the tab bar if specified.
+        if (Settings::fullScreenHideTabBar())
+            tabWidgetPointer->setTabBarVisible(false);
+
         // Hide the status bar if specified.
         if (Settings::fullScreenHideStatusBar())
             statusBar()->setVisible(false);
@@ -662,27 +644,33 @@ void BrowserWindow::toggleFullScreen()
         navigationToolBarPointer->setVisible(true);
         urlToolBarPointer->setVisible(true);
 
+        // Show the tab bar.
+        tabWidgetPointer->setTabBarVisible(true);
+
         // Show the status bar.
         statusBar()->setVisible(true);
     }
 }
 
+void BrowserWindow::updateCookiesAction(const int numberOfCookies) const
+{
+    // Update the action text.
+    cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", numberOfCookies));
+}
+
 void BrowserWindow::updateDomStorageAction(const bool &isEnabled) const
 {
     // Set the action checked status.
     domStorageActionPointer->setChecked(isEnabled);
 }
 
-void BrowserWindow::updateDomainSettingsIndicator(const bool &status, const QString &domainSettingsDomain)
+void BrowserWindow::updateDomainSettingsIndicator(const bool status)
 {
     // Set the domain palette according to the status.
     if (status)
         urlLineEditPointer->setPalette(domainSettingsPalette);
     else
         urlLineEditPointer->setPalette(noDomainSettingsPalette);
-
-    // Store the domain.
-    currentDomainSettingsDomain = domainSettingsDomain;
 }
 
 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
@@ -823,7 +811,7 @@ void BrowserWindow::updateUserAgentActions(const QString &userAgent, const bool
         // Update the user agent menu action text.
         userAgentMenuActionPointer->setText(i18nc("The main user agent menu action", "User Agent - Privacy Browser"));
     }
-    else if (userAgent == BrowserView::webEngineDefaultUserAgent)  // WebEngine default.
+    else if (userAgent == TabWidget::webEngineDefaultUserAgent)  // WebEngine default.
     {
         // check the WebEngine default user agent action.
         userAgentWebEngineDefaultActionPointer->setChecked(true);
@@ -935,8 +923,15 @@ void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl)
     // Update the URL line edit if it does not have focus.
     if (!urlLineEditPointer->hasFocus())
     {
+        // Get the new URL string.
+        QString newUrlString = newUrl.toString();
+
         // Update the URL line edit.
-        urlLineEditPointer->setText(newUrl.toString());
+        urlLineEditPointer->setText(newUrlString);
+
+        // Set the focus if the new URL is blank.
+        if (newUrlString == QStringLiteral(""))
+            urlLineEditPointer->setFocus();
     }
 
     // Store the current URL.
index a405b6c957ea947b2d7f3c111fe5bfafbf1dac18..39b8e8f5ea7e0caffacf2aa67a8706f77f7768f7 100644 (file)
@@ -21,7 +21,7 @@
 #define BROWSERWINDOW_H
 
 // Application headers.
-#include "views/BrowserView.h"
+#include "widgets/TabWidget.h"
 
 // KDE Frameworks headers.
 #include <KConfigDialog>
@@ -33,9 +33,6 @@
 #include <QLabel>
 #include <QProgressBar>
 
-// C++ headers.
-#include <list>
-
 class BrowserWindow : public KXmlGuiWindow
 {
     // Include the Q_OBJECT macro.
@@ -50,7 +47,6 @@ public:
 
 private Q_SLOTS:
     // The private slots.
-    void addCookieToList(const QNetworkCookie &newCookie) const;
     void addOrEditDomainSettings() const;
     void back() const;
     void clearUrlLineEditFocus() const;
@@ -62,7 +58,6 @@ private Q_SLOTS:
     void home() const;
     void loadUrlFromLineEdit(const QString &url) const;
     void refresh() const;
-    void removeCookieFromList(const QNetworkCookie &cookie) const;
     void showCookiesDialog();
     void showDownloadLocationBrowseDialog() const;
     void showDomainSettingsDialog() const;
@@ -72,8 +67,9 @@ private Q_SLOTS:
     void toggleJavaScript() const;
     void toggleLocalStorage() const;
     void toggleFullScreen();
+    void updateCookiesAction(const int numberOfCookies) const;
     void updateDomStorageAction(const bool &isEnabled) const;
-    void updateDomainSettingsIndicator(const bool &status, const QString &domainSettingsDomain);
+    void updateDomainSettingsIndicator(const bool status);
     void updateJavaScriptAction(const bool &isEnabled);
     void updateLocalStorageAction(const bool &isEnabled);
     void updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus);
@@ -85,11 +81,8 @@ private Q_SLOTS:
 
 private:
     // The private variables.
-    BrowserView *browserViewPointer;
     KConfigDialog *configDialogPointer;
-    std::list<QNetworkCookie> *cookieListPointer;
     QAction *cookiesActionPointer;
-    QString currentDomainSettingsDomain;
     QUrl currentUrl;
     double currentZoomFactor;
     bool customSearchEngineEnabled;
@@ -114,6 +107,7 @@ private:
     QAction *searchEngineBingActionPointer;
     QAction *searchEngineYahooActionPointer;
     QAction *searchEngineCustomActionPointer;
+    TabWidget *tabWidgetPointer;
     QLabel *userAgentLabelPointer;
     QAction *userAgentMenuActionPointer;
     QAction *userAgentPrivacyBrowserActionPointer;