summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2020-01-22 00:56:16 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2020-02-03 23:44:03 +0100
commit7cf69cb52d434f5e74619b0577104d05688b0c22 (patch)
treed0d60f971c59087b7f353123df5233a3e2343b3b
parenta8e4ad7726f1aa52624a0367558650cd4d899c79 (diff)
Add PdfNavigationStack for forward/back navigation
Works well enough to use, but needs autotests and at least one fix. Change-Id: I2114b9fb3b5ddf7cfe2106d4a4fbc7d74852c61d Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r--examples/pdf/pdfviewer/viewer.qml31
-rw-r--r--src/pdf/quick/plugin.cpp2
-rw-r--r--src/pdf/quick/qml/PdfPageView.qml27
-rw-r--r--src/pdf/quick/qquickpdfnavigationstack.cpp162
-rw-r--r--src/pdf/quick/qquickpdfnavigationstack_p.h95
-rw-r--r--src/pdf/quick/quick.pro2
6 files changed, 307 insertions, 12 deletions
diff --git a/examples/pdf/pdfviewer/viewer.qml b/examples/pdf/pdfviewer/viewer.qml
index 1cf0b432b..b0cd8985d 100644
--- a/examples/pdf/pdfviewer/viewer.qml
+++ b/examples/pdf/pdfviewer/viewer.qml
@@ -57,8 +57,8 @@ import Qt.labs.platform 1.1 as Platform
ApplicationWindow {
id: root
- width: 800
- height: 640
+ width: 1280
+ height: 1024
color: "lightgrey"
title: document.title
visible: true
@@ -125,12 +125,22 @@ ApplicationWindow {
onTriggered: pageView.rotation += 90
}
}
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-previous-view-page.svg"
+ enabled: pageView.backEnabled
+ onTriggered: pageView.back()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "go back"
+ }
SpinBox {
id: currentPageSB
from: 1
to: document.pageCount
- value: 1
editable: true
+ onValueChanged: pageView.currentPage = value - 1
Shortcut {
sequence: StandardKey.MoveToPreviousPage
onActivated: currentPageSB.value--
@@ -142,6 +152,16 @@ ApplicationWindow {
}
ToolButton {
action: Action {
+ icon.source: "resources/go-next-view-page.svg"
+ enabled: pageView.forwardEnabled
+ onTriggered: pageView.forward()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "go forward"
+ }
+ ToolButton {
+ action: Action {
shortcut: StandardKey.Copy
icon.source: "resources/edit-copy.svg"
enabled: pageView.selectedText !== ""
@@ -203,7 +223,10 @@ ApplicationWindow {
PdfPageView {
id: pageView
- currentPage: currentPageSB.value - 1
+// currentPage: currentPageSB.value - 1
+ // TODO should work but ends up being NaN in QQuickSpinBoxPrivate::setValue() (?!)
+// onCurrentPageChanged: currentPageSB.value = pageView.currrentPage + 1
+ onCurrentPageReallyChanged: currentPageSB.value = page + 1
document: PdfDocument {
id: document
onStatusChanged: if (status === PdfDocument.Error) errorDialog.open()
diff --git a/src/pdf/quick/plugin.cpp b/src/pdf/quick/plugin.cpp
index 519ea43af..3c8077ff2 100644
--- a/src/pdf/quick/plugin.cpp
+++ b/src/pdf/quick/plugin.cpp
@@ -40,6 +40,7 @@
#include <QtQml/qqmlextensionplugin.h>
#include "qquickpdfdocument_p.h"
#include "qquickpdflinkmodel_p.h"
+#include "qquickpdfnavigationstack_p.h"
#include "qquickpdfsearchmodel_p.h"
#include "qquickpdfselection_p.h"
@@ -83,6 +84,7 @@ public:
qmlRegisterType<QQuickPdfDocument>(uri, 5, 15, "PdfDocument");
qmlRegisterType<QQuickPdfLinkModel>(uri, 5, 15, "PdfLinkModel");
+ qmlRegisterType<QQuickPdfNavigationStack>(uri, 5, 15, "PdfNavigationStack");
qmlRegisterType<QQuickPdfSearchModel>(uri, 5, 15, "PdfSearchModel");
qmlRegisterType<QQuickPdfSelection>(uri, 5, 15, "PdfSelection");
diff --git a/src/pdf/quick/qml/PdfPageView.qml b/src/pdf/quick/qml/PdfPageView.qml
index e20ebd1b4..041054e59 100644
--- a/src/pdf/quick/qml/PdfPageView.qml
+++ b/src/pdf/quick/qml/PdfPageView.qml
@@ -48,13 +48,18 @@ Rectangle {
property var document: null
property real renderScale: 1
property alias sourceSize: image.sourceSize
- property alias currentPage: image.currentFrame
+ property alias currentPage: navigationStack.currentPage
property alias pageCount: image.frameCount
property alias searchString: searchModel.searchString
property alias selectedText: selection.text
property alias status: image.status
+ property alias backEnabled: navigationStack.backAvailable
+ property alias forwardEnabled: navigationStack.forwardAvailable
+ function back() { navigationStack.back() }
+ function forward() { navigationStack.forward() }
+ signal currentPageReallyChanged(page: int)
- property real __pageScale: image.paintedWidth / document.pagePointSize(image.currentFrame).width
+ property real __pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width
function resetScale() {
image.sourceSize.width = 0
@@ -78,7 +83,7 @@ Rectangle {
function scaleToPage(width, height) {
var windowAspect = width / height
var halfRotation = Math.abs(paper.rotation % 180)
- var pagePointSize = document.pagePointSize(image.currentFrame)
+ var pagePointSize = document.pagePointSize(navigationStack.currentPage)
if (halfRotation > 45 && halfRotation < 135) {
// rotated 90 or 270ยบ
var pageAspect = pagePointSize.height / pagePointSize.width
@@ -104,7 +109,7 @@ Rectangle {
PdfSelection {
id: selection
document: paper.document
- page: image.currentFrame
+ page: navigationStack.currentPage
fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / paper.__pageScale, textSelectionDrag.centroid.pressPosition.y / paper.__pageScale)
toPoint: Qt.point(textSelectionDrag.centroid.position.x / paper.__pageScale, textSelectionDrag.centroid.position.y / paper.__pageScale)
hold: !textSelectionDrag.active && !tapHandler.pressed
@@ -116,11 +121,17 @@ Rectangle {
PdfSearchModel {
id: searchModel
document: paper.document
- page: image.currentFrame
+ page: navigationStack.currentPage
+ }
+
+ PdfNavigationStack {
+ id: navigationStack
+ onCurrentPageChanged: paper.currentPageReallyChanged(navigationStack.currentPage)
}
Image {
id: image
+ currentFrame: navigationStack.currentPage
source: document.status === PdfDocument.Ready ? document.source : ""
asynchronous: true
fillMode: Image.PreserveAspectFit
@@ -145,7 +156,7 @@ Rectangle {
}
}
onRenderScaleChanged: {
- image.sourceSize.width = document.pagePointSize(image.currentFrame).width * renderScale
+ image.sourceSize.width = document.pagePointSize(navigationStack.currentPage).width * renderScale
image.sourceSize.height = 0
paper.scale = 1
}
@@ -178,7 +189,7 @@ Rectangle {
model: PdfLinkModel {
id: linkModel
document: paper.document
- page: image.currentFrame
+ page: navigationStack.currentPage
}
delegate: Rectangle {
color: "transparent"
@@ -191,7 +202,7 @@ Rectangle {
TapHandler {
onTapped: {
if (page >= 0)
- image.currentFrame = page
+ navigationStack.currentPage = page
else
Qt.openUrlExternally(url)
}
diff --git a/src/pdf/quick/qquickpdfnavigationstack.cpp b/src/pdf/quick/qquickpdfnavigationstack.cpp
new file mode 100644
index 000000000..c19fae735
--- /dev/null
+++ b/src/pdf/quick/qquickpdfnavigationstack.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** 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 "qquickpdfnavigationstack_p.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcNav, "qt.pdf.navigationstack")
+
+/*!
+ \qmltype PdfNavigationStack
+ \instantiates QQuickPdfNavigationStack
+ \inqmlmodule QtQuick.Pdf
+ \ingroup pdf
+ \brief History of the pages visited within a PDF Document.
+ \since 5.15
+
+ PdfNavigationStack remembers which pages the user has visited in a PDF
+ document, and provides the ability to traverse backward and forward.
+*/
+
+QQuickPdfNavigationStack::QQuickPdfNavigationStack(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \qmlmethod void PdfNavigationStack::forward()
+
+ Goes back to the page that was being viewed before back() was called, and
+ then emits the \l currentPageJumped() signal.
+
+ If \l currentPage was set by assignment or binding since the last time
+ \l back() was called, the forward() function does nothing, because there is
+ a branch in the timeline which causes the "future" to be lost.
+*/
+void QQuickPdfNavigationStack::forward()
+{
+ if (m_nextHistoryIndex >= m_pageHistory.count())
+ return;
+ bool backAvailableWas = backAvailable();
+ bool forwardAvailableWas = forwardAvailable();
+ m_changing = true;
+ setCurrentPage(m_pageHistory.at(++m_nextHistoryIndex));
+ m_changing = false;
+ emit currentPageJumped(m_currentPage);
+ if (backAvailableWas != backAvailable())
+ emit backAvailableChanged();
+ if (forwardAvailableWas != forwardAvailable())
+ emit forwardAvailableChanged();
+}
+
+/*!
+ \qmlmethod void PdfNavigationStack::back()
+
+ Pops the stack and causes the \l currentPage property to change to the
+ most-recently-viewed page, and then emits the \l currentPageJumped()
+ signal.
+*/
+void QQuickPdfNavigationStack::back()
+{
+ if (m_nextHistoryIndex <= 0)
+ return;
+ bool backAvailableWas = backAvailable();
+ bool forwardAvailableWas = forwardAvailable();
+ m_changing = true;
+ // TODO don't do that when going back after going forward
+ m_pageHistory.append(m_currentPage);
+ setCurrentPage(m_pageHistory.at(--m_nextHistoryIndex));
+ m_changing = false;
+ emit currentPageJumped(m_currentPage);
+ if (backAvailableWas != backAvailable())
+ emit backAvailableChanged();
+ if (forwardAvailableWas != forwardAvailable())
+ emit forwardAvailableChanged();
+}
+
+/*!
+ \qmlproperty int PdfNavigationStack::currentPage
+
+ This property holds the current page that is being viewed.
+
+ It should be set when the viewer's current page changes. Every time this
+ property is set, it pushes the current page number onto the stack, such
+ that the history of pages that have been viewed will grow.
+*/
+void QQuickPdfNavigationStack::setCurrentPage(int currentPage)
+{
+ if (m_currentPage == currentPage)
+ return;
+ bool backAvailableWas = backAvailable();
+ bool forwardAvailableWas = forwardAvailable();
+ if (!m_changing) {
+ if (m_nextHistoryIndex >= 0 && m_nextHistoryIndex < m_pageHistory.count())
+ m_pageHistory.remove(m_nextHistoryIndex, m_pageHistory.count() - m_nextHistoryIndex);
+ m_pageHistory.append(m_currentPage);
+ m_nextHistoryIndex = m_pageHistory.count();
+ }
+ m_currentPage = currentPage;
+ emit currentPageChanged();
+ if (backAvailableWas != backAvailable())
+ emit backAvailableChanged();
+ if (forwardAvailableWas != forwardAvailable())
+ emit forwardAvailableChanged();
+ qCDebug(qLcNav) << "current" << m_currentPage << "history" << m_pageHistory;
+}
+
+bool QQuickPdfNavigationStack::backAvailable() const
+{
+ return m_nextHistoryIndex > 0;
+}
+
+bool QQuickPdfNavigationStack::forwardAvailable() const
+{
+ return m_nextHistoryIndex < m_pageHistory.count();
+}
+
+/*!
+ \qmlsignal PdfNavigationStack::currentPageJumped(int page)
+
+ This signal is emitted when either forward() or back() is called, to
+ distinguish navigational jumps from cases when the \l currentPage property
+ is set by means of a binding or assignment. Contrast with the
+ \c currentPageChanged signal, which is emitted in all cases, and does not
+ include the \c page argument.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/pdf/quick/qquickpdfnavigationstack_p.h b/src/pdf/quick/qquickpdfnavigationstack_p.h
new file mode 100644
index 000000000..54713fabb
--- /dev/null
+++ b/src/pdf/quick/qquickpdfnavigationstack_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 QQUICKPDFNAVIGATIONSTACK_P_H
+#define QQUICKPDFNAVIGATIONSTACK_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 <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPdfNavigationStack : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
+ Q_PROPERTY(bool backAvailable READ backAvailable NOTIFY backAvailableChanged)
+ Q_PROPERTY(bool forwardAvailable READ forwardAvailable NOTIFY forwardAvailableChanged)
+
+public:
+ explicit QQuickPdfNavigationStack(QObject *parent = nullptr);
+
+ Q_INVOKABLE void forward();
+ Q_INVOKABLE void back();
+
+ int currentPage() const { return m_currentPage; }
+ void setCurrentPage(int currentPage);
+
+ bool backAvailable() const;
+ bool forwardAvailable() const;
+
+Q_SIGNALS:
+ void currentPageChanged();
+ void currentPageJumped(int page);
+ void backAvailableChanged();
+ void forwardAvailableChanged();
+
+private:
+ QVector<int> m_pageHistory;
+ int m_nextHistoryIndex = 0;
+ int m_currentPage = 0;
+ bool m_changing = false;
+
+ Q_DISABLE_COPY(QQuickPdfNavigationStack)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPdfNavigationStack)
+
+#endif // QQUICKPDFNAVIGATIONSTACK_P_H
diff --git a/src/pdf/quick/quick.pro b/src/pdf/quick/quick.pro
index 7d65091aa..a3bdfb45e 100644
--- a/src/pdf/quick/quick.pro
+++ b/src/pdf/quick/quick.pro
@@ -16,12 +16,14 @@ SOURCES += \
plugin.cpp \
qquickpdfdocument.cpp \
qquickpdflinkmodel.cpp \
+ qquickpdfnavigationstack.cpp \
qquickpdfsearchmodel.cpp \
qquickpdfselection.cpp \
HEADERS += \
qquickpdfdocument_p.h \
qquickpdflinkmodel_p.h \
+ qquickpdfnavigationstack_p.h \
qquickpdfsearchmodel_p.h \
qquickpdfselection_p.h \