]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/commitdiff
Implement finding of text withing a page.
authorSoren Stoutner <soren@stoutner.com>
Fri, 26 Aug 2022 20:03:07 +0000 (13:03 -0700)
committerSoren Stoutner <soren@stoutner.com>
Fri, 26 Aug 2022 20:03:07 +0000 (13:03 -0700)
src/ui.rcs/CMakeLists.txt
src/ui.rcs/browser_ui.rc [deleted file]
src/ui.rcs/browser_window_ui.rc [new file with mode: 0644]
src/widgets/PrivacyWebEngineView.h
src/widgets/TabWidget.cpp
src/widgets/TabWidget.h
src/windows/BrowserWindow.cpp
src/windows/BrowserWindow.h

index 2c8c30ebcbc3bea1a78434f87120f0302a6b5d9b..2ac4766fd0b6b83a5b5e61dee8c102c71e4989c0 100644 (file)
@@ -18,5 +18,5 @@
 
 # Install Privacy Browser's RC (Runtime Configuration) files.
 install(FILES
-    browser_ui.rc
+    browser_window_ui.rc
     DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/privacybrowser)
diff --git a/src/ui.rcs/browser_ui.rc b/src/ui.rcs/browser_ui.rc
deleted file mode 100644 (file)
index 0526147..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
-
-  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-android>.
-
-  Privacy Browser PC is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  Privacy Browser PC is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Documentation at <https://techbase.kde.org/Development/Architecture/KDE4/XMLGUI_Technology>. -->
-<!-- Better documentation at <https://invent.kde.org/frameworks/kxmlgui/-/blob/master/src/kxmlgui.xsd>. -->
-<gui
-    name="privacybrowser"
-    version="1"
-    xmlns="http://www.kde.org/standards/kxmlgui/1.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >
-
-    <!-- The menu bar. -->
-    <MenuBar>
-        <!-- On-the-fly Settings. -->
-        <Menu name="on_the_fly_settings"> <text>On-The-Fly Settings</text>
-            <Menu name="user_agent" icon="user-group-properties">
-                <Action name="user_agent_privacy_browser" />
-                <Action name="user_agent_webengine_default" />
-                <Action name="user_agent_firefox_linux" />
-                <Action name="user_agent_chromium_linux" />
-                <Action name="user_agent_firefox_windows" />
-                <Action name="user_agent_chrome_windows" />
-                <Action name="user_agent_edge_windows" />
-                <Action name="user_agent_safari_macos" />
-                <Action name="user_agent_custom" />
-            </Menu>
-
-            <Action name="zoom_factor" />
-
-            <Separator />
-
-            <Menu name="search_engine" icon="search">
-                <Action name="search_engine_mojeek" />
-                <Action name="search_engine_monocles" />
-                <Action name="search_engine_metager" />
-                <Action name="search_engine_google" />
-                <Action name="search_engine_bing" />
-                <Action name="search_engine_yahoo" />
-                <Action name="search_engine_custom" />
-            </Menu>
-        </Menu>
-
-        <!-- Settings. -->
-        <Menu name="settings">
-            <Action name="domain_settings" />
-            <Action name="cookies" />
-        </Menu>
-    </MenuBar>
-
-    <!-- The main toolbar is removed. -->
-    <ToolBar name="mainToolBar" deleted="true" />
-
-    <!-- The navigation toolbar. -->
-    <ToolBar name="navigation_toolbar" iconText="icononly"> <text>Navigation Toolbar</text>
-        <Action name="go_back" />
-        <Action name="go_forward" />
-        <Action name="view_redisplay" />
-        <Action name="go_home" />
-    </ToolBar>
-
-    <!-- The URL toolbar. -->
-    <ToolBar name="url_toolbar" iconText="icononly"> <text>URL Toolbar</text>
-        <Action name="javascript" />
-        <Action name="local_storage" />
-        <Action name="dom_storage" />
-    </ToolBar>
-</gui>
diff --git a/src/ui.rcs/browser_window_ui.rc b/src/ui.rcs/browser_window_ui.rc
new file mode 100644 (file)
index 0000000..6722426
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright © 2022 Soren Stoutner <soren@stoutner.com>.
+
+  This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-android>.
+
+  Privacy Browser PC is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  Privacy Browser PC is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- Documentation at <https://techbase.kde.org/Development/Architecture/KDE4/XMLGUI_Technology>. -->
+<!-- Better documentation at <https://invent.kde.org/frameworks/kxmlgui/-/blob/master/src/kxmlgui.xsd>. -->
+<!-- This file interacts with the default template located at /etc/xdg/ui/ui_standards.rc, which is part of the libkf5xmlgui-data package. -->
+<gui
+    name="privacybrowser"
+    version="1"
+    xmlns="http://www.kde.org/standards/kxmlgui/1.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >
+
+    <!-- The menu bar. -->
+    <MenuBar>
+        <!-- On-the-fly Settings. -->
+        <Menu name="on_the_fly_settings"> <text>On-The-Fly Settings</text>
+            <Menu name="user_agent" icon="user-group-properties">
+                <Action name="user_agent_privacy_browser" />
+                <Action name="user_agent_webengine_default" />
+                <Action name="user_agent_firefox_linux" />
+                <Action name="user_agent_chromium_linux" />
+                <Action name="user_agent_firefox_windows" />
+                <Action name="user_agent_chrome_windows" />
+                <Action name="user_agent_edge_windows" />
+                <Action name="user_agent_safari_macos" />
+                <Action name="user_agent_custom" />
+            </Menu>
+
+            <Action name="zoom_factor" />
+
+            <Separator />
+
+            <Menu name="search_engine" icon="search">
+                <Action name="search_engine_mojeek" />
+                <Action name="search_engine_monocles" />
+                <Action name="search_engine_metager" />
+                <Action name="search_engine_google" />
+                <Action name="search_engine_bing" />
+                <Action name="search_engine_yahoo" />
+                <Action name="search_engine_custom" />
+            </Menu>
+        </Menu>
+
+        <!-- Settings. -->
+        <Menu name="settings">
+            <Action name="domain_settings" />
+            <Action name="cookies" />
+        </Menu>
+    </MenuBar>
+
+    <!-- The main toolbar is removed. -->
+    <ToolBar name="mainToolBar" deleted="true" />
+
+    <!-- The navigation toolbar. -->
+    <ToolBar name="navigation_toolbar" iconText="icononly"> <text>Navigation Toolbar</text>
+        <Action name="go_back" />
+        <Action name="go_forward" />
+        <Action name="view_redisplay" />
+        <Action name="go_home" />
+    </ToolBar>
+
+    <!-- The URL toolbar. -->
+    <ToolBar name="url_toolbar" iconText="icononly"> <text>URL Toolbar</text>
+        <Action name="javascript" />
+        <Action name="local_storage" />
+        <Action name="dom_storage" />
+        <Action name="edit_find_next" />
+        <Action name="edit_find_prev" />
+        <Action name="find_case_sensitive" />
+    </ToolBar>
+</gui>
index 863cf5d4429ce1bc9af8b14c9acbc4deb1445c1b..c227f428ee2bd1a0aab6a0b89a8708f2a6335519 100644 (file)
@@ -22,6 +22,7 @@
 
 // Qt toolkit headers.
 #include <QNetworkCookie>
+#include <QWebEngineFindTextResult>
 #include <QWebEngineView>
 
 class PrivacyWebEngineView : public QWebEngineView
@@ -36,6 +37,9 @@ public:
     // The public variables.
     std::list<QNetworkCookie> *cookieListPointer = new std::list<QNetworkCookie>;
     QString domainSettingsName = QStringLiteral("");
+    bool findCaseSensitive = false;
+    QString findString = QStringLiteral("");
+    QWebEngineFindTextResult findTextResult = QWebEngineFindTextResult();
     int loadProgressInt = -1;
     bool localStorageEnabled = false;
 
index 4a3c1455ecc63acc1c327bcd5bddd2683ac83d76..3a1b54f33f2028f411b5eefadb14d346f794bb13 100644 (file)
@@ -216,6 +216,9 @@ PrivacyWebEngineView* TabWidget::addTab(const bool focusNewWebEngineView)
             emit hideProgressBar();
     });
 
+    // Display find text results.
+    connect(webEnginePagePointer, SIGNAL(findTextFinished(const QWebEngineFindTextResult &)), this, SLOT(findTextFinished(const QWebEngineFindTextResult &)));
+
     // Handle full screen requests.
     connect(webEnginePagePointer, SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest)));
 
@@ -612,6 +615,52 @@ void TabWidget::deleteTab(const int tabIndex)
     }
 }
 
+void TabWidget::findPrevious(const QString &text) const
+{
+    // Store the current text.
+    currentPrivacyWebEngineViewPointer->findString = text;
+
+    // Find the previous text in the current privacy WebEngine.
+    if (currentPrivacyWebEngineViewPointer->findCaseSensitive)
+        currentPrivacyWebEngineViewPointer->findText(text, QWebEnginePage::FindCaseSensitively|QWebEnginePage::FindBackward);
+    else
+        currentPrivacyWebEngineViewPointer->findText(text, QWebEnginePage::FindBackward);
+}
+
+void TabWidget::findText(const QString &text) const
+{
+    // Store the current text.
+    currentPrivacyWebEngineViewPointer->findString = text;
+
+    // Find the text in the current privacy WebEngine.
+    if (currentPrivacyWebEngineViewPointer->findCaseSensitive)
+        currentPrivacyWebEngineViewPointer->findText(text, QWebEnginePage::FindCaseSensitively);
+    else
+        currentPrivacyWebEngineViewPointer->findText(text);
+
+    // Clear the currently selected text in the WebEngine page if the find text is empty.
+    if (text.isEmpty())
+        currentWebEnginePagePointer->action(QWebEnginePage::Unselect)->activate(QAction::Trigger);
+}
+
+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`.
+    if (wipingCurrentFindTextSelection)  // The current selection is being wiped.
+    {
+        // Reset the flag.
+        wipingCurrentFindTextSelection = false;
+    }
+    else  // A new search has been performed.
+    {
+        // Store the result.
+        currentPrivacyWebEngineViewPointer->findTextResult = findTextResult;
+
+        // Update the UI.
+        emit updateFindTextResults(findTextResult);
+    }
+}
+
 void TabWidget::forward() const
 {
     // Go forward.
@@ -867,6 +916,21 @@ void TabWidget::toggleDomStorage() const
     currentPrivacyWebEngineViewPointer->reload();
 }
 
+void TabWidget::toggleFindCaseSensitive(const QString &text)
+{
+    // Toggle find case sensitive.
+    currentPrivacyWebEngineViewPointer->findCaseSensitive = !currentPrivacyWebEngineViewPointer->findCaseSensitive;
+
+    // Set the wiping current find text selection flag.
+    wipingCurrentFindTextSelection = true;
+
+    // Wipe the previous search.  Otherwise currently highlighted words will remain highlighted.
+    findText(QStringLiteral(""));
+
+    // Update the find text.
+    findText(text);
+}
+
 void TabWidget::toggleJavaScript() const
 {
     // Toggle JavaScript.
@@ -904,19 +968,25 @@ void TabWidget::updateUiWithTabSettings()
     // Clear the URL line edit focus.
     emit clearUrlLineEditFocus();
 
-    // Update the UI.
+    // Update the actions.
     emit updateBackAction(currentWebEngineHistoryPointer->canGoBack());
     emit updateCookiesAction(currentPrivacyWebEngineViewPointer->cookieListPointer->size());
-    emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral(""));
     emit updateDomStorageAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::LocalStorageEnabled));
     emit updateForwardAction(currentWebEngineHistoryPointer->canGoForward());
     emit updateJavaScriptAction(currentWebEngineSettingsPointer->testAttribute(QWebEngineSettings::JavascriptEnabled));
     emit updateLocalStorageAction(currentPrivacyWebEngineViewPointer->localStorageEnabled);
-    emit updateWindowTitle(currentPrivacyWebEngineViewPointer->title());
-    emit updateUrlLineEdit(currentPrivacyWebEngineViewPointer->url());
     emit updateUserAgentActions(currentWebEngineProfilePointer->httpUserAgent(), true);
     emit updateZoomFactorAction(currentPrivacyWebEngineViewPointer->zoomFactor());
 
+    // Update the URL.
+    emit updateWindowTitle(currentPrivacyWebEngineViewPointer->title());
+    emit updateDomainSettingsIndicator(currentPrivacyWebEngineViewPointer->domainSettingsName != QStringLiteral(""));
+    emit updateUrlLineEdit(currentPrivacyWebEngineViewPointer->url());
+
+    // Update the find text.
+    emit updateFindText(currentPrivacyWebEngineViewPointer->findString, currentPrivacyWebEngineViewPointer->findCaseSensitive);
+    emit updateFindTextResults(currentPrivacyWebEngineViewPointer->findTextResult);
+
     // Update the progress bar.
     if (currentPrivacyWebEngineViewPointer->loadProgressInt >= 0)
         emit showProgressBar(currentPrivacyWebEngineViewPointer->loadProgressInt);
index ed9ad03b002e314227c792d6a501d86f7533cd2c..bd857b0d65a8b431c8a7dd08779cde91d057ad30 100644 (file)
@@ -52,10 +52,12 @@ public:
     void applyOnTheFlyZoomFactor(const double &zoomFactor);
     PrivacyWebEngineView* loadBlankInitialWebsite();
     void loadInitialWebsite();
+    void findPrevious(const QString &text) const;
     std::list<QNetworkCookie>* getCookieList() const;
     QString& getDomainSettingsName() const;
     void setTabBarVisible(const bool visible) const;
     void toggleDomStorage() const;
+    void toggleFindCaseSensitive(const QString &text);
     void toggleJavaScript() const;
     void toggleLocalStorage();
 
@@ -75,6 +77,8 @@ signals:
     void updateCookiesAction(const int numberOfCookies) const;
     void updateDomStorageAction(const bool &isEnabled) const;
     void updateDomainSettingsIndicator(const bool status) const;
+    void updateFindText(const QString &text, const bool findCaseSensitive) const;
+    void updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const;
     void updateForwardAction(const bool &isEnabled) const;
     void updateJavaScriptAction(const bool &isEnabled) const;
     void updateLocalStorageAction(const bool &isEnabled) const;
@@ -96,6 +100,7 @@ public Q_SLOTS:
     void back() const;
     void deleteAllCookies() const;
     void deleteCookieFromStore(const QNetworkCookie &cookie) const;
+    void findText(const QString &text) const;
     void forward() const;
     void home() const;
     void loadUrlFromLineEdit(QString url) const;
@@ -109,6 +114,7 @@ private Q_SLOTS:
     // The private slots.
     void addFirstTab();
     void deleteTab(const int tabIndex);
+    void findTextFinished(const QWebEngineFindTextResult &findTextResult);
     void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) const;
     void pageLinkHovered(const QString &linkUrl) const;
     void printWebpage(QPrinter *printerPointer) const;
@@ -128,6 +134,7 @@ private:
     QIcon defaultTabIcon = QIcon::fromTheme(QStringLiteral("globe"));
     QString searchEngineUrl;
     QTabWidget *tabWidgetPointer;
+    bool wipingCurrentFindTextSelection = false;
 
     // The private functions.
     void applyDomainSettings(const QString &hostname, const bool reloadWebsite);
index 064c7eda22b7a70c4152306250e4fcd257f8bb30..716f2e0c58f57dea8d676a00c660ebf697ac58c1 100644 (file)
@@ -29,6 +29,7 @@
 
 // KDE Frameworks headers.
 #include <KActionCollection>
+#include <KColorScheme>
 #include <KToolBar>
 
 // Qt toolkit headers.
@@ -38,6 +39,7 @@
 #include <QMenuBar>
 #include <QShortcut>
 #include <QStatusBar>
+#include <QWebEngineFindTextResult>
 
 // Construct the class.
 BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
@@ -66,6 +68,9 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     QAction *forwardActionPointer = KStandardAction::forward(this, SLOT(forward()), actionCollectionPointer);
     KStandardAction::home(this, SLOT(home()), actionCollectionPointer);
     KStandardAction::preferences(this, SLOT(showSettingsDialog()), actionCollectionPointer);
+    KStandardAction::find(this, SLOT(focusFindLineEdit()), actionCollectionPointer);
+    QAction *findNextActionPointer = KStandardAction::findNext(this, SLOT(findNext()), actionCollectionPointer);
+    KStandardAction::findPrev(this, SLOT(findPrevious()), actionCollectionPointer);
 
     // Add the custom actions.
     userAgentPrivacyBrowserActionPointer = actionCollectionPointer->addAction(QStringLiteral("user_agent_privacy_browser"));
@@ -90,6 +95,7 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     javaScriptActionPointer = actionCollectionPointer->addAction(QStringLiteral("javascript"));
     localStorageActionPointer = actionCollectionPointer->addAction(QStringLiteral("local_storage"));
     domStorageActionPointer = actionCollectionPointer->addAction(QStringLiteral("dom_storage"));
+    findCaseSensitiveActionPointer = actionCollectionPointer->addAction(QStringLiteral("find_case_sensitive"));
 
     // Create the action groups
     QActionGroup *userAgentActionGroupPointer = new QActionGroup(this);
@@ -117,6 +123,7 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     javaScriptActionPointer->setCheckable(true);
     localStorageActionPointer->setCheckable(true);
     domStorageActionPointer->setCheckable(true);
+    findCaseSensitiveActionPointer->setCheckable(true);
     userAgentPrivacyBrowserActionPointer->setCheckable(true);
     userAgentWebEngineDefaultActionPointer->setCheckable(true);
     userAgentFirefoxLinuxActionPointer->setCheckable(true);
@@ -154,6 +161,7 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     javaScriptActionPointer->setText(i18nc("JavaScript action", "JavaScript"));
     localStorageActionPointer->setText(i18nc("The Local Storage action", "Local Storage"));
     domStorageActionPointer->setText(i18nc("DOM Storage action", "DOM Storage"));
+    findCaseSensitiveActionPointer->setText(i18nc("Find Case Sensitive action", "Find Case Sensitive"));
 
     // Set the action icons.
     userAgentPrivacyBrowserActionPointer->setIcon(QIcon(":/icons/privacy-mode"));
@@ -176,6 +184,7 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     domainSettingsActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("settings-configure")));
     cookiesActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("preferences-web-browser-cookies")));
     domStorageActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("code-class")));
+    findCaseSensitiveActionPointer->setIcon(QIcon::fromTheme(QStringLiteral("format-text-lowercase")));
 
     // Update the on-the-fly menus.
     connect(tabWidgetPointer, SIGNAL(updateUserAgentActions(QString, bool)), this, SLOT(updateUserAgentActions(QString, bool)));
@@ -206,8 +215,11 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     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"));
+    // Connect the find text actions.
+    connect(findCaseSensitiveActionPointer, SIGNAL(triggered()), this, SLOT(toggleFindCaseSensitive()));
+
+    // Setup the GUI based on the browser_window_ui.rc file.
+    setupGUI(StandardWindowOption::Default, ("browser_window_ui.rc"));
 
     // Get lists of the actions' associated widgets.
     QList<QWidget*> userAgentAssociatedWidgetsPointerList = userAgentPrivacyBrowserActionPointer->associatedWidgets();
@@ -229,8 +241,33 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     navigationToolBarPointer = toolBar(QStringLiteral("navigation_toolbar"));
     urlToolBarPointer = toolBar(QStringLiteral("url_toolbar"));
 
-    // Create a URL line edit.
+    // Create the line edits.
     urlLineEditPointer = new KLineEdit();
+    findTextLineEditPointer = new KLineEdit();
+
+    // Get the line edit size policies.
+    QSizePolicy urlLineEditSizePolicy = urlLineEditPointer->sizePolicy();
+    QSizePolicy findTextLineEditSizePolicy = findTextLineEditPointer->sizePolicy();
+
+    // Set the URL line edit horizontal stretch to be five times the find text line edit stretch.
+    urlLineEditSizePolicy.setHorizontalStretch(5);
+    findTextLineEditSizePolicy.setHorizontalStretch(1);
+
+    // Set the policies.
+    urlLineEditPointer->setSizePolicy(urlLineEditSizePolicy);
+    findTextLineEditPointer->setSizePolicy(findTextLineEditSizePolicy);
+
+    // Set the widths.
+    urlLineEditPointer->setMinimumWidth(350);
+    findTextLineEditPointer->setMinimumWidth(200);
+    findTextLineEditPointer->setMaximumWidth(350);
+
+    // Set the placehold text.
+    urlLineEditPointer->setPlaceholderText(i18nc("The URL line edit placeholder text", "URL or Search Terms"));
+    findTextLineEditPointer->setPlaceholderText(i18nc("The find line edit placeholder text", "Find Text"));
+
+    // Show the clear button on the find line edit.
+    findTextLineEditPointer->setClearButtonEnabled(true);
 
     // Add an edit or add domain settings action to the URL line edit.
     QAction *addOrEditDomainSettingsActionPointer = urlLineEditPointer->addAction(QIcon::fromTheme("settings-configure"), QLineEdit::TrailingPosition);
@@ -238,12 +275,32 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     // Add or edit the current domain settings.
     connect(addOrEditDomainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(addOrEditDomainSettings()));
 
-    // Populate the URL toolbar.
+    // Create a find text label pointer.
+    findTextLabelPointer = new QLabel();
+
+    // Set the default label text.
+    findTextLabelPointer->setText(QStringLiteral("  ") + i18nc("Default find results.", "0/0") + QStringLiteral("  "));
+
+    // Insert the widgets into the toolbars.
     urlToolBarPointer->insertWidget(javaScriptActionPointer, urlLineEditPointer);
+    urlToolBarPointer->insertWidget(findNextActionPointer, findTextLineEditPointer);
+    urlToolBarPointer->insertWidget(findNextActionPointer, findTextLabelPointer);
 
     // Load a new URL from the URL line edit.
     connect(urlLineEditPointer, SIGNAL(returnKeyPressed(const QString)), this, SLOT(loadUrlFromLineEdit(const QString)));
 
+    // Find text as it is typed.
+    connect(findTextLineEditPointer, SIGNAL(textEdited(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
+
+    // Find next if the enter key is pressed.
+    connect(findTextLineEditPointer, SIGNAL(returnKeyPressed(const QString &)), tabWidgetPointer, SLOT(findText(const QString &)));
+
+    // Update find text when switching tabs.
+    connect(tabWidgetPointer, SIGNAL(updateFindText(const QString &, const bool)), this, SLOT(updateFindText(const QString &, const bool)));
+
+    // Update the find text results.
+    connect(tabWidgetPointer, SIGNAL(updateFindTextResults(const QWebEngineFindTextResult &)), this, SLOT(updateFindTextResults(const QWebEngineFindTextResult &)));
+
     // Update the URL line edit on page loads.
     connect(tabWidgetPointer, SIGNAL(updateUrlLineEdit(QUrl)), this, SLOT(updateUrlLineEdit(QUrl)));
 
@@ -270,11 +327,13 @@ BrowserWindow::BrowserWindow(bool firstWindow) : KXmlGuiWindow()
     connect(tabWidgetPointer, SIGNAL(clearUrlLineEditFocus()), this, SLOT(clearUrlLineEditFocus()));
 
     // Get the URL line edit palettes.
-    noDomainSettingsPalette = urlLineEditPointer->palette();
-    domainSettingsPalette = urlLineEditPointer->palette();
+    normalBackgroundPalette = urlLineEditPointer->palette();
+    negativeBackgroundPalette = normalBackgroundPalette;
+    positiveBackgroundPalette = normalBackgroundPalette;
 
-    // Modify the domain settings palette.
-    domainSettingsPalette.setColor(QPalette::Base, QColor("#C8E6C9"));
+    // Modify the palettes.
+    KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground);
+    KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground);
 
     // Update the applied palette.
     connect(tabWidgetPointer, SIGNAL(updateDomainSettingsIndicator(const bool)), this, SLOT(updateDomainSettingsIndicator(const bool)));
@@ -350,9 +409,20 @@ void BrowserWindow::clearUrlLineEditFocus() const
 
 void BrowserWindow::escape() const
 {
-    // Exit full screen browsing if it is enabled.
-    if (fullScreenActionPointer->isChecked())
+    // Process the excape according to the status of the browser.
+    if (fullScreenActionPointer->isChecked())  // Full screen browsing is enabled.
+    {
+        // Exit full screen browsing.
         fullScreenActionPointer->trigger();
+    }
+    else if (!findTextLineEditPointer->text().isEmpty())  // Find text is activated.
+    {
+        // Clear the text in the line edit.
+        findTextLineEditPointer->clear();
+
+        // Clear the search in the WebEngine.
+        tabWidgetPointer->findText(QStringLiteral(""));
+    }
 }
 
 void BrowserWindow::fileNew() const
@@ -361,6 +431,35 @@ void BrowserWindow::fileNew() const
     (new BrowserWindow)->show();
 }
 
+void BrowserWindow::findNext() const
+{
+    // Get the find string.
+    const QString findString = findTextLineEditPointer->text();
+
+    // Search for the text if it is not empty.
+    if (!findString.isEmpty())
+        tabWidgetPointer->findText(findString);
+}
+
+void BrowserWindow::findPrevious() const
+{
+    // Get the find string.
+    const QString findString = findTextLineEditPointer->text();
+
+    // Search for the text if it is not empty.
+    if (!findString.isEmpty())
+        tabWidgetPointer->findPrevious(findString);
+}
+
+void BrowserWindow::focusFindLineEdit() const
+{
+    // Set the focus on the find line edit.
+    findTextLineEditPointer->setFocus();
+
+    // Select all the text in the find line edit.
+    findTextLineEditPointer->selectAll();
+}
+
 void BrowserWindow::forward() const
 {
     // Remove the focus from the URL line edit.
@@ -591,6 +690,15 @@ void BrowserWindow::toggleDomStorage() const
     tabWidgetPointer->toggleDomStorage();
 }
 
+void BrowserWindow::toggleFindCaseSensitive() const
+{
+    // Get the current find string.
+    const QString findString = findTextLineEditPointer->text();
+
+    // Toggle find case sensitive.
+    tabWidgetPointer->toggleFindCaseSensitive(findString);
+}
+
 void BrowserWindow::toggleJavaScript() const
 {
     // Remove the focus from the URL line edit.
@@ -672,9 +780,32 @@ void BrowserWindow::updateDomainSettingsIndicator(const bool status)
 {
     // Set the domain palette according to the status.
     if (status)
-        urlLineEditPointer->setPalette(domainSettingsPalette);
+        urlLineEditPointer->setPalette(positiveBackgroundPalette);
+    else
+        urlLineEditPointer->setPalette(normalBackgroundPalette);
+}
+
+void BrowserWindow::updateFindText(const QString &text, const bool findCaseSensitive) const
+{
+    // Set the text.
+    findTextLineEditPointer->setText(text);
+
+    // Set the find case sensitive action checked status.
+    findCaseSensitiveActionPointer->setChecked(findCaseSensitive);
+}
+
+void BrowserWindow::updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const
+{
+    // Update the find text label.
+    findTextLabelPointer->setText(QStringLiteral("  %1/%2  ").arg(findTextResult.activeMatch()).arg(findTextResult.numberOfMatches()));
+
+    // Set the background color according to the find status.
+    if (findTextLineEditPointer->text().isEmpty())
+        findTextLineEditPointer->setPalette(normalBackgroundPalette);
+    else if (findTextResult.numberOfMatches() == 0)
+        findTextLineEditPointer->setPalette(negativeBackgroundPalette);
     else
-        urlLineEditPointer->setPalette(noDomainSettingsPalette);
+        findTextLineEditPointer->setPalette(positiveBackgroundPalette);
 }
 
 void BrowserWindow::updateJavaScriptAction(const bool &isEnabled)
index a131a4484e02f52d5d20e0669e7780b01e212124..4c043d2e8f4717b13e4dba0193ba8e7225d3064c 100644 (file)
@@ -55,6 +55,9 @@ private Q_SLOTS:
     void clearUrlLineEditFocus() const;
     void escape() const;
     void fileNew() const;
+    void findNext() const;
+    void findPrevious() const;
+    void focusFindLineEdit() const;
     void forward() const;
     void fullScreenRequested(const bool toggleOn);
     void getZoomFactorFromUser();
@@ -67,12 +70,15 @@ private Q_SLOTS:
     void showProgressBar(const int &progress) const;
     void showSettingsDialog();
     void toggleDomStorage() const;
+    void toggleFindCaseSensitive() const;
     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);
+    void updateFindText(const QString &text, const bool findCaseSensitive) const;
+    void updateFindTextResults(const QWebEngineFindTextResult &findTextResult) const;
     void updateJavaScriptAction(const bool &isEnabled);
     void updateLocalStorageAction(const bool &isEnabled);
     void updateSearchEngineActions(const QString &searchEngine, const bool &updateCustomSearchEngineStatus);
@@ -92,15 +98,19 @@ private:
     bool customSearchEngineEnabled;
     bool customUserAgentEnabled;
     QAction *domStorageActionPointer;
-    QPalette domainSettingsPalette;
     QComboBox *downloadLocationComboBoxPointer;
+    QAction *findCaseSensitiveActionPointer;
+    QLabel *findTextLabelPointer;
+    KLineEdit *findTextLineEditPointer;
     KToggleFullScreenAction *fullScreenActionPointer;
     QAction *javaScriptActionPointer;
     bool javaScriptEnabled;
     QAction *localStorageActionPointer;
     bool localStorageEnabled;
     KToolBar *navigationToolBarPointer;
-    QPalette noDomainSettingsPalette;
+    QPalette negativeBackgroundPalette;
+    QPalette normalBackgroundPalette;
+    QPalette positiveBackgroundPalette;
     QProgressBar *progressBarPointer;
     QLabel *searchEngineLabelPointer;
     QAction *searchEngineMenuActionPointer;