diff options
Diffstat (limited to 'src/pdfwidgets/qpdfview.cpp')
-rw-r--r-- | src/pdfwidgets/qpdfview.cpp | 412 |
1 files changed, 316 insertions, 96 deletions
diff --git a/src/pdfwidgets/qpdfview.cpp b/src/pdfwidgets/qpdfview.cpp index 35e368633..a67667fed 100644 --- a/src/pdfwidgets/qpdfview.cpp +++ b/src/pdfwidgets/qpdfview.cpp @@ -1,38 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> -** 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$ -** -****************************************************************************/ +// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com> +// 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 #include "qpdfview.h" #include "qpdfview_p.h" @@ -40,21 +8,31 @@ #include "qpdfpagerenderer.h" #include <QGuiApplication> +#include <QLoggingCategory> +#include <QPainter> +#include <QPaintEvent> #include <QPdfDocument> -#include <QPdfPageNavigation> +#include <QPdfPageNavigator> +#include <QPdfSearchModel> #include <QScreen> #include <QScrollBar> -#include <QScroller> QT_BEGIN_NAMESPACE -QPdfViewPrivate::QPdfViewPrivate() - : QAbstractScrollAreaPrivate() +Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links") +//#define DEBUG_LINKS + +static const QColor SearchResultHighlight("#80B0C4DE"); +static const QColor CurrentSearchResultHighlight(Qt::cyan); +static const int CurrentSearchResultWidth(2); + +QPdfViewPrivate::QPdfViewPrivate(QPdfView *q) + : q_ptr(q) , m_document(nullptr) - , m_pageNavigation(nullptr) + , m_pageNavigator(nullptr) , m_pageRenderer(nullptr) - , m_pageMode(QPdfView::SinglePage) - , m_zoomMode(QPdfView::CustomZoom) + , m_pageMode(QPdfView::PageMode::SinglePage) + , m_zoomMode(QPdfView::ZoomMode::Custom) , m_zoomFactor(1.0) , m_pageSpacing(3) , m_documentMargins(6, 6, 6, 6) @@ -68,7 +46,7 @@ void QPdfViewPrivate::init() { Q_Q(QPdfView); - m_pageNavigation = new QPdfPageNavigation(q); + m_pageNavigator = new QPdfPageNavigator(q); m_pageRenderer = new QPdfPageRenderer(q); m_pageRenderer->setRenderMode(QPdfPageRenderer::RenderMode::MultiThreaded); } @@ -88,7 +66,7 @@ void QPdfViewPrivate::currentPageChanged(int currentPage) q->verticalScrollBar()->setValue(yPositionForPage(currentPage)); - if (m_pageMode == QPdfView::SinglePage) + if (m_pageMode == QPdfView::PageMode::SinglePage) invalidateDocumentLayout(); } @@ -116,29 +94,31 @@ void QPdfViewPrivate::setViewport(QRect viewport) if (oldSize != m_viewport.size()) { updateDocumentLayout(); - if (m_zoomMode != QPdfView::CustomZoom) { + if (m_zoomMode != QPdfView::ZoomMode::Custom) { invalidatePageCache(); } } - if (m_pageMode == QPdfView::MultiPage) { + if (m_pageMode == QPdfView::PageMode::MultiPage) { // An imaginary, 2px height line at the upper half of the viewport, which is used to // determine which page is currently located there -> we propagate that as 'current' page - // to the QPdfPageNavigation object + // to the QPdfPageNavigator object const QRect currentPageLine(m_viewport.x(), m_viewport.y() + m_viewport.height() * 0.4, m_viewport.width(), 2); int currentPage = 0; - for (auto it = m_documentLayout.pageGeometries.cbegin(); it != m_documentLayout.pageGeometries.cend(); ++it) { - const QRect pageGeometry = it.value(); + for (auto it = m_documentLayout.pageGeometryAndScale.cbegin(); + it != m_documentLayout.pageGeometryAndScale.cend(); ++it) { + const QRect pageGeometry = it.value().first; if (pageGeometry.intersects(currentPageLine)) { currentPage = it.key(); break; } } - if (currentPage != m_pageNavigation->currentPage()) { + if (currentPage != m_pageNavigator->currentPage()) { m_blockPageScrolling = true; - m_pageNavigation->setCurrentPage(currentPage); + // ΤODO give location on the page + m_pageNavigator->jump(currentPage, {}, m_zoomFactor); m_blockPageScrolling = false; } } @@ -161,11 +141,11 @@ void QPdfViewPrivate::pageRendered(int pageNumber, QSize imageSize, const QImage { Q_Q(QPdfView); - Q_UNUSED(imageSize) - Q_UNUSED(requestId) + Q_UNUSED(imageSize); + Q_UNUSED(requestId); if (!m_cachedPagesLRU.contains(pageNumber)) { - if (m_cachedPagesLRU.length() > m_pageCacheLimit) + if (m_cachedPagesLRU.size() > m_pageCacheLimit) m_pageCache.remove(m_cachedPagesLRU.takeFirst()); m_cachedPagesLRU.append(pageNumber); @@ -200,37 +180,43 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const DocumentLayout documentLayout; - if (!m_document || m_document->status() != QPdfDocument::Ready) + if (!m_document || m_document->status() != QPdfDocument::Status::Ready) return documentLayout; - QHash<int, QRect> pageGeometries; + QHash<int, QPair<QRect, qreal>> pageGeometryAndScale; const int pageCount = m_document->pageCount(); int totalWidth = 0; - const int startPage = (m_pageMode == QPdfView::SinglePage ? m_pageNavigation->currentPage() : 0); - const int endPage = (m_pageMode == QPdfView::SinglePage ? m_pageNavigation->currentPage() + 1 : pageCount); + const int startPage = (m_pageMode == QPdfView::PageMode::SinglePage ? m_pageNavigator->currentPage() : 0); + const int endPage = (m_pageMode == QPdfView::PageMode::SinglePage ? m_pageNavigator->currentPage() + 1 : pageCount); // calculate page sizes for (int page = startPage; page < endPage; ++page) { QSize pageSize; - if (m_zoomMode == QPdfView::CustomZoom) { - pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution * m_zoomFactor).toSize(); - } else if (m_zoomMode == QPdfView::FitToWidth) { - pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution).toSize(); - const qreal factor = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) / qreal(pageSize.width())); - pageSize *= factor; - } else if (m_zoomMode == QPdfView::FitInView) { - const QSize viewportSize(m_viewport.size() + QSize(-m_documentMargins.left() - m_documentMargins.right(), -m_pageSpacing)); - - pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution).toSize(); - pageSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio); + qreal pageScale = m_zoomFactor; + if (m_zoomMode == QPdfView::ZoomMode::Custom) { + pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution * m_zoomFactor).toSize(); + } else if (m_zoomMode == QPdfView::ZoomMode::FitToWidth) { + pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution).toSize(); + pageScale = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) / + qreal(pageSize.width())); + pageSize *= pageScale; + } else if (m_zoomMode == QPdfView::ZoomMode::FitInView) { + const QSize viewportSize(m_viewport.size() + + QSize(-m_documentMargins.left() - m_documentMargins.right(), -m_pageSpacing)); + + pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution).toSize(); + QSize scaledSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio); + // because of KeepAspectRatio, the ratio of widths should be the same as the ratio of heights + pageScale = qreal(scaledSize.width()) / qreal(pageSize.width()); + pageSize = scaledSize; } totalWidth = qMax(totalWidth, pageSize.width()); - pageGeometries[page] = QRect(QPoint(0, 0), pageSize); + pageGeometryAndScale[page] = {QRect(QPoint(0, 0), pageSize), pageScale}; } totalWidth += m_documentMargins.left() + m_documentMargins.right(); @@ -239,19 +225,19 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const // calculate page positions for (int page = startPage; page < endPage; ++page) { - const QSize pageSize = pageGeometries[page].size(); + const QSize pageSize = pageGeometryAndScale[page].first.size(); // center horizontal inside the viewport const int pageX = (qMax(totalWidth, m_viewport.width()) - pageSize.width()) / 2; - pageGeometries[page].moveTopLeft(QPoint(pageX, pageY)); + pageGeometryAndScale[page].first.moveTopLeft(QPoint(pageX, pageY)); pageY += pageSize.height() + m_pageSpacing; } pageY += m_documentMargins.bottom(); - documentLayout.pageGeometries = pageGeometries; + documentLayout.pageGeometryAndScale = pageGeometryAndScale; // calculate overall document size documentLayout.documentSize = QSize(totalWidth, pageY); @@ -261,11 +247,26 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const qreal QPdfViewPrivate::yPositionForPage(int pageNumber) const { - const auto it = m_documentLayout.pageGeometries.constFind(pageNumber); - if (it == m_documentLayout.pageGeometries.cend()) + const auto it = m_documentLayout.pageGeometryAndScale.constFind(pageNumber); + if (it == m_documentLayout.pageGeometryAndScale.cend()) return 0.0; - return (*it).y(); + return (*it).first.y(); +} + +QTransform QPdfViewPrivate::screenScaleTransform(int page) const +{ + qreal scale = m_screenResolution * m_zoomFactor; + switch (m_zoomMode) { + case QPdfView::ZoomMode::FitToWidth: + case QPdfView::ZoomMode::FitInView: + scale = m_screenResolution * m_documentLayout.pageGeometryAndScale[page].second; + break; + default: + break; + } + + return QTransform::fromScale(scale, scale); } void QPdfViewPrivate::updateDocumentLayout() @@ -275,39 +276,55 @@ void QPdfViewPrivate::updateDocumentLayout() updateScrollBars(); } +/*! + \class QPdfView + \inmodule QtPdf + \brief A PDF viewer widget. + + QPdfView is a PDF viewer widget that offers a user experience similar to + many common PDF viewer applications, with two \l {pageMode}{modes}. + In the \c MultiPage mode, it supports flicking through the pages in the + entire document, with narrow gaps between the page images. + In the \c SinglePage mode, it shows one page at a time. +*/ +/*! + Constructs a PDF viewer with parent widget \a parent. +*/ QPdfView::QPdfView(QWidget *parent) - : QAbstractScrollArea(*new QPdfViewPrivate(), parent) + : QAbstractScrollArea(parent) + , d_ptr(new QPdfViewPrivate(this)) { Q_D(QPdfView); d->init(); - connect(d->m_pageNavigation, &QPdfPageNavigation::currentPageChanged, this, [d](int page){ d->currentPageChanged(page); }); + connect(d->m_pageNavigator, &QPdfPageNavigator::currentPageChanged, this, + [d](int page){ d->currentPageChanged(page); }); - connect(d->m_pageRenderer, &QPdfPageRenderer::pageRendered, - this, [d](int pageNumber, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions, quint64 requestId){ d->pageRendered(pageNumber, imageSize, image, requestId); }); + connect(d->m_pageRenderer, &QPdfPageRenderer::pageRendered, this, + [d](int pageNumber, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions, quint64 requestId) { + d->pageRendered(pageNumber, imageSize, image, requestId); }); verticalScrollBar()->setSingleStep(20); horizontalScrollBar()->setSingleStep(20); - QScroller::grabGesture(this); - + setMouseTracking(true); d->calculateViewport(); } /*! - \internal + Destroys the PDF viewer. */ -QPdfView::QPdfView(QPdfViewPrivate &dd, QWidget *parent) - : QAbstractScrollArea(dd, parent) -{ -} - QPdfView::~QPdfView() { } +/*! + \property QPdfView::document + + This property holds the document to be viewed. +*/ void QPdfView::setDocument(QPdfDocument *document) { Q_D(QPdfView); @@ -322,10 +339,12 @@ void QPdfView::setDocument(QPdfDocument *document) emit documentChanged(d->m_document); if (d->m_document) - d->m_documentStatusChangedConnection = connect(d->m_document.data(), &QPdfDocument::statusChanged, this, [d](){ d->documentStatusChanged(); }); + d->m_documentStatusChangedConnection = + connect(d->m_document.data(), &QPdfDocument::statusChanged, this, + [d](){ d->documentStatusChanged(); }); - d->m_pageNavigation->setDocument(d->m_document); d->m_pageRenderer->setDocument(d->m_document); + d->m_linkModel.setDocument(d->m_document); d->documentStatusChanged(); } @@ -337,13 +356,94 @@ QPdfDocument *QPdfView::document() const return d->m_document; } -QPdfPageNavigation *QPdfView::pageNavigation() const +/*! + \since 6.6 + \property QPdfView::searchModel + + If this property is set, QPdfView draws highlight rectangles over the + search results provided by \l QPdfSearchModel::resultsOnPage(). By default + it is \c nullptr. +*/ +void QPdfView::setSearchModel(QPdfSearchModel *searchModel) +{ + Q_D(QPdfView); + if (d->m_searchModel == searchModel) + return; + + if (d->m_searchModel) + d->m_searchModel->disconnect(this); + + d->m_searchModel = searchModel; + emit searchModelChanged(searchModel); + + if (searchModel) { + connect(searchModel, &QPdfSearchModel::dataChanged, this, + [this](const QModelIndex &, const QModelIndex &, const QList<int> &) { update(); }); + } + setCurrentSearchResultIndex(-1); +} + +QPdfSearchModel *QPdfView::searchModel() const +{ + Q_D(const QPdfView); + return d->m_searchModel; +} + +/*! + \since 6.6 + \property QPdfView::currentSearchResultIndex + + If this property is set to a positive number, and \l searchModel is set, + QPdfView draws a frame around the search result provided by + \l QPdfSearchModel at the given index. For example, if QPdfSearchModel is + used as the model for a QListView, you can keep this property updated by + connecting QItemSelectionModel::currentChanged() from + QListView::selectionModel() to a function that will in turn call this function. + + By default it is \c -1, so that no search results are framed. +*/ +void QPdfView::setCurrentSearchResultIndex(int currentResult) +{ + Q_D(QPdfView); + if (d->m_currentSearchResultIndex == currentResult) + return; + + d->m_currentSearchResultIndex = currentResult; + emit currentSearchResultIndexChanged(currentResult); + viewport()->update(); //update(); +} + +int QPdfView::currentSearchResultIndex() const +{ + Q_D(const QPdfView); + return d->m_currentSearchResultIndex; +} + +/*! + This accessor returns the navigation stack that will handle back/forward navigation. +*/ +QPdfPageNavigator *QPdfView::pageNavigator() const { Q_D(const QPdfView); - return d->m_pageNavigation; + return d->m_pageNavigator; } +/*! + \enum QPdfView::PageMode + + This enum describes the overall behavior of the PDF viewer: + + \value SinglePage Show one page at a time. + \value MultiPage Allow scrolling through all pages in the document. +*/ + +/*! + \property QPdfView::pageMode + + This property holds whether to show one page at a time, or all pages in the + document. The default is \c SinglePage. +*/ QPdfView::PageMode QPdfView::pageMode() const { Q_D(const QPdfView); @@ -364,6 +464,24 @@ void QPdfView::setPageMode(PageMode mode) emit pageModeChanged(d->m_pageMode); } +/*! + \enum QPdfView::ZoomMode + + This enum describes the magnification behavior of the PDF viewer: + + \value Custom Use \l zoomFactor only. + \value FitToWidth Automatically choose a zoom factor so that + the width of the page fits in the view. + \value FitInView Automatically choose a zoom factor so that + the entire page fits in the view. +*/ + +/*! + \property QPdfView::zoomMode + + This property indicates whether to use a custom size for the page(s), + or zoom them to fit to the view. The default is \c CustomZoom. +*/ QPdfView::ZoomMode QPdfView::zoomMode() const { Q_D(const QPdfView); @@ -384,6 +502,12 @@ void QPdfView::setZoomMode(ZoomMode mode) emit zoomModeChanged(d->m_zoomMode); } +/*! + \property QPdfView::zoomFactor + + 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. +*/ qreal QPdfView::zoomFactor() const { Q_D(const QPdfView); @@ -404,6 +528,12 @@ void QPdfView::setZoomFactor(qreal factor) emit zoomFactorChanged(d->m_zoomFactor); } +/*! + \property QPdfView::pageSpacing + + This property holds the size of the padding between pages in the \l MultiPage + \l {pageMode}{mode}. +*/ int QPdfView::pageSpacing() const { Q_D(const QPdfView); @@ -424,6 +554,11 @@ void QPdfView::setPageSpacing(int spacing) emit pageSpacingChanged(d->m_pageSpacing); } +/*! + \property QPdfView::documentMargins + + This property holds the margins around the page view. +*/ QMargins QPdfView::documentMargins() const { Q_D(const QPdfView); @@ -452,8 +587,9 @@ void QPdfView::paintEvent(QPaintEvent *event) painter.fillRect(event->rect(), palette().brush(QPalette::Dark)); painter.translate(-d->m_viewport.x(), -d->m_viewport.y()); - for (auto it = d->m_documentLayout.pageGeometries.cbegin(); it != d->m_documentLayout.pageGeometries.cend(); ++it) { - const QRect pageGeometry = it.value(); + for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin(); + it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) { + const QRect pageGeometry = it.value().first; if (pageGeometry.intersects(d->m_viewport)) { // page needs to be painted painter.fillRect(pageGeometry, Qt::white); @@ -461,9 +597,47 @@ void QPdfView::paintEvent(QPaintEvent *event) const auto pageIt = d->m_pageCache.constFind(page); if (pageIt != d->m_pageCache.cend()) { const QImage &img = pageIt.value(); - painter.drawImage(pageGeometry.topLeft(), img); + painter.drawImage(pageGeometry, img); } else { - d->m_pageRenderer->requestPage(page, pageGeometry.size()); + d->m_pageRenderer->requestPage(page, pageGeometry.size() * devicePixelRatioF()); + } + + const QTransform scaleTransform = d->screenScaleTransform(page); +#ifdef DEBUG_LINKS + const QString fmt = u"page %1 @ %2, %3"_s; + d->m_linkModel.setPage(page); + const int linkCount = d->m_linkModel.rowCount({}); + for (int i = 0; i < linkCount; ++i) { + const QRectF linkBounds = scaleTransform.mapRect( + d->m_linkModel.data(d->m_linkModel.index(i), + int(QPdfLinkModel::Role::Rect)).toRectF()) + .translated(pageGeometry.topLeft()); + painter.setPen(Qt::blue); + painter.drawRect(linkBounds); + painter.setPen(Qt::red); + const QPoint loc = d->m_linkModel.data(d->m_linkModel.index(i), + int(QPdfLinkModel::Role::Location)).toPoint(); + // TODO maybe draw destination URL if that's what it is + painter.drawText(linkBounds.bottomLeft() + QPoint(2, -2), + fmt.arg(d->m_linkModel.data(d->m_linkModel.index(i), + int(QPdfLinkModel::Role::Page)).toInt()) + .arg(loc.x()).arg(loc.y())); + } +#endif + if (d->m_searchModel) { + for (const QPdfLink &result : d->m_searchModel->resultsOnPage(page)) { + for (const QRectF &rect : result.rectangles()) + painter.fillRect(scaleTransform.mapRect(rect).translated(pageGeometry.topLeft()), SearchResultHighlight); + } + + if (d->m_currentSearchResultIndex >= 0 && d->m_currentSearchResultIndex < d->m_searchModel->rowCount({})) { + const QPdfLink &cur = d->m_searchModel->resultAtIndex(d->m_currentSearchResultIndex); + if (cur.page() == page) { + painter.setPen({CurrentSearchResultHighlight, CurrentSearchResultWidth}); + for (const auto &rect : cur.rectangles()) + painter.drawRect(scaleTransform.mapRect(rect).translated(pageGeometry.topLeft())); + } + } } } } @@ -488,6 +662,52 @@ void QPdfView::scrollContentsBy(int dx, int dy) d->calculateViewport(); } +void QPdfView::mousePressEvent(QMouseEvent *event) +{ + Q_ASSERT(event->isAccepted()); +} + +void QPdfView::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QPdfView); + for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin(); + it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) { + const int page = it.key(); + const QTransform screenInvTransform = d->screenScaleTransform(page).inverted(); + const QRect pageGeometry = it.value().first; + if (pageGeometry.contains(event->position().toPoint())) { + const QPointF posInPoints = screenInvTransform.map(event->position() - pageGeometry.topLeft()); + d->m_linkModel.setPage(page); + auto dest = d->m_linkModel.linkAt(posInPoints); + setCursor(dest.isValid() ? Qt::PointingHandCursor : Qt::ArrowCursor); + if (dest.isValid()) + qCDebug(qLcLink) << event->position() << ":" << posInPoints << "pt ->" << dest; + } + } +} + +void QPdfView::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QPdfView); + for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin(); + it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) { + const int page = it.key(); + const QTransform screenInvTransform = d->screenScaleTransform(page).inverted(); + const QRect pageGeometry = it.value().first; + if (pageGeometry.contains(event->position().toPoint())) { + const QPointF posInPoints = screenInvTransform.map(event->position() - pageGeometry.topLeft()); + d->m_linkModel.setPage(page); + auto dest = d->m_linkModel.linkAt(posInPoints); + if (dest.isValid()) { + qCDebug(qLcLink) << event << ": jumping to" << dest; + d->m_pageNavigator->jump(dest.page(), dest.location(), dest.zoom()); + // TODO scroll and zoom to where the link tells us to + } + return; + } + } +} + QT_END_NAMESPACE #include "moc_qpdfview.cpp" |