diff options
29 files changed, 1154 insertions, 5 deletions
diff --git a/examples/examples.pro b/examples/examples.pro index 825cacaae..b4f411aeb 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -5,3 +5,5 @@ qtHaveModule(webengine): SUBDIRS += webengine qtHaveModule(webenginewidgets): SUBDIRS += webenginewidgets qtHaveModule(pdfwidgets): SUBDIRS += pdfwidgets + +qtHaveModule(quick): qtHaveModule(pdf): qtHaveModule(pdfwidgets): SUBDIRS += pdf diff --git a/examples/pdf/pdf.pro b/examples/pdf/pdf.pro new file mode 100644 index 000000000..45df33e46 --- /dev/null +++ b/examples/pdf/pdf.pro @@ -0,0 +1,3 @@ +TEMPLATE=subdirs + +SUBDIRS += pdfviewer diff --git a/examples/pdf/pdfviewer/main.cpp b/examples/pdf/pdfviewer/main.cpp new file mode 100644 index 000000000..6b94a3de1 --- /dev/null +++ b/examples/pdf/pdfviewer/main.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples 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$ +** +****************************************************************************/ + +#include <QApplication> +#include <QQmlApplicationEngine> + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + QCoreApplication::setApplicationName("Qt Quick PDF Viewer Example"); + QCoreApplication::setOrganizationName("QtProject"); + QCoreApplication::setApplicationVersion(QT_VERSION_STR); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:///pdfviewer/viewer.qml"))); + if (app.arguments().count() > 1) { + QUrl toLoad = QUrl::fromUserInput(app.arguments().at(1)); + engine.rootObjects().first()->setProperty("source", toLoad); + } + + return app.exec(); +} diff --git a/examples/pdf/pdfviewer/pdfviewer.pro b/examples/pdf/pdfviewer/pdfviewer.pro new file mode 100644 index 000000000..697349cee --- /dev/null +++ b/examples/pdf/pdfviewer/pdfviewer.pro @@ -0,0 +1,14 @@ +TEMPLATE = app + +QT += qml quick pdf widgets + +SOURCES += main.cpp + +RESOURCES += \ + viewer.qrc +EXAMPLE_FILES = \ + viewer.qml + +target.path = $$[QT_INSTALL_EXAMPLES]/pdf/pdfviewer +INSTALLS += target + diff --git a/examples/pdf/pdfviewer/resources/document-open.svg b/examples/pdf/pdfviewer/resources/document-open.svg new file mode 100644 index 000000000..bf23123a3 --- /dev/null +++ b/examples/pdf/pdfviewer/resources/document-open.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path style="fill:currentColor;fill-opacity:1;stroke:none" + d="m4 4v24h24l-1-1h-22v-13h5l3-3h14v16l1 1v-21h-10l-3-3z" + class="ColorScheme-Text" + /> +</svg> diff --git a/examples/pdf/pdfviewer/resources/edit-clear.svg b/examples/pdf/pdfviewer/resources/edit-clear.svg new file mode 100644 index 000000000..1c35aaf04 --- /dev/null +++ b/examples/pdf/pdfviewer/resources/edit-clear.svg @@ -0,0 +1,15 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path + style="fill:currentColor;fill-opacity:1;stroke:none" + d="M 8 3 L 0.94335938 10.056641 L 0 11 L 0.94335938 11.943359 L 8 19 L 20.333984 19 L 22 19 L 22 3 L 20.333984 3 L 8 3 z M 11.320312 7 L 14 9.6796875 L 16.679688 7 L 18 8.3203125 L 15.320312 11 L 18 13.679688 L 16.679688 15 L 14 12.320312 L 11.320312 15 L 10 13.679688 L 12.679688 11 L 10 8.3203125 L 11.320312 7 z " + class="ColorScheme-Text" + transform="translate(1,1)" + /> +</svg> diff --git a/examples/pdf/pdfviewer/resources/go-next-view-page.svg b/examples/pdf/pdfviewer/resources/go-next-view-page.svg new file mode 100644 index 000000000..e453ddbec --- /dev/null +++ b/examples/pdf/pdfviewer/resources/go-next-view-page.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path style="fill:currentColor;fill-opacity:1;stroke:none" + d="M 8.7070312 4 L 8 4.7070312 L 14.125 10.832031 L 15.292969 12 L 14.125 13.167969 L 8 19.292969 L 8.7070312 20 L 14.832031 13.875 L 16.707031 12 L 14.832031 10.125 L 8.7070312 4 z " + class="ColorScheme-Text" + /> +</svg> diff --git a/examples/pdf/pdfviewer/resources/go-previous-view-page.svg b/examples/pdf/pdfviewer/resources/go-previous-view-page.svg new file mode 100644 index 000000000..b032309e9 --- /dev/null +++ b/examples/pdf/pdfviewer/resources/go-previous-view-page.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path style="fill:currentColor;fill-opacity:1;stroke:none" + d="M 15.292969 4 L 9.1679688 10.125 L 7.2929688 12 L 9.1679688 13.875 L 15.292969 20 L 16 19.292969 L 9.875 13.167969 L 8.7070312 12 L 9.875 10.832031 L 16 4.7070312 L 15.292969 4 z " + class="ColorScheme-Text" + /> +</svg> diff --git a/examples/pdf/pdfviewer/resources/zoom-in.svg b/examples/pdf/pdfviewer/resources/zoom-in.svg new file mode 100644 index 000000000..efdc9f17d --- /dev/null +++ b/examples/pdf/pdfviewer/resources/zoom-in.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path style="fill:currentColor;fill-opacity:1;stroke:none" + d="M 4 4 L 4 6 L 5 6 L 5 5 L 6 5 L 6 4 L 4 4 z M 9 4 L 9 5 L 11 5 L 11 4 L 9 4 z M 13 4 L 13 5 L 15 5 L 15 4 L 13 4 z M 18 4 L 18 5 L 19 5 L 19 6 L 20 6 L 20 4 L 18 4 z M 12 8 L 12 9 L 14.292969 9 L 11 12.292969 L 11.707031 13 L 15 9.7070312 L 15 12 L 16 12 L 16 8 L 15 8 L 12 8 z M 4 9 L 4 11 L 5 11 L 5 9 L 4 9 z M 19 9 L 19 11 L 20 11 L 20 9 L 19 9 z M 19 13 L 19 15 L 20 15 L 20 13 L 19 13 z M 4 14 L 4 20 L 10 20 L 10 14 L 4 14 z M 5 15 L 9 15 L 9 19 L 5 19 L 5 15 z M 19 18 L 19 19 L 18 19 L 18 20 L 20 20 L 20 18 L 19 18 z " + class="ColorScheme-Text" + /> +</svg> diff --git a/examples/pdf/pdfviewer/resources/zoom-original.svg b/examples/pdf/pdfviewer/resources/zoom-original.svg new file mode 100644 index 000000000..1b4080a03 --- /dev/null +++ b/examples/pdf/pdfviewer/resources/zoom-original.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path style="fill:currentColor;fill-opacity:1;stroke:none" + d="M 4 4 L 4 5 L 4 7 L 5 7 L 5 5 L 7 5 L 7 4 L 5 4 L 4 4 z M 17 4 L 17 5 L 19 5 L 19 7 L 20 7 L 20 5 L 20 4 L 19 4 L 17 4 z M 6 6 L 6 18 L 18 18 L 18 6 L 6 6 z M 7 7 L 17 7 L 17 17 L 7 17 L 7 7 z M 4 17 L 4 19 L 4 20 L 7 20 L 7 19 L 5 19 L 5 17 L 4 17 z M 19 17 L 19 19 L 17 19 L 17 20 L 20 20 L 20 17 L 19 17 z " + class="ColorScheme-Text" + /> +</svg> diff --git a/examples/pdf/pdfviewer/resources/zoom-out.svg b/examples/pdf/pdfviewer/resources/zoom-out.svg new file mode 100644 index 000000000..fcde9e526 --- /dev/null +++ b/examples/pdf/pdfviewer/resources/zoom-out.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <defs id="defs3051"> + <style type="text/css" id="current-color-scheme"> + .ColorScheme-Text { + color:#232629; + } + </style> + </defs> + <path style="fill:currentColor;fill-opacity:1;stroke:none" + d="M 4 4 L 4 11 L 5 11 L 5 5 L 19 5 L 19 19 L 13 19 L 13 20 L 20 20 L 20 19 L 20 5 L 20 4 L 5 4 L 4 4 z M 15.292969 8 L 12 11.292969 L 12 9 L 11 9 L 11 13 L 12 13 L 15 13 L 15 12 L 12.707031 12 L 16 8.7070312 L 15.292969 8 z M 4 14 L 4 16 L 5 16 L 5 15 L 6 15 L 6 14 L 4 14 z M 8 14 L 8 15 L 9 15 L 9 16 L 10 16 L 10 14 L 8 14 z M 4 18 L 4 20 L 6 20 L 6 19 L 5 19 L 5 18 L 4 18 z M 9 18 L 9 19 L 8 19 L 8 20 L 10 20 L 10 18 L 9 18 z " + class="ColorScheme-Text" + /> +</svg> diff --git a/examples/pdf/pdfviewer/viewer.qml b/examples/pdf/pdfviewer/viewer.qml new file mode 100644 index 000000000..47853aa31 --- /dev/null +++ b/examples/pdf/pdfviewer/viewer.qml @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples 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.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Pdf 5.15 +import QtQuick.Shapes 1.15 +import QtQuick.Window 2.15 +import Qt.labs.platform 1.1 as Platform + +ApplicationWindow { + id: root + width: 800 + height: 640 + color: "lightgrey" + title: document.title + visible: true + property alias source: document.source // for main.cpp + property real scaleStep: Math.sqrt(2) + + header: ToolBar { + RowLayout { + anchors.fill: parent + anchors.rightMargin: 6 + ToolButton { + action: Action { + shortcut: StandardKey.Open + icon.source: "resources/document-open.svg" + onTriggered: fileDialog.open() + } + } + ToolButton { + action: Action { + shortcut: StandardKey.ZoomIn + enabled: pageView.sourceSize.width < 10000 + icon.source: "resources/zoom-in.svg" + onTriggered: pageView.renderScale *= root.scaleStep + } + } + ToolButton { + action: Action { + shortcut: StandardKey.ZoomOut + enabled: pageView.sourceSize.width > 50 + icon.source: "resources/zoom-out.svg" + onTriggered: pageView.renderScale /= root.scaleStep + } + } + ToolButton { + action: Action { + shortcut: "Ctrl+0" + icon.source: "resources/zoom-original.svg" + onTriggered: pageView.renderScale = 1 + } + } + ToolButton { + action: Action { + shortcut: StandardKey.MoveToPreviousPage + icon.source: "resources/go-previous-view-page.svg" + enabled: pageView.currentPage > 0 + onTriggered: pageView.currentPage-- + } + } + ToolButton { + action: Action { + shortcut: StandardKey.MoveToNextPage + icon.source: "resources/go-next-view-page.svg" + enabled: pageView.currentPage < pageView.pageCount - 1 + onTriggered: pageView.currentPage++ + } + } + TextField { + id: searchField + placeholderText: "search" + Layout.minimumWidth: 200 + Layout.fillWidth: true + Image { + visible: searchField.text !== "" + source: "resources/edit-clear.svg" + anchors { + right: parent.right + top: parent.top + bottom: parent.bottom + margins: 3 + rightMargin: 5 + } + TapHandler { + onTapped: searchField.clear() + } + } + } + Shortcut { + sequence: StandardKey.Find + onActivated: searchField.forceActiveFocus() + } + Shortcut { + sequence: StandardKey.Quit + onActivated: Qt.quit() + } + } + } + + Platform.FileDialog { + id: fileDialog + title: "Open a PDF file" + nameFilters: [ "PDF files (*.pdf)" ] + onAccepted: document.source = file + } + + Dialog { + id: errorDialog + title: "Error loading " + document.source + standardButtons: Dialog.Ok + modal: true + closePolicy: Popup.CloseOnEscape + anchors.centerIn: parent + width: 300 + + Label { + id: errorField + text: document.error + } + } + + PdfPageView { + id: pageView + document: PdfDocument { + id: document + onStatusChanged: if (status === PdfDocument.Error) errorDialog.open() + } + searchString: searchField.text + } + + footer: Label { + property size implicitPointSize: document.pagePointSize(pageView.currentPage) + text: "page " + (pageView.currentPage + 1) + " of " + pageView.pageCount + + " scale " + pageView.renderScale.toFixed(2) + + " sourceSize " + pageView.sourceSize.width.toFixed(1) + "x" + pageView.sourceSize.height.toFixed(1) + + " original " + implicitPointSize.width.toFixed(1) + "x" + implicitPointSize.height.toFixed(1) + visible: pageView.pageCount > 0 + } +} diff --git a/examples/pdf/pdfviewer/viewer.qrc b/examples/pdf/pdfviewer/viewer.qrc new file mode 100644 index 000000000..59045b75c --- /dev/null +++ b/examples/pdf/pdfviewer/viewer.qrc @@ -0,0 +1,12 @@ +<RCC> + <qresource prefix="/pdfviewer"> + <file>viewer.qml</file> + <file>resources/edit-clear.svg</file> + <file>resources/go-next-view-page.svg</file> + <file>resources/go-previous-view-page.svg</file> + <file>resources/zoom-in.svg</file> + <file>resources/zoom-original.svg</file> + <file>resources/zoom-out.svg</file> + <file>resources/document-open.svg</file> + </qresource> +</RCC> diff --git a/src/pdf/api/qpdfdocument.h b/src/pdf/api/qpdfdocument.h index a0a2a21be..1252fa6d2 100644 --- a/src/pdf/api/qpdfdocument.h +++ b/src/pdf/api/qpdfdocument.h @@ -119,6 +119,7 @@ Q_SIGNALS: private: friend class QPdfBookmarkModelPrivate; + friend class QPdfSearchModel; Q_PRIVATE_SLOT(d, void _q_tryLoadingWithSizeFromContentHeader()) Q_PRIVATE_SLOT(d, void _q_copyFromSequentialSourceDevice()) diff --git a/src/pdf/api/qpdfsearchmodel.h b/src/pdf/api/qpdfsearchmodel.h new file mode 100644 index 000000000..02d2a20d5 --- /dev/null +++ b/src/pdf/api/qpdfsearchmodel.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPDFSEARCHMODEL_H +#define QPDFSEARCHMODEL_H + +#include "qtpdfglobal.h" +#include "qpdfdocument.h" + +#include <QObject> + +QT_BEGIN_NAMESPACE + +class QPdfSearchModelPrivate; + +class Q_PDF_EXPORT QPdfSearchModel : public QObject // TODO QAIM? +{ + Q_OBJECT + Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) + +public: + explicit QPdfSearchModel(QObject *parent = nullptr); + ~QPdfSearchModel(); + + QVector<QRectF> matches(int page, const QString &searchString); + + QPdfDocument *document() const; + +public Q_SLOTS: + void setDocument(QPdfDocument *document); + +Q_SIGNALS: + void documentChanged(); + +private: + QScopedPointer<QPdfSearchModelPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QPDFSEARCHMODEL_H diff --git a/src/pdf/pdfcore.pro b/src/pdf/pdfcore.pro index 5314d30d2..1f9f21e0a 100644 --- a/src/pdf/pdfcore.pro +++ b/src/pdf/pdfcore.pro @@ -62,7 +62,8 @@ SOURCES += \ qpdfbookmarkmodel.cpp \ qpdfdocument.cpp \ qpdfpagenavigation.cpp \ - qpdfpagerenderer.cpp + qpdfpagerenderer.cpp \ + qpdfsearchmodel.cpp \ # all "public" headers must be in "api" for sync script and to hide auto generated headers # by Chromium in case of in-source build @@ -72,10 +73,11 @@ HEADERS += \ api/qpdfdocument.h \ api/qpdfdocument_p.h \ api/qpdfdocumentrenderoptions.h \ + api/qtpdfglobal.h \ api/qpdfnamespace.h \ api/qpdfpagenavigation.h \ api/qpdfpagerenderer.h \ - api/qtpdfglobal.h \ - api/qpdfdocument_p.h + api/qpdfsearchmodel.h \ + qpdfsearchmodel_p.h \ load(qt_module) diff --git a/src/pdf/qpdfsearchmodel.cpp b/src/pdf/qpdfsearchmodel.cpp new file mode 100644 index 000000000..9010d76d3 --- /dev/null +++ b/src/pdf/qpdfsearchmodel.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpdfsearchmodel.h" +#include "qpdfsearchmodel_p.h" +#include "qpdfdocument_p.h" + +#include "third_party/pdfium/public/fpdf_doc.h" +#include "third_party/pdfium/public/fpdf_text.h" + +#include <QLoggingCategory> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcS, "qt.pdf.search") + +QPdfSearchModel::QPdfSearchModel(QObject *parent) + : QObject(parent), + d(new QPdfSearchModelPrivate()) +{ +} + +QPdfSearchModel::~QPdfSearchModel() {} + +QVector<QRectF> QPdfSearchModel::matches(int page, const QString &searchString) +{ + const QPdfMutexLocker lock; + FPDF_PAGE pdfPage = FPDF_LoadPage(d->document->d->doc, page); + if (!pdfPage) { + qWarning() << "failed to load page" << page; + return {}; + } + double pageHeight = FPDF_GetPageHeight(pdfPage); + FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); + if (!textPage) { + qWarning() << "failed to load text of page" << page; + FPDF_ClosePage(pdfPage); + return {}; + } + QVector<QRectF> ret; + if (searchString.isEmpty()) + return ret; + FPDF_SCHHANDLE sh = FPDFText_FindStart(textPage, searchString.utf16(), 0, 0); + while (FPDFText_FindNext(sh)) { + int idx = FPDFText_GetSchResultIndex(sh); + int count = FPDFText_GetSchCount(sh); + int rectCount = FPDFText_CountRects(textPage, idx, count); + qCDebug(qLcS) << searchString << ": matched" << count << "chars @" << idx << "across" << rectCount << "rects"; + for (int r = 0; r < rectCount; ++r) { + double left, top, right, bottom; + FPDFText_GetRect(textPage, r, &left, &top, &right, &bottom); + ret << QRectF(left, pageHeight - top, right - left, top - bottom); + qCDebug(qLcS) << ret.last(); + } + } + FPDFText_FindClose(sh); + FPDFText_ClosePage(textPage); + FPDF_ClosePage(pdfPage); + + return ret; +} + +QPdfDocument *QPdfSearchModel::document() const +{ + return d->document; +} + +void QPdfSearchModel::setDocument(QPdfDocument *document) +{ + if (d->document == document) + return; + d->document = document; + emit documentChanged(); +} + +QPdfSearchModelPrivate::QPdfSearchModelPrivate() +{ +} + +QT_END_NAMESPACE + +#include "moc_qpdfsearchmodel.cpp" diff --git a/src/pdf/qpdfsearchmodel_p.h b/src/pdf/qpdfsearchmodel_p.h new file mode 100644 index 000000000..90490d8e5 --- /dev/null +++ b/src/pdf/qpdfsearchmodel_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPDFSEARCHMODEL_P_H +#define QPDFSEARCHMODEL_P_H + +#include "qpdfsearchmodel.h" + +#include "third_party/pdfium/public/fpdfview.h" + +QT_BEGIN_NAMESPACE + +class QPdfSearchModelPrivate +{ +public: + QPdfSearchModelPrivate(); + + QPdfDocument *document = nullptr; +}; + +QT_END_NAMESPACE + +#endif // QPDFSEARCHMODEL_P_H diff --git a/src/pdf/quick/plugin.cpp b/src/pdf/quick/plugin.cpp index 59aca576b..664ba51ab 100644 --- a/src/pdf/quick/plugin.cpp +++ b/src/pdf/quick/plugin.cpp @@ -39,6 +39,7 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlextensionplugin.h> #include "qquickpdfdocument_p.h" +#include "qquickpdfsearchmodel_p.h" QT_BEGIN_NAMESPACE @@ -79,6 +80,9 @@ public: qmlRegisterModule(uri, 2, QT_VERSION_MINOR); qmlRegisterType<QQuickPdfDocument>(uri, 5, 15, "PdfDocument"); + qmlRegisterType<QQuickPdfSearchModel>(uri, 5, 15, "PdfSearchModel"); + + qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfPageView.qml"), uri, 5, 15, "PdfPageView"); } }; diff --git a/src/pdf/quick/qml/PdfPageView.qml b/src/pdf/quick/qml/PdfPageView.qml new file mode 100644 index 000000000..adcdc807a --- /dev/null +++ b/src/pdf/quick/qml/PdfPageView.qml @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Pdf 5.15 +import QtQuick.Shapes 1.15 + +Rectangle { + id: paper + width: image.width + height: image.height + transformOrigin: Item.TopLeft + + // public API + // TODO 5.15: required property + property var document: null + property real renderScale: 1 + property alias sourceSize: image.sourceSize + property alias currentPage: image.currentFrame + property alias pageCount: image.frameCount + property alias searchString: searchModel.searchString + property alias status: image.status + + property real __pageScale: image.paintedWidth / document.pagePointSize(image.currentFrame).width + + PdfSearchModel { + id: searchModel + document: paper.document + page: image.currentFrame + } + + Image { + id: image + source: document.status === PdfDocument.Ready ? document.source : "" + asynchronous: true + fillMode: Image.PreserveAspectFit + } + function reRenderIfNecessary() { + var newSourceWidth = image.sourceSize.width * paper.scale + var ratio = newSourceWidth / image.sourceSize.width + if (ratio > 1.1 || ratio < 0.9) { + image.sourceSize.width = newSourceWidth + image.sourceSize.height = 1 + paper.scale = 1 + } + } + onRenderScaleChanged: { + image.sourceSize.width = document.pagePointSize(image.currentFrame).width * renderScale + image.sourceSize.height = 0 + paper.scale = 1 + } + + Shape { + anchors.fill: parent + opacity: 0.25 + visible: image.status === Image.Ready + ShapePath { + strokeWidth: 1 + strokeColor: "blue" + fillColor: "cyan" + scale: Qt.size(paper.__pageScale, paper.__pageScale) + PathMultiline { + id: searchResultBoundaries + paths: searchModel.matchGeometry + } + } + } + PinchHandler { + id: pinch + minimumScale: 0.1 + maximumScale: 10 + minimumRotation: 0 + maximumRotation: 0 + onActiveChanged: if (!active) paper.reRenderIfNecessary() + grabPermissions: PinchHandler.TakeOverForbidden // don't allow takeover if pinch has started + } + DragHandler { + id: pageMovingTouchDrag + acceptedDevices: PointerDevice.TouchScreen + } + DragHandler { + id: pageMovingMiddleMouseDrag + acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus + acceptedButtons: Qt.MiddleButton + snapMode: DragHandler.NoSnap + } +} diff --git a/src/pdf/quick/qquickpdfdocument.cpp b/src/pdf/quick/qquickpdfdocument.cpp index f0f40c227..73b3d4537 100644 --- a/src/pdf/quick/qquickpdfdocument.cpp +++ b/src/pdf/quick/qquickpdfdocument.cpp @@ -95,6 +95,41 @@ void QQuickPdfDocument::setSource(QUrl source) } /*! + \qmlproperty string Document::error + + This property holds a translated string representation of the current + error, if any. + + \sa status +*/ +QString QQuickPdfDocument::error() const +{ + switch (m_doc.error()) { + case QPdfDocument::NoError: + return tr("no error"); + break; + case QPdfDocument::UnknownError: + break; + case QPdfDocument::DataNotYetAvailableError: + return tr("data not yet available"); + break; + case QPdfDocument::FileNotFoundError: + return tr("file not found"); + break; + case QPdfDocument::InvalidFileFormatError: + return tr("invalid file format"); + break; + case QPdfDocument::IncorrectPasswordError: + return tr("incorrect password"); + break; + case QPdfDocument::UnsupportedSecuritySchemeError: + return tr("unsupported security scheme"); + break; + } + return tr("unknown error"); +} + +/*! \qmlproperty bool Document::password This property holds the document password. If the passwordRequired() diff --git a/src/pdf/quick/qquickpdfdocument_p.h b/src/pdf/quick/qquickpdfdocument_p.h index ee6195679..1ec7edb1a 100644 --- a/src/pdf/quick/qquickpdfdocument_p.h +++ b/src/pdf/quick/qquickpdfdocument_p.h @@ -64,6 +64,7 @@ class QQuickPdfDocument : public QObject, public QQmlParserStatus Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL) Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL) Q_PROPERTY(QPdfDocument::Status status READ status NOTIFY statusChanged FINAL) + Q_PROPERTY(QString error READ error NOTIFY statusChanged FINAL) Q_PROPERTY(QString title READ title NOTIFY metaDataChanged) Q_PROPERTY(QString subject READ subject NOTIFY metaDataChanged) @@ -86,6 +87,8 @@ public: int pageCount() const { return m_doc.pageCount(); } QPdfDocument::Status status() const { return m_doc.status(); } + QString error() const; + QString password() const { return m_doc.password(); } void setPassword(const QString &password); @@ -115,6 +118,7 @@ private: QUrl m_source; QPdfDocument m_doc; + friend class QQuickPdfSearchModel; friend class QQuickPdfSelection; Q_DISABLE_COPY(QQuickPdfDocument) diff --git a/src/pdf/quick/qquickpdfsearchmodel.cpp b/src/pdf/quick/qquickpdfsearchmodel.cpp new file mode 100644 index 000000000..8b0e88673 --- /dev/null +++ b/src/pdf/quick/qquickpdfsearchmodel.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpdfsearchmodel_p.h" +#include <QQuickItem> +#include <QQmlEngine> +#include <QStandardPaths> +#include <private/qguiapplication_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype PdfSearchModel + \instantiates QQuickPdfSearchModel + \inqmlmodule QtQuick.Pdf + \ingroup pdf + \brief A representation of text search results within a PDF Document. + \since 5.15 + + PdfSearchModel provides the ability to search for text strings within a + document and get the geometric locations of matches on each page. +*/ + +QQuickPdfSearchModel::QQuickPdfSearchModel(QObject *parent) + : QPdfSearchModel(parent) +{ +} + +QQuickPdfDocument *QQuickPdfSearchModel::document() const +{ + return m_quickDocument; +} + +void QQuickPdfSearchModel::setDocument(QQuickPdfDocument *document) +{ + if (document == m_quickDocument) + return; + m_quickDocument = document; + QPdfSearchModel::setDocument(&document->m_doc); +} + +/*! + \qmlproperty list<list<point>> PdfSearchModel::matchGeometry + + A set of paths in a form that can be bound to the \c paths property of a + \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of + rectangles around all the locations where search results are found: + + \qml + PdfDocument { + id: doc + } + PdfSearchModel { + id: searchModel + document: doc + page: doc.currentPage + } + Shape { + ShapePath { + PathMultiline { + paths: searchModel.matchGeometry + } + } + } + \endqml + + \sa PathMultiline +*/ +QVector<QPolygonF> QQuickPdfSearchModel::matchGeometry() const +{ + return m_matchGeometry; +} + +/*! + \qmlproperty string PdfSearchModel::searchString + + The string to search for. +*/ +QString QQuickPdfSearchModel::searchString() const +{ + return m_searchString; +} + +void QQuickPdfSearchModel::setSearchString(QString searchString) +{ + if (m_searchString == searchString) + return; + + m_searchString = searchString; + emit searchStringChanged(); + updateResults(); +} + +/*! + \qmlproperty int PdfSearchModel::page + + The page number on which to search. + + \sa QtQuick::Image::currentFrame +*/ +int QQuickPdfSearchModel::page() const +{ + return m_page; +} + +void QQuickPdfSearchModel::setPage(int page) +{ + if (m_page == page) + return; + + m_page = page; + emit pageChanged(); + updateResults(); +} + +void QQuickPdfSearchModel::updateResults() +{ + if (!document() || (m_searchString.isEmpty() && !m_matchGeometry.isEmpty()) || m_page < 0 || m_page > document()->pageCount()) { + m_matchGeometry.clear(); + emit matchGeometryChanged(); + } + QVector<QRectF> m = QPdfSearchModel::matches(m_page, m_searchString); + QVector<QPolygonF> matches; + for (QRectF r : m) + matches << QPolygonF(r); + if (matches != m_matchGeometry) { + m_matchGeometry = matches; + emit matchGeometryChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfsearchmodel_p.h b/src/pdf/quick/qquickpdfsearchmodel_p.h new file mode 100644 index 000000000..799ef825f --- /dev/null +++ b/src/pdf/quick/qquickpdfsearchmodel_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtPDF module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPDFSEARCHMODEL_P_H +#define QQUICKPDFSEARCHMODEL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpdfdocument_p.h" +#include "../api/qpdfsearchmodel.h" + +#include <QVariant> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QQuickPdfSearchModel : public QPdfSearchModel +{ + Q_OBJECT + Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged) + Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) + Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged) + Q_PROPERTY(QVector<QPolygonF> matchGeometry READ matchGeometry NOTIFY matchGeometryChanged) + +public: + explicit QQuickPdfSearchModel(QObject *parent = nullptr); + + QQuickPdfDocument *document() const; + void setDocument(QQuickPdfDocument * document); + + int page() const; + void setPage(int page); + + QString searchString() const; + void setSearchString(QString searchString); + + QVector<QPolygonF> matchGeometry() const; + +signals: + void documentChanged(); + void pageChanged(); + void searchStringChanged(); + void matchGeometryChanged(); + +private: + void updateResults(); + +private: + QQuickPdfDocument *m_quickDocument = nullptr; + QString m_searchString; + QVector<QPolygonF> m_matchGeometry; + int m_page; + + Q_DISABLE_COPY(QQuickPdfSearchModel) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPdfSearchModel) + +#endif // QQUICKPDFSEARCHMODEL_P_H diff --git a/src/pdf/quick/quick.pro b/src/pdf/quick/quick.pro index eb88bc003..cda768369 100644 --- a/src/pdf/quick/quick.pro +++ b/src/pdf/quick/quick.pro @@ -5,12 +5,21 @@ IMPORT_VERSION = 1.0 #QMAKE_DOCS = $$PWD/doc/qtquickpdf.qdocconf +PDF_QML_FILES = \ + qml/PdfPageView.qml \ + +QML_FILES += $$PDF_QML_FILES qmldir + +RESOURCES += resources.qrc + SOURCES += \ + plugin.cpp \ qquickpdfdocument.cpp \ - plugin.cpp + qquickpdfsearchmodel.cpp \ HEADERS += \ - qquickpdfdocument_p.h + qquickpdfdocument_p.h \ + qquickpdfsearchmodel_p.h \ QT += pdf quick-private gui gui-private core core-private qml qml-private diff --git a/src/pdf/quick/resources.qrc b/src/pdf/quick/resources.qrc new file mode 100644 index 000000000..a3f34189c --- /dev/null +++ b/src/pdf/quick/resources.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/qt-project.org/qtpdf"> + <file>qml/PdfPageView.qml</file> + </qresource> +</RCC> diff --git a/tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro b/tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro new file mode 100644 index 000000000..205fef175 --- /dev/null +++ b/tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +TARGET = tst_qpdfsearchmodel +QT += pdf testlib network +macos:CONFIG -= app_bundle +SOURCES += tst_qpdfsearchmodel.cpp diff --git a/tests/auto/pdf/qpdfsearchmodel/test.pdf b/tests/auto/pdf/qpdfsearchmodel/test.pdf Binary files differnew file mode 100644 index 000000000..a9dc1bc29 --- /dev/null +++ b/tests/auto/pdf/qpdfsearchmodel/test.pdf diff --git a/tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp b/tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp new file mode 100644 index 000000000..e690bfc11 --- /dev/null +++ b/tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <QPdfDocument> +#include <QPdfSearchModel> + +class tst_QPdfSearchModel: public QObject +{ + Q_OBJECT + +public: + tst_QPdfSearchModel() {} + +private slots: + void findText(); +}; + +void tst_QPdfSearchModel::findText() +{ + QPdfDocument document; + QCOMPARE(document.load(QFINDTESTDATA("test.pdf")), QPdfDocument::NoError); + + QPdfSearchModel model; + model.setDocument(&document); + QVector<QRectF> matches = model.matches(1, "ai"); + + qDebug() << matches; + QCOMPARE(matches.count(), 3); +} + +QTEST_MAIN(tst_QPdfSearchModel) + +#include "tst_qpdfsearchmodel.moc" |