From e9ca3a4a821978ecc8c1d38a8b9a4e187cdcd868 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sun, 17 Dec 2023 18:11:49 +0100 Subject: [PATCH] Issue #54: Finishing of bookmarking --- Pdf4QtViewer/pdf4qtviewer.qrc | 3 + Pdf4QtViewer/pdfbookmarkmanager.cpp | 159 +++++++++++++----- Pdf4QtViewer/pdfbookmarkmanager.h | 15 +- Pdf4QtViewer/pdfbookmarkui.cpp | 39 ++++- Pdf4QtViewer/pdfprogramcontroller.cpp | 101 +++++++++++ Pdf4QtViewer/pdfprogramcontroller.h | 14 ++ Pdf4QtViewer/pdfsidebarwidget.cpp | 43 +++++ Pdf4QtViewer/pdfsidebarwidget.h | 4 + Pdf4QtViewer/pdfviewermainwindow.cpp | 6 + Pdf4QtViewer/pdfviewermainwindow.ui | 106 ++++++++++++ Pdf4QtViewer/pdfviewermainwindowlite.cpp | 6 + Pdf4QtViewer/pdfviewermainwindowlite.ui | 108 ++++++++++++ Pdf4QtViewer/pdfviewersettings.cpp | 11 +- Pdf4QtViewer/pdfviewersettings.h | 3 + Pdf4QtViewer/resources/bookmark-next.svg | 75 +++++++++ Pdf4QtViewer/resources/bookmark-previous.svg | 75 +++++++++ Pdf4QtViewer/resources/bookmark.svg | 70 ++++++++ Pdf4QtViewer/resources/sidebar-favourites.svg | 26 ++- 18 files changed, 808 insertions(+), 56 deletions(-) create mode 100644 Pdf4QtViewer/resources/bookmark-next.svg create mode 100644 Pdf4QtViewer/resources/bookmark-previous.svg create mode 100644 Pdf4QtViewer/resources/bookmark.svg diff --git a/Pdf4QtViewer/pdf4qtviewer.qrc b/Pdf4QtViewer/pdf4qtviewer.qrc index b9d80e6..37379d8 100644 --- a/Pdf4QtViewer/pdf4qtviewer.qrc +++ b/Pdf4QtViewer/pdf4qtviewer.qrc @@ -105,5 +105,8 @@ resources/sidebar-visibility.svg resources/outline.svg resources/sidebar-favourites.svg + resources/bookmark.svg + resources/bookmark-next.svg + resources/bookmark-previous.svg diff --git a/Pdf4QtViewer/pdfbookmarkmanager.cpp b/Pdf4QtViewer/pdfbookmarkmanager.cpp index 8ae9a39..b78c3f2 100644 --- a/Pdf4QtViewer/pdfbookmarkmanager.cpp +++ b/Pdf4QtViewer/pdfbookmarkmanager.cpp @@ -110,46 +110,23 @@ 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) + if (document.hasReset()) { - // Pass the key - key = QString::fromLatin1(m_document->getSourceDataHash().toHex()); - - if (m_bookmarks.count(m_currentKey) && m_currentKey != key) + if (!document.hasPreserveView()) { - m_bookmarks[key] = m_bookmarks[m_currentKey]; - m_bookmarks.erase(m_currentKey); + m_bookmarks.bookmarks.clear(); + regenerateAutoBookmarks(); } } - 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); + QJsonDocument doc(PDFBookmarkManagerHelper::convertBookmarksToJson(m_bookmarks)); // Příklad zápisu do souboru QFile file(fileName); @@ -168,31 +145,130 @@ bool PDFBookmarkManager::loadFromFile(QString fileName) QJsonDocument loadedDoc = QJsonDocument::fromJson(file.readAll()); file.close(); - m_bookmarks = PDFBookmarkManagerHelper::convertBookmarksMapFromJsonDocument(loadedDoc); + Q_EMIT bookmarksAboutToBeChanged(); + m_bookmarks = PDFBookmarkManagerHelper::convertBookmarksFromJson(loadedDoc.object()); + Q_EMIT bookmarksChanged(); return true; } return false; } +bool PDFBookmarkManager::isEmpty() const +{ + return m_bookmarks.bookmarks.empty(); +} + int PDFBookmarkManager::getBookmarkCount() const { - if (m_bookmarks.count(m_currentKey)) - { - return m_bookmarks.at(m_currentKey).bookmarks.size(); - } - - return 0; + return static_cast(m_bookmarks.bookmarks.size()); } PDFBookmarkManager::Bookmark PDFBookmarkManager::getBookmark(int index) const { - if (m_bookmarks.count(m_currentKey)) + return m_bookmarks.bookmarks.at(index); +} + +void PDFBookmarkManager::toggleBookmark(pdf::PDFInteger pageIndex) +{ + Q_EMIT bookmarksAboutToBeChanged(); + + auto it = std::find_if(m_bookmarks.bookmarks.begin(), m_bookmarks.bookmarks.end(), [pageIndex](const auto& bookmark) { return bookmark.pageIndex == pageIndex; }); + if (it != m_bookmarks.bookmarks.cend()) { - return m_bookmarks.at(m_currentKey).bookmarks.at(index); + Bookmark& bookmark = *it; + if (bookmark.isAuto) + { + bookmark.isAuto = false; + } + else + { + m_bookmarks.bookmarks.erase(it); + } + } + else + { + Bookmark bookmark; + bookmark.isAuto = false; + bookmark.name = tr("User bookmark for page %1").arg(pageIndex + 1); + bookmark.pageIndex = pageIndex; + m_bookmarks.bookmarks.push_back(bookmark); + sortBookmarks(); } - return Bookmark(); + Q_EMIT bookmarksChanged(); +} + +void PDFBookmarkManager::setGenerateBookmarksAutomatically(bool generateBookmarksAutomatically) +{ + if (m_generateBookmarksAutomatically != generateBookmarksAutomatically) + { + Q_EMIT bookmarksAboutToBeChanged(); + m_generateBookmarksAutomatically = generateBookmarksAutomatically; + regenerateAutoBookmarks(); + Q_EMIT bookmarksChanged(); + } +} + +void PDFBookmarkManager::goToNextBookmark() +{ + if (isEmpty()) + { + return; + } + + m_currentBookmark = (m_currentBookmark + 1) % getBookmarkCount(); + goToCurrentBookmark(); +} + +void PDFBookmarkManager::goToPreviousBookmark() +{ + if (isEmpty()) + { + return; + } + + if (m_currentBookmark <= 0) + { + m_currentBookmark = getBookmarkCount() - 1; + } + else + { + --m_currentBookmark; + } + + goToCurrentBookmark(); +} + +void PDFBookmarkManager::goToCurrentBookmark() +{ + if (isEmpty()) + { + return; + } + + if (m_currentBookmark >= 0 && m_currentBookmark < getBookmarkCount()) + { + Q_EMIT bookmarkActivated(m_currentBookmark, m_bookmarks.bookmarks.at(m_currentBookmark)); + } +} + +void PDFBookmarkManager::goToBookmark(int index, bool force) +{ + if (m_currentBookmark != index || force) + { + m_currentBookmark = index; + goToCurrentBookmark(); + } +} + +void PDFBookmarkManager::sortBookmarks() +{ + auto predicate = [](const auto& l, const auto& r) + { + return l.pageIndex < r.pageIndex; + }; + std::sort(m_bookmarks.bookmarks.begin(), m_bookmarks.bookmarks.end(), predicate); } void PDFBookmarkManager::regenerateAutoBookmarks() @@ -203,7 +279,7 @@ void PDFBookmarkManager::regenerateAutoBookmarks() } // Create bookmarks for all main chapters - Bookmarks& bookmarks = m_bookmarks[m_currentKey]; + Bookmarks& bookmarks = m_bookmarks; for (auto it = bookmarks.bookmarks.begin(); it != bookmarks.bookmarks.end();) { @@ -217,6 +293,11 @@ void PDFBookmarkManager::regenerateAutoBookmarks() } } + if (!m_generateBookmarksAutomatically) + { + return; + } + if (auto outlineRoot = m_document->getCatalog()->getOutlineRootPtr()) { size_t childCount = outlineRoot->getChildCount(); diff --git a/Pdf4QtViewer/pdfbookmarkmanager.h b/Pdf4QtViewer/pdfbookmarkmanager.h index fd68760..ac7fc99 100644 --- a/Pdf4QtViewer/pdfbookmarkmanager.h +++ b/Pdf4QtViewer/pdfbookmarkmanager.h @@ -47,16 +47,26 @@ public: pdf::PDFInteger pageIndex = -1; }; + bool isEmpty() const; int getBookmarkCount() const; Bookmark getBookmark(int index) const; + void toggleBookmark(pdf::PDFInteger pageIndex); + void setGenerateBookmarksAutomatically(bool generateBookmarksAutomatically); + + void goToNextBookmark(); + void goToPreviousBookmark(); + void goToCurrentBookmark(); + void goToBookmark(int index, bool force); signals: void bookmarksAboutToBeChanged(); void bookmarksChanged(); + void bookmarkActivated(int index, Bookmark bookmark); private: friend class PDFBookmarkManagerHelper; + void sortBookmarks(); void regenerateAutoBookmarks(); struct Bookmarks @@ -65,8 +75,9 @@ private: }; pdf::PDFDocument* m_document; - QString m_currentKey; - std::map m_bookmarks; + Bookmarks m_bookmarks; + int m_currentBookmark = -1; + bool m_generateBookmarksAutomatically = true; }; } // namespace pdf diff --git a/Pdf4QtViewer/pdfbookmarkui.cpp b/Pdf4QtViewer/pdfbookmarkui.cpp index e53d278..48d52a0 100644 --- a/Pdf4QtViewer/pdfbookmarkui.cpp +++ b/Pdf4QtViewer/pdfbookmarkui.cpp @@ -17,6 +17,7 @@ #include "pdfbookmarkui.h" #include "pdfwidgetutils.h" +#include "pdfpainterutils.h" #include #include @@ -34,11 +35,17 @@ PDFBookmarkItemModel::PDFBookmarkItemModel(PDFBookmarkManager* bookmarkManager, QModelIndex PDFBookmarkItemModel::index(int row, int column, const QModelIndex& parent) const { + if (parent.isValid()) + { + return QModelIndex(); + } + return createIndex(row, column, nullptr); } QModelIndex PDFBookmarkItemModel::parent(const QModelIndex& child) const { + Q_UNUSED(child); return QModelIndex(); } @@ -54,6 +61,11 @@ int PDFBookmarkItemModel::rowCount(const QModelIndex& parent) const int PDFBookmarkItemModel::columnCount(const QModelIndex& parent) const { + if (parent.isValid()) + { + return 0; + } + return 1; } @@ -92,14 +104,22 @@ void PDFBookmarkItemDelegate::paint(QPainter* painter, QRect rect = options.rect; rect.marginsRemoved(QMargins(margin, margin, margin, margin)); + QColor color = bookmark.isAuto ? QColor(0, 123, 255) : QColor(255, 159, 0); + + if (options.state.testFlag(QStyle::State_Selected)) + { + color = Qt::yellow; + } + 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)); + drawStar(*painter, iconRect.center(), iconRect.width() * 0.5, color); QRect textRect = rect; textRect.setLeft(iconRect.right() + margin); + textRect.moveTop(rect.top() + (rect.height() - 2 * options.fontMetrics.lineSpacing()) / 2); textRect.setHeight(options.fontMetrics.lineSpacing()); @@ -135,18 +155,19 @@ QSize PDFBookmarkItemDelegate::sizeHint(const QStyleOptionViewItem& option, cons void PDFBookmarkItemDelegate::drawStar(QPainter& painter, const QPointF& center, double size, const QColor& color) const { - painter.save(); + pdf::PDFPainterStateGuard guard(&painter); painter.setPen(Qt::NoPen); painter.setBrush(color); QPainterPath path; double angle = M_PI / 5; + double phase = -M_PI / 10; 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)); + QPointF point(radius * cos(i * angle + phase), radius * sin(i * angle + phase)); point += center; if (i == 0) @@ -159,15 +180,19 @@ void PDFBookmarkItemDelegate::drawStar(QPainter& painter, const QPointF& center, } } path.closeSubpath(); - painter.drawPath(path); - - painter.restore(); } QString PDFBookmarkItemDelegate::getPageText(const PDFBookmarkManager::Bookmark& bookmark) const { - return tr("Page %1").arg(bookmark.pageIndex + 1); + if (bookmark.isAuto) + { + return tr("Page %1 | Generated").arg(bookmark.pageIndex + 1); + } + else + { + return tr("Page %1").arg(bookmark.pageIndex + 1); + } } } // namespace pdfviewer diff --git a/Pdf4QtViewer/pdfprogramcontroller.cpp b/Pdf4QtViewer/pdfprogramcontroller.cpp index 8110c3b..b2bf992 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.cpp +++ b/Pdf4QtViewer/pdfprogramcontroller.cpp @@ -210,6 +210,9 @@ void PDFActionManager::initActions(QSize iconSize, bool initializeStampActions) setShortcut(GoToPreviousPage, QKeySequence::MoveToPreviousPage); setShortcut(GoToNextLine, QKeySequence::MoveToNextLine); setShortcut(GoToPreviousLine, QKeySequence::MoveToPreviousLine); + setShortcut(BookmarkPage, QKeySequence("Ctrl+M")); + setShortcut(BookmarkGoToNext, QKeySequence("Ctrl+.")); + setShortcut(BookmarkGoToPrevious, QKeySequence("Ctrl+,")); if (hasActions({ CreateStickyNoteComment, CreateStickyNoteHelp, CreateStickyNoteInsert, CreateStickyNoteKey, CreateStickyNoteNewParagraph, CreateStickyNoteNote, CreateStickyNoteParagraph })) { @@ -403,6 +406,8 @@ void PDFProgramController::initializeFormManager() void PDFProgramController::initializeBookmarkManager() { m_bookmarkManager = new PDFBookmarkManager(this); + connect(m_bookmarkManager, &PDFBookmarkManager::bookmarkActivated, this, &PDFProgramController::onBookmarkActivated); + updateBookmarkSettings(); } void PDFProgramController::initialize(Features features, @@ -581,6 +586,30 @@ void PDFProgramController::initialize(Features features, { connect(action, &QAction::triggered, this, &PDFProgramController::onActionAutomaticDocumentRefresh); } + if (QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkPage)) + { + connect(action, &QAction::triggered, this, &PDFProgramController::onActionBookmarkPage); + } + if (QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkGoToNext)) + { + connect(action, &QAction::triggered, this, &PDFProgramController::onActionBookmarkGoToNext); + } + if (QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkGoToPrevious)) + { + connect(action, &QAction::triggered, this, &PDFProgramController::onActionBookmarkGoToPrevious); + } + if (QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkExport)) + { + connect(action, &QAction::triggered, this, &PDFProgramController::onActionBookmarkExport); + } + if (QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkImport)) + { + connect(action, &QAction::triggered, this, &PDFProgramController::onActionBookmarkImport); + } + if (QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkGenerateAutomatically)) + { + connect(action, &QAction::triggered, this, &PDFProgramController::onActionBookmarkGenerateAutomatically); + } if (m_recentFileManager) { @@ -1559,6 +1588,8 @@ void PDFProgramController::readSettings(Settings settingsFlags) { m_formManager->setAppearanceFlags(m_settings->getSettings().m_formAppearanceFlags); } + + updateBookmarkSettings(); } if (settingsFlags.testFlag(PluginsSettings)) @@ -1712,6 +1743,13 @@ void PDFProgramController::onFileChanged(const QString& fileName) } } +void PDFProgramController::onBookmarkActivated(int index, PDFBookmarkManager::Bookmark bookmark) +{ + Q_UNUSED(index); + + m_pdfWidget->getDrawWidgetProxy()->goToPage(bookmark.pageIndex); +} + void PDFProgramController::updateFileInfo(const QString& fileName) { QFileInfo fileInfo(fileName); @@ -1996,6 +2034,22 @@ void PDFProgramController::updateRenderingOptionActions() } } +void PDFProgramController::updateBookmarkSettings() +{ + const bool enable = m_settings->getSettings().m_autoGenerateBookmarks; + + if (m_bookmarkManager) + { + m_bookmarkManager->setGenerateBookmarksAutomatically(enable); + } + + QAction* action = m_actionManager->getAction(PDFActionManager::BookmarkGenerateAutomatically); + if (action) + { + action->setChecked(enable); + } +} + void PDFProgramController::updateTitle() { if (m_pdfDocument) @@ -2550,6 +2604,53 @@ void PDFProgramController::onActionAutomaticDocumentRefresh() updateFileWatcher(); } +void PDFProgramController::onActionBookmarkPage() +{ + std::vector currentPages = m_pdfWidget->getDrawWidget()->getCurrentPages(); + if (!currentPages.empty()) + { + m_bookmarkManager->toggleBookmark(currentPages.front()); + } +} + +void PDFProgramController::onActionBookmarkGoToNext() +{ + m_bookmarkManager->goToNextBookmark(); +} + +void PDFProgramController::onActionBookmarkGoToPrevious() +{ + m_bookmarkManager->goToPreviousBookmark(); +} + +void PDFProgramController::onActionBookmarkExport() +{ + QFileInfo fileInfo(m_fileInfo.originalFileName); + QString saveFileName = QFileDialog::getSaveFileName(m_mainWindow, tr("Export Bookmarks As"), fileInfo.dir().absoluteFilePath(m_fileInfo.originalFileName).replace(".pdf", ".json"), tr("JSON (*.json);;All files (*.*)")); + if (!saveFileName.isEmpty()) + { + m_bookmarkManager->saveToFile(saveFileName); + } +} + +void PDFProgramController::onActionBookmarkImport() +{ + QFileInfo fileInfo(m_fileInfo.originalFileName); + QString fileName = QFileDialog::getOpenFileName(m_mainWindow, tr("Select PDF document"), fileInfo.dir().absolutePath(), tr("JSON (*.json)")); + if (!fileName.isEmpty()) + { + m_bookmarkManager->loadFromFile(fileName); + } +} + +void PDFProgramController::onActionBookmarkGenerateAutomatically(bool checked) +{ + auto settings = m_settings->getSettings(); + settings.m_autoGenerateBookmarks = checked; + m_settings->setSettings(settings); + m_bookmarkManager->setGenerateBookmarksAutomatically(checked); +} + void PDFProgramController::onPageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount) { if (errorsCount > 0) diff --git a/Pdf4QtViewer/pdfprogramcontroller.h b/Pdf4QtViewer/pdfprogramcontroller.h index 8be65c2..76507c5 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.h +++ b/Pdf4QtViewer/pdfprogramcontroller.h @@ -178,6 +178,12 @@ public: ToolScreenshot, ToolExtractImage, DeveloperCreateInstaller, + BookmarkPage, + BookmarkGoToNext, + BookmarkGoToPrevious, + BookmarkExport, + BookmarkImport, + BookmarkGenerateAutomatically, LastAction }; @@ -367,6 +373,12 @@ private: void onActionGetSource(); void onActionBecomeSponsor(); void onActionAutomaticDocumentRefresh(); + void onActionBookmarkPage(); + void onActionBookmarkGoToNext(); + void onActionBookmarkGoToPrevious(); + void onActionBookmarkExport(); + void onActionBookmarkImport(); + void onActionBookmarkGenerateAutomatically(bool checked); void onDrawSpaceChanged(); void onPageLayoutChanged(); @@ -377,6 +389,7 @@ private: void onViewerSettingsChanged(); void onColorManagementSystemChanged(); void onFileChanged(const QString& fileName); + void onBookmarkActivated(int index, PDFBookmarkManager::Bookmark bookmark); void updateMagnifierToolSettings(); void updateUndoRedoSettings(); @@ -384,6 +397,7 @@ private: void updateTitle(); void updatePageLayoutActions(); void updateRenderingOptionActions(); + void updateBookmarkSettings(); void setPageLayout(pdf::PageLayout pageLayout); void updateFileInfo(const QString& fileName); diff --git a/Pdf4QtViewer/pdfsidebarwidget.cpp b/Pdf4QtViewer/pdfsidebarwidget.cpp index 9fce464..45eb3aa 100644 --- a/Pdf4QtViewer/pdfsidebarwidget.cpp +++ b/Pdf4QtViewer/pdfsidebarwidget.cpp @@ -134,6 +134,9 @@ PDFSidebarWidget::PDFSidebarWidget(pdf::PDFDrawWidgetProxy* proxy, m_bookmarkItemModel = new PDFBookmarkItemModel(bookmarkManager, this); ui->bookmarksView->setModel(m_bookmarkItemModel); ui->bookmarksView->setItemDelegate(new PDFBookmarkItemDelegate(bookmarkManager, this)); + connect(m_bookmarkManager, &PDFBookmarkManager::bookmarkActivated, this, &PDFSidebarWidget::onBookmarkActivated); + connect(ui->bookmarksView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PDFSidebarWidget::onBookmarsCurrentIndexChanged); + connect(ui->bookmarksView, &QListView::clicked, this, &PDFSidebarWidget::onBookmarkClicked); m_pageInfo[Invalid] = { nullptr, ui->emptyPage }; m_pageInfo[OptionalContent] = { ui->optionalContentButton, ui->optionalContentPage }; @@ -956,6 +959,46 @@ void PDFSidebarWidget::onOutlineItemsChanged() } } +void PDFSidebarWidget::onBookmarkActivated(int index, PDFBookmarkManager::Bookmark bookmark) +{ + if (m_bookmarkChangeInProgress) + { + return; + } + + pdf::PDFTemporaryValueChange guard(&m_bookmarkChangeInProgress, true); + QModelIndex currentIndex = m_bookmarkItemModel->index(index, 0, QModelIndex()); + ui->bookmarksView->selectionModel()->select(currentIndex, QItemSelectionModel::SelectCurrent); + ui->bookmarksView->setCurrentIndex(currentIndex); +} + +void PDFSidebarWidget::onBookmarsCurrentIndexChanged(const QModelIndex& current, const QModelIndex& previous) +{ + Q_UNUSED(previous); + + if (m_bookmarkChangeInProgress) + { + return; + } + + pdf::PDFTemporaryValueChange guard(&m_bookmarkChangeInProgress, true); + m_bookmarkManager->goToBookmark(current.row(), false); +} + +void PDFSidebarWidget::onBookmarkClicked(const QModelIndex& index) +{ + if (m_bookmarkChangeInProgress) + { + return; + } + + if (index == ui->bookmarksView->currentIndex()) + { + pdf::PDFTemporaryValueChange guard(&m_bookmarkChangeInProgress, true); + m_bookmarkManager->goToCurrentBookmark(); + } +} + void PDFSidebarWidget::paintEvent(QPaintEvent* event) { Q_UNUSED(event); diff --git a/Pdf4QtViewer/pdfsidebarwidget.h b/Pdf4QtViewer/pdfsidebarwidget.h index f7ee57b..069ab5e 100644 --- a/Pdf4QtViewer/pdfsidebarwidget.h +++ b/Pdf4QtViewer/pdfsidebarwidget.h @@ -119,6 +119,9 @@ private: void onSignatureCustomContextMenuRequested(const QPoint &pos); void onOutlineTreeViewContextMenuRequested(const QPoint &pos); void onOutlineItemsChanged(); + void onBookmarkActivated(int index, PDFBookmarkManager::Bookmark bookmark); + void onBookmarsCurrentIndexChanged(const QModelIndex& current, const QModelIndex& previous); + void onBookmarkClicked(const QModelIndex& index); struct PageInfo { @@ -142,6 +145,7 @@ private: std::map m_pageInfo; std::vector m_signatures; std::vector m_certificateInfos; + bool m_bookmarkChangeInProgress = false; }; } // namespace pdfviewer diff --git a/Pdf4QtViewer/pdfviewermainwindow.cpp b/Pdf4QtViewer/pdfviewermainwindow.cpp index 50dd398..156c65e 100644 --- a/Pdf4QtViewer/pdfviewermainwindow.cpp +++ b/Pdf4QtViewer/pdfviewermainwindow.cpp @@ -194,6 +194,12 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) : m_actionManager->setAction(PDFActionManager::ToolScreenshot, ui->actionScreenshot); m_actionManager->setAction(PDFActionManager::ToolExtractImage, ui->actionExtractImage); m_actionManager->setAction(PDFActionManager::DeveloperCreateInstaller, ui->actionDeveloperCreateInstaller); + m_actionManager->setAction(PDFActionManager::BookmarkPage, ui->actionBookmarkPage); + m_actionManager->setAction(PDFActionManager::BookmarkGoToNext, ui->actionGotoNextBookmark); + m_actionManager->setAction(PDFActionManager::BookmarkGoToPrevious, ui->actionGotoPreviousBookmark); + m_actionManager->setAction(PDFActionManager::BookmarkExport, ui->actionBookmarkExport); + m_actionManager->setAction(PDFActionManager::BookmarkImport, ui->actionBookmarkImport); + m_actionManager->setAction(PDFActionManager::BookmarkGenerateAutomatically, ui->actionBookmarkAutoGenerate); m_actionManager->initActions(pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24)), true); for (QAction* action : m_programController->getRecentFileManager()->getActions()) diff --git a/Pdf4QtViewer/pdfviewermainwindow.ui b/Pdf4QtViewer/pdfviewermainwindow.ui index ba41469..ba7a134 100644 --- a/Pdf4QtViewer/pdfviewermainwindow.ui +++ b/Pdf4QtViewer/pdfviewermainwindow.ui @@ -46,12 +46,25 @@ Go To + + + Bookmark Settings + + + + + + + + + + @@ -1051,6 +1064,99 @@ Convert the colored images to monochromatic to create a bitonal document. + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Bookmark Page + + + Bookmark Page + + + Bookmark page for fast navigation. + + + + + + :/resources/bookmark-next.svg:/resources/bookmark-next.svg + + + Go to Next Bookmark + + + Go to Next Bookmark + + + Navigates to the next bookmarked page. + + + + + + :/resources/bookmark-previous.svg:/resources/bookmark-previous.svg + + + Go to Previous Bookmark + + + Go to Previous Bookmark + + + Navigates to the previous bookmarked page. + + + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Export Bookmarks + + + Export Bookmarks + + + Export bookmarks to the file. + + + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Import Bookmarks + + + Import Bookmarks + + + Import bookmarks from the file. + + + + + true + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Generate Bookmarks Automatically + + + Generate Bookmarks Automatically + + + If checked, bookmarks for main document chapters are generated automatically. + + diff --git a/Pdf4QtViewer/pdfviewermainwindowlite.cpp b/Pdf4QtViewer/pdfviewermainwindowlite.cpp index ed2713c..5528af5 100644 --- a/Pdf4QtViewer/pdfviewermainwindowlite.cpp +++ b/Pdf4QtViewer/pdfviewermainwindowlite.cpp @@ -151,6 +151,12 @@ PDFViewerMainWindowLite::PDFViewerMainWindowLite(QWidget* parent) : m_actionManager->setAction(PDFActionManager::PageLayoutTwoPages, ui->actionPageLayoutTwoPages); m_actionManager->setAction(PDFActionManager::PageLayoutTwoColumns, ui->actionPageLayoutTwoColumns); m_actionManager->setAction(PDFActionManager::PageLayoutFirstPageOnRightSide, ui->actionFirstPageOnRightSide); + m_actionManager->setAction(PDFActionManager::BookmarkPage, ui->actionBookmarkPage); + m_actionManager->setAction(PDFActionManager::BookmarkGoToNext, ui->actionGotoNextBookmark); + m_actionManager->setAction(PDFActionManager::BookmarkGoToPrevious, ui->actionGotoPreviousBookmark); + m_actionManager->setAction(PDFActionManager::BookmarkExport, ui->actionBookmarkExport); + m_actionManager->setAction(PDFActionManager::BookmarkImport, ui->actionBookmarkImport); + m_actionManager->setAction(PDFActionManager::BookmarkGenerateAutomatically, ui->actionBookmarkAutoGenerate); m_actionManager->initActions(pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24)), true); for (QAction* action : m_programController->getRecentFileManager()->getActions()) diff --git a/Pdf4QtViewer/pdfviewermainwindowlite.ui b/Pdf4QtViewer/pdfviewermainwindowlite.ui index a5b8e7c..2142345 100644 --- a/Pdf4QtViewer/pdfviewermainwindowlite.ui +++ b/Pdf4QtViewer/pdfviewermainwindowlite.ui @@ -42,12 +42,26 @@ Go To + + + Bookmark Settings + + + + + + + + + + + @@ -543,6 +557,100 @@ Become a Sponsor + + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Bookmark Page + + + Bookmark Page + + + Bookmark page for fast navigation. + + + + + + :/resources/bookmark-next.svg:/resources/bookmark-next.svg + + + Go to Next Bookmark + + + Go to Next Bookmark + + + Navigates to the next bookmarked page. + + + + + + :/resources/bookmark-previous.svg:/resources/bookmark-previous.svg + + + Go to Previous Bookmark + + + Go to Previous Bookmark + + + Navigates to the previous bookmarked page. + + + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Export Bookmarks + + + Export Bookmarks + + + Export bookmarks to the file. + + + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Import Bookmarks + + + Import Bookmarks + + + Import bookmarks from the file. + + + + + true + + + + :/resources/bookmark.svg:/resources/bookmark.svg + + + Generate Bookmarks Automatically + + + Generate Bookmarks Automatically + + + If checked, bookmarks for main document chapters are generated automatically. + + diff --git a/Pdf4QtViewer/pdfviewersettings.cpp b/Pdf4QtViewer/pdfviewersettings.cpp index 329c97c..02ce814 100644 --- a/Pdf4QtViewer/pdfviewersettings.cpp +++ b/Pdf4QtViewer/pdfviewersettings.cpp @@ -104,6 +104,10 @@ void PDFViewerSettings::readSettings(QSettings& settings, const pdf::PDFCMSSetti m_settings.m_signatureUseSystemStore = settings.value("signatureUseSystemStore", defaultSettings.m_signatureUseSystemStore).toBool(); settings.endGroup(); + settings.beginGroup("Bookmarks"); + m_settings.m_autoGenerateBookmarks = settings.value("autoGenerateBookmarks", defaultSettings.m_autoGenerateBookmarks).toBool(); + settings.endGroup(); + Q_EMIT settingsChanged(); } @@ -174,6 +178,10 @@ void PDFViewerSettings::writeSettings(QSettings& settings) settings.setValue("signatureIgnoreCertificateValidityTime", m_settings.m_signatureIgnoreCertificateValidityTime); settings.setValue("signatureUseSystemStore", m_settings.m_signatureUseSystemStore); settings.endGroup(); + + settings.beginGroup("Bookmarks"); + settings.setValue("autoGenerateBookmarks", m_settings.m_autoGenerateBookmarks); + settings.endGroup(); } QString PDFViewerSettings::getDirectory() const @@ -287,7 +295,8 @@ PDFViewerSettings::Settings::Settings() : m_signatureVerificationEnabled(true), m_signatureTreatWarningsAsErrors(false), m_signatureIgnoreCertificateValidityTime(false), - m_signatureUseSystemStore(true) + m_signatureUseSystemStore(true), + m_autoGenerateBookmarks(true) { } diff --git a/Pdf4QtViewer/pdfviewersettings.h b/Pdf4QtViewer/pdfviewersettings.h index eb6f90d..90e2769 100644 --- a/Pdf4QtViewer/pdfviewersettings.h +++ b/Pdf4QtViewer/pdfviewersettings.h @@ -91,6 +91,9 @@ public: bool m_signatureTreatWarningsAsErrors; bool m_signatureIgnoreCertificateValidityTime; bool m_signatureUseSystemStore; + + // Bookmarks settings + bool m_autoGenerateBookmarks; }; const Settings& getSettings() const { return m_settings; } diff --git a/Pdf4QtViewer/resources/bookmark-next.svg b/Pdf4QtViewer/resources/bookmark-next.svg new file mode 100644 index 0000000..4f2b635 --- /dev/null +++ b/Pdf4QtViewer/resources/bookmark-next.svg @@ -0,0 +1,75 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Pdf4QtViewer/resources/bookmark-previous.svg b/Pdf4QtViewer/resources/bookmark-previous.svg new file mode 100644 index 0000000..0a8b2b6 --- /dev/null +++ b/Pdf4QtViewer/resources/bookmark-previous.svg @@ -0,0 +1,75 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Pdf4QtViewer/resources/bookmark.svg b/Pdf4QtViewer/resources/bookmark.svg new file mode 100644 index 0000000..6a0f488 --- /dev/null +++ b/Pdf4QtViewer/resources/bookmark.svg @@ -0,0 +1,70 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/Pdf4QtViewer/resources/sidebar-favourites.svg b/Pdf4QtViewer/resources/sidebar-favourites.svg index f9804e2..6a0f488 100644 --- a/Pdf4QtViewer/resources/sidebar-favourites.svg +++ b/Pdf4QtViewer/resources/sidebar-favourites.svg @@ -43,16 +43,28 @@ inkscape:window-height="2035" id="namedview817" showgrid="false" - inkscape:zoom="0.30348968" - inkscape:cx="-2950.1732" - inkscape:cy="277.06973" + inkscape:zoom="1.2139587" + inkscape:cx="535.31725" + inkscape:cy="132.65123" inkscape:window-x="-13" inkscape:window-y="-13" inkscape:window-maximized="1" inkscape:current-layer="svg815" /> + sodipodi:type="star" + style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:26.45669291;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" + id="path839" + sodipodi:sides="5" + sodipodi:cx="259.20364" + sodipodi:cy="269.65189" + sodipodi:r1="203.30641" + sodipodi:r2="101.65321" + sodipodi:arg1="-1.585122" + sodipodi:arg2="-0.95680346" + inkscape:flatsided="false" + inkscape:rounded="0" + inkscape:randomized="0" + d="m 256.29124,66.366336 61.47844,120.198874 133.87003,17.49813 -95.31804,95.61296 24.7264,132.72518 L 260.65984,371.29467 142.07158,435.82522 162.9856,302.44616 64.967615,209.60305 198.28142,188.27708 Z" + inkscape:transform-center-x="0.89998123" + inkscape:transform-center-y="-18.55611" />