summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnu Aliyas <anu.aliyas@qt.io>2023-04-17 13:34:23 +0200
committerAnu Aliyas <anu.aliyas@qt.io>2023-04-20 16:32:38 +0200
commit97c3782e2f5ecd3115aab1d0216b989b55f54f21 (patch)
tree0a8832e5d214707e224585165ae8dd5bc428d84c
parent421d3c4e0b57170343df57de0b222d0f57a7bcb7 (diff)
downloadqtwebengine-97c3782e2f5ecd3115aab1d0216b989b55f54f21.tar.gz
Add WebEngineView::save() convenience API
Add the convenience method QQuickWebEngineView::save for saving pages without the need to explicitly handle download requests. Task-number: QTBUG-56093 Change-Id: I67909fdca6472d1ea9b32e0f89c1ab90219bca3b Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io> Reviewed-by: Michal Klocek <michal.klocek@qt.io>
-rw-r--r--src/webenginequick/api/qquickwebengineprofile.cpp3
-rw-r--r--src/webenginequick/api/qquickwebengineview.cpp7
-rw-r--r--src/webenginequick/api/qquickwebengineview_p.h5
-rw-r--r--src/webenginequick/doc/src/webengineview_lgpl.qdoc19
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp6
-rw-r--r--tests/auto/quick/qmltests/CMakeLists.txt1
-rw-r--r--tests/auto/quick/qmltests/data/tst_save.qml123
-rw-r--r--tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp78
8 files changed, 240 insertions, 2 deletions
diff --git a/src/webenginequick/api/qquickwebengineprofile.cpp b/src/webenginequick/api/qquickwebengineprofile.cpp
index a830e969e..92ab9dc25 100644
--- a/src/webenginequick/api/qquickwebengineprofile.cpp
+++ b/src/webenginequick/api/qquickwebengineprofile.cpp
@@ -212,7 +212,8 @@ void QQuickWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
QWebEngineDownloadRequestPrivate *itemPrivate =
new QWebEngineDownloadRequestPrivate(m_profileAdapter);
itemPrivate->downloadId = info.id;
- itemPrivate->downloadState = QWebEngineDownloadRequest::DownloadRequested;
+ itemPrivate->downloadState = info.accepted ? QWebEngineDownloadRequest::DownloadInProgress
+ : QWebEngineDownloadRequest::DownloadRequested;
itemPrivate->startTime = info.startTime;
itemPrivate->downloadUrl = info.url;
itemPrivate->totalBytes = info.totalBytes;
diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp
index 2d49c9419..f11274741 100644
--- a/src/webenginequick/api/qquickwebengineview.cpp
+++ b/src/webenginequick/api/qquickwebengineview.cpp
@@ -2411,6 +2411,13 @@ QQmlComponent *QQuickWebEngineView::touchHandleDelegate() const
return d_ptr->m_touchHandleDelegate;
}
+void QQuickWebEngineView::save(const QString &filePath,
+ QWebEngineDownloadRequest::SavePageFormat format) const
+{
+ Q_D(const QQuickWebEngineView);
+ d->adapter->save(filePath, format);
+}
+
QT_END_NAMESPACE
#include "moc_qquickwebengineview_p.cpp"
diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h
index 946bf1e0a..f057ba9be 100644
--- a/src/webenginequick/api/qquickwebengineview_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p.h
@@ -17,6 +17,7 @@
#include <QtWebEngineCore/qtwebenginecoreglobal.h>
#include <QtWebEngineCore/qwebenginequotarequest.h>
+#include <QtWebEngineCore/qwebenginedownloadrequest.h>
#include <QtWebEngineQuick/private/qtwebenginequickglobal_p.h>
#include <QtGui/qcolor.h>
#include <QtQml/qqmlregistration.h>
@@ -465,6 +466,10 @@ QT_WARNING_POP
QQmlComponent *touchHandleDelegate() const;
void setTouchHandleDelegate(QQmlComponent *delegagte);
+ Q_REVISION(6, 6)
+ Q_INVOKABLE void save(const QString &filePath,
+ QWebEngineDownloadRequest::SavePageFormat format =
+ QWebEngineDownloadRequest::MimeHtmlSaveFormat) const;
public Q_SLOTS:
void runJavaScript(const QString&, const QJSValue & = QJSValue());
diff --git a/src/webenginequick/doc/src/webengineview_lgpl.qdoc b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
index be626c053..4dc99f00b 100644
--- a/src/webenginequick/doc/src/webengineview_lgpl.qdoc
+++ b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
@@ -1528,5 +1528,24 @@
*/
+/*!
+ \qmlmethod void WebEngineView::save(const QString &filePath, QWebEngineDownloadRequest::SavePageFormat format)
+ \since QtWebEngine 6.6
+
+ Save the current web page to disk.
+
+ The web page is saved to \a filePath in the specified \a{format}.
+
+ This is a shortcut for the following actions:
+ \list
+ \li Trigger the Save web action.
+ \li Accept the next download item and set the specified file path and save format.
+ \endlist
+
+ This function issues an asynchronous download request for the web page and returns immediately.
+
+ \sa QWebEngineDownloadRequest::SavePageFormat
+*/
+
\sa {WebEngine Qt Quick Custom Touch Handle Example}
*/
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 501b4af29..e18671d0c 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -72,7 +72,9 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *
<< &QQuickWebEngineTouchSelectionMenuRequest::staticMetaObject
;
-static QList<QMetaEnum> knownEnumNames = QList<QMetaEnum>();
+static QList<QMetaEnum> knownEnumNames = QList<QMetaEnum>()
+ << QWebEngineDownloadRequest::staticMetaObject.enumerator(QWebEngineDownloadRequest::staticMetaObject.indexOfEnumerator("SavePageFormat"))
+ ;
static const QStringList hardcodedTypes = QStringList()
<< "QJSValue"
@@ -787,6 +789,8 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.zoomFactor --> double"
<< "QQuickWebEngineView.zoomFactorChanged(double) --> void"
<< "QQuickWebEngineView.acceptAsNewWindow(QWebEngineNewWindowRequest*) --> void"
+ << "QQuickWebEngineView.save(QString) --> void"
+ << "QQuickWebEngineView.save(QString,QWebEngineDownloadRequest::SavePageFormat) --> void"
<< "QWebEngineQuotaRequest.accept() --> void"
<< "QWebEngineQuotaRequest.origin --> QUrl"
<< "QWebEngineQuotaRequest.reject() --> void"
diff --git a/tests/auto/quick/qmltests/CMakeLists.txt b/tests/auto/quick/qmltests/CMakeLists.txt
index ecbb6ac3e..acd783bd5 100644
--- a/tests/auto/quick/qmltests/CMakeLists.txt
+++ b/tests/auto/quick/qmltests/CMakeLists.txt
@@ -60,6 +60,7 @@ set(testList
tst_userScripts.qml
tst_userScriptCollection.qml
tst_viewSource.qml
+ tst_save.qml
)
if(QT_FEATURE_webengine_webchannel)
diff --git a/tests/auto/quick/qmltests/data/tst_save.qml b/tests/auto/quick/qmltests/data/tst_save.qml
new file mode 100644
index 000000000..9757f8fac
--- /dev/null
+++ b/tests/auto/quick/qmltests/data/tst_save.qml
@@ -0,0 +1,123 @@
+import QtQuick
+import QtTest
+import QtWebEngine
+import Test.util
+
+TestWebEngineView {
+ id: webEngineView
+ width: 200
+ height: 200
+ profile: testSaveProfile
+
+ property url downloadUrl: ""
+ property int totalBytes: 0
+ property int receivedBytes: 0
+ property string downloadDir: ""
+ property string downloadFileName: ""
+ property var downloadState: []
+ property int savePageFormat: WebEngineDownloadRequest.MimeHtmlSaveFormat;
+
+ TempDir {
+ id: tempDir
+ }
+
+ SignalSpy {
+ id: downLoadRequestedSpy
+ target: testSaveProfile
+ signalName: "downloadRequested"
+ }
+
+ SignalSpy {
+ id: downloadFinishedSpy
+ target: testSaveProfile
+ signalName: "downloadFinished"
+ }
+
+ WebEngineProfile {
+ id: testSaveProfile
+
+ onDownloadRequested: function(download) {
+ downloadState.push(download.state)
+ downloadUrl = download.url
+ savePageFormat = download.savePageFormat
+ downloadDir = download.downloadDirectory;
+ downloadFileName = download.downloadFileName
+ }
+ onDownloadFinished: function(download) {
+ receivedBytes = download.receivedBytes
+ totalBytes = download.totalBytes
+ downloadState.push(download.state)
+ }
+ }
+
+ TestCase {
+ name: "WebEngineViewSave"
+
+ function verifyData() {
+ var isDataValid = false
+ webEngineView.runJavaScript("(function() {" +
+ "var title = document.title.toString();" +
+ "var body = document.body.innerText;" +
+ " return title === \"Test page 1\" && body.includes(\"Hello.\")" +
+ "})();", function(result) {
+ isDataValid = result;
+ });
+ tryVerify(function() { return isDataValid });
+ return isDataValid;
+ }
+
+ function init() {
+ downLoadRequestedSpy.clear()
+ downloadFinishedSpy.clear()
+ totalBytes = 0
+ receivedBytes = 0
+ downloadDir = ""
+ downloadFileName = ""
+ downloadState = []
+ downloadUrl = ""
+ }
+
+ function test_savePage_data() {
+ return [
+ { tag: "SingleHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.SingleHtmlSaveFormat },
+ { tag: "CompleteHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.CompleteHtmlSaveFormat },
+ { tag: "MimeHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.MimeHtmlSaveFormat },
+ ];
+ }
+
+ function test_savePage(row) {
+ var saveFormat = row.savePageFormat
+
+ var fileDir = tempDir.path()
+ var fileName = "saved_page.html"
+ var filePath = fileDir + "/"+ fileName
+
+ // load data to view
+ webEngineView.url = Qt.resolvedUrl("test1.html")
+ verify(webEngineView.waitForLoadSucceeded())
+ verify(verifyData())
+
+ webEngineView.save(filePath, saveFormat)
+ downLoadRequestedSpy.wait()
+ compare(downLoadRequestedSpy.count, 1)
+ compare(downloadUrl, webEngineView.url)
+ compare(savePageFormat, saveFormat)
+ compare(downloadDir, fileDir)
+ compare(downloadFileName, fileName)
+ compare(downloadState[0], WebEngineDownloadRequest.DownloadInProgress)
+ downloadFinishedSpy.wait()
+ compare(downloadFinishedSpy.count, 1)
+ compare(totalBytes, receivedBytes)
+ compare(downloadState[1], WebEngineDownloadRequest.DownloadCompleted)
+
+ // load some other data
+ webEngineView.url = Qt.resolvedUrl("about:blank")
+ verify(webEngineView.waitForLoadSucceeded())
+
+ // load save file to view
+ webEngineView.url = Qt.resolvedUrl(filePath)
+ verify(webEngineView.waitForLoadSucceeded())
+ verify(verifyData())
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
index 5ae032061..f82c58264 100644
--- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
+++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
@@ -16,6 +16,7 @@
#include <QtGui/private/qinputmethod_p.h>
#include <QtWebEngineQuick/private/qquickwebenginescriptcollection_p.h>
#include <QtWebEngineQuick/private/qquickwebenginesettings_p.h>
+#include <QtWebEngineQuick/private/qquickwebenginedownloadrequest_p.h>
#include <QtWebEngineQuick/private/qquickwebengineview_p.h>
#include <QtWebEngineCore/private/qtwebenginecore-config_p.h>
#include <qpa/qplatforminputcontext.h>
@@ -74,6 +75,8 @@ private Q_SLOTS:
void focusChild();
#endif
void htmlSelectPopup();
+ void savePage_data();
+ void savePage();
private:
inline QQuickWebEngineView *newWebEngineView();
@@ -1274,6 +1277,81 @@ void tst_QQuickWebEngineView::htmlSelectPopup()
QCOMPARE(evaluateJavaScriptSync(&view, "document.getElementById('select').value").toString(), QStringLiteral("O2"));
}
+void tst_QQuickWebEngineView::savePage_data()
+{
+ QTest::addColumn<QWebEngineDownloadRequest::SavePageFormat>("savePageFormat");
+
+ QTest::newRow("SingleHtmlSaveFormat") << QWebEngineDownloadRequest::SingleHtmlSaveFormat;
+ QTest::newRow("CompleteHtmlSaveFormat") << QWebEngineDownloadRequest::CompleteHtmlSaveFormat;
+ QTest::newRow("MimeHtmlSaveFormat") << QWebEngineDownloadRequest::MimeHtmlSaveFormat;
+}
+
+void tst_QQuickWebEngineView::savePage()
+{
+ QFETCH(QWebEngineDownloadRequest::SavePageFormat, savePageFormat);
+
+ QTemporaryDir tempDir(QDir::tempPath() + "/tst_QQuickWebEngineView-XXXXXX");
+ QVERIFY(tempDir.isValid());
+ const QString filePath = tempDir.path() + "/saved_page.html";
+
+ QQuickWebEngineView *view = webEngineView();
+ connect(view->profile(), &QQuickWebEngineProfile::downloadRequested,
+ [&](QQuickWebEngineDownloadRequest *downloadRequest) {
+ QCOMPARE(downloadRequest->state(),
+ QQuickWebEngineDownloadRequest::DownloadInProgress);
+ QCOMPARE(downloadRequest->isSavePageDownload(), true);
+ QCOMPARE(downloadRequest->savePageFormat(), savePageFormat);
+ QCOMPARE(QDir(downloadRequest->downloadDirectory())
+ .filePath(downloadRequest->downloadFileName()),
+ filePath);
+ QCOMPARE(downloadRequest->url(), view->url());
+
+ connect(downloadRequest, &QQuickWebEngineDownloadRequest::isFinishedChanged,
+ [&, downloadRequest]() {
+ QCOMPARE(downloadRequest->state(),
+ QQuickWebEngineDownloadRequest::DownloadCompleted);
+ QCOMPARE(downloadRequest->isSavePageDownload(), true);
+ QCOMPARE(downloadRequest->isFinished(), true);
+ QCOMPARE(downloadRequest->savePageFormat(), savePageFormat);
+ QCOMPARE(downloadRequest->totalBytes(),
+ downloadRequest->receivedBytes());
+ QVERIFY(downloadRequest->receivedBytes() > 0);
+ QCOMPARE(QDir(downloadRequest->downloadDirectory())
+ .filePath(downloadRequest->downloadFileName()),
+ filePath);
+ QCOMPARE(downloadRequest->url(), view->url());
+ QTestEventLoop::instance().exitLoop();
+ });
+ });
+
+ const QString originalData = QStringLiteral("Basic page");
+ view->setUrl(urlFromTestPath("html/basic_page.html"));
+ QVERIFY(waitForLoadSucceeded(view));
+ QCOMPARE(evaluateJavaScriptSync(view, "document.getElementsByTagName('h1')[0].innerText")
+ .toString(),
+ originalData);
+
+ // Save the loaded page as HTML.
+ view->save(filePath, savePageFormat);
+ QTestEventLoop::instance().enterLoop(10);
+ QFile file(filePath);
+ QVERIFY(file.exists());
+
+ // Load something else.
+ view->setUrl(urlFromTestPath("html/basic_page2.html"));
+ QVERIFY(waitForLoadSucceeded(view));
+ QVERIFY(evaluateJavaScriptSync(view, "document.getElementsByTagName('h1')[0].innerText")
+ .toString()
+ != originalData);
+
+ // Load the saved page and compare the contents.
+ view->setUrl(QUrl::fromLocalFile(filePath));
+ QVERIFY(waitForLoadSucceeded(view));
+ QCOMPARE(evaluateJavaScriptSync(view, "document.getElementsByTagName('h1')[0].innerText")
+ .toString(),
+ originalData);
+}
+
#if QT_CONFIG(accessibility)
static QByteArrayList params = QByteArrayList()
<< "--force-renderer-accessibility";