summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2019-07-12 13:39:06 +0200
committerPeter Varga <pvarga@inf.u-szeged.hu>2019-08-23 10:25:23 +0200
commita6abc01319798e2175914323273e91927516eba0 (patch)
treec7fe231f43e80cc4442c535442f41de1cd521fda
parent55a4c28542c6dc9e4a4edc0aab7043feef2ab0d2 (diff)
Introduce findTextFinished signal
This is a replacement for the callbacks. Also introduces QWebEngineFindTextResult class what is common for the Quick and Widget APIs. This makes possible to provide extra information about the match, eg. the number of matches and the index of the currently highlighted match. [ChangeLog][QtWebEngine][WebEngineView] Introduces findTextFinished signal and FindTextResult type to provide extra information about the result of a text search. [ChangeLog][QtWebEngineWidgets][QWebEnginePage] Introduces findTextFinished signal and QWebEngineFindTextResult class to provide extra information about the result of a text search. Task-number: QTBUG-50420 Change-Id: Icb9737d2f596e6bc0fc5733144eeeaf2a77aab02 Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
-rw-r--r--examples/webengine/quicknanobrowser/BrowserWindow.qml59
-rw-r--r--examples/webengine/quicknanobrowser/FindBar.qml146
-rw-r--r--examples/webengine/quicknanobrowser/quicknanobrowser.pro1
-rw-r--r--examples/webengine/quicknanobrowser/resources.qrc1
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.cpp18
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.h1
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.cpp4
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.h1
-rw-r--r--src/core/api/core_api.pro2
-rw-r--r--src/core/api/qwebenginefindtextresult.cpp116
-rw-r--r--src/core/api/qwebenginefindtextresult.h81
-rw-r--r--src/core/find_text_helper.cpp10
-rw-r--r--src/core/find_text_helper.h5
-rw-r--r--src/core/web_contents_adapter_client.h2
-rw-r--r--src/core/web_contents_delegate_qt.cpp2
-rw-r--r--src/webengine/api/qquickwebengineview.cpp7
-rw-r--r--src/webengine/api/qquickwebengineview_p.h2
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h2
-rw-r--r--src/webengine/doc/src/webengineview_lgpl.qdoc43
-rw-r--r--src/webengine/plugin/plugin.cpp3
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp18
-rw-r--r--src/webenginewidgets/api/qwebenginepage.h3
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h2
-rw-r--r--src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc3
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp5
-rw-r--r--tests/auto/quick/qmltests/data/tst_findText.qml84
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp113
27 files changed, 713 insertions, 21 deletions
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index 088b23e59..39a13df59 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -57,7 +57,7 @@ import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
import QtQuick.Window 2.1
-import QtWebEngine 1.10
+import QtWebEngine 1.11
ApplicationWindow {
id: browserWindow
@@ -73,6 +73,10 @@ ApplicationWindow {
// Make sure the Qt.WindowFullscreenButtonHint is set on OS X.
Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint
+ onCurrentWebViewChanged: {
+ findBar.reset();
+ }
+
// Create a styleItem to determine the platform.
// When using style "mac", ToolButtons are not supposed to accept focus.
QQCPrivate.StyleItem { id: styleItem }
@@ -136,6 +140,9 @@ ApplicationWindow {
fullScreenNotification.hide();
currentWebView.triggerWebAction(WebEngineView.ExitFullScreen);
}
+
+ if (findBar.visible)
+ findBar.visible = false;
}
}
Action {
@@ -187,6 +194,21 @@ ApplicationWindow {
shortcut: StandardKey.Forward
onTriggered: currentWebView.triggerWebAction(WebEngineView.Forward)
}
+ Action {
+ shortcut: StandardKey.Find
+ onTriggered: {
+ if (!findBar.visible)
+ findBar.visible = true;
+ }
+ }
+ Action {
+ shortcut: StandardKey.FindNext
+ onTriggered: findBar.findNext()
+ }
+ Action {
+ shortcut: StandardKey.FindPrevious
+ onTriggered: findBar.findPrevious()
+ }
toolBar: ToolBar {
id: navigationBar
@@ -553,6 +575,19 @@ ApplicationWindow {
selection.certificates[0].select();
}
+ onFindTextFinished: function(result) {
+ if (!findBar.visible)
+ findBar.visible = true;
+
+ findBar.numberOfMatches = result.numberOfMatches;
+ findBar.activeMatchOrdinal = result.activeMatchOrdinal;
+ }
+
+ onLoadingChanged: function(loadRequest) {
+ if (loadRequest.status == WebEngineView.LoadStartedStatus)
+ findBar.reset();
+ }
+
Timer {
id: reloadTimer
interval: 0
@@ -625,6 +660,28 @@ ApplicationWindow {
download.accept();
}
+ FindBar {
+ id: findBar
+ visible: false
+ anchors.right: parent.right
+ anchors.rightMargin: 10
+ anchors.top: parent.top
+
+ onFindNext: {
+ if (text)
+ currentWebView && currentWebView.findText(text);
+ else if (!visible)
+ visible = true;
+ }
+ onFindPrevious: {
+ if (text)
+ currentWebView && currentWebView.findText(text, WebEngineView.FindBackward);
+ else if (!visible)
+ visible = true;
+ }
+ }
+
+
Rectangle {
id: statusBubble
color: "oldlace"
diff --git a/examples/webengine/quicknanobrowser/FindBar.qml b/examples/webengine/quicknanobrowser/FindBar.qml
new file mode 100644
index 000000000..2d673592a
--- /dev/null
+++ b/examples/webengine/quicknanobrowser/FindBar.qml
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.0
+
+Rectangle {
+ id: root
+
+ property int numberOfMatches: 0
+ property int activeMatchOrdinal: 0
+ property alias text: findTextField.text
+
+ function reset() {
+ numberOfMatches = 0;
+ activeMatchOrdinal = 0;
+ visible = false;
+ }
+
+ signal findNext()
+ signal findPrevious()
+
+ width: 250
+ height: 35
+ radius: 2
+
+ border.width: 1
+ border.color: "black"
+ color: "white"
+
+ onVisibleChanged: {
+ if (visible)
+ findTextField.forceActiveFocus();
+ }
+
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.topMargin: 5
+ anchors.bottomMargin: 5
+ anchors.leftMargin: 10
+ anchors.rightMargin: 10
+
+ spacing: 5
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ TextField {
+ id: findTextField
+ anchors.fill: parent
+
+ style: TextFieldStyle {
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+
+ onAccepted: root.findNext()
+ onTextChanged: root.findNext()
+ onActiveFocusChanged: activeFocus ? selectAll() : deselect()
+ }
+ }
+
+ Label {
+ text: activeMatchOrdinal + "/" + numberOfMatches
+ visible: findTextField.text != ""
+ }
+
+ Rectangle {
+ border.width: 1
+ border.color: "#ddd"
+ width: 2
+ height: parent.height
+ anchors.topMargin: 5
+ anchors.bottomMargin: 5
+ }
+
+ ToolButton {
+ text: "<"
+ enabled: numberOfMatches > 0
+ onClicked: root.findPrevious()
+ }
+
+ ToolButton {
+ text: ">"
+ enabled: numberOfMatches > 0
+ onClicked: root.findNext()
+ }
+
+ ToolButton {
+ text: "x"
+ onClicked: root.visible = false
+ }
+ }
+}
diff --git a/examples/webengine/quicknanobrowser/quicknanobrowser.pro b/examples/webengine/quicknanobrowser/quicknanobrowser.pro
index 5a27f5fd4..922cf79e2 100644
--- a/examples/webengine/quicknanobrowser/quicknanobrowser.pro
+++ b/examples/webengine/quicknanobrowser/quicknanobrowser.pro
@@ -10,6 +10,7 @@ OTHER_FILES += ApplicationRoot.qml \
BrowserDialog.qml \
BrowserWindow.qml \
DownloadView.qml \
+ FindBar.qml \
FullScreenNotification.qml
RESOURCES += resources.qrc
diff --git a/examples/webengine/quicknanobrowser/resources.qrc b/examples/webengine/quicknanobrowser/resources.qrc
index c6270897d..50ea05f5e 100644
--- a/examples/webengine/quicknanobrowser/resources.qrc
+++ b/examples/webengine/quicknanobrowser/resources.qrc
@@ -4,6 +4,7 @@
<file>BrowserDialog.qml</file>
<file>BrowserWindow.qml</file>
<file>DownloadView.qml</file>
+ <file>FindBar.qml</file>
<file>FullScreenNotification.qml</file>
</qresource>
<qresource prefix="icons">
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
index 5d00cd19a..2bb9045b0 100644
--- a/examples/webenginewidgets/simplebrowser/browserwindow.cpp
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
@@ -66,6 +66,7 @@
#include <QStatusBar>
#include <QToolBar>
#include <QVBoxLayout>
+#include <QWebEngineFindTextResult>
#include <QWebEngineProfile>
BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools)
@@ -129,6 +130,7 @@ BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool
connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() {
m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text()));
});
+ connect(m_tabWidget, &TabWidget::findTextFinished, this, &BrowserWindow::handleFindTextFinished);
QAction *focusUrlLineEditAction = new QAction(this);
addAction(focusUrlLineEditAction);
@@ -460,10 +462,7 @@ void BrowserWindow::handleFindActionTriggered()
m_lastSearch, &ok);
if (ok && !search.isEmpty()) {
m_lastSearch = search;
- currentTab()->findText(m_lastSearch, 0, [this](bool found) {
- if (!found)
- statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
- });
+ currentTab()->findText(m_lastSearch);
}
}
@@ -526,3 +525,14 @@ void BrowserWindow::handleDevToolsRequested(QWebEnginePage *source)
source->setDevToolsPage(m_browser->createDevToolsWindow()->currentTab()->page());
source->triggerAction(QWebEnginePage::InspectElement);
}
+
+void BrowserWindow::handleFindTextFinished(const QWebEngineFindTextResult &result)
+{
+ if (result.numberOfMatches() == 0) {
+ statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
+ } else {
+ statusBar()->showMessage(tr("\"%1\" found: %2/%3").arg(m_lastSearch,
+ QString::number(result.activeMatchOrdinal()),
+ QString::number(result.numberOfMatches())));
+ }
+}
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.h b/examples/webenginewidgets/simplebrowser/browserwindow.h
index 8f328b751..11a655469 100644
--- a/examples/webenginewidgets/simplebrowser/browserwindow.h
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.h
@@ -88,6 +88,7 @@ private slots:
void handleWebViewTitleChanged(const QString &title);
void handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
void handleDevToolsRequested(QWebEnginePage *source);
+ void handleFindTextFinished(const QWebEngineFindTextResult &result);
private:
QMenu *createFileMenu(TabWidget *tabWidget);
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
index 369bebfd9..3b6d84ebe 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
@@ -200,6 +200,10 @@ void TabWidget::setupView(WebView *webView)
closeTab(index);
});
connect(webView, &WebView::devToolsRequested, this, &TabWidget::devToolsRequested);
+ connect(webPage, &QWebEnginePage::findTextFinished, [this, webView](const QWebEngineFindTextResult &result) {
+ if (currentIndex() == indexOf(webView))
+ emit findTextFinished(result);
+ });
}
WebView *TabWidget::createTab()
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.h b/examples/webenginewidgets/simplebrowser/tabwidget.h
index bf83781df..fba61d44f 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.h
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.h
@@ -78,6 +78,7 @@ signals:
void favIconChanged(const QIcon &icon);
void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
void devToolsRequested(QWebEnginePage *source);
+ void findTextFinished(const QWebEngineFindTextResult &result);
public slots:
// current tab/page slots
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro
index 326d4481f..5e8b8387e 100644
--- a/src/core/api/core_api.pro
+++ b/src/core/api/core_api.pro
@@ -37,6 +37,7 @@ HEADERS = \
qtwebenginecoreglobal_p.h \
qwebenginecookiestore.h \
qwebenginecookiestore_p.h \
+ qwebenginefindtextresult.h \
qwebenginehttprequest.h \
qwebenginemessagepumpscheduler_p.h \
qwebenginenotification.h \
@@ -53,6 +54,7 @@ SOURCES = \
qtwebenginecoreglobal.cpp \
qwebengineclientcertificatestore.cpp \
qwebenginecookiestore.cpp \
+ qwebenginefindtextresult.cpp \
qwebenginehttprequest.cpp \
qwebenginemessagepumpscheduler.cpp \
qwebenginenotification.cpp \
diff --git a/src/core/api/qwebenginefindtextresult.cpp b/src/core/api/qwebenginefindtextresult.cpp
new file mode 100644
index 000000000..ce1be359e
--- /dev/null
+++ b/src/core/api/qwebenginefindtextresult.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwebenginefindtextresult.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWebEngineFindTextResultPrivate : public QSharedData {
+public:
+ int numberOfMatches = 0;
+ int activeMatchOrdinal = 0;
+};
+
+/*!
+ \class QWebEngineFindTextResult
+ \brief The QWebEngineFindTextResult class encapsulates the result of a string search on a page.
+ \since 5.14
+
+ \inmodule QtWebEngineCore
+
+ Results are passed to the user in the
+ \l QWebEnginePage::findTextFinished() and
+ \l{WebEngineView::findTextFinished()}{WebEngineView.findTextFinished()} signals.
+*/
+
+/*! \internal
+*/
+QWebEngineFindTextResult::QWebEngineFindTextResult()
+ : d(new QWebEngineFindTextResultPrivate)
+{}
+
+/*! \internal
+*/
+QWebEngineFindTextResult::QWebEngineFindTextResult(int numberOfMatches, int activeMatchOrdinal)
+ : d(new QWebEngineFindTextResultPrivate)
+{
+ d->numberOfMatches = numberOfMatches;
+ d->activeMatchOrdinal = activeMatchOrdinal;
+}
+
+/*! \internal
+*/
+QWebEngineFindTextResult::QWebEngineFindTextResult(const QWebEngineFindTextResult &other)
+ : d(other.d)
+{}
+
+/*! \internal
+*/
+QWebEngineFindTextResult &QWebEngineFindTextResult::operator=(const QWebEngineFindTextResult &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*! \internal
+*/
+QWebEngineFindTextResult::~QWebEngineFindTextResult()
+{}
+
+/*!
+ \property QWebEngineFindTextResult::numberOfMatches
+ \brief The number of matches found.
+*/
+int QWebEngineFindTextResult::numberOfMatches() const
+{
+ return d->numberOfMatches;
+}
+
+/*!
+ \property QWebEngineFindTextResult::activeMatchOrdinal
+ \brief The index of the currently highlighted match.
+*/
+int QWebEngineFindTextResult::activeMatchOrdinal() const
+{
+ return d->activeMatchOrdinal;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwebenginefindtextresult.cpp"
diff --git a/src/core/api/qwebenginefindtextresult.h b/src/core/api/qwebenginefindtextresult.h
new file mode 100644
index 000000000..073a8135f
--- /dev/null
+++ b/src/core/api/qwebenginefindtextresult.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBENGINEFINDTEXTRESULT_H
+#define QWEBENGINEFINDTEXTRESULT_H
+
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+#include <QtCore/QObject>
+#include <QtCore/QSharedData>
+
+namespace QtWebEngineCore {
+class FindTextHelper;
+}
+
+QT_BEGIN_NAMESPACE
+
+class QWebEngineFindTextResultPrivate;
+
+class Q_WEBENGINECORE_EXPORT QWebEngineFindTextResult {
+ Q_GADGET
+ Q_PROPERTY(int numberOfMatches READ numberOfMatches CONSTANT FINAL)
+ Q_PROPERTY(int activeMatchOrdinal READ activeMatchOrdinal CONSTANT FINAL)
+
+public:
+ int numberOfMatches() const;
+ int activeMatchOrdinal() const;
+
+ QWebEngineFindTextResult();
+ QWebEngineFindTextResult(const QWebEngineFindTextResult &other);
+ QWebEngineFindTextResult &operator=(const QWebEngineFindTextResult &other);
+ ~QWebEngineFindTextResult();
+
+private:
+ QWebEngineFindTextResult(int numberOfMatches, int activeMatchOrdinal);
+
+ QSharedDataPointer<QWebEngineFindTextResultPrivate> d;
+
+ friend class QtWebEngineCore::FindTextHelper;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QWebEngineFindTextResult)
+
+#endif // QWEBENGINEFINDTEXTRESULT_H
diff --git a/src/core/find_text_helper.cpp b/src/core/find_text_helper.cpp
index 5fb56dacc..effda529f 100644
--- a/src/core/find_text_helper.cpp
+++ b/src/core/find_text_helper.cpp
@@ -38,7 +38,9 @@
****************************************************************************/
#include "find_text_helper.h"
+#include "qwebenginefindtextresult.h"
#include "type_conversion.h"
+#include "web_contents_adapter_client.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
@@ -48,8 +50,9 @@ namespace QtWebEngineCore {
// static
int FindTextHelper::m_findRequestIdCounter = -1;
-FindTextHelper::FindTextHelper(content::WebContents *webContents)
+FindTextHelper::FindTextHelper(content::WebContents *webContents, WebContentsAdapterClient *viewClient)
: m_webContents(webContents)
+ , m_viewClient(viewClient)
, m_currentFindRequestId(m_findRequestIdCounter++)
, m_lastCompletedFindRequestId(m_currentFindRequestId)
{
@@ -65,6 +68,7 @@ void FindTextHelper::startFinding(const QString &findText, bool caseSensitively,
{
if (findText.isEmpty()) {
stopFinding();
+ m_viewClient->findTextFinished(QWebEngineFindTextResult());
m_widgetCallbacks.invokeEmpty(resultCallback);
return;
}
@@ -77,6 +81,7 @@ void FindTextHelper::startFinding(const QString &findText, bool caseSensitively,
{
if (findText.isEmpty()) {
stopFinding();
+ m_viewClient->findTextFinished(QWebEngineFindTextResult());
if (!resultCallback.isUndefined()) {
QJSValueList args;
args.append(QJSValue(0));
@@ -103,6 +108,7 @@ void FindTextHelper::startFinding(const QString &findText, bool caseSensitively,
// waiting for it forever.
// Assume that any unfinished find has been unsuccessful when a new one is started
// to cover that case.
+ m_viewClient->findTextFinished(QWebEngineFindTextResult());
invokeResultCallback(m_currentFindRequestId, 0);
}
@@ -132,7 +138,6 @@ void FindTextHelper::handleFindReply(content::WebContents *source, int requestId
const gfx::Rect &selectionRect, int activeMatchOrdinal, bool finalUpdate)
{
Q_UNUSED(selectionRect);
- Q_UNUSED(activeMatchOrdinal);
Q_ASSERT(source == m_webContents);
@@ -141,6 +146,7 @@ void FindTextHelper::handleFindReply(content::WebContents *source, int requestId
Q_ASSERT(m_currentFindRequestId == requestId);
m_lastCompletedFindRequestId = requestId;
+ m_viewClient->findTextFinished(QWebEngineFindTextResult(numberOfMatches, activeMatchOrdinal));
invokeResultCallback(requestId, numberOfMatches);
}
diff --git a/src/core/find_text_helper.h b/src/core/find_text_helper.h
index 17e76ecc7..e8f186272 100644
--- a/src/core/find_text_helper.h
+++ b/src/core/find_text_helper.h
@@ -66,9 +66,11 @@ class Rect;
namespace QtWebEngineCore {
+class WebContentsAdapterClient;
+
class Q_WEBENGINECORE_PRIVATE_EXPORT FindTextHelper {
public:
- FindTextHelper(content::WebContents *webContents);
+ FindTextHelper(content::WebContents *webContents, WebContentsAdapterClient *viewClient);
~FindTextHelper();
void startFinding(const QString &findText, bool caseSensitively, bool findBackward, const QWebEngineCallback<bool> resultCallback);
@@ -83,6 +85,7 @@ private:
void invokeResultCallback(int requestId, int numberOfMatches);
content::WebContents *m_webContents;
+ WebContentsAdapterClient *m_viewClient;
static int m_findRequestIdCounter;
int m_currentFindRequestId;
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 4743c1ed7..4bdb55b4c 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -64,6 +64,7 @@ QT_FORWARD_DECLARE_CLASS(CertificateErrorController)
QT_FORWARD_DECLARE_CLASS(ClientCertSelectController)
QT_FORWARD_DECLARE_CLASS(QKeyEvent)
QT_FORWARD_DECLARE_CLASS(QVariant)
+QT_FORWARD_DECLARE_CLASS(QWebEngineFindTextResult)
QT_FORWARD_DECLARE_CLASS(QWebEngineQuotaRequest)
QT_FORWARD_DECLARE_CLASS(QWebEngineRegisterProtocolHandlerRequest)
QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInfo)
@@ -498,6 +499,7 @@ public:
virtual TouchHandleDrawableClient *createTouchHandle(const QMap<int, QImage> &images) = 0;
virtual void showTouchSelectionMenu(TouchSelectionMenuController *menuController, const QRect &bounds, const QSize &handleSize) = 0;
virtual void hideTouchSelectionMenu() = 0;
+ virtual void findTextFinished(const QWebEngineFindTextResult &result) = 0;
virtual ProfileAdapter *profileAdapter() = 0;
virtual WebContentsAdapter* webContentsAdapter() = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index e3015d5f6..9855e3859 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -103,7 +103,7 @@ static WebContentsAdapterClient::JavaScriptConsoleMessageLevel mapToJavascriptCo
WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents *webContents, WebContentsAdapterClient *adapterClient)
: m_viewClient(adapterClient)
, m_faviconManager(new FaviconManager(webContents, adapterClient))
- , m_findTextHelper(new FindTextHelper(webContents))
+ , m_findTextHelper(new FindTextHelper(webContents, adapterClient))
, m_lastLoadProgress(-1)
, m_loadingState(determineLoadingState(webContents))
, m_didStartLoadingSeen(m_loadingState == LoadingState::Loading)
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index f340ebd33..58d950cd9 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -62,6 +62,7 @@
#include "qquickwebenginesettings_p.h"
#include "qquickwebenginescript_p.h"
#include "qquickwebenginetouchhandleprovider_p_p.h"
+#include "qwebenginefindtextresult.h"
#include "qwebenginequotarequest.h"
#include "qwebengineregisterprotocolhandlerrequest.h"
@@ -699,6 +700,12 @@ void QQuickWebEngineViewPrivate::widgetChanged(RenderWidgetHostViewQtDelegate *n
bindViewAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateQuick *>(newWidgetBase));
}
+void QQuickWebEngineViewPrivate::findTextFinished(const QWebEngineFindTextResult &result)
+{
+ Q_Q(QQuickWebEngineView);
+ Q_EMIT q->findTextFinished(result);
+}
+
WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const
{
return m_settings->d_ptr.data();
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 3c8e1d9ec..4a88e3c28 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -79,6 +79,7 @@ class QQuickWebEngineSettings;
class QQuickWebEngineTooltipRequest;
class QQuickWebEngineFormValidationMessageRequest;
class QQuickWebEngineViewPrivate;
+class QWebEngineFindTextResult;
class QWebEngineQuotaRequest;
class QWebEngineRegisterProtocolHandlerRequest;
@@ -574,6 +575,7 @@ Q_SIGNALS:
Q_REVISION(10) void tooltipRequested(QQuickWebEngineTooltipRequest *request);
Q_REVISION(11) void lifecycleStateChanged(LifecycleState state);
Q_REVISION(11) void recommendedStateChanged(LifecycleState state);
+ Q_REVISION(11) void findTextFinished(const QWebEngineFindTextResult &result);
#if QT_CONFIG(webengine_testsupport)
void testSupportChanged();
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 7a1916d82..df6843ac3 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -80,6 +80,7 @@ class QQuickWebEngineSettings;
class QQuickWebEngineFaviconProvider;
class QQuickWebEngineProfilePrivate;
class QQuickWebEngineTouchHandleProvider;
+class QWebEngineFindTextResult;
QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event);
@@ -169,6 +170,7 @@ public:
QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override;
void printRequested() override;
void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidgetBase) override;
+ void findTextFinished(const QWebEngineFindTextResult &result) override;
void updateAction(QQuickWebEngineView::WebAction) const;
void adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents);
diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index 1c4328d01..8f03774c8 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -414,26 +414,33 @@
\qmlmethod void WebEngineView::findText(string subString)
\since QtWebEngine 1.1
Finds the specified string, \a subString, in the page.
+ The findTextFinished() signal is emitted when a string search is completed.
To clear the search highlight, just pass an empty string.
+
+ \sa findTextFinished()
*/
/*!
\qmlmethod void WebEngineView::findText(string subString, FindFlags options)
\since QtWebEngine 1.1
Finds the specified string, \a subString, in the page, using the given \a options.
+ The findTextFinished() signal is emitted when a string search is completed.
To clear the search highlight, just pass an empty string.
\code
findText("Qt", WebEngineView.FindBackward | WebEngineView.FindCaseSensitively);
\endcode
+
+ \sa findTextFinished()
*/
/*!
\qmlmethod void WebEngineView::findText(string subString, FindFlags options, variant resultCallback)
\since QtWebEngine 1.1
Finds the specified string, \a subString, in the page, using the given \a options.
+ The findTextFinished() signal is emitted when a string search is completed.
To clear the search highlight, just pass an empty string.
@@ -447,6 +454,8 @@
console.log("Qt was found!");
});
\endcode
+
+ \sa findTextFinished()
*/
/*!
@@ -1569,5 +1578,39 @@
resource state is however completely safe.
\sa lifecycleState, {WebEngine Lifecycle Example}
+*/
+
+/*!
+ \qmltype FindTextResult
+ \instantiates QWebEngineFindTextResult
+ \inqmlmodule QtWebEngine
+ \since QtWebEngine 1.11
+
+ \brief A utility type for encapsulating the result of a string search on a page.
+
+ \sa WebEngineView::findTextFinished()
+*/
+
+/*!
+ \qmlproperty int FindTextResult::numberOfMatches
+ \readonly
+
+ \brief The number of matches found.
+*/
+
+/*!
+ \qmlproperty int FindTextResult::activeMatchOrdinal
+ \readonly
+
+ \brief The index of the currently highlighted match.
+*/
+
+/*!
+ \qmlsignal WebEngineView::findTextFinished(FindTextResult result)
+ \since QtWebEngine 1.11
+
+ This signal is emitted when a string search on a page is completed. \a result is
+ the result of the string search.
+ \sa findText(), FindTextResult
*/
diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp
index ad49d6543..e47a46a95 100644
--- a/src/webengine/plugin/plugin.cpp
+++ b/src/webengine/plugin/plugin.cpp
@@ -55,6 +55,7 @@
#include <QtWebEngine/private/qquickwebenginetouchhandleprovider_p_p.h>
#include <QtWebEngine/private/qquickwebengineview_p.h>
#include <QtWebEngine/private/qquickwebengineaction_p.h>
+#include <QtWebEngineCore/qwebenginefindtextresult.h>
#include <QtWebEngineCore/qwebenginenotification.h>
#include <QtWebEngineCore/qwebenginequotarequest.h>
#include <QtWebEngineCore/qwebengineregisterprotocolhandlerrequest.h>
@@ -170,6 +171,8 @@ public:
qmlRegisterUncreatableType<QWebEngineNotification>(uri, 1, 9, "WebEngineNotification", msgUncreatableType("WebEngineNotification"));
qmlRegisterUncreatableType<QQuickWebEngineTooltipRequest>(uri, 1, 10, "TooltipRequest",
msgUncreatableType("TooltipRequest"));
+ qRegisterMetaType<QWebEngineFindTextResult>();
+ qmlRegisterUncreatableType<QWebEngineFindTextResult>(uri, 1, 11, "FindTextResult", msgUncreatableType("FindTextResult"));
}
private:
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 29566f021..c9e9177b7 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -52,6 +52,7 @@
#include "printer_worker.h"
#endif
#include "qwebenginecertificateerror.h"
+#include "qwebenginefindtextresult.h"
#include "qwebenginefullscreenrequest.h"
#include "qwebenginehistory.h"
#include "qwebenginehistory_p.h"
@@ -171,6 +172,7 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile)
qRegisterMetaType<QWebEngineQuotaRequest>();
qRegisterMetaType<QWebEngineRegisterProtocolHandlerRequest>();
+ qRegisterMetaType<QWebEngineFindTextResult>();
// See setVisible().
wasShownTimer.setSingleShot(true);
@@ -698,6 +700,12 @@ void QWebEnginePagePrivate::widgetChanged(RenderWidgetHostViewQtDelegate *newWid
bindPageAndWidget(q, static_cast<RenderWidgetHostViewQtDelegateWidget *>(newWidgetBase));
}
+void QWebEnginePagePrivate::findTextFinished(const QWebEngineFindTextResult &result)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->findTextFinished(result);
+}
+
void QWebEnginePagePrivate::ensureInitialized() const
{
if (!adapter->isInitialized())
@@ -798,6 +806,16 @@ QWebEnginePage::QWebEnginePage(QObject* parent)
}
/*!
+ \fn void QWebEnginePage::findTextFinished(const QWebEngineFindTextResult &result)
+ \since 5.14
+
+ This signal is emitted when a search string search on a page is completed. \a result is
+ the result of the string search.
+
+ \sa findText()
+*/
+
+/*!
\fn void QWebEnginePage::printRequested()
\since 5.12
diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h
index 736d7ed69..cd012ea70 100644
--- a/src/webenginewidgets/api/qwebenginepage.h
+++ b/src/webenginewidgets/api/qwebenginepage.h
@@ -62,6 +62,7 @@ class QWebChannel;
class QWebEngineCertificateError;
class QWebEngineClientCertificateSelection;
class QWebEngineContextMenuData;
+class QWebEngineFindTextResult;
class QWebEngineFullScreenRequest;
class QWebEngineHistory;
class QWebEnginePage;
@@ -369,6 +370,8 @@ Q_SIGNALS:
void lifecycleStateChanged(LifecycleState state);
void recommendedStateChanged(LifecycleState state);
+ void findTextFinished(const QWebEngineFindTextResult &result);
+
protected:
virtual QWebEnginePage *createWindow(WebWindowType type);
virtual QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes);
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index a8cde8199..fae97b9fa 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -72,6 +72,7 @@ class WebContentsAdapter;
}
QT_BEGIN_NAMESPACE
+class QWebEngineFindTextResult;
class QWebEngineHistory;
class QWebEnginePage;
class QWebEngineProfile;
@@ -162,6 +163,7 @@ public:
ClientType clientType() override { return QtWebEngineCore::WebContentsAdapterClient::WidgetsClient; }
void interceptRequest(QWebEngineUrlRequestInfo &) override;
void widgetChanged(QtWebEngineCore::RenderWidgetHostViewQtDelegate *newWidget) override;
+ void findTextFinished(const QWebEngineFindTextResult &result) override;
QtWebEngineCore::ProfileAdapter *profileAdapter() override;
QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override;
diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
index 99bbc5162..64fe4c9cd 100644
--- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
@@ -489,6 +489,7 @@
/*!
\fn void QWebEnginePage::findText(const QString &subString, QWebEnginePage::FindFlags options = FindFlags(), const QWebEngineCallback<bool> &resultCallback = QWebEngineCallback<bool>())
Finds the specified string, \a subString, in the page, using the given \a options.
+ The findTextFinished() signal is emitted when a string search is completed.
To clear the search highlight, just pass an empty string.
@@ -501,6 +502,8 @@
For example:
\snippet qtwebengine_qwebenginepage_snippet.cpp 0
+
+ \sa findTextFinished()
*/
/*!
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index f464d58d0..9f7dfa8ad 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -35,6 +35,7 @@
#include <QtTest/QtTest>
#include <QtWebEngine/QQuickWebEngineProfile>
#include <QtWebEngine/QQuickWebEngineScript>
+#include <QtWebEngineCore/QWebEngineFindTextResult>
#include <QtWebEngineCore/QWebEngineNotification>
#include <QtWebEngineCore/QWebEngineQuotaRequest>
#include <QtWebEngineCore/QWebEngineRegisterProtocolHandlerRequest>
@@ -85,6 +86,7 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *
<< &QWebEngineQuotaRequest::staticMetaObject
<< &QWebEngineRegisterProtocolHandlerRequest::staticMetaObject
<< &QWebEngineNotification::staticMetaObject
+ << &QWebEngineFindTextResult::staticMetaObject
;
static QList<const char *> knownEnumNames = QList<const char *>();
@@ -276,6 +278,8 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineFileDialogRequest.dialogAccept(QStringList) --> void"
<< "QQuickWebEngineFileDialogRequest.dialogReject() --> void"
<< "QQuickWebEngineFileDialogRequest.mode --> FileMode"
+ << "QWebEngineFindTextResult.numberOfMatches --> int"
+ << "QWebEngineFindTextResult.activeMatchOrdinal --> int"
<< "QQuickWebEngineFormValidationMessageRequest.Hide --> RequestType"
<< "QQuickWebEngineFormValidationMessageRequest.Move --> RequestType"
<< "QQuickWebEngineFormValidationMessageRequest.Show --> RequestType"
@@ -694,6 +698,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.findText(QString) --> void"
<< "QQuickWebEngineView.findText(QString,FindFlags) --> void"
<< "QQuickWebEngineView.findText(QString,FindFlags,QJSValue) --> void"
+ << "QQuickWebEngineView.findTextFinished(QWebEngineFindTextResult) --> void"
<< "QQuickWebEngineView.formValidationMessageRequested(QQuickWebEngineFormValidationMessageRequest*) --> void"
<< "QQuickWebEngineView.fullScreenCancelled() --> void"
<< "QQuickWebEngineView.fullScreenRequested(QQuickWebEngineFullScreenRequest) --> void"
diff --git a/tests/auto/quick/qmltests/data/tst_findText.qml b/tests/auto/quick/qmltests/data/tst_findText.qml
index 14053a675..040d324e6 100644
--- a/tests/auto/quick/qmltests/data/tst_findText.qml
+++ b/tests/auto/quick/qmltests/data/tst_findText.qml
@@ -38,9 +38,16 @@ TestWebEngineView {
property int matchCount: 0
property bool findFailed: false
+ SignalSpy {
+ id: findTextSpy
+ target: webEngineView
+ signalName: "findTextFinished"
+ }
+
function clear() {
findFailed = false
matchCount = -1
+ findTextSpy.clear()
}
function findCallbackCalled() { return matchCount != -1 }
@@ -104,6 +111,9 @@ TestWebEngineView {
webEngineView.findText("Hello", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 1)
verify(!findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 1)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1)
}
function test_findTextCaseInsensitive() {
@@ -115,6 +125,9 @@ TestWebEngineView {
webEngineView.findText("heLLo", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 1)
verify(!findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 1)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1)
}
function test_findTextManyMatches() {
@@ -126,6 +139,9 @@ TestWebEngineView {
webEngineView.findText("bla", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 100, 20000)
verify(!findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 100)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1)
}
@@ -138,6 +154,9 @@ TestWebEngineView {
webEngineView.findText("heLLo", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 0)
verify(findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 0)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 0)
}
function test_findTextNotFound() {
@@ -149,6 +168,9 @@ TestWebEngineView {
webEngineView.findText("string-that-is-not-threre", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 0)
verify(findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 0)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 0)
}
function test_findTextAfterNotFound() {
@@ -160,6 +182,9 @@ TestWebEngineView {
webEngineView.findText("hello", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 0)
verify(findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 0)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 0)
webEngineView.url = Qt.resolvedUrl("test1.html")
verify(webEngineView.waitForLoadSucceeded())
@@ -168,6 +193,9 @@ TestWebEngineView {
webEngineView.findText("hello", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 1)
verify(!findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 1)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1)
}
function test_findTextInModifiedDOMAfterNotFound() {
@@ -182,6 +210,9 @@ TestWebEngineView {
webEngineView.findText("hello", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 0, 20000)
verify(findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 0)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 0)
runJavaScript("document.body.innerHTML = 'blahellobla'");
tryVerify(function() { return getBodyInnerHTML() == "blahellobla"; }, 20000);
@@ -190,6 +221,9 @@ TestWebEngineView {
webEngineView.findText("hello", findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, "matchCount", 1)
verify(!findFailed)
+ tryCompare(findTextSpy, "count", 1)
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 1)
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1)
}
function test_findTextInterruptedByLoad() {
@@ -227,5 +261,55 @@ TestWebEngineView {
webEngineView.findText('New page', findFlags, webEngineView.findTextCallback)
tryCompare(webEngineView, 'matchCount', 1)
}
+
+ function test_findTextActiveMatchOrdinal() {
+ webEngineView.loadHtml(
+ "<html><body>" +
+ "foo bar foo bar foo" +
+ "</body></html>");
+ verify(webEngineView.waitForLoadSucceeded());
+
+ // Iterate over all "foo" matches.
+ webEngineView.clear();
+ for (var i = 1; i <= 3; ++i) {
+ webEngineView.findText("foo");
+ findTextSpy.wait();
+ compare(findTextSpy.count, i);
+ compare(findTextSpy.signalArguments[i-1][0].numberOfMatches, 3);
+ compare(findTextSpy.signalArguments[i-1][0].activeMatchOrdinal, i);
+ }
+
+ // The last match is followed by the fist one.
+ webEngineView.clear();
+ webEngineView.findText("foo");
+ findTextSpy.wait();
+ compare(findTextSpy.count, 1);
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 3);
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1);
+
+ // The first match is preceded by the last one.
+ webEngineView.clear();
+ webEngineView.findText("foo", WebEngineView.FindBackward);
+ findTextSpy.wait();
+ compare(findTextSpy.count, 1);
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 3);
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 3);
+
+ // Finding another word resets the activeMatchOrdinal.
+ webEngineView.clear();
+ webEngineView.findText("bar");
+ findTextSpy.wait();
+ compare(findTextSpy.count, 1);
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 2);
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 1);
+
+ // If no match activeMatchOrdinal is 0.
+ webEngineView.clear();
+ webEngineView.findText("bla");
+ findTextSpy.wait();
+ compare(findTextSpy.count, 1);
+ compare(findTextSpy.signalArguments[0][0].numberOfMatches, 0);
+ compare(findTextSpy.signalArguments[0][0].activeMatchOrdinal, 0);
+ }
}
}
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 7e9815298..dbb15ba10 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -47,6 +47,7 @@
#include <qnetworkreply.h>
#include <qnetworkrequest.h>
#include <qwebenginedownloaditem.h>
+#include <qwebenginefindtextresult.h>
#include <qwebenginefullscreenrequest.h>
#include <qwebenginehistory.h>
#include <qwebenginenotification.h>
@@ -128,6 +129,7 @@ private Q_SLOTS:
void findTextResult();
void findTextSuccessiveShouldCallAllCallbacks();
void findTextCalledOnMatch();
+ void findTextActiveMatchOrdinal();
void deleteQWebEngineViewTwice();
void loadSignalsOrder_data();
void loadSignalsOrder();
@@ -942,18 +944,24 @@ void tst_QWebEnginePage::findText()
// Invoking a stopFinding operation will not change or clear the currently selected text,
// if nothing was found beforehand.
{
- CallbackSpy<bool> spy;
- m_view->findText("", 0, spy.ref());
- QVERIFY(spy.wasCalled());
+ CallbackSpy<bool> callbackSpy;
+ QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
+ m_view->findText("", 0, callbackSpy.ref());
+ QVERIFY(callbackSpy.wasCalled());
+ QCOMPARE(signalSpy.count(), 1);
QTRY_COMPARE(m_view->selectedText(), QString("foo bar"));
}
// Invoking a startFinding operation with text that won't be found, will clear the current
// selection.
{
- CallbackSpy<bool> spy;
- m_view->findText("Will not be found", 0, spy.ref());
- QCOMPARE(spy.waitForResult(), false);
+ CallbackSpy<bool> callbackSpy;
+ QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
+ m_view->findText("Will not be found", 0, callbackSpy.ref());
+ QCOMPARE(callbackSpy.waitForResult(), false);
+ QTRY_COMPARE(signalSpy.count(), 1);
+ auto result = signalSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ QCOMPARE(result.numberOfMatches(), 0);
QTRY_VERIFY(m_view->selectedText().isEmpty());
}
@@ -964,24 +972,36 @@ void tst_QWebEnginePage::findText()
// Invoking a startFinding operation with text that will be found, will clear the current
// selection as well.
{
- CallbackSpy<bool> spy;
- m_view->findText("foo", 0, spy.ref());
- QVERIFY(spy.waitForResult());
+ CallbackSpy<bool> callbackSpy;
+ QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
+ m_view->findText("foo", 0, callbackSpy.ref());
+ QVERIFY(callbackSpy.waitForResult());
+ QTRY_COMPARE(signalSpy.count(), 1);
QTRY_VERIFY(m_view->selectedText().isEmpty());
}
// Invoking a stopFinding operation after text was found, will set the selected text to the
// found text.
{
- CallbackSpy<bool> spy;
- m_view->findText("", 0, spy.ref());
- QTRY_VERIFY(spy.wasCalled());
+ CallbackSpy<bool> callbackSpy;
+ QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
+ m_view->findText("", 0, callbackSpy.ref());
+ QTRY_VERIFY(callbackSpy.wasCalled());
+ QTRY_COMPARE(signalSpy.count(), 1);
QTRY_COMPARE(m_view->selectedText(), QString("foo"));
}
}
void tst_QWebEnginePage::findTextResult()
{
+ QSignalSpy findTextSpy(m_view->page(), &QWebEnginePage::findTextFinished);
+ auto signalResult = [&findTextSpy]() -> QVector<int> {
+ if (findTextSpy.count() != 1)
+ return QVector<int>({-1, -1});
+ auto r = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ return QVector<int>({ r.numberOfMatches(), r.activeMatchOrdinal() });
+ };
+
// findText will abort in blink if the view has an empty size.
m_view->resize(800, 600);
m_view->show();
@@ -991,15 +1011,21 @@ void tst_QWebEnginePage::findTextResult()
QTRY_COMPARE(loadSpy.count(), 1);
QCOMPARE(findTextSync(m_page, ""), false);
+ QCOMPARE(signalResult(), QVector<int>({0, 0}));
const QStringList words = { "foo", "bar" };
for (const QString &subString : words) {
QCOMPARE(findTextSync(m_page, subString), true);
+ QCOMPARE(signalResult(), QVector<int>({1, 1}));
+
QCOMPARE(findTextSync(m_page, ""), false);
+ QCOMPARE(signalResult(), QVector<int>({0, 0}));
}
QCOMPARE(findTextSync(m_page, "blahhh"), false);
+ QCOMPARE(signalResult(), QVector<int>({0, 0}));
QCOMPARE(findTextSync(m_page, ""), false);
+ QCOMPARE(signalResult(), QVector<int>({0, 0}));
}
void tst_QWebEnginePage::findTextSuccessiveShouldCallAllCallbacks()
@@ -1035,6 +1061,7 @@ void tst_QWebEnginePage::findTextCalledOnMatch()
m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>"));
QTRY_COMPARE(loadSpy.count(), 1);
+ // CALLBACK
bool callbackCalled = false;
m_view->page()->findText("foo", 0, [this, &callbackCalled](bool found) {
QVERIFY(found);
@@ -1045,6 +1072,68 @@ void tst_QWebEnginePage::findTextCalledOnMatch()
});
});
QTRY_VERIFY(callbackCalled);
+
+ // SIGNAL
+ int findTextFinishedCount = 0;
+ connect(m_view->page(), &QWebEnginePage::findTextFinished, [this, &findTextFinishedCount](QWebEngineFindTextResult result) {
+ QCOMPARE(result.numberOfMatches(), 1);
+ if (findTextFinishedCount == 0)
+ m_view->page()->findText("bar");
+ findTextFinishedCount++;
+ });
+
+ m_view->page()->findText("foo");
+ QTRY_COMPARE(findTextFinishedCount, 2);
+}
+
+void tst_QWebEnginePage::findTextActiveMatchOrdinal()
+{
+ QSignalSpy loadSpy(m_view->page(), &QWebEnginePage::loadFinished);
+ QSignalSpy findTextSpy(m_view->page(), &QWebEnginePage::findTextFinished);
+ QWebEngineFindTextResult result;
+
+ // findText will abort in blink if the view has an empty size.
+ m_view->resize(800, 600);
+ m_view->show();
+ m_view->setHtml(QString("<html><head></head><body><div>foo bar foo bar foo</div></body></html>"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ // Iterate over all "foo" matches.
+ for (int i = 1; i <= 3; ++i) {
+ m_view->page()->findText("foo", 0);
+ QTRY_COMPARE(findTextSpy.count(), 1);
+ result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ QCOMPARE(result.numberOfMatches(), 3);
+ QCOMPARE(result.activeMatchOrdinal(), i);
+ }
+
+ // The last match is followed by the fist one.
+ m_view->page()->findText("foo", 0);
+ QTRY_COMPARE(findTextSpy.count(), 1);
+ result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ QCOMPARE(result.numberOfMatches(), 3);
+ QCOMPARE(result.activeMatchOrdinal(), 1);
+
+ // The first match is preceded by the last one.
+ m_view->page()->findText("foo", QWebEnginePage::FindBackward);
+ QTRY_COMPARE(findTextSpy.count(), 1);
+ result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ QCOMPARE(result.numberOfMatches(), 3);
+ QCOMPARE(result.activeMatchOrdinal(), 3);
+
+ // Finding another word resets the activeMatchOrdinal.
+ m_view->page()->findText("bar", 0);
+ QTRY_COMPARE(findTextSpy.count(), 1);
+ result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ QCOMPARE(result.numberOfMatches(), 2);
+ QCOMPARE(result.activeMatchOrdinal(), 1);
+
+ // If no match activeMatchOrdinal is 0.
+ m_view->page()->findText("bla", 0);
+ QTRY_COMPARE(findTextSpy.count(), 1);
+ result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
+ QCOMPARE(result.numberOfMatches(), 0);
+ QCOMPARE(result.activeMatchOrdinal(), 0);
}
static QWindow *findNewTopLevelWindow(const QWindowList &oldTopLevelWindows)