X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserPC.git;a=blobdiff_plain;f=src%2Fwidgets%2FTabWidget.cpp;h=9e843ef306da564f362d7c5e434a0589b7dda21d;hp=84cd3aca089de34bcd188e3e5baa006508254595;hb=refs%2Fheads%2Fmaster;hpb=e715eca23297fb10dcf70e4c8bb2712413d16e3d diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index 84cd3ac..0728ecc 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -1,7 +1,7 @@ /* - * Copyright 2022-2023 Soren Stoutner . + * Copyright 2022-2024 Soren Stoutner . * - * This file is part of Privacy Browser PC . + * 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 @@ -18,9 +18,11 @@ */ // Application headers. +#include "DevToolsWebEngineView.h" #include "TabWidget.h" #include "Settings.h" #include "ui_AddTabWidget.h" +#include "ui_Tab.h" #include "ui_TabWidget.h" #include "databases/CookiesDatabase.h" #include "dialogs/SaveDialog.h" @@ -127,11 +129,16 @@ TabWidget::~TabWidget() // Manually delete each WebEngine page. for (int i = 0; i < numberOfTabs; ++i) { - // Get the privacy WebEngine view. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + // Get the tab splitter widget. + QWidget *tabSplitterWidgetPointer = qTabWidgetPointer->widget(i); - // Deletion the WebEngine page to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` + // Get the WebEngine views. + PrivacyWebEngineView *privacyWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); + DevToolsWebEngineView *devToolsWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); + + // Deletion the WebEngine pages to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` delete privacyWebEngineViewPointer->page(); + delete devToolsWebEngineViewPointer->page(); } } @@ -171,25 +178,55 @@ void TabWidget::addFirstTab() qTabWidgetPointer->currentWidget()->setFocus(); } -PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab, const QString urlString) +PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool adjacent, const bool backgroundTab, const QString urlString) { - // Create a privacy WebEngine view. + // Create a splitter widget. + QSplitter *splitterPointer = new QSplitter(); + + // Set the splitter to be vertical. + splitterPointer->setOrientation(Qt::Vertical); + + // Set the splitter handle size. + splitterPointer->setHandleWidth(5); + + // Create the WebEngines. PrivacyWebEngineView *privacyWebEngineViewPointer = new PrivacyWebEngineView(); + DevToolsWebEngineView *devToolsWebEngineViewPointer = new DevToolsWebEngineView(); + + // Add the WebEngines to the splitter. + splitterPointer->addWidget(privacyWebEngineViewPointer); + splitterPointer->addWidget(devToolsWebEngineViewPointer); + + // Initialize the new tab index. + int newTabIndex = 0; // Add a new tab. - int newTabIndex = qTabWidgetPointer->addTab(privacyWebEngineViewPointer, i18nc("New tab label.", "New Tab")); + if (adjacent) // Add the new tab adjacent to the current tab. + newTabIndex = qTabWidgetPointer->insertTab((qTabWidgetPointer->currentIndex() + 1), splitterPointer, i18nc("New tab label.", "New Tab")); + else // Add the new tab at the end of the list. + newTabIndex = qTabWidgetPointer->addTab(splitterPointer, i18nc("New tab label.", "New Tab")); // Set the default tab icon. qTabWidgetPointer->setTabIcon(newTabIndex, defaultFavoriteIcon); - // Get handles for the WebEngine page and profile. + // Get handles for the WebEngine components. QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page(); QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile(); - - // Get handles for the web engine elements. QWebEngineCookieStore *webEngineCookieStorePointer = webEngineProfilePointer->cookieStore(); QWebEngineSettings *webEngineSettingsPointer = webEnginePagePointer->settings(); + // Set the development tools WebEngine. This must be done here to preserve the bottom half of the window as the initial development tools size. + webEnginePagePointer->setDevToolsPage(devToolsWebEngineViewPointer->page()); + + // Initially hide the development tools WebEngine. + devToolsWebEngineViewPointer->setVisible(false); + + // Initially disable the development tools WebEngine. + webEnginePagePointer->setDevToolsPage(nullptr); + + // Disable JavaScript on the development tools WebEngine to prevent error messages from being written to the console. + devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); + // Update the URL line edit when the URL changes. connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [this, privacyWebEngineViewPointer] (const QUrl &newUrl) { @@ -206,10 +243,10 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Update the title when it changes. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, privacyWebEngineViewPointer] (const QString &title) + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::titleChanged, [this, splitterPointer] (const QString &title) { // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Update the title for this tab. qTabWidgetPointer->setTabText(tabIndex, title); @@ -220,10 +257,10 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Connect the loading favorite icon movie to the tab icon. - connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, privacyWebEngineViewPointer] + connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, splitterPointer, privacyWebEngineViewPointer] { // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Display the loading favorite icon if this tab is loading. if (privacyWebEngineViewPointer->isLoading) @@ -231,7 +268,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Update the icon when it changes. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon) + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, splitterPointer, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon) { // Store the favorite icon in the privacy web engine view. if (newFavoriteIcon.isNull()) @@ -240,7 +277,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const privacyWebEngineViewPointer->favoriteIcon = newFavoriteIcon; // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Update the icon for this tab. if (newFavoriteIcon.isNull()) @@ -278,7 +315,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const }); // Update the progress bar when a load finishes. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, privacyWebEngineViewPointer] () + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, splitterPointer, privacyWebEngineViewPointer] () { // Set the privacy web engine view to be not loading. privacyWebEngineViewPointer->isLoading = false; @@ -291,7 +328,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const emit hideProgressBar(); // Get the index for this tab. - int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer); + int tabIndex = qTabWidgetPointer->indexOf(splitterPointer); // Display the current favorite icon qTabWidgetPointer->setTabIcon(tabIndex, privacyWebEngineViewPointer->favoriteIcon); @@ -306,7 +343,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const for (int i = 0; i < numberOfTabs; i++) { // Get the privacy WebEngine view for the tab. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Check to see if it is currently loading. If at least one tab is loading, this flag will end up being marked `false` when the for loop has finished. if (privacyWebEngineViewPointer->isLoading) @@ -415,12 +452,20 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const // Plugins must be enabled for the PDF viewer to work. webEngineSettingsPointer->setAttribute(QWebEngineSettings::PluginsEnabled, true); + // Update the blocked requests action. + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::requestBlocked, [this, privacyWebEngineViewPointer] (const int blockedRequests) + { + // Update the blocked requests action if the specified privacy WebEngine view is the current privacy WebEngine view. + if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer) + emit blockedRequestsUpdated(blockedRequests); + }); + // Update the cookies action. - connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::updateCookiesAction, [this, privacyWebEngineViewPointer] (const int numberOfCookies) + connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::numberOfCookiesChanged, [this, privacyWebEngineViewPointer] (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); + emit cookiesChanged(numberOfCookies); }); // Process cookie changes. @@ -475,7 +520,7 @@ void TabWidget::applyApplicationSettings() // Apply the spatial navigation settings to each WebEngine. for (int i = 0; i < numberOfTabs; ++i) { // Get the WebEngine view pointer. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Apply the spatial navigation settings to each page. privacyWebEngineViewPointer->page()->settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation()); @@ -496,7 +541,7 @@ void TabWidget::applyDomainSettingsAndReload() // Apply the domain settings to each WebEngine. for (int i = 0; i < numberOfTabs; ++i) { // Get the WebEngine view pointer. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Apply the spatial navigation settings to each page. privacyWebEngineViewPointer->applyDomainSettings(privacyWebEngineViewPointer->url().host(), true); @@ -536,10 +581,10 @@ void TabWidget::applyOnTheFlyUserAgent(QAction *userAgentActionPointer) const currentPrivacyWebEngineViewPointer->reload(); } -void TabWidget::applyOnTheFlyZoomFactor(const double &zoomFactor) const +void TabWidget::applyOnTheFlyZoomFactor(const double zoomFactorDouble) const { // Set the zoom factor. - currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactor); + currentPrivacyWebEngineViewPointer->setZoomFactor(zoomFactorDouble); } void TabWidget::applySpellCheckLanguages() const @@ -551,7 +596,7 @@ void TabWidget::applySpellCheckLanguages() const for (int i = 0; i < numberOfTabs; ++i) { // Get the WebEngine view pointer. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(i)); + PrivacyWebEngineView *privacyWebEngineViewPointer = qTabWidgetPointer->widget(i)->findChild(); // Get the WebEngine page pointer. QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page(); @@ -584,20 +629,29 @@ void TabWidget::deleteCookieFromStore(const QNetworkCookie &cookie) const void TabWidget::deleteTab(const int tabIndex) { - // Get the privacy WebEngine view. - PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->widget(tabIndex)); + // Get the tab splitter widget. + QWidget *tabSplitterWidgetPointer = qTabWidgetPointer->widget(tabIndex); + + // Get the WebEngine views. + PrivacyWebEngineView *privacyWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); + DevToolsWebEngineView *devToolsWebEngineViewPointer = tabSplitterWidgetPointer->findChild(); // Process the tab delete according to the number of tabs. if (qTabWidgetPointer->count() > 1) // There is more than one tab. { - // Delete the tab. + // Remove the tab. qTabWidgetPointer->removeTab(tabIndex); - // Delete the WebEngine page to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` + // Delete the WebEngine pages to prevent the following error: `Release of profile requested but WebEnginePage still not deleted. Expect troubles !` delete privacyWebEngineViewPointer->page(); + delete devToolsWebEngineViewPointer->page(); - // Delete the privacy WebEngine view. + // Delete the WebEngine views. delete privacyWebEngineViewPointer; + delete devToolsWebEngineViewPointer; + + // Delete the tab splitter widget. + delete tabSplitterWidgetPointer; } else // There is only one tab. { @@ -691,6 +745,12 @@ QString TabWidget::getCurrentTabUrl() const return currentPrivacyWebEngineViewPointer->url().toString(); } +QString TabWidget::getCurrentUserAgent() const +{ + // Return the current WebEngine user agent. + return currentWebEngineProfilePointer->httpUserAgent(); +} + QString& TabWidget::getDomainSettingsName() const { // Return the domain settings name. @@ -854,6 +914,9 @@ void TabWidget::printWebpage(QPrinter *printerPointer) const void TabWidget::refresh() const { + // Reset the HTTP authentication dialog counter. + currentPrivacyWebEngineViewPointer->httpAuthenticationDialogsDisplayed = 0; + // Reload the website. currentPrivacyWebEngineViewPointer->reload(); } @@ -864,6 +927,35 @@ void TabWidget::reloadAndBypassCache() const currentWebEnginePagePointer->triggerAction(QWebEnginePage::ReloadAndBypassCache); } +void TabWidget::saveArchive() +{ + // Get the suggested file name. + QString suggestedFileName = currentPrivacyWebEngineViewPointer->title() + ".mht"; + + // Get the download directory. + QString downloadDirectory = Settings::downloadDirectory(); + + // Resolve the system download directory if specified. + if (downloadDirectory == QLatin1String("System Download Directory")) + downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + + // Get a file path from the file picker. + QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName); + + // Save the webpage as an archive if the file save path is populated. + if (!saveFilePath.isEmpty()) + { + // Update the download directory if specified. + if (Settings::autoUpateDownloadDirectory()) + updateDownloadDirectory(saveFilePath); + + // Set the saving archive flag. Otherwise, a second download tries to run. + savingArchive = true; + + // Save the archive. + currentWebEnginePagePointer->save(saveFilePath); + } +} void TabWidget::setTabBarVisible(const bool visible) const { @@ -873,162 +965,211 @@ void TabWidget::setTabBarVisible(const bool visible) const void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPointer) { - // Get the download attributes. - QUrl downloadUrl = webEngineDownloadItemPointer->url(); - QString mimeTypeString = webEngineDownloadItemPointer->mimeType(); - QString suggestedFileName = webEngineDownloadItemPointer->suggestedFileName(); - int totalBytes = webEngineDownloadItemPointer->totalBytes(); - - // Check to see if Privacy Browser is not running KDE or if local storage (cookies) is enabled. - if (!isRunningKde || currentPrivacyWebEngineViewPointer->localStorageEnabled) // KDE is not running or local storage (cookies) is enabled. Use WebEngine's downloader. + // Only show the save dialog if an archive is not currently being saved. Otherwise, two save dialogs will be shown. + if (!savingArchive) { - // Instantiate the save dialog. - SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes); + // Get the download attributes. + QUrl downloadUrl = webEngineDownloadItemPointer->url(); + QString mimeTypeString = webEngineDownloadItemPointer->mimeType(); + QString suggestedFileName = webEngineDownloadItemPointer->suggestedFileName(); + int totalBytes = webEngineDownloadItemPointer->totalBytes(); + + // Check to see if Privacy Browser is not running KDE or if local storage (cookies) is enabled. + if (!isRunningKde || currentPrivacyWebEngineViewPointer->localStorageEnabled) // KDE is not running or local storage (cookies) is enabled. Use WebEngine's downloader. + { + // Instantiate the save dialog. + SaveDialog *saveDialogPointer = new SaveDialog(this, downloadUrl, mimeTypeString, totalBytes); - // Display the save dialog. - int saveDialogResult = saveDialogPointer->exec(); + // Display the save dialog. + int saveDialogResult = saveDialogPointer->exec(); - // Process the save dialog results. - if (saveDialogResult == QDialog::Accepted) // Save was selected. - { - // Get the download directory. - QString downloadDirectory = Settings::downloadLocation(); + // Process the save dialog results. + if (saveDialogResult == QDialog::Accepted) // Save was selected. + { + // Get the download directory. + QString downloadDirectory = Settings::downloadDirectory(); - // Resolve the system download directory if specified. - if (downloadDirectory == QLatin1String("System Download Directory")) - downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + // Resolve the system download directory if specified. + if (downloadDirectory == QLatin1String("System Download Directory")) + downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); - // Get a file path from the file picker. - QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName); + // Get a file path from the file picker. + QString saveFilePath = QFileDialog::getSaveFileName(this, i18nc("Save file dialog caption", "Save File"), downloadDirectory + QLatin1Char('/') + suggestedFileName); - // Process the save file path. - if (!saveFilePath.isEmpty()) // The file save path is populated. - { - // Create a save file path file info. - QFileInfo saveFilePathFileInfo = QFileInfo(saveFilePath); + // Process the save file path. + if (!saveFilePath.isEmpty()) // The file save path is populated. + { + // Update the download directory if specified. + if (Settings::autoUpateDownloadDirectory()) + updateDownloadDirectory(saveFilePath); - // Get the canonical save path and file name. - QString absoluteSavePath = saveFilePathFileInfo.absolutePath(); - QString saveFileName = saveFilePathFileInfo.fileName(); + // Create a save file path file info. + QFileInfo saveFilePathFileInfo = QFileInfo(saveFilePath); - // Set the download directory and file name. - webEngineDownloadItemPointer->setDownloadDirectory(absoluteSavePath); - webEngineDownloadItemPointer->setDownloadFileName(saveFileName); + // Get the canonical save path and file name. + QString absoluteSavePath = saveFilePathFileInfo.absolutePath(); + QString saveFileName = saveFilePathFileInfo.fileName(); - // Create a file download notification. - KNotification *fileDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload")); + // Set the download directory and file name. + webEngineDownloadItemPointer->setDownloadDirectory(absoluteSavePath); + webEngineDownloadItemPointer->setDownloadFileName(saveFileName); + + // Create a file download notification. + KNotification *fileDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload")); - // Set the notification title. - fileDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download")); + // Set the notification title. + fileDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download")); - // Set the notification text. - fileDownloadNotificationPointer->setText(i18nc("Downloading notification text", "Downloading %1", saveFileName)); + // Set the notification text. + fileDownloadNotificationPointer->setText(i18nc("Downloading notification text", "Downloading %1", saveFileName)); - // Get the download icon from the theme. - QIcon downloadIcon = QIcon::fromTheme(QLatin1String("download"), QIcon::fromTheme(QLatin1String("document-save"))); + // Get the download icon from the theme. + QIcon downloadIcon = QIcon::fromTheme(QLatin1String("download"), QIcon::fromTheme(QLatin1String("document-save"))); - // Set the notification icon. - fileDownloadNotificationPointer->setIconName(downloadIcon.name()); + // Set the notification icon. + fileDownloadNotificationPointer->setIconName(downloadIcon.name()); - // Set the action list cancel button. - fileDownloadNotificationPointer->setActions(QStringList({i18nc("Download notification action","Cancel")})); + // Set the action list cancel button. + fileDownloadNotificationPointer->setActions(QStringList({i18nc("Download notification action","Cancel")})); - // Prevent the notification from being autodeleted if it is closed. Otherwise, the updates to the notification below cause a crash. - fileDownloadNotificationPointer->setAutoDelete(false); + // Prevent the notification from being autodeleted if it is closed. Otherwise, the updates to the notification below cause a crash. + fileDownloadNotificationPointer->setAutoDelete(false); - // Handle clicks on the cancel button. - connect(fileDownloadNotificationPointer, &KNotification::action1Activated, [webEngineDownloadItemPointer, saveFileName] () - { - // Cancel the download. - webEngineDownloadItemPointer->cancel(); + // Handle clicks on the cancel button. + connect(fileDownloadNotificationPointer, &KNotification::action1Activated, [webEngineDownloadItemPointer, saveFileName] () + { + // Cancel the download. + webEngineDownloadItemPointer->cancel(); - // Create a file download notification. - KNotification *canceledDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload")); + // Create a file download notification. + KNotification *canceledDownloadNotificationPointer = new KNotification(QLatin1String("FileDownload")); - // Set the notification title. - canceledDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download")); + // Set the notification title. + canceledDownloadNotificationPointer->setTitle(i18nc("Download notification title", "Download")); - // Set the new text. - canceledDownloadNotificationPointer->setText(i18nc("Download canceled notification", "%1 download canceled", saveFileName)); + // Set the new text. + canceledDownloadNotificationPointer->setText(i18nc("Download canceled notification", "%1 download canceled", saveFileName)); - // Set the notification icon. - canceledDownloadNotificationPointer->setIconName(QLatin1String("download")); + // Set the notification icon. + canceledDownloadNotificationPointer->setIconName(QLatin1String("download")); - // Display the notification. - canceledDownloadNotificationPointer->sendEvent(); - }); + // Display the notification. + canceledDownloadNotificationPointer->sendEvent(); + }); - // Update the notification when the download progresses. - connect(webEngineDownloadItemPointer, &QWebEngineDownloadItem::downloadProgress, [fileDownloadNotificationPointer, saveFileName] (qint64 bytesReceived, qint64 totalBytes) - { - // Set the new text. Total bytes will be 0 if the download size is unknown. - if (totalBytes > 0) + // Update the notification when the download progresses. + connect(webEngineDownloadItemPointer, &QWebEngineDownloadItem::downloadProgress, [fileDownloadNotificationPointer, saveFileName] (qint64 bytesReceived, qint64 totalBytes) { - // Calculate the download percentage. - int downloadPercentage = 100 * bytesReceived / totalBytes; - - // Set the file download notification text. - fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1\% of %2 downloaded (%3 of %4 bytes)", downloadPercentage, saveFileName, - bytesReceived, totalBytes)); - } - else + // Set the new text. Total bytes will be 0 if the download size is unknown. + if (totalBytes > 0) + { + // Calculate the download percentage. + int downloadPercentage = 100 * bytesReceived / totalBytes; + + // Set the file download notification text. + fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1\% of %2 downloaded (%3 of %4 bytes)", downloadPercentage, saveFileName, + bytesReceived, totalBytes)); + } + else + { + // Set the file download notification text. + fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1: %2 bytes downloaded", saveFileName, bytesReceived)); + } + + // Display the updated notification. + fileDownloadNotificationPointer->update(); + }); + + // Update the notification when the download finishes. The save file name must be copied into the lambda or a crash occurs. + connect(webEngineDownloadItemPointer, &QWebEngineDownloadItem::finished, [fileDownloadNotificationPointer, saveFileName, saveFilePath] () { - // Set the file download notification text. - fileDownloadNotificationPointer->setText(i18nc("Download progress notification text", "%1: %2 bytes downloaded", saveFileName, bytesReceived)); - } + // Set the new text. + fileDownloadNotificationPointer->setText(i18nc("Download finished notification text", "%1 download finished", saveFileName)); - // Display the updated notification. - fileDownloadNotificationPointer->update(); - }); + // Set the URL so the file options will be displayed. + fileDownloadNotificationPointer->setUrls(QList {QUrl(saveFilePath)}); - // Update the notification when the download finishes. The save file name must be copied into the lambda or a crash occurs. - connect(webEngineDownloadItemPointer, &QWebEngineDownloadItem::finished, [fileDownloadNotificationPointer, saveFileName, saveFilePath] () - { - // Set the new text. - fileDownloadNotificationPointer->setText(i18nc("Download finished notification text", "%1 download finished", saveFileName)); - - // Set the URL so the file options will be displayed. - fileDownloadNotificationPointer->setUrls(QList {QUrl(saveFilePath)}); - - // Remove the actions from the notification. - fileDownloadNotificationPointer->setActions(QStringList()); + // Remove the actions from the notification. + fileDownloadNotificationPointer->setActions(QStringList()); - // Set the notification to disappear after a timeout. - fileDownloadNotificationPointer->setFlags(KNotification::CloseOnTimeout); + // Set the notification to disappear after a timeout. + fileDownloadNotificationPointer->setFlags(KNotification::CloseOnTimeout); - // Display the updated notification. - fileDownloadNotificationPointer->update(); - }); + // Display the updated notification. + fileDownloadNotificationPointer->update(); + }); - // Display the notification. - fileDownloadNotificationPointer->sendEvent(); + // Display the notification. + fileDownloadNotificationPointer->sendEvent(); - // Start the download. - webEngineDownloadItemPointer->accept(); + // Start the download. + webEngineDownloadItemPointer->accept(); + } + else // The file save path is not populated. + { + // Cancel the download. + webEngineDownloadItemPointer->cancel(); + } } - else // The file save path is not populated. + else // Cancel was selected. { // Cancel the download. webEngineDownloadItemPointer->cancel(); } } - else // Cancel was selected. + else // KDE is running and local storage (cookies) is disabled. Use KDE's native downloader. + // This must use the show command to launch a separate dialog which cancels WebEngine's automatic background download of the file to a temporary location. { - // Cancel the download. - webEngineDownloadItemPointer->cancel(); + // Instantiate the save dialog. `true` instructs it to use the native downloader + SaveDialog *saveDialogPointer = new SaveDialog(this, downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true); + + // Connect the save button. + connect(saveDialogPointer, SIGNAL(useNativeKdeDownloader(QUrl &, QString &)), this, SLOT(useNativeKdeDownloader(QUrl &, QString &))); + + // Show the dialog. + saveDialogPointer->show(); } } - else // KDE is running and local storage (cookies) is disabled. Use KDE's native downloader. - // This must use the show command to launch a separate dialog which cancels WebEngine's automatic background download of the file to a temporary location. + + // Reset the saving archive flag. + savingArchive = false; +} + +void TabWidget::stop() const +{ + // Stop the loading of the current privacy WebEngine. + currentPrivacyWebEngineViewPointer->stop(); +} + +void TabWidget::toggleDeveloperTools(const bool enabled) const +{ + // Get a handle for the current developer tools WebEngine. + DevToolsWebEngineView *devToolsWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild(); + + if (enabled) + { + // Set the zoom factor on the development tools WebEngine. + devToolsWebEngineViewPointer->setZoomFactor(currentWebEnginePagePointer->zoomFactor()); + + // Enable the development tools. + currentWebEnginePagePointer->setDevToolsPage(devToolsWebEngineViewPointer->page()); + + // Enable JavaScript on the development tools WebEngine. + devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + + // Display the developer tools. + devToolsWebEngineViewPointer->setVisible(true); + } + else { - // Instantiate the save dialog. `true` instructs it to use the native downloader - SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true); + // Disable JavaScript on the development tools WebEngine to prevent error messages from being written to the console. + devToolsWebEngineViewPointer->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); - // Connect the save button. - connect(saveDialogPointer, SIGNAL(useNativeKdeDownloader(QUrl &, QString &)), this, SLOT(useNativeKdeDownloader(QUrl &, QString &))); + // Disable the development tools. + currentWebEnginePagePointer->setDevToolsPage(nullptr); - // Show the dialog. - saveDialogPointer->show(); + // Hide the developer tools. + devToolsWebEngineViewPointer->setVisible(false); } } @@ -1083,6 +1224,21 @@ void TabWidget::toggleLocalStorage() currentPrivacyWebEngineViewPointer->reload(); } +void TabWidget::updateDownloadDirectory(QString newDownloadDirectory) const +{ + // Remove the file name from the save file path. + newDownloadDirectory.truncate(newDownloadDirectory.lastIndexOf(QLatin1Char('/'))); + + // Update the download location. + Settings::setDownloadDirectory(newDownloadDirectory); + + // Get a handle for the KConfig skeleton. + KConfigSkeleton *kConfigSkeletonPointer = Settings::self(); + + // Write the settings to disk. + kConfigSkeletonPointer->save(); +} + void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWebEngineViewPointer) const { // Only update the UI if the signal was emitted from the current privacy WebEngine. @@ -1102,7 +1258,7 @@ void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWeb void TabWidget::updateUiWithTabSettings() { // Update the current WebEngine pointers. - currentPrivacyWebEngineViewPointer = qobject_cast(qTabWidgetPointer->currentWidget()); + currentPrivacyWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild(); currentWebEngineSettingsPointer = currentPrivacyWebEngineViewPointer->settings(); currentWebEnginePagePointer = currentPrivacyWebEngineViewPointer->page(); currentWebEngineProfilePointer = currentWebEnginePagePointer->profile(); @@ -1112,10 +1268,15 @@ void TabWidget::updateUiWithTabSettings() // Clear the URL line edit focus. emit clearUrlLineEditFocus(); + // Get a handle for the development tools WebEngine view. + DevToolsWebEngineView *devToolsWebEngineViewPointer = qTabWidgetPointer->currentWidget()->findChild(); + // Update the actions. + emit blockedRequestsUpdated(currentPrivacyWebEngineViewPointer->blockedRequests); + emit cookiesChanged(currentPrivacyWebEngineViewPointer->cookieListPointer->size()); emit updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor); emit updateBackAction(currentWebEngineHistoryPointer->canGoBack()); - emit updateCookiesAction(currentPrivacyWebEngineViewPointer->cookieListPointer->size()); + emit updateDeveloperToolsAction(devToolsWebEngineViewPointer->isVisible()); emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled)); emit updateForwardAction(currentWebEngineHistoryPointer->canGoForward()); emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled)); @@ -1142,7 +1303,7 @@ void TabWidget::updateUiWithTabSettings() void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFileName) { // Get the download directory. - QString downloadDirectory = Settings::downloadLocation(); + QString downloadDirectory = Settings::downloadDirectory(); // Resolve the system download directory if specified. if (downloadDirectory == QLatin1String("System Download Directory")) @@ -1161,11 +1322,15 @@ void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFile saveFileDialogPointer->setWindowModality(Qt::WindowModal); // Process the saving of the file. The save file dialog pointer must be captured directly instead of by reference or nasty crashes occur. - auto saveFile = [saveFileDialogPointer, downloadUrl] () + auto saveFile = [saveFileDialogPointer, downloadUrl, this] () { // Get the save location. The dialog box should only allow the selecting of one file location. QUrl saveLocation = saveFileDialogPointer->selectedUrls().value(0); + // Update the download directory if specified. + if (Settings::autoUpateDownloadDirectory()) + updateDownloadDirectory(saveLocation.toLocalFile()); + // Create a file copy job. `-1` creates the file with default permissions. KIO::FileCopyJob *fileCopyJobPointer = KIO::file_copy(downloadUrl, saveLocation, -1, KIO::Overwrite);