diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2020-02-05 15:53:57 +0100 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2020-02-11 08:29:28 +0100 |
commit | 09a6eac4a63b32548ecc1ff5b16a5d8fc3ba1c04 (patch) | |
tree | 924c615feb59f8d3372886ec53121b05b1701d28 /src/pdf/quick | |
parent | 25a371caa376c513f22d5c01e425a18629657fdc (diff) |
Add QPdfDestination; NavigationStack stores page, location and zoom
Push/back/forward behavior seems more correct now, but still no
autotest yet.
QPdfDestination might be useful to represent locations of search results,
for link destinations and maybe named destinations too.
Fixes: QTBUG-77512
Change-Id: I113b2c535a2cd302106e6546104c64e12985d387
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/pdf/quick')
-rw-r--r-- | src/pdf/quick/qml/PdfMultiPageView.qml | 4 | ||||
-rw-r--r-- | src/pdf/quick/qml/PdfPageView.qml | 3 | ||||
-rw-r--r-- | src/pdf/quick/qquickpdfnavigationstack.cpp | 188 | ||||
-rw-r--r-- | src/pdf/quick/qquickpdfnavigationstack_p.h | 21 |
4 files changed, 164 insertions, 52 deletions
diff --git a/src/pdf/quick/qml/PdfMultiPageView.qml b/src/pdf/quick/qml/PdfMultiPageView.qml index 28436b90d..be41153b6 100644 --- a/src/pdf/quick/qml/PdfMultiPageView.qml +++ b/src/pdf/quick/qml/PdfMultiPageView.qml @@ -111,7 +111,7 @@ Item { property bool rot90: rotationModulus > 45 && rotationModulus < 135 property size firstPagePointSize: document.pagePointSize(0) onCurrentIndexChanged: { - navigationStack.currentPage = currentIndex + navigationStack.push(currentIndex, Qt.point(0, 0), root.renderScale) root.currentPageReallyChanged(currentIndex) } delegate: Rectangle { @@ -244,7 +244,7 @@ Item { } PdfNavigationStack { id: navigationStack - onCurrentPageJumped: listView.currentIndex = page + onJumped: listView.currentIndex = page onCurrentPageChanged: root.currentPageReallyChanged(navigationStack.currentPage) } } diff --git a/src/pdf/quick/qml/PdfPageView.qml b/src/pdf/quick/qml/PdfPageView.qml index cf287ecf7..d03e9dc9d 100644 --- a/src/pdf/quick/qml/PdfPageView.qml +++ b/src/pdf/quick/qml/PdfPageView.qml @@ -57,6 +57,7 @@ Rectangle { property alias forwardEnabled: navigationStack.forwardAvailable function back() { navigationStack.back() } function forward() { navigationStack.forward() } + function goToPage(page) { navigationStack.push(page, Qt.point(0, 0), renderScale) } signal currentPageReallyChanged(page: int) property real __pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width @@ -203,7 +204,7 @@ Rectangle { cursorShape: Qt.PointingHandCursor onClicked: { if (page >= 0) - navigationStack.currentPage = page + navigationStack.push(page, Qt.point(0, 0), paper.renderScale) else Qt.openUrlExternally(url) } diff --git a/src/pdf/quick/qquickpdfnavigationstack.cpp b/src/pdf/quick/qquickpdfnavigationstack.cpp index c19fae735..57acdc4bc 100644 --- a/src/pdf/quick/qquickpdfnavigationstack.cpp +++ b/src/pdf/quick/qquickpdfnavigationstack.cpp @@ -46,10 +46,10 @@ Q_LOGGING_CATEGORY(qLcNav, "qt.pdf.navigationstack") \instantiates QQuickPdfNavigationStack \inqmlmodule QtQuick.Pdf \ingroup pdf - \brief History of the pages visited within a PDF Document. + \brief History of the destinations visited within a PDF Document. \since 5.15 - PdfNavigationStack remembers which pages the user has visited in a PDF + PdfNavigationStack remembers which destinations the user has visited in a PDF document, and provides the ability to traverse backward and forward. */ @@ -61,102 +61,206 @@ QQuickPdfNavigationStack::QQuickPdfNavigationStack(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. + Goes back to the page, location and zoom level that was being viewed before + back() was called, and then emits the \l jumped() 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. + If a new destination was pushed 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()) + if (m_currentHistoryIndex >= m_pageHistory.count() - 1) return; bool backAvailableWas = backAvailable(); bool forwardAvailableWas = forwardAvailable(); + QPointF currentLocationWas = currentLocation(); + qreal currentZoomWas = currentZoom(); + ++m_currentHistoryIndex; m_changing = true; - setCurrentPage(m_pageHistory.at(++m_nextHistoryIndex)); - m_changing = false; - emit currentPageJumped(m_currentPage); - if (backAvailableWas != backAvailable()) + emit jumped(currentPage(), currentLocation(), currentZoom()); + emit currentPageChanged(); + if (currentLocationWas != currentLocation()) + emit currentLocationChanged(); + if (currentZoomWas != currentZoom()) + emit currentZoomChanged(); + if (!backAvailableWas) emit backAvailableChanged(); if (forwardAvailableWas != forwardAvailable()) emit forwardAvailableChanged(); + m_changing = false; } /*! \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. + Pops the stack, updates the \l currentPage, \l currentLocation and + \l currentZoom properties to the most-recently-viewed destination, and then + emits the \l jumped() signal. */ void QQuickPdfNavigationStack::back() { - if (m_nextHistoryIndex <= 0) + if (m_currentHistoryIndex <= 0) return; bool backAvailableWas = backAvailable(); bool forwardAvailableWas = forwardAvailable(); + QPointF currentLocationWas = currentLocation(); + qreal currentZoomWas = currentZoom(); + --m_currentHistoryIndex; 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); + emit jumped(currentPage(), currentLocation(), currentZoom()); + emit currentPageChanged(); + if (currentLocationWas != currentLocation()) + emit currentLocationChanged(); + if (currentZoomWas != currentZoom()) + emit currentZoomChanged(); if (backAvailableWas != backAvailable()) emit backAvailableChanged(); - if (forwardAvailableWas != forwardAvailable()) + if (!forwardAvailableWas) emit forwardAvailableChanged(); + m_changing = false; } /*! \qmlproperty int PdfNavigationStack::currentPage This property holds the current page that is being viewed. + If there is no current page, it holds \c -1. +*/ +int QQuickPdfNavigationStack::currentPage() const +{ + if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) + return -1; + return m_pageHistory.at(m_currentHistoryIndex)->page; +} + +/*! + \qmlproperty point PdfNavigationStack::currentLocation + + This property holds the current location on the page that is being viewed. +*/ +QPointF QQuickPdfNavigationStack::currentLocation() const +{ + if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) + return QPointF(); + return m_pageHistory.at(m_currentHistoryIndex)->location; +} - 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. +/*! + \qmlproperty real PdfNavigationStack::currentZoom + + This property holds the magnification scale on the page that is being viewed. */ -void QQuickPdfNavigationStack::setCurrentPage(int currentPage) +qreal QQuickPdfNavigationStack::currentZoom() const { - if (m_currentPage == currentPage) + if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) + return 1; + return m_pageHistory.at(m_currentHistoryIndex)->zoom; +} + +/*! + \qmlmethod void PdfNavigationStack::push(int page, point location, qreal zoom) + + Adds the given destination, consisting of \a page, \a location and \a zoom, + to the history of visited locations. + + If forwardAvailable is \c true, calling this function represents a branch + in the timeline which causes the "future" to be lost, and therefore + forwardAvailable will change to \c false. +*/ +void QQuickPdfNavigationStack::push(int page, QPointF location, qreal zoom) +{ + if (page == currentPage() && location == currentLocation() && zoom == currentZoom()) return; + if (qFuzzyIsNull(zoom)) + zoom = currentZoom(); 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(); + if (m_currentHistoryIndex >= 0 && forwardAvailableWas) + m_pageHistory.remove(m_currentHistoryIndex + 1, m_pageHistory.count() - m_currentHistoryIndex - 1); + m_pageHistory.append(QExplicitlySharedDataPointer<QPdfDestinationPrivate>(new QPdfDestinationPrivate(page, location, zoom))); + m_currentHistoryIndex = m_pageHistory.count() - 1; } - m_currentPage = currentPage; emit currentPageChanged(); - if (backAvailableWas != backAvailable()) + emit currentLocationChanged(); + emit currentZoomChanged(); + if (m_changing) + return; + if (!backAvailableWas) emit backAvailableChanged(); - if (forwardAvailableWas != forwardAvailable()) + if (forwardAvailableWas) emit forwardAvailableChanged(); - qCDebug(qLcNav) << "current" << m_currentPage << "history" << m_pageHistory; + qCDebug(qLcNav) << "push: index" << m_currentHistoryIndex << "page" << page + << "@" << location << "zoom" << zoom << "-> history" << + [this]() { + QStringList ret; + for (auto d : m_pageHistory) + ret << QString::number(d->page); + return ret.join(','); + }(); +} + +/*! + \qmlmethod void PdfNavigationStack::update(int page, point location, qreal zoom) + + Modifies the current destination, consisting of \a page, \a location and \a zoom. + + This can be called periodically while the user is manually moving around + the document, so that after back() is called, forward() will jump back to + the most-recently-viewed destination rather than the destination that was + last specified by push(). + + The \c currentPageChanged, \c currentLocationChanged and \c currentZoomChanged + signals will be emitted if the respective properties are actually changed. + The \l jumped signal is not emitted, because this operation + represents smooth movement rather than a navigational jump. +*/ +void QQuickPdfNavigationStack::update(int page, QPointF location, qreal zoom) +{ + if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count()) + return; + int currentPageWas = currentPage(); + QPointF currentLocationWas = currentLocation(); + qreal currentZoomWas = currentZoom(); + if (page == currentPageWas && location == currentLocationWas && zoom == currentZoomWas) + return; + m_pageHistory[m_currentHistoryIndex]->page = page; + m_pageHistory[m_currentHistoryIndex]->location = location; + m_pageHistory[m_currentHistoryIndex]->zoom = zoom; + if (currentPageWas != page) + emit currentPageChanged(); + if (currentLocationWas != location) + emit currentLocationChanged(); + if (currentZoomWas != zoom) + emit currentZoomChanged(); + qCDebug(qLcNav) << "update: index" << m_currentHistoryIndex << "page" << page + << "@" << location << "zoom" << zoom << "-> history" << + [this]() { + QStringList ret; + for (auto d : m_pageHistory) + ret << QString::number(d->page); + return ret.join(','); + }(); } bool QQuickPdfNavigationStack::backAvailable() const { - return m_nextHistoryIndex > 0; + return m_currentHistoryIndex > 0; } bool QQuickPdfNavigationStack::forwardAvailable() const { - return m_nextHistoryIndex < m_pageHistory.count(); + return m_currentHistoryIndex < m_pageHistory.count() - 1; } /*! - \qmlsignal PdfNavigationStack::currentPageJumped(int page) + \qmlsignal PdfNavigationStack::jumped(int page, point location, qreal zoom) 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. + distinguish navigational jumps from cases when push() is called. + Contrast with the \c currentPageChanged signal, which is emitted in all + cases, and does not include the \c page, \c location and \c zoom arguments. */ QT_END_NAMESPACE diff --git a/src/pdf/quick/qquickpdfnavigationstack_p.h b/src/pdf/quick/qquickpdfnavigationstack_p.h index 54713fabb..8d7102fb1 100644 --- a/src/pdf/quick/qquickpdfnavigationstack_p.h +++ b/src/pdf/quick/qquickpdfnavigationstack_p.h @@ -49,6 +49,7 @@ // #include "qquickpdfdocument_p.h" +#include "../api/qpdfdestination_p.h" #include <QtQml/qqml.h> @@ -57,32 +58,38 @@ QT_BEGIN_NAMESPACE class QQuickPdfNavigationStack : public QObject { Q_OBJECT - Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged) + Q_PROPERTY(int currentPage READ currentPage NOTIFY currentPageChanged) + Q_PROPERTY(QPointF currentLocation READ currentLocation NOTIFY currentLocationChanged) + Q_PROPERTY(qreal currentZoom READ currentZoom NOTIFY currentZoomChanged) 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 push(int page, QPointF location, qreal zoom); + Q_INVOKABLE void update(int page, QPointF location, qreal zoom); Q_INVOKABLE void forward(); Q_INVOKABLE void back(); - int currentPage() const { return m_currentPage; } - void setCurrentPage(int currentPage); + int currentPage() const; + QPointF currentLocation() const; + qreal currentZoom() const; bool backAvailable() const; bool forwardAvailable() const; Q_SIGNALS: void currentPageChanged(); - void currentPageJumped(int page); + void currentLocationChanged(); + void currentZoomChanged(); void backAvailableChanged(); void forwardAvailableChanged(); + void jumped(int page, QPointF location, qreal zoom); private: - QVector<int> m_pageHistory; - int m_nextHistoryIndex = 0; - int m_currentPage = 0; + QVector<QExplicitlySharedDataPointer<QPdfDestinationPrivate>> m_pageHistory; + int m_currentHistoryIndex = 0; bool m_changing = false; Q_DISABLE_COPY(QQuickPdfNavigationStack) |