Issue #54: Bookmarks page - model, bookmarks manager

This commit is contained in:
Jakub Melka 2023-12-16 20:23:53 +01:00
parent c1c59139b5
commit 7a5f37e38f
14 changed files with 756 additions and 5 deletions

View File

@ -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}")

View File

@ -104,5 +104,6 @@
<file>resources/sidebar-thumbnails.svg</file>
<file>resources/sidebar-visibility.svg</file>
<file>resources/outline.svg</file>
<file>resources/sidebar-favourites.svg</file>
</qresource>
</RCC>

View File

@ -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 <https://www.gnu.org/licenses/>.
#include "pdfbookmarkmanager.h"
#include "pdfaction.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
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<QString, PDFBookmarkManager::Bookmarks>& bookmarksMap)
{
QJsonObject mainObject;
for (const auto& pair : bookmarksMap)
{
mainObject[pair.first] = convertBookmarksToJson(pair.second);
}
return QJsonDocument(mainObject);
}
static std::map<QString, PDFBookmarkManager::Bookmarks> convertBookmarksMapFromJsonDocument(const QJsonDocument &doc)
{
std::map<QString, PDFBookmarkManager::Bookmarks> 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<const pdf::PDFActionGoTo*>(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

View File

@ -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 <https://www.gnu.org/licenses/>.
#ifndef PDFBOOKMARKMANAGER_H
#define PDFBOOKMARKMANAGER_H
#include "pdfdocument.h"
#include <QObject>
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<Bookmark> bookmarks;
};
pdf::PDFDocument* m_document;
QString m_currentKey;
std::map<QString, Bookmarks> m_bookmarks;
};
} // namespace pdf
#endif // PDFBOOKMARKMANAGER_H

View File

@ -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 <https://www.gnu.org/licenses/>.
#include "pdfbookmarkui.h"
#include "pdfwidgetutils.h"
#include <QPainter>
#include <QPainterPath>
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

View File

@ -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 <https://www.gnu.org/licenses/>.
#ifndef PDFBOOKMARKUI_H
#define PDFBOOKMARKUI_H
#include "pdfviewerglobal.h"
#include "pdfbookmarkmanager.h"
#include <QStyledItemDelegate>
#include <QAbstractItemModel>
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

View File

@ -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);

View File

@ -24,6 +24,7 @@
#include "pdfdocumentreader.h"
#include "pdfdocumentpropertiesdialog.h"
#include "pdfplugin.h"
#include "pdfbookmarkmanager.h"
#include <QObject>
#include <QAction>
@ -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<pdf::PDFCertificateStore*>(&m_certificateStore); }
PDFBookmarkManager* getBookmarkManager() const { return m_bookmarkManager; }
PDFTextToSpeech* getTextToSpeech() const { return m_textToSpeech; }
const std::vector<pdf::PDFSignatureVerificationResult>* 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;

View File

@ -33,6 +33,7 @@
#include "pdfdrawspacecontroller.h"
#include "pdfdocumentbuilder.h"
#include "pdfwidgetutils.h"
#include "pdfbookmarkui.h"
#include <QMenu>
#include <QAction>
@ -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();

View File

@ -20,6 +20,7 @@
#define PDFSIDEBARWIDGET_H
#include "pdfglobal.h"
#include "pdfbookmarkmanager.h"
#include <QWidget>
@ -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;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>339</width>
<height>584</height>
<width>388</width>
<height>681</height>
</rect>
</property>
<layout class="QHBoxLayout" name="sidebarLayout">
@ -225,6 +225,35 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="bookmarksButton">
<property name="minimumSize">
<size>
<width>96</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Bookmarks</string>
</property>
<property name="icon">
<iconset resource="pdf4qtviewer.qrc">
<normaloff>:/resources/sidebar-favourites.svg</normaloff>:/resources/sidebar-favourites.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
</widget>
</item>
<item>
<spacer name="buttonSpacer">
<property name="orientation">
@ -243,7 +272,7 @@
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
<number>5</number>
</property>
<widget class="QWidget" name="emptyPage"/>
<widget class="QWidget" name="outlinePage">
@ -383,6 +412,32 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="bookmarksPage">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListView" name="bookmarksView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="speechPage">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg815"
width="512"
height="512"
viewBox="0 0 512 512"
sodipodi:docname="sidebar-favourites.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs819" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2035"
id="namedview817"
showgrid="false"
inkscape:zoom="0.30348968"
inkscape:cx="-2950.1732"
inkscape:cy="277.06973"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1"
inkscape:current-layer="svg815" />
<path
style="fill:#000000;stroke-width:0.5"
d="m 139.03566,421.94715 c -2.79737,-0.85185 -5.79201,-3.2299 -7.58405,-6.02256 -1.38453,-2.1576 -1.70923,-3.19414 -1.84701,-5.8962 -0.14818,-2.90575 0.12519,-4.10246 2.405,-10.52839 1.41469,-3.9875 4.55587,-13.1 6.98039,-20.25 2.42452,-7.15 8.16662,-23.9125 12.76022,-37.25 10.50154,-30.49115 19.75557,-58.03253 19.7309,-58.72206 -0.0189,-0.52992 -4.92747,-4.22387 -27.73111,-20.86941 -3.575,-2.60957 -18.45339,-13.61279 -33.0631,-24.4516 -14.609695,-10.83881 -29.86493,-22.13597 -33.900515,-25.1048 -8.016685,-5.89759 -9.791975,-7.96334 -10.83006,-12.60198 -1.16825,-5.22029 1.75494,-11.13603 6.780105,-13.72108 l 2.48643,-1.27907 64.45687,-0.25 64.45687,-0.25 4.95111,-14 c 9.84582,-27.84052 18.59349,-52.75333 22.91133,-65.25 12.57291,-36.388445 11.92763,-34.83447 15.41594,-37.124915 3.76617,-2.472895 7.65066,-3.013205 11.61282,-1.615275 4.54841,1.60477 7.5252,5.1016 9.52236,11.18591 3.41941,10.417175 24.25254,69.83815 32.84417,93.67928 l 4.81995,13.375 63.76786,0.022 c 68.86041,0.0237 65.60095,-0.10273 69.25773,2.68643 5.43773,4.14757 6.32897,13.06779 1.83878,18.40408 -0.72796,0.86513 -6.6122,5.50844 -13.07611,10.31847 -6.4639,4.81003 -21.12961,15.73706 -32.59047,24.28229 -11.46085,8.54523 -25.18585,18.73451 -30.5,22.64284 -5.31414,3.90832 -13.49778,9.92958 -18.18586,13.38056 l -8.52378,6.27452 4.60426,13.61944 c 2.53235,7.49068 7.23127,21.26943 10.44205,30.61943 3.21079,9.35 8.60821,25.1 11.99428,35 3.38606,9.9 8.20409,23.92662 10.70673,31.17026 5.00498,14.48644 5.27817,16.09668 3.52561,20.78082 -1.78384,4.76773 -6.69274,7.99046 -12.22536,8.02602 -3.72318,0.024 -4.28878,-0.29608 -17.25,-9.75992 -5.3625,-3.91551 -12.45,-9.03772 -15.75,-11.38269 -3.3,-2.34497 -8.71337,-6.19203 -12.02971,-8.54904 -3.31633,-2.357 -11.48374,-8.22295 -18.14978,-13.03545 -6.66605,-4.8125 -16.56996,-11.9 -22.0087,-15.75 -5.43875,-3.85 -13.8661,-9.86019 -18.72745,-13.35597 l -8.83882,-6.35598 -14.1826,10.17114 c -7.80043,5.59413 -18.88068,13.60572 -24.62277,17.80354 -10.5153,7.68731 -12.89484,9.43081 -30.69017,22.48681 -5.3625,3.93434 -12,8.80233 -14.75,10.81777 -2.75,2.01544 -8.2625,6.07362 -12.25,9.01819 -3.9875,2.94456 -8.21074,5.89541 -9.38497,6.55743 -2.44103,1.37625 -6.90762,1.86779 -9.57937,1.05421 z M 180,365.74416 c 12.20892,-9.0382 32.34222,-23.69689 54.93082,-39.99416 3.43044,-2.475 6.29932,-4.725 6.37529,-5 0.076,-0.275 -1.80418,-1.85 -4.17811,-3.5 -2.37392,-1.65 -7.70513,-5.4946 -11.84712,-8.54355 -16.45615,-12.11352 -27.85131,-20.30252 -28.01669,-20.13389 -0.35952,0.36659 -11.41106,32.16678 -21.26102,61.17744 -3.22606,9.50154 -6.69433,19.14572 -8.81029,24.49864 -0.3916,0.99065 -0.38294,0.99098 1.08118,0.0411 0.81176,-0.52666 6.08844,-4.37216 11.72594,-8.54558 z m 162.19338,7.13084 c -0.41924,-1.16875 -3.35012,-9.6625 -6.51306,-18.875 -15.3913,-44.82929 -22.70379,-65.48939 -23.18032,-65.49185 -0.28679,-0.002 -14.64506,10.30154 -27.5,19.7331 -4.8125,3.53088 -10.60625,7.7753 -12.875,9.43204 -2.26875,1.65674 -4.11976,3.13925 -4.11334,3.29448 0.006,0.15522 2.98766,2.43192 6.625,5.05931 3.63734,2.62741 11.78834,8.52736 18.11334,13.11103 10.32734,7.48413 23.19979,16.70141 39,27.92587 3.025,2.14896 6.625,4.80197 8,5.89558 1.375,1.0936 2.65877,2.00008 2.85282,2.01441 0.19405,0.0143 0.01,-0.93022 -0.40944,-2.09897 z M 198.69993,237.48095 c 4.91075,-14.58548 8.82349,-26.62419 8.695,-26.75269 -0.1285,-0.1285 -20.44134,-0.17618 -45.13965,-0.10594 l -44.90601,0.12768 9.87824,7.25 c 16.71033,12.2643 52.7714,38.9228 57.52249,42.52405 2.475,1.87601 4.6173,3.42556 4.76065,3.44344 0.14336,0.0179 4.27854,-11.90107 9.18928,-26.48654 z m 131.55489,18.96204 c 8.37364,-6.22386 20.01545,-14.80142 44.91847,-33.09545 5.54219,-4.07135 11.58831,-8.45885 13.43583,-9.75 1.84751,-1.29115 3.36627,-2.51629 3.375,-2.72254 0.009,-0.20625 -20.26035,-0.375 -45.04241,-0.375 h -45.05829 l 0.27138,1.125 c 0.26839,1.11263 13.59221,40.36652 15.99548,47.125 1.87238,5.26551 1.90355,5.32494 2.53311,4.83075 0.31163,-0.24462 4.61878,-3.45661 9.57143,-7.13776 z m -48.53136,-60.99938 c 0.42896,-0.42953 -25.58476,-76.76693 -26.54687,-77.90194 -0.0971,-0.11458 -0.29176,-0.0932 -0.43253,0.0476 C 254.16118,118.17216 228,193.90628 228,195.01079 c 0,0.24982 2.30625,0.53052 5.125,0.62377 8.72051,0.28849 48.27486,0.13307 48.59846,-0.19095 z"
id="path825"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB