mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Issue #118: Continuation
This commit is contained in:
@@ -47,13 +47,19 @@ add_library(Pdf4QtLibWidgets SHARED
|
||||
sources/pdfselectpagesdialog.h
|
||||
sources/pdfselectpagesdialog.cpp
|
||||
sources/pdfselectpagesdialog.ui
|
||||
sources/pdfwidgetannotation.h
|
||||
sources/pdfwidgetannotation.cpp
|
||||
sources/pdfpagecontentelements.cpp
|
||||
sources/pdfpagecontentelements.h
|
||||
sources/pdfitemmodels.cpp
|
||||
sources/pdfitemmodels.h
|
||||
)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
GENERATE_EXPORT_HEADER(Pdf4QtLibWidgets
|
||||
EXPORT_MACRO_NAME
|
||||
PDF4QTLIBSHARED_EXPORT
|
||||
PDF4QTLIBCORESHARED_EXPORT
|
||||
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtlibwidgets_export.h")
|
||||
|
||||
if(PDF4QT_ENABLE_OPENGL)
|
||||
|
@@ -29,7 +29,7 @@ namespace pdf
|
||||
/// Tool that creates 'sticky note' annotations. Multiple types of sticky
|
||||
/// notes are available, user can select a type of sticky note. When
|
||||
/// user select a point, popup window appears and user can enter a text.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateStickyNoteTool : public PDFWidgetTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateStickyNoteTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -52,7 +52,7 @@ private:
|
||||
TextAnnotationIcon m_icon;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateAnnotationTool : public PDFWidgetTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateAnnotationTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -69,7 +69,7 @@ protected:
|
||||
/// Tool that creates url link annotation. Multiple types of link highlights
|
||||
/// are available, user can select a link highlight. When link annotation
|
||||
/// is clicked, url address is triggered.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateHyperlinkTool : public PDFCreateAnnotationTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateHyperlinkTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -91,7 +91,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that creates free text note without callout line.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateFreeTextTool : public PDFCreateAnnotationTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateFreeTextTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that creates line/polyline/polygon annotations.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateLineTypeTool : public PDFCreateAnnotationTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateLineTypeTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -160,7 +160,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that creates ellipse annotation.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateEllipseTool : public PDFCreateAnnotationTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateEllipseTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -196,7 +196,7 @@ private:
|
||||
QColor m_fillColor;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateFreehandCurveTool : public PDFCreateAnnotationTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateFreehandCurveTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -234,7 +234,7 @@ private:
|
||||
|
||||
/// Tool that creates 'stamp' annotations. Multiple types of stamps
|
||||
/// are available, user can select a type of stamp (text).
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateStampTool : public PDFWidgetTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateStampTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -267,7 +267,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool for highlighting of text in document
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateHighlightTextTool : public PDFWidgetTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateHighlightTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -319,7 +319,7 @@ private:
|
||||
|
||||
/// Tool that creates redaction annotation from rectangle. Rectangle is not
|
||||
/// selected from the text, it is just any rectangle.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateRedactRectangleTool : public PDFCreateAnnotationTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateRedactRectangleTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -337,7 +337,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool for redaction of text in document. Creates redaction annotation from text selection.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateRedactTextTool : public PDFWidgetTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateRedactTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -33,7 +33,7 @@ class PDFCertificateManagerDialog;
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCertificateManagerDialog : public QDialog
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCertificateManagerDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -30,7 +30,7 @@ class PDFCreateCertificateDialog;
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateCertificateDialog : public QDialog
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreateCertificateDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -54,7 +54,7 @@ public:
|
||||
virtual bool doEvent(QEvent* event) = 0;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFWidget : public QWidget
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
1191
Pdf4QtLibWidgets/sources/pdfitemmodels.cpp
Normal file
1191
Pdf4QtLibWidgets/sources/pdfitemmodels.cpp
Normal file
File diff suppressed because it is too large
Load Diff
332
Pdf4QtLibWidgets/sources/pdfitemmodels.h
Normal file
332
Pdf4QtLibWidgets/sources/pdfitemmodels.h
Normal file
@@ -0,0 +1,332 @@
|
||||
// Copyright (C) 2019-2021 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 PDFITEMMODELS_H
|
||||
#define PDFITEMMODELS_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
#include "pdfobject.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QPixmapCache>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFAction;
|
||||
class PDFDocument;
|
||||
class PDFOutlineItem;
|
||||
class PDFModifiedDocument;
|
||||
class PDFFileSpecification;
|
||||
class PDFOptionalContentActivity;
|
||||
class PDFDrawWidgetProxy;
|
||||
class PDFDestination;
|
||||
|
||||
/// Represents tree item in the GUI tree
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFTreeItem
|
||||
{
|
||||
public:
|
||||
inline explicit PDFTreeItem() = default;
|
||||
inline explicit PDFTreeItem(PDFTreeItem* parent) : m_parent(parent) { }
|
||||
virtual ~PDFTreeItem();
|
||||
|
||||
template<typename T, typename... Arguments>
|
||||
inline T* addChild(Arguments&&... arguments)
|
||||
{
|
||||
T* item = new T(this, std::forward(arguments)...);
|
||||
m_children.push_back(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
template<typename T, typename... Arguments>
|
||||
inline T* insertChild(int position, Arguments&&... arguments)
|
||||
{
|
||||
T* item = new T(this, std::forward(arguments)...);
|
||||
m_children.insert(std::next(m_children.begin(), position), item);
|
||||
return item;
|
||||
}
|
||||
|
||||
void insertCreatedChild(int position, PDFTreeItem* item)
|
||||
{
|
||||
item->m_parent = this;
|
||||
m_children.insert(std::next(m_children.begin(), position), item);
|
||||
}
|
||||
|
||||
void addCreatedChild(PDFTreeItem* item)
|
||||
{
|
||||
item->m_parent = this;
|
||||
m_children.push_back(item);
|
||||
}
|
||||
|
||||
int getRow() const { return m_parent->m_children.indexOf(const_cast<PDFTreeItem*>(this)); }
|
||||
int getChildCount() const { return m_children.size(); }
|
||||
const PDFTreeItem* getChild(int index) const { return m_children.at(index); }
|
||||
PDFTreeItem* getChild(int index) { return m_children.at(index); }
|
||||
const PDFTreeItem* getParent() const { return m_parent; }
|
||||
PDFTreeItem* takeChild(int index);
|
||||
|
||||
private:
|
||||
PDFTreeItem* m_parent = nullptr;
|
||||
QList<PDFTreeItem*> m_children;
|
||||
};
|
||||
|
||||
/// Root of all tree item models. Reimplementations of this model
|
||||
/// must handle "soft" document updates, such as only annotations changed etc.
|
||||
/// Model should be rebuilded only, if it is neccessary.
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFTreeItemModel : public QAbstractItemModel
|
||||
{
|
||||
public:
|
||||
explicit PDFTreeItemModel(QObject* parent);
|
||||
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
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 bool hasChildren(const QModelIndex& parent) const override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
virtual void update() = 0;
|
||||
|
||||
protected:
|
||||
const PDFDocument* m_document;
|
||||
std::unique_ptr<PDFTreeItem> m_rootItem;
|
||||
};
|
||||
|
||||
class PDFOptionalContentTreeItem : public PDFTreeItem
|
||||
{
|
||||
public:
|
||||
inline explicit PDFOptionalContentTreeItem(PDFOptionalContentTreeItem* parent, PDFObjectReference reference, QString text, bool locked) :
|
||||
PDFTreeItem(parent),
|
||||
m_reference(reference),
|
||||
m_text(qMove(text)),
|
||||
m_locked(locked)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFObjectReference getReference() const { return m_reference; }
|
||||
QString getText() const;
|
||||
bool isLocked() const { return m_locked; }
|
||||
|
||||
private:
|
||||
PDFObjectReference m_reference; ///< Reference to optional content group
|
||||
QString m_text; ///< Node display name
|
||||
bool m_locked; ///< Node is locked (user can't change it)
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFOptionalContentTreeItemModel : public PDFTreeItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
inline explicit PDFOptionalContentTreeItemModel(QObject* parent) :
|
||||
PDFTreeItemModel(parent),
|
||||
m_activity(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void setActivity(PDFOptionalContentActivity* activity);
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent) const override;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
virtual void update() override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
|
||||
private:
|
||||
PDFOptionalContentActivity* m_activity;
|
||||
};
|
||||
|
||||
class PDFOutlineTreeItem : public PDFTreeItem
|
||||
{
|
||||
public:
|
||||
explicit PDFOutlineTreeItem(PDFOutlineTreeItem* parent, QSharedPointer<PDFOutlineItem> outlineItem);
|
||||
|
||||
const PDFOutlineItem* getOutlineItem() const { return m_outlineItem.data(); }
|
||||
PDFOutlineItem* getOutlineItem() { return m_outlineItem.data(); }
|
||||
|
||||
private:
|
||||
QSharedPointer<PDFOutlineItem> m_outlineItem;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFOutlineTreeItemModel : public PDFTreeItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PDFOutlineTreeItemModel(QIcon icon, bool editable, QObject* parent) :
|
||||
PDFTreeItemModel(parent),
|
||||
m_icon(qMove(icon)),
|
||||
m_editable(editable)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent) const override;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
virtual void update() override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
virtual Qt::DropActions supportedDropActions() const override;
|
||||
virtual Qt::DropActions supportedDragActions() const override;
|
||||
virtual bool insertRows(int row, int count, const QModelIndex& parent) override;
|
||||
virtual bool removeRows(int row, int count, const QModelIndex& parent) override;
|
||||
virtual bool moveRows(const QModelIndex& sourceParent, int sourceRow, int count, const QModelIndex& destinationParent, int destinationChild) override;
|
||||
virtual QStringList mimeTypes() const override;
|
||||
virtual QMimeData* mimeData(const QModelIndexList& indexes) const override;
|
||||
virtual bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override;
|
||||
virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override;
|
||||
|
||||
/// Returns action assigned to the index. If index is invalid, or
|
||||
/// points to the invalid item, nullptr is returned.
|
||||
/// \param index Index of the outline item
|
||||
const PDFAction* getAction(const QModelIndex& index) const;
|
||||
|
||||
/// Returns the outline item for the given index, or nullptr
|
||||
/// if no outline item is assigned to that index.
|
||||
const PDFOutlineItem* getOutlineItem(const QModelIndex& index) const;
|
||||
|
||||
/// Returns the outline item for the given index, or nullptr
|
||||
/// if no outline item is assigned to that index.
|
||||
PDFOutlineItem* getOutlineItem(const QModelIndex& index);
|
||||
|
||||
void setFontBold(const QModelIndex& index, bool value);
|
||||
void setFontItalics(const QModelIndex& index, bool value);
|
||||
void setDestination(const QModelIndex& index, const PDFDestination& destination);
|
||||
|
||||
const PDFOutlineItem* getRootOutlineItem() const;
|
||||
|
||||
bool isEditable() const { return m_editable; }
|
||||
|
||||
private:
|
||||
QIcon m_icon;
|
||||
bool m_editable;
|
||||
mutable QSharedPointer<PDFOutlineItem> m_dragDropItem;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFSelectableOutlineTreeItemModel : public PDFOutlineTreeItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFOutlineTreeItemModel;
|
||||
|
||||
public:
|
||||
PDFSelectableOutlineTreeItemModel(QIcon icon, QObject* parent) :
|
||||
BaseClass(qMove(icon), false, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
virtual void update() override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
|
||||
std::vector<const PDFOutlineItem*> getSelectedItems() const;
|
||||
|
||||
private:
|
||||
std::set<const PDFOutlineItem*> m_selectedItems;
|
||||
};
|
||||
|
||||
class PDFAttachmentsTreeItem : public PDFTreeItem
|
||||
{
|
||||
public:
|
||||
explicit PDFAttachmentsTreeItem(PDFAttachmentsTreeItem* parent, QIcon icon, QString title, QString description, const PDFFileSpecification* fileSpecification);
|
||||
virtual ~PDFAttachmentsTreeItem() override;
|
||||
|
||||
const QIcon& getIcon() const { return m_icon; }
|
||||
const QString& getTitle() const { return m_title; }
|
||||
const QString& getDescription() const { return m_description; }
|
||||
const PDFFileSpecification* getFileSpecification() const { return m_fileSpecification.get(); }
|
||||
|
||||
private:
|
||||
QIcon m_icon;
|
||||
QString m_title;
|
||||
QString m_description;
|
||||
std::unique_ptr<PDFFileSpecification> m_fileSpecification;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFAttachmentsTreeItemModel : public PDFTreeItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PDFAttachmentsTreeItemModel(QObject* parent) :
|
||||
PDFTreeItemModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
enum Column
|
||||
{
|
||||
Title,
|
||||
Description,
|
||||
EndColumn
|
||||
};
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent) const override;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
virtual void update() override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
const PDFFileSpecification* getFileSpecification(const QModelIndex& index) const;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFThumbnailsItemModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFThumbnailsItemModel(const PDFDrawWidgetProxy* proxy, QObject* parent);
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
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;
|
||||
|
||||
void setThumbnailsSize(int size);
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Sets the extra item width/height for size hint. This space will be added to the size hint (pixmap size)
|
||||
void setExtraItemSizeHint(int width, int height) { m_extraItemWidthHint = width; m_extraItemHeighHint = height; }
|
||||
|
||||
PDFInteger getPageIndex(const QModelIndex& index) const;
|
||||
|
||||
private:
|
||||
void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages);
|
||||
|
||||
/// Returns generated key for page index
|
||||
QString getKey(int pageIndex) const;
|
||||
|
||||
const PDFDrawWidgetProxy* m_proxy;
|
||||
int m_thumbnailSize;
|
||||
int m_extraItemWidthHint;
|
||||
int m_extraItemHeighHint;
|
||||
int m_pageCount;
|
||||
const PDFDocument* m_document;
|
||||
QPixmapCache m_thumbnailCache;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFITEMMODELS_H
|
@@ -38,7 +38,7 @@ namespace pdf
|
||||
{
|
||||
class PDFPageContentElement;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentEditorStyleSettings : public QWidget
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorStyleSettings : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -33,7 +33,7 @@ class PDFPageContentElementRectangle;
|
||||
class PDFPageContentElementFreehandCurve;
|
||||
class PDFTextEditPseudowidget;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTool : public PDFWidgetTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -58,7 +58,7 @@ protected:
|
||||
};
|
||||
|
||||
/// Tool that creates rectangle element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementRectangleTool : public PDFCreatePCElementTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementRectangleTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -91,7 +91,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that displays SVG image (or raster image)
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementImageTool : public PDFCreatePCElementTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementImageTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -131,7 +131,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that creates line element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementLineTool : public PDFCreatePCElementTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementLineTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -167,7 +167,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that creates dot element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementDotTool : public PDFCreatePCElementTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementDotTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -199,7 +199,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that creates freehand curve element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementFreehandCurveTool : public PDFCreatePCElementTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementFreehandCurveTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -237,7 +237,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool that displays SVG image
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTextTool : public PDFCreatePCElementTool
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFCreatePCElementTextTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -38,7 +38,7 @@ class PDFPageContentScene;
|
||||
class PDFPageContentElement;
|
||||
class PDFPageContentEditorStyleSettings;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentEditorWidget : public QDockWidget
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentEditorWidget : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
2535
Pdf4QtLibWidgets/sources/pdfpagecontentelements.cpp
Normal file
2535
Pdf4QtLibWidgets/sources/pdfpagecontentelements.cpp
Normal file
File diff suppressed because it is too large
Load Diff
626
Pdf4QtLibWidgets/sources/pdfpagecontentelements.h
Normal file
626
Pdf4QtLibWidgets/sources/pdfpagecontentelements.h
Normal file
@@ -0,0 +1,626 @@
|
||||
// Copyright (C) 2022 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 PDFPAGECONTENTELEMENTS_H
|
||||
#define PDFPAGECONTENTELEMENTS_H
|
||||
|
||||
#include "pdfdocumentdrawinterface.h"
|
||||
|
||||
#include <QPen>
|
||||
#include <QFont>
|
||||
#include <QBrush>
|
||||
#include <QCursor>
|
||||
#include <QPainterPath>
|
||||
|
||||
#include <set>
|
||||
|
||||
class QSvgRenderer;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFWidget;
|
||||
class PDFDocument;
|
||||
class PDFPageContentScene;
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElement
|
||||
{
|
||||
public:
|
||||
explicit PDFPageContentElement() = default;
|
||||
virtual ~PDFPageContentElement() = default;
|
||||
|
||||
virtual PDFPageContentElement* clone() const = 0;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const = 0;
|
||||
|
||||
/// Returns manipulation mode. If manipulation mode is zero, then element
|
||||
/// cannot be manipulated. If it is nonzero, then element can be manipulated
|
||||
/// in some way.
|
||||
/// \param point Point on page
|
||||
/// \param snapPointDistanceTreshold Snap point threshold
|
||||
virtual uint getManipulationMode(const QPointF& point, PDFReal snapPointDistanceThreshold) const = 0;
|
||||
|
||||
/// Performs manipulation of given mode. Mode must be the one returned
|
||||
/// from function getManipulationMode. \sa getManipulationMode
|
||||
/// \param mode Mode
|
||||
/// \param offset Offset
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) = 0;
|
||||
|
||||
/// Returns bounding box of the element
|
||||
virtual QRectF getBoundingBox() const = 0;
|
||||
|
||||
/// Sets size to the elements that supports it. Does
|
||||
/// nothing for elements, which does not support it.
|
||||
virtual void setSize(QSizeF size) = 0;
|
||||
|
||||
/// Returns description of the element
|
||||
virtual QString getDescription() const = 0;
|
||||
|
||||
PDFInteger getPageIndex() const;
|
||||
void setPageIndex(PDFInteger newPageIndex);
|
||||
|
||||
PDFInteger getElementId() const;
|
||||
void setElementId(PDFInteger newElementId);
|
||||
|
||||
/// Returns cursor shape for manipulation mode
|
||||
/// \param mode Manipulation mode
|
||||
static Qt::CursorShape getCursorShapeForManipulationMode(uint mode);
|
||||
|
||||
enum ManipulationModes : uint
|
||||
{
|
||||
None = 0,
|
||||
Translate,
|
||||
Top,
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight,
|
||||
Pt1,
|
||||
Pt2
|
||||
};
|
||||
|
||||
protected:
|
||||
uint getRectangleManipulationMode(const QRectF& rectangle,
|
||||
const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const;
|
||||
|
||||
void performRectangleManipulation(QRectF& rectangle,
|
||||
uint mode,
|
||||
const QPointF& offset);
|
||||
|
||||
void performRectangleSetSize(QRectF& rectangle, QSizeF size);
|
||||
|
||||
QString formatDescription(const QString& description) const;
|
||||
|
||||
PDFInteger m_elementId = -1;
|
||||
PDFInteger m_pageIndex = -1;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentStyledElement : public PDFPageContentElement
|
||||
{
|
||||
public:
|
||||
explicit PDFPageContentStyledElement() = default;
|
||||
virtual ~PDFPageContentStyledElement() = default;
|
||||
|
||||
const QPen& getPen() const;
|
||||
void setPen(const QPen& newPen);
|
||||
|
||||
const QBrush& getBrush() const;
|
||||
void setBrush(const QBrush& newBrush);
|
||||
|
||||
protected:
|
||||
QPen m_pen;
|
||||
QBrush m_brush;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElementRectangle : public PDFPageContentStyledElement
|
||||
{
|
||||
public:
|
||||
virtual ~PDFPageContentElementRectangle() = default;
|
||||
|
||||
virtual PDFPageContentElementRectangle* clone() const override;
|
||||
|
||||
bool isRounded() const;
|
||||
void setRounded(bool newRounded);
|
||||
|
||||
const QRectF& getRectangle() const;
|
||||
void setRectangle(const QRectF& newRectangle);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size) override;
|
||||
virtual QString getDescription() const override;
|
||||
|
||||
private:
|
||||
bool m_rounded = false;
|
||||
QRectF m_rectangle;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElementLine : public PDFPageContentStyledElement
|
||||
{
|
||||
public:
|
||||
virtual ~PDFPageContentElementLine() = default;
|
||||
|
||||
virtual PDFPageContentElementLine* clone() const override;
|
||||
|
||||
enum class LineGeometry
|
||||
{
|
||||
General,
|
||||
Horizontal,
|
||||
Vertical
|
||||
};
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size) override;
|
||||
virtual QString getDescription() const override;
|
||||
|
||||
LineGeometry getGeometry() const;
|
||||
void setGeometry(LineGeometry newGeometry);
|
||||
|
||||
const QLineF& getLine() const;
|
||||
void setLine(const QLineF& newLine);
|
||||
|
||||
private:
|
||||
LineGeometry m_geometry = LineGeometry::General;
|
||||
QLineF m_line;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElementDot : public PDFPageContentStyledElement
|
||||
{
|
||||
public:
|
||||
virtual ~PDFPageContentElementDot() = default;
|
||||
|
||||
virtual PDFPageContentElementDot* clone() const override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size) override;
|
||||
virtual QString getDescription() const override;
|
||||
|
||||
QPointF getPoint() const;
|
||||
void setPoint(QPointF newPoint);
|
||||
|
||||
private:
|
||||
QPointF m_point;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElementFreehandCurve : public PDFPageContentStyledElement
|
||||
{
|
||||
public:
|
||||
virtual ~PDFPageContentElementFreehandCurve() = default;
|
||||
|
||||
virtual PDFPageContentElementFreehandCurve* clone() const override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size);
|
||||
virtual QString getDescription() const override;
|
||||
|
||||
QPainterPath getCurve() const;
|
||||
void setCurve(QPainterPath newCurve);
|
||||
|
||||
bool isEmpty() const { return m_curve.isEmpty(); }
|
||||
void addStartPoint(const QPointF& point);
|
||||
void addPoint(const QPointF& point);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QPainterPath m_curve;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentImageElement : public PDFPageContentElement
|
||||
{
|
||||
public:
|
||||
PDFPageContentImageElement();
|
||||
virtual ~PDFPageContentImageElement();
|
||||
|
||||
virtual PDFPageContentImageElement* clone() const override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size);
|
||||
virtual QString getDescription() const override;
|
||||
|
||||
const QByteArray& getContent() const;
|
||||
void setContent(const QByteArray& newContent);
|
||||
|
||||
const QRectF& getRectangle() const;
|
||||
void setRectangle(const QRectF& newRectangle);
|
||||
|
||||
private:
|
||||
QRectF m_rectangle;
|
||||
QByteArray m_content;
|
||||
QImage m_image;
|
||||
std::unique_ptr<QSvgRenderer> m_renderer;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElementTextBox : public PDFPageContentStyledElement
|
||||
{
|
||||
public:
|
||||
virtual ~PDFPageContentElementTextBox() = default;
|
||||
|
||||
virtual PDFPageContentElementTextBox* clone() const override;
|
||||
|
||||
const QRectF& getRectangle() const { return m_rectangle; }
|
||||
void setRectangle(const QRectF& newRectangle) { m_rectangle = newRectangle; }
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual uint getManipulationMode(const QPointF& point,
|
||||
PDFReal snapPointDistanceThreshold) const override;
|
||||
|
||||
virtual void performManipulation(uint mode, const QPointF& offset) override;
|
||||
virtual QRectF getBoundingBox() const override;
|
||||
virtual void setSize(QSizeF size) override;
|
||||
virtual QString getDescription() const override;
|
||||
|
||||
const QString& getText() const;
|
||||
void setText(const QString& newText);
|
||||
|
||||
const QFont& getFont() const;
|
||||
void setFont(const QFont& newFont);
|
||||
|
||||
PDFReal getAngle() const;
|
||||
void setAngle(PDFReal newAngle);
|
||||
|
||||
const Qt::Alignment& getAlignment() const;
|
||||
void setAlignment(const Qt::Alignment& newAlignment);
|
||||
|
||||
private:
|
||||
QString m_text;
|
||||
QRectF m_rectangle;
|
||||
QFont m_font;
|
||||
PDFReal m_angle = 0.0;
|
||||
Qt::Alignment m_alignment = Qt::AlignCenter;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentElementManipulator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PDFPageContentElementManipulator(PDFPageContentScene* scene, QObject* parent);
|
||||
|
||||
enum class Operation
|
||||
{
|
||||
AlignTop,
|
||||
AlignCenterVertically,
|
||||
AlignBottom,
|
||||
AlignLeft,
|
||||
AlignCenterHorizontally,
|
||||
AlignRight,
|
||||
SetSameHeight,
|
||||
SetSameWidth,
|
||||
SetSameSize,
|
||||
CenterHorizontally,
|
||||
CenterVertically,
|
||||
CenterHorAndVert,
|
||||
LayoutVertically,
|
||||
LayoutHorizontally,
|
||||
LayoutForm,
|
||||
LayoutGrid
|
||||
};
|
||||
|
||||
enum SelectionMode
|
||||
{
|
||||
NoUpdate = 0x0000,
|
||||
Clear = 0x0001, ///< Clears current selection
|
||||
Select = 0x0002, ///< Selects item
|
||||
Deselect = 0x0004, ///< Deselects item
|
||||
Toggle = 0x0008, ///< Toggles selection of the item
|
||||
};
|
||||
Q_DECLARE_FLAGS(SelectionModes, SelectionMode)
|
||||
|
||||
/// Returns true, if element with given id is selected
|
||||
/// \param id Element id
|
||||
bool isSelected(PDFInteger id) const;
|
||||
|
||||
/// Returns true, if all elements are selected
|
||||
/// \param ids Element ids
|
||||
bool isAllSelected(const std::set<PDFInteger>& elementIds) const;
|
||||
|
||||
/// Returns true, if selection is empty
|
||||
bool isSelectionEmpty() const { return m_selection.empty(); }
|
||||
|
||||
/// Clear all selection, stop manipulation
|
||||
void reset();
|
||||
|
||||
void update(PDFInteger id, SelectionModes modes);
|
||||
void update(const std::set<PDFInteger>& ids, SelectionModes modes);
|
||||
void select(PDFInteger id);
|
||||
void select(const std::set<PDFInteger>& ids);
|
||||
void selectNew(PDFInteger id);
|
||||
void selectNew(const std::set<PDFInteger>& ids);
|
||||
void deselect(PDFInteger id);
|
||||
void deselect(const std::set<PDFInteger>& ids);
|
||||
void selectAll();
|
||||
void deselectAll();
|
||||
|
||||
bool isManipulationAllowed(PDFInteger pageIndex) const;
|
||||
bool isManipulationInProgress() const { return m_isManipulationInProgress; }
|
||||
|
||||
void performOperation(Operation operation);
|
||||
void performDeleteSelection();
|
||||
|
||||
void startManipulation(PDFInteger pageIndex,
|
||||
const QPointF& startPoint,
|
||||
const QPointF& currentPoint,
|
||||
PDFReal snapPointDistanceThreshold);
|
||||
|
||||
void updateManipulation(PDFInteger pageIndex,
|
||||
const QPointF& startPoint,
|
||||
const QPointF& currentPoint);
|
||||
|
||||
void finishManipulation(PDFInteger pageIndex,
|
||||
const QPointF& startPoint,
|
||||
const QPointF& currentPoint,
|
||||
bool createCopy);
|
||||
|
||||
void cancelManipulation();
|
||||
|
||||
void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const;
|
||||
|
||||
/// Returns bounding box of whole selection
|
||||
QRectF getSelectionBoundingRect() const;
|
||||
|
||||
/// Returns page rectangle for the page
|
||||
QRectF getPageMediaBox(PDFInteger pageIndex) const;
|
||||
|
||||
signals:
|
||||
void selectionChanged();
|
||||
void stateChanged();
|
||||
|
||||
private:
|
||||
void eraseSelectedElementById(PDFInteger id);
|
||||
|
||||
PDFPageContentScene* m_scene;
|
||||
std::vector<PDFInteger> m_selection;
|
||||
bool m_isManipulationInProgress;
|
||||
std::vector<std::unique_ptr<PDFPageContentElement>> m_manipulatedElements;
|
||||
std::map<PDFInteger, uint> m_manipulationModes;
|
||||
QPointF m_lastUpdatedPoint;
|
||||
};
|
||||
|
||||
class PDF4QTLIBCORESHARED_EXPORT PDFPageContentScene : public QObject,
|
||||
public IDocumentDrawInterface,
|
||||
public IDrawWidgetInputInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFPageContentScene(QObject* parent);
|
||||
virtual ~PDFPageContentScene();
|
||||
|
||||
static constexpr PDFInteger INVALID_ELEMENT_ID = 0;
|
||||
|
||||
/// Add new element to page content scene, scene
|
||||
/// takes ownership over the element.
|
||||
/// \param element Element
|
||||
void addElement(PDFPageContentElement* element);
|
||||
|
||||
/// Replaces element in the page content scene, scene
|
||||
/// takes ownership over the element.
|
||||
/// \param element Element
|
||||
void replaceElement(PDFPageContentElement* element);
|
||||
|
||||
/// Returns element by its id (identifier number)
|
||||
/// \param id Element id
|
||||
PDFPageContentElement* getElementById(PDFInteger id) const;
|
||||
|
||||
/// Clear whole scene - remove all page content elements
|
||||
void clear();
|
||||
|
||||
/// Returns true, if scene is empty
|
||||
bool isEmpty() const { return m_elements.empty(); }
|
||||
|
||||
bool isActive() const;
|
||||
void setActive(bool newIsActive);
|
||||
|
||||
/// Returns set of all element ids
|
||||
std::set<PDFInteger> getElementIds() const;
|
||||
|
||||
/// Returns set of selected element ids
|
||||
std::set<PDFInteger> getSelectedElementIds() const;
|
||||
|
||||
/// Returns set of involved pages
|
||||
std::set<PDFInteger> getPageIndices() const;
|
||||
|
||||
/// Returns bounding box of elements on page
|
||||
QRectF getBoundingBox(PDFInteger pageIndex) const;
|
||||
|
||||
/// Set selected items
|
||||
void setSelectedElementIds(const std::set<PDFInteger>& selectedElementIds);
|
||||
|
||||
/// Removes elements specified in selection
|
||||
/// \param selection Items to be removed
|
||||
void removeElementsById(const std::vector<PDFInteger>& selection);
|
||||
|
||||
/// Performs manipulation of selected elements with manipulator
|
||||
void performOperation(int operation);
|
||||
|
||||
/// Returns document (or nullptr)
|
||||
const PDFDocument* getDocument() const;
|
||||
|
||||
// IDrawWidgetInputInterface interface
|
||||
public:
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||
virtual QString getTooltip() const override;
|
||||
virtual const std::optional<QCursor>& getCursor() const override;
|
||||
virtual int getInputPriority() const override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
PDFWidget* widget() const;
|
||||
void setWidget(PDFWidget* newWidget);
|
||||
|
||||
void drawElements(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
QList<PDFRenderError>& errors) const;
|
||||
|
||||
signals:
|
||||
/// This signal is emitted when scene has changed (including graphics)
|
||||
void sceneChanged(bool graphicsOnly);
|
||||
|
||||
void selectionChanged();
|
||||
|
||||
/// Request to edit the elements
|
||||
void editElementRequest(const std::set<PDFInteger>& elements);
|
||||
|
||||
private:
|
||||
|
||||
struct MouseEventInfo
|
||||
{
|
||||
std::set<PDFInteger> hoveredElementIds;
|
||||
QPoint widgetMouseStartPos;
|
||||
QPoint widgetMouseCurrentPos;
|
||||
QElapsedTimer timer;
|
||||
PDFInteger pageIndex = -1;
|
||||
QPointF pagePos;
|
||||
|
||||
bool isValid() const { return !hoveredElementIds.empty(); }
|
||||
};
|
||||
|
||||
MouseEventInfo getMouseEventInfo(QWidget* widget, QPoint point);
|
||||
|
||||
struct MouseGrabInfo
|
||||
{
|
||||
MouseEventInfo info;
|
||||
int mouseGrabNesting = 0;
|
||||
|
||||
bool isMouseGrabbed() const { return mouseGrabNesting > 0; }
|
||||
};
|
||||
|
||||
PDFReal getSnapPointDistanceThreshold() const;
|
||||
|
||||
bool isMouseGrabbed() const { return m_mouseGrabInfo.isMouseGrabbed(); }
|
||||
|
||||
/// Grabs mouse input, if mouse is already grabbed, or if event
|
||||
/// is accepted.
|
||||
/// \param info Mouse event info
|
||||
/// \param event Mouse event
|
||||
void grabMouse(const MouseEventInfo& info, QMouseEvent* event);
|
||||
|
||||
/// Release mouse input
|
||||
/// \param info Mouse event info
|
||||
/// \param event Mouse event
|
||||
void ungrabMouse(const MouseEventInfo& info, QMouseEvent* event);
|
||||
|
||||
/// Updates mouse cursor
|
||||
/// \param info Mouse event info
|
||||
/// \param snapPointDistanceTreshold Snap point threshold
|
||||
void updateMouseCursor(const MouseEventInfo& info, PDFReal snapPointDistanceThreshold);
|
||||
|
||||
/// Reaction on selection changed
|
||||
void onSelectionChanged();
|
||||
|
||||
PDFInteger m_firstFreeId;
|
||||
bool m_isActive;
|
||||
PDFWidget* m_widget;
|
||||
std::vector<std::unique_ptr<PDFPageContentElement>> m_elements;
|
||||
std::optional<QCursor> m_cursor;
|
||||
PDFPageContentElementManipulator m_manipulator;
|
||||
MouseGrabInfo m_mouseGrabInfo;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(pdf::PDFPageContentElementManipulator::SelectionModes)
|
||||
|
||||
#endif // PDFPAGECONTENTELEMENTS_H
|
@@ -31,7 +31,7 @@ namespace pdf
|
||||
{
|
||||
class PDFWidget;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFRenderingErrorsWidget : public QDialog
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFRenderingErrorsWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -30,7 +30,7 @@ class PDFSelectPagesDialog;
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFSelectPagesDialog : public QDialog
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFSelectPagesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
513
Pdf4QtLibWidgets/sources/pdfwidgetannotation.cpp
Normal file
513
Pdf4QtLibWidgets/sources/pdfwidgetannotation.cpp
Normal file
@@ -0,0 +1,513 @@
|
||||
// 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 "pdfdrawwidget.h"
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QDialog>
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include <QGroupBox>
|
||||
#include <QScrollArea>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QStyleOptionButton>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFWidgetAnnotationManager::PDFWidgetAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent) :
|
||||
BaseClass(proxy->getFontCache(), proxy->getCMSManager(), proxy->getOptionalContentActivity(), proxy->getMeshQualitySettings(), proxy->getFeatures(), Target::View, parent),
|
||||
m_proxy(proxy)
|
||||
{
|
||||
Q_ASSERT(proxy);
|
||||
m_proxy->registerDrawInterface(this);
|
||||
}
|
||||
|
||||
PDFWidgetAnnotationManager::~PDFWidgetAnnotationManager()
|
||||
{
|
||||
m_proxy->unregisterDrawInterface(this);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
BaseClass::setDocument(document);
|
||||
|
||||
if (document.hasReset() || document.getFlags().testFlag(PDFModifiedDocument::Annotation))
|
||||
{
|
||||
m_editableAnnotation = PDFObjectReference();
|
||||
m_editableAnnotationPage = PDFObjectReference();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::keyReleaseEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
updateFromMouseEvent(event);
|
||||
|
||||
// Show context menu?
|
||||
if (event->button() == Qt::RightButton)
|
||||
{
|
||||
PDFWidget* pdfWidget = m_proxy->getWidget();
|
||||
std::vector<PDFInteger> currentPages = pdfWidget->getDrawWidget()->getCurrentPages();
|
||||
|
||||
if (!hasAnyPageAnnotation(currentPages))
|
||||
{
|
||||
// All pages doesn't have annotation
|
||||
return;
|
||||
}
|
||||
|
||||
m_editableAnnotation = PDFObjectReference();
|
||||
m_editableAnnotationPage = PDFObjectReference();
|
||||
for (PDFInteger pageIndex : currentPages)
|
||||
{
|
||||
PageAnnotations& pageAnnotations = getPageAnnotations(pageIndex);
|
||||
for (PageAnnotation& pageAnnotation : pageAnnotations.annotations)
|
||||
{
|
||||
if (!pageAnnotation.isHovered)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!PDFAnnotation::isTypeEditable(pageAnnotation.annotation->getType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_editableAnnotation = pageAnnotation.annotation->getSelfReference();
|
||||
m_editableAnnotationPage = pageAnnotation.annotation->getPageReference();
|
||||
|
||||
if (!m_editableAnnotationPage.isValid())
|
||||
{
|
||||
m_editableAnnotationPage = m_document->getCatalog()->getPage(pageIndex)->getPageReference();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_editableAnnotation.isValid())
|
||||
{
|
||||
QMenu menu(tr("Annotation"), pdfWidget);
|
||||
QAction* showPopupAction = menu.addAction(tr("Show Popup Window"));
|
||||
QAction* copyAction = menu.addAction(tr("Copy to Multiple Pages"));
|
||||
QAction* editAction = menu.addAction(tr("Edit"));
|
||||
QAction* deleteAction = menu.addAction(tr("Delete"));
|
||||
connect(showPopupAction, &QAction::triggered, this, &PDFWidgetAnnotationManager::onShowPopupAnnotation);
|
||||
connect(copyAction, &QAction::triggered, this, &PDFWidgetAnnotationManager::onCopyAnnotation);
|
||||
connect(editAction, &QAction::triggered, this, &PDFWidgetAnnotationManager::onEditAnnotation);
|
||||
connect(deleteAction, &QAction::triggered, this, &PDFWidgetAnnotationManager::onDeleteAnnotation);
|
||||
|
||||
m_editableAnnotationGlobalPosition = pdfWidget->mapToGlobal(event->pos());
|
||||
menu.exec(m_editableAnnotationGlobalPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
updateFromMouseEvent(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
updateFromMouseEvent(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::updateFromMouseEvent(QMouseEvent* event)
|
||||
{
|
||||
PDFWidget* widget = m_proxy->getWidget();
|
||||
std::vector<PDFInteger> currentPages = widget->getDrawWidget()->getCurrentPages();
|
||||
|
||||
if (!hasAnyPageAnnotation(currentPages))
|
||||
{
|
||||
// All pages doesn't have annotation
|
||||
return;
|
||||
}
|
||||
|
||||
m_tooltip = QString();
|
||||
m_cursor = std::nullopt;
|
||||
bool appearanceChanged = false;
|
||||
|
||||
// We must update appearance states, and update tooltip
|
||||
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
||||
const bool isDown = event->buttons().testFlag(Qt::LeftButton);
|
||||
const PDFAppeareanceStreams::Appearance hoverAppearance = isDown ? PDFAppeareanceStreams::Appearance::Down : PDFAppeareanceStreams::Appearance::Rollover;
|
||||
|
||||
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
||||
{
|
||||
PageAnnotations& pageAnnotations = getPageAnnotations(snapshotItem.pageIndex);
|
||||
for (PageAnnotation& pageAnnotation : pageAnnotations.annotations)
|
||||
{
|
||||
if (pageAnnotation.annotation->isReplyTo())
|
||||
{
|
||||
// Annotation is reply to another annotation, do not interact with it
|
||||
continue;
|
||||
}
|
||||
|
||||
const PDFAppeareanceStreams::Appearance oldAppearance = pageAnnotation.appearance;
|
||||
QRectF annotationRect = pageAnnotation.annotation->getRectangle();
|
||||
QTransform matrix = prepareTransformations(snapshotItem.pageToDeviceMatrix, widget, pageAnnotation.annotation->getEffectiveFlags(), m_document->getCatalog()->getPage(snapshotItem.pageIndex), annotationRect);
|
||||
QPainterPath path;
|
||||
path.addRect(annotationRect);
|
||||
path = matrix.map(path);
|
||||
|
||||
if (path.contains(event->pos()))
|
||||
{
|
||||
pageAnnotation.appearance = hoverAppearance;
|
||||
pageAnnotation.isHovered = true;
|
||||
|
||||
// Generate tooltip
|
||||
if (m_tooltip.isEmpty())
|
||||
{
|
||||
const PDFMarkupAnnotation* markupAnnotation = pageAnnotation.annotation->asMarkupAnnotation();
|
||||
if (markupAnnotation)
|
||||
{
|
||||
QString title = markupAnnotation->getWindowTitle();
|
||||
if (title.isEmpty())
|
||||
{
|
||||
title = markupAnnotation->getSubject();
|
||||
}
|
||||
if (title.isEmpty())
|
||||
{
|
||||
title = PDFTranslationContext::tr("Info");
|
||||
}
|
||||
|
||||
const size_t repliesCount = pageAnnotations.getReplies(pageAnnotation).size();
|
||||
if (repliesCount > 0)
|
||||
{
|
||||
title = PDFTranslationContext::tr("%1 (%2 replies)").arg(title).arg(repliesCount);
|
||||
}
|
||||
|
||||
m_tooltip = QString("<p><b>%1</b></p><p>%2</p>").arg(title, markupAnnotation->getContents());
|
||||
}
|
||||
}
|
||||
|
||||
const PDFAction* linkAction = nullptr;
|
||||
const AnnotationType annotationType = pageAnnotation.annotation->getType();
|
||||
if (annotationType == AnnotationType::Link)
|
||||
{
|
||||
const PDFLinkAnnotation* linkAnnotation = dynamic_cast<const PDFLinkAnnotation*>(pageAnnotation.annotation.data());
|
||||
Q_ASSERT(linkAnnotation);
|
||||
|
||||
// We must check, if user clicked to the link area
|
||||
QPainterPath activationPath = linkAnnotation->getActivationRegion().getPath();
|
||||
activationPath = snapshotItem.pageToDeviceMatrix.map(activationPath);
|
||||
if (activationPath.contains(event->pos()) && linkAnnotation->getAction())
|
||||
{
|
||||
m_cursor = QCursor(Qt::PointingHandCursor);
|
||||
linkAction = linkAnnotation->getAction();
|
||||
}
|
||||
}
|
||||
if (annotationType == AnnotationType::Widget)
|
||||
{
|
||||
if (m_formManager && m_formManager->hasFormFieldWidgetText(pageAnnotation.annotation->getSelfReference()))
|
||||
{
|
||||
m_cursor = QCursor(Qt::IBeamCursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cursor = QCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate popup window
|
||||
if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton)
|
||||
{
|
||||
const PDFMarkupAnnotation* markupAnnotation = pageAnnotation.annotation->asMarkupAnnotation();
|
||||
if (markupAnnotation)
|
||||
{
|
||||
QDialog* dialog = createDialogForMarkupAnnotations(widget, pageAnnotation, pageAnnotations);
|
||||
|
||||
// Set proper dialog position - according to the popup annotation. If we
|
||||
// do not have popup annotation, then try to use annotations rectangle.
|
||||
if (const PageAnnotation* popupAnnotation = pageAnnotations.getPopupAnnotation(pageAnnotation))
|
||||
{
|
||||
QPoint popupPoint = snapshotItem.pageToDeviceMatrix.map(popupAnnotation->annotation->getRectangle().bottomLeft()).toPoint();
|
||||
popupPoint = widget->mapToGlobal(popupPoint);
|
||||
dialog->move(popupPoint);
|
||||
}
|
||||
else if (markupAnnotation->getRectangle().isValid())
|
||||
{
|
||||
QPoint popupPoint = snapshotItem.pageToDeviceMatrix.map(markupAnnotation->getRectangle().bottomRight()).toPoint();
|
||||
popupPoint = widget->mapToGlobal(popupPoint);
|
||||
dialog->move(popupPoint);
|
||||
}
|
||||
|
||||
dialog->exec();
|
||||
}
|
||||
|
||||
if (linkAction)
|
||||
{
|
||||
Q_EMIT actionTriggered(linkAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pageAnnotation.appearance = PDFAppeareanceStreams::Appearance::Normal;
|
||||
pageAnnotation.isHovered = false;
|
||||
}
|
||||
|
||||
const bool currentAppearanceChanged = oldAppearance != pageAnnotation.appearance;
|
||||
if (currentAppearanceChanged)
|
||||
{
|
||||
// We have changed appearance - we must mark stream as dirty
|
||||
pageAnnotation.appearanceStream.dirty();
|
||||
appearanceChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If appearance has changed, then we must redraw the page
|
||||
if (appearanceChanged)
|
||||
{
|
||||
Q_EMIT widget->getDrawWidgetProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::onShowPopupAnnotation()
|
||||
{
|
||||
PDFWidgetSnapshot snapshot = m_proxy->getSnapshot();
|
||||
for (const PDFWidgetSnapshot::SnapshotItem& snapshotItem : snapshot.items)
|
||||
{
|
||||
PageAnnotations& pageAnnotations = getPageAnnotations(snapshotItem.pageIndex);
|
||||
for (PageAnnotation& pageAnnotation : pageAnnotations.annotations)
|
||||
{
|
||||
if (pageAnnotation.annotation->isReplyTo())
|
||||
{
|
||||
// Annotation is reply to another annotation, do not interact with it
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pageAnnotation.annotation->getSelfReference() == m_editableAnnotation)
|
||||
{
|
||||
QDialog* dialog = createDialogForMarkupAnnotations(m_proxy->getWidget(), pageAnnotation, pageAnnotations);
|
||||
dialog->move(m_editableAnnotationGlobalPosition);
|
||||
dialog->exec();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::onCopyAnnotation()
|
||||
{
|
||||
pdf::PDFSelectPagesDialog dialog(tr("Copy Annotation"), tr("Copy Annotation onto Multiple Pages"),
|
||||
m_document->getCatalog()->getPageCount(), m_proxy->getWidget()->getDrawWidget()->getCurrentPages(), m_proxy->getWidget());
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
std::vector<PDFInteger> pages = dialog.getSelectedPages();
|
||||
const PDFInteger currentPageIndex = m_document->getCatalog()->getPageIndexFromPageReference(m_editableAnnotationPage);
|
||||
|
||||
for (PDFInteger& pageIndex : pages)
|
||||
{
|
||||
--pageIndex;
|
||||
}
|
||||
|
||||
auto it = std::find(pages.begin(), pages.end(), currentPageIndex);
|
||||
if (it != pages.end())
|
||||
{
|
||||
pages.erase(it);
|
||||
}
|
||||
|
||||
if (pages.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PDFDocumentModifier modifier(m_document);
|
||||
modifier.markAnnotationsChanged();
|
||||
|
||||
for (const PDFInteger pageIndex : pages)
|
||||
{
|
||||
modifier.getBuilder()->copyAnnotation(m_document->getCatalog()->getPage(pageIndex)->getPageReference(), m_editableAnnotation);
|
||||
}
|
||||
|
||||
if (modifier.finalize())
|
||||
{
|
||||
Q_EMIT documentModified(PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::onEditAnnotation()
|
||||
{
|
||||
PDFEditObjectDialog dialog(EditObjectType::Annotation, m_proxy->getWidget());
|
||||
|
||||
PDFObject originalObject = m_document->getObjectByReference(m_editableAnnotation);
|
||||
dialog.setObject(originalObject);
|
||||
|
||||
if (dialog.exec() == PDFEditObjectDialog::Accepted)
|
||||
{
|
||||
PDFObject object = dialog.getObject();
|
||||
if (object != originalObject)
|
||||
{
|
||||
PDFDocumentModifier modifier(m_document);
|
||||
modifier.markAnnotationsChanged();
|
||||
modifier.getBuilder()->setObject(m_editableAnnotation, object);
|
||||
modifier.getBuilder()->updateAnnotationAppearanceStreams(m_editableAnnotation);
|
||||
|
||||
if (modifier.finalize())
|
||||
{
|
||||
Q_EMIT documentModified(PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::onDeleteAnnotation()
|
||||
{
|
||||
if (m_editableAnnotation.isValid())
|
||||
{
|
||||
PDFDocumentModifier modifier(m_document);
|
||||
modifier.markAnnotationsChanged();
|
||||
modifier.getBuilder()->removeAnnotation(m_editableAnnotationPage, m_editableAnnotation);
|
||||
|
||||
if (modifier.finalize())
|
||||
{
|
||||
Q_EMIT documentModified(PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDialog* PDFWidgetAnnotationManager::createDialogForMarkupAnnotations(PDFWidget* widget,
|
||||
const PageAnnotation& pageAnnotation,
|
||||
const PageAnnotations& pageAnnotations)
|
||||
{
|
||||
QDialog* dialog = new QDialog(widget->getDrawWidget()->getWidget(), Qt::Popup);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
createWidgetsForMarkupAnnotations(dialog, pageAnnotation, pageAnnotations);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
void PDFWidgetAnnotationManager::createWidgetsForMarkupAnnotations(QWidget* parentWidget,
|
||||
const PageAnnotation& pageAnnotation,
|
||||
const PageAnnotations& pageAnnotations)
|
||||
{
|
||||
std::vector<const PageAnnotation*> replies = pageAnnotations.getReplies(pageAnnotation);
|
||||
replies.insert(replies.begin(), &pageAnnotation);
|
||||
|
||||
QScrollArea* scrollArea = new QScrollArea(parentWidget);
|
||||
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(parentWidget);
|
||||
layout->addWidget(scrollArea);
|
||||
layout->setContentsMargins(QMargins());
|
||||
|
||||
QWidget* frameWidget = new QWidget(scrollArea);
|
||||
QVBoxLayout* frameLayout = new QVBoxLayout(frameWidget);
|
||||
frameLayout->setSpacing(0);
|
||||
scrollArea->setWidget(frameWidget);
|
||||
|
||||
const PDFMarkupAnnotation* markupMainAnnotation = pageAnnotation.annotation->asMarkupAnnotation();
|
||||
QColor color = markupMainAnnotation->getDrawColorFromAnnotationColor(markupMainAnnotation->getColor(), 1.0);
|
||||
QColor titleColor = QColor::fromHslF(color.hueF(), color.saturationF(), 0.2f, 1.0f);
|
||||
QColor backgroundColor = QColor::fromHslF(color.hueF(), color.saturationF(), 0.9f, 1.0f);
|
||||
|
||||
QString style = "QGroupBox { "
|
||||
"border: 2px solid black; "
|
||||
"border-color: rgb(%4, %5, %6); "
|
||||
"margin-top: 3ex; "
|
||||
"background-color: rgb(%1, %2, %3); "
|
||||
"}"
|
||||
"QGroupBox::title { "
|
||||
"subcontrol-origin: margin; "
|
||||
"subcontrol-position: top center; "
|
||||
"padding: 0px 8192px; "
|
||||
"background-color: rgb(%4, %5, %6); "
|
||||
"color: #FFFFFF;"
|
||||
"}";
|
||||
style = style.arg(backgroundColor.red()).arg(backgroundColor.green()).arg(backgroundColor.blue()).arg(titleColor.red()).arg(titleColor.green()).arg(titleColor.blue());
|
||||
|
||||
for (const PageAnnotation* annotation : replies)
|
||||
{
|
||||
const PDFMarkupAnnotation* markupAnnotation = annotation->annotation->asMarkupAnnotation();
|
||||
|
||||
if (!markupAnnotation)
|
||||
{
|
||||
// This should not happen...
|
||||
continue;
|
||||
}
|
||||
|
||||
QGroupBox* groupBox = new QGroupBox(scrollArea);
|
||||
frameLayout->addWidget(groupBox);
|
||||
|
||||
QString title = markupAnnotation->getWindowTitle();
|
||||
if (title.isEmpty())
|
||||
{
|
||||
title = markupAnnotation->getSubject();
|
||||
}
|
||||
|
||||
QString dateTimeString = QLocale::system().toString(markupAnnotation->getCreationDate().toLocalTime(), QLocale::LongFormat);
|
||||
title = QString("%1 (%2)").arg(title, dateTimeString).trimmed();
|
||||
|
||||
groupBox->setStyleSheet(style);
|
||||
groupBox->setTitle(title);
|
||||
QVBoxLayout* groupBoxLayout = new QVBoxLayout(groupBox);
|
||||
|
||||
QLabel* label = new QLabel(groupBox);
|
||||
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
label->setWordWrap(true);
|
||||
label->setText(markupAnnotation->getContents());
|
||||
label->setFixedWidth(PDFWidgetUtils::scaleDPI_x(label, 250));
|
||||
label->setMinimumHeight(label->sizeHint().height());
|
||||
groupBoxLayout->addWidget(label);
|
||||
}
|
||||
|
||||
frameWidget->setFixedSize(frameWidget->minimumSizeHint());
|
||||
parentWidget->setFixedSize(scrollArea->sizeHint());
|
||||
}
|
||||
|
||||
} // namespace pdf
|
95
Pdf4QtLibWidgets/sources/pdfwidgetannotation.h
Normal file
95
Pdf4QtLibWidgets/sources/pdfwidgetannotation.h
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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 "pdfannotation.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDFDrawWidgetProxy;
|
||||
|
||||
/// Annotation manager for GUI rendering, it also manages annotations widgets
|
||||
/// for parent widget.
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFWidgetAnnotationManager : public PDFAnnotationManager, public IDrawWidgetInputInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFAnnotationManager;
|
||||
|
||||
public:
|
||||
explicit PDFWidgetAnnotationManager(PDFDrawWidgetProxy* proxy, QObject* parent);
|
||||
virtual ~PDFWidgetAnnotationManager() override;
|
||||
|
||||
virtual void setDocument(const PDFModifiedDocument& document) override;
|
||||
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||
|
||||
/// Returns tooltip generated from annotation
|
||||
virtual QString getTooltip() const override { return m_tooltip; }
|
||||
|
||||
/// Returns current cursor
|
||||
virtual const std::optional<QCursor>& getCursor() const override { return m_cursor; }
|
||||
|
||||
virtual int getInputPriority() const override { return AnnotationPriority; }
|
||||
|
||||
signals:
|
||||
void actionTriggered(const PDFAction* action);
|
||||
void documentModified(PDFModifiedDocument document);
|
||||
|
||||
private:
|
||||
void updateFromMouseEvent(QMouseEvent* event);
|
||||
|
||||
void onShowPopupAnnotation();
|
||||
void onCopyAnnotation();
|
||||
void onEditAnnotation();
|
||||
void onDeleteAnnotation();
|
||||
|
||||
/// Creates dialog for markup annotations. This function is used only for markup annotations,
|
||||
/// do not use them for other annotations (function can crash).
|
||||
/// \param widget Dialog's parent widget
|
||||
/// \param pageAnnotation Markup annotation
|
||||
/// \param pageAnnotations Page annotations
|
||||
QDialog* createDialogForMarkupAnnotations(PDFWidget* widget,
|
||||
const PageAnnotation& pageAnnotation,
|
||||
const PageAnnotations& pageAnnotations);
|
||||
|
||||
/// Creates widgets for markup annotation main popup widget. Also sets
|
||||
/// default size of parent widget.
|
||||
/// \param parentWidget Parent widget, where widgets are created
|
||||
/// \param pageAnnotation Markup annotation
|
||||
/// \param pageAnnotations Page annotations
|
||||
void createWidgetsForMarkupAnnotations(QWidget* parentWidget,
|
||||
const PageAnnotation& pageAnnotation,
|
||||
const PageAnnotations& pageAnnotations);
|
||||
|
||||
PDFDrawWidgetProxy* m_proxy;
|
||||
QString m_tooltip;
|
||||
std::optional<QCursor> m_cursor;
|
||||
QPoint m_editableAnnotationGlobalPosition; ///< Position, where action on annotation was executed
|
||||
PDFObjectReference m_editableAnnotation; ///< Annotation to be edited or deleted
|
||||
PDFObjectReference m_editableAnnotationPage; ///< Page of annotation above
|
||||
};
|
||||
|
||||
} // namespace pdf
|
@@ -34,7 +34,7 @@ namespace pdf
|
||||
/// Base class for various widget tools (for example, searching, text selection,
|
||||
/// screenshots, zoom tool etc.). Each tool can have subtools (for example,
|
||||
/// screenshot tool is picking screenshot rectangle).
|
||||
class PDF4QTLIBSHARED_EXPORT PDFWidgetTool : public QObject, public IDocumentDrawInterface
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFWidgetTool : public QObject, public IDocumentDrawInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -273,7 +273,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tool to magnify specific area in the drawing widget
|
||||
class PDF4QTLIBSHARED_EXPORT PDFMagnifierTool : public PDFWidgetTool
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFMagnifierTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -308,7 +308,7 @@ private:
|
||||
};
|
||||
|
||||
/// Tools for picking various items on page - points, rectangles, images etc.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPickTool : public PDFWidgetTool
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFPickTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -433,7 +433,7 @@ private:
|
||||
|
||||
/// Tool that makes screenshot of page area and copies it to the clipboard,
|
||||
/// using current client area to determine image size.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFScreenshotTool : public PDFWidgetTool
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFScreenshotTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -455,7 +455,7 @@ private:
|
||||
|
||||
/// Tool that extracts image from page and copies it to the clipboard,
|
||||
/// using image original size (not zoomed size from widget area)
|
||||
class PDF4QTLIBSHARED_EXPORT PDFExtractImageTool : public PDFWidgetTool
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFExtractImageTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -481,7 +481,7 @@ private:
|
||||
/// Manager used for managing tools, their activity, availability
|
||||
/// and other settings. It also defines a predefined set of tools,
|
||||
/// available for various purposes (text searching, magnifier tool etc.)
|
||||
class PDF4QTLIBSHARED_EXPORT PDFToolManager : public QObject, public IDrawWidgetInputInterface
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFToolManager : public QObject, public IDrawWidgetInputInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFWidgetUtils
|
||||
class PDF4QTLIBWIDGETSSHARED_EXPORT PDFWidgetUtils
|
||||
{
|
||||
public:
|
||||
PDFWidgetUtils() = delete;
|
||||
|
Reference in New Issue
Block a user