From 7a5f37e38fd8e35fa75109cf6a2aaff358a1ac8f Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sat, 16 Dec 2023 20:23:53 +0100 Subject: [PATCH] Issue #54: Bookmarks page - model, bookmarks manager --- Pdf4QtViewer/CMakeLists.txt | 4 + Pdf4QtViewer/pdf4qtviewer.qrc | 1 + Pdf4QtViewer/pdfbookmarkmanager.cpp | 272 ++++++++++++++++++ Pdf4QtViewer/pdfbookmarkmanager.h | 74 +++++ Pdf4QtViewer/pdfbookmarkui.cpp | 173 +++++++++++ Pdf4QtViewer/pdfbookmarkui.h | 76 +++++ Pdf4QtViewer/pdfprogramcontroller.cpp | 15 + Pdf4QtViewer/pdfprogramcontroller.h | 4 + Pdf4QtViewer/pdfsidebarwidget.cpp | 13 + Pdf4QtViewer/pdfsidebarwidget.h | 6 + Pdf4QtViewer/pdfsidebarwidget.ui | 61 +++- Pdf4QtViewer/pdfviewermainwindow.cpp | 2 +- Pdf4QtViewer/pdfviewermainwindowlite.cpp | 2 +- Pdf4QtViewer/resources/sidebar-favourites.svg | 58 ++++ 14 files changed, 756 insertions(+), 5 deletions(-) create mode 100644 Pdf4QtViewer/pdfbookmarkmanager.cpp create mode 100644 Pdf4QtViewer/pdfbookmarkmanager.h create mode 100644 Pdf4QtViewer/pdfbookmarkui.cpp create mode 100644 Pdf4QtViewer/pdfbookmarkui.h create mode 100644 Pdf4QtViewer/resources/sidebar-favourites.svg diff --git a/Pdf4QtViewer/CMakeLists.txt b/Pdf4QtViewer/CMakeLists.txt index 40aeb89..e15e348 100644 --- a/Pdf4QtViewer/CMakeLists.txt +++ b/Pdf4QtViewer/CMakeLists.txt @@ -69,6 +69,10 @@ add_library(Pdf4QtViewer SHARED pdfcreatebitonaldocumentdialog.cpp pdfcreatebitonaldocumentdialog.h pdf4qtviewer.qrc + pdfbookmarkmanager.h + pdfbookmarkmanager.cpp + pdfbookmarkui.h + pdfbookmarkui.cpp ) add_compile_definitions(QT_INSTALL_DIRECTORY="${QT6_INSTALL_PREFIX}") diff --git a/Pdf4QtViewer/pdf4qtviewer.qrc b/Pdf4QtViewer/pdf4qtviewer.qrc index 9633962..b9d80e6 100644 --- a/Pdf4QtViewer/pdf4qtviewer.qrc +++ b/Pdf4QtViewer/pdf4qtviewer.qrc @@ -104,5 +104,6 @@ resources/sidebar-thumbnails.svg resources/sidebar-visibility.svg resources/outline.svg + resources/sidebar-favourites.svg diff --git a/Pdf4QtViewer/pdfbookmarkmanager.cpp b/Pdf4QtViewer/pdfbookmarkmanager.cpp new file mode 100644 index 0000000..8ae9a39 --- /dev/null +++ b/Pdf4QtViewer/pdfbookmarkmanager.cpp @@ -0,0 +1,272 @@ +// Copyright (C) 2023 Jakub Melka +// +// This file is part of PDF4QT. +// +// PDF4QT is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// with the written consent of the copyright owner, any later version. +// +// PDF4QT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDF4QT. If not, see . + +#include "pdfbookmarkmanager.h" +#include "pdfaction.h" + +#include +#include +#include + +namespace pdfviewer +{ + +class PDFBookmarkManagerHelper +{ +public: + constexpr PDFBookmarkManagerHelper() = delete; + + static QJsonObject convertBookmarkToJson(const PDFBookmarkManager::Bookmark& bookmark) + { + QJsonObject json; + json["isAuto"] = bookmark.isAuto; + json["name"] = bookmark.name; + json["pageIndex"] = bookmark.pageIndex; + return json; + } + + static PDFBookmarkManager::Bookmark convertJsonToBookmark(const QJsonObject& json) + { + PDFBookmarkManager::Bookmark bookmark; + bookmark.isAuto = json["isAuto"].toBool(); + bookmark.name = json["name"].toString(); + bookmark.pageIndex = json["pageIndex"].toInt(); + return bookmark; + } + + static QJsonObject convertBookmarksToJson(const PDFBookmarkManager::Bookmarks& bookmarks) + { + QJsonArray jsonArray; + + for (const auto& bookmark : bookmarks.bookmarks) + { + jsonArray.append(convertBookmarkToJson(bookmark)); + } + + QJsonObject jsonObject; + jsonObject["bookmarks"] = jsonArray; + return jsonObject; + } + + static PDFBookmarkManager::Bookmarks convertBookmarksFromJson(const QJsonObject& object) + { + PDFBookmarkManager::Bookmarks bookmarks; + + QJsonArray jsonArray = object["bookmarks"].toArray(); + + for (const auto& jsonValue : jsonArray) + { + bookmarks.bookmarks.push_back(convertJsonToBookmark(jsonValue.toObject())); + } + + return bookmarks; + } + + static QJsonDocument convertBookmarksMapToJsonDocument(const std::map& bookmarksMap) + { + QJsonObject mainObject; + for (const auto& pair : bookmarksMap) + { + mainObject[pair.first] = convertBookmarksToJson(pair.second); + } + return QJsonDocument(mainObject); + } + + static std::map convertBookmarksMapFromJsonDocument(const QJsonDocument &doc) + { + std::map container; + QJsonObject mainObject = doc.object(); + + for (auto it = mainObject.begin(); it != mainObject.end(); ++it) + { + container[it.key()] = convertBookmarksFromJson(it.value().toObject()); + } + + return container; + } +}; + +PDFBookmarkManager::PDFBookmarkManager(QObject* parent) : + BaseClass(parent) +{ + +} + +void PDFBookmarkManager::setDocument(const pdf::PDFModifiedDocument& document) +{ + Q_EMIT bookmarksAboutToBeChanged(); + + const bool init = !m_document; + m_document = document.getDocument(); + + QString key; + + if (document.hasPreserveView() && m_document) + { + // Pass the key + key = QString::fromLatin1(m_document->getSourceDataHash().toHex()); + + if (m_bookmarks.count(m_currentKey) && m_currentKey != key) + { + m_bookmarks[key] = m_bookmarks[m_currentKey]; + m_bookmarks.erase(m_currentKey); + } + } + + if (init && m_document) + { + key = QString::fromLatin1(m_document->getSourceDataHash().toHex()); + } + + if (key.isEmpty()) + { + key = "generic"; + } + + m_currentKey = key; + + if (document.hasReset() && !document.hasPreserveView()) + { + regenerateAutoBookmarks(); + } + + Q_EMIT bookmarksChanged(); +} + +void PDFBookmarkManager::saveToFile(QString fileName) +{ + QJsonDocument doc = PDFBookmarkManagerHelper::convertBookmarksMapToJsonDocument(m_bookmarks); + + // Příklad zápisu do souboru + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) + { + file.write(doc.toJson()); + file.close(); + } +} + +bool PDFBookmarkManager::loadFromFile(QString fileName) +{ + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) + { + QJsonDocument loadedDoc = QJsonDocument::fromJson(file.readAll()); + file.close(); + + m_bookmarks = PDFBookmarkManagerHelper::convertBookmarksMapFromJsonDocument(loadedDoc); + return true; + } + + return false; +} + +int PDFBookmarkManager::getBookmarkCount() const +{ + if (m_bookmarks.count(m_currentKey)) + { + return m_bookmarks.at(m_currentKey).bookmarks.size(); + } + + return 0; +} + +PDFBookmarkManager::Bookmark PDFBookmarkManager::getBookmark(int index) const +{ + if (m_bookmarks.count(m_currentKey)) + { + return m_bookmarks.at(m_currentKey).bookmarks.at(index); + } + + return Bookmark(); +} + +void PDFBookmarkManager::regenerateAutoBookmarks() +{ + if (!m_document) + { + return; + } + + // Create bookmarks for all main chapters + Bookmarks& bookmarks = m_bookmarks[m_currentKey]; + + for (auto it = bookmarks.bookmarks.begin(); it != bookmarks.bookmarks.end();) + { + if (it->isAuto) + { + it = bookmarks.bookmarks.erase(it); + } + else + { + ++it; + } + } + + if (auto outlineRoot = m_document->getCatalog()->getOutlineRootPtr()) + { + size_t childCount = outlineRoot->getChildCount(); + for (size_t i = 0; i < childCount; ++i) + { + Bookmark bookmark; + bookmark.isAuto = true; + bookmark.pageIndex = pdf::PDFCatalog::INVALID_PAGE_INDEX; + + const pdf::PDFOutlineItem* child = outlineRoot->getChild(i); + const pdf::PDFAction* action = child->getAction(); + + if (action) + { + for (const pdf::PDFAction* currentAction : action->getActionList()) + { + if (currentAction->getType() != pdf::ActionType::GoTo) + { + continue; + } + + const pdf::PDFActionGoTo* typedAction = dynamic_cast(currentAction); + pdf::PDFDestination destination = typedAction->getDestination(); + if (destination.getDestinationType() == pdf::DestinationType::Named) + { + if (const pdf::PDFDestination* targetDestination = m_document->getCatalog()->getNamedDestination(destination.getName())) + { + destination = *targetDestination; + } + } + + if (destination.getDestinationType() != pdf::DestinationType::Invalid && + destination.getPageReference() != pdf::PDFObjectReference()) + { + const size_t pageIndex = m_document->getCatalog()->getPageIndexFromPageReference(destination.getPageReference()); + if (pageIndex != pdf::PDFCatalog::INVALID_PAGE_INDEX) + { + bookmark.pageIndex = pageIndex; + bookmark.name = child->getTitle(); + } + } + } + } + + if (bookmark.pageIndex != pdf::PDFCatalog::INVALID_PAGE_INDEX) + { + bookmarks.bookmarks.emplace_back(std::move(bookmark)); + } + } + } +} + +} // namespace pdf diff --git a/Pdf4QtViewer/pdfbookmarkmanager.h b/Pdf4QtViewer/pdfbookmarkmanager.h new file mode 100644 index 0000000..fd68760 --- /dev/null +++ b/Pdf4QtViewer/pdfbookmarkmanager.h @@ -0,0 +1,74 @@ +// Copyright (C) 2023 Jakub Melka +// +// This file is part of PDF4QT. +// +// PDF4QT is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// with the written consent of the copyright owner, any later version. +// +// PDF4QT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDF4QT. If not, see . + +#ifndef PDFBOOKMARKMANAGER_H +#define PDFBOOKMARKMANAGER_H + +#include "pdfdocument.h" + +#include + +namespace pdfviewer +{ + +class PDFBookmarkManager : public QObject +{ + Q_OBJECT + +private: + using BaseClass = QObject; + +public: + PDFBookmarkManager(QObject* parent); + + void setDocument(const pdf::PDFModifiedDocument& document); + + void saveToFile(QString fileName); + bool loadFromFile(QString fileName); + + struct Bookmark + { + bool isAuto = false; + QString name; + pdf::PDFInteger pageIndex = -1; + }; + + int getBookmarkCount() const; + Bookmark getBookmark(int index) const; + +signals: + void bookmarksAboutToBeChanged(); + void bookmarksChanged(); + +private: + friend class PDFBookmarkManagerHelper; + + void regenerateAutoBookmarks(); + + struct Bookmarks + { + std::vector bookmarks; + }; + + pdf::PDFDocument* m_document; + QString m_currentKey; + std::map m_bookmarks; +}; + +} // namespace pdf + +#endif // PDFBOOKMARKMANAGER_H diff --git a/Pdf4QtViewer/pdfbookmarkui.cpp b/Pdf4QtViewer/pdfbookmarkui.cpp new file mode 100644 index 0000000..e53d278 --- /dev/null +++ b/Pdf4QtViewer/pdfbookmarkui.cpp @@ -0,0 +1,173 @@ +// Copyright (C) 2023 Jakub Melka +// +// This file is part of PDF4QT. +// +// PDF4QT is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// with the written consent of the copyright owner, any later version. +// +// PDF4QT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDF4QT. If not, see . + +#include "pdfbookmarkui.h" +#include "pdfwidgetutils.h" + +#include +#include + +namespace pdfviewer +{ + +PDFBookmarkItemModel::PDFBookmarkItemModel(PDFBookmarkManager* bookmarkManager, QObject* parent) : + BaseClass(parent), + m_bookmarkManager(bookmarkManager) +{ + connect(m_bookmarkManager, &PDFBookmarkManager::bookmarksAboutToBeChanged, this, &PDFBookmarkItemModel::beginResetModel); + connect(m_bookmarkManager, &PDFBookmarkManager::bookmarksChanged, this, &PDFBookmarkItemModel::endResetModel); +} + +QModelIndex PDFBookmarkItemModel::index(int row, int column, const QModelIndex& parent) const +{ + return createIndex(row, column, nullptr); +} + +QModelIndex PDFBookmarkItemModel::parent(const QModelIndex& child) const +{ + return QModelIndex(); +} + +int PDFBookmarkItemModel::rowCount(const QModelIndex& parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return m_bookmarkManager ? m_bookmarkManager->getBookmarkCount() : 0; +} + +int PDFBookmarkItemModel::columnCount(const QModelIndex& parent) const +{ + return 1; +} + +QVariant PDFBookmarkItemModel::data(const QModelIndex& index, int role) const +{ + if (role == Qt::DisplayRole) + { + return m_bookmarkManager->getBookmark(index.row()).name; + } + + return QVariant(); +} + +PDFBookmarkItemDelegate::PDFBookmarkItemDelegate(PDFBookmarkManager* bookmarkManager, QObject* parent) : + BaseClass(parent), + m_bookmarkManager(bookmarkManager) +{ + +} + +void PDFBookmarkItemDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QStyleOptionViewItem options = option; + initStyleOption(&options, index); + + PDFBookmarkManager::Bookmark bookmark = m_bookmarkManager->getBookmark(index.row()); + + options.text = QString(); + options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter); + + const int margin = pdf::PDFWidgetUtils::scaleDPI_x(option.widget, MARGIN); + const int iconSize = pdf::PDFWidgetUtils::scaleDPI_x(option.widget, ICON_SIZE); + + QRect rect = options.rect; + rect.marginsRemoved(QMargins(margin, margin, margin, margin)); + + QRect iconRect = rect; + iconRect.setWidth(iconSize); + iconRect.setHeight(iconSize); + iconRect.moveCenter(QPoint(rect.left() + iconSize / 2, rect.center().y())); + drawStar(*painter, iconRect.center(), iconRect.width() * 0.5, QColor(64, 64, 192)); + + QRect textRect = rect; + textRect.setLeft(iconRect.right() + margin); + + textRect.setHeight(options.fontMetrics.lineSpacing()); + + QFont font = options.font; + font.setBold(true); + + painter->setFont(font); + painter->drawText(textRect, getPageText(bookmark)); + + textRect.translate(0, textRect.height()); + + painter->setFont(options.font); + painter->drawText(textRect, bookmark.name); +} + +QSize PDFBookmarkItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + PDFBookmarkManager::Bookmark bookmark = m_bookmarkManager->getBookmark(index.row()); + + const int textWidthLine1 = option.fontMetrics.horizontalAdvance(getPageText(bookmark)); + const int textWidthLine2 = option.fontMetrics.horizontalAdvance(option.text); + const int textWidth = qMax(textWidthLine1, textWidthLine2); + const int textHeight = option.fontMetrics.lineSpacing() * 2; + + const int margin = pdf::PDFWidgetUtils::scaleDPI_x(option.widget, MARGIN); + const int iconSize = pdf::PDFWidgetUtils::scaleDPI_x(option.widget, ICON_SIZE); + + const int requiredWidth = 3 * margin + iconSize + textWidth; + const int requiredHeight = 2 * margin + qMax(iconSize, textHeight); + + return QSize(requiredWidth, requiredHeight); +} + +void PDFBookmarkItemDelegate::drawStar(QPainter& painter, const QPointF& center, double size, const QColor& color) const +{ + painter.save(); + + painter.setPen(Qt::NoPen); + painter.setBrush(color); + + QPainterPath path; + double angle = M_PI / 5; + + for (int i = 0; i < 10; ++i) + { + double radius = (i % 2 == 0) ? size : size / 2.5; + QPointF point(radius * cos(i * angle), radius * sin(i * angle)); + point += center; + + if (i == 0) + { + path.moveTo(point); + } + else + { + path.lineTo(point); + } + } + path.closeSubpath(); + + painter.drawPath(path); + + painter.restore(); +} + +QString PDFBookmarkItemDelegate::getPageText(const PDFBookmarkManager::Bookmark& bookmark) const +{ + return tr("Page %1").arg(bookmark.pageIndex + 1); +} + +} // namespace pdfviewer diff --git a/Pdf4QtViewer/pdfbookmarkui.h b/Pdf4QtViewer/pdfbookmarkui.h new file mode 100644 index 0000000..4aa8200 --- /dev/null +++ b/Pdf4QtViewer/pdfbookmarkui.h @@ -0,0 +1,76 @@ +// Copyright (C) 2023 Jakub Melka +// +// This file is part of PDF4QT. +// +// PDF4QT is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// with the written consent of the copyright owner, any later version. +// +// PDF4QT is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDF4QT. If not, see . + +#ifndef PDFBOOKMARKUI_H +#define PDFBOOKMARKUI_H + +#include "pdfviewerglobal.h" +#include "pdfbookmarkmanager.h" + +#include +#include + +namespace pdfviewer +{ + +class PDFBookmarkItemModel : public QAbstractItemModel +{ + Q_OBJECT + +private: + using BaseClass = QAbstractItemModel; + +public: + PDFBookmarkItemModel(PDFBookmarkManager* bookmarkManager, QObject* parent); + + virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override; + virtual QModelIndex parent(const QModelIndex& child) const override; + virtual int rowCount(const QModelIndex& parent) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual QVariant data(const QModelIndex& index, int role) const override; + +private: + PDFBookmarkManager* m_bookmarkManager = nullptr; +}; + +class PDFBookmarkItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +private: + using BaseClass = QStyledItemDelegate; + +public: + PDFBookmarkItemDelegate(PDFBookmarkManager* bookmarkManager, QObject* parent); + + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; + +private: + static constexpr int MARGIN = 6; + static constexpr int ICON_SIZE = 32; + + void drawStar(QPainter& painter, const QPointF& center, double size, const QColor& color) const; + + QString getPageText(const PDFBookmarkManager::Bookmark& bookmark) const; + + PDFBookmarkManager* m_bookmarkManager = nullptr; +}; + +} // namespace pdfviewer + +#endif // PDFBOOKMARKUI_H diff --git a/Pdf4QtViewer/pdfprogramcontroller.cpp b/Pdf4QtViewer/pdfprogramcontroller.cpp index 4b94c8d..8110c3b 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.cpp +++ b/Pdf4QtViewer/pdfprogramcontroller.cpp @@ -361,6 +361,7 @@ PDFProgramController::PDFProgramController(QObject* parent) : m_toolManager(nullptr), m_annotationManager(nullptr), m_formManager(nullptr), + m_bookmarkManager(nullptr), m_isBusy(false), m_isFactorySettingsBeingRestored(false), m_progress(nullptr) @@ -375,6 +376,9 @@ PDFProgramController::~PDFProgramController() delete m_annotationManager; m_annotationManager = nullptr; + + delete m_bookmarkManager; + m_bookmarkManager = nullptr; } void PDFProgramController::initializeAnnotationManager() @@ -396,6 +400,11 @@ void PDFProgramController::initializeFormManager() connect(m_formManager, &pdf::PDFFormManager::documentModified, this, &PDFProgramController::onDocumentModified); } +void PDFProgramController::initializeBookmarkManager() +{ + m_bookmarkManager = new PDFBookmarkManager(this); +} + void PDFProgramController::initialize(Features features, QMainWindow* mainWindow, IMainWindow* mainWindowInterface, @@ -605,6 +614,7 @@ void PDFProgramController::initialize(Features features, } initializeAnnotationManager(); + initializeBookmarkManager(); if (features.testFlag(Forms)) { @@ -1915,6 +1925,11 @@ void PDFProgramController::setDocument(pdf::PDFModifiedDocument document, bool i m_annotationManager->setDocument(document); } + if (m_bookmarkManager) + { + m_bookmarkManager->setDocument(document); + } + if (m_formManager) { m_formManager->setDocument(document); diff --git a/Pdf4QtViewer/pdfprogramcontroller.h b/Pdf4QtViewer/pdfprogramcontroller.h index e179606..8be65c2 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.h +++ b/Pdf4QtViewer/pdfprogramcontroller.h @@ -24,6 +24,7 @@ #include "pdfdocumentreader.h" #include "pdfdocumentpropertiesdialog.h" #include "pdfplugin.h" +#include "pdfbookmarkmanager.h" #include #include @@ -275,6 +276,7 @@ public: PDFViewerSettings* getSettings() const { return m_settings; } pdf::PDFDocument* getDocument() const { return m_pdfDocument.data(); } pdf::PDFCertificateStore* getCertificateStore() const { return const_cast(&m_certificateStore); } + PDFBookmarkManager* getBookmarkManager() const { return m_bookmarkManager; } PDFTextToSpeech* getTextToSpeech() const { return m_textToSpeech; } const std::vector* getSignatures() const { return &m_signatures; } @@ -326,6 +328,7 @@ private: void initializeToolManager(); void initializeAnnotationManager(); void initializeFormManager(); + void initializeBookmarkManager(); void onActionGoToDocumentStartTriggered(); void onActionGoToDocumentEndTriggered(); @@ -422,6 +425,7 @@ private: pdf::PDFToolManager* m_toolManager; pdf::PDFWidgetAnnotationManager* m_annotationManager; pdf::PDFWidgetFormManager* m_formManager; + PDFBookmarkManager* m_bookmarkManager; PDFFileInfo m_fileInfo; QFileSystemWatcher m_fileWatcher; diff --git a/Pdf4QtViewer/pdfsidebarwidget.cpp b/Pdf4QtViewer/pdfsidebarwidget.cpp index babe0a2..9fce464 100644 --- a/Pdf4QtViewer/pdfsidebarwidget.cpp +++ b/Pdf4QtViewer/pdfsidebarwidget.cpp @@ -33,6 +33,7 @@ #include "pdfdrawspacecontroller.h" #include "pdfdocumentbuilder.h" #include "pdfwidgetutils.h" +#include "pdfbookmarkui.h" #include #include @@ -60,6 +61,7 @@ constexpr const char* STYLESHEET = PDFSidebarWidget::PDFSidebarWidget(pdf::PDFDrawWidgetProxy* proxy, PDFTextToSpeech* textToSpeech, pdf::PDFCertificateStore* certificateStore, + PDFBookmarkManager* bookmarkManager, PDFViewerSettings* settings, bool editableOutline, QWidget* parent) : @@ -68,10 +70,12 @@ PDFSidebarWidget::PDFSidebarWidget(pdf::PDFDrawWidgetProxy* proxy, m_proxy(proxy), m_textToSpeech(textToSpeech), m_certificateStore(certificateStore), + m_bookmarkManager(bookmarkManager), m_settings(settings), m_outlineTreeModel(nullptr), m_thumbnailsModel(nullptr), m_optionalContentTreeModel(nullptr), + m_bookmarkItemModel(nullptr), m_document(nullptr), m_optionalContentActivity(nullptr), m_attachmentsTreeModel(nullptr) @@ -126,6 +130,11 @@ PDFSidebarWidget::PDFSidebarWidget(pdf::PDFDrawWidgetProxy* proxy, ui->attachmentsTreeView->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->attachmentsTreeView, &QTreeView::customContextMenuRequested, this, &PDFSidebarWidget::onAttachmentCustomContextMenuRequested); + // Bookmarks + m_bookmarkItemModel = new PDFBookmarkItemModel(bookmarkManager, this); + ui->bookmarksView->setModel(m_bookmarkItemModel); + ui->bookmarksView->setItemDelegate(new PDFBookmarkItemDelegate(bookmarkManager, this)); + m_pageInfo[Invalid] = { nullptr, ui->emptyPage }; m_pageInfo[OptionalContent] = { ui->optionalContentButton, ui->optionalContentPage }; m_pageInfo[Outline] = { ui->outlineButton, ui->outlinePage }; @@ -133,6 +142,7 @@ PDFSidebarWidget::PDFSidebarWidget(pdf::PDFDrawWidgetProxy* proxy, m_pageInfo[Attachments] = { ui->attachmentsButton, ui->attachmentsPage }; m_pageInfo[Speech] = { ui->speechButton, ui->speechPage }; m_pageInfo[Signatures] = { ui->signaturesButton, ui->signaturesPage }; + m_pageInfo[Bookmarks] = { ui->bookmarksButton, ui->bookmarksPage }; for (const auto& pageInfo : m_pageInfo) { @@ -271,6 +281,9 @@ bool PDFSidebarWidget::isEmpty(Page page) const case Attachments: return m_attachmentsTreeModel->isEmpty(); + case Bookmarks: + return !m_document || !m_bookmarkManager; + case Speech: return !m_textToSpeech->isValid(); diff --git a/Pdf4QtViewer/pdfsidebarwidget.h b/Pdf4QtViewer/pdfsidebarwidget.h index e65aee4..f7ee57b 100644 --- a/Pdf4QtViewer/pdfsidebarwidget.h +++ b/Pdf4QtViewer/pdfsidebarwidget.h @@ -20,6 +20,7 @@ #define PDFSIDEBARWIDGET_H #include "pdfglobal.h" +#include "pdfbookmarkmanager.h" #include @@ -52,6 +53,7 @@ namespace pdfviewer { class PDFTextToSpeech; class PDFViewerSettings; +class PDFBookmarkItemModel; class PDFSidebarWidget : public QWidget { @@ -61,6 +63,7 @@ public: explicit PDFSidebarWidget(pdf::PDFDrawWidgetProxy* proxy, PDFTextToSpeech* textToSpeech, pdf::PDFCertificateStore* certificateStore, + PDFBookmarkManager* bookmarkManager, PDFViewerSettings* settings, bool editableOutline, QWidget* parent); @@ -78,6 +81,7 @@ public: Attachments, Speech, Signatures, + Bookmarks, _END }; @@ -126,10 +130,12 @@ private: pdf::PDFDrawWidgetProxy* m_proxy; PDFTextToSpeech* m_textToSpeech; pdf::PDFCertificateStore* m_certificateStore; + PDFBookmarkManager* m_bookmarkManager; PDFViewerSettings* m_settings; pdf::PDFOutlineTreeItemModel* m_outlineTreeModel; pdf::PDFThumbnailsItemModel* m_thumbnailsModel; pdf::PDFOptionalContentTreeItemModel* m_optionalContentTreeModel; + PDFBookmarkItemModel* m_bookmarkItemModel; const pdf::PDFDocument* m_document; pdf::PDFOptionalContentActivity* m_optionalContentActivity; pdf::PDFAttachmentsTreeItemModel* m_attachmentsTreeModel; diff --git a/Pdf4QtViewer/pdfsidebarwidget.ui b/Pdf4QtViewer/pdfsidebarwidget.ui index f6f6d9f..04ea4ef 100644 --- a/Pdf4QtViewer/pdfsidebarwidget.ui +++ b/Pdf4QtViewer/pdfsidebarwidget.ui @@ -6,8 +6,8 @@ 0 0 - 339 - 584 + 388 + 681 @@ -225,6 +225,35 @@ + + + + + 96 + 0 + + + + Bookmarks + + + + :/resources/sidebar-favourites.svg:/resources/sidebar-favourites.svg + + + + 64 + 64 + + + + true + + + Qt::ToolButtonTextUnderIcon + + + @@ -243,7 +272,7 @@ - 1 + 5 @@ -383,6 +412,32 @@ + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + diff --git a/Pdf4QtViewer/pdfviewermainwindow.cpp b/Pdf4QtViewer/pdfviewermainwindow.cpp index 3d8f231..50dd398 100644 --- a/Pdf4QtViewer/pdfviewermainwindow.cpp +++ b/Pdf4QtViewer/pdfviewermainwindow.cpp @@ -269,7 +269,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) : setCentralWidget(m_programController->getPdfWidget()); setFocusProxy(m_programController->getPdfWidget()); - m_sidebarWidget = new PDFSidebarWidget(m_programController->getPdfWidget()->getDrawWidgetProxy(), m_programController->getTextToSpeech(), m_programController->getCertificateStore(), m_programController->getSettings(), true, this); + m_sidebarWidget = new PDFSidebarWidget(m_programController->getPdfWidget()->getDrawWidgetProxy(), m_programController->getTextToSpeech(), m_programController->getCertificateStore(), m_programController->getBookmarkManager(), m_programController->getSettings(), true, this); m_sidebarDockWidget = new QDockWidget(tr("Sidebar"), this); m_sidebarDockWidget->setObjectName("SidebarDockWidget"); m_sidebarDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); diff --git a/Pdf4QtViewer/pdfviewermainwindowlite.cpp b/Pdf4QtViewer/pdfviewermainwindowlite.cpp index 28b6073..ed2713c 100644 --- a/Pdf4QtViewer/pdfviewermainwindowlite.cpp +++ b/Pdf4QtViewer/pdfviewermainwindowlite.cpp @@ -202,7 +202,7 @@ PDFViewerMainWindowLite::PDFViewerMainWindowLite(QWidget* parent) : setCentralWidget(m_programController->getPdfWidget()); setFocusProxy(m_programController->getPdfWidget()); - m_sidebarWidget = new PDFSidebarWidget(m_programController->getPdfWidget()->getDrawWidgetProxy(), m_programController->getTextToSpeech(), m_programController->getCertificateStore(), m_programController->getSettings(), false, this); + m_sidebarWidget = new PDFSidebarWidget(m_programController->getPdfWidget()->getDrawWidgetProxy(), m_programController->getTextToSpeech(), m_programController->getCertificateStore(), m_programController->getBookmarkManager(), m_programController->getSettings(), false, this); m_sidebarDockWidget = new QDockWidget(tr("Sidebar"), this); m_sidebarDockWidget->setObjectName("SidebarDockWidget"); m_sidebarDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); diff --git a/Pdf4QtViewer/resources/sidebar-favourites.svg b/Pdf4QtViewer/resources/sidebar-favourites.svg new file mode 100644 index 0000000..f9804e2 --- /dev/null +++ b/Pdf4QtViewer/resources/sidebar-favourites.svg @@ -0,0 +1,58 @@ + + + + + + + + image/svg+xml + + + + + + + + +