Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpdfview.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
2// Copyright (C) 2022 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qpdfview.h"
6#include "qpdfview_p.h"
8#include <QtPdf/private/qtpdfglobal_p.h>
9
10#include <QGuiApplication>
11#include <QLoggingCategory>
12#include <QPainter>
13#include <QPaintEvent>
14#include <QPdfDocument>
15#include <QPdfPageNavigator>
16#include <QPdfSearchModel>
17#include <QScreen>
18#include <QScrollBar>
19
21
22Q_PDF_LOGGING_CATEGORY(qLcWLink, "qt.pdf.widgets.links")
23//#define DEBUG_LINKS
24
25static const QColor SearchResultHighlight("#80B0C4DE");
27static const int CurrentSearchResultWidth(2);
28
29QPdfViewPrivate::QPdfViewPrivate(QPdfView *q)
30 : q_ptr(q)
31 , m_document(nullptr)
32 , m_pageNavigator(nullptr)
33 , m_pageRenderer(nullptr)
34 , m_pageMode(QPdfView::PageMode::SinglePage)
35 , m_zoomMode(QPdfView::ZoomMode::Custom)
36 , m_zoomFactor(1.0)
37 , m_pageSpacing(3)
38 , m_documentMargins(6, 6, 6, 6)
41 , m_screenResolution(QGuiApplication::primaryScreen()->logicalDotsPerInch() / 72.0)
42{
43}
44
46{
47 Q_Q(QPdfView);
48
49 m_pageNavigator = new QPdfPageNavigator(q);
50 m_pageRenderer = new QPdfPageRenderer(q);
51 m_pageRenderer->setRenderMode(QPdfPageRenderer::RenderMode::MultiThreaded);
52}
53
54void QPdfViewPrivate::documentStatusChanged(QPdfDocument::Status status)
55{
56 if (status == QPdfDocument::Status::Ready)
59}
60
61void QPdfViewPrivate::currentPageChanged(int currentPage)
62{
63 Q_Q(QPdfView);
64
66 return;
67
68 q->verticalScrollBar()->setValue(yPositionForPage(currentPage));
69
70 if (m_pageMode == QPdfView::PageMode::SinglePage)
72}
73
75{
76 Q_Q(QPdfView);
77
78 const int x = q->horizontalScrollBar()->value();
79 const int y = q->verticalScrollBar()->value();
80 const int width = q->viewport()->width();
81 const int height = q->viewport()->height();
82
83 setViewport(QRect(x, y, width, height));
84}
85
86void QPdfViewPrivate::setViewport(QRect viewport)
87{
88 if (m_viewport == viewport)
89 return;
90
91 const QSize oldSize = m_viewport.size();
92
93 m_viewport = viewport;
94
95 if (oldSize != m_viewport.size()) {
97
98 if (m_zoomMode != QPdfView::ZoomMode::Custom) {
100 }
101 }
102
103 if (m_pageMode == QPdfView::PageMode::MultiPage) {
104 // An imaginary, 2px height line at the upper half of the viewport, which is used to
105 // determine which page is currently located there -> we propagate that as 'current' page
106 // to the QPdfPageNavigator object
107 const QRect currentPageLine(m_viewport.x(), m_viewport.y() + m_viewport.height() * 0.4, m_viewport.width(), 2);
108
109 int currentPage = 0;
110 for (auto it = m_documentLayout.pageGeometryAndScale.cbegin();
111 it != m_documentLayout.pageGeometryAndScale.cend(); ++it) {
112 const QRect pageGeometry = it.value().first;
113 if (pageGeometry.intersects(currentPageLine)) {
114 currentPage = it.key();
115 break;
116 }
117 }
118
119 if (currentPage != m_pageNavigator->currentPage()) {
121 // ΤODO give location on the page
122 m_pageNavigator->jump(currentPage, {}, m_zoomFactor);
123 m_blockPageScrolling = false;
124 }
125 }
126}
127
129{
130 Q_Q(QPdfView);
131
132 const QSize p = q->viewport()->size();
133 const QSize v = m_documentLayout.documentSize;
134
135 q->horizontalScrollBar()->setRange(0, v.width() - p.width());
136 q->horizontalScrollBar()->setPageStep(p.width());
137 q->verticalScrollBar()->setRange(0, v.height() - p.height());
138 q->verticalScrollBar()->setPageStep(p.height());
139}
140
141void QPdfViewPrivate::pageRendered(int pageNumber, QSize imageSize, const QImage &image, quint64 requestId)
142{
143 Q_Q(QPdfView);
144
145 Q_UNUSED(imageSize);
146 Q_UNUSED(requestId);
147
148 if (!m_cachedPagesLRU.contains(pageNumber)) {
149 if (m_cachedPagesLRU.size() > m_pageCacheLimit)
150 m_pageCache.remove(m_cachedPagesLRU.takeFirst());
151
152 m_cachedPagesLRU.append(pageNumber);
153 }
154
155 m_pageCache.insert(pageNumber, image);
156
157 q->viewport()->update();
158}
159
165
167{
168 Q_Q(QPdfView);
169
170 m_pageCache.clear();
171 q->viewport()->update();
172}
173
175{
176 // The DocumentLayout describes a virtual layout where all pages are positioned inside
177 // - For SinglePage mode, this is just an area as large as the current page surrounded
178 // by the m_documentMargins.
179 // - For MultiPage mode, this is the area that is covered by all pages which are placed
180 // below each other, with m_pageSpacing inbetween and surrounded by m_documentMargins
181
182 DocumentLayout documentLayout;
183
184 if (!m_document || m_document->status() != QPdfDocument::Status::Ready)
185 return documentLayout;
186
187 QHash<int, QPair<QRect, qreal>> pageGeometryAndScale;
188
189 const int pageCount = m_document->pageCount();
190
191 int totalWidth = 0;
192
193 const int startPage = (m_pageMode == QPdfView::PageMode::SinglePage ? m_pageNavigator->currentPage() : 0);
194 const int endPage = (m_pageMode == QPdfView::PageMode::SinglePage ? m_pageNavigator->currentPage() + 1 : pageCount);
195
196 // calculate page sizes
197 for (int page = startPage; page < endPage; ++page) {
198 QSize pageSize;
199 qreal pageScale = m_zoomFactor;
200 if (m_zoomMode == QPdfView::ZoomMode::Custom) {
201 pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution * m_zoomFactor).toSize();
202 } else if (m_zoomMode == QPdfView::ZoomMode::FitToWidth) {
203 pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution).toSize();
204 pageScale = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) /
205 qreal(pageSize.width()));
206 pageSize *= pageScale;
207 } else if (m_zoomMode == QPdfView::ZoomMode::FitInView) {
208 const QSize viewportSize(m_viewport.size() +
209 QSize(-m_documentMargins.left() - m_documentMargins.right(), -m_pageSpacing));
210
211 pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution).toSize();
212 QSize scaledSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio);
213 // because of KeepAspectRatio, the ratio of widths should be the same as the ratio of heights
214 pageScale = qreal(scaledSize.width()) / qreal(pageSize.width());
215 pageSize = scaledSize;
216 }
217
218 totalWidth = qMax(totalWidth, pageSize.width());
219
220 pageGeometryAndScale[page] = {QRect(QPoint(0, 0), pageSize), pageScale};
221 }
222
223 totalWidth += m_documentMargins.left() + m_documentMargins.right();
224
225 int pageY = m_documentMargins.top();
226
227 // calculate page positions
228 for (int page = startPage; page < endPage; ++page) {
229 const QSize pageSize = pageGeometryAndScale[page].first.size();
230
231 // center horizontal inside the viewport
232 const int pageX = (qMax(totalWidth, m_viewport.width()) - pageSize.width()) / 2;
233
234 pageGeometryAndScale[page].first.moveTopLeft(QPoint(pageX, pageY));
235
236 pageY += pageSize.height() + m_pageSpacing;
237 }
238
239 pageY += m_documentMargins.bottom();
240
241 documentLayout.pageGeometryAndScale = pageGeometryAndScale;
242
243 // calculate overall document size
244 documentLayout.documentSize = QSize(totalWidth, pageY);
245
246 return documentLayout;
247}
248
250{
251 const auto it = m_documentLayout.pageGeometryAndScale.constFind(pageNumber);
252 if (it == m_documentLayout.pageGeometryAndScale.cend())
253 return 0.0;
254
255 return (*it).first.y();
256}
257
259{
260 qreal scale = m_screenResolution * m_zoomFactor;
261 switch (m_zoomMode) {
262 case QPdfView::ZoomMode::FitToWidth:
263 case QPdfView::ZoomMode::FitInView:
264 scale = m_screenResolution * m_documentLayout.pageGeometryAndScale[page].second;
265 break;
266 default:
267 break;
268 }
269
270 return QTransform::fromScale(scale, scale);
271}
272
274{
275 m_documentLayout = calculateDocumentLayout();
276
278}
279
280/*!
281 \class QPdfView
282 \inmodule QtPdf
283 \brief A PDF viewer widget.
284
285 QPdfView is a PDF viewer widget that offers a user experience similar to
286 many common PDF viewer applications, with two \l {pageMode}{modes}.
287 In the \c MultiPage mode, it supports flicking through the pages in the
288 entire document, with narrow gaps between the page images.
289 In the \c SinglePage mode, it shows one page at a time.
290*/
291
292/*!
293 Constructs a PDF viewer with parent widget \a parent.
294*/
295QPdfView::QPdfView(QWidget *parent)
296 : QAbstractScrollArea(parent)
297 , d_ptr(new QPdfViewPrivate(this))
298{
299 Q_D(QPdfView);
300
301 d->init();
302
303 connect(d->m_pageNavigator, &QPdfPageNavigator::currentPageChanged, this,
304 [d](int page){ d->currentPageChanged(page); });
305
306 connect(d->m_pageRenderer, &QPdfPageRenderer::pageRendered, this,
307 [d](int pageNumber, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions, quint64 requestId) {
308 d->pageRendered(pageNumber, imageSize, image, requestId); });
309
310 verticalScrollBar()->setSingleStep(20);
311 horizontalScrollBar()->setSingleStep(20);
312
313 setMouseTracking(true);
314 d->calculateViewport();
315}
316
317/*!
318 Destroys the PDF viewer.
319*/
320QPdfView::~QPdfView()
321{
322}
323
324/*!
325 \property QPdfView::document
326
327 This property holds the document to be viewed.
328*/
329void QPdfView::setDocument(QPdfDocument *document)
330{
331 Q_D(QPdfView);
332
333 if (d->m_document == document)
334 return;
335
336 if (d->m_document)
337 disconnect(d->m_documentStatusChangedConnection);
338
339 d->m_document = document;
340 emit documentChanged(d->m_document);
341
342 if (d->m_document)
343 d->m_documentStatusChangedConnection =
344 connect(d->m_document.data(), &QPdfDocument::statusChanged, this,
345 [d](QPdfDocument::Status s){ d->documentStatusChanged(s); });
346
347 d->m_pageRenderer->setDocument(d->m_document);
348 d->m_linkModel.setDocument(d->m_document);
349
350 d->documentStatusChanged(document->status());
351}
352
353QPdfDocument *QPdfView::document() const
354{
355 Q_D(const QPdfView);
356
357 return d->m_document;
358}
359
360/*!
361 \since 6.6
362 \property QPdfView::searchModel
363
364 If this property is set, QPdfView draws highlight rectangles over the
365 search results provided by \l QPdfSearchModel::resultsOnPage(). By default
366 it is \c nullptr.
367*/
368void QPdfView::setSearchModel(QPdfSearchModel *searchModel)
369{
370 Q_D(QPdfView);
371 if (d->m_searchModel == searchModel)
372 return;
373
374 if (d->m_searchModel)
375 d->m_searchModel->disconnect(this);
376
377 d->m_searchModel = searchModel;
378 emit searchModelChanged(searchModel);
379
380 if (searchModel) {
381 connect(searchModel, &QPdfSearchModel::dataChanged, this,
382 [this](const QModelIndex &, const QModelIndex &, const QList<int> &) { update(); });
383 }
384 setCurrentSearchResultIndex(-1);
385}
386
387QPdfSearchModel *QPdfView::searchModel() const
388{
389 Q_D(const QPdfView);
390 return d->m_searchModel;
391}
392
393/*!
394 \since 6.6
395 \property QPdfView::currentSearchResultIndex
396
397 If this property is set to a positive number, and \l searchModel is set,
398 QPdfView draws a frame around the search result provided by
399 \l QPdfSearchModel at the given index. For example, if QPdfSearchModel is
400 used as the model for a QListView, you can keep this property updated by
401 connecting QItemSelectionModel::currentChanged() from
402 QListView::selectionModel() to a function that will in turn call this function.
403
404 By default it is \c -1, so that no search results are framed.
405*/
406void QPdfView::setCurrentSearchResultIndex(int currentResult)
407{
408 Q_D(QPdfView);
409 if (d->m_currentSearchResultIndex == currentResult)
410 return;
411
412 d->m_currentSearchResultIndex = currentResult;
413 emit currentSearchResultIndexChanged(currentResult);
414 viewport()->update(); //update();
415}
416
417int QPdfView::currentSearchResultIndex() const
418{
419 Q_D(const QPdfView);
420 return d->m_currentSearchResultIndex;
421}
422
423/*!
424 This accessor returns the navigation stack that will handle back/forward navigation.
425*/
426QPdfPageNavigator *QPdfView::pageNavigator() const
427{
428 Q_D(const QPdfView);
429
430 return d->m_pageNavigator;
431}
432
433/*!
434 \enum QPdfView::PageMode
435
436 This enum describes the overall behavior of the PDF viewer:
437
438 \value SinglePage Show one page at a time.
439 \value MultiPage Allow scrolling through all pages in the document.
440*/
441
442/*!
443 \property QPdfView::pageMode
444
445 This property holds whether to show one page at a time, or all pages in the
446 document. The default is \c SinglePage.
447*/
448QPdfView::PageMode QPdfView::pageMode() const
449{
450 Q_D(const QPdfView);
451
452 return d->m_pageMode;
453}
454
455void QPdfView::setPageMode(PageMode mode)
456{
457 Q_D(QPdfView);
458
459 if (d->m_pageMode == mode)
460 return;
461
462 d->m_pageMode = mode;
463 d->invalidateDocumentLayout();
464
465 emit pageModeChanged(d->m_pageMode);
466}
467
468/*!
469 \enum QPdfView::ZoomMode
470
471 This enum describes the magnification behavior of the PDF viewer:
472
473 \value Custom Use \l zoomFactor only.
474 \value FitToWidth Automatically choose a zoom factor so that
475 the width of the page fits in the view.
476 \value FitInView Automatically choose a zoom factor so that
477 the entire page fits in the view.
478*/
479
480/*!
481 \property QPdfView::zoomMode
482
483 This property indicates whether to use a custom size for the page(s),
484 or zoom them to fit to the view. The default is \c CustomZoom.
485*/
486QPdfView::ZoomMode QPdfView::zoomMode() const
487{
488 Q_D(const QPdfView);
489
490 return d->m_zoomMode;
491}
492
493void QPdfView::setZoomMode(ZoomMode mode)
494{
495 Q_D(QPdfView);
496
497 if (d->m_zoomMode == mode)
498 return;
499
500 d->m_zoomMode = mode;
501 d->invalidateDocumentLayout();
502
503 emit zoomModeChanged(d->m_zoomMode);
504}
505
506/*!
507 \property QPdfView::zoomFactor
508
509 This property holds the ratio of pixels to points. The default is \c 1,
510 meaning one point (1/72 of an inch) equals 1 logical pixel.
511*/
512qreal QPdfView::zoomFactor() const
513{
514 Q_D(const QPdfView);
515
516 return d->m_zoomFactor;
517}
518
519void QPdfView::setZoomFactor(qreal factor)
520{
521 Q_D(QPdfView);
522
523 if (d->m_zoomFactor == factor)
524 return;
525
526 d->m_zoomFactor = factor;
527 d->invalidateDocumentLayout();
528
529 emit zoomFactorChanged(d->m_zoomFactor);
530}
531
532/*!
533 \property QPdfView::pageSpacing
534
535 This property holds the size of the padding between pages in the \l MultiPage
536 \l {pageMode}{mode}.
537*/
538int QPdfView::pageSpacing() const
539{
540 Q_D(const QPdfView);
541
542 return d->m_pageSpacing;
543}
544
545void QPdfView::setPageSpacing(int spacing)
546{
547 Q_D(QPdfView);
548
549 if (d->m_pageSpacing == spacing)
550 return;
551
552 d->m_pageSpacing = spacing;
553 d->invalidateDocumentLayout();
554
555 emit pageSpacingChanged(d->m_pageSpacing);
556}
557
558/*!
559 \property QPdfView::documentMargins
560
561 This property holds the margins around the page view.
562*/
563QMargins QPdfView::documentMargins() const
564{
565 Q_D(const QPdfView);
566
567 return d->m_documentMargins;
568}
569
570void QPdfView::setDocumentMargins(QMargins margins)
571{
572 Q_D(QPdfView);
573
574 if (d->m_documentMargins == margins)
575 return;
576
577 d->m_documentMargins = margins;
578 d->invalidateDocumentLayout();
579
580 emit documentMarginsChanged(d->m_documentMargins);
581}
582
583void QPdfView::paintEvent(QPaintEvent *event)
584{
585 Q_D(QPdfView);
586
587 QPainter painter(viewport());
588 painter.fillRect(event->rect(), palette().brush(QPalette::Dark));
589 painter.translate(-d->m_viewport.x(), -d->m_viewport.y());
590
591 for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin();
592 it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) {
593 const QRect pageGeometry = it.value().first;
594 if (pageGeometry.intersects(d->m_viewport)) { // page needs to be painted
595 painter.fillRect(pageGeometry, Qt::white);
596
597 const int page = it.key();
598 const auto pageIt = d->m_pageCache.constFind(page);
599 if (pageIt != d->m_pageCache.cend()) {
600 const QImage &img = pageIt.value();
601 painter.drawImage(pageGeometry, img);
602 } else {
603 d->m_pageRenderer->requestPage(page, pageGeometry.size() * devicePixelRatioF());
604 }
605
606 const QTransform scaleTransform = d->screenScaleTransform(page);
607#ifdef DEBUG_LINKS
608 const QString fmt = u"page %1 @ %2, %3"_s;
609 d->m_linkModel.setPage(page);
610 const int linkCount = d->m_linkModel.rowCount({});
611 for (int i = 0; i < linkCount; ++i) {
612 const QRectF linkBounds = scaleTransform.mapRect(
613 d->m_linkModel.data(d->m_linkModel.index(i),
614 int(QPdfLinkModel::Role::Rect)).toRectF())
615 .translated(pageGeometry.topLeft());
616 painter.setPen(Qt::blue);
617 painter.drawRect(linkBounds);
618 painter.setPen(Qt::red);
619 const QPoint loc = d->m_linkModel.data(d->m_linkModel.index(i),
620 int(QPdfLinkModel::Role::Location)).toPoint();
621 // TODO maybe draw destination URL if that's what it is
622 painter.drawText(linkBounds.bottomLeft() + QPoint(2, -2),
623 fmt.arg(d->m_linkModel.data(d->m_linkModel.index(i),
624 int(QPdfLinkModel::Role::Page)).toInt())
625 .arg(loc.x()).arg(loc.y()));
626 }
627#endif
628 if (d->m_searchModel) {
629 for (const QPdfLink &result : d->m_searchModel->resultsOnPage(page)) {
630 for (const QRectF &rect : result.rectangles())
631 painter.fillRect(scaleTransform.mapRect(rect).translated(pageGeometry.topLeft()), SearchResultHighlight);
632 }
633
634 if (d->m_currentSearchResultIndex >= 0 && d->m_currentSearchResultIndex < d->m_searchModel->rowCount({})) {
635 const QPdfLink &cur = d->m_searchModel->resultAtIndex(d->m_currentSearchResultIndex);
636 if (cur.page() == page) {
637 painter.setPen({CurrentSearchResultHighlight, CurrentSearchResultWidth});
638 for (const auto &rect : cur.rectangles())
639 painter.drawRect(scaleTransform.mapRect(rect).translated(pageGeometry.topLeft()));
640 }
641 }
642 }
643 }
644 }
645}
646
647void QPdfView::resizeEvent(QResizeEvent *event)
648{
649 Q_D(QPdfView);
650
651 QAbstractScrollArea::resizeEvent(event);
652
653 d->updateScrollBars();
654 d->calculateViewport();
655}
656
657void QPdfView::scrollContentsBy(int dx, int dy)
658{
659 Q_D(QPdfView);
660
661 QAbstractScrollArea::scrollContentsBy(dx, dy);
662
663 d->calculateViewport();
664}
665
666void QPdfView::mousePressEvent(QMouseEvent *event)
667{
668 Q_ASSERT(event->isAccepted());
669}
670
671void QPdfView::mouseMoveEvent(QMouseEvent *event)
672{
673 Q_D(QPdfView);
674 for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin();
675 it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) {
676 const int page = it.key();
677 const QTransform screenInvTransform = d->screenScaleTransform(page).inverted();
678 const QRect pageGeometry = it.value().first;
679 if (pageGeometry.contains(event->position().toPoint())) {
680 QPointF posInPoints = screenInvTransform.map(event->position() - pageGeometry.topLeft()
681 + d->m_viewport.topLeft());
682 d->m_linkModel.setPage(page);
683 auto dest = d->m_linkModel.linkAt(posInPoints);
684 setCursor(dest.isValid() ? Qt::PointingHandCursor : Qt::ArrowCursor);
685 if (dest.isValid())
686 qCDebug(qLcWLink) << event->position() << ":" << posInPoints << "pt ->" << dest;
687 }
688 }
689}
690
691void QPdfView::mouseReleaseEvent(QMouseEvent *event)
692{
693 Q_D(QPdfView);
694 for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin();
695 it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) {
696 const int page = it.key();
697 const QTransform screenInvTransform = d->screenScaleTransform(page).inverted();
698 const QRect pageGeometry = it.value().first;
699 if (pageGeometry.contains(event->position().toPoint())) {
700 QPointF posInPoints = screenInvTransform.map(event->position() - pageGeometry.topLeft()
701 + d->m_viewport.topLeft());
702 d->m_linkModel.setPage(page);
703 auto dest = d->m_linkModel.linkAt(posInPoints);
704 if (dest.isValid()) {
705 qCDebug(qLcWLink) << event << ": jumping to" << dest;
706 d->m_pageNavigator->jump(dest.page(), dest.location(), dest.zoom());
707 // TODO scroll and zoom to where the link tells us to
708 }
709 return;
710 }
711 }
712}
713
714QT_END_NAMESPACE
715
716#include "moc_qpdfview.cpp"
QTransform screenScaleTransform(int page) const
Definition qpdfview.cpp:258
void updateScrollBars()
Definition qpdfview.cpp:128
void setViewport(QRect viewport)
Definition qpdfview.cpp:86
QPdfPageRenderer * m_pageRenderer
Definition qpdfview_p.h:64
void updateDocumentLayout()
Definition qpdfview.cpp:273
QPdfPageNavigator * m_pageNavigator
Definition qpdfview_p.h:63
void documentStatusChanged(QPdfDocument::Status status)
Definition qpdfview.cpp:54
qreal yPositionForPage(int page) const
Definition qpdfview.cpp:249
void invalidatePageCache()
Definition qpdfview.cpp:166
void invalidateDocumentLayout()
Definition qpdfview.cpp:160
void currentPageChanged(int currentPage)
Definition qpdfview.cpp:61
bool m_blockPageScrolling
Definition qpdfview_p.h:76
void calculateViewport()
Definition qpdfview.cpp:74
DocumentLayout calculateDocumentLayout() const
Definition qpdfview.cpp:174
void pageRendered(int pageNumber, QSize imageSize, const QImage &image, quint64 requestId)
Definition qpdfview.cpp:141
Combined button and popup list for selecting options.
static const QColor CurrentSearchResultHighlight(Qt::cyan)
static const int CurrentSearchResultWidth(2)