summaryrefslogtreecommitdiffstats
path: root/src/pdf/quick
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2019-08-26 15:31:00 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2020-01-23 19:44:17 +0100
commitb6dd845ec4a6bfb6b620686681e20d38a2f24101 (patch)
treecafcf5b7c8f3185fb7fa5dfe07b38cd9b17a8cb7 /src/pdf/quick
parent32fb888f3c5b6d415d84895e3cab594de026d3dd (diff)
Add QPdfSearchModel, QML PdfSearchModel and PdfPageView
This enables searching a PDF for a text string and getting the boundaries of the areas where it is found. The boundaries are returned as polygons intended to be rendered with PathMultiline. PdfPageView is a QML component intended to be a drop-in viewer for use in applications that need the most common PDF viewing functionality. More advanced applications are free to use it as a starting point for customization. Task-number: QTBUG-77507 Task-number: QTBUG-77514 Change-Id: Id08ac30224e41b6cdfb9300cc4288d5750259f78 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/pdf/quick')
-rw-r--r--src/pdf/quick/plugin.cpp4
-rw-r--r--src/pdf/quick/qml/PdfPageView.qml120
-rw-r--r--src/pdf/quick/qquickpdfdocument.cpp35
-rw-r--r--src/pdf/quick/qquickpdfdocument_p.h4
-rw-r--r--src/pdf/quick/qquickpdfsearchmodel.cpp165
-rw-r--r--src/pdf/quick/qquickpdfsearchmodel_p.h103
-rw-r--r--src/pdf/quick/quick.pro13
-rw-r--r--src/pdf/quick/resources.qrc5
8 files changed, 447 insertions, 2 deletions
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>