mirror of https://github.com/qt/qtdoc.git
273 lines
8.4 KiB
C++
273 lines
8.4 KiB
C++
// Copyright (C) 2023 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
#include "pdfviewer.h"
|
|
#include "zoomselector.h"
|
|
#include "hoverwatcher.h"
|
|
|
|
#include <QApplication>
|
|
#include <QEvent>
|
|
#include <QFile>
|
|
#include <QMouseEvent>
|
|
|
|
#include <QPdfBookmarkModel>
|
|
#include <QPdfDocument>
|
|
#include <QPdfPageNavigator>
|
|
#include <QPdfView>
|
|
#include <QPdfPageSelector>
|
|
|
|
#include <QtMath>
|
|
#include <QDir>
|
|
#include <QStandardPaths>
|
|
|
|
#include <QListView>
|
|
#include <QListWidget>
|
|
#include <QMainWindow>
|
|
#include <QScrollBar>
|
|
#include <QScroller>
|
|
#include <QSpinBox>
|
|
#include <QToolBar>
|
|
#include <QTreeView>
|
|
|
|
#ifdef DOCUMENTVIEWER_PRINTSUPPORT
|
|
#include <QPrinter>
|
|
#include <QPainter>
|
|
#endif
|
|
|
|
Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer")
|
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
PdfViewer::PdfViewer()
|
|
{
|
|
connect(this, &AbstractViewer::uiInitialized, this, &PdfViewer::initPdfViewer);
|
|
}
|
|
|
|
void PdfViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow)
|
|
{
|
|
AbstractViewer::init(file, new QPdfView(parent), mainWindow);
|
|
setTranslationBaseName("pdfviewer"_L1);
|
|
m_document = new QPdfDocument(this);
|
|
m_pdfView = qobject_cast<QPdfView *>(widget());
|
|
}
|
|
|
|
void PdfViewer::cleanup()
|
|
{
|
|
delete m_pageSelector;
|
|
m_pageSelector = nullptr;
|
|
delete m_zoomSelector;
|
|
m_zoomSelector = nullptr;
|
|
delete m_pages;
|
|
m_pages = nullptr;
|
|
delete m_bookmarks;
|
|
m_bookmarks = nullptr;
|
|
delete m_document;
|
|
m_document = nullptr;
|
|
AbstractViewer::cleanup();
|
|
}
|
|
|
|
PdfViewer::~PdfViewer()
|
|
{
|
|
PdfViewer::cleanup();
|
|
}
|
|
|
|
QStringList PdfViewer::supportedMimeTypes() const
|
|
{
|
|
return {"application/pdf"_L1};
|
|
}
|
|
|
|
void PdfViewer::initPdfViewer()
|
|
{
|
|
m_toolBar = addToolBar(tr("PDF"));
|
|
m_zoomSelector = new ZoomSelector(m_toolBar);
|
|
|
|
auto *nav = m_pdfView->pageNavigator();
|
|
m_pageSelector = new QPdfPageSelector(m_toolBar);
|
|
m_toolBar->insertWidget(m_uiAssets.forward, m_pageSelector);
|
|
m_pageSelector->setDocument(m_document);
|
|
connect(m_pageSelector, &QPdfPageSelector::currentPageChanged,
|
|
this, &PdfViewer::pageSelected);
|
|
connect(m_pageSelector, &QPdfPageSelector::currentPageChanged,
|
|
this, &PdfViewer::pageSelected);
|
|
connect(nav, &QPdfPageNavigator::currentPageChanged,
|
|
m_pageSelector, &QPdfPageSelector::setCurrentPage);
|
|
|
|
connect(m_pdfView->pageNavigator(), &QPdfPageNavigator::backAvailableChanged,
|
|
m_uiAssets.back, &QAction::setEnabled);
|
|
m_actionBack = m_uiAssets.back;
|
|
m_actionForward = m_uiAssets.forward;
|
|
m_connections.append(connect(m_uiAssets.back, &QAction::triggered,
|
|
this, &PdfViewer::onActionBackTriggered));
|
|
m_connections.append(connect(m_uiAssets.forward, &QAction::triggered,
|
|
this, &PdfViewer::onActionForwardTriggered));
|
|
|
|
m_toolBar->addSeparator();
|
|
m_toolBar->addWidget(m_zoomSelector);
|
|
|
|
QIcon icon = QIcon::fromTheme(QIcon::ThemeIcon::ZoomIn, QIcon(":/demos/documentviewer/images/zoom-in.png"_L1));
|
|
m_actionZoomIn = m_toolBar->addAction(icon, tr("Zoom in"), QKeySequence::ZoomIn);
|
|
connect(m_actionZoomIn, &QAction::triggered, this, &PdfViewer::onActionZoomInTriggered);
|
|
|
|
icon = QIcon::fromTheme(QIcon::ThemeIcon::ZoomOut,
|
|
QIcon(":/demos/documentviewer/images/zoom-out.png"_L1));
|
|
m_actionZoomOut = m_toolBar->addAction(icon, tr("Zoom out"), QKeySequence::ZoomOut);
|
|
connect(m_actionZoomOut, &QAction::triggered, this, &PdfViewer::onActionZoomOutTriggered);
|
|
|
|
connect(nav, &QPdfPageNavigator::backAvailableChanged, m_actionBack, &QAction::setEnabled);
|
|
connect(nav, &QPdfPageNavigator::forwardAvailableChanged, m_actionForward, &QAction::setEnabled);
|
|
|
|
connect(m_zoomSelector, &ZoomSelector::zoomModeChanged, m_pdfView, &QPdfView::setZoomMode);
|
|
connect(m_zoomSelector, &ZoomSelector::zoomFactorChanged, m_pdfView, &QPdfView::setZoomFactor);
|
|
m_zoomSelector->reset();
|
|
|
|
QPdfBookmarkModel *bookmarkModel = new QPdfBookmarkModel(this);
|
|
bookmarkModel->setDocument(m_document);
|
|
m_uiAssets.tabs->clear();
|
|
m_bookmarks = new QTreeView(m_uiAssets.tabs);
|
|
connect(m_bookmarks, &QAbstractItemView::activated, this, &PdfViewer::bookmarkSelected);
|
|
m_bookmarks->setModel(bookmarkModel);
|
|
m_pdfView->setDocument(m_document);
|
|
m_pdfView->setPageMode(QPdfView::PageMode::MultiPage);
|
|
|
|
openPdfFile();
|
|
if (!m_document->pageCount())
|
|
return;
|
|
|
|
m_pages = new QListView(m_uiAssets.tabs);
|
|
m_pages->setModel(m_document->pageModel());
|
|
connect(m_pages->selectionModel(), &QItemSelectionModel::currentRowChanged, m_pages, [&]
|
|
(const QModelIndex ¤t, const QModelIndex &previous){
|
|
if (previous == current)
|
|
return;
|
|
|
|
auto *nav = m_pdfView->pageNavigator();
|
|
const int &row = current.row();
|
|
if (nav->currentPage() == row)
|
|
return;
|
|
|
|
nav->jump(row, QPointF(), nav->currentZoom());
|
|
});
|
|
|
|
connect(m_pdfView->pageNavigator(), &QPdfPageNavigator::currentPageChanged, m_pages, [&](int page){
|
|
if (m_pages->currentIndex().row() == page)
|
|
return;
|
|
|
|
m_pages->setCurrentIndex(m_pages->model()->index(page, 0));
|
|
});
|
|
|
|
m_uiAssets.tabs->addTab(m_pages, tr("Pages"));
|
|
m_uiAssets.tabs->addTab(m_bookmarks, tr("Bookmarks"));
|
|
QScroller::grabGesture(m_pdfView->viewport(), QScroller::ScrollerGestureType::LeftMouseButtonGesture);
|
|
HoverWatcher::watcher(m_pdfView->viewport());
|
|
}
|
|
|
|
void PdfViewer::openPdfFile()
|
|
{
|
|
disablePrinting();
|
|
|
|
if (m_file->open(QIODevice::ReadOnly))
|
|
m_document->load(m_file.get());
|
|
|
|
const auto documentTitle = m_document->metaData(QPdfDocument::MetaDataField::Title).toString();
|
|
statusMessage(documentTitle.isEmpty() ? "PDF Viewer"_L1 : documentTitle);
|
|
pageSelected(0);
|
|
|
|
statusMessage(tr("Opened PDF file %1")
|
|
.arg(QDir::toNativeSeparators(m_file->fileName())));
|
|
qCDebug(lcExample) << "Opened file" << m_file->fileName();
|
|
|
|
maybeEnablePrinting();
|
|
}
|
|
|
|
bool PdfViewer::hasContent() const
|
|
{
|
|
return m_document ? m_document->pageCount() > 0 : false;
|
|
}
|
|
|
|
#ifdef DOCUMENTVIEWER_PRINTSUPPORT
|
|
void PdfViewer::printDocument(QPrinter *printer) const
|
|
{
|
|
if (!hasContent())
|
|
return;
|
|
|
|
QPainter painter;
|
|
painter.begin(printer);
|
|
const QRect pageRect = printer->pageRect(QPrinter::Unit::DevicePixel).toRect();
|
|
const QSize pageSize = pageRect.size();
|
|
for (int i = 0; i < m_document->pageCount(); ++i) {
|
|
if (i > 0)
|
|
printer->newPage();
|
|
const QImage &page = m_document->render(i, pageSize);
|
|
painter.drawImage(pageRect, page);
|
|
}
|
|
painter.end();
|
|
}
|
|
#endif // DOCUMENTVIEWER_PRINTSUPPORT
|
|
|
|
void PdfViewer::bookmarkSelected(const QModelIndex &index)
|
|
{
|
|
if (!index.isValid())
|
|
return;
|
|
|
|
const int page = index.data(int(QPdfBookmarkModel::Role::Page)).toInt();
|
|
const qreal zoomLevel = index.data(int(QPdfBookmarkModel::Role::Level)).toReal();
|
|
m_pdfView->pageNavigator()->jump(page, {}, zoomLevel);
|
|
}
|
|
|
|
void PdfViewer::pageSelected(int page)
|
|
{
|
|
auto nav = m_pdfView->pageNavigator();
|
|
nav->jump(page, {}, nav->currentZoom());
|
|
}
|
|
|
|
void PdfViewer::onActionZoomInTriggered()
|
|
{
|
|
m_pdfView->setZoomFactor(m_pdfView->zoomFactor() * zoomMultiplier);
|
|
}
|
|
|
|
void PdfViewer::onActionZoomOutTriggered()
|
|
{
|
|
m_pdfView->setZoomFactor(m_pdfView->zoomFactor() / zoomMultiplier);
|
|
}
|
|
|
|
void PdfViewer::onActionPreviousPageTriggered()
|
|
{
|
|
auto nav = m_pdfView->pageNavigator();
|
|
nav->jump(nav->currentPage() - 1, {}, nav->currentZoom());
|
|
}
|
|
|
|
void PdfViewer::onActionNextPageTriggered()
|
|
{
|
|
auto nav = m_pdfView->pageNavigator();
|
|
nav->jump(nav->currentPage() + 1, {}, nav->currentZoom());
|
|
}
|
|
|
|
void PdfViewer::onActionBackTriggered()
|
|
{
|
|
m_pdfView->pageNavigator()->back();
|
|
}
|
|
|
|
void PdfViewer::onActionForwardTriggered()
|
|
{
|
|
m_pdfView->pageNavigator()->forward();
|
|
}
|
|
|
|
void PdfViewer::retranslate()
|
|
{
|
|
if (m_toolBar)
|
|
m_toolBar->setWindowTitle(tr("PDF"));
|
|
if (m_actionZoomIn)
|
|
m_actionZoomIn->setText(tr("Zoom in"));
|
|
if (m_actionZoomOut) {
|
|
m_actionZoomOut->setText(tr("Zoom out"));
|
|
}
|
|
if (m_pages && m_bookmarks && m_uiAssets.tabs) {
|
|
int pagesIndex = m_uiAssets.tabs->indexOf(m_pages);
|
|
if (pagesIndex >= 0)
|
|
m_uiAssets.tabs->setTabText(pagesIndex, tr("Pages"));
|
|
int bookmarksIndex = m_uiAssets.tabs->indexOf(m_bookmarks);
|
|
if (bookmarksIndex >= 0)
|
|
m_uiAssets.tabs->setTabText(bookmarksIndex, tr("Bookmarks"));
|
|
}
|
|
}
|