mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Issue #118: First part of splitting
This commit is contained in:
82
Pdf4QtLibWidgets/CMakeLists.txt
Normal file
82
Pdf4QtLibWidgets/CMakeLists.txt
Normal file
@ -0,0 +1,82 @@
|
||||
# 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/>.
|
||||
|
||||
add_library(Pdf4QtLibWidgets SHARED
|
||||
sources/pdfadvancedtools.cpp
|
||||
sources/pdfadvancedtools.h
|
||||
sources/pdfwidgettool.cpp
|
||||
sources/pdfwidgetutils.cpp
|
||||
sources/pdfwidgettool.h
|
||||
sources/pdfwidgetutils.h
|
||||
sources/pdfcertificatemanagerdialog.cpp
|
||||
sources/pdfcertificatemanagerdialog.h
|
||||
sources/pdfcertificatemanagerdialog.ui
|
||||
sources/pdfcreatecertificatedialog.cpp
|
||||
sources/pdfcreatecertificatedialog.h
|
||||
sources/pdfcreatecertificatedialog.ui
|
||||
sources/pdfdrawwidget.cpp
|
||||
sources/pdfdrawwidget.h
|
||||
sources/pdfobjecteditorwidget.h
|
||||
sources/pdfobjecteditorwidget_impl.h
|
||||
sources/pdfobjecteditorwidget.cpp
|
||||
sources/pdfpagecontenteditorstylesettings.h
|
||||
sources/pdfpagecontenteditorstylesettings.cpp
|
||||
sources/pdfpagecontenteditorstylesettings.ui
|
||||
sources/pdfpagecontenteditortools.cpp
|
||||
sources/pdfpagecontenteditorwidget.cpp
|
||||
sources/pdfpagecontenteditortools.h
|
||||
sources/pdfpagecontenteditorwidget.h
|
||||
sources/pdfpagecontenteditorwidget.ui
|
||||
sources/pdfrenderingerrorswidget.h
|
||||
sources/pdfrenderingerrorswidget.cpp
|
||||
sources/pdfrenderingerrorswidget.ui
|
||||
sources/pdfselectpagesdialog.h
|
||||
sources/pdfselectpagesdialog.cpp
|
||||
sources/pdfselectpagesdialog.ui
|
||||
)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
GENERATE_EXPORT_HEADER(Pdf4QtLibWidgets
|
||||
EXPORT_MACRO_NAME
|
||||
PDF4QTLIBSHARED_EXPORT
|
||||
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtlibwidgets_export.h")
|
||||
|
||||
if(PDF4QT_ENABLE_OPENGL)
|
||||
target_link_libraries(Pdf4QtLibWidgets PRIVATE Qt6::OpenGLWidgets)
|
||||
endif()
|
||||
|
||||
target_link_libraries(Pdf4QtLibWidgets PRIVATE Pdf4QtLibCore Qt6::Core Qt6::Gui Qt6::Xml Qt6::Svg Qt6::Widgets)
|
||||
|
||||
if(LINUX_GCC)
|
||||
target_link_libraries(Pdf4QtLibWidgets PUBLIC TBB::tbb)
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
target_link_libraries(Pdf4QtLibWidgets PRIVATE Secur32 Mscms Gdi32 User32 crypt32)
|
||||
endif()
|
||||
|
||||
target_include_directories(Pdf4QtLibWidgets INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/sources)
|
||||
target_include_directories(Pdf4QtLibWidgets PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})
|
||||
|
||||
set_target_properties(Pdf4QtLibWidgets PROPERTIES
|
||||
VERSION ${PDF4QT_VERSION}
|
||||
SOVERSION ${PDF4QT_VERSION}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_LIB_DIR}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${PDF4QT_INSTALL_BIN_DIR})
|
||||
|
||||
install(TARGETS Pdf4QtLibWidgets RUNTIME DESTINATION ${PDF4QT_INSTALL_BIN_DIR} LIBRARY DESTINATION ${PDF4QT_INSTALL_LIB_DIR})
|
1324
Pdf4QtLibWidgets/sources/pdfadvancedtools.cpp
Normal file
1324
Pdf4QtLibWidgets/sources/pdfadvancedtools.cpp
Normal file
File diff suppressed because it is too large
Load Diff
383
Pdf4QtLibWidgets/sources/pdfadvancedtools.h
Normal file
383
Pdf4QtLibWidgets/sources/pdfadvancedtools.h
Normal file
@ -0,0 +1,383 @@
|
||||
// Copyright (C) 2020-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 PDFADVANCEDTOOLS_H
|
||||
#define PDFADVANCEDTOOLS_H
|
||||
|
||||
#include "pdfwidgettool.h"
|
||||
#include "pdfannotation.h"
|
||||
|
||||
class QActionGroup;
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateStickyNoteTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent);
|
||||
|
||||
protected:
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void onActionTriggered(QAction* action);
|
||||
void onPointPicked(PDFInteger pageIndex, QPointF pagePoint);
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
QActionGroup* m_actionGroup;
|
||||
PDFPickTool* m_pickTool;
|
||||
TextAnnotationIcon m_icon;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateAnnotationTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateAnnotationTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
|
||||
protected:
|
||||
virtual void updateActions() override;
|
||||
};
|
||||
|
||||
/// 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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreateAnnotationTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateHyperlinkTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||
|
||||
LinkHighlightMode getHighlightMode() const;
|
||||
void setHighlightMode(const LinkHighlightMode& highlightMode);
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFPickTool* m_pickTool;
|
||||
LinkHighlightMode m_highlightMode = LinkHighlightMode::Outline;
|
||||
};
|
||||
|
||||
/// Tool that creates free text note without callout line.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateFreeTextTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreateAnnotationTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateFreeTextTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFPickTool* m_pickTool;
|
||||
};
|
||||
|
||||
/// Tool that creates line/polyline/polygon annotations.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateLineTypeTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreateAnnotationTool;
|
||||
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
Line,
|
||||
PolyLine,
|
||||
Polygon,
|
||||
Rectangle
|
||||
};
|
||||
|
||||
explicit PDFCreateLineTypeTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, Type type, QAction* action, QObject* parent);
|
||||
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
PDFReal getPenWidth() const;
|
||||
void setPenWidth(PDFReal penWidth);
|
||||
|
||||
QColor getStrokeColor() const;
|
||||
void setStrokeColor(const QColor& strokeColor);
|
||||
|
||||
QColor getFillColor() const;
|
||||
void setFillColor(const QColor& fillColor);
|
||||
|
||||
private:
|
||||
void onPointPicked(PDFInteger pageIndex, QPointF pagePoint);
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
void finishDefinition();
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFPickTool* m_pickTool;
|
||||
Type m_type;
|
||||
PDFReal m_penWidth;
|
||||
QColor m_strokeColor;
|
||||
QColor m_fillColor;
|
||||
PDFInteger m_rectPageIndex = 0;
|
||||
QRectF m_rectOnPage;
|
||||
};
|
||||
|
||||
/// Tool that creates ellipse annotation.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateEllipseTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreateAnnotationTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateEllipseTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
PDFReal getPenWidth() const;
|
||||
void setPenWidth(PDFReal penWidth);
|
||||
|
||||
QColor getStrokeColor() const;
|
||||
void setStrokeColor(const QColor& strokeColor);
|
||||
|
||||
QColor getFillColor() const;
|
||||
void setFillColor(const QColor& fillColor);
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFReal m_penWidth;
|
||||
QColor m_strokeColor;
|
||||
QColor m_fillColor;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateFreehandCurveTool : public PDFCreateAnnotationTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreateAnnotationTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateFreehandCurveTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
PDFReal getPenWidth() const;
|
||||
void setPenWidth(const PDFReal& penWidth);
|
||||
|
||||
QColor getStrokeColor() const;
|
||||
void setStrokeColor(const QColor& strokeColor);
|
||||
|
||||
private:
|
||||
void resetTool();
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFInteger m_pageIndex;
|
||||
std::vector<QPointF> m_pickedPoints;
|
||||
PDFReal m_penWidth;
|
||||
QColor m_strokeColor;
|
||||
};
|
||||
|
||||
/// 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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateStampTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void onActionTriggered(QAction* action);
|
||||
void onPointPicked(PDFInteger pageIndex, QPointF pagePoint);
|
||||
|
||||
pdf::PDFInteger m_pageIndex;
|
||||
PDFToolManager* m_toolManager;
|
||||
QActionGroup* m_actionGroup;
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFStampAnnotation m_stampAnnotation;
|
||||
};
|
||||
|
||||
/// Tool for highlighting of text in document
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateHighlightTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
|
||||
/// Creates new highlight text tool
|
||||
/// \param proxy Proxy
|
||||
/// \param type Annotation type, must be one of: Highlight, Underline, Squiggly, StrikeOut
|
||||
/// \param actionGroup Action group with actions. Each action must define annotation type.
|
||||
/// \param parent Parent
|
||||
explicit PDFCreateHighlightTextTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QActionGroup* actionGroup, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void updateActions() override;
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
void onActionTriggered(QAction* action);
|
||||
void updateCursor();
|
||||
void setSelection(pdf::PDFTextSelection&& textSelection);
|
||||
|
||||
struct SelectionInfo
|
||||
{
|
||||
PDFInteger pageIndex = -1;
|
||||
QPointF selectionStartPoint;
|
||||
};
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
QActionGroup* m_actionGroup;
|
||||
AnnotationType m_type;
|
||||
pdf::PDFTextSelection m_textSelection;
|
||||
SelectionInfo m_selectionInfo;
|
||||
bool m_isCursorOverText;
|
||||
};
|
||||
|
||||
/// 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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreateAnnotationTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateRedactRectangleTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFPickTool* m_pickTool;
|
||||
};
|
||||
|
||||
/// Tool for redaction of text in document. Creates redaction annotation from text selection.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateRedactTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreateRedactTextTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, QAction* action, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void updateActions() override;
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
void updateCursor();
|
||||
void setSelection(pdf::PDFTextSelection&& textSelection);
|
||||
|
||||
struct SelectionInfo
|
||||
{
|
||||
PDFInteger pageIndex = -1;
|
||||
QPointF selectionStartPoint;
|
||||
};
|
||||
|
||||
PDFToolManager* m_toolManager;
|
||||
pdf::PDFTextSelection m_textSelection;
|
||||
SelectionInfo m_selectionInfo;
|
||||
bool m_isCursorOverText;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFADVANCEDTOOLS_H
|
133
Pdf4QtLibWidgets/sources/pdfcertificatemanagerdialog.cpp
Normal file
133
Pdf4QtLibWidgets/sources/pdfcertificatemanagerdialog.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// 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/>.
|
||||
|
||||
#include "pdfcertificatemanagerdialog.h"
|
||||
#include "ui_pdfcertificatemanagerdialog.h"
|
||||
#include "pdfcreatecertificatedialog.h"
|
||||
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QPushButton>
|
||||
#include <QFileSystemModel>
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFCertificateManagerDialog::PDFCertificateManagerDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::PDFCertificateManagerDialog),
|
||||
m_newCertificateButton(nullptr),
|
||||
m_openCertificateDirectoryButton(nullptr),
|
||||
m_deleteCertificateButton(nullptr),
|
||||
m_importCertificateButton(nullptr),
|
||||
m_certificateFileModel(nullptr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QDir::root().mkpath(PDFCertificateManager::getCertificateDirectory());
|
||||
|
||||
m_certificateFileModel = new QFileSystemModel(this);
|
||||
QModelIndex rootIndex = m_certificateFileModel->setRootPath(PDFCertificateManager::getCertificateDirectory());
|
||||
ui->fileView->setModel(m_certificateFileModel);
|
||||
ui->fileView->setRootIndex(rootIndex);
|
||||
|
||||
m_newCertificateButton = ui->buttonBox->addButton(tr("Create"), QDialogButtonBox::ActionRole);
|
||||
m_openCertificateDirectoryButton = ui->buttonBox->addButton(tr("Open Directory"), QDialogButtonBox::ActionRole);
|
||||
m_deleteCertificateButton = ui->buttonBox->addButton(tr("Delete"), QDialogButtonBox::ActionRole);
|
||||
m_importCertificateButton = ui->buttonBox->addButton(tr("Import"), QDialogButtonBox::ActionRole);
|
||||
|
||||
connect(m_newCertificateButton, &QPushButton::clicked, this, &PDFCertificateManagerDialog::onNewCertificateClicked);
|
||||
connect(m_openCertificateDirectoryButton, &QPushButton::clicked, this, &PDFCertificateManagerDialog::onOpenCertificateDirectoryClicked);
|
||||
connect(m_deleteCertificateButton, &QPushButton::clicked, this, &PDFCertificateManagerDialog::onDeleteCertificateClicked);
|
||||
connect(m_importCertificateButton, &QPushButton::clicked, this, &PDFCertificateManagerDialog::onImportCertificateClicked);
|
||||
|
||||
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(640, 480)));
|
||||
}
|
||||
|
||||
PDFCertificateManagerDialog::~PDFCertificateManagerDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PDFCertificateManagerDialog::onNewCertificateClicked()
|
||||
{
|
||||
PDFCreateCertificateDialog dialog(this);
|
||||
if (dialog.exec() == PDFCreateCertificateDialog::Accepted)
|
||||
{
|
||||
const PDFCertificateManager::NewCertificateInfo info = dialog.getNewCertificateInfo();
|
||||
m_certificateManager.createCertificate(info);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCertificateManagerDialog::onOpenCertificateDirectoryClicked()
|
||||
{
|
||||
QDesktopServices::openUrl(QString("file:///%1").arg(PDFCertificateManager::getCertificateDirectory(), QUrl::TolerantMode));
|
||||
}
|
||||
|
||||
void PDFCertificateManagerDialog::onDeleteCertificateClicked()
|
||||
{
|
||||
QFileInfo fileInfo = m_certificateFileModel->fileInfo(ui->fileView->currentIndex());
|
||||
if (fileInfo.exists())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Confirm delete"), tr("Do you want to delete certificate '%1'?").arg(fileInfo.fileName()), QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes)
|
||||
{
|
||||
QFile file(fileInfo.filePath());
|
||||
if (!file.remove())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot delete certificate '%1'").arg(fileInfo.fileName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCertificateManagerDialog::onImportCertificateClicked()
|
||||
{
|
||||
QString selectedFile = QFileDialog::getOpenFileName(this, tr("Import Certificate"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), tr("Certificate file (*.pfx);;All files (*.*)"));
|
||||
|
||||
if (selectedFile.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(selectedFile);
|
||||
if (file.exists())
|
||||
{
|
||||
QString path = PDFCertificateManager::getCertificateDirectory();
|
||||
QString targetFile = QString("%1/%2").arg(path, QFileInfo(file).fileName());
|
||||
if (QFile::exists(targetFile))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Target file exists. Please rename the certificate file to import."));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file.copy(targetFile))
|
||||
{
|
||||
QMessageBox::information(this, tr("Import Certificate"), tr("Certificate '%1' was successfully imported.").arg(file.fileName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Import Certificate"), tr("Error occured during certificate '%1' import.").arg(file.fileName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdf
|
61
Pdf4QtLibWidgets/sources/pdfcertificatemanagerdialog.h
Normal file
61
Pdf4QtLibWidgets/sources/pdfcertificatemanagerdialog.h
Normal file
@ -0,0 +1,61 @@
|
||||
// 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 PDFCERTIFICATEMANAGERDIALOG_H
|
||||
#define PDFCERTIFICATEMANAGERDIALOG_H
|
||||
|
||||
#include "pdfcertificatemanager.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QAction;
|
||||
class QFileSystemModel;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFCertificateManagerDialog;
|
||||
}
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCertificateManagerDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFCertificateManagerDialog(QWidget* parent);
|
||||
virtual ~PDFCertificateManagerDialog() override;
|
||||
|
||||
private:
|
||||
void onNewCertificateClicked();
|
||||
void onOpenCertificateDirectoryClicked();
|
||||
void onDeleteCertificateClicked();
|
||||
void onImportCertificateClicked();
|
||||
|
||||
Ui::PDFCertificateManagerDialog* ui;
|
||||
PDFCertificateManager m_certificateManager;
|
||||
QPushButton* m_newCertificateButton;
|
||||
QPushButton* m_openCertificateDirectoryButton;
|
||||
QPushButton* m_deleteCertificateButton;
|
||||
QPushButton* m_importCertificateButton;
|
||||
QFileSystemModel* m_certificateFileModel;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFCERTIFICATEMANAGERDIALOG_H
|
76
Pdf4QtLibWidgets/sources/pdfcertificatemanagerdialog.ui
Normal file
76
Pdf4QtLibWidgets/sources/pdfcertificatemanagerdialog.ui
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFCertificateManagerDialog</class>
|
||||
<widget class="QDialog" name="PDFCertificateManagerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>789</width>
|
||||
<height>511</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Certificate Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="certificateGroupBox">
|
||||
<property name="title">
|
||||
<string>Certificates</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTreeView" name="fileView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PDFCertificateManagerDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PDFCertificateManagerDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
162
Pdf4QtLibWidgets/sources/pdfcreatecertificatedialog.cpp
Normal file
162
Pdf4QtLibWidgets/sources/pdfcreatecertificatedialog.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
// 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/>.
|
||||
|
||||
#include "pdfcreatecertificatedialog.h"
|
||||
#include "ui_pdfcreatecertificatedialog.h"
|
||||
|
||||
#include "pdfcertificatemanager.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
#include <QDate>
|
||||
#include <QCalendar>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFCreateCertificateDialog::PDFCreateCertificateDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::PDFCreateCertificateDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->fileNameEdit->setReadOnly(true);
|
||||
ui->fileNameEdit->setText(PDFCertificateManager::generateCertificateFileName());
|
||||
|
||||
ui->keyLengthCombo->addItem(tr("1024 bits"), 1024);
|
||||
ui->keyLengthCombo->addItem(tr("2048 bits"), 2048);
|
||||
ui->keyLengthCombo->addItem(tr("4096 bits"), 4096);
|
||||
ui->keyLengthCombo->setCurrentIndex(ui->keyLengthCombo->findData(2048));
|
||||
|
||||
QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||
std::sort(locales.begin(), locales.end(), [](const QLocale& left, const QLocale& right) { return QString::compare(left.nativeTerritoryName(), right.nativeTerritoryName(), Qt::CaseInsensitive) < 0; });
|
||||
|
||||
int currentIndex = 0;
|
||||
QLocale currentLocale = QLocale::system();
|
||||
|
||||
for (const QLocale& locale : locales)
|
||||
{
|
||||
if (locale.territory() == QLocale::AnyTerritory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (locale.nativeTerritoryName().isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QString localeName = locale.name();
|
||||
QString countryCode = localeName.split(QChar('_')).back();
|
||||
QString text = QString("%1 | %2").arg(countryCode, locale.nativeTerritoryName());
|
||||
|
||||
if (ui->countryCombo->findText(text) >= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (locale.bcp47Name() == currentLocale.bcp47Name())
|
||||
{
|
||||
currentIndex = ui->countryCombo->count();
|
||||
}
|
||||
|
||||
ui->countryCombo->addItem(text, countryCode);
|
||||
}
|
||||
|
||||
ui->countryCombo->setCurrentIndex(currentIndex);
|
||||
ui->countryCombo->setMaxVisibleItems(25);
|
||||
|
||||
QDate minDate = QDate::currentDate();
|
||||
ui->validTillEdit->setMinimumDate(minDate);
|
||||
|
||||
QDate selectedDate = minDate;
|
||||
selectedDate = selectedDate.addYears(5, ui->validTillEdit->calendar());
|
||||
ui->validTillEdit->setSelectedDate(selectedDate);
|
||||
}
|
||||
|
||||
PDFCreateCertificateDialog::~PDFCreateCertificateDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PDFCreateCertificateDialog::accept()
|
||||
{
|
||||
if (validate())
|
||||
{
|
||||
bool ok = false;
|
||||
QString password1 = QInputDialog::getText(this, tr("Certificate Protection"), tr("Enter password to protect your certificate."), QLineEdit::Password, QString(), &ok);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString password2 = QInputDialog::getText(this, tr("Certificate Protection"), tr("Enter password again to verify password text."), QLineEdit::Password, QString(), &ok);
|
||||
|
||||
if (password1 != password2)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Reentered password is not equal to the first one!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QDate date = ui->validTillEdit->selectedDate();
|
||||
QDate currentDate = QDate::currentDate();
|
||||
int days = currentDate.daysTo(date);
|
||||
|
||||
// Fill certificate info
|
||||
m_newCertificateInfo.fileName = ui->fileNameEdit->text();
|
||||
m_newCertificateInfo.privateKeyPasword = password1;
|
||||
m_newCertificateInfo.certCountryCode = ui->countryCombo->currentData().toString();
|
||||
m_newCertificateInfo.certOrganization = ui->organizationEdit->text();
|
||||
m_newCertificateInfo.certOrganizationUnit = ui->organizationUnitEdit->text();
|
||||
m_newCertificateInfo.certCommonName = ui->commonNameEdit->text();
|
||||
m_newCertificateInfo.certEmail = ui->emailEdit->text();
|
||||
m_newCertificateInfo.rsaKeyLength = ui->keyLengthCombo->currentData().toInt();
|
||||
m_newCertificateInfo.validityInSeconds = days * 24 * 3600;
|
||||
|
||||
BaseClass::accept();
|
||||
}
|
||||
}
|
||||
|
||||
bool PDFCreateCertificateDialog::validate()
|
||||
{
|
||||
// validate empty text fields
|
||||
if (ui->commonNameEdit->text().isEmpty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please enter a name!"));
|
||||
ui->commonNameEdit->setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ui->organizationEdit->text().isEmpty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please enter an organization name!"));
|
||||
ui->organizationEdit->setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ui->emailEdit->text().isEmpty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please enter an email address!"));
|
||||
ui->emailEdit->setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
59
Pdf4QtLibWidgets/sources/pdfcreatecertificatedialog.h
Normal file
59
Pdf4QtLibWidgets/sources/pdfcreatecertificatedialog.h
Normal file
@ -0,0 +1,59 @@
|
||||
// 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 PDFCREATECERTIFICATEDIALOG_H
|
||||
#define PDFCREATECERTIFICATEDIALOG_H
|
||||
|
||||
#include "pdfcertificatemanager.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFCreateCertificateDialog;
|
||||
}
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreateCertificateDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QDialog;
|
||||
|
||||
public:
|
||||
explicit PDFCreateCertificateDialog(QWidget* parent);
|
||||
virtual ~PDFCreateCertificateDialog() override;
|
||||
|
||||
const PDFCertificateManager::NewCertificateInfo& getNewCertificateInfo() const { return m_newCertificateInfo; }
|
||||
|
||||
public slots:
|
||||
virtual void accept() override;
|
||||
|
||||
private:
|
||||
bool validate();
|
||||
|
||||
PDFCertificateManager::NewCertificateInfo m_newCertificateInfo;
|
||||
|
||||
Ui::PDFCreateCertificateDialog* ui;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFCREATECERTIFICATEDIALOG_H
|
182
Pdf4QtLibWidgets/sources/pdfcreatecertificatedialog.ui
Normal file
182
Pdf4QtLibWidgets/sources/pdfcreatecertificatedialog.ui
Normal file
@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFCreateCertificateDialog</class>
|
||||
<widget class="QDialog" name="PDFCreateCertificateDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>514</width>
|
||||
<height>488</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Certificate</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="certificateGroupBox">
|
||||
<property name="title">
|
||||
<string>Create Self Signed Certificate</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="commonNameEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="organizationLabel">
|
||||
<property name="text">
|
||||
<string>Organization</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="organizationUnitLabel">
|
||||
<property name="text">
|
||||
<string>Organization Unit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="emailLabel">
|
||||
<property name="text">
|
||||
<string>Email</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="organizationEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="organizationUnitEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="emailEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="countryLabel">
|
||||
<property name="text">
|
||||
<string>Country</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="keyLengthLabel">
|
||||
<property name="text">
|
||||
<string>Key length</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="validityLabel">
|
||||
<property name="text">
|
||||
<string>Valid till</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCalendarWidget" name="validTillEdit"/>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="keyLengthCombo"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="countryCombo"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="fileNameEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="certificateFileLabel">
|
||||
<property name="text">
|
||||
<string>Certificate file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PDFCreateCertificateDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PDFCreateCertificateDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
658
Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp
Normal file
658
Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp
Normal file
@ -0,0 +1,658 @@
|
||||
// Copyright (C) 2018-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 "pdfdrawspacecontroller.h"
|
||||
#include "pdfcompiler.h"
|
||||
#include "pdfwidgettool.h"
|
||||
#include "pdfannotation.h"
|
||||
#include "pdfform.h"
|
||||
#include "pdfdbgheap.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QGridLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QApplication>
|
||||
#include <QPixmapCache>
|
||||
#include <QColorSpace>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_cmsManager(cmsManager),
|
||||
m_toolManager(nullptr),
|
||||
m_annotationManager(nullptr),
|
||||
m_formManager(nullptr),
|
||||
m_drawWidget(nullptr),
|
||||
m_horizontalScrollBar(nullptr),
|
||||
m_verticalScrollBar(nullptr),
|
||||
m_proxy(nullptr)
|
||||
{
|
||||
m_drawWidget = createDrawWidget(getEffectiveRenderer(engine), samplesCount);
|
||||
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
|
||||
m_verticalScrollBar = new QScrollBar(Qt::Vertical, this);
|
||||
|
||||
QGridLayout* layout = new QGridLayout(this);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(m_drawWidget->getWidget(), 0, 0);
|
||||
layout->addWidget(m_horizontalScrollBar, 1, 0);
|
||||
layout->addWidget(m_verticalScrollBar, 0, 1);
|
||||
layout->setContentsMargins(QMargins());
|
||||
|
||||
setLayout(layout);
|
||||
setFocusProxy(m_drawWidget->getWidget());
|
||||
|
||||
m_proxy = new PDFDrawWidgetProxy(this);
|
||||
m_proxy->init(this);
|
||||
connect(m_proxy, &PDFDrawWidgetProxy::renderingError, this, &PDFWidget::onRenderingError);
|
||||
connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
|
||||
connect(m_proxy, &PDFDrawWidgetProxy::pageImageChanged, this, &PDFWidget::onPageImageChanged);
|
||||
updateRendererImpl();
|
||||
}
|
||||
|
||||
PDFWidget::~PDFWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PDFWidget::focusNextPrevChild(bool next)
|
||||
{
|
||||
if (m_formManager && m_formManager->focusNextPrevFormField(next))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return QWidget::focusNextPrevChild(next);
|
||||
}
|
||||
|
||||
void PDFWidget::setDocument(const PDFModifiedDocument& document)
|
||||
{
|
||||
m_proxy->setDocument(document);
|
||||
m_pageRenderingErrors.clear();
|
||||
m_drawWidget->getWidget()->update();
|
||||
}
|
||||
|
||||
void PDFWidget::updateRenderer(RendererEngine engine, int samplesCount)
|
||||
{
|
||||
engine = getEffectiveRenderer(engine);
|
||||
|
||||
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
|
||||
PDFDrawWidget* softwareDrawWidget = qobject_cast<PDFDrawWidget*>(m_drawWidget->getWidget());
|
||||
|
||||
// Do we need to change renderer?
|
||||
if ((openglDrawWidget && engine != RendererEngine::OpenGL) || (softwareDrawWidget && engine != RendererEngine::Software))
|
||||
{
|
||||
QGridLayout* layout = qobject_cast<QGridLayout*>(this->layout());
|
||||
layout->removeWidget(m_drawWidget->getWidget());
|
||||
delete m_drawWidget->getWidget();
|
||||
|
||||
m_drawWidget = createDrawWidget(engine, samplesCount);
|
||||
layout->addWidget(m_drawWidget->getWidget(), 0, 0);
|
||||
setFocusProxy(m_drawWidget->getWidget());
|
||||
connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
|
||||
}
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
else if (openglDrawWidget)
|
||||
{
|
||||
// Just check the samples count
|
||||
QSurfaceFormat format = openglDrawWidget->format();
|
||||
if (format.samples() != samplesCount)
|
||||
{
|
||||
format.setSamples(samplesCount);
|
||||
openglDrawWidget->setFormat(format);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
updateRendererImpl();
|
||||
}
|
||||
|
||||
void PDFWidget::updateCacheLimits(int compiledPageCacheLimit, int thumbnailsCacheLimit, int fontCacheLimit, int instancedFontCacheLimit)
|
||||
{
|
||||
m_proxy->getCompiler()->setCacheLimit(compiledPageCacheLimit);
|
||||
QPixmapCache::setCacheLimit(thumbnailsCacheLimit);
|
||||
m_proxy->getFontCache()->setCacheLimits(fontCacheLimit, instancedFontCacheLimit);
|
||||
}
|
||||
|
||||
int PDFWidget::getPageRenderingErrorCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const auto& item : m_pageRenderingErrors)
|
||||
{
|
||||
count += item.second.size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void PDFWidget::updateRendererImpl()
|
||||
{
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
|
||||
m_proxy->updateRenderer(openglDrawWidget != nullptr, openglDrawWidget ? openglDrawWidget->format() : QSurfaceFormat::defaultFormat());
|
||||
#else
|
||||
m_proxy->updateRenderer(false, QSurfaceFormat::defaultFormat());
|
||||
#endif
|
||||
}
|
||||
|
||||
void PDFWidget::onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors)
|
||||
{
|
||||
// Empty list of error should not be reported!
|
||||
Q_ASSERT(!errors.empty());
|
||||
m_pageRenderingErrors[pageIndex] = errors;
|
||||
Q_EMIT pageRenderingErrorsChanged(pageIndex, errors.size());
|
||||
}
|
||||
|
||||
void PDFWidget::onPageImageChanged(bool all, const std::vector<PDFInteger>& pages)
|
||||
{
|
||||
if (all)
|
||||
{
|
||||
m_drawWidget->getWidget()->update();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<PDFInteger> currentPages = m_drawWidget->getCurrentPages();
|
||||
|
||||
Q_ASSERT(std::is_sorted(pages.cbegin(), pages.cend()));
|
||||
for (PDFInteger pageIndex : currentPages)
|
||||
{
|
||||
if (std::binary_search(pages.cbegin(), pages.cend(), pageIndex))
|
||||
{
|
||||
m_drawWidget->getWidget()->update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IDrawWidget* PDFWidget::createDrawWidget(RendererEngine rendererEngine, int samplesCount)
|
||||
{
|
||||
switch (rendererEngine)
|
||||
{
|
||||
case RendererEngine::Software:
|
||||
return new PDFDrawWidget(this, this);
|
||||
|
||||
case RendererEngine::OpenGL:
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
return new PDFOpenGLDrawWidget(this, samplesCount, this);
|
||||
#else
|
||||
Q_UNUSED(samplesCount);
|
||||
return new PDFDrawWidget(this, this);
|
||||
#endif
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PDFWidget::removeInputInterface(IDrawWidgetInputInterface* inputInterface)
|
||||
{
|
||||
auto it = std::find(m_inputInterfaces.begin(), m_inputInterfaces.end(), inputInterface);
|
||||
if (it != m_inputInterfaces.end())
|
||||
{
|
||||
m_inputInterfaces.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
|
||||
{
|
||||
if (inputInterface)
|
||||
{
|
||||
m_inputInterfaces.push_back(inputInterface);
|
||||
std::sort(m_inputInterfaces.begin(), m_inputInterfaces.end(), IDrawWidgetInputInterface::Comparator());
|
||||
}
|
||||
}
|
||||
|
||||
RendererEngine PDFWidget::getEffectiveRenderer(RendererEngine rendererEngine)
|
||||
{
|
||||
if (rendererEngine == RendererEngine::OpenGL && !pdf::PDFRendererInfo::isHardwareAccelerationSupported())
|
||||
{
|
||||
return RendererEngine::Software;
|
||||
}
|
||||
|
||||
return rendererEngine;
|
||||
}
|
||||
|
||||
PDFFormManager* PDFWidget::getFormManager() const
|
||||
{
|
||||
return m_formManager;
|
||||
}
|
||||
|
||||
void PDFWidget::setFormManager(PDFFormManager* formManager)
|
||||
{
|
||||
removeInputInterface(m_formManager);
|
||||
m_formManager = formManager;
|
||||
addInputInterface(m_formManager);
|
||||
}
|
||||
|
||||
void PDFWidget::setToolManager(PDFToolManager* toolManager)
|
||||
{
|
||||
removeInputInterface(m_toolManager);
|
||||
m_toolManager = toolManager;
|
||||
addInputInterface(m_toolManager);
|
||||
}
|
||||
|
||||
void PDFWidget::setAnnotationManager(PDFWidgetAnnotationManager* annotationManager)
|
||||
{
|
||||
removeInputInterface(m_annotationManager);
|
||||
m_annotationManager = annotationManager;
|
||||
addInputInterface(m_annotationManager);
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
PDFDrawWidgetBase<BaseWidget>::PDFDrawWidgetBase(PDFWidget* widget, QWidget* parent) :
|
||||
BaseWidget(parent),
|
||||
m_widget(widget),
|
||||
m_mouseOperation(MouseOperation::None)
|
||||
{
|
||||
this->setFocusPolicy(Qt::StrongFocus);
|
||||
this->setMouseTracking(true);
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
std::vector<PDFInteger> PDFDrawWidgetBase<BaseWidget>::getCurrentPages() const
|
||||
{
|
||||
return this->m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect());
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
QSize PDFDrawWidgetBase<BaseWidget>::minimumSizeHint() const
|
||||
{
|
||||
return QSize(200, 200);
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
bool PDFDrawWidgetBase<BaseWidget>::event(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::ShortcutOverride)
|
||||
{
|
||||
return processEvent<QKeyEvent, &IDrawWidgetInputInterface::shortcutOverrideEvent>(static_cast<QKeyEvent*>(event));
|
||||
}
|
||||
|
||||
return BaseWidget::event(event);
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::performMouseOperation(QPoint currentMousePosition)
|
||||
{
|
||||
switch (m_mouseOperation)
|
||||
{
|
||||
case MouseOperation::None:
|
||||
// No operation performed
|
||||
break;
|
||||
|
||||
case MouseOperation::Translate:
|
||||
{
|
||||
QPoint difference = currentMousePosition - m_lastMousePosition;
|
||||
m_widget->getDrawWidgetProxy()->scrollByPixels(difference);
|
||||
m_lastMousePosition = currentMousePosition;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
template<typename Event, void (IDrawWidgetInputInterface::* Function)(QWidget*, Event*)>
|
||||
bool PDFDrawWidgetBase<BaseWidget>::processEvent(Event* event)
|
||||
{
|
||||
QString tooltip;
|
||||
for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces())
|
||||
{
|
||||
(inputInterface->*Function)(this, event);
|
||||
|
||||
// Update tooltip
|
||||
if (tooltip.isEmpty())
|
||||
{
|
||||
tooltip = inputInterface->getTooltip();
|
||||
}
|
||||
|
||||
// If event is accepted, then update cursor/tooltip and return
|
||||
if (event->isAccepted())
|
||||
{
|
||||
this->setToolTip(tooltip);
|
||||
this->updateCursor();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this->setToolTip(tooltip);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QKeyEvent, &IDrawWidgetInputInterface::keyPressEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Vertical navigation
|
||||
QScrollBar* verticalScrollbar = m_widget->getVerticalScrollbar();
|
||||
if (verticalScrollbar->isVisible())
|
||||
{
|
||||
constexpr std::pair<QKeySequence::StandardKey, PDFDrawWidgetProxy::Operation> keyToOperations[] =
|
||||
{
|
||||
{ QKeySequence::MoveToStartOfDocument, PDFDrawWidgetProxy::NavigateDocumentStart },
|
||||
{ QKeySequence::MoveToEndOfDocument, PDFDrawWidgetProxy::NavigateDocumentEnd },
|
||||
{ QKeySequence::MoveToNextPage, PDFDrawWidgetProxy::NavigateNextPage },
|
||||
{ QKeySequence::MoveToPreviousPage, PDFDrawWidgetProxy::NavigatePreviousPage },
|
||||
{ QKeySequence::MoveToNextLine, PDFDrawWidgetProxy::NavigateNextStep },
|
||||
{ QKeySequence::MoveToPreviousLine, PDFDrawWidgetProxy::NavigatePreviousStep }
|
||||
};
|
||||
|
||||
for (const std::pair<QKeySequence::StandardKey, PDFDrawWidgetProxy::Operation>& keyToOperation : keyToOperations)
|
||||
{
|
||||
if (event->matches(keyToOperation.first))
|
||||
{
|
||||
m_widget->getDrawWidgetProxy()->performOperation(keyToOperation.second);
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::keyReleaseEvent(QKeyEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QKeyEvent, &IDrawWidgetInputInterface::keyReleaseEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mousePressEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
m_mouseOperation = MouseOperation::Translate;
|
||||
m_lastMousePosition = event->pos();
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mouseDoubleClickEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mouseReleaseEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
performMouseOperation(event->pos());
|
||||
|
||||
switch (m_mouseOperation)
|
||||
{
|
||||
case MouseOperation::None:
|
||||
break;
|
||||
|
||||
case MouseOperation::Translate:
|
||||
{
|
||||
m_mouseOperation = MouseOperation::None;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QMouseEvent, &IDrawWidgetInputInterface::mouseMoveEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
performMouseOperation(event->pos());
|
||||
updateCursor();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::updateCursor()
|
||||
{
|
||||
std::optional<QCursor> cursor;
|
||||
|
||||
for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces())
|
||||
{
|
||||
cursor = inputInterface->getCursor();
|
||||
|
||||
if (cursor)
|
||||
{
|
||||
// We have found cursor
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cursor)
|
||||
{
|
||||
switch (m_mouseOperation)
|
||||
{
|
||||
case MouseOperation::None:
|
||||
cursor = QCursor(Qt::OpenHandCursor);
|
||||
break;
|
||||
|
||||
case MouseOperation::Translate:
|
||||
cursor = QCursor(Qt::ClosedHandCursor);
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor)
|
||||
{
|
||||
this->setCursor(*cursor);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->unsetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename BaseWidget>
|
||||
void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (processEvent<QWheelEvent, &IDrawWidgetInputInterface::wheelEvent>(event))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
|
||||
|
||||
PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
|
||||
if (keyboardModifiers.testFlag(Qt::ControlModifier))
|
||||
{
|
||||
// Zoom in/Zoom out
|
||||
const int angleDeltaY = event->angleDelta().y();
|
||||
const PDFReal zoom = m_widget->getDrawWidgetProxy()->getZoom();
|
||||
const PDFReal zoomStep = std::pow(PDFDrawWidgetProxy::ZOOM_STEP, static_cast<PDFReal>(angleDeltaY) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep));
|
||||
const PDFReal newZoom = zoom * zoomStep;
|
||||
proxy->zoom(newZoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move Up/Down. Angle is negative, if wheel is scrolled down. First we try to scroll by pixel delta.
|
||||
// Otherwise we compute scroll using angle.
|
||||
QPoint scrollByPixels = event->pixelDelta();
|
||||
if (scrollByPixels.isNull())
|
||||
{
|
||||
const QPoint angleDelta = event->angleDelta();
|
||||
const bool shiftModifier = keyboardModifiers.testFlag(Qt::ShiftModifier);
|
||||
int stepVertical = 0;
|
||||
int stepHorizontal = shiftModifier ? m_widget->getHorizontalScrollbar()->pageStep() : m_widget->getHorizontalScrollbar()->singleStep();
|
||||
|
||||
if (proxy->isBlockMode())
|
||||
{
|
||||
// In block mode, we must calculate pixel offsets differently - scrollbars corresponds to indices of blocks,
|
||||
// not to the pixels.
|
||||
QRect boundingBox = proxy->getPagesIntersectingRectBoundingBox(this->rect());
|
||||
|
||||
if (boundingBox.isEmpty())
|
||||
{
|
||||
// This occurs, when we have not opened a document
|
||||
boundingBox = this->rect();
|
||||
}
|
||||
|
||||
stepVertical = shiftModifier ? boundingBox.height() : boundingBox.height() / 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepVertical = shiftModifier ? m_widget->getVerticalScrollbar()->pageStep() : m_widget->getVerticalScrollbar()->singleStep();
|
||||
}
|
||||
|
||||
const int scrollVertical = stepVertical * static_cast<PDFReal>(angleDelta.y()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep);
|
||||
const int scrollHorizontal = stepHorizontal * static_cast<PDFReal>(angleDelta.x()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep);
|
||||
|
||||
scrollByPixels = QPoint(scrollHorizontal, scrollVertical);
|
||||
}
|
||||
|
||||
QPoint offset = proxy->scrollByPixels(scrollByPixels);
|
||||
|
||||
if (offset.y() == 0 && scrollByPixels.y() != 0 && proxy->isBlockMode())
|
||||
{
|
||||
// We must move to another block (we are in block mode)
|
||||
bool up = scrollByPixels.y() > 0;
|
||||
|
||||
m_widget->getVerticalScrollbar()->setValue(m_widget->getVerticalScrollbar()->value() + (up ? -1 : 1));
|
||||
proxy->scrollByPixels(QPoint(0, up ? std::numeric_limits<int>::min() : std::numeric_limits<int>::max()));
|
||||
}
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
PDFOpenGLDrawWidget::PDFOpenGLDrawWidget(PDFWidget* widget, int samplesCount, QWidget* parent) :
|
||||
BaseClass(widget, parent)
|
||||
{
|
||||
QSurfaceFormat format = this->format();
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setSamples(samplesCount);
|
||||
format.setColorSpace(QColorSpace(QColorSpace::SRgb));
|
||||
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
|
||||
setFormat(format);
|
||||
}
|
||||
|
||||
PDFOpenGLDrawWidget::~PDFOpenGLDrawWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFOpenGLDrawWidget::resizeGL(int w, int h)
|
||||
{
|
||||
QOpenGLWidget::resizeGL(w, h);
|
||||
|
||||
getPDFWidget()->getDrawWidgetProxy()->update();
|
||||
}
|
||||
|
||||
void PDFOpenGLDrawWidget::initializeGL()
|
||||
{
|
||||
QOpenGLWidget::initializeGL();
|
||||
}
|
||||
|
||||
void PDFOpenGLDrawWidget::paintGL()
|
||||
{
|
||||
if (this->isValid())
|
||||
{
|
||||
QPainter painter(this);
|
||||
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
|
||||
BaseClass(widget, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFDrawWidget::~PDFDrawWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFDrawWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
|
||||
}
|
||||
|
||||
void PDFDrawWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
BaseClass::resizeEvent(event);
|
||||
|
||||
getPDFWidget()->getDrawWidgetProxy()->update();
|
||||
}
|
||||
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
template class PDFDrawWidgetBase<QOpenGLWidget>;
|
||||
#endif
|
||||
template class PDFDrawWidgetBase<QWidget>;
|
||||
|
||||
} // namespace pdf
|
226
Pdf4QtLibWidgets/sources/pdfdrawwidget.h
Normal file
226
Pdf4QtLibWidgets/sources/pdfdrawwidget.h
Normal file
@ -0,0 +1,226 @@
|
||||
// Copyright (C) 2018-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 PDFDRAWWIDGET_H
|
||||
#define PDFDRAWWIDGET_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
#include "pdfrenderer.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QScrollBar>
|
||||
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
#include <QOpenGLWidget>
|
||||
#endif
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFDocument;
|
||||
class PDFCMSManager;
|
||||
class PDFToolManager;
|
||||
class PDFDrawWidget;
|
||||
class PDFFormManager;
|
||||
class PDFDrawWidgetProxy;
|
||||
class PDFModifiedDocument;
|
||||
class PDFWidgetAnnotationManager;
|
||||
class IDrawWidgetInputInterface;
|
||||
|
||||
class IDrawWidget
|
||||
{
|
||||
public:
|
||||
virtual ~IDrawWidget() = default;
|
||||
|
||||
virtual QWidget* getWidget() = 0;
|
||||
|
||||
/// Returns page indices, which are currently displayed in the widget
|
||||
virtual std::vector<PDFInteger> getCurrentPages() const = 0;
|
||||
|
||||
/// Runs event on this widget
|
||||
virtual bool doEvent(QEvent* event) = 0;
|
||||
};
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// Constructs new PDFWidget.
|
||||
/// \param cmsManager Color management system manager
|
||||
/// \param engine Rendering engine type
|
||||
/// \param samplesCount Samples count for rendering engine MSAA antialiasing
|
||||
explicit PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent);
|
||||
virtual ~PDFWidget() override;
|
||||
|
||||
virtual bool focusNextPrevChild(bool next) override;
|
||||
|
||||
using PageRenderingErrors = std::map<PDFInteger, QList<PDFRenderError>>;
|
||||
|
||||
/// Sets the document to be viewed in this widget. Document can be nullptr,
|
||||
/// in that case, widget contents are cleared. Optional content activity can be nullptr,
|
||||
/// if this occurs, no content is suppressed.
|
||||
/// \param document Document
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Update rendering engine according the settings
|
||||
/// \param engine Engine type
|
||||
/// \param samplesCount Samples count for rendering engine MSAA antialiasing
|
||||
void updateRenderer(RendererEngine engine, int samplesCount);
|
||||
|
||||
/// Updates cache limits
|
||||
/// \param compiledPageCacheLimit Compiled page cache limit [bytes]
|
||||
/// \param thumbnailsCacheLimit Thumbnail image cache limit [kB]
|
||||
/// \param fontCacheLimit Font cache limit [-]
|
||||
/// \param instancedFontCacheLimit Instanced font cache limit [-]
|
||||
void updateCacheLimits(int compiledPageCacheLimit, int thumbnailsCacheLimit, int fontCacheLimit, int instancedFontCacheLimit);
|
||||
|
||||
const PDFCMSManager* getCMSManager() const { return m_cmsManager; }
|
||||
PDFToolManager* getToolManager() const { return m_toolManager; }
|
||||
PDFWidgetAnnotationManager* getAnnotationManager() const { return m_annotationManager; }
|
||||
IDrawWidget* getDrawWidget() const { return m_drawWidget; }
|
||||
QScrollBar* getHorizontalScrollbar() const { return m_horizontalScrollBar; }
|
||||
QScrollBar* getVerticalScrollbar() const { return m_verticalScrollBar; }
|
||||
PDFDrawWidgetProxy* getDrawWidgetProxy() const { return m_proxy; }
|
||||
const PageRenderingErrors* getPageRenderingErrors() const { return &m_pageRenderingErrors; }
|
||||
int getPageRenderingErrorCount() const;
|
||||
const std::vector<IDrawWidgetInputInterface*>& getInputInterfaces() const { return m_inputInterfaces; }
|
||||
|
||||
void setToolManager(PDFToolManager* toolManager);
|
||||
void setAnnotationManager(PDFWidgetAnnotationManager* annotationManager);
|
||||
|
||||
PDFFormManager* getFormManager() const;
|
||||
void setFormManager(PDFFormManager* formManager);
|
||||
|
||||
void removeInputInterface(IDrawWidgetInputInterface* inputInterface);
|
||||
void addInputInterface(IDrawWidgetInputInterface* inputInterface);
|
||||
|
||||
signals:
|
||||
void pageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount);
|
||||
|
||||
private:
|
||||
RendererEngine getEffectiveRenderer(RendererEngine rendererEngine);
|
||||
|
||||
void updateRendererImpl();
|
||||
void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
|
||||
void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages);
|
||||
|
||||
IDrawWidget* createDrawWidget(RendererEngine rendererEngine, int samplesCount);
|
||||
|
||||
const PDFCMSManager* m_cmsManager;
|
||||
PDFToolManager* m_toolManager;
|
||||
PDFWidgetAnnotationManager* m_annotationManager;
|
||||
PDFFormManager* m_formManager;
|
||||
IDrawWidget* m_drawWidget;
|
||||
QScrollBar* m_horizontalScrollBar;
|
||||
QScrollBar* m_verticalScrollBar;
|
||||
PDFDrawWidgetProxy* m_proxy;
|
||||
PageRenderingErrors m_pageRenderingErrors;
|
||||
std::vector<IDrawWidgetInputInterface*> m_inputInterfaces;
|
||||
};
|
||||
|
||||
template<typename BaseWidget>
|
||||
class PDFDrawWidgetBase : public BaseWidget, public IDrawWidget
|
||||
{
|
||||
public:
|
||||
explicit PDFDrawWidgetBase(PDFWidget* widget, QWidget* parent);
|
||||
virtual ~PDFDrawWidgetBase() override = default;
|
||||
|
||||
/// Returns page indices, which are currently displayed in the widget
|
||||
virtual std::vector<PDFInteger> getCurrentPages() const override;
|
||||
|
||||
virtual QSize minimumSizeHint() const override;
|
||||
virtual QWidget* getWidget() override { return this; }
|
||||
virtual bool doEvent(QEvent* event) override { return this->event(event); }
|
||||
|
||||
protected:
|
||||
virtual bool event(QEvent* event) override;
|
||||
virtual void keyPressEvent(QKeyEvent* event) override;
|
||||
virtual void keyReleaseEvent(QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QMouseEvent* event) override;
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent* event) override;
|
||||
virtual void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
PDFWidget* getPDFWidget() const { return m_widget; }
|
||||
|
||||
private:
|
||||
void updateCursor();
|
||||
|
||||
template<typename Event, void(IDrawWidgetInputInterface::* Function)(QWidget*, Event*)>
|
||||
bool processEvent(Event* event);
|
||||
|
||||
enum class MouseOperation
|
||||
{
|
||||
None,
|
||||
Translate
|
||||
};
|
||||
|
||||
/// Performs the mouse operation (under the current mouse position)
|
||||
/// \param currentMousePosition Current position of the mouse
|
||||
void performMouseOperation(QPoint currentMousePosition);
|
||||
|
||||
PDFWidget* m_widget;
|
||||
QPoint m_lastMousePosition;
|
||||
MouseOperation m_mouseOperation;
|
||||
};
|
||||
|
||||
class PDFDrawWidget : public PDFDrawWidgetBase<QWidget>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFDrawWidgetBase<QWidget>;
|
||||
|
||||
public:
|
||||
explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent);
|
||||
virtual ~PDFDrawWidget() override;
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
virtual void resizeEvent(QResizeEvent* event) override;
|
||||
};
|
||||
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
class PDFOpenGLDrawWidget : public PDFDrawWidgetBase<QOpenGLWidget>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFDrawWidgetBase<QOpenGLWidget>;
|
||||
|
||||
public:
|
||||
explicit PDFOpenGLDrawWidget(PDFWidget* widget, int samplesCount, QWidget* parent);
|
||||
virtual ~PDFOpenGLDrawWidget() override;
|
||||
|
||||
protected:
|
||||
virtual void resizeGL(int w, int h) override;
|
||||
virtual void initializeGL() override;
|
||||
virtual void paintGL() override;
|
||||
};
|
||||
#else
|
||||
using PDFOpenGLDrawWidget = PDFDrawWidget;
|
||||
#endif
|
||||
|
||||
#ifdef PDF4QT_ENABLE_OPENGL
|
||||
extern template class PDFDrawWidgetBase<QOpenGLWidget>;
|
||||
#endif
|
||||
extern template class PDFDrawWidgetBase<QWidget>;
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFDRAWWIDGET_H
|
1015
Pdf4QtLibWidgets/sources/pdfobjecteditorwidget.cpp
Normal file
1015
Pdf4QtLibWidgets/sources/pdfobjecteditorwidget.cpp
Normal file
File diff suppressed because it is too large
Load Diff
76
Pdf4QtLibWidgets/sources/pdfobjecteditorwidget.h
Normal file
76
Pdf4QtLibWidgets/sources/pdfobjecteditorwidget.h
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright (C) 2020-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 PDFOBJECTEDITORWIDGET_H
|
||||
#define PDFOBJECTEDITORWIDGET_H
|
||||
|
||||
#include "pdfobjecteditormodel.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
class QTabWidget;
|
||||
class QDialogButtonBox;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFObjectEditorWidgetMapper;
|
||||
|
||||
enum class EditObjectType
|
||||
{
|
||||
Annotation
|
||||
};
|
||||
|
||||
class PDFObjectEditorWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QWidget;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorWidget(EditObjectType type, QWidget* parent);
|
||||
|
||||
void setObject(PDFObject object);
|
||||
PDFObject getObject();
|
||||
|
||||
private:
|
||||
PDFObjectEditorWidgetMapper* m_mapper;
|
||||
QTabWidget* m_tabWidget;
|
||||
};
|
||||
|
||||
class PDFEditObjectDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QDialog;
|
||||
|
||||
public:
|
||||
explicit PDFEditObjectDialog(EditObjectType type, QWidget* parent);
|
||||
|
||||
void setObject(PDFObject object);
|
||||
PDFObject getObject();
|
||||
|
||||
private:
|
||||
PDFObjectEditorWidget* m_widget;
|
||||
QDialogButtonBox* m_buttonBox;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFOBJECTEDITORWIDGET_H
|
296
Pdf4QtLibWidgets/sources/pdfobjecteditorwidget_impl.h
Normal file
296
Pdf4QtLibWidgets/sources/pdfobjecteditorwidget_impl.h
Normal file
@ -0,0 +1,296 @@
|
||||
// Copyright (C) 2020-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 PDFOBJECTEDITORWIDGET_IMPL_H
|
||||
#define PDFOBJECTEDITORWIDGET_IMPL_H
|
||||
|
||||
#include "pdfobjecteditormodel.h"
|
||||
|
||||
class QLabel;
|
||||
class QGroupBox;
|
||||
class QComboBox;
|
||||
class QTabWidget;
|
||||
class QGridLayout;
|
||||
class QLineEdit;
|
||||
class QTextBrowser;
|
||||
class QPushButton;
|
||||
class QDateTimeEdit;
|
||||
class QCheckBox;
|
||||
class QDoubleSpinBox;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDFObjectEditorMappedWidgetAdapter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QObject;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedWidgetAdapter(PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
/// Returns PDFObject value currently present in the widget
|
||||
virtual PDFObject getValue() const = 0;
|
||||
|
||||
/// Sets PDFObject value to the widget. If data are incompatible,
|
||||
/// then no data are set to the widget.
|
||||
/// \param object Value to be set to the widget
|
||||
virtual void setValue(PDFObject object) = 0;
|
||||
|
||||
/// Updates widget state (for example, visibility, enabledness and readonly mode)
|
||||
virtual void update() = 0;
|
||||
|
||||
signals:
|
||||
void commitRequested(size_t attribute);
|
||||
|
||||
protected:
|
||||
// Initializes label text with attributes name
|
||||
void initLabel(QLabel* label);
|
||||
|
||||
PDFObjectEditorAbstractModel* m_model;
|
||||
size_t m_attribute;
|
||||
};
|
||||
|
||||
class PDFObjectEditorWidgetMapper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QObject;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorWidgetMapper(PDFObjectEditorAbstractModel* model, QObject* parent);
|
||||
|
||||
void initialize(QTabWidget* tabWidget);
|
||||
|
||||
void setObject(PDFObject object);
|
||||
PDFObject getObject();
|
||||
|
||||
private:
|
||||
struct Subcategory
|
||||
{
|
||||
QString name;
|
||||
std::vector<size_t> attributes;
|
||||
};
|
||||
|
||||
struct Category
|
||||
{
|
||||
QString name;
|
||||
std::vector<Subcategory> subcategories;
|
||||
QWidget* page = nullptr;
|
||||
|
||||
Subcategory* getOrCreateSubcategory(QString name);
|
||||
};
|
||||
|
||||
void loadWidgets();
|
||||
void onEditedObjectChanged();
|
||||
void onCommitRequested(size_t attribute);
|
||||
void createMappedAdapter(QGroupBox* groupBox, QGridLayout* layout, size_t attribute);
|
||||
Category* getOrCreateCategory(QString categoryName);
|
||||
|
||||
/// Returns true, if category is visible
|
||||
/// \param category Category
|
||||
bool isCategoryVisible(const Category& category) const;
|
||||
|
||||
PDFObjectEditorAbstractModel* m_model;
|
||||
QTabWidget* m_tabWidget;
|
||||
std::vector<Category> m_categories;
|
||||
std::map<size_t, PDFObjectEditorMappedWidgetAdapter*> m_adapters;
|
||||
bool m_isCommitingDisabled;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedComboBoxAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedComboBoxAdapter(QLabel* label, QComboBox* comboBox, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QComboBox* m_comboBox;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedLineEditAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedLineEditAdapter(QLabel* label, QLineEdit* lineEdit, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QLineEdit* m_lineEdit;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedTextBrowserAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedTextBrowserAdapter(QLabel* label, QTextBrowser* textBrowser, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QTextBrowser* m_textBrowser;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedRectangleAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedRectangleAdapter(QLabel* label, QPushButton* pushButton, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QPushButton* m_pushButton;
|
||||
PDFObject m_rectangle;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedDateTimeAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedDateTimeAdapter(QLabel* label, QDateTimeEdit* dateTimeEdit, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QDateTimeEdit* m_dateTimeEdit;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedFlagsAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedFlagsAdapter(std::vector<std::pair<uint32_t, QCheckBox*>> flagCheckBoxes,
|
||||
PDFObjectEditorAbstractModel* model,
|
||||
size_t attribute,
|
||||
QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<uint32_t, QCheckBox*>> m_flagCheckBoxes;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedCheckBoxAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedCheckBoxAdapter(QLabel* label, QCheckBox* checkBox, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QCheckBox* m_checkBox;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedColorAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedColorAdapter(QLabel* label, QComboBox* comboBox, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QIcon getIconForColor(QColor color) const;
|
||||
|
||||
QLabel* m_label;
|
||||
QComboBox* m_comboBox;
|
||||
};
|
||||
|
||||
class PDFObjectEditorMappedDoubleAdapter : public PDFObjectEditorMappedWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFObjectEditorMappedWidgetAdapter;
|
||||
|
||||
public:
|
||||
explicit PDFObjectEditorMappedDoubleAdapter(QLabel* label, QDoubleSpinBox* spinBox, PDFObjectEditorAbstractModel* model, size_t attribute, QObject* parent);
|
||||
|
||||
virtual PDFObject getValue() const override;
|
||||
virtual void setValue(PDFObject object) override;
|
||||
virtual void update() override;
|
||||
|
||||
private:
|
||||
QLabel* m_label;
|
||||
QDoubleSpinBox* m_spinBox;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFOBJECTEDITORWIDGET_IMPL_H
|
548
Pdf4QtLibWidgets/sources/pdfpagecontenteditorstylesettings.cpp
Normal file
548
Pdf4QtLibWidgets/sources/pdfpagecontenteditorstylesettings.cpp
Normal file
@ -0,0 +1,548 @@
|
||||
// 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/>.
|
||||
|
||||
#include "pdfpagecontenteditorstylesettings.h"
|
||||
#include "ui_pdfpagecontenteditorstylesettings.h"
|
||||
|
||||
#include "pdfwidgetutils.h"
|
||||
#include "pdfpagecontentelements.h"
|
||||
|
||||
#include <QFontDialog>
|
||||
#include <QColorDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QTextEdit>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFPageContentEditorStyleSettings::PDFPageContentEditorStyleSettings(QWidget* parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::PDFPageContentEditorStyleSettings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
for (QString colorName : QColor::colorNames())
|
||||
{
|
||||
QColor color(colorName);
|
||||
QIcon icon = getIconForColor(color);
|
||||
|
||||
ui->penColorCombo->addItem(icon, colorName, color);
|
||||
ui->brushColorCombo->addItem(icon, colorName, color);
|
||||
}
|
||||
|
||||
ui->penStyleCombo->addItem(tr("None"), int(Qt::NoPen));
|
||||
ui->penStyleCombo->addItem(tr("Solid"), int(Qt::SolidLine));
|
||||
ui->penStyleCombo->addItem(tr("Dashed"), int(Qt::DashLine));
|
||||
ui->penStyleCombo->addItem(tr("Dotted"), int(Qt::DotLine));
|
||||
ui->penStyleCombo->addItem(tr("Dash-dot"), int(Qt::DashDotLine));
|
||||
ui->penStyleCombo->addItem(tr("Dash-dot-dot"), int(Qt::DashDotDotLine));
|
||||
|
||||
ui->brushStyleCombo->addItem(tr("None"), int(Qt::NoBrush));
|
||||
ui->brushStyleCombo->addItem(tr("Solid"), int(Qt::SolidPattern));
|
||||
ui->brushStyleCombo->addItem(tr("Horizontal"), int(Qt::HorPattern));
|
||||
ui->brushStyleCombo->addItem(tr("Vertical"), int(Qt::VerPattern));
|
||||
ui->brushStyleCombo->addItem(tr("B-Diagonal"), int(Qt::BDiagPattern));
|
||||
ui->brushStyleCombo->addItem(tr("F-Diagonal"), int(Qt::FDiagPattern));
|
||||
ui->brushStyleCombo->addItem(tr("Cross"), int(Qt::CrossPattern));
|
||||
|
||||
connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, &PDFPageContentEditorStyleSettings::onFontChanged);
|
||||
connect(ui->selectPenColorButton, &QToolButton::clicked, this, &PDFPageContentEditorStyleSettings::onSelectPenColorButtonClicked);
|
||||
connect(ui->selectBrushColorButton, &QToolButton::clicked, this, &PDFPageContentEditorStyleSettings::onSelectBrushColorButtonClicked);
|
||||
connect(ui->selectFontButton, &QToolButton::clicked, this, &PDFPageContentEditorStyleSettings::onSelectFontButtonClicked);
|
||||
connect(ui->penWidthEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &PDFPageContentEditorStyleSettings::onPenWidthChanged);
|
||||
connect(ui->penStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onPenStyleChanged);
|
||||
connect(ui->brushStyleCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onBrushStyleChanged);
|
||||
connect(ui->textAngleEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &PDFPageContentEditorStyleSettings::onTextAngleChanged);
|
||||
connect(ui->penColorCombo->lineEdit(), &QLineEdit::editingFinished, this, &PDFPageContentEditorStyleSettings::onPenColorComboTextChanged);
|
||||
connect(ui->penColorCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onPenColorComboIndexChanged);
|
||||
connect(ui->brushColorCombo->lineEdit(), &QLineEdit::editingFinished, this, &PDFPageContentEditorStyleSettings::onBrushColorComboTextChanged);
|
||||
connect(ui->brushColorCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFPageContentEditorStyleSettings::onBrushColorComboIndexChanged);
|
||||
|
||||
m_alignmentMapper.setMapping(ui->al11Button, int(Qt::AlignLeft | Qt::AlignTop));
|
||||
m_alignmentMapper.setMapping(ui->al12Button, int(Qt::AlignHCenter | Qt::AlignTop));
|
||||
m_alignmentMapper.setMapping(ui->al13Button, int(Qt::AlignRight | Qt::AlignTop));
|
||||
m_alignmentMapper.setMapping(ui->al21Button, int(Qt::AlignLeft | Qt::AlignVCenter));
|
||||
m_alignmentMapper.setMapping(ui->al22Button, int(Qt::AlignCenter));
|
||||
m_alignmentMapper.setMapping(ui->al23Button, int(Qt::AlignRight | Qt::AlignVCenter));
|
||||
m_alignmentMapper.setMapping(ui->al31Button, int(Qt::AlignLeft | Qt::AlignBottom));
|
||||
m_alignmentMapper.setMapping(ui->al32Button, int(Qt::AlignHCenter | Qt::AlignBottom));
|
||||
m_alignmentMapper.setMapping(ui->al33Button, int(Qt::AlignRight | Qt::AlignBottom));
|
||||
|
||||
for (QRadioButton* radioButton : findChildren<QRadioButton*>())
|
||||
{
|
||||
connect(radioButton, &QRadioButton::clicked, &m_alignmentMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
}
|
||||
connect(&m_alignmentMapper, &QSignalMapper::mappedInt, this, &PDFPageContentEditorStyleSettings::onAlignmentRadioButtonClicked);
|
||||
|
||||
loadFromElement(nullptr, true);
|
||||
}
|
||||
|
||||
PDFPageContentEditorStyleSettings::~PDFPageContentEditorStyleSettings()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::loadFromElement(const PDFPageContentElement* element, bool forceUpdate)
|
||||
{
|
||||
const PDFPageContentStyledElement* styledElement = dynamic_cast<const PDFPageContentStyledElement*>(element);
|
||||
const PDFPageContentElementTextBox* textElement = dynamic_cast<const PDFPageContentElementTextBox*>(element);
|
||||
|
||||
StyleFeatures features = None;
|
||||
|
||||
if (styledElement)
|
||||
{
|
||||
features.setFlag(Pen);
|
||||
features.setFlag(PenColor);
|
||||
features.setFlag(Brush);
|
||||
}
|
||||
|
||||
if (textElement)
|
||||
{
|
||||
features.setFlag(PenColor);
|
||||
features.setFlag(Text);
|
||||
}
|
||||
|
||||
const bool hasPen = features.testFlag(Pen);
|
||||
const bool hasPenColor = features.testFlag(PenColor);
|
||||
const bool hasBrush = features.testFlag(Brush);
|
||||
const bool hasText = features.testFlag(Text);
|
||||
|
||||
ui->penWidthEdit->setEnabled(hasPen);
|
||||
ui->penWidthLabel->setEnabled(hasPen);
|
||||
|
||||
ui->penStyleCombo->setEnabled(hasPen);
|
||||
ui->penStyleLabel->setEnabled(hasPen);
|
||||
|
||||
ui->penColorCombo->setEnabled(hasPenColor);
|
||||
ui->penColorLabel->setEnabled(hasPenColor);
|
||||
ui->selectPenColorButton->setEnabled(hasPenColor);
|
||||
|
||||
ui->brushStyleLabel->setEnabled(hasBrush);
|
||||
ui->brushStyleCombo->setEnabled(hasBrush);
|
||||
|
||||
ui->brushColorCombo->setEnabled(hasBrush);
|
||||
ui->brushColorLabel->setEnabled(hasBrush);
|
||||
ui->selectBrushColorButton->setEnabled(hasBrush);
|
||||
|
||||
ui->fontComboBox->setEnabled(hasText);
|
||||
ui->fontLabel->setEnabled(hasText);
|
||||
ui->selectFontButton->setEnabled(hasText);
|
||||
|
||||
for (QRadioButton* radioButton : findChildren<QRadioButton*>())
|
||||
{
|
||||
radioButton->setEnabled(hasText);
|
||||
}
|
||||
ui->textAlignmentLabel->setEnabled(hasText);
|
||||
|
||||
ui->textAngleLabel->setEnabled(hasText);
|
||||
ui->textAngleEdit->setEnabled(hasText);
|
||||
|
||||
QPen pen(Qt::SolidLine);
|
||||
QBrush brush(Qt::transparent);
|
||||
QFont font = QGuiApplication::font();
|
||||
Qt::Alignment alignment = Qt::AlignCenter;
|
||||
PDFReal textAngle = 0.0;
|
||||
|
||||
if (styledElement)
|
||||
{
|
||||
pen = styledElement->getPen();
|
||||
brush = styledElement->getBrush();
|
||||
}
|
||||
|
||||
if (textElement)
|
||||
{
|
||||
font = textElement->getFont();
|
||||
alignment = textElement->getAlignment();
|
||||
textAngle = textElement->getAngle();
|
||||
}
|
||||
|
||||
setPen(pen, forceUpdate);
|
||||
setBrush(brush, forceUpdate);
|
||||
setFont(font, forceUpdate);
|
||||
setFontAlignment(alignment, forceUpdate);
|
||||
setTextAngle(textAngle, forceUpdate);
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setPen(const QPen& pen, bool forceUpdate)
|
||||
{
|
||||
if (m_pen != pen || forceUpdate)
|
||||
{
|
||||
const bool oldBlockSignals = blockSignals(true);
|
||||
|
||||
m_pen = pen;
|
||||
ui->penWidthEdit->setValue(pen.widthF());
|
||||
ui->penStyleCombo->setCurrentIndex(ui->penStyleCombo->findData(int(pen.style())));
|
||||
setColorToComboBox(ui->penColorCombo, pen.color());
|
||||
|
||||
blockSignals(oldBlockSignals);
|
||||
Q_EMIT penChanged(m_pen);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setBrush(const QBrush& brush, bool forceUpdate)
|
||||
{
|
||||
if (m_brush != brush || forceUpdate)
|
||||
{
|
||||
const bool oldBlockSignals = blockSignals(true);
|
||||
|
||||
m_brush = brush;
|
||||
ui->brushStyleCombo->setCurrentIndex(ui->brushStyleCombo->findData(int(brush.style())));
|
||||
setColorToComboBox(ui->brushColorCombo, brush.color());
|
||||
|
||||
blockSignals(oldBlockSignals);
|
||||
Q_EMIT brushChanged(m_brush);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setFont(const QFont& font, bool forceUpdate)
|
||||
{
|
||||
if (m_font != font || forceUpdate)
|
||||
{
|
||||
const bool oldBlockSignals = blockSignals(true);
|
||||
|
||||
m_font = font;
|
||||
ui->fontComboBox->setCurrentFont(m_font);
|
||||
|
||||
blockSignals(oldBlockSignals);
|
||||
Q_EMIT fontChanged(m_font);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setFontAlignment(Qt::Alignment alignment, bool forceUpdate)
|
||||
{
|
||||
if (m_alignment != alignment || forceUpdate)
|
||||
{
|
||||
const bool oldBlockSignals = blockSignals(true);
|
||||
|
||||
for (QRadioButton* radioButton : findChildren<QRadioButton*>())
|
||||
{
|
||||
radioButton->setChecked(false);
|
||||
}
|
||||
|
||||
m_alignment = alignment;
|
||||
QRadioButton* radioButton = qobject_cast<QRadioButton*>(m_alignmentMapper.mapping(int(alignment)));
|
||||
radioButton->setChecked(true);
|
||||
|
||||
blockSignals(oldBlockSignals);
|
||||
Q_EMIT alignmentChanged(m_alignment);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setTextAngle(PDFReal angle, bool forceUpdate)
|
||||
{
|
||||
if (ui->textAngleEdit->value() != angle || forceUpdate)
|
||||
{
|
||||
const bool oldBlockSignals = blockSignals(true);
|
||||
ui->textAngleEdit->setValue(angle);
|
||||
blockSignals(oldBlockSignals);
|
||||
Q_EMIT textAngleChanged(ui->textAngleEdit->value());
|
||||
}
|
||||
}
|
||||
|
||||
bool PDFPageContentEditorStyleSettings::showEditElementStyleDialog(QWidget* parent,
|
||||
PDFPageContentElement* element)
|
||||
{
|
||||
QDialog dialog(parent);
|
||||
dialog.setWindowTitle(tr("Edit Item"));
|
||||
dialog.setLayout(new QVBoxLayout());
|
||||
|
||||
QTextEdit* textEdit = nullptr;
|
||||
PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(element);
|
||||
PDFPageContentElementTextBox* textElement = dynamic_cast<PDFPageContentElementTextBox*>(element);
|
||||
if (textElement)
|
||||
{
|
||||
QGroupBox* contentGroupBox = new QGroupBox(&dialog);
|
||||
textEdit = new QTextEdit(textElement->getText(), contentGroupBox);
|
||||
textEdit->setFont(textElement->getFont());
|
||||
textEdit->setAlignment(textElement->getAlignment());
|
||||
textEdit->setTextColor(textElement->getPen().color());
|
||||
contentGroupBox->setTitle(tr("Content"));
|
||||
contentGroupBox->setLayout(new QVBoxLayout());
|
||||
contentGroupBox->layout()->addWidget(textEdit);
|
||||
dialog.layout()->addWidget(contentGroupBox);
|
||||
}
|
||||
|
||||
PDFPageContentEditorStyleSettings* appearanceWidget = new PDFPageContentEditorStyleSettings(&dialog);
|
||||
appearanceWidget->loadFromElement(element, true);
|
||||
if (textEdit)
|
||||
{
|
||||
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::alignmentChanged, textEdit, &QTextEdit::setAlignment);
|
||||
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::fontChanged, textEdit, &QTextEdit::setFont);
|
||||
connect(appearanceWidget, &PDFPageContentEditorStyleSettings::penChanged, textEdit, [textEdit](const QPen& pen) { textEdit->setTextColor(pen.color()); });
|
||||
}
|
||||
|
||||
QGroupBox* appearanceGroupBox = new QGroupBox(&dialog);
|
||||
appearanceGroupBox->setTitle(tr("Appearance"));
|
||||
appearanceGroupBox->setLayout(new QVBoxLayout());
|
||||
appearanceGroupBox->layout()->addWidget(appearanceWidget);
|
||||
dialog.layout()->addWidget(appearanceGroupBox);
|
||||
|
||||
QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
|
||||
connect(dialogButtonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
connect(dialogButtonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
dialog.layout()->addWidget(dialogButtonBox);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
{
|
||||
if (styledElement)
|
||||
{
|
||||
styledElement->setPen(appearanceWidget->getPen());
|
||||
styledElement->setBrush(appearanceWidget->getBrush());
|
||||
}
|
||||
|
||||
if (textElement)
|
||||
{
|
||||
textElement->setText(textEdit->toPlainText());
|
||||
textElement->setFont(appearanceWidget->getFont());
|
||||
textElement->setAlignment(appearanceWidget->getAlignment());
|
||||
textElement->setAngle(appearanceWidget->getTextAngle());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QIcon PDFPageContentEditorStyleSettings::getIconForColor(QColor color) const
|
||||
{
|
||||
QIcon icon;
|
||||
|
||||
QSize iconSize = PDFWidgetUtils::scaleDPI(this, QSize(16, 16));
|
||||
|
||||
QPixmap pixmap(iconSize.width(), iconSize.height());
|
||||
pixmap.fill(color);
|
||||
icon.addPixmap(pixmap);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setColorToComboBox(QComboBox* comboBox, QColor color)
|
||||
{
|
||||
if (!color.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString name = color.name(QColor::HexArgb);
|
||||
|
||||
int index = comboBox->findData(color, Qt::UserRole, Qt::MatchExactly);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
// Jakub Melka: try to find text (color name)
|
||||
index = comboBox->findText(name);
|
||||
}
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
comboBox->setCurrentIndex(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
comboBox->addItem(getIconForColor(color), name, color);
|
||||
comboBox->setCurrentIndex(comboBox->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onSelectFontButtonClicked()
|
||||
{
|
||||
bool ok = false;
|
||||
QFont font = QFontDialog::getFont(&ok, m_font, this, tr("Select Font"));
|
||||
|
||||
if (ok && m_font != font)
|
||||
{
|
||||
m_font = font;
|
||||
ui->fontComboBox->setCurrentFont(m_font);
|
||||
Q_EMIT fontChanged(m_font);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setPenColor(QColor color)
|
||||
{
|
||||
if (color.isValid() && m_pen.color() != color)
|
||||
{
|
||||
m_pen.setColor(color);
|
||||
setColorToComboBox(ui->penColorCombo, color);
|
||||
Q_EMIT penChanged(m_pen);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onSelectPenColorButtonClicked()
|
||||
{
|
||||
QColor color = QColorDialog::getColor(m_pen.color(), this, tr("Select Color for Pen"), QColorDialog::ShowAlphaChannel);
|
||||
setPenColor(color);
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::setBrushColor(QColor color)
|
||||
{
|
||||
if (color.isValid() && m_brush.color() != color)
|
||||
{
|
||||
m_brush.setColor(color);
|
||||
setColorToComboBox(ui->brushColorCombo, color);
|
||||
Q_EMIT brushChanged(m_brush);
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment PDFPageContentEditorStyleSettings::getAlignment() const
|
||||
{
|
||||
return m_alignment;
|
||||
}
|
||||
|
||||
PDFReal PDFPageContentEditorStyleSettings::getTextAngle() const
|
||||
{
|
||||
return ui->textAngleEdit->value();
|
||||
}
|
||||
|
||||
const QFont& PDFPageContentEditorStyleSettings::getFont() const
|
||||
{
|
||||
return m_font;
|
||||
}
|
||||
|
||||
const QBrush& PDFPageContentEditorStyleSettings::getBrush() const
|
||||
{
|
||||
return m_brush;
|
||||
}
|
||||
|
||||
const QPen& PDFPageContentEditorStyleSettings::getPen() const
|
||||
{
|
||||
return m_pen;
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onSelectBrushColorButtonClicked()
|
||||
{
|
||||
QColor color = QColorDialog::getColor(m_pen.color(), this, tr("Select Color for Brush"), QColorDialog::ShowAlphaChannel);
|
||||
setBrushColor(color);
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onPenWidthChanged(double value)
|
||||
{
|
||||
if (m_pen.widthF() != value)
|
||||
{
|
||||
m_pen.setWidthF(value);
|
||||
Q_EMIT penChanged(m_pen);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onTextAngleChanged(double value)
|
||||
{
|
||||
Q_EMIT textAngleChanged(value);
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onAlignmentRadioButtonClicked(int alignment)
|
||||
{
|
||||
Qt::Alignment alignmentValue = static_cast<Qt::Alignment>(alignment);
|
||||
if (m_alignment != alignmentValue)
|
||||
{
|
||||
m_alignment = alignmentValue;
|
||||
Q_EMIT alignmentChanged(m_alignment);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onPenStyleChanged()
|
||||
{
|
||||
Qt::PenStyle penStyle = static_cast<Qt::PenStyle>(ui->penStyleCombo->currentData().toInt());
|
||||
if (m_pen.style() != penStyle)
|
||||
{
|
||||
m_pen.setStyle(penStyle);
|
||||
Q_EMIT penChanged(m_pen);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onBrushStyleChanged()
|
||||
{
|
||||
Qt::BrushStyle brushStyle = static_cast<Qt::BrushStyle>(ui->brushStyleCombo->currentData().toInt());
|
||||
if (m_brush.style() != brushStyle)
|
||||
{
|
||||
m_brush.setStyle(brushStyle);
|
||||
Q_EMIT brushChanged(m_brush);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onPenColorComboTextChanged()
|
||||
{
|
||||
QColor color(ui->penColorCombo->currentText());
|
||||
if (color.isValid())
|
||||
{
|
||||
setColorToComboBox(ui->penColorCombo, color);
|
||||
|
||||
if (m_pen.color() != color)
|
||||
{
|
||||
m_pen.setColor(color);
|
||||
Q_EMIT penChanged(m_pen);
|
||||
}
|
||||
}
|
||||
else if (ui->penColorCombo->currentIndex() != -1)
|
||||
{
|
||||
ui->penColorCombo->setEditText(ui->penColorCombo->itemText(ui->penColorCombo->currentIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onPenColorComboIndexChanged()
|
||||
{
|
||||
const int index = ui->penColorCombo->currentIndex();
|
||||
QColor color = ui->penColorCombo->itemData(index, Qt::UserRole).value<QColor>();
|
||||
if (color.isValid() && m_pen.color() != color)
|
||||
{
|
||||
m_pen.setColor(color);
|
||||
Q_EMIT penChanged(m_pen);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onBrushColorComboTextChanged()
|
||||
{
|
||||
QColor color(ui->brushColorCombo->currentText());
|
||||
if (color.isValid())
|
||||
{
|
||||
setColorToComboBox(ui->brushColorCombo, color);
|
||||
|
||||
if (m_brush.color() != color)
|
||||
{
|
||||
m_brush.setColor(color);
|
||||
Q_EMIT brushChanged(m_brush);
|
||||
}
|
||||
}
|
||||
else if (ui->brushColorCombo->currentIndex() != -1)
|
||||
{
|
||||
ui->brushColorCombo->setEditText(ui->brushColorCombo->itemText(ui->brushColorCombo->currentIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onBrushColorComboIndexChanged()
|
||||
{
|
||||
const int index = ui->brushColorCombo->currentIndex();
|
||||
QColor color = ui->brushColorCombo->itemData(index, Qt::UserRole).value<QColor>();
|
||||
if (color.isValid() && m_brush.color() != color)
|
||||
{
|
||||
m_brush.setColor(color);
|
||||
Q_EMIT brushChanged(m_brush);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorStyleSettings::onFontChanged(const QFont& font)
|
||||
{
|
||||
if (m_font != font)
|
||||
{
|
||||
m_font = font;
|
||||
Q_EMIT fontChanged(m_font);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pdf
|
118
Pdf4QtLibWidgets/sources/pdfpagecontenteditorstylesettings.h
Normal file
118
Pdf4QtLibWidgets/sources/pdfpagecontenteditorstylesettings.h
Normal file
@ -0,0 +1,118 @@
|
||||
// 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 PDFPAGECONTENTEDITORSTYLESETTINGS_H
|
||||
#define PDFPAGECONTENTEDITORSTYLESETTINGS_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <QPen>
|
||||
#include <QIcon>
|
||||
#include <QFont>
|
||||
#include <QBrush>
|
||||
#include <QWidget>
|
||||
#include <QSignalMapper>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFPageContentEditorStyleSettings;
|
||||
}
|
||||
|
||||
class QComboBox;
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFPageContentElement;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentEditorStyleSettings : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum StyleFeature
|
||||
{
|
||||
None = 0,
|
||||
Pen = 1 << 0,
|
||||
PenColor = 1 << 1,
|
||||
Brush = 1 << 2,
|
||||
Text = 1 << 3
|
||||
};
|
||||
Q_DECLARE_FLAGS(StyleFeatures, StyleFeature)
|
||||
|
||||
explicit PDFPageContentEditorStyleSettings(QWidget* parent);
|
||||
virtual ~PDFPageContentEditorStyleSettings() override;
|
||||
|
||||
/// Loads data from element, element can be nullptr
|
||||
/// \param element Element
|
||||
void loadFromElement(const PDFPageContentElement* element, bool forceUpdate);
|
||||
|
||||
void setPen(const QPen& pen, bool forceUpdate);
|
||||
void setBrush(const QBrush& brush, bool forceUpdate);
|
||||
void setFont(const QFont& font, bool forceUpdate);
|
||||
void setFontAlignment(Qt::Alignment alignment, bool forceUpdate);
|
||||
void setTextAngle(PDFReal angle, bool forceUpdate);
|
||||
|
||||
static bool showEditElementStyleDialog(QWidget* parent, PDFPageContentElement* element);
|
||||
|
||||
const QPen& getPen() const;
|
||||
const QBrush& getBrush() const;
|
||||
const QFont& getFont() const;
|
||||
Qt::Alignment getAlignment() const;
|
||||
PDFReal getTextAngle() const;
|
||||
|
||||
signals:
|
||||
void penChanged(const QPen& pen);
|
||||
void brushChanged(const QBrush& brush);
|
||||
void fontChanged(const QFont& font);
|
||||
void alignmentChanged(Qt::Alignment alignment);
|
||||
void textAngleChanged(pdf::PDFReal angle);
|
||||
|
||||
private slots:
|
||||
void onSelectFontButtonClicked();
|
||||
void onSelectPenColorButtonClicked();
|
||||
void onSelectBrushColorButtonClicked();
|
||||
void onPenWidthChanged(double value);
|
||||
void onTextAngleChanged(double value);
|
||||
void onAlignmentRadioButtonClicked(int alignment);
|
||||
void onPenStyleChanged();
|
||||
void onBrushStyleChanged();
|
||||
void onPenColorComboTextChanged();
|
||||
void onPenColorComboIndexChanged();
|
||||
void onBrushColorComboTextChanged();
|
||||
void onBrushColorComboIndexChanged();
|
||||
|
||||
private:
|
||||
Ui::PDFPageContentEditorStyleSettings* ui;
|
||||
|
||||
void onFontChanged(const QFont& font);
|
||||
void setColorToComboBox(QComboBox* comboBox, QColor color);
|
||||
QIcon getIconForColor(QColor color) const;
|
||||
|
||||
void setPenColor(QColor color);
|
||||
void setBrushColor(QColor color);
|
||||
|
||||
QPen m_pen;
|
||||
QBrush m_brush;
|
||||
QFont m_font;
|
||||
Qt::Alignment m_alignment = Qt::AlignCenter;
|
||||
QSignalMapper m_alignmentMapper;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFPAGECONTENTEDITORSTYLESETTINGS_H
|
230
Pdf4QtLibWidgets/sources/pdfpagecontenteditorstylesettings.ui
Normal file
230
Pdf4QtLibWidgets/sources/pdfpagecontenteditorstylesettings.ui
Normal file
@ -0,0 +1,230 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFPageContentEditorStyleSettings</class>
|
||||
<widget class="QWidget" name="PDFPageContentEditorStyleSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>344</width>
|
||||
<height>310</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Style Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="textAlignmentLabel">
|
||||
<property name="text">
|
||||
<string>Text Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="penStyleLabel">
|
||||
<property name="text">
|
||||
<string>Pen Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="brushColorCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="penStyleCombo"/>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QDoubleSpinBox" name="penWidthEdit"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="penColorCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="penWidthLabel">
|
||||
<property name="text">
|
||||
<string>Pen Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="brushColorLabel">
|
||||
<property name="text">
|
||||
<string>Brush Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="2">
|
||||
<layout class="QGridLayout" name="textAlignmentLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="al21Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QRadioButton" name="al13Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="al32Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="al22Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QRadioButton" name="al33Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="al31Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QRadioButton" name="al23Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="al11Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QRadioButton" name="al12Button">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QDoubleSpinBox" name="textAngleEdit">
|
||||
<property name="minimum">
|
||||
<double>-90.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QToolButton" name="selectBrushColorButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="penColorLabel">
|
||||
<property name="text">
|
||||
<string>Pen Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="fontLabel">
|
||||
<property name="text">
|
||||
<string>Font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QFontComboBox" name="fontComboBox"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="textAngleLabel">
|
||||
<property name="text">
|
||||
<string>Text Angle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QToolButton" name="selectPenColorButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QToolButton" name="selectFontButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="brushStyleLabel">
|
||||
<property name="text">
|
||||
<string>Brush Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="brushStyleCombo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
969
Pdf4QtLibWidgets/sources/pdfpagecontenteditortools.cpp
Normal file
969
Pdf4QtLibWidgets/sources/pdfpagecontenteditortools.cpp
Normal file
@ -0,0 +1,969 @@
|
||||
// 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/>.
|
||||
|
||||
#include "pdfpagecontenteditortools.h"
|
||||
#include "pdfpagecontentelements.h"
|
||||
#include "pdfpainterutils.h"
|
||||
#include "pdftexteditpseudowidget.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
|
||||
#include <QPen>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QImageReader>
|
||||
#include <QGuiApplication>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFCreatePCElementTool::PDFCreatePCElementTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent) :
|
||||
PDFWidgetTool(proxy, action, parent),
|
||||
m_scene(scene)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTool::setPen(const QPen& pen)
|
||||
{
|
||||
if (PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(getElement()))
|
||||
{
|
||||
styledElement->setPen(pen);
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTool::setBrush(const QBrush& brush)
|
||||
{
|
||||
if (PDFPageContentStyledElement* styledElement = dynamic_cast<PDFPageContentStyledElement*>(getElement()))
|
||||
{
|
||||
styledElement->setBrush(brush);
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTool::setFont(const QFont& font)
|
||||
{
|
||||
if (PDFPageContentElementTextBox* textBoxElement = dynamic_cast<PDFPageContentElementTextBox*>(getElement()))
|
||||
{
|
||||
textBoxElement->setFont(font);
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTool::setAlignment(Qt::Alignment alignment)
|
||||
{
|
||||
if (PDFPageContentElementTextBox* textBoxElement = dynamic_cast<PDFPageContentElementTextBox*>(getElement()))
|
||||
{
|
||||
textBoxElement->setAlignment(alignment);
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTool::setTextAngle(PDFReal angle)
|
||||
{
|
||||
if (PDFPageContentElementTextBox* textBoxElement = dynamic_cast<PDFPageContentElementTextBox*>(getElement()))
|
||||
{
|
||||
textBoxElement->setAngle(angle);
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
QRectF PDFCreatePCElementTool::getRectangleFromPickTool(PDFPickTool* pickTool,
|
||||
const QTransform& pagePointToDevicePointMatrix)
|
||||
{
|
||||
const std::vector<QPointF>& points = pickTool->getPickedPoints();
|
||||
if (points.empty())
|
||||
{
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
QPointF mousePoint = pagePointToDevicePointMatrix.inverted().map(pickTool->getSnappedPoint());
|
||||
QPointF point = points.front();
|
||||
qreal xMin = qMin(point.x(), mousePoint.x());
|
||||
qreal xMax = qMax(point.x(), mousePoint.x());
|
||||
qreal yMin = qMin(point.y(), mousePoint.y());
|
||||
qreal yMax = qMax(point.y(), mousePoint.y());
|
||||
qreal width = xMax - xMin;
|
||||
qreal height = yMax - yMin;
|
||||
|
||||
if (!qFuzzyIsNull(width) && !qFuzzyIsNull(height))
|
||||
{
|
||||
return QRectF(xMin, yMin, width, height);
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
PDFCreatePCElementRectangleTool::PDFCreatePCElementRectangleTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
bool isRounded,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_pickTool(nullptr),
|
||||
m_element(nullptr)
|
||||
{
|
||||
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||
m_pickTool->setDrawSelectionRectangle(false);
|
||||
addTool(m_pickTool);
|
||||
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementRectangleTool::onRectanglePicked);
|
||||
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setWidthF(1.0);
|
||||
|
||||
m_element = new PDFPageContentElementRectangle();
|
||||
m_element->setBrush(Qt::NoBrush);
|
||||
m_element->setPen(std::move(pen));
|
||||
m_element->setRounded(isRounded);
|
||||
|
||||
updateActions();
|
||||
}
|
||||
|
||||
PDFCreatePCElementRectangleTool::~PDFCreatePCElementRectangleTool()
|
||||
{
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementRectangleTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
if (pageIndex != m_pickTool->getPageIndex())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF rectangle = getRectangleFromPickTool(m_pickTool, pagePointToDevicePointMatrix);
|
||||
if (!rectangle.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setRectangle(rectangle);
|
||||
|
||||
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
}
|
||||
|
||||
const PDFPageContentElement* PDFCreatePCElementRectangleTool::getElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
PDFPageContentElement* PDFCreatePCElementRectangleTool::getElement()
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementRectangleTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||
{
|
||||
if (pageRectangle.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setRectangle(pageRectangle);
|
||||
m_scene->addElement(m_element->clone());
|
||||
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
PDFCreatePCElementLineTool::PDFCreatePCElementLineTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
bool isHorizontal,
|
||||
bool isVertical,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_pickTool(nullptr),
|
||||
m_element(nullptr)
|
||||
{
|
||||
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Points, this);
|
||||
m_pickTool->setDrawSelectionRectangle(false);
|
||||
addTool(m_pickTool);
|
||||
connect(m_pickTool, &PDFPickTool::pointPicked, this, &PDFCreatePCElementLineTool::onPointPicked);
|
||||
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setWidthF(2.0);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
|
||||
PDFPageContentElementLine::LineGeometry geometry = PDFPageContentElementLine::LineGeometry::General;
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
geometry = PDFPageContentElementLine::LineGeometry::Horizontal;
|
||||
}
|
||||
|
||||
if (isVertical)
|
||||
{
|
||||
geometry = PDFPageContentElementLine::LineGeometry::Vertical;
|
||||
}
|
||||
|
||||
m_element = new PDFPageContentElementLine();
|
||||
m_element->setBrush(Qt::NoBrush);
|
||||
m_element->setPen(std::move(pen));
|
||||
m_element->setGeometry(geometry);
|
||||
|
||||
updateActions();
|
||||
}
|
||||
|
||||
PDFCreatePCElementLineTool::~PDFCreatePCElementLineTool()
|
||||
{
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementLineTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
if (pageIndex != m_pickTool->getPageIndex() || !m_startPoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
|
||||
QPointF startPoint = *m_startPoint;
|
||||
QPointF endPoint = pagePointToDevicePointMatrix.inverted().map(m_pickTool->getSnappedPoint());
|
||||
QLineF line(startPoint, endPoint);
|
||||
|
||||
if (!qFuzzyIsNull(line.length()))
|
||||
{
|
||||
m_element->setLine(line);
|
||||
}
|
||||
|
||||
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
}
|
||||
|
||||
const PDFPageContentElement* PDFCreatePCElementLineTool::getElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
PDFPageContentElement* PDFCreatePCElementLineTool::getElement()
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementLineTool::clear()
|
||||
{
|
||||
m_startPoint = std::nullopt;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementLineTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint)
|
||||
{
|
||||
if (!m_startPoint || m_element->getPageIndex() != pageIndex)
|
||||
{
|
||||
m_startPoint = pagePoint;
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setLine(QLineF(pagePoint, pagePoint));
|
||||
return;
|
||||
}
|
||||
|
||||
if (qFuzzyCompare(m_startPoint.value().x(), pagePoint.x()) &&
|
||||
qFuzzyCompare(m_startPoint.value().y(), pagePoint.y()))
|
||||
{
|
||||
// Jakub Melka: Point is same as the start point
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
QLineF line = m_element->getLine();
|
||||
line.setP2(pagePoint);
|
||||
m_element->setLine(line);
|
||||
m_scene->addElement(m_element->clone());
|
||||
clear();
|
||||
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
PDFCreatePCElementImageTool::PDFCreatePCElementImageTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QByteArray content,
|
||||
bool askSelectImage,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_pickTool(nullptr),
|
||||
m_element(nullptr),
|
||||
m_askSelectImage(askSelectImage)
|
||||
{
|
||||
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||
m_pickTool->setDrawSelectionRectangle(false);
|
||||
addTool(m_pickTool);
|
||||
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementImageTool::onRectanglePicked);
|
||||
|
||||
m_element = new PDFPageContentImageElement();
|
||||
m_element->setContent(content);
|
||||
|
||||
updateActions();
|
||||
}
|
||||
|
||||
PDFCreatePCElementImageTool::~PDFCreatePCElementImageTool()
|
||||
{
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementImageTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
if (pageIndex != m_pickTool->getPageIndex())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QRectF rectangle = getRectangleFromPickTool(m_pickTool, pagePointToDevicePointMatrix);
|
||||
if (!rectangle.isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setRectangle(rectangle);
|
||||
|
||||
{
|
||||
PDFPainterStateGuard guard(painter);
|
||||
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->setPen(Qt::DotLine);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(rectangle);
|
||||
}
|
||||
|
||||
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
}
|
||||
|
||||
const PDFPageContentElement* PDFCreatePCElementImageTool::getElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
PDFPageContentElement* PDFCreatePCElementImageTool::getElement()
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementImageTool::setActiveImpl(bool active)
|
||||
{
|
||||
BaseClass::setActiveImpl(active);
|
||||
|
||||
if (active && m_askSelectImage)
|
||||
{
|
||||
QTimer::singleShot(0, this, &PDFCreatePCElementImageTool::selectImage);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementImageTool::selectImage()
|
||||
{
|
||||
if (m_imageDirectory.isEmpty())
|
||||
{
|
||||
QStringList pictureDirectiories = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
|
||||
if (!pictureDirectiories.isEmpty())
|
||||
{
|
||||
m_imageDirectory = pictureDirectiories.last();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_imageDirectory = QDir::currentPath();
|
||||
}
|
||||
}
|
||||
|
||||
QList<QByteArray> mimeTypes = QImageReader::supportedMimeTypes();
|
||||
QStringList mimeTypeFilters;
|
||||
for (const QByteArray& mimeType : mimeTypes)
|
||||
{
|
||||
mimeTypeFilters.append(mimeType);
|
||||
}
|
||||
|
||||
QFileDialog dialog(getProxy()->getWidget(), tr("Select Image"));
|
||||
dialog.setDirectory(m_imageDirectory);
|
||||
dialog.setMimeTypeFilters(mimeTypeFilters);
|
||||
dialog.selectMimeTypeFilter("image/svg+xml");
|
||||
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
|
||||
if (dialog.exec() == QFileDialog::Accepted)
|
||||
{
|
||||
QString fileName = dialog.selectedFiles().constFirst();
|
||||
QFile file(fileName);
|
||||
if (file.open(QFile::ReadOnly))
|
||||
{
|
||||
m_element->setContent(file.readAll());
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
setActive(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementImageTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||
{
|
||||
if (pageRectangle.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setRectangle(pageRectangle);
|
||||
m_scene->addElement(m_element->clone());
|
||||
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
PDFCreatePCElementDotTool::PDFCreatePCElementDotTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_pickTool(nullptr),
|
||||
m_element(nullptr)
|
||||
{
|
||||
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Points, this);
|
||||
m_pickTool->setDrawSelectionRectangle(false);
|
||||
addTool(m_pickTool);
|
||||
connect(m_pickTool, &PDFPickTool::pointPicked, this, &PDFCreatePCElementDotTool::onPointPicked);
|
||||
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setWidthF(5.0);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
|
||||
m_element = new PDFPageContentElementDot();
|
||||
m_element->setBrush(Qt::NoBrush);
|
||||
m_element->setPen(std::move(pen));
|
||||
|
||||
updateActions();
|
||||
}
|
||||
|
||||
PDFCreatePCElementDotTool::~PDFCreatePCElementDotTool()
|
||||
{
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementDotTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
QPointF point = pagePointToDevicePointMatrix.inverted().map(m_pickTool->getSnappedPoint());
|
||||
|
||||
PDFPainterStateGuard guard(painter);
|
||||
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->setPen(m_element->getPen());
|
||||
painter->setBrush(m_element->getBrush());
|
||||
painter->drawPoint(point);
|
||||
}
|
||||
|
||||
const PDFPageContentElement* PDFCreatePCElementDotTool::getElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
PDFPageContentElement* PDFCreatePCElementDotTool::getElement()
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementDotTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint)
|
||||
{
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setPoint(pagePoint);
|
||||
|
||||
m_scene->addElement(m_element->clone());
|
||||
m_element->setPageIndex(-1);
|
||||
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
PDFCreatePCElementFreehandCurveTool::PDFCreatePCElementFreehandCurveTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_element(nullptr)
|
||||
{
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setWidthF(2.0);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
|
||||
m_element = new PDFPageContentElementFreehandCurve();
|
||||
m_element->setBrush(Qt::NoBrush);
|
||||
m_element->setPen(std::move(pen));
|
||||
}
|
||||
|
||||
PDFCreatePCElementFreehandCurveTool::~PDFCreatePCElementFreehandCurveTool()
|
||||
{
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementFreehandCurveTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
if (pageIndex != m_element->getPageIndex() || m_element->isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
}
|
||||
|
||||
const PDFPageContentElement* PDFCreatePCElementFreehandCurveTool::getElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
PDFPageContentElement* PDFCreatePCElementFreehandCurveTool::getElement()
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementFreehandCurveTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->accept();
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
// Try to perform pick point
|
||||
QPointF pagePoint;
|
||||
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
if (pageIndex != -1 && // We have picked some point on page
|
||||
(m_element->getPageIndex() == -1 || m_element->getPageIndex() == pageIndex)) // We are under current page
|
||||
{
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->addStartPoint(pagePoint);
|
||||
}
|
||||
}
|
||||
else if (event->button() == Qt::RightButton)
|
||||
{
|
||||
resetTool();
|
||||
}
|
||||
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementFreehandCurveTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->accept();
|
||||
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
// Try to perform pick point
|
||||
QPointF pagePoint;
|
||||
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
if (pageIndex != -1 && // We have picked some point on page
|
||||
(m_element->getPageIndex() == pageIndex)) // We are under current page
|
||||
{
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->addPoint(pagePoint);
|
||||
|
||||
if (!m_element->isEmpty())
|
||||
{
|
||||
m_scene->addElement(m_element->clone());
|
||||
}
|
||||
}
|
||||
|
||||
resetTool();
|
||||
}
|
||||
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementFreehandCurveTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
event->accept();
|
||||
|
||||
if (event->buttons() & Qt::LeftButton && m_element->getPageIndex() != -1)
|
||||
{
|
||||
// Try to add point to the path
|
||||
QPointF pagePoint;
|
||||
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
if (pageIndex == m_element->getPageIndex())
|
||||
{
|
||||
m_element->addPoint(pagePoint);
|
||||
}
|
||||
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementFreehandCurveTool::setActiveImpl(bool active)
|
||||
{
|
||||
BaseClass::setActiveImpl(active);
|
||||
|
||||
if (!active)
|
||||
{
|
||||
resetTool();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementFreehandCurveTool::resetTool()
|
||||
{
|
||||
m_element->clear();
|
||||
}
|
||||
|
||||
PDFCreatePCElementTextTool::PDFCreatePCElementTextTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent) :
|
||||
BaseClass(proxy, scene, action, parent),
|
||||
m_pickTool(nullptr),
|
||||
m_element(nullptr),
|
||||
m_textEditWidget(nullptr)
|
||||
{
|
||||
m_pickTool = new PDFPickTool(proxy, PDFPickTool::Mode::Rectangles, this);
|
||||
m_pickTool->setDrawSelectionRectangle(true);
|
||||
connect(m_pickTool, &PDFPickTool::rectanglePicked, this, &PDFCreatePCElementTextTool::onRectanglePicked);
|
||||
|
||||
QFont font = QGuiApplication::font();
|
||||
font.setPixelSize(16.0);
|
||||
|
||||
m_element = new PDFPageContentElementTextBox();
|
||||
m_element->setBrush(Qt::NoBrush);
|
||||
m_element->setPen(QPen(Qt::SolidLine));
|
||||
m_element->setFont(font);
|
||||
|
||||
m_textEditWidget = new PDFTextEditPseudowidget(PDFFormField::Multiline);
|
||||
}
|
||||
|
||||
PDFCreatePCElementTextTool::~PDFCreatePCElementTextTool()
|
||||
{
|
||||
delete m_textEditWidget;
|
||||
delete m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const
|
||||
{
|
||||
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
|
||||
|
||||
if (pageIndex != m_element->getPageIndex())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEditing())
|
||||
{
|
||||
PDFPainterStateGuard guard(painter);
|
||||
AnnotationDrawParameters parameters;
|
||||
parameters.painter = painter;
|
||||
parameters.boundingRectangle = m_element->getRectangle();
|
||||
parameters.key.first = PDFAppeareanceStreams::Appearance::Normal;
|
||||
parameters.colorConvertor = getProxy()->getCMSManager()->getColorConvertor();
|
||||
PDFRenderer::applyFeaturesToColorConvertor(getProxy()->getFeatures(), parameters.colorConvertor);
|
||||
|
||||
painter->setWorldTransform(QTransform(pagePointToDevicePointMatrix), true);
|
||||
m_textEditWidget->draw(parameters, true);
|
||||
}
|
||||
}
|
||||
|
||||
const PDFPageContentElement* PDFCreatePCElementTextTool::getElement() const
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
PDFPageContentElement* PDFCreatePCElementTextTool::getElement()
|
||||
{
|
||||
return m_element;
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::resetTool()
|
||||
{
|
||||
m_textEditWidget->setText(QString());
|
||||
m_element->setText(QString());
|
||||
m_element->setPageIndex(-1);
|
||||
|
||||
if (getTopToolstackTool())
|
||||
{
|
||||
removeTool();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::setActiveImpl(bool active)
|
||||
{
|
||||
BaseClass::setActiveImpl(active);
|
||||
|
||||
if (active)
|
||||
{
|
||||
Q_ASSERT(!getTopToolstackTool());
|
||||
addTool(m_pickTool);
|
||||
}
|
||||
else
|
||||
{
|
||||
resetTool();
|
||||
}
|
||||
|
||||
m_pickTool->setActive(active);
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle)
|
||||
{
|
||||
if (pageRectangle.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_element->setPageIndex(pageIndex);
|
||||
m_element->setRectangle(pageRectangle);
|
||||
|
||||
m_textEditWidget->setAppearance(m_element->getFont(),
|
||||
m_element->getAlignment(),
|
||||
m_element->getRectangle(),
|
||||
std::numeric_limits<int>::max(),
|
||||
m_element->getPen().color());
|
||||
|
||||
removeTool();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::finishEditing()
|
||||
{
|
||||
m_element->setText(m_textEditWidget->getText());
|
||||
|
||||
if (!m_element->getText().isEmpty())
|
||||
{
|
||||
m_scene->addElement(m_element->clone());
|
||||
}
|
||||
|
||||
resetTool();
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
std::optional<QPointF> PDFCreatePCElementTextTool::getPagePointUnderMouse(QMouseEvent* event) const
|
||||
{
|
||||
QPointF pagePoint;
|
||||
PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
|
||||
if (pageIndex == m_element->getPageIndex() &&
|
||||
m_element->getRectangle().contains(pagePoint))
|
||||
{
|
||||
return pagePoint;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool PDFCreatePCElementTextTool::isEditing() const
|
||||
{
|
||||
return isActive() && !getTopToolstackTool();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::shortcutOverrideEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
|
||||
if (isEditing())
|
||||
{
|
||||
m_textEditWidget->shortcutOverrideEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::keyPressEvent(QWidget* widget, QKeyEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
|
||||
if (!isEditing())
|
||||
{
|
||||
BaseClass::keyPressEvent(widget, event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Escape)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_textEditWidget->isMultiline() && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
||||
{
|
||||
// Commit the editor and create element
|
||||
finishEditing();
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
m_textEditWidget->keyPressEvent(widget, event);
|
||||
|
||||
if (event->isAccepted())
|
||||
{
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||
if (pagePoint)
|
||||
{
|
||||
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||
m_textEditWidget->setCursorPosition(cursorPosition, event->modifiers() & Qt::ShiftModifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
finishEditing();
|
||||
}
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::mousePressEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
{
|
||||
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||
if (pagePoint)
|
||||
{
|
||||
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||
m_textEditWidget->setCursorPosition(cursorPosition, false);
|
||||
m_textEditWidget->setCursorPosition(m_textEditWidget->getCursorWordBackward(), false);
|
||||
m_textEditWidget->setCursorPosition(m_textEditWidget->getCursorWordForward(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
finishEditing();
|
||||
}
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::mousePressEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
std::optional<QPointF> pagePoint = getPagePointUnderMouse(event);
|
||||
if (pagePoint)
|
||||
{
|
||||
// We must test, if left mouse button is pressed while
|
||||
// we are moving the mouse - if yes, then select the text.
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
const int cursorPosition = m_textEditWidget->getCursorPositionFromWidgetPosition(pagePoint.value(), true);
|
||||
m_textEditWidget->setCursorPosition(cursorPosition, true);
|
||||
|
||||
event->accept();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::mouseMoveEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::wheelEvent(QWidget* widget, QWheelEvent* event)
|
||||
{
|
||||
if (isEditing())
|
||||
{
|
||||
event->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::wheelEvent(widget, event);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::setFont(const QFont& font)
|
||||
{
|
||||
BaseClass::setFont(font);
|
||||
m_textEditWidget->setAppearance(font, m_element->getAlignment(), m_element->getRectangle(), std::numeric_limits<int>::max(), m_element->getPen().color());
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::setAlignment(Qt::Alignment alignment)
|
||||
{
|
||||
BaseClass::setAlignment(alignment);
|
||||
m_textEditWidget->setAppearance(m_element->getFont(), alignment, m_element->getRectangle(), std::numeric_limits<int>::max(), m_element->getPen().color());
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
|
||||
void PDFCreatePCElementTextTool::setPen(const QPen& pen)
|
||||
{
|
||||
BaseClass::setPen(pen);
|
||||
|
||||
QFont font = m_element->getFont();
|
||||
font.setHintingPreference(QFont::PreferNoHinting);
|
||||
if (font.pointSizeF() > 0.0)
|
||||
{
|
||||
font.setPixelSize(qRound(font.pointSizeF()));
|
||||
}
|
||||
|
||||
m_textEditWidget->setAppearance(font, m_element->getAlignment(), m_element->getRectangle(), std::numeric_limits<int>::max(), pen.color());
|
||||
Q_EMIT getProxy()->repaintNeeded();
|
||||
}
|
||||
|
||||
} // namespace pdf
|
292
Pdf4QtLibWidgets/sources/pdfpagecontenteditortools.h
Normal file
292
Pdf4QtLibWidgets/sources/pdfpagecontenteditortools.h
Normal file
@ -0,0 +1,292 @@
|
||||
// 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 PDFPAGECONTENTEDITORTOOLS_H
|
||||
#define PDFPAGECONTENTEDITORTOOLS_H
|
||||
|
||||
#include "pdfwidgettool.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDFPageContentScene;
|
||||
class PDFPageContentElement;
|
||||
class PDFPageContentImageElement;
|
||||
class PDFPageContentElementDot;
|
||||
class PDFPageContentElementLine;
|
||||
class PDFPageContentElementTextBox;
|
||||
class PDFPageContentElementRectangle;
|
||||
class PDFPageContentElementFreehandCurve;
|
||||
class PDFTextEditPseudowidget;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PDFCreatePCElementTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent);
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const = 0;
|
||||
virtual PDFPageContentElement* getElement() = 0;
|
||||
|
||||
virtual void setPen(const QPen& pen);
|
||||
virtual void setBrush(const QBrush& brush);
|
||||
virtual void setFont(const QFont& font);
|
||||
virtual void setAlignment(Qt::Alignment alignment);
|
||||
virtual void setTextAngle(pdf::PDFReal angle);
|
||||
|
||||
protected:
|
||||
static QRectF getRectangleFromPickTool(PDFPickTool* pickTool, const QTransform& pagePointToDevicePointMatrix);
|
||||
|
||||
PDFPageContentScene* m_scene;
|
||||
};
|
||||
|
||||
/// Tool that creates rectangle element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementRectangleTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementRectangleTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
bool isRounded,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementRectangleTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const override;
|
||||
virtual PDFPageContentElement* getElement() override;
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFPageContentElementRectangle* m_element;
|
||||
};
|
||||
|
||||
/// Tool that displays SVG image (or raster image)
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementImageTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementImageTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QByteArray content,
|
||||
bool askSelectImage,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementImageTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const override;
|
||||
virtual PDFPageContentElement* getElement() override;
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
void selectImage();
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFPageContentImageElement* m_element;
|
||||
bool m_askSelectImage;
|
||||
QString m_imageDirectory;
|
||||
};
|
||||
|
||||
/// Tool that creates line element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementLineTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementLineTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
bool isHorizontal,
|
||||
bool isVertical,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementLineTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const override;
|
||||
virtual PDFPageContentElement* getElement() override;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
void onPointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFPageContentElementLine* m_element;
|
||||
std::optional<QPointF> m_startPoint;
|
||||
};
|
||||
|
||||
/// Tool that creates dot element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementDotTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementDotTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementDotTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const override;
|
||||
virtual PDFPageContentElement* getElement() override;
|
||||
|
||||
private:
|
||||
void onPointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFPageContentElementDot* m_element;
|
||||
};
|
||||
|
||||
/// Tool that creates freehand curve element.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementFreehandCurveTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementFreehandCurveTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementFreehandCurveTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const override;
|
||||
virtual PDFPageContentElement* getElement() override;
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
void resetTool();
|
||||
|
||||
PDFPageContentElementFreehandCurve* m_element;
|
||||
};
|
||||
|
||||
/// Tool that displays SVG image
|
||||
class PDF4QTLIBSHARED_EXPORT PDFCreatePCElementTextTool : public PDFCreatePCElementTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFCreatePCElementTool;
|
||||
|
||||
public:
|
||||
explicit PDFCreatePCElementTextTool(PDFDrawWidgetProxy* proxy,
|
||||
PDFPageContentScene* scene,
|
||||
QAction* action,
|
||||
QObject* parent);
|
||||
virtual ~PDFCreatePCElementTextTool() override;
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual const PDFPageContentElement* getElement() const override;
|
||||
virtual PDFPageContentElement* getElement() override;
|
||||
|
||||
virtual void setPen(const QPen& pen) override;
|
||||
virtual void setFont(const QFont& font) override;
|
||||
virtual void setAlignment(Qt::Alignment alignment) override;
|
||||
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||
|
||||
private:
|
||||
void onRectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
void finishEditing();
|
||||
void resetTool();
|
||||
std::optional<QPointF> getPagePointUnderMouse(QMouseEvent* event) const;
|
||||
|
||||
bool isEditing() const;
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFPageContentElementTextBox* m_element;
|
||||
PDFTextEditPseudowidget* m_textEditWidget;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFPAGECONTENTEDITORTOOLS_H
|
276
Pdf4QtLibWidgets/sources/pdfpagecontenteditorwidget.cpp
Normal file
276
Pdf4QtLibWidgets/sources/pdfpagecontenteditorwidget.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
// 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/>.
|
||||
|
||||
#include "pdfpagecontenteditorwidget.h"
|
||||
#include "pdfpagecontenteditorstylesettings.h"
|
||||
#include "ui_pdfpagecontenteditorwidget.h"
|
||||
#include "pdfwidgetutils.h"
|
||||
#include "pdfpagecontentelements.h"
|
||||
#include "pdfutils.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QToolButton>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFPageContentEditorWidget::PDFPageContentEditorWidget(QWidget* parent) :
|
||||
QDockWidget(parent),
|
||||
ui(new Ui::PDFPageContentEditorWidget),
|
||||
m_toolBoxColumnCount(6),
|
||||
m_scene(nullptr),
|
||||
m_selectionChangeEnabled(true),
|
||||
m_updatesEnabled(true)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_toolButtonIconSize = PDFWidgetUtils::scaleDPI(this, QSize(32, 32));
|
||||
|
||||
for (QToolButton* button : findChildren<QToolButton*>())
|
||||
{
|
||||
button->setIconSize(m_toolButtonIconSize);
|
||||
}
|
||||
|
||||
m_settingsWidget = new PDFPageContentEditorStyleSettings(this);
|
||||
ui->appearanceLayout->addWidget(m_settingsWidget);
|
||||
|
||||
m_operationMapper.setMapping(ui->alignVertTopButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignTop));
|
||||
m_operationMapper.setMapping(ui->alignVertMiddleButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignCenterVertically));
|
||||
m_operationMapper.setMapping(ui->alignVertBottomButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignBottom));
|
||||
m_operationMapper.setMapping(ui->alignHorLeftButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignLeft));
|
||||
m_operationMapper.setMapping(ui->alignHorMiddleButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignCenterHorizontally));
|
||||
m_operationMapper.setMapping(ui->alignHorRightButton, static_cast<int>(PDFPageContentElementManipulator::Operation::AlignRight));
|
||||
m_operationMapper.setMapping(ui->setSameWidthButton, static_cast<int>(PDFPageContentElementManipulator::Operation::SetSameWidth));
|
||||
m_operationMapper.setMapping(ui->setSameHeightButton, static_cast<int>(PDFPageContentElementManipulator::Operation::SetSameHeight));
|
||||
m_operationMapper.setMapping(ui->setSameSizeButton, static_cast<int>(PDFPageContentElementManipulator::Operation::SetSameSize));
|
||||
m_operationMapper.setMapping(ui->centerHorizontallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::CenterHorizontally));
|
||||
m_operationMapper.setMapping(ui->centerVerticallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::CenterVertically));
|
||||
m_operationMapper.setMapping(ui->centerRectButton, static_cast<int>(PDFPageContentElementManipulator::Operation::CenterHorAndVert));
|
||||
m_operationMapper.setMapping(ui->layoutHorizontallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutHorizontally));
|
||||
m_operationMapper.setMapping(ui->layoutVerticallyButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutVertically));
|
||||
m_operationMapper.setMapping(ui->layoutFormButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutForm));
|
||||
m_operationMapper.setMapping(ui->layoutGridButton, static_cast<int>(PDFPageContentElementManipulator::Operation::LayoutGrid));
|
||||
|
||||
connect(ui->alignVertTopButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->alignVertMiddleButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->alignVertBottomButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->alignHorLeftButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->alignHorMiddleButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->alignHorRightButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->setSameWidthButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->setSameHeightButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->setSameSizeButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->centerHorizontallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->centerVerticallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->centerRectButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->layoutHorizontallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->layoutVerticallyButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->layoutFormButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(ui->layoutGridButton, &QToolButton::clicked, &m_operationMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
|
||||
connect(&m_actionMapper, &QSignalMapper::mappedObject, this, &PDFPageContentEditorWidget::onActionTriggerRequest);
|
||||
connect(&m_operationMapper, &QSignalMapper::mappedInt, this, &PDFPageContentEditorWidget::operationTriggered);
|
||||
connect(ui->itemsListWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PDFPageContentEditorWidget::onItemSelectionChanged);
|
||||
|
||||
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::penChanged, this, &PDFPageContentEditorWidget::penChanged);
|
||||
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::brushChanged, this, &PDFPageContentEditorWidget::brushChanged);
|
||||
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::fontChanged, this, &PDFPageContentEditorWidget::fontChanged);
|
||||
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::alignmentChanged, this, &PDFPageContentEditorWidget::alignmentChanged);
|
||||
connect(m_settingsWidget, &PDFPageContentEditorStyleSettings::textAngleChanged, this, &PDFPageContentEditorWidget::textAngleChanged);
|
||||
}
|
||||
|
||||
PDFPageContentEditorWidget::~PDFPageContentEditorWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::addAction(QAction* action)
|
||||
{
|
||||
// First, find position for our action
|
||||
int row = 0;
|
||||
int column = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!ui->toolGroupBoxLayout->itemAtPosition(row, column))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
++column;
|
||||
|
||||
if (column == m_toolBoxColumnCount)
|
||||
{
|
||||
column = 0;
|
||||
++row;
|
||||
}
|
||||
}
|
||||
|
||||
QToolButton* button = new QToolButton(this);
|
||||
button->setIcon(action->icon());
|
||||
button->setText(action->text());
|
||||
button->setToolTip(action->toolTip());
|
||||
button->setCheckable(action->isCheckable());
|
||||
button->setChecked(action->isChecked());
|
||||
button->setEnabled(action->isEnabled());
|
||||
button->setShortcut(action->shortcut());
|
||||
button->setIconSize(m_toolButtonIconSize);
|
||||
m_actionMapper.setMapping(button, action);
|
||||
connect(button, &QToolButton::clicked, &m_actionMapper, QOverload<>::of(&QSignalMapper::map));
|
||||
connect(action, &QAction::changed, this, &PDFPageContentEditorWidget::onActionChanged);
|
||||
|
||||
ui->toolGroupBoxLayout->addWidget(button, row, column, Qt::AlignCenter);
|
||||
}
|
||||
|
||||
QToolButton* PDFPageContentEditorWidget::getToolButtonForOperation(int operation) const
|
||||
{
|
||||
return qobject_cast<QToolButton*>(m_operationMapper.mapping(operation));
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::updateItemsInListWidget()
|
||||
{
|
||||
if (!m_updatesEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pdf::PDFTemporaryValueChange guard(&m_updatesEnabled, false);
|
||||
ui->itemsListWidget->setUpdatesEnabled(false);
|
||||
|
||||
if (m_scene)
|
||||
{
|
||||
std::set<PDFInteger> presentElementIds;
|
||||
std::set<PDFInteger> elementIds = m_scene->getElementIds();
|
||||
|
||||
// Remove items which are not here
|
||||
for (int i = 0; i < ui->itemsListWidget->count();)
|
||||
{
|
||||
QListWidgetItem* item = ui->itemsListWidget->item(i);
|
||||
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
|
||||
if (!elementIds.count(elementId))
|
||||
{
|
||||
delete ui->itemsListWidget->takeItem(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
presentElementIds.insert(elementId);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Add items which are here
|
||||
for (PDFInteger elementId : elementIds)
|
||||
{
|
||||
if (presentElementIds.count(elementId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const PDFPageContentElement* element = m_scene->getElementById(elementId);
|
||||
Q_ASSERT(element);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(element->getDescription());
|
||||
item->setData(Qt::UserRole, int(elementId));
|
||||
|
||||
ui->itemsListWidget->addItem(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->itemsListWidget->clear();
|
||||
}
|
||||
|
||||
ui->itemsListWidget->setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::onActionTriggerRequest(QObject* actionObject)
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(actionObject);
|
||||
Q_ASSERT(action);
|
||||
|
||||
action->trigger();
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::onActionChanged()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
QToolButton* button = qobject_cast<QToolButton*>(m_actionMapper.mapping(action));
|
||||
|
||||
Q_ASSERT(action);
|
||||
Q_ASSERT(button);
|
||||
|
||||
button->setChecked(action->isChecked());
|
||||
button->setEnabled(action->isEnabled());
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::onItemSelectionChanged()
|
||||
{
|
||||
if (m_selectionChangeEnabled)
|
||||
{
|
||||
Q_EMIT itemSelectionChangedByUser();
|
||||
}
|
||||
}
|
||||
|
||||
PDFPageContentScene* PDFPageContentEditorWidget::scene() const
|
||||
{
|
||||
return m_scene;
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::setScene(PDFPageContentScene* newScene)
|
||||
{
|
||||
if (m_scene != newScene)
|
||||
{
|
||||
m_scene = newScene;
|
||||
updateItemsInListWidget();
|
||||
}
|
||||
}
|
||||
|
||||
std::set<PDFInteger> PDFPageContentEditorWidget::getSelection() const
|
||||
{
|
||||
std::set<PDFInteger> result;
|
||||
|
||||
for (int i = 0; i < ui->itemsListWidget->count(); ++i)
|
||||
{
|
||||
QListWidgetItem* item = ui->itemsListWidget->item(i);
|
||||
if (item->isSelected())
|
||||
{
|
||||
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
|
||||
result.insert(elementId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::setSelection(const std::set<PDFInteger>& selection)
|
||||
{
|
||||
pdf::PDFTemporaryValueChange guard(&m_selectionChangeEnabled, false);
|
||||
|
||||
for (int i = 0; i < ui->itemsListWidget->count(); ++i)
|
||||
{
|
||||
QListWidgetItem* item = ui->itemsListWidget->item(i);
|
||||
const PDFInteger elementId = item->data(Qt::UserRole).toLongLong();
|
||||
item->setSelected(selection.count(elementId));
|
||||
}
|
||||
}
|
||||
|
||||
void PDFPageContentEditorWidget::loadStyleFromElement(const PDFPageContentElement* element)
|
||||
{
|
||||
m_settingsWidget->loadFromElement(element, false);
|
||||
}
|
||||
|
||||
} // namespace pdf
|
95
Pdf4QtLibWidgets/sources/pdfpagecontenteditorwidget.h
Normal file
95
Pdf4QtLibWidgets/sources/pdfpagecontenteditorwidget.h
Normal file
@ -0,0 +1,95 @@
|
||||
// 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 PDFPAGECONTENTEDITORWIDGET_H
|
||||
#define PDFPAGECONTENTEDITORWIDGET_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QSignalMapper>
|
||||
|
||||
#include <set>
|
||||
|
||||
class QToolButton;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFPageContentEditorWidget;
|
||||
}
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFPageContentScene;
|
||||
class PDFPageContentElement;
|
||||
class PDFPageContentEditorStyleSettings;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPageContentEditorWidget : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFPageContentEditorWidget(QWidget* parent);
|
||||
virtual ~PDFPageContentEditorWidget() override;
|
||||
|
||||
/// Adds external action to the tool box
|
||||
void addAction(QAction* action);
|
||||
|
||||
QToolButton* getToolButtonForOperation(int operation) const;
|
||||
|
||||
/// Update items in list widget
|
||||
void updateItemsInListWidget();
|
||||
|
||||
PDFPageContentScene* scene() const;
|
||||
void setScene(PDFPageContentScene* newScene);
|
||||
|
||||
std::set<PDFInteger> getSelection() const;
|
||||
void setSelection(const std::set<PDFInteger>& selection);
|
||||
|
||||
/// Loads style from element, element can be nullptr
|
||||
/// \param element Element
|
||||
void loadStyleFromElement(const PDFPageContentElement* element);
|
||||
|
||||
signals:
|
||||
void operationTriggered(int operation);
|
||||
void itemSelectionChangedByUser();
|
||||
|
||||
void penChanged(const QPen& pen);
|
||||
void brushChanged(const QBrush& brush);
|
||||
void fontChanged(const QFont& font);
|
||||
void alignmentChanged(Qt::Alignment alignment);
|
||||
void textAngleChanged(pdf::PDFReal angle);
|
||||
|
||||
private:
|
||||
void onActionTriggerRequest(QObject* actionObject);
|
||||
void onActionChanged();
|
||||
void onItemSelectionChanged();
|
||||
|
||||
Ui::PDFPageContentEditorWidget* ui;
|
||||
PDFPageContentEditorStyleSettings* m_settingsWidget;
|
||||
QSignalMapper m_actionMapper;
|
||||
QSignalMapper m_operationMapper;
|
||||
int m_toolBoxColumnCount;
|
||||
QSize m_toolButtonIconSize;
|
||||
PDFPageContentScene* m_scene;
|
||||
bool m_selectionChangeEnabled;
|
||||
bool m_updatesEnabled;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFPAGECONTENTEDITORWIDGET_H
|
204
Pdf4QtLibWidgets/sources/pdfpagecontenteditorwidget.ui
Normal file
204
Pdf4QtLibWidgets/sources/pdfpagecontenteditorwidget.ui
Normal file
@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFPageContentEditorWidget</class>
|
||||
<widget class="QDockWidget" name="PDFPageContentEditorWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>333</width>
|
||||
<height>607</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="allowedAreas">
|
||||
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Content editor</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,1">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="toolGroupBox">
|
||||
<property name="title">
|
||||
<string>Toolbox</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="toolGroupBoxLayout"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="adjustBox">
|
||||
<property name="title">
|
||||
<string>Geometry Tools</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="geometryToolsGroupBoxLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QToolButton" name="alignVertTopButton">
|
||||
<property name="toolTip">
|
||||
<string>Align to Top</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolButton" name="alignVertMiddleButton">
|
||||
<property name="toolTip">
|
||||
<string>Align to Vertical Center</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="alignVertBottomButton">
|
||||
<property name="toolTip">
|
||||
<string>Align to Bottom</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QToolButton" name="setSameWidthButton">
|
||||
<property name="toolTip">
|
||||
<string>Set Same Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QToolButton" name="setSameHeightButton">
|
||||
<property name="toolTip">
|
||||
<string>Set Same Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QToolButton" name="setSameSizeButton">
|
||||
<property name="toolTip">
|
||||
<string>Set Same Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QToolButton" name="alignHorLeftButton">
|
||||
<property name="toolTip">
|
||||
<string>Align to Left</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QToolButton" name="alignHorMiddleButton">
|
||||
<property name="toolTip">
|
||||
<string>Align to Horizontal Center</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QToolButton" name="alignHorRightButton">
|
||||
<property name="toolTip">
|
||||
<string>Align to Right</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QToolButton" name="centerHorizontallyButton">
|
||||
<property name="toolTip">
|
||||
<string>Center Horizontally</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QToolButton" name="centerVerticallyButton">
|
||||
<property name="toolTip">
|
||||
<string>Center Vertically</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QToolButton" name="centerRectButton">
|
||||
<property name="toolTip">
|
||||
<string>Center to Page Media Box</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="layoutGroupBox">
|
||||
<property name="title">
|
||||
<string>Layout Tools</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="layoutToolBoxLayout">
|
||||
<item>
|
||||
<widget class="QToolButton" name="layoutHorizontallyButton">
|
||||
<property name="toolTip">
|
||||
<string>Make Horizontal Layout</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="layoutVerticallyButton">
|
||||
<property name="toolTip">
|
||||
<string>Make Vertical Layout</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="layoutFormButton">
|
||||
<property name="toolTip">
|
||||
<string>Make Form Layout</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="layoutGridButton">
|
||||
<property name="toolTip">
|
||||
<string>Make Grid Layout</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="appearanceGroupBox">
|
||||
<property name="title">
|
||||
<string>Appearance</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="appearanceLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<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>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="contentGroupBox">
|
||||
<property name="title">
|
||||
<string>Content</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QListWidget" name="itemsListWidget">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
111
Pdf4QtLibWidgets/sources/pdfrenderingerrorswidget.cpp
Normal file
111
Pdf4QtLibWidgets/sources/pdfrenderingerrorswidget.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2019-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/>.
|
||||
|
||||
#include "pdfrenderingerrorswidget.h"
|
||||
#include "pdfdrawwidget.h"
|
||||
#include "pdfdbgheap.h"
|
||||
#include "ui_pdfrenderingerrorswidget.h"
|
||||
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFRenderingErrorsWidget::PDFRenderingErrorsWidget(QWidget* parent, PDFWidget* pdfWidget) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::PDFRenderingErrorsWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->renderErrorsTreeWidget->setColumnCount(3);
|
||||
ui->renderErrorsTreeWidget->setColumnWidth(0, 100);
|
||||
ui->renderErrorsTreeWidget->setColumnWidth(1, 300);
|
||||
ui->renderErrorsTreeWidget->setHeaderLabels({ tr("Page"), tr("Error type"), tr("Description") });
|
||||
|
||||
Q_ASSERT(pdfWidget);
|
||||
std::vector<PDFInteger> currentPages = pdfWidget->getDrawWidget()->getCurrentPages();
|
||||
std::sort(currentPages.begin(), currentPages.end());
|
||||
|
||||
QTreeWidgetItem* scrollToItem = nullptr;
|
||||
const PDFWidget::PageRenderingErrors* pageRenderingErrors = pdfWidget->getPageRenderingErrors();
|
||||
for (const auto& pageRenderingError : *pageRenderingErrors)
|
||||
{
|
||||
const PDFInteger pageIndex = pageRenderingError.first;
|
||||
QTreeWidgetItem* root = new QTreeWidgetItem(ui->renderErrorsTreeWidget, QStringList() << QString::number(pageIndex + 1) << QString() << QString());
|
||||
|
||||
for (const PDFRenderError& error : pageRenderingError.second)
|
||||
{
|
||||
QString typeString;
|
||||
switch (error.type)
|
||||
{
|
||||
case RenderErrorType::Error:
|
||||
{
|
||||
typeString = tr("Error");
|
||||
break;
|
||||
}
|
||||
|
||||
case RenderErrorType::Warning:
|
||||
{
|
||||
typeString = tr("Warning");
|
||||
break;
|
||||
}
|
||||
|
||||
case RenderErrorType::NotImplemented:
|
||||
{
|
||||
typeString = tr("Not implemented");
|
||||
break;
|
||||
}
|
||||
|
||||
case RenderErrorType::NotSupported:
|
||||
{
|
||||
typeString = tr("Not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new QTreeWidgetItem(root, QStringList() << QString() << typeString << error.message);
|
||||
}
|
||||
|
||||
bool isCurrentPage = std::binary_search(currentPages.cbegin(), currentPages.cend(), pageIndex);
|
||||
root->setExpanded(isCurrentPage);
|
||||
|
||||
if (isCurrentPage && !scrollToItem)
|
||||
{
|
||||
scrollToItem = root;
|
||||
}
|
||||
}
|
||||
|
||||
if (scrollToItem)
|
||||
{
|
||||
ui->renderErrorsTreeWidget->scrollToItem(scrollToItem, QAbstractItemView::EnsureVisible);
|
||||
}
|
||||
|
||||
pdf::PDFWidgetUtils::style(this);
|
||||
}
|
||||
|
||||
PDFRenderingErrorsWidget::~PDFRenderingErrorsWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
48
Pdf4QtLibWidgets/sources/pdfrenderingerrorswidget.h
Normal file
48
Pdf4QtLibWidgets/sources/pdfrenderingerrorswidget.h
Normal file
@ -0,0 +1,48 @@
|
||||
// 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 PDFRENDERINGERRORSWIDGET_H
|
||||
#define PDFRENDERINGERRORSWIDGET_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFRenderingErrorsWidget;
|
||||
}
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFWidget;
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFRenderingErrorsWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFRenderingErrorsWidget(QWidget* parent, PDFWidget* pdfWidget);
|
||||
virtual ~PDFRenderingErrorsWidget() override;
|
||||
|
||||
private:
|
||||
Ui::PDFRenderingErrorsWidget* ui;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFRENDERINGERRORSWIDGET_H
|
73
Pdf4QtLibWidgets/sources/pdfrenderingerrorswidget.ui
Normal file
73
Pdf4QtLibWidgets/sources/pdfrenderingerrorswidget.ui
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFRenderingErrorsWidget</class>
|
||||
<widget class="QDialog" name="PDFRenderingErrorsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>798</width>
|
||||
<height>510</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Rendering errors</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="renderErrorsTreeWidget">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PDFRenderingErrorsWidget</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PDFRenderingErrorsWidget</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
137
Pdf4QtLibWidgets/sources/pdfselectpagesdialog.cpp
Normal file
137
Pdf4QtLibWidgets/sources/pdfselectpagesdialog.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright (C) 2020-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/>.
|
||||
|
||||
#include "pdfselectpagesdialog.h"
|
||||
#include "pdfdbgheap.h"
|
||||
#include "ui_pdfselectpagesdialog.h"
|
||||
|
||||
#include "pdfwidgetutils.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFSelectPagesDialog::PDFSelectPagesDialog(QString windowTitle,
|
||||
QString groupBoxTitle,
|
||||
pdf::PDFInteger pageCount,
|
||||
const std::vector<pdf::PDFInteger>& visiblePages,
|
||||
QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::PDFSelectPagesDialog),
|
||||
m_pageCount(pageCount),
|
||||
m_visiblePages(visiblePages)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowTitle(windowTitle);
|
||||
ui->selectPagesGroupBox->setTitle(groupBoxTitle);
|
||||
|
||||
for (pdf::PDFInteger& pageIndex : m_visiblePages)
|
||||
{
|
||||
++pageIndex;
|
||||
}
|
||||
|
||||
m_evenPages.reserve(pageCount / 2);
|
||||
m_oddPages.reserve(pageCount / 2 + 1);
|
||||
|
||||
for (pdf::PDFInteger i = 1; i <= pageCount; ++i)
|
||||
{
|
||||
if (i % 2 == 1)
|
||||
{
|
||||
m_oddPages.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_evenPages.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
connect(ui->customPageRangeRadioButton, &QRadioButton::toggled, this, &PDFSelectPagesDialog::updateUi);
|
||||
|
||||
setMinimumWidth(pdf::PDFWidgetUtils::scaleDPI_x(this, 400));
|
||||
updateUi();
|
||||
pdf::PDFWidgetUtils::style(this);
|
||||
}
|
||||
|
||||
PDFSelectPagesDialog::~PDFSelectPagesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
std::vector<pdf::PDFInteger> PDFSelectPagesDialog::getSelectedPages() const
|
||||
{
|
||||
std::vector<pdf::PDFInteger> result;
|
||||
|
||||
if (ui->visiblePagesRadioButton->isChecked())
|
||||
{
|
||||
result = m_visiblePages;
|
||||
}
|
||||
else if (ui->allPagesRadioButton->isChecked())
|
||||
{
|
||||
result.resize(m_pageCount, 0);
|
||||
std::iota(result.begin(), result.end(), 1);
|
||||
}
|
||||
else if (ui->evenPagesRadioButton->isChecked())
|
||||
{
|
||||
result = m_evenPages;
|
||||
}
|
||||
else if (ui->oddPagesRadioButton->isChecked())
|
||||
{
|
||||
result = m_oddPages;
|
||||
}
|
||||
else if (ui->customPageRangeRadioButton->isChecked())
|
||||
{
|
||||
QString errorMessage;
|
||||
result = pdf::PDFClosedIntervalSet::parse(1, m_pageCount, ui->customPageRangeEdit->text(), &errorMessage).unfold();
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFSelectPagesDialog::updateUi()
|
||||
{
|
||||
ui->customPageRangeEdit->setEnabled(ui->customPageRangeRadioButton->isChecked());
|
||||
}
|
||||
|
||||
void PDFSelectPagesDialog::accept()
|
||||
{
|
||||
if (ui->customPageRangeRadioButton->isChecked())
|
||||
{
|
||||
QString errorMessage;
|
||||
pdf::PDFClosedIntervalSet::parse(1, m_pageCount, ui->customPageRangeEdit->text(), &errorMessage);
|
||||
if (!errorMessage.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), errorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (getSelectedPages().empty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Selected page range is empty."));
|
||||
return;
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
} // namespace pdf
|
62
Pdf4QtLibWidgets/sources/pdfselectpagesdialog.h
Normal file
62
Pdf4QtLibWidgets/sources/pdfselectpagesdialog.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright (C) 2020-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 PDFSELECTPAGESDIALOG_H
|
||||
#define PDFSELECTPAGESDIALOG_H
|
||||
|
||||
#include "pdfutils.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class PDFSelectPagesDialog;
|
||||
}
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFSelectPagesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PDFSelectPagesDialog(QString windowTitle,
|
||||
QString groupBoxTitle,
|
||||
pdf::PDFInteger pageCount,
|
||||
const std::vector<pdf::PDFInteger>& visiblePages,
|
||||
QWidget* parent);
|
||||
|
||||
virtual ~PDFSelectPagesDialog() override;
|
||||
|
||||
virtual void accept() override;
|
||||
|
||||
std::vector<pdf::PDFInteger> getSelectedPages() const;
|
||||
|
||||
private:
|
||||
void updateUi();
|
||||
|
||||
Ui::PDFSelectPagesDialog* ui;
|
||||
pdf::PDFInteger m_pageCount;
|
||||
std::vector<pdf::PDFInteger> m_visiblePages;
|
||||
std::vector<pdf::PDFInteger> m_evenPages;
|
||||
std::vector<pdf::PDFInteger> m_oddPages;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFSELECTPAGESDIALOG_H
|
121
Pdf4QtLibWidgets/sources/pdfselectpagesdialog.ui
Normal file
121
Pdf4QtLibWidgets/sources/pdfselectpagesdialog.ui
Normal file
@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PDFSelectPagesDialog</class>
|
||||
<widget class="QDialog" name="PDFSelectPagesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>218</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="selectPagesGroupBox">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="allPagesRadioButton">
|
||||
<property name="text">
|
||||
<string>All pages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="customPageRangeEdit"/>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="evenPagesRadioButton">
|
||||
<property name="text">
|
||||
<string>Even pages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="oddPagesRadioButton">
|
||||
<property name="text">
|
||||
<string>Odd pages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QRadioButton" name="customPageRangeRadioButton">
|
||||
<property name="text">
|
||||
<string>Custom page range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="visiblePagesRadioButton">
|
||||
<property name="text">
|
||||
<string>Visible pages</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PDFSelectPagesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PDFSelectPagesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
2018
Pdf4QtLibWidgets/sources/pdfwidgettool.cpp
Normal file
2018
Pdf4QtLibWidgets/sources/pdfwidgettool.cpp
Normal file
File diff suppressed because it is too large
Load Diff
620
Pdf4QtLibWidgets/sources/pdfwidgettool.h
Normal file
620
Pdf4QtLibWidgets/sources/pdfwidgettool.h
Normal file
@ -0,0 +1,620 @@
|
||||
// Copyright (C) 2020-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 PDFWIDGETTOOL_H
|
||||
#define PDFWIDGETTOOL_H
|
||||
|
||||
#include "pdfdrawspacecontroller.h"
|
||||
#include "pdftextlayout.h"
|
||||
#include "pdfsnapper.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QCursor>
|
||||
|
||||
class QCheckBox;
|
||||
class QLineEdit;
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QObject;
|
||||
|
||||
public:
|
||||
explicit PDFWidgetTool(PDFDrawWidgetProxy* proxy, QObject* parent);
|
||||
explicit PDFWidgetTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
virtual ~PDFWidgetTool();
|
||||
|
||||
/// Sets document, shuts down the tool, if it is active, and document
|
||||
/// is changing.
|
||||
/// \param document Document
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
/// Sets tool as active or inactive. If tool is active, then it is processed
|
||||
/// in draw widget proxy events (such as drawing etc.).
|
||||
/// \param active Is tool active?
|
||||
void setActive(bool active);
|
||||
|
||||
/// Returns true, if tool is active
|
||||
bool isActive() const { return m_active; }
|
||||
|
||||
/// Returns action for activating/deactivating this tool
|
||||
QAction* getAction() const { return m_action; }
|
||||
|
||||
/// Handles shortcut override event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles key press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles key release event from widget
|
||||
/// \param widget Widget
|
||||
/// \param event Event
|
||||
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event);
|
||||
|
||||
/// Handles mouse press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse double click event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse release event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse move event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event);
|
||||
|
||||
/// Handles mouse wheel event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event);
|
||||
|
||||
/// Returns actual cursor defined by the tool. Cursor can be undefined,
|
||||
/// in this case, optional will be set to nullopt.
|
||||
const std::optional<QCursor>& getCursor() const;
|
||||
|
||||
signals:
|
||||
/// Informs about tool activity changed (if tool is enabled or disabled)
|
||||
/// \param active Is tool active?
|
||||
void toolActivityChanged(bool active);
|
||||
|
||||
/// This is signal is set, when we want to display information message
|
||||
/// to the user, with timeout in miliseconds, after which message
|
||||
/// dissappears.
|
||||
/// \param text Text, which should be displayed to the user
|
||||
/// \param timeout Timeout in miliseconds
|
||||
void messageDisplayRequest(const QString& text, int timeout);
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active);
|
||||
virtual void updateActions();
|
||||
|
||||
/// Returns currently active tool from toolstack,
|
||||
/// or nullptr, if no active tool from toolstack exists.
|
||||
PDFWidgetTool* getTopToolstackTool() const;
|
||||
|
||||
const PDFDocument* getDocument() const { return m_document; }
|
||||
PDFDrawWidgetProxy* getProxy() const { return m_proxy; }
|
||||
|
||||
inline void setCursor(QCursor cursor) { m_cursor = qMove(cursor); }
|
||||
inline void unsetCursor() { m_cursor = std::nullopt; }
|
||||
|
||||
void addTool(PDFWidgetTool* tool);
|
||||
void removeTool();
|
||||
|
||||
private:
|
||||
bool m_active;
|
||||
const PDFDocument* m_document;
|
||||
QAction* m_action;
|
||||
PDFDrawWidgetProxy* m_proxy;
|
||||
std::vector<PDFWidgetTool*> m_toolStack;
|
||||
std::optional<QCursor> m_cursor;
|
||||
};
|
||||
|
||||
/// Simple tool for find text in PDF document. It is much simpler than advanced
|
||||
/// search and can't search using regular expressions.
|
||||
class PDFFindTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Construct new text search tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param prevAction Action for navigating to previous result
|
||||
/// \param nextAction Action for navigating to next result
|
||||
/// \param parent Parent object
|
||||
/// \param parentDialog Paret dialog for tool dialog
|
||||
explicit PDFFindTextTool(PDFDrawWidgetProxy* proxy, QAction* prevAction, QAction* nextAction, QObject* parent, QWidget* parentDialog);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void onSearchText();
|
||||
void onActionPrevious();
|
||||
void onActionNext();
|
||||
void onDialogRejected();
|
||||
|
||||
void performSearch();
|
||||
void updateResultsUI();
|
||||
void updateTitle();
|
||||
void clearResults();
|
||||
void goToCurrentResult();
|
||||
|
||||
QAction* m_prevAction;
|
||||
QAction* m_nextAction;
|
||||
QWidget* m_parentDialog;
|
||||
|
||||
QDialog* m_dialog;
|
||||
QCheckBox* m_caseSensitiveCheckBox;
|
||||
QCheckBox* m_wholeWordsCheckBox;
|
||||
QLineEdit* m_findTextEdit;
|
||||
QPushButton* m_previousButton;
|
||||
QPushButton* m_nextButton;
|
||||
|
||||
QString m_savedText;
|
||||
bool m_savedIsCaseSensitive = false;
|
||||
bool m_savedIsWholeWords = false;
|
||||
|
||||
pdf::PDFTextSelection getTextSelection() const { return m_textSelection.get(this, &PDFFindTextTool::getTextSelectionImpl); }
|
||||
pdf::PDFTextSelection getTextSelectionImpl() const;
|
||||
pdf::PDFTextSelection getTextSelectionSelectedResultOnly() const;
|
||||
|
||||
struct SearchParameters
|
||||
{
|
||||
QString phrase;
|
||||
bool isCaseSensitive = false;
|
||||
bool isWholeWordsOnly = false;
|
||||
bool isSearchFinished = false;
|
||||
};
|
||||
|
||||
SearchParameters m_parameters;
|
||||
pdf::PDFFindResults m_findResults;
|
||||
size_t m_selectedResultIndex;
|
||||
mutable pdf::PDFCachedItem<pdf::PDFTextSelection> m_textSelection;
|
||||
};
|
||||
|
||||
/// Tool for selection of text in document
|
||||
class PDFSelectTextTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Construct new text selection tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param action Tool activation action
|
||||
/// \param copyTextAction Copy text action
|
||||
/// \param selectAllAction Select all text action
|
||||
/// \param deselectAction Deselect text action
|
||||
/// \param parent Parent object
|
||||
explicit PDFSelectTextTool(PDFDrawWidgetProxy* proxy, QAction* action, QAction* copyTextAction, QAction* selectAllAction, QAction* deselectAction, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void updateCursor();
|
||||
void onActionCopyText();
|
||||
void onActionSelectAll();
|
||||
void onActionDeselect();
|
||||
void setSelection(pdf::PDFTextSelection&& textSelection);
|
||||
|
||||
struct SelectionInfo
|
||||
{
|
||||
PDFInteger pageIndex = -1;
|
||||
QPointF selectionStartPoint;
|
||||
};
|
||||
|
||||
QAction* m_copyTextAction;
|
||||
QAction* m_selectAllAction;
|
||||
QAction* m_deselectAction;
|
||||
pdf::PDFTextSelection m_textSelection;
|
||||
SelectionInfo m_selectionInfo;
|
||||
bool m_isCursorOverText;
|
||||
};
|
||||
|
||||
/// Tool to magnify specific area in the drawing widget
|
||||
class PDF4QTLIBSHARED_EXPORT PDFMagnifierTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Constructs new magnifier tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param action Tool activation action
|
||||
/// \param parent Parent object
|
||||
explicit PDFMagnifierTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
|
||||
|
||||
int getMagnifierSize() const;
|
||||
void setMagnifierSize(int magnifierSize);
|
||||
|
||||
PDFReal getMagnifierZoom() const;
|
||||
void setMagnifierZoom(const PDFReal& magnifierZoom);
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
QPoint m_mousePos;
|
||||
int m_magnifierSize;
|
||||
PDFReal m_magnifierZoom;
|
||||
};
|
||||
|
||||
/// Tools for picking various items on page - points, rectangles, images etc.
|
||||
class PDF4QTLIBSHARED_EXPORT PDFPickTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
|
||||
enum class Mode
|
||||
{
|
||||
Points, ///< Pick points
|
||||
Rectangles, ///< Pick rectangles
|
||||
Images ///< Pick images
|
||||
};
|
||||
|
||||
/// Constructs new picking tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param mode Picking mode
|
||||
/// \param parent Parent object
|
||||
explicit PDFPickTool(PDFDrawWidgetProxy* proxy, Mode mode, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter, PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
virtual void drawPostRendering(QPainter* painter, QRect rect) const override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
QPointF getSnappedPoint() const;
|
||||
PDFInteger getPageIndex() const { return m_pageIndex; }
|
||||
const std::vector<QPointF>& getPickedPoints() const { return m_pickedPoints; }
|
||||
|
||||
/// Sets custom snap points for given page. If points on page aren't currently picked,
|
||||
/// function does nothing. Snap data are not updated.
|
||||
/// \param pageIndex pageIndex
|
||||
/// \param snapPoints Custom snap points
|
||||
void setCustomSnapPoints(PDFInteger pageIndex, const std::vector<QPointF>& snapPoints);
|
||||
|
||||
void resetTool();
|
||||
|
||||
/// Turns on/off drawing of selection rectangle, if rectangle picking
|
||||
/// mode is active.
|
||||
/// \param drawSelectionRectangle Draw selection rectangle?
|
||||
void setDrawSelectionRectangle(bool drawSelectionRectangle);
|
||||
|
||||
QColor getSelectionRectangleColor() const;
|
||||
void setSelectionRectangleColor(QColor selectionRectangleColor);
|
||||
|
||||
signals:
|
||||
void pointPicked(pdf::PDFInteger pageIndex, QPointF pagePoint);
|
||||
void rectanglePicked(pdf::PDFInteger pageIndex, QRectF pageRectangle);
|
||||
void imagePicked(const QImage& image);
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
void buildSnapData();
|
||||
|
||||
Mode m_mode;
|
||||
PDFSnapper m_snapper;
|
||||
QPoint m_mousePosition;
|
||||
PDFInteger m_pageIndex;
|
||||
std::vector<QPointF> m_pickedPoints;
|
||||
bool m_drawSelectionRectangle;
|
||||
QColor m_selectionRectangleColor;
|
||||
};
|
||||
|
||||
/// Tool for selection of table in document. Rows and columns
|
||||
/// are automatically detected and are modifiable by the user.
|
||||
class PDFSelectTableTool : public PDFWidgetTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Construct new table selection tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param action Tool activation action
|
||||
/// \param parent Parent object
|
||||
explicit PDFSelectTableTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
|
||||
virtual void drawPage(QPainter* painter,
|
||||
PDFInteger pageIndex,
|
||||
const PDFPrecompiledPage* compiledPage,
|
||||
PDFTextLayoutGetter& layoutGetter,
|
||||
const QTransform& pagePointToDevicePointMatrix,
|
||||
QList<PDFRenderError>& errors) const override;
|
||||
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void setActiveImpl(bool active) override;
|
||||
|
||||
private:
|
||||
void setPickedRectangle(const QRectF& newPickedRectangle);
|
||||
void setPageIndex(PDFInteger newPageIndex);
|
||||
void setTextLayout(PDFTextLayout&& newTextLayout);
|
||||
void autodetectTableGeometry();
|
||||
|
||||
bool isTablePicked() const;
|
||||
|
||||
void onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
PDFInteger m_pageIndex;
|
||||
QRectF m_pickedRectangle;
|
||||
PDFTextLayout m_textLayout;
|
||||
bool m_isTransposed;
|
||||
std::vector<PDFReal> m_horizontalBreaks;
|
||||
std::vector<PDFReal> m_verticalBreaks;
|
||||
PageRotation m_rotation;
|
||||
};
|
||||
|
||||
/// 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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Constructs new screenshot tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param action Tool activation action
|
||||
/// \param parent Parent object
|
||||
explicit PDFScreenshotTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
|
||||
private:
|
||||
void onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
};
|
||||
|
||||
/// 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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = PDFWidgetTool;
|
||||
|
||||
public:
|
||||
/// Constructs new extract image tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param action Tool activation action
|
||||
/// \param parent Parent object
|
||||
explicit PDFExtractImageTool(PDFDrawWidgetProxy* proxy, QAction* action, QObject* parent);
|
||||
|
||||
protected:
|
||||
virtual void updateActions() override;
|
||||
|
||||
private:
|
||||
void onImagePicked(const QImage& image);
|
||||
|
||||
PDFPickTool* m_pickTool;
|
||||
};
|
||||
|
||||
/// 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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
using BaseClass = QObject;
|
||||
|
||||
public:
|
||||
struct Actions
|
||||
{
|
||||
QAction* findPrevAction = nullptr; ///< Action for navigating to previous result
|
||||
QAction* findNextAction = nullptr; ///< Action for navigating to next result
|
||||
QAction* selectTextToolAction = nullptr;
|
||||
QAction* selectTableToolAction = nullptr;
|
||||
QAction* selectAllAction = nullptr;
|
||||
QAction* deselectAction = nullptr;
|
||||
QAction* copyTextAction = nullptr;
|
||||
QAction* magnifierAction = nullptr;
|
||||
QAction* screenshotToolAction = nullptr;
|
||||
QAction* extractImageAction = nullptr;
|
||||
};
|
||||
|
||||
/// Construct new text search tool
|
||||
/// \param proxy Draw widget proxy
|
||||
/// \param actions Actions
|
||||
/// \param parent Parent object
|
||||
/// \param parentDialog Paret dialog for tool dialog
|
||||
explicit PDFToolManager(PDFDrawWidgetProxy* proxy, Actions actions, QObject* parent, QWidget* parentDialog);
|
||||
|
||||
/// Sets document
|
||||
/// \param document Document
|
||||
void setDocument(const PDFModifiedDocument& document);
|
||||
|
||||
enum PredefinedTools
|
||||
{
|
||||
PickRectangleTool,
|
||||
FindTextTool,
|
||||
SelectTextTool,
|
||||
SelectTableTool,
|
||||
MagnifierTool,
|
||||
ScreenshotTool,
|
||||
ExtractImageTool,
|
||||
ToolEnd
|
||||
};
|
||||
|
||||
/// Sets active tool
|
||||
void setActiveTool(PDFWidgetTool* tool);
|
||||
|
||||
/// Adds a new tool to tool manager
|
||||
void addTool(PDFWidgetTool* tool);
|
||||
|
||||
/// Picks rectangle, if rectangle is successfully picked,
|
||||
/// then callback is called.
|
||||
/// \param callback Callback function
|
||||
void pickRectangle(std::function<void(PDFInteger, QRectF)> callback);
|
||||
|
||||
/// Returns first active tool from tool set. If no tool is active,
|
||||
/// then nullptr is returned.
|
||||
PDFWidgetTool* getActiveTool() const;
|
||||
|
||||
/// Returns find text tool
|
||||
PDFFindTextTool* getFindTextTool() const;
|
||||
|
||||
/// Returns magnifier tool
|
||||
PDFMagnifierTool* getMagnifierTool() const;
|
||||
|
||||
/// Handles shortcut override event
|
||||
virtual void shortcutOverrideEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
|
||||
/// Handles key press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void keyPressEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
|
||||
/// Handles key release event from widget
|
||||
/// \param widget Widget
|
||||
/// \param event Event
|
||||
virtual void keyReleaseEvent(QWidget* widget, QKeyEvent* event) override;
|
||||
|
||||
/// Handles mouse press event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
/// Handles mouse double click event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseDoubleClickEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
/// Handles mouse release event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
/// Handles mouse move event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
|
||||
|
||||
/// Handles mouse wheel event from widget, over which tool operates
|
||||
/// \param widget Widget, over which tool operates
|
||||
/// \param event Event
|
||||
virtual void wheelEvent(QWidget* widget, QWheelEvent* event) override;
|
||||
|
||||
/// Returns actual cursor defined by the tool. Cursor can be undefined,
|
||||
/// in this case, optional will be set to nullopt.
|
||||
virtual const std::optional<QCursor>& getCursor() const override;
|
||||
|
||||
virtual QString getTooltip() const override { return QString(); }
|
||||
virtual int getInputPriority() const override { return ToolPriority; }
|
||||
|
||||
signals:
|
||||
/// This is signal is set, when we want to display information message
|
||||
/// to the user, with timeout in miliseconds, after which message
|
||||
/// dissappears.
|
||||
/// \param text Text, which should be displayed to the user
|
||||
/// \param timeout Timeout in miliseconds
|
||||
void messageDisplayRequest(const QString& text, int timeout);
|
||||
|
||||
/// This signal is emitted, when tool changes the document by some way
|
||||
/// \param documet Modified document
|
||||
void documentModified(pdf::PDFModifiedDocument document);
|
||||
|
||||
private:
|
||||
void onToolActivityChanged(bool active);
|
||||
void onToolActionTriggered(bool checked);
|
||||
void onRectanglePicked(PDFInteger pageIndex, QRectF pageRectangle);
|
||||
|
||||
std::set<PDFWidgetTool*> m_tools;
|
||||
std::array<PDFWidgetTool*, ToolEnd> m_predefinedTools;
|
||||
std::map<QAction*, PDFWidgetTool*> m_actionsToTools;
|
||||
std::function<void(PDFInteger, QRectF)> m_pickRectangleCallback;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFWIDGETTOOL_H
|
212
Pdf4QtLibWidgets/sources/pdfwidgetutils.cpp
Normal file
212
Pdf4QtLibWidgets/sources/pdfwidgetutils.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
// Copyright (C) 2019-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/>.
|
||||
|
||||
#include "pdfwidgetutils.h"
|
||||
#include "pdfcolorconvertor.h"
|
||||
#include "pdfdbgheap.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QGroupBox>
|
||||
#include <QApplication>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
int qt_default_dpi_x() { return 72; }
|
||||
int qt_default_dpi_y() { return 72; }
|
||||
#else
|
||||
int qt_default_dpi_x() { return 96; }
|
||||
int qt_default_dpi_y() { return 96; }
|
||||
#endif
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
static constexpr bool isScalingNeeded()
|
||||
{
|
||||
return QT_VERSION_MAJOR < 6;
|
||||
}
|
||||
|
||||
int PDFWidgetUtils::getPixelSize(const QPaintDevice* device, pdf::PDFReal sizeMM)
|
||||
{
|
||||
const int width = device->width();
|
||||
const int height = device->height();
|
||||
|
||||
if (width > height)
|
||||
{
|
||||
return PDFReal(width) * sizeMM / PDFReal(device->widthMM());
|
||||
}
|
||||
else
|
||||
{
|
||||
return PDFReal(height) * sizeMM / PDFReal(device->heightMM());
|
||||
}
|
||||
}
|
||||
|
||||
int PDFWidgetUtils::scaleDPI_x(const QPaintDevice* device, int unscaledSize)
|
||||
{
|
||||
if constexpr (isScalingNeeded())
|
||||
{
|
||||
const double logicalDPI_x = device->logicalDpiX();
|
||||
const double defaultDPI_x = qt_default_dpi_x();
|
||||
return (logicalDPI_x / defaultDPI_x) * unscaledSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return unscaledSize;
|
||||
}
|
||||
}
|
||||
|
||||
int PDFWidgetUtils::scaleDPI_y(const QPaintDevice* device, int unscaledSize)
|
||||
{
|
||||
if constexpr (isScalingNeeded())
|
||||
{
|
||||
const double logicalDPI_y = device->logicalDpiY();
|
||||
const double defaultDPI_y = qt_default_dpi_y();
|
||||
return (logicalDPI_y / defaultDPI_y) * unscaledSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return unscaledSize;
|
||||
}
|
||||
}
|
||||
|
||||
PDFReal PDFWidgetUtils::scaleDPI_x(const QPaintDevice* device, PDFReal unscaledSize)
|
||||
{
|
||||
if constexpr (isScalingNeeded())
|
||||
{
|
||||
const double logicalDPI_x = device->logicalDpiX();
|
||||
const double defaultDPI_x = qt_default_dpi_x();
|
||||
return (logicalDPI_x / defaultDPI_x) * unscaledSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return unscaledSize;
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetUtils::scaleWidget(QWidget* widget, QSize unscaledSize)
|
||||
{
|
||||
if constexpr (!isScalingNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const double logicalDPI_x = widget->logicalDpiX();
|
||||
const double logicalDPI_y = widget->logicalDpiY();
|
||||
const double defaultDPI_x = qt_default_dpi_x();
|
||||
const double defaultDPI_y = qt_default_dpi_y();
|
||||
|
||||
const int width = (logicalDPI_x / defaultDPI_x) * unscaledSize.width();
|
||||
const int height = (logicalDPI_y / defaultDPI_y) * unscaledSize.height();
|
||||
|
||||
widget->resize(width, height);
|
||||
}
|
||||
|
||||
QSize PDFWidgetUtils::scaleDPI(const QPaintDevice* widget, QSize unscaledSize)
|
||||
{
|
||||
if constexpr (isScalingNeeded())
|
||||
{
|
||||
const double logicalDPI_x = widget->logicalDpiX();
|
||||
const double logicalDPI_y = widget->logicalDpiY();
|
||||
const double defaultDPI_x = qt_default_dpi_x();
|
||||
const double defaultDPI_y = qt_default_dpi_y();
|
||||
|
||||
const int width = (logicalDPI_x / defaultDPI_x) * unscaledSize.width();
|
||||
const int height = (logicalDPI_y / defaultDPI_y) * unscaledSize.height();
|
||||
|
||||
return QSize(width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
return unscaledSize;
|
||||
}
|
||||
}
|
||||
|
||||
void PDFWidgetUtils::style(QWidget* widget)
|
||||
{
|
||||
const int dialogMarginX = scaleDPI_x(widget, 12);
|
||||
const int dialogMarginY = scaleDPI_y(widget, 12);
|
||||
const int dialogSpacing = scaleDPI_y(widget, 12);
|
||||
|
||||
const int groupBoxMarginX = scaleDPI_x(widget, 20);
|
||||
const int groupBoxMarginY = scaleDPI_y(widget, 20);
|
||||
const int groupBoxSpacing = scaleDPI_y(widget, 12);
|
||||
|
||||
QList<QWidget*> childWidgets = widget->findChildren<QWidget*>();
|
||||
childWidgets.append(widget);
|
||||
|
||||
for (QWidget* childWidget : childWidgets)
|
||||
{
|
||||
if (qobject_cast<QGroupBox*>(childWidget))
|
||||
{
|
||||
childWidget->layout()->setContentsMargins(groupBoxMarginX, groupBoxMarginY, groupBoxMarginX, groupBoxMarginY);
|
||||
childWidget->layout()->setSpacing(groupBoxSpacing);
|
||||
}
|
||||
else if (qobject_cast<QDialog*>(childWidget))
|
||||
{
|
||||
childWidget->layout()->setContentsMargins(dialogMarginX, dialogMarginY, dialogMarginX, dialogMarginY);
|
||||
childWidget->layout()->setSpacing(dialogSpacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PDFWidgetUtils::isDarkTheme()
|
||||
{
|
||||
QPalette palette = QApplication::palette();
|
||||
QColor backgroundColor = palette.color(QPalette::Window);
|
||||
QColor textColor = palette.color(QPalette::WindowText);
|
||||
|
||||
return backgroundColor.lightness() < textColor.lightness();
|
||||
}
|
||||
|
||||
void PDFWidgetUtils::convertActionForDarkTheme(QAction* action, QSize iconSize, qreal devicePixelRatioF)
|
||||
{
|
||||
if (!action)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QIcon icon = action->icon();
|
||||
if (!icon.isNull())
|
||||
{
|
||||
icon = pdf::PDFWidgetUtils::convertIconForDarkTheme(icon, iconSize, devicePixelRatioF);
|
||||
action->setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
QIcon PDFWidgetUtils::convertIconForDarkTheme(QIcon icon, QSize iconSize, qreal devicePixelRatioF)
|
||||
{
|
||||
QPixmap pixmap(iconSize * devicePixelRatioF);
|
||||
pixmap.setDevicePixelRatio(devicePixelRatioF);
|
||||
pixmap.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&pixmap);
|
||||
icon.paint(&painter, QRect(0, 0, iconSize.width(), iconSize.height()));
|
||||
painter.end();
|
||||
|
||||
PDFColorConvertor convertor;
|
||||
convertor.setMode(PDFColorConvertor::Mode::InvertedColors);
|
||||
|
||||
QImage image = pixmap.toImage();
|
||||
image = convertor.convert(image);
|
||||
pixmap = QPixmap::fromImage(image);
|
||||
|
||||
return QIcon(pixmap);
|
||||
}
|
||||
|
||||
} // namespace pdf
|
94
Pdf4QtLibWidgets/sources/pdfwidgetutils.h
Normal file
94
Pdf4QtLibWidgets/sources/pdfwidgetutils.h
Normal file
@ -0,0 +1,94 @@
|
||||
// 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 PDFWIDGETUTILS_H
|
||||
#define PDFWIDGETUTILS_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QWidget>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDF4QTLIBSHARED_EXPORT PDFWidgetUtils
|
||||
{
|
||||
public:
|
||||
PDFWidgetUtils() = delete;
|
||||
|
||||
/// Converts size in MM to pixel size
|
||||
static int getPixelSize(const QPaintDevice* device, pdf::PDFReal sizeMM);
|
||||
|
||||
/// Scale horizontal DPI value
|
||||
/// \param device Paint device to obtain logical DPI for scaling
|
||||
static int scaleDPI_x(const QPaintDevice* device, int unscaledSize);
|
||||
|
||||
/// Scale vertical DPI value
|
||||
/// \param device Paint device to obtain logical DPI for scaling
|
||||
static int scaleDPI_y(const QPaintDevice* device, int unscaledSize);
|
||||
|
||||
/// Scale horizontal DPI value
|
||||
/// \param device Paint device to obtain logical DPI for scaling
|
||||
static PDFReal scaleDPI_x(const QPaintDevice* device, PDFReal unscaledSize);
|
||||
|
||||
/// Scales widget based on DPI
|
||||
/// \param widget Widget to be scaled
|
||||
/// \param unscaledSize Unscaled size of the widget
|
||||
static void scaleWidget(QWidget* widget, QSize unscaledSize);
|
||||
|
||||
/// Scales size based on DPI
|
||||
/// \param device Paint device to obtain logical DPI for scaling
|
||||
/// \param unscaledSize Unscaled size
|
||||
static QSize scaleDPI(const QPaintDevice* widget, QSize unscaledSize);
|
||||
|
||||
/// Apply style to the widget
|
||||
static void style(QWidget* widget);
|
||||
|
||||
/// Vrátí true, pokud je aktuálně nastavená dark theme
|
||||
/// pro aplikaci.
|
||||
static bool isDarkTheme();
|
||||
|
||||
/// Converts an action's icon for use in a dark theme.
|
||||
/// \param action Pointer to the QAction to be converted.
|
||||
/// \param iconSize The size of the action's icon.
|
||||
/// \param devicePixelRatioF The device pixel ratio factor.
|
||||
static void convertActionForDarkTheme(QAction* action, QSize iconSize, qreal devicePixelRatioF);
|
||||
|
||||
/// Converts an icon for use in a dark theme.
|
||||
/// \param icon The icon to be converted.
|
||||
/// \param iconSize The size of the icon.
|
||||
/// \param devicePixelRatioF The device pixel ratio factor.
|
||||
static QIcon convertIconForDarkTheme(QIcon icon, QSize iconSize, qreal devicePixelRatioF);
|
||||
|
||||
/// Converts an action's icon for use in a dark theme.
|
||||
/// \param action Pointer to the QAction to be converted.
|
||||
/// \param iconSize The size of the action's icon.
|
||||
/// \param devicePixelRatioF The device pixel ratio factor.
|
||||
template<typename Container>
|
||||
static void convertActionsForDarkTheme(const Container& actions, QSize iconSize, qreal devicePixelRatioF)
|
||||
{
|
||||
for (QAction* action : actions)
|
||||
{
|
||||
convertActionForDarkTheme(action, iconSize, devicePixelRatioF);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFWIDGETUTILS_H
|
Reference in New Issue
Block a user