summaryrefslogtreecommitdiffstats
path: root/src/pdfquick/PdfMultiPageView.qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdfquick/PdfMultiPageView.qml')
-rw-r--r--src/pdfquick/PdfMultiPageView.qml623
1 files changed, 623 insertions, 0 deletions
diff --git a/src/pdfquick/PdfMultiPageView.qml b/src/pdfquick/PdfMultiPageView.qml
new file mode 100644
index 000000000..194d7866e
--- /dev/null
+++ b/src/pdfquick/PdfMultiPageView.qml
@@ -0,0 +1,623 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Pdf
+import QtQuick.Shapes
+
+/*!
+ \qmltype PdfMultiPageView
+ \inqmlmodule QtQuick.Pdf
+ \brief A complete PDF viewer component for scrolling through multiple pages.
+
+ PdfMultiPageView provides a PDF viewer component that offers a user
+ experience similar to many common PDF viewer applications. It supports
+ flicking through the pages in the entire document, with narrow gaps between
+ the page images.
+
+ PdfMultiPageView also supports selecting text and copying it to the
+ clipboard, zooming in and out, clicking an internal link to jump to another
+ section in the document, rotating the view, and searching for text. The
+ \l {PDF Multipage Viewer Example} demonstrates how to use these features
+ in an application.
+
+ The implementation is a QML assembly of smaller building blocks that are
+ available separately. In case you want to make changes in your own version
+ of this component, you can copy the QML, which is installed into the
+ \c QtQuick/Pdf/qml module directory, and modify it as needed.
+
+ \sa PdfPageView, PdfScrollablePageView, PdfStyle
+*/
+Item {
+ /*!
+ \qmlproperty PdfDocument PdfMultiPageView::document
+
+ A PdfDocument object with a valid \c source URL is required:
+
+ \snippet multipageview.qml 0
+ */
+ required property PdfDocument document
+
+ /*!
+ \qmlproperty PdfDocument PdfMultiPageView::selectedText
+
+ The selected text.
+ */
+ property string selectedText
+
+ /*!
+ \qmlmethod void PdfMultiPageView::selectAll()
+
+ Selects all the text on the \l {currentPage}{current page}, and makes it
+ available as the system \l {QClipboard::Selection}{selection} on systems
+ that support that feature.
+
+ \sa copySelectionToClipboard()
+ */
+ function selectAll() {
+ const currentItem = tableView.itemAtCell(tableView.cellAtPos(root.width / 2, root.height / 2))
+ const pdfSelection = currentItem?.selection as PdfSelection
+ pdfSelection?.selectAll()
+ }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::copySelectionToClipboard()
+
+ Copies the selected text (if any) to the
+ \l {QClipboard::Clipboard}{system clipboard}.
+
+ \sa selectAll()
+ */
+ function copySelectionToClipboard() {
+ const currentItem = tableView.itemAtCell(tableView.cellAtPos(root.width / 2, root.height / 2))
+ const pdfSelection = currentItem?.selection as PdfSelection
+ console.log(lcMPV, "currentItem", currentItem, "sel", pdfSelection?.text)
+ pdfSelection?.copyToClipboard()
+ }
+
+ // --------------------------------
+ // page navigation
+
+ /*!
+ \qmlproperty int PdfMultiPageView::currentPage
+ \readonly
+
+ This property holds the zero-based page number of the page visible in the
+ scrollable view. If there is no current page, it holds -1.
+
+ This property is read-only, and is typically used in a binding (or
+ \c onCurrentPageChanged script) to update the part of the user interface
+ that shows the current page number, such as a \l SpinBox.
+
+ \sa PdfPageNavigator::currentPage
+ */
+ property alias currentPage: pageNavigator.currentPage
+
+ /*!
+ \qmlproperty bool PdfMultiPageView::backEnabled
+ \readonly
+
+ This property indicates if it is possible to go back in the navigation
+ history to a previous-viewed page.
+
+ \sa PdfPageNavigator::backAvailable, back()
+ */
+ property alias backEnabled: pageNavigator.backAvailable
+
+ /*!
+ \qmlproperty bool PdfMultiPageView::forwardEnabled
+ \readonly
+
+ This property indicates if it is possible to go to next location in the
+ navigation history.
+
+ \sa PdfPageNavigator::forwardAvailable, forward()
+ */
+ property alias forwardEnabled: pageNavigator.forwardAvailable
+
+ /*!
+ \qmlmethod void PdfMultiPageView::back()
+
+ Scrolls the view back to the previous page that the user visited most
+ recently; or does nothing if there is no previous location on the
+ navigation stack.
+
+ \sa PdfPageNavigator::back(), currentPage, backEnabled
+ */
+ function back() { pageNavigator.back() }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::forward()
+
+ Scrolls the view to the page that the user was viewing when the back()
+ method was called; or does nothing if there is no "next" location on the
+ navigation stack.
+
+ \sa PdfPageNavigator::forward(), currentPage
+ */
+ function forward() { pageNavigator.forward() }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::goToPage(int page)
+
+ Scrolls the view to the given \a page number, if possible.
+
+ \sa PdfPageNavigator::jump(), currentPage
+ */
+ function goToPage(page) {
+ if (page === pageNavigator.currentPage)
+ return
+ goToLocation(page, Qt.point(-1, -1), 0)
+ }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::goToLocation(int page, point location, real zoom)
+
+ Scrolls the view to the \a location on the \a page, if possible,
+ and sets the \a zoom level.
+
+ \sa PdfPageNavigator::jump(), currentPage
+ */
+ function goToLocation(page, location, zoom) {
+ if (tableView.rows === 0) {
+ // save this request for later
+ tableView.pendingRow = page
+ tableView.pendingLocation = location
+ tableView.pendingZoom = zoom
+ return
+ }
+ if (zoom > 0) {
+ pageNavigator.jumping = true // don't call pageNavigator.update() because we will jump() instead
+ root.renderScale = zoom
+ pageNavigator.jumping = false
+ }
+ pageNavigator.jump(page, location, zoom) // actually jump
+ }
+
+ /*!
+ \qmlproperty int PdfMultiPageView::currentPageRenderingStatus
+
+ This property holds the \l {QtQuick::Image::status}{rendering status} of
+ the \l {currentPage}{current page}.
+ */
+ property int currentPageRenderingStatus: Image.Null
+
+ // --------------------------------
+ // page scaling
+
+ /*!
+ \qmlproperty real PdfMultiPageView::renderScale
+
+ This property holds the ratio of pixels to points. The default is \c 1,
+ meaning one point (1/72 of an inch) equals 1 logical pixel.
+ */
+ property real renderScale: 1
+
+ /*!
+ \qmlproperty real PdfMultiPageView::pageRotation
+
+ This property holds the clockwise rotation of the pages.
+
+ The default value is \c 0 degrees (that is, no rotation relative to the
+ orientation of the pages as stored in the PDF file).
+ */
+ property real pageRotation: 0
+
+ /*!
+ \qmlmethod void PdfMultiPageView::resetScale()
+
+ Sets \l renderScale back to its default value of \c 1.
+ */
+ function resetScale() { root.renderScale = 1 }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::scaleToWidth(real width, real height)
+
+ Sets \l renderScale such that the width of the first page will fit into a
+ viewport with the given \a width and \a height. If the page is not rotated,
+ it will be scaled so that its width fits \a width. If it is rotated +/- 90
+ degrees, it will be scaled so that its width fits \a height.
+ */
+ function scaleToWidth(width, height) {
+ root.renderScale = width / (tableView.rot90 ? tableView.firstPagePointSize.height : tableView.firstPagePointSize.width)
+ }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::scaleToPage(real width, real height)
+
+ Sets \l renderScale such that the whole first page will fit into a viewport
+ with the given \a width and \a height. The resulting \l renderScale depends
+ on \l pageRotation: the page will fit into the viewport at a larger size if
+ it is first rotated to have a matching aspect ratio.
+ */
+ function scaleToPage(width, height) {
+ const windowAspect = width / height
+ const pageAspect = tableView.firstPagePointSize.width / tableView.firstPagePointSize.height
+ if (tableView.rot90) {
+ if (windowAspect > pageAspect) {
+ root.renderScale = height / tableView.firstPagePointSize.width
+ } else {
+ root.renderScale = width / tableView.firstPagePointSize.height
+ }
+ } else {
+ if (windowAspect > pageAspect) {
+ root.renderScale = height / tableView.firstPagePointSize.height
+ } else {
+ root.renderScale = width / tableView.firstPagePointSize.width
+ }
+ }
+ }
+
+ // --------------------------------
+ // text search
+
+ /*!
+ \qmlproperty PdfSearchModel PdfMultiPageView::searchModel
+
+ This property holds a PdfSearchModel containing the list of search results
+ for a given \l searchString.
+
+ \sa PdfSearchModel
+ */
+ property alias searchModel: searchModel
+
+ /*!
+ \qmlproperty string PdfMultiPageView::searchString
+
+ This property holds the search string that the user may choose to search
+ for. It is typically used in a binding to the \c text property of a
+ TextField.
+
+ \sa searchModel
+ */
+ property alias searchString: searchModel.searchString
+
+ /*!
+ \qmlmethod void PdfMultiPageView::searchBack()
+
+ Decrements the
+ \l{PdfSearchModel::currentResult}{searchModel's current result}
+ so that the view will jump to the previous search result.
+ */
+ function searchBack() { --searchModel.currentResult }
+
+ /*!
+ \qmlmethod void PdfMultiPageView::searchForward()
+
+ Increments the
+ \l{PdfSearchModel::currentResult}{searchModel's current result}
+ so that the view will jump to the next search result.
+ */
+ function searchForward() { ++searchModel.currentResult }
+
+ LoggingCategory {
+ id: lcMPV
+ name: "qt.pdf.multipageview"
+ }
+
+ id: root
+ PdfStyle { id: style }
+ TableView {
+ id: tableView
+ property bool debug: false
+ property real minScale: 0.1
+ property real maxScale: 10
+ property point jumpLocationMargin: Qt.point(10, 10) // px away from viewport edges
+ anchors.fill: parent
+ anchors.leftMargin: 2
+ model: root.document ? root.document.pageCount : 0
+ rowSpacing: 6
+ property real rotationNorm: Math.round((360 + (root.pageRotation % 360)) % 360)
+ property bool rot90: rotationNorm == 90 || rotationNorm == 270
+ onRot90Changed: forceLayout()
+ onHeightChanged: forceLayout()
+ onWidthChanged: forceLayout()
+ property size firstPagePointSize: root.document?.status === PdfDocument.Ready ? root.document.pagePointSize(0) : Qt.size(1, 1)
+ property real pageHolderWidth: Math.max(root.width, ((rot90 ? root.document?.maxPageHeight : root.document?.maxPageWidth) ?? 0) * root.renderScale)
+ columnWidthProvider: function(col) { return root.document ? pageHolderWidth + vscroll.width + 2 : 0 }
+ rowHeightProvider: function(row) { return (rot90 ? root.document.pagePointSize(row).width : root.document.pagePointSize(row).height) * root.renderScale }
+
+ // delayed-jump feature in case the user called goToPage() or goToLocation() too early
+ property int pendingRow: -1
+ property point pendingLocation
+ property real pendingZoom: -1
+ onRowsChanged: {
+ if (rows > 0 && tableView.pendingRow >= 0) {
+ console.log(lcMPV, "initiating delayed jump to page", tableView.pendingRow, "loc", tableView.pendingLocation, "zoom", tableView.pendingZoom)
+ root.goToLocation(tableView.pendingRow, tableView.pendingLocation, tableView.pendingZoom)
+ tableView.pendingRow = -1
+ tableView.pendingLocation = Qt.point(-1, -1)
+ tableView.pendingZoom = -1
+ }
+ }
+
+ delegate: Rectangle {
+ id: pageHolder
+ required property int index
+ color: tableView.debug ? "beige" : "transparent"
+ Text {
+ visible: tableView.debug
+ anchors { right: parent.right; verticalCenter: parent.verticalCenter }
+ rotation: -90; text: pageHolder.width.toFixed(1) + "x" + pageHolder.height.toFixed(1) + "\n" +
+ image.width.toFixed(1) + "x" + image.height.toFixed(1)
+ }
+ property alias selection: selection
+ Rectangle {
+ id: paper
+ width: image.width
+ height: image.height
+ rotation: root.pageRotation
+ anchors.centerIn: pinch.active ? undefined : parent
+ property size pagePointSize: root.document.pagePointSize(pageHolder.index)
+ property real pageScale: image.paintedWidth / pagePointSize.width
+ PdfPageImage {
+ id: image
+ document: root.document
+ currentFrame: pageHolder.index
+ asynchronous: true
+ fillMode: Image.PreserveAspectFit
+ width: paper.pagePointSize.width * root.renderScale
+ height: paper.pagePointSize.height * root.renderScale
+ property real renderScale: root.renderScale
+ property real oldRenderScale: 1
+ onRenderScaleChanged: {
+ image.sourceSize.width = paper.pagePointSize.width * renderScale * Screen.devicePixelRatio
+ image.sourceSize.height = 0
+ paper.scale = 1
+ searchHighlights.update()
+ }
+ onStatusChanged: {
+ if (pageHolder.index === pageNavigator.currentPage)
+ root.currentPageRenderingStatus = status
+ }
+ }
+ Shape {
+ anchors.fill: parent
+ visible: image.status === Image.Ready
+ onVisibleChanged: searchHighlights.update()
+ ShapePath {
+ strokeWidth: -1
+ fillColor: style.pageSearchResultsColor
+ scale: Qt.size(paper.pageScale, paper.pageScale)
+ PathMultiline {
+ id: searchHighlights
+ function update() {
+ // paths could be a binding, but we need to be able to "kick" it sometimes
+ paths = searchModel.boundingPolygonsOnPage(pageHolder.index)
+ }
+ }
+ }
+ Connections {
+ target: searchModel
+ // whenever the highlights on the _current_ page change, they actually need to change on _all_ pages
+ // (usually because the search string has changed)
+ function onCurrentPageBoundingPolygonsChanged() { searchHighlights.update() }
+ }
+ ShapePath {
+ strokeWidth: -1
+ fillColor: style.selectionColor
+ scale: Qt.size(paper.pageScale, paper.pageScale)
+ PathMultiline {
+ paths: selection.geometry
+ }
+ }
+ }
+ Shape {
+ anchors.fill: parent
+ visible: image.status === Image.Ready && searchModel.currentPage === pageHolder.index
+ ShapePath {
+ strokeWidth: style.currentSearchResultStrokeWidth
+ strokeColor: style.currentSearchResultStrokeColor
+ fillColor: "transparent"
+ scale: Qt.size(paper.pageScale, paper.pageScale)
+ PathMultiline {
+ paths: searchModel.currentResultBoundingPolygons
+ }
+ }
+ }
+ PinchHandler {
+ id: pinch
+ minimumScale: tableView.minScale / root.renderScale
+ maximumScale: Math.max(1, tableView.maxScale / root.renderScale)
+ minimumRotation: root.pageRotation
+ maximumRotation: root.pageRotation
+ onActiveChanged:
+ if (active) {
+ paper.z = 10
+ } else {
+ paper.z = 0
+ const centroidInPoints = Qt.point(pinch.centroid.position.x / root.renderScale,
+ pinch.centroid.position.y / root.renderScale)
+ const centroidInFlickable = tableView.mapFromItem(paper, pinch.centroid.position.x, pinch.centroid.position.y)
+ const newSourceWidth = image.sourceSize.width * paper.scale
+ const ratio = newSourceWidth / image.sourceSize.width
+ console.log(lcMPV, "pinch ended on page", pageHolder.index,
+ "with scale", paper.scale.toFixed(3), "ratio", ratio.toFixed(3),
+ "centroid", pinch.centroid.position, centroidInPoints,
+ "wrt flickable", centroidInFlickable,
+ "page at", pageHolder.x.toFixed(2), pageHolder.y.toFixed(2),
+ "contentX/Y were", tableView.contentX.toFixed(2), tableView.contentY.toFixed(2))
+ if (ratio > 1.1 || ratio < 0.9) {
+ const centroidOnPage = Qt.point(centroidInPoints.x * root.renderScale * ratio, centroidInPoints.y * root.renderScale * ratio)
+ paper.scale = 1
+ pinch.persistentScale = 1
+ paper.x = 0
+ paper.y = 0
+ root.renderScale *= ratio
+ tableView.forceLayout()
+ if (tableView.rotationNorm == 0) {
+ tableView.contentX = pageHolder.x + tableView.originX + centroidOnPage.x - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + centroidOnPage.y - centroidInFlickable.y
+ } else if (tableView.rotationNorm == 90) {
+ tableView.contentX = pageHolder.x + tableView.originX + image.height - centroidOnPage.y - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + centroidOnPage.x - centroidInFlickable.y
+ } else if (tableView.rotationNorm == 180) {
+ tableView.contentX = pageHolder.x + tableView.originX + image.width - centroidOnPage.x - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + image.height - centroidOnPage.y - centroidInFlickable.y
+ } else if (tableView.rotationNorm == 270) {
+ tableView.contentX = pageHolder.x + tableView.originX + centroidOnPage.y - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + image.width - centroidOnPage.x - centroidInFlickable.y
+ }
+ console.log(lcMPV, "contentX/Y adjusted to", tableView.contentX.toFixed(2), tableView.contentY.toFixed(2), "y @top", pageHolder.y)
+ tableView.returnToBounds()
+ }
+ }
+ grabPermissions: PointerHandler.CanTakeOverFromAnything
+ }
+ DragHandler {
+ id: textSelectionDrag
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ target: null
+ }
+ TapHandler {
+ id: mouseClickHandler
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ }
+ TapHandler {
+ id: touchTapHandler
+ acceptedDevices: PointerDevice.TouchScreen
+ onTapped: {
+ selection.clear()
+ selection.forceActiveFocus()
+ }
+ }
+ Repeater {
+ model: PdfLinkModel {
+ id: linkModel
+ document: root.document
+ page: image.currentFrame
+ }
+ delegate: PdfLinkDelegate {
+ x: rectangle.x * paper.pageScale
+ y: rectangle.y * paper.pageScale
+ width: rectangle.width * paper.pageScale
+ height: rectangle.height * paper.pageScale
+ visible: image.status === Image.Ready
+ onTapped:
+ (link) => {
+ if (link.page >= 0)
+ root.goToLocation(link.page, link.location, link.zoom)
+ else
+ Qt.openUrlExternally(url)
+ }
+ }
+ }
+ PdfSelection {
+ id: selection
+ anchors.fill: parent
+ document: root.document
+ page: image.currentFrame
+ renderScale: image.renderScale
+ from: textSelectionDrag.centroid.pressPosition
+ to: textSelectionDrag.centroid.position
+ hold: !textSelectionDrag.active && !mouseClickHandler.pressed
+ onTextChanged: root.selectedText = text
+ focus: true
+ }
+ }
+ }
+ ScrollBar.vertical: ScrollBar {
+ id: vscroll
+ property bool moved: false
+ onPositionChanged: moved = true
+ onPressedChanged: if (pressed) {
+ // When the user starts scrolling, push the location where we came from so the user can go "back" there
+ const cell = tableView.cellAtPos(root.width / 2, root.height / 2)
+ const currentItem = tableView.itemAtCell(cell)
+ const currentLocation = currentItem
+ ? Qt.point((tableView.contentX - currentItem.x + tableView.jumpLocationMargin.x) / root.renderScale,
+ (tableView.contentY - currentItem.y + tableView.jumpLocationMargin.y) / root.renderScale)
+ : Qt.point(0, 0) // maybe the delegate wasn't loaded yet
+ pageNavigator.jump(cell.y, currentLocation, root.renderScale)
+ }
+ onActiveChanged: if (!active ) {
+ // When the scrollbar stops moving, tell navstack where we are, so as to update currentPage etc.
+ const cell = tableView.cellAtPos(root.width / 2, root.height / 2)
+ const currentItem = tableView.itemAtCell(cell)
+ const currentLocation = currentItem
+ ? Qt.point((tableView.contentX - currentItem.x + tableView.jumpLocationMargin.x) / root.renderScale,
+ (tableView.contentY - currentItem.y + tableView.jumpLocationMargin.y) / root.renderScale)
+ : Qt.point(0, 0) // maybe the delegate wasn't loaded yet
+ pageNavigator.update(cell.y, currentLocation, root.renderScale)
+ }
+ }
+ ScrollBar.horizontal: ScrollBar { }
+ }
+ onRenderScaleChanged: {
+ // if pageNavigator.jumped changes the scale, don't turn around and update the stack again;
+ // and don't force layout either, because positionViewAtCell() will do that
+ if (pageNavigator.jumping)
+ return
+ // page size changed: TableView needs to redo layout to avoid overlapping delegates or gaps between them
+ tableView.forceLayout()
+ const cell = tableView.cellAtPos(root.width / 2, root.height / 2)
+ const currentItem = tableView.itemAtCell(cell)
+ if (currentItem) {
+ const currentLocation = Qt.point((tableView.contentX - currentItem.x + tableView.jumpLocationMargin.x) / root.renderScale,
+ (tableView.contentY - currentItem.y + tableView.jumpLocationMargin.y) / root.renderScale)
+ pageNavigator.update(cell.y, currentLocation, renderScale)
+ }
+ }
+ PdfPageNavigator {
+ id: pageNavigator
+ property bool jumping: false
+ property int previousPage: 0
+ onJumped: function(current) {
+ jumping = true
+ if (current.zoom > 0)
+ root.renderScale = current.zoom
+ const pageSize = root.document.pagePointSize(current.page)
+ if (current.location.y < 0) {
+ // invalid to indicate that a specific location was not needed,
+ // so attempt to position the new page just as the current page is
+ const previousPageDelegate = tableView.itemAtCell(0, previousPage)
+ const currentYOffset = previousPageDelegate
+ ? tableView.contentY - previousPageDelegate.y
+ : 0
+ tableView.positionViewAtRow(current.page, Qt.AlignTop, currentYOffset)
+ console.log(lcMPV, "going from page", previousPage, "to", current.page, "offset", currentYOffset,
+ "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1))
+ } else if (current.rectangles.length > 0) {
+ // jump to a search result and position the covered area within the viewport
+ pageSize.width *= root.renderScale
+ pageSize.height *= root.renderScale
+ const rectPts = current.rectangles[0]
+ const rectPx = Qt.rect(rectPts.x * root.renderScale - tableView.jumpLocationMargin.x,
+ rectPts.y * root.renderScale - tableView.jumpLocationMargin.y,
+ rectPts.width * root.renderScale + tableView.jumpLocationMargin.x * 2,
+ rectPts.height * root.renderScale + tableView.jumpLocationMargin.y * 2)
+ tableView.positionViewAtCell(0, current.page, TableView.Contain, Qt.point(0, 0), rectPx)
+ console.log(lcMPV, "going to zoom", root.renderScale, "rect", rectPx, "on page", current.page,
+ "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1))
+ } else {
+ // jump to a page and position the given location relative to the top-left corner of the viewport
+ pageSize.width *= root.renderScale
+ pageSize.height *= root.renderScale
+ const rectPx = Qt.rect(current.location.x * root.renderScale - tableView.jumpLocationMargin.x,
+ current.location.y * root.renderScale - tableView.jumpLocationMargin.y,
+ tableView.jumpLocationMargin.x * 2, tableView.jumpLocationMargin.y * 2)
+ tableView.positionViewAtCell(0, current.page, TableView.AlignLeft | TableView.AlignTop, Qt.point(0, 0), rectPx)
+ console.log(lcMPV, "going to zoom", root.renderScale, "loc", current.location, "on page", current.page,
+ "ended up @", tableView.contentX.toFixed(1) + ", " + tableView.contentY.toFixed(1))
+ }
+ jumping = false
+ previousPage = current.page
+ }
+
+ property url documentSource: root.document.source
+ onDocumentSourceChanged: {
+ pageNavigator.clear()
+ root.resetScale()
+ tableView.contentX = 0
+ tableView.contentY = 0
+ }
+ }
+ PdfSearchModel {
+ id: searchModel
+ document: root.document === undefined ? null : root.document
+ onCurrentResultChanged: pageNavigator.jump(currentResultLink)
+ }
+}