From c76e7c8baa9761d771e5891ee699ea6ddc78c23a Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Sat, 17 Jun 2023 17:22:47 -0700 Subject: [PATCH] Add view page source controls. https://redmine.stoutner.com/issues/1022 --- doc/index.docbook | 40 ++++++++++++++++++- src/ui.rcs/browserwindowui.rc | 5 +++ src/widgets/TabWidget.cpp | 7 +++- src/widgets/TabWidget.h | 2 +- src/windows/BrowserWindow.cpp | 73 ++++++++++++++++++++++++++++++----- src/windows/BrowserWindow.h | 5 ++- 6 files changed, 118 insertions(+), 14 deletions(-) diff --git a/doc/index.docbook b/doc/index.docbook index fbad58a..f8b1136 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -551,7 +551,45 @@ - Reload the website in the current tab bypassing any information in the cache and loading everything from the server. + Reload the website in the current tab bypassing any information in the cache and loading everything from the webserver. + + + + + + + + + + &Ctrl;U + + View + View Source + + + + + + Toggle between viewing the source and viewing the rendered website. + + + + + + + + + + &Ctrl;&Shift;U + + View + View Source in New Tab> + + + + + + Open a new tab displaying the source of the current tab, or a new tab displaying the rendered version if the source is already displayed. Note that right-clicking on the background of a rendered website will display a context menu with a "View page source" entry, which performs the first of these actions. diff --git a/src/ui.rcs/browserwindowui.rc b/src/ui.rcs/browserwindowui.rc index d296881..a1f54df 100644 --- a/src/ui.rcs/browserwindowui.rc +++ b/src/ui.rcs/browserwindowui.rc @@ -39,6 +39,11 @@ + + + + + diff --git a/src/widgets/TabWidget.cpp b/src/widgets/TabWidget.cpp index e19244e..2b14018 100644 --- a/src/widgets/TabWidget.cpp +++ b/src/widgets/TabWidget.cpp @@ -171,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(); @@ -454,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; } @@ -715,7 +718,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)); diff --git a/src/widgets/TabWidget.h b/src/widgets/TabWidget.h index 57082e0..ab21a4c 100644 --- a/src/widgets/TabWidget.h +++ b/src/widgets/TabWidget.h @@ -94,7 +94,7 @@ signals: public Q_SLOTS: // The public slots. void addCookieToStore(QNetworkCookie cookie, QWebEngineCookieStore *webEngineCookieStorePointer = nullptr) const; - PrivacyWebEngineView* addTab(const bool removeUrlLineEditFocus=false, const bool backgroundTab=false); + PrivacyWebEngineView* addTab(const bool removeUrlLineEditFocus = false, const bool backgroundTab = false, const QString urlString = nullptr); void applyApplicationSettings(); void applyDomainSettingsAndReload(); void applyOnTheFlySearchEngine(QAction *searchEngineActionPointer); diff --git a/src/windows/BrowserWindow.cpp b/src/windows/BrowserWindow.cpp index b5d062b..3ba0e67 100644 --- a/src/windows/BrowserWindow.cpp +++ b/src/windows/BrowserWindow.cpp @@ -76,6 +76,8 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() QAction *newTabActionPointer = actionCollectionPointer->addAction(QLatin1String("new_tab")); QAction *newWindowActionPointer = actionCollectionPointer->addAction(QLatin1String("new_window")); QAction *reloadAndBypassCacheActionPointer = actionCollectionPointer->addAction(QLatin1String("reload_and_bypass_cache")); + viewSourceActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source")); + QAction *viewSourceInNewTabActionPointer = actionCollectionPointer->addAction(QLatin1String("view_source_in_new_tab")); userAgentPrivacyBrowserActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_privacy_browser")); userAgentWebEngineDefaultActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_webengine_default")); userAgentFirefoxLinuxActionPointer = actionCollectionPointer->addAction(QLatin1String("user_agent_firefox_linux")); @@ -128,6 +130,7 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() localStorageActionPointer->setCheckable(true); domStorageActionPointer->setCheckable(true); findCaseSensitiveActionPointer->setCheckable(true); + viewSourceActionPointer->setCheckable(true); userAgentPrivacyBrowserActionPointer->setCheckable(true); userAgentWebEngineDefaultActionPointer->setCheckable(true); userAgentFirefoxLinuxActionPointer->setCheckable(true); @@ -149,6 +152,8 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() UserAgentHelper *userAgentHelperPointer = new UserAgentHelper(); // Set the action text. + viewSourceActionPointer->setText(i18nc("View source action", "View Source")); + viewSourceInNewTabActionPointer->setText(i18nc("View source in new tab action", "View Source in New Tab")); newTabActionPointer->setText(i18nc("New tab action", "New Tab")); newWindowActionPointer->setText(i18nc("New window action", "New Window")); reloadAndBypassCacheActionPointer->setText(i18nc("Reload and bypass cache action", "Reload and Bypass Cache")); @@ -179,17 +184,16 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() newTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("tab-new"))); newWindowActionPointer->setIcon(QIcon::fromTheme(QLatin1String("window-new"))); reloadAndBypassCacheActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); + viewSourceActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor")))); + viewSourceInNewTabActionPointer->setIcon(QIcon::fromTheme(QLatin1String("view-choose"), QIcon::fromTheme(QLatin1String("accessories-text-editor")))); userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode.svg")); - userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), - QIcon::fromTheme(QLatin1String("contact-new"))))); + userAgentWebEngineDefaultActionPointer->setIcon(QIcon::fromTheme(QLatin1String("qtlogo"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); userAgentFirefoxLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); - userAgentChromiumLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), - QIcon::fromTheme(QLatin1String("contact-new"))))); + userAgentChromiumLinuxActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); userAgentFirefoxWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("firefox-esr"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); - userAgentChromeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), - QIcon::fromTheme(QLatin1String("contact-new"))))); + userAgentChromeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("chromium"), QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new"))))); userAgentEdgeWindowsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))); userAgentSafariMacosActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))); userAgentCustomActionPointer->setIcon(QIcon::fromTheme(QLatin1String("user-group-properties"), QIcon::fromTheme(QLatin1String("contact-new")))); @@ -211,6 +215,8 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() QKeySequence ctrlTKeySequence = QKeySequence(i18nc("The open new tab key sequence.", "Ctrl+T")); QKeySequence ctrlNKeySequence = QKeySequence(i18nc("The open new window key sequence.", "Ctrl+N")); QKeySequence ctrlF5KeySequence = QKeySequence(i18nc("The reload and bypass cache key sequence.", "Ctrl+F5")); + QKeySequence ctrlUKeySequence = QKeySequence(i18nc("The view source key sequence.", "Ctrl+U")); + QKeySequence ctrlShiftUKeySequence = QKeySequence(i18nc("The view source in new tab key sequence.", "Ctrl+Shift+U")); QKeySequence ctrlShiftPKeySequence = QKeySequence(i18nc("The print preview key sequence.", "Ctrl+Shift+P")); QKeySequence ctrlAltPKeySequence = QKeySequence(i18nc("The Privacy Browser user agent key sequence.", "Ctrl+Alt+P")); QKeySequence ctrlAltWKeySequence = QKeySequence(i18nc("The WebEngine Default user agent key sequence.", "Ctrl+Alt+W")); @@ -236,6 +242,8 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() actionCollectionPointer->setDefaultShortcut(newTabActionPointer, ctrlTKeySequence); actionCollectionPointer->setDefaultShortcut(newWindowActionPointer, ctrlNKeySequence); actionCollectionPointer->setDefaultShortcut(reloadAndBypassCacheActionPointer, ctrlF5KeySequence); + actionCollectionPointer->setDefaultShortcut(viewSourceActionPointer, ctrlUKeySequence); + actionCollectionPointer->setDefaultShortcut(viewSourceInNewTabActionPointer, ctrlShiftUKeySequence); actionCollectionPointer->setDefaultShortcut(printPreviewActionPointer, ctrlShiftPKeySequence); actionCollectionPointer->setDefaultShortcut(userAgentPrivacyBrowserActionPointer, ctrlAltPKeySequence); actionCollectionPointer->setDefaultShortcut(userAgentWebEngineDefaultActionPointer, ctrlAltWKeySequence); @@ -261,6 +269,8 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow() connect(newTabActionPointer, SIGNAL(triggered()), tabWidgetPointer, SLOT(addTab())); connect(newWindowActionPointer, SIGNAL(triggered()), this, SLOT(newWindow())); connect(reloadAndBypassCacheActionPointer, SIGNAL(triggered()), this, SLOT(reloadAndBypassCache())); + connect(viewSourceActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSource())); + connect(viewSourceInNewTabActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSourceInNewTab())); connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser())); connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog())); connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(showDomainSettingsDialog())); @@ -986,6 +996,48 @@ void BrowserWindow::toggleFullScreen() } } +void BrowserWindow::toggleViewSource() const +{ + // Get the current URL. + QString url = urlLineEditPointer->text(); + + // Toggle the URL. + if (url.startsWith(QLatin1String("view-source:"))) // The source is currently being viewed. + { + // Remove `view-source:` from the URL. + url = url.remove(0, 12); + } + else // The source is not currently being viewed. + { + // Prepend `view-source:` from the URL. + url = url.prepend(QLatin1String("view-source:")); + } + + // Make it so. + loadUrlFromLineEdit(url); +} + +void BrowserWindow::toggleViewSourceInNewTab() const +{ + // Get the current URL. + QString url = urlLineEditPointer->text(); + + // Toggle the URL. + if (url.startsWith(QLatin1String("view-source:"))) // The source is currently being viewed. + { + // Remove `view-source:` from the URL. + url = url.remove(0, 12); + } + else // The source is not currently being viewed. + { + // Prepend `view-source:` from the URL. + url = url.prepend(QLatin1String("view-source:")); + } + + // Add the new tab. `true` removes the URL line edit focus, `false` does not open a background tab. + tabWidgetPointer->addTab(true, false, url); +} + void BrowserWindow::updateCookiesAction(const int numberOfCookies) const { // Update the action text. @@ -1326,12 +1378,15 @@ void BrowserWindow::updateSearchEngineLabel(const QString &searchEngineString) c void BrowserWindow::updateUrlLineEdit(const QUrl &newUrl) { + // Get the new URL string. + QString newUrlString = newUrl.toString(); + + // Update the view source checkbox. + viewSourceActionPointer->setChecked(newUrlString.startsWith(QLatin1String("view-source:"))); + // 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(newUrlString); diff --git a/src/windows/BrowserWindow.h b/src/windows/BrowserWindow.h index 44486d9..99fd146 100644 --- a/src/windows/BrowserWindow.h +++ b/src/windows/BrowserWindow.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2023 Soren Stoutner . + * Copyright 2022-2023 Soren Stoutner . * * This file is part of Privacy Browser PC . * @@ -76,6 +76,8 @@ private Q_SLOTS: void toggleJavaScript() const; void toggleLocalStorage() const; void toggleFullScreen(); + void toggleViewSource() const; + void toggleViewSourceInNewTab() const; void updateCookiesAction(const int numberOfCookies) const; void updateDomStorageAction(const bool &isEnabled) const; void updateDomainSettingsIndicator(const bool status); @@ -141,6 +143,7 @@ private: QAction *userAgentCustomActionPointer; KLineEdit *urlLineEditPointer; KToolBar *urlToolBarPointer; + QAction *viewSourceActionPointer; QAction *zoomFactorActionPointer; }; #endif -- 2.45.2