Commit f467edc9 authored by Shawn Rutledge's avatar Shawn Rutledge
Browse files

PdfMultiPageView: use TableView; horz. scroll; control page position


TableView is missing some features compared to ListView; so finding out
where we currently are (which row) and programmatic positioning on a
specific y coordinate of a specific row require some workarounds for now,
including helpers in PdfDocument.

TableView also assumes (and sporadically enforces) that all cells in a
column have the same width.  So we need a placeholder Item for each page.
This also helps with rotation: the placeholder is now as wide as the
window or the image, whichever is wider, and the "paper" is centered
within; thus there's always room to rotate it.

There's still some problem with setting contentY in goToPage() after
the page has been zoomed to a size larger than the window: the values
look correct, but it scrolls too far.

But on the plus side, horizontal scrolling works.  So now we attempt to
control the horizontal position too: NavigationStack tracks it, and can
go back to a previous position; and links can in theory jump to specific
positions and zoom levels, scrolling horizontally such that a specific x
coordinate is visible.

Includes minor UI tweaks to make it look better on iOS.

Change-Id: I643d8ef48ef815aeb49cae77dcb84c3682563d56
Reviewed-by: default avatarShawn Rutledge <shawn.rutledge@qt.io>
Showing with 283 additions and 168 deletions
......@@ -249,6 +249,7 @@ ApplicationWindow {
y: root.header.height
height: view.height
dim: false
clip: true
ListView {
id: searchResultsList
anchors.fill: parent
......@@ -286,7 +287,7 @@ ApplicationWindow {
TextField {
id: searchField
placeholderText: "search"
Layout.minimumWidth: 200
Layout.minimumWidth: 150
Layout.fillWidth: true
onAccepted: searchDrawer.open()
Image {
......@@ -316,11 +317,10 @@ ApplicationWindow {
}
Label {
id: statusLabel
Layout.fillWidth: true
property size implicitPointSize: document.pagePointSize(view.currentPage)
text: "page " + (currentPageSB.value) + " of " + document.pageCount +
" scale " + view.renderScale.toFixed(2) +
" original size " + implicitPointSize.width.toFixed(1) + "x" + implicitPointSize.height.toFixed(1) + " pt"
" original " + implicitPointSize.width.toFixed(1) + "x" + implicitPointSize.height.toFixed(1) + " pt"
visible: document.pageCount > 0
}
}
......
This diff is collapsed.
......@@ -90,6 +90,7 @@ void QQuickPdfDocument::setSource(QUrl source)
return;
m_source = source;
m_maxPageWidthHeight = QSizeF();
emit sourceChanged();
if (source.scheme() == QLatin1String("qrc"))
m_doc.load(QLatin1Char(':') + source.path());
......@@ -172,6 +173,71 @@ QSizeF QQuickPdfDocument::pagePointSize(int page) const
return m_doc.pageSize(page);
}
qreal QQuickPdfDocument::maxPageWidth() const
{
const_cast<QQuickPdfDocument *>(this)->updateMaxPageSize();
return m_maxPageWidthHeight.width();
}
qreal QQuickPdfDocument::maxPageHeight() const
{
const_cast<QQuickPdfDocument *>(this)->updateMaxPageSize();
return m_maxPageWidthHeight.height();
}
/*!
\internal
\qmlmethod size PdfDocument::heightSumBeforePage(int page)
Returns the sum of the heights, in points, of all sets of \a facingPages
pages from 0 to the given \a page, exclusive.
That is, if the pages were laid out end-to-end in adjacent sets of
\a facingPages, what would be the distance in points from the top of the
first page to the top of the given page.
*/
// Workaround for lack of something analogous to ListView.positionViewAtIndex() in TableView
qreal QQuickPdfDocument::heightSumBeforePage(int page, qreal spacing, int facingPages) const
{
qreal ret = 0;
for (int i = 0; i < page; i+= facingPages) {
if (i + facingPages > page)
break;
qreal facingPagesHeight = 0;
for (int j = i; j < i + facingPages; ++j)
facingPagesHeight = qMax(facingPagesHeight, pagePointSize(j).height());
ret += facingPagesHeight + spacing;
}
return ret;
}
void QQuickPdfDocument::updateMaxPageSize()
{
if (m_maxPageWidthHeight.isValid())
return;
qreal w = 0;
qreal h = 0;
const int count = pageCount();
for (int i = 0; i < count; ++i) {
auto size = pagePointSize(i);
w = qMax(w, size.width());
h = qMax(w, size.height());
}
m_maxPageWidthHeight = QSizeF(w, h);
}
/*!
\qmlproperty real PdfDocument::maxPageWidth
This property holds the width of the widest page in the document, in points.
*/
/*!
\qmlproperty real PdfDocument::maxPageHeight
This property holds the height of the tallest page in the document, in points.
*/
/*!
\qmlproperty string PdfDocument::title
......
......@@ -62,6 +62,8 @@ class QQuickPdfDocument : public QObject, public QQmlParserStatus
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL)
Q_PROPERTY(qreal maxPageWidth READ maxPageWidth NOTIFY metaDataChanged)
Q_PROPERTY(qreal maxPageHeight READ maxPageHeight NOTIFY metaDataChanged)
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)
......@@ -102,6 +104,9 @@ public:
QDateTime modificationDate() { return m_doc.metaData(QPdfDocument::ModificationDate).toDateTime(); }
Q_INVOKABLE QSizeF pagePointSize(int page) const;
qreal maxPageWidth() const;
qreal maxPageHeight() const;
Q_INVOKABLE qreal heightSumBeforePage(int page, qreal spacing = 0, int facingPages = 1) const;
Q_SIGNALS:
void sourceChanged();
......@@ -113,10 +118,12 @@ Q_SIGNALS:
private:
QPdfDocument &document() { return m_doc; }
void updateMaxPageSize();
private:
QUrl m_source;
QPdfDocument m_doc;
QSizeF m_maxPageWidthHeight;
friend class QQuickPdfLinkModel;
friend class QQuickPdfSearchModel;
......
......@@ -80,11 +80,11 @@ void QQuickPdfNavigationStack::forward()
++m_currentHistoryIndex;
m_changing = true;
emit jumped(currentPage(), currentLocation(), currentZoom());
if (currentZoomWas != currentZoom())
emit currentZoomChanged();
emit currentPageChanged();
if (currentLocationWas != currentLocation())
emit currentLocationChanged();
if (currentZoomWas != currentZoom())
emit currentZoomChanged();
if (!backAvailableWas)
emit backAvailableChanged();
if (forwardAvailableWas != forwardAvailable())
......@@ -110,11 +110,11 @@ void QQuickPdfNavigationStack::back()
--m_currentHistoryIndex;
m_changing = true;
emit jumped(currentPage(), currentLocation(), currentZoom());
if (currentZoomWas != currentZoom())
emit currentZoomChanged();
emit currentPageChanged();
if (currentLocationWas != currentLocation())
emit currentLocationChanged();
if (currentZoomWas != currentZoom())
emit currentZoomChanged();
if (backAvailableWas != backAvailable())
emit backAvailableChanged();
if (!forwardAvailableWas)
......@@ -183,15 +183,16 @@ void QQuickPdfNavigationStack::push(int page, QPointF location, qreal zoom)
m_pageHistory.append(QExplicitlySharedDataPointer<QPdfDestinationPrivate>(new QPdfDestinationPrivate(page, location, zoom)));
m_currentHistoryIndex = m_pageHistory.count() - 1;
}
emit currentZoomChanged();
emit currentPageChanged();
emit currentLocationChanged();
emit currentZoomChanged();
if (m_changing)
return;
if (!backAvailableWas)
emit backAvailableChanged();
if (forwardAvailableWas)
emit forwardAvailableChanged();
emit jumped(page, location, zoom);
qCDebug(qLcNav) << "push: index" << m_currentHistoryIndex << "page" << page
<< "@" << location << "zoom" << zoom << "-> history" <<
[this]() {
......@@ -212,7 +213,7 @@ void QQuickPdfNavigationStack::push(int page, QPointF location, qreal zoom)
the most-recently-viewed destination rather than the destination that was
last specified by push().
The \c currentPageChanged, \c currentLocationChanged and \c currentZoomChanged
The \c currentZoomChanged, \c currentPageChanged and \c currentLocationChanged
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.
......@@ -229,12 +230,12 @@ void QQuickPdfNavigationStack::update(int page, QPointF location, qreal zoom)
m_pageHistory[m_currentHistoryIndex]->page = page;
m_pageHistory[m_currentHistoryIndex]->location = location;
m_pageHistory[m_currentHistoryIndex]->zoom = zoom;
if (currentZoomWas != zoom)
emit currentZoomChanged();
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]() {
......@@ -258,10 +259,8 @@ bool QQuickPdfNavigationStack::forwardAvailable() const
/*!
\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 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.
This signal is emitted when forward(), back() or push() is called, but not
when update() is called.
*/
QT_END_NAMESPACE
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment