summaryrefslogtreecommitdiffstats
path: root/examples/pdf/pdfviewer
diff options
context:
space:
mode:
Diffstat (limited to 'examples/pdf/pdfviewer')
-rw-r--r--examples/pdf/pdfviewer/images/busy.pngbin0 -> 172 bytes
-rw-r--r--examples/pdf/pdfviewer/images/fileopen.pngbin0 -> 1771 bytes
-rw-r--r--examples/pdf/pdfviewer/images/go-next-24.pngbin0 -> 782 bytes
-rw-r--r--examples/pdf/pdfviewer/images/go-previous-24.pngbin0 -> 797 bytes
-rw-r--r--examples/pdf/pdfviewer/images/zoom-in-24.pngbin0 -> 1302 bytes
-rw-r--r--examples/pdf/pdfviewer/images/zoom-in-32.pngbin0 -> 1873 bytes
-rw-r--r--examples/pdf/pdfviewer/images/zoom-out-24.pngbin0 -> 1247 bytes
-rw-r--r--examples/pdf/pdfviewer/images/zoom-out-32.pngbin0 -> 1749 bytes
-rw-r--r--examples/pdf/pdfviewer/main.cpp51
-rw-r--r--examples/pdf/pdfviewer/mainwindow.cpp170
-rw-r--r--examples/pdf/pdfviewer/mainwindow.h89
-rw-r--r--examples/pdf/pdfviewer/mainwindow.ui173
-rw-r--r--examples/pdf/pdfviewer/pagerenderer.cpp105
-rw-r--r--examples/pdf/pdfviewer/pagerenderer.h80
-rw-r--r--examples/pdf/pdfviewer/pdfviewer.pro21
-rw-r--r--examples/pdf/pdfviewer/resources.qrc12
-rw-r--r--examples/pdf/pdfviewer/sequentialpagewidget.cpp192
-rw-r--r--examples/pdf/pdfviewer/sequentialpagewidget.h96
18 files changed, 989 insertions, 0 deletions
diff --git a/examples/pdf/pdfviewer/images/busy.png b/examples/pdf/pdfviewer/images/busy.png
new file mode 100644
index 0000000..69056c4
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/busy.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/fileopen.png b/examples/pdf/pdfviewer/images/fileopen.png
new file mode 100644
index 0000000..33e0d63
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/fileopen.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/go-next-24.png b/examples/pdf/pdfviewer/images/go-next-24.png
new file mode 100644
index 0000000..9a55ef3
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/go-next-24.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/go-previous-24.png b/examples/pdf/pdfviewer/images/go-previous-24.png
new file mode 100644
index 0000000..2ea769e
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/go-previous-24.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/zoom-in-24.png b/examples/pdf/pdfviewer/images/zoom-in-24.png
new file mode 100644
index 0000000..d29b142
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/zoom-in-24.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/zoom-in-32.png b/examples/pdf/pdfviewer/images/zoom-in-32.png
new file mode 100644
index 0000000..34d70af
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/zoom-in-32.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/zoom-out-24.png b/examples/pdf/pdfviewer/images/zoom-out-24.png
new file mode 100644
index 0000000..1970347
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/zoom-out-24.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/images/zoom-out-32.png b/examples/pdf/pdfviewer/images/zoom-out-32.png
new file mode 100644
index 0000000..b832206
--- /dev/null
+++ b/examples/pdf/pdfviewer/images/zoom-out-32.png
Binary files differ
diff --git a/examples/pdf/pdfviewer/main.cpp b/examples/pdf/pdfviewer/main.cpp
new file mode 100644
index 0000000..20fa6f8
--- /dev/null
+++ b/examples/pdf/pdfviewer/main.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "mainwindow.h"
+#include <QApplication>
+#include <QUrl>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ QStringList args = a.arguments();
+ w.show();
+ if (args.length() > 1)
+ w.open(QUrl::fromLocalFile(args[1]));
+
+ return a.exec();
+}
diff --git a/examples/pdf/pdfviewer/mainwindow.cpp b/examples/pdf/pdfviewer/mainwindow.cpp
new file mode 100644
index 0000000..d865a8b
--- /dev/null
+++ b/examples/pdf/pdfviewer/mainwindow.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include "sequentialpagewidget.h"
+
+#include <QFileDialog>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QPdfDocument>
+#include <QScroller>
+#include <QtMath>
+
+const qreal zoomMultiplier = qSqrt(2.0);
+
+Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer")
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+ , m_pageWidget(new SequentialPageWidget(this))
+ , m_zoomEdit(new QLineEdit(this))
+ , m_pageEdit(new QLineEdit(this))
+ , m_document(new QPdfDocument(this))
+{
+ ui->setupUi(this);
+ ui->scrollArea->setWidget(m_pageWidget);
+ m_zoomEdit->setMaximumWidth(50);
+ m_zoomEdit->setAlignment(Qt::AlignHCenter);
+ ui->mainToolBar->insertWidget(ui->actionZoom_In, m_zoomEdit);
+ m_pageEdit->setMaximumWidth(50);
+ m_pageEdit->setAlignment(Qt::AlignHCenter);
+ ui->mainToolBar->insertWidget(ui->actionGo, m_pageEdit);
+ connect(m_pageWidget, SIGNAL(showingPageRange(int,int)),
+ this, SLOT(showingPageRange(int,int)), Qt::QueuedConnection);
+ connect(m_pageWidget, SIGNAL(zoomChanged(qreal)),
+ this, SLOT(zoomChanged(qreal)));
+ connect(m_zoomEdit, SIGNAL(returnPressed()), this, SLOT(zoomEdited()));
+ connect(m_pageEdit, SIGNAL(returnPressed()), this, SLOT(on_actionGo_triggered()));
+
+ QScroller::grabGesture(ui->scrollArea);
+
+ m_pageWidget->setDocument(m_document);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::open(const QUrl &docLocation)
+{
+ if (docLocation.isLocalFile()) {
+ m_document->load(docLocation.toLocalFile());
+ } else {
+ qCDebug(lcExample) << docLocation << "is not a valid local file";
+ QMessageBox::critical(this, tr("Failed to open"), tr("%1 is not a valid local file").arg(docLocation.toString()));
+ }
+ qCDebug(lcExample) << docLocation;
+ ui->scrollArea->ensureVisible(0, 0, 0, 0);
+}
+
+void MainWindow::showingPageRange(int start, int end)
+{
+ ui->statusBar->clearMessage();
+ if (start == end)
+ ui->statusBar->showMessage(tr("showing page %1").arg(start));
+ else
+ ui->statusBar->showMessage(tr("showing pages %1 to %2").arg(start).arg(end));
+ m_pageEdit->setText(QString::number(end));
+}
+
+void MainWindow::zoomChanged(qreal factor)
+{
+ m_zoomEdit->setText(tr("%1%").arg(factor * 100., 0, 'f', 0));
+}
+
+void MainWindow::zoomEdited()
+{
+ bool ok = false;
+ qreal factor = m_zoomEdit->text().remove(QChar('%')).toDouble(&ok);
+ if (ok)
+ m_pageWidget->setZoom(factor / 100.);
+}
+
+void MainWindow::on_actionOpen_triggered()
+{
+ QUrl toOpen = QFileDialog::getOpenFileUrl(this, tr("Choose a PDF"), QUrl(), "Portable Documents (*.pdf)");
+ if (toOpen.isValid())
+ open(toOpen);
+}
+
+void MainWindow::on_actionQuit_triggered()
+{
+ QApplication::quit();
+}
+
+void MainWindow::on_actionAbout_triggered()
+{
+ QMessageBox::about(this, tr("About PdfViewer"),
+ tr("An example using QPdfDocument"));
+}
+
+void MainWindow::on_actionAbout_Qt_triggered()
+{
+ QMessageBox::aboutQt(this);
+}
+
+void MainWindow::on_actionZoom_In_triggered()
+{
+ m_pageWidget->setZoom(m_pageWidget->zoom() * zoomMultiplier);
+}
+
+void MainWindow::on_actionZoom_Out_triggered()
+{
+ m_pageWidget->setZoom(m_pageWidget->zoom() / zoomMultiplier);
+}
+
+void MainWindow::on_actionGo_triggered()
+{
+ bool ok = false;
+ int page = m_pageEdit->text().toInt(&ok);
+ if (!ok) return;
+ ui->scrollArea->ensureVisible(0, m_pageWidget->yForPage(page));
+}
+
+void MainWindow::on_actionPrevious_Page_triggered()
+{
+ ui->scrollArea->ensureVisible(0, m_pageWidget->yForPage(m_pageWidget->topPageShowing() - 1));
+}
+
+void MainWindow::on_actionNext_Page_triggered()
+{
+ ui->scrollArea->ensureVisible(0, m_pageWidget->yForPage(m_pageWidget->bottomPageShowing() + 1));
+}
diff --git a/examples/pdf/pdfviewer/mainwindow.h b/examples/pdf/pdfviewer/mainwindow.h
new file mode 100644
index 0000000..dedc812
--- /dev/null
+++ b/examples/pdf/pdfviewer/mainwindow.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QLoggingCategory>
+#include <QMainWindow>
+
+Q_DECLARE_LOGGING_CATEGORY(lcExample)
+
+namespace Ui {
+class MainWindow;
+}
+
+class QLineEdit;
+class QPdfDocument;
+class SequentialPageWidget;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+public slots:
+ void open(const QUrl &docLocation);
+
+private slots:
+ void showingPageRange(int start, int end);
+ void zoomChanged(qreal factor);
+ void zoomEdited();
+
+ // action handlers
+ void on_actionOpen_triggered();
+ void on_actionQuit_triggered();
+ void on_actionAbout_triggered();
+ void on_actionAbout_Qt_triggered();
+ void on_actionZoom_In_triggered();
+ void on_actionZoom_Out_triggered();
+ void on_actionGo_triggered();
+ void on_actionPrevious_Page_triggered();
+ void on_actionNext_Page_triggered();
+
+private:
+ Ui::MainWindow *ui;
+ SequentialPageWidget *m_pageWidget;
+ QLineEdit *m_zoomEdit;
+ QLineEdit *m_pageEdit;
+
+ QPdfDocument *m_document;
+};
+
+#endif // MAINWINDOW_H
diff --git a/examples/pdf/pdfviewer/mainwindow.ui b/examples/pdf/pdfviewer/mainwindow.ui
new file mode 100644
index 0000000..7070619
--- /dev/null
+++ b/examples/pdf/pdfviewer/mainwindow.ui
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>200</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2"/>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>19</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="actionOpen"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <widget class="QMenu" name="menuHelp">
+ <property name="title">
+ <string>Help</string>
+ </property>
+ <addaction name="actionAbout"/>
+ <addaction name="actionAbout_Qt"/>
+ </widget>
+ <widget class="QMenu" name="menuView">
+ <property name="title">
+ <string>View</string>
+ </property>
+ <addaction name="actionZoom_In"/>
+ <addaction name="actionZoom_Out"/>
+ <addaction name="actionPrevious_Page"/>
+ <addaction name="actionNext_Page"/>
+ </widget>
+ <addaction name="menuFile"/>
+ <addaction name="menuView"/>
+ <addaction name="menuHelp"/>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionOpen"/>
+ <addaction name="separator"/>
+ <addaction name="actionZoom_Out"/>
+ <addaction name="actionZoom_In"/>
+ <addaction name="separator"/>
+ <addaction name="actionGo"/>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ <action name="actionOpen">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/images/fileopen.png</normaloff>:/icons/images/fileopen.png</iconset>
+ </property>
+ <property name="text">
+ <string>Open...</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action name="actionQuit">
+ <property name="text">
+ <string>Quit</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="actionAbout">
+ <property name="text">
+ <string>About</string>
+ </property>
+ </action>
+ <action name="actionAbout_Qt">
+ <property name="text">
+ <string>About Qt</string>
+ </property>
+ </action>
+ <action name="actionZoom_In">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/images/zoom-in-24.png</normaloff>:/icons/images/zoom-in-24.png</iconset>
+ </property>
+ <property name="text">
+ <string>Zoom In</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+=</string>
+ </property>
+ </action>
+ <action name="actionZoom_Out">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/images/zoom-out-24.png</normaloff>:/icons/images/zoom-out-24.png</iconset>
+ </property>
+ <property name="text">
+ <string>Zoom Out</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+-</string>
+ </property>
+ </action>
+ <action name="actionGo">
+ <property name="text">
+ <string>Go</string>
+ </property>
+ <property name="toolTip">
+ <string>Go to Page</string>
+ </property>
+ </action>
+ <action name="actionPrevious_Page">
+ <property name="text">
+ <string>Previous Page</string>
+ </property>
+ <property name="shortcut">
+ <string>PgUp</string>
+ </property>
+ </action>
+ <action name="actionNext_Page">
+ <property name="text">
+ <string>Next Page</string>
+ </property>
+ <property name="shortcut">
+ <string>PgDown</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/examples/pdf/pdfviewer/pagerenderer.cpp b/examples/pdf/pdfviewer/pagerenderer.cpp
new file mode 100644
index 0000000..c8f2456
--- /dev/null
+++ b/examples/pdf/pdfviewer/pagerenderer.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "pagerenderer.h"
+
+#include <QElapsedTimer>
+#include <QLoggingCategory>
+#include <QPainter>
+#include <QPdfDocument>
+#include <QUrl>
+
+Q_DECLARE_LOGGING_CATEGORY(lcExample)
+
+PageRenderer::PageRenderer(QObject *parent)
+ : QThread(parent)
+ , m_document(nullptr)
+ , m_page(0)
+ , m_zoom(1.)
+ , m_minRenderTime(1000000000.)
+ , m_maxRenderTime(0.)
+ , m_totalRenderTime(0.)
+ , m_totalPagesRendered(0)
+{
+}
+
+void PageRenderer::setDocument(QPdfDocument *document)
+{
+ m_document = document;
+}
+
+void PageRenderer::requestPage(int page, qreal zoom, Priority priority)
+{
+ // TODO maybe queue up the requests
+ m_page = page;
+ m_zoom = zoom;
+ start(priority);
+}
+
+void PageRenderer::run()
+{
+ renderPage(m_page, m_zoom);
+}
+
+void PageRenderer::renderPage(int page, qreal zoom)
+{
+ if (!m_document || m_document->status() != QPdfDocument::Ready)
+ return;
+
+ const QSizeF size = m_document->pageSize(page) * m_zoom;
+
+ QElapsedTimer timer;
+ timer.start();
+
+ const QImage &img = m_document->render(page, size);
+
+ const qreal secs = timer.nsecsElapsed() / 1000000000.0;
+ if (secs < m_minRenderTime)
+ m_minRenderTime = secs;
+
+ if (secs > m_maxRenderTime)
+ m_maxRenderTime = secs;
+
+ m_totalRenderTime += secs;
+ ++m_totalPagesRendered;
+
+ emit pageReady(page, zoom, img);
+
+ qCDebug(lcExample) << "page" << page << "zoom" << m_zoom << "size" << size << "in" << secs <<
+ "secs; min" << m_minRenderTime <<
+ "avg" << m_totalRenderTime / m_totalPagesRendered <<
+ "max" << m_maxRenderTime;
+}
diff --git a/examples/pdf/pdfviewer/pagerenderer.h b/examples/pdf/pdfviewer/pagerenderer.h
new file mode 100644
index 0000000..5feccaa
--- /dev/null
+++ b/examples/pdf/pdfviewer/pagerenderer.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 PAGECACHE_H
+#define PAGECACHE_H
+
+#include <QImage>
+#include <QThread>
+
+class QPdfDocument;
+
+class PageRenderer : public QThread
+{
+ Q_OBJECT
+
+public:
+ explicit PageRenderer(QObject *parent = nullptr);
+
+public slots:
+ void setDocument(QPdfDocument *document);
+
+ void requestPage(int page, qreal zoom, Priority priority = QThread::NormalPriority);
+
+signals:
+ void pageReady(int page, qreal zoom, QImage image);
+
+protected:
+ void run() override;
+
+private:
+ void renderPage(int page, qreal zoom);
+
+private:
+ QPdfDocument *m_document;
+
+ // current request only
+ int m_page;
+ qreal m_zoom;
+
+ // performance statistics
+ qreal m_minRenderTime;
+ qreal m_maxRenderTime;
+ qreal m_totalRenderTime;
+ int m_totalPagesRendered;
+};
+
+#endif // PAGECACHE_H
diff --git a/examples/pdf/pdfviewer/pdfviewer.pro b/examples/pdf/pdfviewer/pdfviewer.pro
new file mode 100644
index 0000000..10cacce
--- /dev/null
+++ b/examples/pdf/pdfviewer/pdfviewer.pro
@@ -0,0 +1,21 @@
+QT += core gui widgets pdf
+TARGET = pdfviewer
+TEMPLATE = app
+
+SOURCES += main.cpp\
+ mainwindow.cpp \
+ sequentialpagewidget.cpp \
+ pagerenderer.cpp
+
+HEADERS += mainwindow.h \
+ sequentialpagewidget.h \
+ pagerenderer.h
+
+FORMS += mainwindow.ui
+
+RESOURCES += \
+ resources.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/pdf/pdfviewer
+INSTALLS += target
+
diff --git a/examples/pdf/pdfviewer/resources.qrc b/examples/pdf/pdfviewer/resources.qrc
new file mode 100644
index 0000000..02d9655
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources.qrc
@@ -0,0 +1,12 @@
+<RCC>
+ <qresource prefix="/icons">
+ <file>images/fileopen.png</file>
+ <file>images/go-next-24.png</file>
+ <file>images/go-previous-24.png</file>
+ <file>images/zoom-in-24.png</file>
+ <file>images/zoom-in-32.png</file>
+ <file>images/zoom-out-24.png</file>
+ <file>images/zoom-out-32.png</file>
+ <file>images/busy.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/pdf/pdfviewer/sequentialpagewidget.cpp b/examples/pdf/pdfviewer/sequentialpagewidget.cpp
new file mode 100644
index 0000000..904bc17
--- /dev/null
+++ b/examples/pdf/pdfviewer/sequentialpagewidget.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "sequentialpagewidget.h"
+#include "pagerenderer.h"
+#include <QPaintEvent>
+#include <QPainter>
+#include <QPdfDocument>
+#include <QGuiApplication>
+#include <QScreen>
+#include <QLoggingCategory>
+#include <QElapsedTimer>
+
+Q_DECLARE_LOGGING_CATEGORY(lcExample)
+
+SequentialPageWidget::SequentialPageWidget(QWidget *parent)
+ : QWidget(parent)
+ , m_pageCacheLimit(20)
+ , m_pageRenderer(new PageRenderer())
+ , m_background(Qt::darkGray)
+ , m_placeholderIcon(":icons/images/busy.png")
+ , m_placeholderBackground(Qt::white)
+ , m_pageSpacing(3)
+ , m_topPageShowing(0)
+ , m_zoom(1.)
+ , m_screenResolution(QGuiApplication::primaryScreen()->logicalDotsPerInch() / 72.0)
+ , m_document(nullptr)
+{
+ connect(m_pageRenderer, SIGNAL(pageReady(int, qreal, QImage)), this, SLOT(pageLoaded(int, qreal, QImage)), Qt::QueuedConnection);
+ grabGesture(Qt::SwipeGesture);
+}
+
+SequentialPageWidget::~SequentialPageWidget()
+{
+ delete m_pageRenderer;
+}
+
+void SequentialPageWidget::setDocument(QPdfDocument *document)
+{
+ m_pageRenderer->setDocument(document);
+
+ m_document = document;
+ connect(m_document, &QPdfDocument::statusChanged, this, &SequentialPageWidget::documentStatusChanged);
+
+ documentStatusChanged();
+}
+
+void SequentialPageWidget::setZoom(qreal factor)
+{
+ m_zoom = factor;
+ emit zoomChanged(factor);
+ invalidate();
+}
+
+QSizeF SequentialPageWidget::pageSize(int page)
+{
+// if (!m_pageSizes.length() <= page)
+// return QSizeF();
+ return m_pageSizes[page] * m_screenResolution * m_zoom;
+}
+
+void SequentialPageWidget::invalidate()
+{
+ QSizeF totalSize(0, m_pageSpacing);
+ for (int page = 0; page < pageCount(); ++page) {
+ QSizeF size = pageSize(page);
+ totalSize.setHeight(totalSize.height() + size.height());
+ if (size.width() > totalSize.width())
+ totalSize.setWidth(size.width());
+ }
+ m_totalSize = totalSize.toSize();
+ setMinimumSize(m_totalSize);
+ emit zoomChanged(m_zoom);
+ qCDebug(lcExample) << "total size" << m_totalSize;
+ m_pageCache.clear();
+ update();
+}
+
+void SequentialPageWidget::documentStatusChanged()
+{
+ m_pageSizes.clear();
+ m_topPageShowing = 0;
+
+ if (m_document->status() == QPdfDocument::Ready) {
+ for (int page = 0; page < m_document->pageCount(); ++page)
+ m_pageSizes.append(m_document->pageSize(page));
+ }
+
+ invalidate();
+}
+
+void SequentialPageWidget::pageLoaded(int page, qreal zoom, QImage image)
+{
+ Q_UNUSED(zoom)
+ if (m_cachedPagesLRU.length() > m_pageCacheLimit)
+ m_pageCache.remove(m_cachedPagesLRU.takeFirst());
+ m_pageCache.insert(page, image);
+ m_cachedPagesLRU.append(page);
+ update();
+}
+
+int SequentialPageWidget::pageCount()
+{
+ return m_pageSizes.count();
+}
+
+void SequentialPageWidget::paintEvent(QPaintEvent * event)
+{
+ QPainter painter(this);
+ painter.fillRect(event->rect(), m_background);
+
+ if (m_pageSizes.isEmpty())
+ return;
+
+ // Find the first page that needs to be rendered
+ int page = 0;
+ int y = 0;
+ while (page < pageCount()) {
+ QSizeF size = pageSize(page);
+ int height = size.toSize().height();
+ if (y + height >= event->rect().top())
+ break;
+ y += height + m_pageSpacing;
+ ++page;
+ }
+ y += m_pageSpacing;
+ m_topPageShowing = page;
+
+ // Actually render pages
+ while (y < event->rect().bottom() && page < pageCount()) {
+ QSizeF size = pageSize(page);
+ if (m_pageCache.contains(page)) {
+ const QImage &img = m_pageCache[page];
+ painter.fillRect((width() - img.width()) / 2, y, size.width(), size.height(), Qt::white);
+ painter.drawImage((width() - img.width()) / 2, y, img);
+ } else {
+ painter.fillRect((width() - size.width()) / 2, y, size.width(), size.height(), m_placeholderBackground);
+ painter.drawPixmap((size.width() - m_placeholderIcon.width()) / 2,
+ (size.height() - m_placeholderIcon.height()) / 2, m_placeholderIcon);
+ m_pageRenderer->requestPage(page, m_screenResolution * m_zoom);
+ }
+ y += size.height() + m_pageSpacing;
+ ++page;
+ }
+ m_bottomPageShowing = page - 1;
+ emit showingPageRange(m_topPageShowing, m_bottomPageShowing);
+}
+
+qreal SequentialPageWidget::yForPage(int endPage)
+{
+ // TODO maybe put this loop into a page iterator class
+ int y = m_pageSpacing;
+ for (int page = 0; page < pageCount() && page < endPage; ++page) {
+ QSizeF size = pageSize(page);
+ int height = size.toSize().height();
+ y += height + m_pageSpacing;
+ }
+ return y;
+}
diff --git a/examples/pdf/pdfviewer/sequentialpagewidget.h b/examples/pdf/pdfviewer/sequentialpagewidget.h
new file mode 100644
index 0000000..85f3571
--- /dev/null
+++ b/examples/pdf/pdfviewer/sequentialpagewidget.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 SEQUENTIALPAGEWIDGET_H
+#define SEQUENTIALPAGEWIDGET_H
+
+#include <QWidget>
+
+class QPdfDocument;
+class PageRenderer;
+
+class SequentialPageWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit SequentialPageWidget(QWidget *parent = 0);
+ ~SequentialPageWidget();
+
+ void paintEvent(QPaintEvent * event);
+ qreal zoom() { return m_zoom; }
+ qreal yForPage(int page);
+ int topPageShowing() { return m_topPageShowing; }
+ int bottomPageShowing() { return m_bottomPageShowing; }
+
+ void setDocument(QPdfDocument *document);
+
+public slots:
+ void setZoom(qreal factor);
+ void invalidate();
+
+signals:
+ void showingPageRange(int start, int end);
+ void zoomChanged(qreal factor);
+
+private slots:
+ void documentStatusChanged();
+ void pageLoaded(int page, qreal zoom, QImage image);
+
+private:
+ int pageCount();
+ QSizeF pageSize(int page);
+ void render(int page);
+
+private:
+ QHash<int, QImage> m_pageCache;
+ QVector<int> m_cachedPagesLRU;
+ int m_pageCacheLimit;
+ QVector<QSizeF> m_pageSizes;
+ PageRenderer *m_pageRenderer;
+ QBrush m_background;
+ QPixmap m_placeholderIcon;
+ QBrush m_placeholderBackground;
+ int m_pageSpacing;
+ int m_topPageShowing;
+ int m_bottomPageShowing;
+ QSize m_totalSize;
+ qreal m_zoom;
+ qreal m_screenResolution; // pixels per point
+
+ QPdfDocument *m_document;
+};
+
+#endif // SEQUENTIALPAGEWIDGET_H