making clangd happy and making script to compile/build with run.sh

This commit is contained in:
talksik
2024-02-07 13:12:51 -08:00
commit 45c681e7be
79 changed files with 4235 additions and 0 deletions
+39
View File
@@ -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"
)
+212
View File
@@ -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;
}
}
+69
View File
@@ -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
+266
View File
@@ -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 &current, 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();
}
+76
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
{ "Keys": [ "pdfviewer" ] }
+64
View File
@@ -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);
}
}
+30
View File
@@ -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