making clangd happy and making script to compile/build with run.sh
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# Copyright (C) 2023 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets PdfWidgets
|
||||
OPTIONAL_COMPONENTS PrintSupport)
|
||||
|
||||
qt_add_plugin(pdfviewer
|
||||
CLASS_NAME PdfViewer
|
||||
pdfviewer.cpp pdfviewer.h
|
||||
zoomselector.cpp zoomselector.h
|
||||
hoverwatcher.cpp hoverwatcher.h
|
||||
)
|
||||
|
||||
set_target_properties(pdfviewer PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/app"
|
||||
)
|
||||
|
||||
target_include_directories(pdfviewer PRIVATE
|
||||
../../app
|
||||
..
|
||||
)
|
||||
|
||||
target_link_libraries(pdfviewer PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
Qt6::PdfWidgets
|
||||
abstractviewer
|
||||
)
|
||||
|
||||
if(TARGET Qt6::PrintSupport)
|
||||
target_link_libraries(pdfviewer PRIVATE Qt6::PrintSupport)
|
||||
endif()
|
||||
|
||||
install(TARGETS pdfviewer
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}/plugins"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}/plugins"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
#include "hoverwatcher.h"
|
||||
#include <QGuiApplication>
|
||||
#include <QWidget>
|
||||
#include <QMouseEvent>
|
||||
|
||||
HoverWatcher::HoverWatcher(QWidget *watched)
|
||||
: QObject(watched), m_watched(watched)
|
||||
{
|
||||
Q_ASSERT(watched);
|
||||
m_cursorShapes[Entered].emplace(Qt::OpenHandCursor);
|
||||
m_cursorShapes[MousePress].emplace(Qt::ClosedHandCursor);
|
||||
m_cursorShapes[MouseRelease].emplace(Qt::OpenHandCursor);
|
||||
// no default for Left => restore override cursor
|
||||
m_watched->installEventFilter(this);
|
||||
}
|
||||
|
||||
HoverWatcher::~HoverWatcher()
|
||||
{
|
||||
m_watched->removeEventFilter(this);
|
||||
}
|
||||
|
||||
typedef QHash<QWidget *, HoverWatcher*> WatchMap;
|
||||
Q_GLOBAL_STATIC(WatchMap, qt_allHoverWatchers)
|
||||
|
||||
HoverWatcher *HoverWatcher::watcher(QWidget *watched)
|
||||
{
|
||||
if (qt_allHoverWatchers()->contains(watched))
|
||||
return qt_allHoverWatchers()->value(watched);
|
||||
|
||||
HoverWatcher *watcher = new HoverWatcher(watched);
|
||||
qt_allHoverWatchers()->insert(watched, watcher);
|
||||
return watcher;
|
||||
}
|
||||
|
||||
/*!
|
||||
\overload Const version of watcher
|
||||
*/
|
||||
const HoverWatcher *HoverWatcher::watcher(const QWidget *watched)
|
||||
{
|
||||
return watcher(const_cast<QWidget *>(watched));
|
||||
}
|
||||
|
||||
void HoverWatcher::dismiss(QWidget *watched)
|
||||
{
|
||||
if (!hasWatcher(watched))
|
||||
return;
|
||||
|
||||
delete qt_allHoverWatchers()->take(watched);
|
||||
}
|
||||
|
||||
bool HoverWatcher::hasWatcher(QWidget *widget)
|
||||
{
|
||||
return qt_allHoverWatchers()->contains(widget);
|
||||
}
|
||||
|
||||
static constexpr HoverWatcher::HoverAction toHoverAction(QEvent::Type et)
|
||||
{
|
||||
switch (et) {
|
||||
case QEvent::Type::Enter:
|
||||
return HoverWatcher::HoverAction::Entered;
|
||||
case QEvent::Type::Leave:
|
||||
return HoverWatcher::HoverAction::Left;
|
||||
case QEvent::Type::MouseButtonPress:
|
||||
return HoverWatcher::HoverAction::MousePress;
|
||||
case QEvent::Type::MouseButtonRelease:
|
||||
return HoverWatcher::HoverAction::MouseRelease;
|
||||
default:
|
||||
return HoverWatcher::HoverAction::Ignore;
|
||||
}
|
||||
}
|
||||
|
||||
void HoverWatcher::handleAction (HoverWatcher::HoverAction action)
|
||||
{
|
||||
const Qt::CursorShape newShape = cursorShape(action);
|
||||
if (QGuiApplication::overrideCursor()
|
||||
&& (QGuiApplication::overrideCursor()->shape() == newShape
|
||||
|| action == HoverAction::Ignore)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QGuiApplication::setOverrideCursor(cursorShape(action));
|
||||
emit hoverAction(action);
|
||||
|
||||
switch (action) {
|
||||
case HoverAction::Entered:
|
||||
emit entered();
|
||||
break;
|
||||
case HoverAction::Left:
|
||||
emit left();
|
||||
break;
|
||||
case HoverAction::MousePress:
|
||||
emit mousePressed();
|
||||
break;
|
||||
case HoverAction::MouseRelease: {
|
||||
emit mouseReleased();
|
||||
}
|
||||
break;
|
||||
case HoverAction::Ignore:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool HoverWatcher::hasShape(HoverAction action) const
|
||||
{
|
||||
return action != HoverAction::Ignore && m_cursorShapes[action].has_value();
|
||||
}
|
||||
|
||||
void HoverWatcher::setApplicationCursor(HoverAction action) const
|
||||
{
|
||||
if (!hasShape(action)) {
|
||||
QGuiApplication::restoreOverrideCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
QGuiApplication::setOverrideCursor(cursorShape(action));
|
||||
}
|
||||
|
||||
bool HoverWatcher::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
Q_ASSERT(obj == m_watched); // don't install event filters elsewhere
|
||||
|
||||
// Ignore irrelevant events
|
||||
const auto action = toHoverAction(event->type());
|
||||
if (action == HoverAction::Ignore)
|
||||
return false;
|
||||
|
||||
// React to a QScroller having been installed or removed
|
||||
// A Scroller sends a fake mouse release to QPoint (-1, -1)
|
||||
// => needs to be ignored and end of scrolling processed instead
|
||||
static bool hasScroller = false;
|
||||
if (QScroller::hasScroller(m_watched) != hasScroller) {
|
||||
hasScroller = QScroller::hasScroller(m_watched);
|
||||
static QMetaObject::Connection con;
|
||||
if (hasScroller) {
|
||||
con = connect(QScroller::scroller(m_watched), &QScroller::stateChanged,
|
||||
this, &HoverWatcher::handleScrollerStateChange);
|
||||
} else {
|
||||
disconnect(con);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore fake mouse release event sent by scroller
|
||||
if (action == HoverAction::MouseRelease && hasScroller) {
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||
if (me->pos().x() < -9000000 )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore unpermitted mouse buttons
|
||||
if (action == HoverAction::MousePress) {
|
||||
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||
if (!m_mouseButtons.testFlag(me->button()))
|
||||
return false;
|
||||
}
|
||||
|
||||
handleAction(action);
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::CursorShape HoverWatcher::cursorShape(HoverAction type) const
|
||||
{
|
||||
const Qt::CursorShape fallback = Qt::ArrowCursor;
|
||||
if (type == HoverAction::Ignore)
|
||||
return fallback;
|
||||
|
||||
return m_cursorShapes[type].value_or(fallback);
|
||||
}
|
||||
|
||||
void HoverWatcher::setCursorShape(HoverAction type, Qt::CursorShape shape)
|
||||
{
|
||||
if (type == HoverAction::Ignore)
|
||||
return;
|
||||
m_cursorShapes[type].emplace(shape);
|
||||
}
|
||||
|
||||
void HoverWatcher::unSetCursorShape(HoverAction type)
|
||||
{
|
||||
if (type == HoverAction::Ignore)
|
||||
return;
|
||||
m_cursorShapes[type].reset();
|
||||
}
|
||||
|
||||
void HoverWatcher::setMouseButtons(Qt::MouseButtons buttons)
|
||||
{
|
||||
m_mouseButtons = buttons;
|
||||
}
|
||||
|
||||
void HoverWatcher::setMouseButton(Qt::MouseButton button, bool enable)
|
||||
{
|
||||
m_mouseButtons.setFlag(button, enable);;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief This slot handles a QScroller state change, in case the watched
|
||||
widget uses a scroller. It translates \param state into the appropriate
|
||||
action.
|
||||
*/
|
||||
void HoverWatcher::handleScrollerStateChange(QScroller::State state)
|
||||
{
|
||||
switch (state) {
|
||||
case QScroller::State::Pressed:
|
||||
case QScroller::State::Dragging:
|
||||
case QScroller::State::Scrolling:
|
||||
handleAction(HoverAction::MousePress);
|
||||
break;
|
||||
case QScroller::State::Inactive:
|
||||
handleAction(HoverAction::MouseRelease);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef HOVERWATCHER_H
|
||||
#define HOVERWATCHER_H
|
||||
#include <QObject>
|
||||
#include <QEvent>
|
||||
#include <QScroller>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class HoverWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
explicit HoverWatcher(QWidget *watched);
|
||||
static QMap<QWidget *, HoverWatcher *> m_hoverWatchers;
|
||||
|
||||
public:
|
||||
~HoverWatcher();
|
||||
|
||||
enum HoverAction {
|
||||
Entered,
|
||||
MousePress,
|
||||
MouseRelease,
|
||||
Left,
|
||||
Ignore
|
||||
};
|
||||
Q_ENUM(HoverAction);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
Qt::CursorShape cursorShape(HoverAction type) const;
|
||||
Qt::MouseButtons mouseButtons() const { return m_mouseButtons; }
|
||||
|
||||
static HoverWatcher *watcher(QWidget *watched);
|
||||
static const HoverWatcher *watcher(const QWidget *watched);
|
||||
static bool hasWatcher(QWidget *widget);
|
||||
static void dismiss(QWidget *watched);
|
||||
|
||||
public slots:
|
||||
void setCursorShape(HoverAction type, Qt::CursorShape shape);
|
||||
void unSetCursorShape(HoverAction type);
|
||||
void setMouseButtons(Qt::MouseButtons buttons);
|
||||
void setMouseButton(Qt::MouseButton button, bool enable);
|
||||
|
||||
signals:
|
||||
void entered();
|
||||
void mousePressed();
|
||||
void mouseReleased();
|
||||
void left();
|
||||
void hoverAction(HoverAction action);
|
||||
|
||||
private slots:
|
||||
void handleScrollerStateChange(QScroller::State state);
|
||||
|
||||
private:
|
||||
QWidget *m_watched;
|
||||
std::array<std::optional<Qt::CursorShape>, HoverAction::Ignore> m_cursorShapes;
|
||||
Qt::MouseButtons m_mouseButtons = Qt::MouseButton::LeftButton;
|
||||
void handleAction(HoverAction action);
|
||||
void setApplicationCursor(HoverAction action) const;
|
||||
bool hasShape(HoverAction action) const;
|
||||
};
|
||||
|
||||
#endif // HOVERWATCHER_H
|
||||
@@ -0,0 +1,266 @@
|
||||
// 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>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6,6,0)
|
||||
#include <QPdfPageSelector>
|
||||
#endif
|
||||
|
||||
#include <QtMath>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <QListView>
|
||||
#include <QPdfView>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <QtMath>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <QListView>
|
||||
#include <QListWidget>
|
||||
#include <QMainWindow>
|
||||
#include <QScrollBar>
|
||||
#include <QScroller>
|
||||
#include <QSpinBox>
|
||||
#include <QToolBar>
|
||||
#include <QTreeView>
|
||||
|
||||
#ifdef QT_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);
|
||||
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();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6,6,0)
|
||||
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);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
auto *actionZoomIn = m_toolBar->addAction(tr("Zoom in"));
|
||||
actionZoomIn->setToolTip(tr("Increase zoom level"));
|
||||
actionZoomIn->setIcon(QIcon(":/demos/documentviewer/images/zoom-in.png"_L1));
|
||||
m_toolBar->addAction(actionZoomIn);
|
||||
connect(actionZoomIn, &QAction::triggered, this, &PdfViewer::onActionZoomInTriggered);
|
||||
|
||||
auto *actionZoomOut = m_toolBar->addAction(tr("Zoom out"));
|
||||
actionZoomOut->setToolTip(tr("Decrease zoom level"));
|
||||
actionZoomOut->setIcon(QIcon(":/demos/documentviewer/images/zoom-out.png"_L1));
|
||||
m_toolBar->addAction(actionZoomOut);
|
||||
connect(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 QT_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 // QT_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();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PDFVIEWER_H
|
||||
#define PDFVIEWER_H
|
||||
|
||||
#include "viewerinterfaces.h"
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcExample)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMainWindow;
|
||||
class QPdfDocument;
|
||||
class QPdfView;
|
||||
class QPdfPageSelector;
|
||||
class QListView;
|
||||
class QTabWidget;
|
||||
class QTreeView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class ZoomSelector;
|
||||
class PdfViewer : public ViewerInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface" FILE "pdfviewer.json")
|
||||
Q_INTERFACES(ViewerInterface)
|
||||
public:
|
||||
PdfViewer();
|
||||
~PdfViewer() override;
|
||||
void init(QFile *file, QWidget *parent, QMainWindow *mainWindow) override;
|
||||
void cleanup() override;
|
||||
QString viewerName() const override { return QLatin1StringView(staticMetaObject.className()); };
|
||||
QStringList supportedMimeTypes() const override;
|
||||
bool supportsOverview() const override { return true; }
|
||||
bool hasContent() const override;
|
||||
QByteArray saveState() const override { return QByteArray(); }
|
||||
bool restoreState(QByteArray &) override { return true; }
|
||||
|
||||
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||
protected:
|
||||
void printDocument(QPrinter *printer) const override;
|
||||
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT
|
||||
|
||||
public slots:
|
||||
void openPdfFile();
|
||||
|
||||
private slots:
|
||||
void initPdfViewer();
|
||||
void bookmarkSelected(const QModelIndex &index);
|
||||
void pageSelected(int page);
|
||||
|
||||
// action handlers
|
||||
void onActionZoomInTriggered();
|
||||
void onActionZoomOutTriggered();
|
||||
void onActionPreviousPageTriggered();
|
||||
void onActionNextPageTriggered();
|
||||
void onActionBackTriggered();
|
||||
void onActionForwardTriggered();
|
||||
|
||||
private:
|
||||
void populateQuestions();
|
||||
|
||||
const qreal zoomMultiplier = qSqrt(2.0);
|
||||
QToolBar *m_toolBar = nullptr;
|
||||
ZoomSelector *m_zoomSelector = nullptr;
|
||||
QPdfPageSelector *m_pageSelector = nullptr;
|
||||
QPdfDocument *m_document = nullptr;
|
||||
QPdfView *m_pdfView = nullptr;
|
||||
QAction *m_actionForward = nullptr;
|
||||
QAction *m_actionBack = nullptr;
|
||||
QTreeView *m_bookmarks = nullptr;
|
||||
QListView *m_pages = nullptr;
|
||||
};
|
||||
|
||||
#endif //PDFVIEWER_H
|
||||
@@ -0,0 +1 @@
|
||||
{ "Keys": [ "pdfviewer" ] }
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "zoomselector.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
ZoomSelector::ZoomSelector(QWidget *parent)
|
||||
: QComboBox(parent)
|
||||
{
|
||||
setEditable(true);
|
||||
|
||||
addItem(tr("Fit Width"));
|
||||
addItem(tr("Fit Page"));
|
||||
addItem(tr("12%"));
|
||||
addItem(tr("25%"));
|
||||
addItem(tr("33%"));
|
||||
addItem(tr("50%"));
|
||||
addItem(tr("66%"));
|
||||
addItem(tr("75%"));
|
||||
addItem(tr("100%"));
|
||||
addItem(tr("125%"));
|
||||
addItem(tr("150%"));
|
||||
addItem(tr("200%"));
|
||||
addItem(tr("400%"));
|
||||
|
||||
connect(this, &QComboBox::currentTextChanged,
|
||||
this, &ZoomSelector::onCurrentTextChanged);
|
||||
|
||||
connect(lineEdit(), &QLineEdit::editingFinished,
|
||||
this, [this](){onCurrentTextChanged(lineEdit()->text()); });
|
||||
}
|
||||
|
||||
void ZoomSelector::setZoomFactor(qreal zoomFactor)
|
||||
{
|
||||
setCurrentText(QString::number(qRound(zoomFactor * 100)) + QLatin1String("%"));
|
||||
}
|
||||
|
||||
void ZoomSelector::reset()
|
||||
{
|
||||
setCurrentIndex(8); // 100%
|
||||
}
|
||||
|
||||
void ZoomSelector::onCurrentTextChanged(const QString &text)
|
||||
{
|
||||
if (text == QLatin1String("Fit Width")) {
|
||||
emit zoomModeChanged(QPdfView::ZoomMode::FitToWidth);
|
||||
} else if (text == QLatin1String("Fit Page")) {
|
||||
emit zoomModeChanged(QPdfView::ZoomMode::FitInView);
|
||||
} else {
|
||||
qreal factor = 1.0;
|
||||
|
||||
QString withoutPercent(text);
|
||||
withoutPercent.remove(QLatin1Char('%'));
|
||||
|
||||
bool ok = false;
|
||||
const int zoomLevel = withoutPercent.toInt(&ok);
|
||||
if (ok)
|
||||
factor = zoomLevel / 100.0;
|
||||
|
||||
emit zoomModeChanged(QPdfView::ZoomMode::Custom);
|
||||
emit zoomFactorChanged(factor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef ZOOMSELECTOR_H
|
||||
#define ZOOMSELECTOR_H
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QPdfView>
|
||||
|
||||
class ZoomSelector : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ZoomSelector(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void setZoomFactor(qreal zoomFactor);
|
||||
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
void zoomModeChanged(QPdfView::ZoomMode zoomMode);
|
||||
void zoomFactorChanged(qreal zoomFactor);
|
||||
|
||||
private slots:
|
||||
void onCurrentTextChanged(const QString &text);
|
||||
};
|
||||
|
||||
#endif // ZOOMSELECTOR_H
|
||||
Reference in New Issue
Block a user