]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blobdiff - src/widgets/TabWidget.cpp
Additional fix for notifications on Xfce. https://redmine.stoutner.com/issues/1017
[PrivacyBrowserPC.git] / src / widgets / TabWidget.cpp
index 76ff617c3e180f3e253884d277dfd2a536f94dce..84cd3aca089de34bcd188e3e5baa006508254595 100644 (file)
 QString TabWidget::webEngineDefaultUserAgent = QLatin1String("");
 
 // Construct the class.
-TabWidget::TabWidget(QWidget *parent) : QWidget(parent)
+TabWidget::TabWidget(QWidget *windowPointer) : QWidget(windowPointer)
 {
+    // Create a QProcess to check if KDE is running.
+    QProcess *checkIfRunningKdeQProcessPointer = new QProcess();
+
+    // Create an argument string list that contains `ksmserver` (KDE Session Manager).
+    QStringList argument = QStringList(QLatin1String("ksmserver"));
+
+    // Run `pidof` to check for the presence of `ksmserver`.
+    checkIfRunningKdeQProcessPointer->start(QLatin1String("pidof"), argument);
+
+    // Monitor any standard output.
+    connect(checkIfRunningKdeQProcessPointer, &QProcess::readyReadStandardOutput, [this]
+    {
+        // If there is any standard output, `ksmserver` is running.
+        isRunningKde = true;
+    });
+
     // Instantiate the user agent helper.
     userAgentHelperPointer = new UserAgentHelper();
 
@@ -78,6 +94,9 @@ TabWidget::TabWidget(QWidget *parent) : QWidget(parent)
     // Set the loading favorite icon movie file name.
     loadingFavoriteIconMoviePointer->setFileName(QStringLiteral(":/icons/loading.gif"));
 
+    // Stop the loading favorite icon movie if the window is destroyed.  Otherwise, the app will crash if there is more than one window open and a window is closed while at tab is loading.
+    connect(windowPointer, SIGNAL(destroyed()), this, SLOT(stopLoadingFavoriteIconMovie()));
+
     // Add the first tab.
     addFirstTab();
 
@@ -102,8 +121,11 @@ TabWidget::TabWidget(QWidget *parent) : QWidget(parent)
 
 TabWidget::~TabWidget()
 {
+    // Get the number of tabs.
+    int numberOfTabs = qTabWidgetPointer->count();
+
     // Manually delete each WebEngine page.
-    for (int i = 0; i < qTabWidgetPointer->count(); ++i)
+    for (int i = 0; i < numberOfTabs; ++i)
     {
         // Get the privacy WebEngine view.
         PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
@@ -149,7 +171,7 @@ void TabWidget::addFirstTab()
     qTabWidgetPointer->currentWidget()->setFocus();
 }
 
-PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab)
+PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const bool backgroundTab, const QString urlString)
 {
     // Create a privacy WebEngine view.
     PrivacyWebEngineView *privacyWebEngineViewPointer = new PrivacyWebEngineView();
@@ -169,7 +191,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     QWebEngineSettings *webEngineSettingsPointer = webEnginePagePointer->settings();
 
     // Update the URL line edit when the URL changes.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [privacyWebEngineViewPointer, this] (const QUrl &newUrl)
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::urlChanged, [this, privacyWebEngineViewPointer] (const QUrl &newUrl)
     {
         // Only update the UI if this is the current tab.
         if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
@@ -198,7 +220,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     });
 
     // Connect the loading favorite icon movie to the tab icon.
-    connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [privacyWebEngineViewPointer, this]
+    connect(loadingFavoriteIconMoviePointer, &QMovie::frameChanged, [this, privacyWebEngineViewPointer]
     {
         // Get the index for this tab.
         int tabIndex = qTabWidgetPointer->indexOf(privacyWebEngineViewPointer);
@@ -209,7 +231,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     });
 
     // Update the icon when it changes.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [privacyWebEngineViewPointer, this] (const QIcon &newFavoriteIcon)
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::iconChanged, [this, privacyWebEngineViewPointer] (const QIcon &newFavoriteIcon)
     {
         // Store the favorite icon in the privacy web engine view.
         if (newFavoriteIcon.isNull())
@@ -228,7 +250,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     });
 
     // Update the progress bar and the favorite icon when a load is started.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadStarted, [privacyWebEngineViewPointer, this] ()
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadStarted, [this, privacyWebEngineViewPointer] ()
     {
         // Set the privacy web engine view to be loading.
         privacyWebEngineViewPointer->isLoading = true;
@@ -245,7 +267,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     });
 
     // Update the progress bar when a load progresses.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadProgress, [privacyWebEngineViewPointer, this] (const int progress)
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadProgress, [this, privacyWebEngineViewPointer] (const int progress)
     {
         // Store the load progress.
         privacyWebEngineViewPointer->loadProgressInt = progress;
@@ -256,7 +278,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     });
 
     // Update the progress bar when a load finishes.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [privacyWebEngineViewPointer, this] ()
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::loadFinished, [this, privacyWebEngineViewPointer] ()
     {
         // Set the privacy web engine view to be not loading.
         privacyWebEngineViewPointer->isLoading = false;
@@ -277,14 +299,17 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
         // Create a no tabs loading variable.
         bool noTabsLoading = true;
 
+        // Get the number of tabs.
+        int numberOfTabs = qTabWidgetPointer->count();
+
         // Check to see if any other tabs are loading.
-        for (int i = 0; i < qTabWidgetPointer->count(); i++)
+        for (int i = 0; i < numberOfTabs; i++)
         {
             // Get the privacy WebEngine view for the tab.
-            PrivacyWebEngineView *webEngineViewPointer = qobject_cast<PrivacyWebEngineView*>(qTabWidgetPointer->widget(i));
+            PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView*>(qTabWidgetPointer->widget(i));
 
-            // Check to see if it is currently loading.
-            if (webEngineViewPointer->isLoading)
+            // 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)
                 noTabsLoading = false;
         }
 
@@ -294,7 +319,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     });
 
     // Display HTTP Ping blocked dialogs.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::displayHttpPingBlockedDialog, [privacyWebEngineViewPointer, this] (const QString &httpPingUrl)
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::displayHttpPingBlockedDialog, [this, privacyWebEngineViewPointer] (const QString &httpPingUrl)
     {
         // Only display the HTTP Ping blocked dialog if this is the current tab.
         if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
@@ -319,12 +344,12 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
         }
     });
 
-    // Update the zoom factor when changed by CTRL-Scrolling.  This can be modified when <https://redmine.stoutner.com/issues/845> is fixed.
+    // Update the zoom actions when changed by CTRL-Scrolling.  This can be modified when <https://redmine.stoutner.com/issues/845> is fixed.
     connect(webEnginePagePointer, &QWebEnginePage::contentsSizeChanged, [webEnginePagePointer, this] ()
     {
-        // Only update the zoom factor action text if this is the current tab.
+        // Only update the zoom actions if this is the current tab.
         if (webEnginePagePointer == currentWebEnginePagePointer)
-            emit updateZoomFactorAction(webEnginePagePointer->zoomFactor());
+            emit updateZoomActions(webEnginePagePointer->zoomFactor());
     });
 
     // Display find text results.
@@ -372,8 +397,8 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     // Don't allow JavaScript to open windows.
     webEngineSettingsPointer->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
 
-    // Allow keyboard navigation.
-    webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, true);
+    // Allow keyboard navigation between links and input fields.
+    webEngineSettingsPointer->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation());
 
     // Enable full screen support.
     webEngineSettingsPointer->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
@@ -391,7 +416,7 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     webEngineSettingsPointer->setAttribute(QWebEngineSettings::PluginsEnabled, true);
 
     // Update the cookies action.
-    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::updateCookiesAction, [privacyWebEngineViewPointer, this] (const int numberOfCookies)
+    connect(privacyWebEngineViewPointer, &PrivacyWebEngineView::updateCookiesAction, [this, privacyWebEngineViewPointer] (const int numberOfCookies)
     {
         // Update the cookie action if the specified privacy WebEngine view is the current privacy WebEngine view.
         if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
@@ -429,6 +454,9 @@ PrivacyWebEngineView* TabWidget::addTab(const bool removeUrlLineEditFocus, const
     if (removeUrlLineEditFocus)
         emit clearUrlLineEditFocus();
 
+    if (urlString != nullptr)
+        privacyWebEngineViewPointer->load(QUrl::fromUserInput(urlString));
+
     // Return the privacy WebEngine view pointer.
     return privacyWebEngineViewPointer;
 }
@@ -441,6 +469,18 @@ void TabWidget::applyApplicationSettings()
     else
         qTabWidgetPointer->setTabPosition(QTabWidget::South);
 
+    // Get the number of tabs.
+    int numberOfTabs = qTabWidgetPointer->count();
+
+    // Apply the spatial navigation settings to each WebEngine.
+    for (int i = 0; i < numberOfTabs; ++i) {
+        // Get the WebEngine view pointer.
+        PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
+
+        // Apply the spatial navigation settings to each page.
+        privacyWebEngineViewPointer->page()->settings()->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, Settings::spatialNavigation());
+    }
+
     // Set the search engine URL.
     searchEngineUrl = SearchEngineHelper::getSearchUrl(Settings::searchEngine());
 
@@ -450,8 +490,17 @@ void TabWidget::applyApplicationSettings()
 
 void TabWidget::applyDomainSettingsAndReload()
 {
-    // Apply the domain settings.  `true` reloads the website.
-    currentPrivacyWebEngineViewPointer->applyDomainSettings(currentPrivacyWebEngineViewPointer->url().host(), true);
+    // Get the number of tabs.
+    int numberOfTabs = qTabWidgetPointer->count();
+
+    // Apply the domain settings to each WebEngine.
+    for (int i = 0; i < numberOfTabs; ++i) {
+        // Get the WebEngine view pointer.
+        PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
+
+        // Apply the spatial navigation settings to each page.
+        privacyWebEngineViewPointer->applyDomainSettings(privacyWebEngineViewPointer->url().host(), true);
+    }
 }
 
 void TabWidget::applyOnTheFlySearchEngine(QAction *searchEngineActionPointer)
@@ -502,10 +551,10 @@ void TabWidget::applySpellCheckLanguages() const
     for (int i = 0; i < numberOfTabs; ++i)
     {
         // Get the WebEngine view pointer.
-        PrivacyWebEngineView *webEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->currentWidget());
+        PrivacyWebEngineView *privacyWebEngineViewPointer = qobject_cast<PrivacyWebEngineView *>(qTabWidgetPointer->widget(i));
 
         // Get the WebEngine page pointer.
-        QWebEnginePage *webEnginePagePointer = webEngineViewPointer->page();
+        QWebEnginePage *webEnginePagePointer = privacyWebEngineViewPointer->page();
 
         // Get the WebEngine profile pointer.
         QWebEngineProfile *webEngineProfilePointer = webEnginePagePointer->profile();
@@ -587,7 +636,7 @@ void TabWidget::findText(const QString &text) const
 
 void TabWidget::findTextFinished(const QWebEngineFindTextResult &findTextResult)
 {
-    // Update the find text UI if it wasn't simply wiping the current find text selection.  Otherwise the UI temporarially flashes `0/0`.
+    // Update the find text UI if it wasn't simply wiping the current find text selection.  Otherwise the UI temporarily flashes `0/0`.
     if (wipingCurrentFindTextSelection)  // The current selection is being wiped.
     {
         // Reset the flag.
@@ -624,6 +673,24 @@ std::list<QNetworkCookie>* TabWidget::getCookieList() const
     return currentPrivacyWebEngineViewPointer->cookieListPointer;
 }
 
+QIcon TabWidget::getCurrentTabFavoritIcon() const
+{
+    // Return the current Privacy WebEngine favorite icon.
+    return currentPrivacyWebEngineViewPointer->favoriteIcon;
+}
+
+QString TabWidget::getCurrentTabTitle() const
+{
+    // Return the current Privacy WebEngine title.
+    return currentPrivacyWebEngineViewPointer->title();
+}
+
+QString TabWidget::getCurrentTabUrl() const
+{
+    // Return the current Privacy WebEngine URL as a string.
+    return currentPrivacyWebEngineViewPointer->url().toString();
+}
+
 QString& TabWidget::getDomainSettingsName() const
 {
     // Return the domain settings name.
@@ -669,7 +736,7 @@ void TabWidget::loadInitialWebsite()
 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.
+    if (url.startsWith("file://") || url.startsWith("view-source:"))  // The text is likely a file or view source URL.
     {
         // Load the URL.
         currentPrivacyWebEngineViewPointer->load(QUrl::fromUserInput(url));
@@ -725,6 +792,12 @@ void TabWidget::pageLinkHovered(const QString &linkUrl) const
     emit linkHovered(linkUrl);
 }
 
+void TabWidget::stopLoadingFavoriteIconMovie() const
+{
+    // Stop the loading favorite icon movie.  Otherwise, the browser will crash if a second window is closed while a tab in it is loading.  <https://redmine.stoutner.com/issues/1010>
+    loadingFavoriteIconMoviePointer->stop();
+}
+
 void TabWidget::print() const
 {
     // Create a printer.
@@ -785,6 +858,13 @@ void TabWidget::refresh() const
     currentPrivacyWebEngineViewPointer->reload();
 }
 
+void TabWidget::reloadAndBypassCache() const
+{
+    // Reload the website, bypassing the cache.
+    currentWebEnginePagePointer->triggerAction(QWebEnginePage::ReloadAndBypassCache);
+}
+
+
 void TabWidget::setTabBarVisible(const bool visible) const
 {
     // Set the tab bar visibility.
@@ -799,8 +879,8 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin
     QString suggestedFileName = webEngineDownloadItemPointer->suggestedFileName();
     int totalBytes = webEngineDownloadItemPointer->totalBytes();
 
-    // Check to see if local storage (cookies) is enabled.
-    if (currentPrivacyWebEngineViewPointer->localStorageEnabled)  // Local storage (cookies) is enabled.  Use WebEngine's downloader.
+    // 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(downloadUrl, mimeTypeString, totalBytes);
@@ -818,7 +898,7 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin
             if (downloadDirectory == QLatin1String("System Download Directory"))
                 downloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
 
-            // Display a save file dialog.
+            // 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.
@@ -844,21 +924,18 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin
                 // 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")));
+
                 // Set the notification icon.
-                fileDownloadNotificationPointer->setIconName(QLatin1String("download"));
+                fileDownloadNotificationPointer->setIconName(downloadIcon.name());
 
                 // Set the action list cancel button.
                 fileDownloadNotificationPointer->setActions(QStringList({i18nc("Download notification action","Cancel")}));
 
-                // Set the notification to display indefinitely.
-                fileDownloadNotificationPointer->setFlags(KNotification::Persistent);
-
                 // Prevent the notification from being autodeleted if it is closed.  Otherwise, the updates to the notification below cause a crash.
                 fileDownloadNotificationPointer->setAutoDelete(false);
 
-                // Display the notification.
-                fileDownloadNotificationPointer->sendEvent();
-
                 // Handle clicks on the cancel button.
                 connect(fileDownloadNotificationPointer, &KNotification::action1Activated, [webEngineDownloadItemPointer, saveFileName] ()
                 {
@@ -923,6 +1000,9 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin
                     fileDownloadNotificationPointer->update();
                 });
 
+                // Display the notification.
+                fileDownloadNotificationPointer->sendEvent();
+
                 // Start the download.
                 webEngineDownloadItemPointer->accept();
             }
@@ -938,14 +1018,14 @@ void TabWidget::showSaveDialog(QWebEngineDownloadItem *webEngineDownloadItemPoin
             webEngineDownloadItemPointer->cancel();
         }
     }
-    else  // Local storage (cookies) is disabled.  Use KDE's native downloader.
+    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.
     {
         // Instantiate the save dialog.  `true` instructs it to use the native downloader
         SaveDialog *saveDialogPointer = new SaveDialog(downloadUrl, mimeTypeString, totalBytes, suggestedFileName, true);
 
         // Connect the save button.
-        connect(saveDialogPointer, SIGNAL(useNativeDownloader(QUrl &, QString &)), this, SLOT(useNativeDownloader(QUrl &, QString &)));
+        connect(saveDialogPointer, SIGNAL(useNativeKdeDownloader(QUrl &, QString &)), this, SLOT(useNativeKdeDownloader(QUrl &, QString &)));
 
         // Show the dialog.
         saveDialogPointer->show();
@@ -1009,12 +1089,13 @@ void TabWidget::updateUiFromWebEngineView(const PrivacyWebEngineView *privacyWeb
     if (privacyWebEngineViewPointer == currentPrivacyWebEngineViewPointer)
     {
         // Update the UI.
+        emit updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor);
         emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QLatin1String(""));
         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 updateZoomActions(currentPrivacyWebEngineViewPointer->zoomFactor());
     }
 }
 
@@ -1032,6 +1113,7 @@ void TabWidget::updateUiWithTabSettings()
     emit clearUrlLineEditFocus();
 
     // Update the actions.
+    emit updateDefaultZoomFactor(currentPrivacyWebEngineViewPointer->defaultZoomFactor);
     emit updateBackAction(currentWebEngineHistoryPointer->canGoBack());
     emit updateCookiesAction(currentPrivacyWebEngineViewPointer->cookieListPointer->size());
     emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
@@ -1039,7 +1121,7 @@ void TabWidget::updateUiWithTabSettings()
     emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
     emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
     emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
-    emit updateZoomFactorAction(currentPrivacyWebEngineViewPointer->zoomFactor());
+    emit updateZoomActions(currentPrivacyWebEngineViewPointer->zoomFactor());
 
     // Update the URL.
     emit updateWindowTitle(currentPrivacyWebEngineViewPointer->title());
@@ -1057,7 +1139,7 @@ void TabWidget::updateUiWithTabSettings()
         emit hideProgressBar();
 }
 
-void TabWidget::useNativeDownloader(QUrl &downloadUrl, QString &suggestedFileName)
+void TabWidget::useNativeKdeDownloader(QUrl &downloadUrl, QString &suggestedFileName)
 {
     // Get the download directory.
     QString downloadDirectory = Settings::downloadLocation();
@@ -1087,7 +1169,8 @@ void TabWidget::useNativeDownloader(QUrl &downloadUrl, QString &suggestedFileNam
         // 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.
+        // Set the download job to display any warning and error messages.
+        fileCopyJobPointer->uiDelegate()->setAutoWarningHandlingEnabled(true);
         fileCopyJobPointer->uiDelegate()->setAutoErrorHandlingEnabled(true);
 
         // Start the download.