From 0d23ee5e9b43b247cdda0a4cbb73f8b1a70f4500 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Thu, 14 Jul 2022 15:42:29 -0700 Subject: [PATCH] Implement tabbed browsing. --- src/CMakeLists.txt | 6 +- src/databases/CookiesDatabase.cpp | 6 +- src/helpers/UserAgentHelper.cpp | 6 +- src/settings/Settings.kcfg | 8 + src/structs/PrivacyWebEngine.cpp | 28 - src/uis/AddTabWidget.ui | 63 ++ src/uis/CookiesDialog.ui | 8 +- src/uis/SettingsGeneral.ui | 26 + src/uis/{BrowserView.ui => TabWidget.ui} | 38 +- src/views/BrowserView.cpp | 754 --------------- src/views/CMakeLists.txt | 22 - src/{structs => widgets}/CMakeLists.txt | 3 +- src/widgets/PrivacyWebEngineView.cpp | 51 + .../PrivacyWebEngineView.h} | 28 +- src/widgets/TabWidget.cpp | 888 ++++++++++++++++++ .../BrowserView.h => widgets/TabWidget.h} | 44 +- src/windows/BrowserWindow.cpp | 161 ++-- src/windows/BrowserWindow.h | 14 +- 18 files changed, 1209 insertions(+), 945 deletions(-) delete mode 100644 src/structs/PrivacyWebEngine.cpp create mode 100644 src/uis/AddTabWidget.ui rename src/uis/{BrowserView.ui => TabWidget.ui} (61%) delete mode 100644 src/views/BrowserView.cpp delete mode 100644 src/views/CMakeLists.txt rename src/{structs => widgets}/CMakeLists.txt (95%) create mode 100644 src/widgets/PrivacyWebEngineView.cpp rename src/{structs/PrivacyWebEngine.h => widgets/PrivacyWebEngineView.h} (57%) create mode 100644 src/widgets/TabWidget.cpp rename src/{views/BrowserView.h => widgets/TabWidget.h} (77%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 499230e..d80c89d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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. diff --git a/src/databases/CookiesDatabase.cpp b/src/databases/CookiesDatabase.cpp index 8464c06..207f45b 100644 --- a/src/databases/CookiesDatabase.cpp +++ b/src/databases/CookiesDatabase.cpp @@ -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; } diff --git a/src/helpers/UserAgentHelper.cpp b/src/helpers/UserAgentHelper.cpp index 634f16b..9727c31 100644 --- a/src/helpers/UserAgentHelper.cpp +++ b/src/helpers/UserAgentHelper.cpp @@ -20,7 +20,7 @@ // Application headers. #include "Settings.h" #include "UserAgentHelper.h" -#include "views/BrowserView.h" +#include "widgets/TabWidget.h" // KDE Framework headers. #include @@ -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. diff --git a/src/settings/Settings.kcfg b/src/settings/Settings.kcfg index 80726d2..04a74ca 100644 --- a/src/settings/Settings.kcfg +++ b/src/settings/Settings.kcfg @@ -62,6 +62,10 @@ System Download Directory + + true + + true @@ -70,6 +74,10 @@ true + + true + + true diff --git a/src/structs/PrivacyWebEngine.cpp b/src/structs/PrivacyWebEngine.cpp deleted file mode 100644 index 411ac93..0000000 --- a/src/structs/PrivacyWebEngine.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright © 2022 Soren Stoutner . - * - * This file is part of Privacy Browser PC . - * - * Privacy Browser PC is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Privacy Browser PC is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Privacy Browser PC. If not, see . - */ - -// Application headers. -#include "PrivacyWebEngine.h" - -// Construct the struct. -PrivacyWebEngine::PrivacyWebEngine(QWebEngineView *inputWebEngineViewPointer) : webEngineViewPointer(inputWebEngineViewPointer) -{ - // Initialize the local storage status. - localStorageEnabled = false; -} diff --git a/src/uis/AddTabWidget.ui b/src/uis/AddTabWidget.ui new file mode 100644 index 0000000..1a7177f --- /dev/null +++ b/src/uis/AddTabWidget.ui @@ -0,0 +1,63 @@ + + + + + + AddTabWidget + + + + + + + + + + + + + 5 + + + + 5 + + + + 5 + + + + 5 + + + + + + + + + + + + + + + + diff --git a/src/uis/CookiesDialog.ui b/src/uis/CookiesDialog.ui index d182c03..bd2c24f 100644 --- a/src/uis/CookiesDialog.ui +++ b/src/uis/CookiesDialog.ui @@ -45,7 +45,7 @@ - &Add cookie + Add cookie @@ -58,7 +58,7 @@ - &Edit cookie + Edit cookie @@ -71,7 +71,7 @@ - &Delete cookie + Delete cookie @@ -84,7 +84,7 @@ - Delete &all + Delete all diff --git a/src/uis/SettingsGeneral.ui b/src/uis/SettingsGeneral.ui index acd345c..223ec5b 100644 --- a/src/uis/SettingsGeneral.ui +++ b/src/uis/SettingsGeneral.ui @@ -192,6 +192,19 @@ + + + + + Tabs on top + + + + Display the tabs at the top of the screen. The default is enabled. + + + + @@ -226,6 +239,19 @@ + + + + + Hide tab bar + + + + Hide the tab bar when browsing full screen. The default is enabled. + + + + diff --git a/src/uis/BrowserView.ui b/src/uis/TabWidget.ui similarity index 61% rename from src/uis/BrowserView.ui rename to src/uis/TabWidget.ui index 26ba072..375f4d5 100644 --- a/src/uis/BrowserView.ui +++ b/src/uis/TabWidget.ui @@ -19,16 +19,13 @@ along with Privacy Browser PC. If not, see . --> - BrowserView - + TabWidget + + + - - - 0 - - 0 @@ -46,9 +43,32 @@ 0 - + - + + + + 24 + 24 + + + + + true + + + + true + + + + true + + + + Qt::ElideRight + + diff --git a/src/views/BrowserView.cpp b/src/views/BrowserView.cpp deleted file mode 100644 index f17a237..0000000 --- a/src/views/BrowserView.cpp +++ /dev/null @@ -1,754 +0,0 @@ -/* - * Copyright © 2022 Soren Stoutner . - * - * This file is part of Privacy Browser PC . - * - * Privacy Browser PC is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Privacy Browser PC is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Privacy Browser PC. If not, see . - */ - -// Application headers. -#include "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 -#include - -// Qt toolkit headers. -#include -#include -#include -#include -#include - -// Initialize the public static variables. -QString BrowserView::webEngineDefaultUserAgent = QStringLiteral(""); - -// Construct the class. -BrowserView::BrowserView(QWidget *parent) : QWidget(parent) -{ - // Initialize the variables. - privacyWebEngineListPointer = new QList; - - // 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 . - // 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 *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. - 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 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 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 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 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 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 has been resolved. -void BrowserView::applyOnTheFlyZoomFactor(const double &zoomFactor) -{ - // Update the current zoom factor. This can be removed once 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`. - // 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. - webEngineViewPointer->setZoomFactor(currentZoomFactor); -} diff --git a/src/views/CMakeLists.txt b/src/views/CMakeLists.txt deleted file mode 100644 index 2929781..0000000 --- a/src/views/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright © 2022 Soren Stoutner . -# -# This file is part of Privacy Browser PC . -# -# Privacy Browser PC is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Privacy Browser PC is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Privacy Browser PC. If not, see . - - -# List the sources to include in the executable. -target_sources(privacy-browser PRIVATE - BrowserView.cpp -) diff --git a/src/structs/CMakeLists.txt b/src/widgets/CMakeLists.txt similarity index 95% rename from src/structs/CMakeLists.txt rename to src/widgets/CMakeLists.txt index 9e6e2cb..afbc0de 100644 --- a/src/structs/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -18,5 +18,6 @@ # List the sources to include in the executable. target_sources(privacy-browser PRIVATE - PrivacyWebEngine.cpp + TabWidget.cpp + PrivacyWebEngineView.cpp ) diff --git a/src/widgets/PrivacyWebEngineView.cpp b/src/widgets/PrivacyWebEngineView.cpp new file mode 100644 index 0000000..28fb66d --- /dev/null +++ b/src/widgets/PrivacyWebEngineView.cpp @@ -0,0 +1,51 @@ +/* + * Copyright © 2022 Soren Stoutner . + * + * This file is part of Privacy Browser PC . + * + * Privacy Browser PC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser PC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser PC. If not, see . + */ + +// Application headers. +#include "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/structs/PrivacyWebEngine.h b/src/widgets/PrivacyWebEngineView.h similarity index 57% rename from src/structs/PrivacyWebEngine.h rename to src/widgets/PrivacyWebEngineView.h index 2d5035a..3869fc3 100644 --- a/src/structs/PrivacyWebEngine.h +++ b/src/widgets/PrivacyWebEngineView.h @@ -17,20 +17,34 @@ * along with Privacy Browser PC. If not, see . */ -#ifndef PRIVACYWEBENGINE_H -#define PRIVACYWEBENGINE_H +#ifndef PRIVACYWEBENGINEVIEW_H +#define PRIVACYWEBENGINEVIEW_H // Qt toolkit headers. +#include #include -struct PrivacyWebEngine +class PrivacyWebEngineView : public QWebEngineView { + // Include the Q_OBJECT macro. + Q_OBJECT + public: - // The primary constructor. - PrivacyWebEngine(QWebEngineView *inputWebEngineViewPointer); + // The default constructor. + explicit PrivacyWebEngineView(); // The public variables. - bool localStorageEnabled; - QWebEngineView *webEngineViewPointer; + std::list *cookieListPointer = new std::list; + 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 index 0000000..3b0ce08 --- /dev/null +++ b/src/widgets/TabWidget.cpp @@ -0,0 +1,888 @@ +/* + * Copyright © 2022 Soren Stoutner . + * + * This file is part of Privacy Browser PC . + * + * Privacy Browser PC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser PC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser PC. If not, see . + */ + +// Application headers. +#include "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 +#include + +// Qt toolkit headers. +#include +#include +#include +#include +#include +#include +#include + +// 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(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. + 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 *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 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 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 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 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 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 has been resolved. +void TabWidget::applyOnTheFlyZoomFactor(const double &zoomFactor) +{ + // Update the current zoom factor. This can be removed once 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(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* 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`. + // 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(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. + currentPrivacyWebEngineViewPointer->setZoomFactor(currentZoomFactor); +} diff --git a/src/views/BrowserView.h b/src/widgets/TabWidget.h similarity index 77% rename from src/views/BrowserView.h rename to src/widgets/TabWidget.h index 8007aa7..525c81a 100644 --- a/src/views/BrowserView.h +++ b/src/widgets/TabWidget.h @@ -17,38 +17,43 @@ * along with Privacy Browser PC. If not, see . */ -#ifndef BROWSERVIEW_H -#define BROWSERVIEW_H +#ifndef TABWIDGET_H +#define TABWIDGET_H // Application headers. -#include "structs/PrivacyWebEngine.h" +#include "PrivacyWebEngineView.h" // KDE Framework headers. #include // Qt toolkit headers. #include +#include +#include #include #include #include #include #include -class BrowserView : public QWidget +class TabWidget : public QWidget { // Include the Q_OBJECT macro. Q_OBJECT public: // The primary contructor. - explicit BrowserView(QWidget *parent); + explicit TabWidget(QWidget *parent); // The destructor. - ~BrowserView(); + ~TabWidget(); // The public functions. void applyOnTheFlyZoomFactor(const double &zoomFactor); void loadInitialWebsite(); + std::list* getCookieList() const; + QString& getDomainSettingsName() const; + void setTabBarVisible(const bool visible) const; void toggleDomStorage() const; void toggleJavaScript() const; void toggleLocalStorage(); @@ -66,8 +71,9 @@ signals: 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 QString &domainSettingsDomain) 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; @@ -78,7 +84,8 @@ signals: public Q_SLOTS: // The public slots. - void addCookieToStore(QNetworkCookie cookie) const; + void addTab(); + void addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer = nullptr) const; void applyApplicationSettings(); void applyDomainSettingsAndReload(); void applyDomainSettingsWithoutReloading(const QString &hostname); @@ -98,8 +105,8 @@ public Q_SLOTS: private Q_SLOTS: // The private slots. - void cookieAdded(const QNetworkCookie &cookie) const; - void cookieRemoved(const QNetworkCookie &cookie) const; + void addFirstTab(); + void deleteTab(const int tabIndex); void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const; void loadFinished() const; void loadProgress(const int &progress) const; @@ -108,20 +115,21 @@ private Q_SLOTS: 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 has been resolved. - PrivacyWebEngine *currentPrivacyWebEnginePointer; - QList *privacyWebEngineListPointer; + PrivacyWebEngineView *currentPrivacyWebEngineViewPointer; + QWebEngineCookieStore *currentWebEngineCookieStorePointer; + QWebEngineHistory *currentWebEngineHistoryPointer; + QWebEnginePage *currentWebEnginePagePointer; + QWebEngineProfile *currentWebEngineProfilePointer; + QWebEngineSettings *currentWebEngineSettingsPointer; + QIcon defaultTabIcon = QIcon::fromTheme(QStringLiteral("globe")); QString searchEngineUrl; - QWebEngineCookieStore *webEngineCookieStorePointer; - QWebEngineHistory *webEngineHistoryPointer; - QWebEnginePage *webEnginePagePointer; - QWebEngineProfile *webEngineProfilePointer; - QWebEngineSettings *webEngineSettingsPointer; - QWebEngineView *webEngineViewPointer; + QTabWidget *tabWidgetPointer; // The private functions. void applyDomainSettings(const QString &hostname, const bool reloadWebsite); diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index e44357f..8d24171 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -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" @@ -44,23 +43,22 @@ BrowserWindow::BrowserWindow() : KXmlGuiWindow() { // Initialize the variables. - cookieListPointer = new std::list; 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 ¤tDomainSettingsName = 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. diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index a405b6c..39b8e8f 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -21,7 +21,7 @@ #define BROWSERWINDOW_H // Application headers. -#include "views/BrowserView.h" +#include "widgets/TabWidget.h" // KDE Frameworks headers. #include @@ -33,9 +33,6 @@ #include #include -// C++ headers. -#include - 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 *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; -- 2.43.0