diff --git a/Pdf4QtDiff/mainwindow.cpp b/Pdf4QtDiff/mainwindow.cpp index a959dc7..ed88f23 100644 --- a/Pdf4QtDiff/mainwindow.cpp +++ b/Pdf4QtDiff/mainwindow.cpp @@ -666,11 +666,11 @@ void MainWindow::setViewDocument(pdf::PDFDocument* document, bool updateCustomPa if (document) { pdf::PDFModifiedDocument modifiedDocument(document, m_optionalContentActivity); - m_pdfWidget->setDocument(modifiedDocument); + m_pdfWidget->setDocument(modifiedDocument, {}); } else { - m_pdfWidget->setDocument(pdf::PDFModifiedDocument()); + m_pdfWidget->setDocument(pdf::PDFModifiedDocument(), {}); } } diff --git a/Pdf4QtLibCore/sources/pdfannotation.cpp b/Pdf4QtLibCore/sources/pdfannotation.cpp index 6ca20f9..db3b507 100644 --- a/Pdf4QtLibCore/sources/pdfannotation.cpp +++ b/Pdf4QtLibCore/sources/pdfannotation.cpp @@ -24,7 +24,6 @@ #include "pdfparser.h" #include "pdfform.h" #include "pdfpainterutils.h" -#include "pdfdocumentbuilder.h" #include #include diff --git a/Pdf4QtLibGui/pdfprogramcontroller.cpp b/Pdf4QtLibGui/pdfprogramcontroller.cpp index ec75f95..0d1cdb2 100644 --- a/Pdf4QtLibGui/pdfprogramcontroller.cpp +++ b/Pdf4QtLibGui/pdfprogramcontroller.cpp @@ -1744,7 +1744,7 @@ void PDFProgramController::onFileChanged(const QString& fileName) QByteArray hash = pdf::PDFDocumentReader::hash(data); if (m_pdfDocument && m_pdfDocument->getSourceDataHash() != hash) { - auto queryPassword = [this](bool* ok) + auto queryPassword = [](bool* ok) { *ok = false; return QString(); @@ -1879,7 +1879,7 @@ void PDFProgramController::onDocumentReadingFinished() m_pdfDocument = qMove(result.document); m_signatures = qMove(result.signatures); pdf::PDFModifiedDocument document(m_pdfDocument.data(), m_optionalContentActivity); - setDocument(document, true); + setDocument(document, m_signatures, true); if (m_formManager) { @@ -1951,17 +1951,17 @@ void PDFProgramController::onDocumentModified(pdf::PDFModifiedDocument document) m_pdfDocument = document; document.setOptionalContentActivity(m_optionalContentActivity); - setDocument(document, false); + setDocument(document, {}, false); } void PDFProgramController::onDocumentUndoRedo(pdf::PDFModifiedDocument document) { m_pdfDocument = document; document.setOptionalContentActivity(m_optionalContentActivity); - setDocument(document, false); + setDocument(document, {}, false); } -void PDFProgramController::setDocument(pdf::PDFModifiedDocument document, bool isCurrentSaved) +void PDFProgramController::setDocument(pdf::PDFModifiedDocument document, std::vector signatureVerificationResult, bool isCurrentSaved) { if (document.hasReset()) { @@ -2021,7 +2021,7 @@ void PDFProgramController::setDocument(pdf::PDFModifiedDocument document, bool i m_undoRedoManager->setIsCurrentSaved(isCurrentSaved); } - m_pdfWidget->setDocument(document); + m_pdfWidget->setDocument(document, std::move(signatureVerificationResult)); m_mainWindowInterface->setDocument(document); m_CMSManager->setDocument(document); @@ -2065,7 +2065,7 @@ void PDFProgramController::closeDocument() } m_signatures.clear(); - setDocument(pdf::PDFModifiedDocument(), true); + setDocument(pdf::PDFModifiedDocument(), {}, true); m_pdfDocument.reset(); updateActionsAvailability(); updateTitle(); diff --git a/Pdf4QtLibGui/pdfprogramcontroller.h b/Pdf4QtLibGui/pdfprogramcontroller.h index d88ca6d..6a46c11 100644 --- a/Pdf4QtLibGui/pdfprogramcontroller.h +++ b/Pdf4QtLibGui/pdfprogramcontroller.h @@ -275,7 +275,7 @@ public: Q_DECLARE_FLAGS(Features, Feature) void openDocument(const QString& fileName); - void setDocument(pdf::PDFModifiedDocument document, bool isCurrentSaved); + void setDocument(pdf::PDFModifiedDocument document, std::vector signatureVerificationResult, bool isCurrentSaved); void closeDocument(); pdf::PDFWidget* getPdfWidget() const { return m_pdfWidget; } diff --git a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp index 658469b..8c5456a 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp +++ b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.cpp @@ -487,7 +487,7 @@ PDFDrawWidgetProxy::~PDFDrawWidgetProxy() } -void PDFDrawWidgetProxy::setDocument(const PDFModifiedDocument& document) +void PDFDrawWidgetProxy::setDocument(const PDFModifiedDocument& document, std::vector signatureVerificationResult) { if (getDocument() != document) { @@ -509,6 +509,8 @@ void PDFDrawWidgetProxy::setDocument(const PDFModifiedDocument& document) m_cacheClearTimer->start(CACHE_CLEAR_TIMEOUT); } } + + m_signatureVerificationResult = std::move(signatureVerificationResult); } void PDFDrawWidgetProxy::init(PDFWidget* widget) diff --git a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h index 8b9ffb3..bf245e0 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h +++ b/Pdf4QtLibWidgets/sources/pdfdrawspacecontroller.h @@ -18,6 +18,7 @@ #ifndef PDFDRAWSPACECONTROLLER_H #define PDFDRAWSPACECONTROLLER_H +#include "pdfsignaturehandler.h" #include "pdfwidgetsglobal.h" #include "pdfglobal.h" #include "pdfdocument.h" @@ -190,7 +191,7 @@ public: /// in that case, draw space is cleared. Optional content activity can be nullptr, /// in that case, no content is suppressed. /// \param document Document - void setDocument(const PDFModifiedDocument& document); + void setDocument(const PDFModifiedDocument& document, std::vector signatureVerificationResult); void init(PDFWidget* widget); @@ -374,6 +375,7 @@ public: void setGroupTransparency(PDFInteger groupIndex, bool drawPaper = true, PDFReal transparency = 1.0); PDFWidgetAnnotationManager* getAnnotationManager() const; + const std::vector& getSignatureVerificationResult() const { return m_signatureVerificationResult; } signals: void drawSpaceChanged(); @@ -540,6 +542,9 @@ private: /// can be rendered with transparency or without paper /// as overlay. std::map m_groupInfos; + + /// Signature verification results + std::vector m_signatureVerificationResult; }; } // namespace pdf diff --git a/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp b/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp index 871a61d..5d41519 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp +++ b/Pdf4QtLibWidgets/sources/pdfdrawwidget.cpp @@ -86,9 +86,9 @@ bool PDFWidget::focusNextPrevChild(bool next) return QWidget::focusNextPrevChild(next); } -void PDFWidget::setDocument(const PDFModifiedDocument& document) +void PDFWidget::setDocument(const PDFModifiedDocument& document, std::vector signatureVerificationResult) { - m_proxy->setDocument(document); + m_proxy->setDocument(document, std::move(signatureVerificationResult)); m_pageRenderingErrors.clear(); m_drawWidget->getWidget()->update(); } diff --git a/Pdf4QtLibWidgets/sources/pdfdrawwidget.h b/Pdf4QtLibWidgets/sources/pdfdrawwidget.h index d27eacb..c10ae0a 100644 --- a/Pdf4QtLibWidgets/sources/pdfdrawwidget.h +++ b/Pdf4QtLibWidgets/sources/pdfdrawwidget.h @@ -18,6 +18,7 @@ #ifndef PDFDRAWWIDGET_H #define PDFDRAWWIDGET_H +#include "pdfsignaturehandler.h" #include "pdfwidgetsglobal.h" #include "pdfglobal.h" #include "pdfrenderer.h" @@ -73,7 +74,7 @@ public: /// 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); + void setDocument(const PDFModifiedDocument& document, std::vector signatureVerificationResult); /// Update rendering engine according the settings /// \param engine Engine type diff --git a/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.cpp b/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.cpp index 3d1119c..4c7b62b 100644 --- a/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.cpp +++ b/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.cpp @@ -248,6 +248,179 @@ private: PDFTextEditPseudowidget m_textEdit; }; +/// Editor for signatures +class PDFFormFieldSignatureEditor : public PDFFormFieldWidgetEditor +{ + Q_DECLARE_TR_FUNCTIONS(pdf::PDFFormFieldSignatureEditor) + +private: + using BaseClass = PDFFormFieldWidgetEditor; + +public: + explicit PDFFormFieldSignatureEditor(PDFWidgetFormManager* formManager, PDFFormWidget formWidget); + virtual ~PDFFormFieldSignatureEditor() = default; + + virtual bool isEditorDrawEnabled() const override; + virtual void draw(AnnotationDrawParameters& parameters, bool edit) const override; +}; + +PDFFormFieldSignatureEditor::PDFFormFieldSignatureEditor(PDFWidgetFormManager* formManager, PDFFormWidget formWidget) : + BaseClass(formManager, formWidget) +{ + +} + +bool PDFFormFieldSignatureEditor::isEditorDrawEnabled() const +{ + PDFDrawWidgetProxy* proxy = m_formManager->getProxy(); + + if (proxy) + { + const std::vector& signatureVerificationResult = proxy->getSignatureVerificationResult(); + QString qualifiedName = m_formWidget.getParent()->getName(PDFFormField::NameType::FullyQualified); + + for (const PDFSignatureVerificationResult& result : signatureVerificationResult) + { + if (result.getSignatureFieldQualifiedName() == qualifiedName) + { + return true; + } + } + } + + return false; +} + +void PDFFormFieldSignatureEditor::draw(AnnotationDrawParameters& parameters, bool edit) const +{ + PDFPainterStateGuard guard(parameters.painter); + PDFDrawWidgetProxy* proxy = m_formManager->getProxy(); + const PDFSignatureVerificationResult* verificationResult = nullptr; + + Q_UNUSED(edit); + + if (proxy) + { + const std::vector& signatureVerificationResult = proxy->getSignatureVerificationResult(); + QString qualifiedName = m_formWidget.getParent()->getName(PDFFormField::NameType::FullyQualified); + + for (const PDFSignatureVerificationResult& result : signatureVerificationResult) + { + if (result.getSignatureFieldQualifiedName() == qualifiedName) + { + verificationResult = &result; + break; + } + } + } + + bool isValid = false; + QString text = tr("Signature Unknown"); + + if (verificationResult) + { + if (verificationResult->isValid()) + { + isValid = true; + text = tr("Signature Valid"); + } + else + { + isValid = false; + text = tr("Signature Invalid"); + } + } + + QColor foregroundColor = parameters.colorConvertor.convert(QColor(Qt::black), false, true); + parameters.painter->setPen(foregroundColor); + parameters.painter->setBrush(parameters.colorConvertor.convert(QColor(Qt::white), true, false)); + + QRectF rect = m_formManager->getWidgetRectangle(m_formWidget); + parameters.boundingRectangle = rect; + parameters.painter->drawRect(rect); + + QRectF textRect = rect; + textRect.setHeight(rect.height() * 0.25); + textRect.setWidth(rect.width() * 0.95); + textRect.translate((rect.width() - textRect.width()) * 0.5, rect.height() * 0.75); + + QPainterPath path; + path.addText(0, 0, parameters.painter->font(), text); + QSizeF textSize = path.boundingRect().size(); + qreal factor = qMin(textRect.width() / textSize.width(), textRect.height() / textSize.height()); + + QTransform matrix; + matrix.scale(factor, -factor); + path = matrix.map(path); + path.translate(textRect.center() - path.boundingRect().center()); + + parameters.painter->fillPath(path, foregroundColor); + + QPainterPath mark; + if (isValid) + { + parameters.painter->setBrush(Qt::darkGreen); + parameters.painter->setPen(Qt::NoPen); + + QPolygonF checkmark; + checkmark << QPointF(40, 120) + << QPointF(70, 150) + << QPointF(160, 40) + << QPointF(140, 20) + << QPointF(70, 120) + << QPointF(50, 100); + + mark.addPolygon(checkmark); + } + else + { + parameters.painter->setBrush(Qt::darkRed); + parameters.painter->setPen(Qt::NoPen); + + const double halfThickness = 10.0; + const double halfLength = 50.0; + + QPolygonF checkmark; + checkmark << QPointF(-halfLength, -halfThickness) + << QPointF(-halfLength, +halfThickness) + << QPointF(+halfLength, +halfThickness) + << QPointF(+halfLength, -halfThickness) + << QPointF(-halfLength, -halfThickness); + + mark.addPolygon(checkmark); + + checkmark.clear(); + checkmark << QPointF(-halfThickness, -halfLength) + << QPointF(-halfThickness, +halfLength) + << QPointF(+halfThickness, +halfLength) + << QPointF(+halfThickness, -halfLength) + << QPointF(-halfThickness, -halfLength); + mark.addPolygon(checkmark); + mark.setFillRule(Qt::WindingFill); + + QTransform transform; + transform.rotate(45.0); + mark = transform.map(mark); + } + + QRectF markRect = rect; + markRect.setHeight(rect.height() - textRect.height()); + QPointF markCenter = markRect.center(); + markRect.setHeight(markRect.height() * 0.75); + markRect.setWidth(markRect.width() * 0.75); + markRect.moveCenter(markCenter); + + QRectF markSymbolRect = mark.boundingRect(); + qreal symbolFactor = qMin(markRect.width() / markSymbolRect.width(), markRect.height() / markSymbolRect.height()); + + QTransform markTransform; + markTransform.scale(symbolFactor, -symbolFactor); + mark = markTransform.map(mark); + mark.translate(markRect.center() - mark.boundingRect().center()); + + parameters.painter->drawPath(mark); +} + /// Editor for combo boxes class PDFFormFieldComboBoxEditor : public PDFFormFieldWidgetEditor { @@ -761,8 +934,10 @@ void PDFWidgetFormManager::updateFormWidgetEditors() } case PDFFormField::FieldType::Signature: - // Signature fields doesn't have editor + { + m_widgetEditors.push_back(new PDFFormFieldSignatureEditor(this, widget)); break; + } default: Q_ASSERT(false); diff --git a/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.h b/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.h index 25ac14b..009ae31 100644 --- a/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.h +++ b/Pdf4QtLibWidgets/sources/pdfwidgetformmanager.h @@ -144,6 +144,8 @@ public: PDFWidgetAnnotationManager* getAnnotationManager() const; void setAnnotationManager(PDFWidgetAnnotationManager* annotationManager); + PDFDrawWidgetProxy* getProxy() const { return m_proxy; } + protected: virtual void updateFieldValues() override; virtual void onDocumentReset() override; diff --git a/RELEASES.txt b/RELEASES.txt index bfc1a79..168285f 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -10,6 +10,7 @@ CURRENT: - Issue #200: Icons under dark theme on Arch/KDE is broken - Issue #185: Latest git fails to build in linux - Issue #165: Insert > Inline Text latency issues on Flatpak and Appimage packages + - Issue #161: Can it be possible to trust a certificate like in acrobat? V: 1.4.0.0 4.7.2024 - Issue #190: PageMaster crash + black bubbles instead of bubbles with correct color