mirror of https://github.com/JakubMelka/PDF4QT.git
Issue #54: Bookmarks page - model, bookmarks manager
This commit is contained in:
parent
c1c59139b5
commit
7a5f37e38f
|
@ -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}")
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 |
Loading…
Reference in New Issue