2022-02-11 19:15:57 +01:00
// 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 "signatureplugin.h"
# include "pdfdrawwidget.h"
2022-04-02 16:29:31 +02:00
# include "pdfutils.h"
2022-02-26 19:46:13 +01:00
# include "pdfpagecontenteditorwidget.h"
2022-04-17 18:11:07 +02:00
# include "pdfpagecontenteditorstylesettings.h"
2022-04-18 13:54:58 +02:00
# include "pdfdocumentbuilder.h"
2022-06-12 15:45:32 +02:00
# include "pdfcertificatemanagerdialog.h"
2022-05-14 17:38:28 +02:00
# include "signdialog.h"
2022-05-22 17:17:06 +02:00
# include "pdfdocumentwriter.h"
2022-02-11 19:15:57 +01:00
2023-12-21 14:25:41 +01:00
# include <QBuffer>
2022-02-11 19:15:57 +01:00
# include <QAction>
2022-03-20 19:26:54 +01:00
# include <QToolButton>
2022-02-26 19:46:13 +01:00
# include <QMainWindow>
2022-04-18 13:54:58 +02:00
# include <QMessageBox>
2022-05-28 19:42:52 +02:00
# include <QFileDialog>
2022-02-11 19:15:57 +01:00
namespace pdfplugin
{
SignaturePlugin : : SignaturePlugin ( ) :
pdf : : PDFPlugin ( nullptr ) ,
m_actions ( { } ) ,
m_tools ( { } ) ,
2022-02-26 19:46:13 +01:00
m_editorWidget ( nullptr ) ,
2022-04-02 16:29:31 +02:00
m_scene ( nullptr ) ,
m_sceneSelectionChangeEnabled ( true )
2022-02-11 19:15:57 +01:00
{
}
void SignaturePlugin : : setWidget ( pdf : : PDFWidget * widget )
{
Q_ASSERT ( ! m_widget ) ;
BaseClass : : setWidget ( widget ) ;
2022-02-26 19:46:13 +01:00
QAction * activateAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/activate.svg " ) , tr ( " Activate signature creator " ) , this ) ;
QAction * createTextAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-text.svg " ) , tr ( " Create Text Label " ) , this ) ;
QAction * createFreehandCurveAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-freehand-curve.svg " ) , tr ( " Create Freehand Curve " ) , this ) ;
QAction * createAcceptMarkAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-yes-mark.svg " ) , tr ( " Create Accept Mark " ) , this ) ;
QAction * createRejectMarkAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-no-mark.svg " ) , tr ( " Create Reject Mark " ) , this ) ;
QAction * createRectangleAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-rectangle.svg " ) , tr ( " Create Rectangle " ) , this ) ;
QAction * createRoundedRectangleAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-rounded-rectangle.svg " ) , tr ( " Create Rounded Rectangle " ) , this ) ;
QAction * createHorizontalLineAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-horizontal-line.svg " ) , tr ( " Create Horizontal Line " ) , this ) ;
QAction * createVerticalLineAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-vertical-line.svg " ) , tr ( " Create Vertical Line " ) , this ) ;
QAction * createLineAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-line.svg " ) , tr ( " Create Line " ) , this ) ;
QAction * createDotAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-dot.svg " ) , tr ( " Create Dot " ) , this ) ;
QAction * createSvgImageAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/create-svg-image.svg " ) , tr ( " Create SVG Image " ) , this ) ;
QAction * clearAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/clear.svg " ) , tr ( " Clear All Graphics " ) , this ) ;
QAction * signElectronicallyAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/sign-electronically.svg " ) , tr ( " Sign Electronically " ) , this ) ;
QAction * signDigitallyAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/sign-digitally.svg " ) , tr ( " Sign Digitally With Certificate " ) , this ) ;
QAction * certificatesAction = new QAction ( QIcon ( " :/pdfplugins/signatureplugin/certificates.svg " ) , tr ( " Certificates Manager " ) , this ) ;
2022-02-11 19:15:57 +01:00
2022-02-24 20:25:18 +01:00
activateAction - > setObjectName ( " signaturetool_activateAction " ) ;
2022-02-11 19:15:57 +01:00
createTextAction - > setObjectName ( " signaturetool_createTextAction " ) ;
2022-02-24 20:25:18 +01:00
createFreehandCurveAction - > setObjectName ( " signaturetool_createFreehandCurveAction " ) ;
2022-02-11 19:15:57 +01:00
createAcceptMarkAction - > setObjectName ( " signaturetool_createAcceptMarkAction " ) ;
createRejectMarkAction - > setObjectName ( " signaturetool_createRejectMarkAction " ) ;
createRectangleAction - > setObjectName ( " signaturetool_createRectangleAction " ) ;
createRoundedRectangleAction - > setObjectName ( " signaturetool_createRoundedRectangleAction " ) ;
createHorizontalLineAction - > setObjectName ( " signaturetool_createHorizontalLineAction " ) ;
createVerticalLineAction - > setObjectName ( " signaturetool_createVerticalLineAction " ) ;
createLineAction - > setObjectName ( " signaturetool_createLineAction " ) ;
createDotAction - > setObjectName ( " signaturetool_createDotAction " ) ;
createSvgImageAction - > setObjectName ( " signaturetool_createSvgImageAction " ) ;
clearAction - > setObjectName ( " signaturetool_clearAction " ) ;
signElectronicallyAction - > setObjectName ( " signaturetool_signElectronicallyAction " ) ;
signDigitallyAction - > setObjectName ( " signaturetool_signDigitallyAction " ) ;
certificatesAction - > setObjectName ( " signaturetool_certificatesAction " ) ;
2022-02-24 20:25:18 +01:00
activateAction - > setCheckable ( true ) ;
2022-02-11 19:15:57 +01:00
createTextAction - > setCheckable ( true ) ;
2022-02-24 20:25:18 +01:00
createFreehandCurveAction - > setCheckable ( true ) ;
2022-02-11 19:15:57 +01:00
createAcceptMarkAction - > setCheckable ( true ) ;
createRejectMarkAction - > setCheckable ( true ) ;
createRectangleAction - > setCheckable ( true ) ;
createRoundedRectangleAction - > setCheckable ( true ) ;
createHorizontalLineAction - > setCheckable ( true ) ;
createVerticalLineAction - > setCheckable ( true ) ;
createLineAction - > setCheckable ( true ) ;
createDotAction - > setCheckable ( true ) ;
createSvgImageAction - > setCheckable ( true ) ;
2022-02-24 20:25:18 +01:00
m_actions [ Activate ] = activateAction ;
2022-02-11 19:15:57 +01:00
m_actions [ Text ] = createTextAction ;
2022-02-24 20:25:18 +01:00
m_actions [ FreehandCurve ] = createFreehandCurveAction ;
2022-02-11 19:15:57 +01:00
m_actions [ AcceptMark ] = createAcceptMarkAction ;
m_actions [ RejectMark ] = createRejectMarkAction ;
m_actions [ Rectangle ] = createRectangleAction ;
m_actions [ RoundedRectangle ] = createRoundedRectangleAction ;
m_actions [ HorizontalLine ] = createHorizontalLineAction ;
m_actions [ VerticalLine ] = createVerticalLineAction ;
m_actions [ Line ] = createLineAction ;
m_actions [ Dot ] = createDotAction ;
m_actions [ SvgImage ] = createSvgImageAction ;
m_actions [ Clear ] = clearAction ;
m_actions [ SignElectronically ] = signElectronicallyAction ;
m_actions [ SignDigitally ] = signDigitallyAction ;
2022-02-24 20:25:18 +01:00
m_actions [ Certificates ] = certificatesAction ;
2022-02-11 19:15:57 +01:00
2022-02-19 19:30:52 +01:00
QFile acceptMarkFile ( " :/pdfplugins/signatureplugin/accept-mark.svg " ) ;
QByteArray acceptMarkContent ;
if ( acceptMarkFile . open ( QFile : : ReadOnly ) )
{
acceptMarkContent = acceptMarkFile . readAll ( ) ;
acceptMarkFile . close ( ) ;
}
QFile rejectMarkFile ( " :/pdfplugins/signatureplugin/reject-mark.svg " ) ;
QByteArray rejectMarkContent ;
if ( rejectMarkFile . open ( QFile : : ReadOnly ) )
{
rejectMarkContent = rejectMarkFile . readAll ( ) ;
rejectMarkFile . close ( ) ;
}
2022-03-26 19:26:32 +01:00
m_tools [ TextTool ] = new pdf : : PDFCreatePCElementTextTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createTextAction , this ) ;
2022-02-27 19:59:53 +01:00
m_tools [ FreehandCurveTool ] = new pdf : : PDFCreatePCElementFreehandCurveTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createFreehandCurveAction , this ) ;
2022-04-15 17:59:24 +02:00
m_tools [ AcceptMarkTool ] = new pdf : : PDFCreatePCElementImageTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createAcceptMarkAction , acceptMarkContent , false , this ) ;
m_tools [ RejectMarkTool ] = new pdf : : PDFCreatePCElementImageTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createRejectMarkAction , rejectMarkContent , false , this ) ;
2022-02-11 19:15:57 +01:00
m_tools [ RectangleTool ] = new pdf : : PDFCreatePCElementRectangleTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createRectangleAction , false , this ) ;
m_tools [ RoundedRectangleTool ] = new pdf : : PDFCreatePCElementRectangleTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createRoundedRectangleAction , true , this ) ;
2022-02-13 19:46:09 +01:00
m_tools [ HorizontalLineTool ] = new pdf : : PDFCreatePCElementLineTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createHorizontalLineAction , true , false , this ) ;
m_tools [ VerticalLineTool ] = new pdf : : PDFCreatePCElementLineTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createVerticalLineAction , false , true , this ) ;
m_tools [ LineTool ] = new pdf : : PDFCreatePCElementLineTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createLineAction , false , false , this ) ;
2022-02-27 17:08:24 +01:00
m_tools [ DotTool ] = new pdf : : PDFCreatePCElementDotTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createDotAction , this ) ;
2022-04-15 17:59:24 +02:00
m_tools [ ImageTool ] = new pdf : : PDFCreatePCElementImageTool ( widget - > getDrawWidgetProxy ( ) , & m_scene , createSvgImageAction , QByteArray ( ) , true , this ) ;
2022-02-11 19:15:57 +01:00
pdf : : PDFToolManager * toolManager = widget - > getToolManager ( ) ;
for ( pdf : : PDFWidgetTool * tool : m_tools )
{
toolManager - > addTool ( tool ) ;
2022-04-10 19:30:12 +02:00
connect ( tool , & pdf : : PDFWidgetTool : : toolActivityChanged , this , & SignaturePlugin : : onToolActivityChanged ) ;
2022-02-11 19:15:57 +01:00
}
2022-03-05 19:24:35 +01:00
m_widget - > addInputInterface ( & m_scene ) ;
2022-02-11 19:15:57 +01:00
m_widget - > getDrawWidgetProxy ( ) - > registerDrawInterface ( & m_scene ) ;
2022-03-05 19:24:35 +01:00
m_scene . setWidget ( m_widget ) ;
2022-02-24 20:25:18 +01:00
connect ( & m_scene , & pdf : : PDFPageContentScene : : sceneChanged , this , & SignaturePlugin : : onSceneChanged ) ;
2022-04-02 16:29:31 +02:00
connect ( & m_scene , & pdf : : PDFPageContentScene : : selectionChanged , this , & SignaturePlugin : : onSceneSelectionChanged ) ;
2022-04-17 18:11:07 +02:00
connect ( & m_scene , & pdf : : PDFPageContentScene : : editElementRequest , this , & SignaturePlugin : : onSceneEditElement ) ;
2022-02-24 20:25:18 +01:00
connect ( clearAction , & QAction : : triggered , & m_scene , & pdf : : PDFPageContentScene : : clear ) ;
connect ( activateAction , & QAction : : triggered , this , & SignaturePlugin : : setActive ) ;
2022-04-18 13:54:58 +02:00
connect ( signElectronicallyAction , & QAction : : triggered , this , & SignaturePlugin : : onSignElectronically ) ;
2022-05-14 17:38:28 +02:00
connect ( signDigitallyAction , & QAction : : triggered , this , & SignaturePlugin : : onSignDigitally ) ;
2022-04-30 18:12:14 +02:00
connect ( certificatesAction , & QAction : : triggered , this , & SignaturePlugin : : onOpenCertificatesManager ) ;
2022-02-11 19:15:57 +01:00
updateActions ( ) ;
}
void SignaturePlugin : : setDocument ( const pdf : : PDFModifiedDocument & document )
{
BaseClass : : setDocument ( document ) ;
if ( document . hasReset ( ) )
{
2022-02-24 20:25:18 +01:00
setActive ( false ) ;
2022-02-11 19:15:57 +01:00
updateActions ( ) ;
}
}
std : : vector < QAction * > SignaturePlugin : : getActions ( ) const
{
std : : vector < QAction * > result ;
2022-02-24 20:25:18 +01:00
result . push_back ( m_actions [ Activate ] ) ;
2022-02-11 19:15:57 +01:00
result . push_back ( m_actions [ SignElectronically ] ) ;
result . push_back ( m_actions [ SignDigitally ] ) ;
2022-02-24 20:25:18 +01:00
result . push_back ( m_actions [ Certificates ] ) ;
2022-02-11 19:15:57 +01:00
return result ;
}
2022-03-06 19:00:46 +01:00
void SignaturePlugin : : onSceneChanged ( bool graphicsOnly )
2022-02-24 20:25:18 +01:00
{
2022-03-06 19:00:46 +01:00
if ( ! graphicsOnly )
{
updateActions ( ) ;
}
2022-04-02 16:29:31 +02:00
if ( m_editorWidget )
{
m_editorWidget - > updateItemsInListWidget ( ) ;
}
2022-02-24 20:25:18 +01:00
updateGraphics ( ) ;
}
2022-04-02 16:29:31 +02:00
void SignaturePlugin : : onSceneSelectionChanged ( )
{
if ( m_editorWidget & & m_sceneSelectionChangeEnabled )
{
m_editorWidget - > setSelection ( m_scene . getSelectedElementIds ( ) ) ;
}
}
void SignaturePlugin : : onWidgetSelectionChanged ( )
{
Q_ASSERT ( m_editorWidget ) ;
pdf : : PDFTemporaryValueChange guard ( & m_sceneSelectionChangeEnabled , false ) ;
m_scene . setSelectedElementIds ( m_editorWidget - > getSelection ( ) ) ;
}
2022-04-10 19:30:12 +02:00
pdf : : PDFWidgetTool * SignaturePlugin : : getActiveTool ( )
{
for ( pdf : : PDFWidgetTool * currentTool : m_tools )
{
if ( currentTool - > isActive ( ) )
{
return currentTool ;
}
}
return nullptr ;
}
void SignaturePlugin : : onToolActivityChanged ( )
{
if ( m_editorWidget )
{
pdf : : PDFWidgetTool * activeTool = getActiveTool ( ) ;
const pdf : : PDFPageContentElement * element = nullptr ;
pdf : : PDFCreatePCElementTool * tool = qobject_cast < pdf : : PDFCreatePCElementTool * > ( activeTool ) ;
if ( tool )
{
element = tool - > getElement ( ) ;
}
m_editorWidget - > loadStyleFromElement ( element ) ;
}
}
2022-04-17 18:11:07 +02:00
void SignaturePlugin : : onSceneEditElement ( const std : : set < pdf : : PDFInteger > & elements )
{
if ( elements . empty ( ) )
{
return ;
}
pdf : : PDFPageContentElement * element = nullptr ;
for ( pdf : : PDFInteger id : elements )
{
element = m_scene . getElementById ( id ) ;
if ( element )
{
break ;
}
}
if ( ! element )
{
return ;
}
if ( pdf : : PDFPageContentEditorStyleSettings : : showEditElementStyleDialog ( m_dataExchangeInterface - > getMainWindow ( ) , element ) )
{
updateGraphics ( ) ;
}
}
2022-04-18 13:54:58 +02:00
void SignaturePlugin : : onSignElectronically ( )
{
Q_ASSERT ( m_document ) ;
Q_ASSERT ( ! m_scene . isEmpty ( ) ) ;
if ( QMessageBox : : question ( m_dataExchangeInterface - > getMainWindow ( ) , tr ( " Confirm Signature " ) , tr ( " Document will be signed electronically. Do you want to continue? " ) , QMessageBox : : Yes , QMessageBox : : No ) = = QMessageBox : : Yes )
{
pdf : : PDFDocumentModifier modifier ( m_document ) ;
std : : set < pdf : : PDFInteger > pageIndices = m_scene . getPageIndices ( ) ;
for ( pdf : : PDFInteger pageIndex : pageIndices )
{
const pdf : : PDFPage * page = m_document - > getCatalog ( ) - > getPage ( pageIndex ) ;
pdf : : PDFPageContentStreamBuilder pageContentStreamBuilder ( modifier . getBuilder ( ) ,
pdf : : PDFContentStreamBuilder : : CoordinateSystem : : PDF ,
pdf : : PDFPageContentStreamBuilder : : Mode : : PlaceAfter ) ;
QPainter * painter = pageContentStreamBuilder . begin ( page - > getPageReference ( ) ) ;
QList < pdf : : PDFRenderError > errors ;
pdf : : PDFTextLayoutGetter nullGetter ( nullptr , pageIndex ) ;
2022-08-20 17:43:33 +02:00
m_scene . drawElements ( painter , pageIndex , nullGetter , QTransform ( ) , nullptr , errors ) ;
2022-04-18 13:54:58 +02:00
pageContentStreamBuilder . end ( painter ) ;
2022-04-23 20:16:22 +02:00
modifier . markPageContentsChanged ( ) ;
2022-04-18 13:54:58 +02:00
}
2022-04-23 20:16:22 +02:00
m_scene . clear ( ) ;
2022-04-18 13:54:58 +02:00
if ( modifier . finalize ( ) )
{
2022-09-18 13:08:21 +02:00
Q_EMIT m_widget - > getToolManager ( ) - > documentModified ( pdf : : PDFModifiedDocument ( modifier . getDocument ( ) , nullptr , modifier . getFlags ( ) ) ) ;
2022-04-18 13:54:58 +02:00
}
}
}
2022-05-14 17:38:28 +02:00
void SignaturePlugin : : onSignDigitally ( )
{
// Jakub Melka: do we have certificates? If not,
// open certificate dialog, so the user can create
// a new one.
2023-12-22 19:12:35 +01:00
if ( pdf : : PDFCertificateManager : : getCertificates ( ) . empty ( ) )
2022-05-14 17:38:28 +02:00
{
onOpenCertificatesManager ( ) ;
2023-12-22 19:12:35 +01:00
if ( pdf : : PDFCertificateManager : : getCertificates ( ) . empty ( ) )
2022-05-14 17:38:28 +02:00
{
return ;
}
}
SignDialog dialog ( m_dataExchangeInterface - > getMainWindow ( ) , m_scene . isEmpty ( ) ) ;
if ( dialog . exec ( ) = = SignDialog : : Accepted )
{
2023-12-22 19:12:35 +01:00
const pdf : : PDFCertificateEntry * certificate = dialog . getCertificate ( ) ;
Q_ASSERT ( certificate ) ;
2022-05-22 17:17:06 +02:00
QByteArray data = " SampleDataToBeSigned " + QByteArray : : number ( QDateTime : : currentMSecsSinceEpoch ( ) ) ;
QByteArray signature ;
2023-12-22 19:12:35 +01:00
if ( ! pdf : : PDFSignatureFactory : : sign ( * certificate , dialog . getPassword ( ) , data , signature ) )
2022-05-22 17:17:06 +02:00
{
QMessageBox : : critical ( m_widget , tr ( " Error " ) , tr ( " Failed to create digital signature. " ) ) ;
return ;
}
2022-05-28 19:42:52 +02:00
QString signatureName = QString ( " pdf4qt_signature_%1 " ) . arg ( QString : : number ( QDateTime : : currentMSecsSinceEpoch ( ) ) ) ;
2022-05-22 17:17:06 +02:00
pdf : : PDFInteger offsetMark = 123456789123 ;
constexpr const char * offsetMarkString = " 123456789123 " ;
const auto offsetMarkStringLength = std : : strlen ( offsetMarkString ) ;
2022-05-14 17:38:28 +02:00
2022-05-22 17:17:06 +02:00
pdf : : PDFDocumentBuilder builder ( m_document ) ;
pdf : : PDFObjectReference signatureDictionary = builder . createSignatureDictionary ( " Adobe.PPKLite " , " adbe.pkcs7.detached " , signature , QDateTime : : currentDateTime ( ) , offsetMark ) ;
2022-05-28 19:42:52 +02:00
pdf : : PDFObjectReference formField = builder . createFormFieldSignature ( signatureName , { } , signatureDictionary ) ;
2022-05-22 17:17:06 +02:00
builder . createAcroForm ( { formField } ) ;
2022-05-29 17:27:58 +02:00
const pdf : : PDFCatalog * catalog = m_document - > getCatalog ( ) ;
2022-05-28 19:42:52 +02:00
if ( dialog . getSignMethod ( ) = = SignDialog : : SignDigitallyInvisible )
{
if ( catalog - > getPageCount ( ) > 0 )
{
const pdf : : PDFObjectReference pageReference = catalog - > getPage ( 0 ) - > getPageReference ( ) ;
builder . createInvisibleFormFieldWidget ( formField , pageReference ) ;
}
}
2022-05-29 17:27:58 +02:00
else if ( dialog . getSignMethod ( ) = = SignDialog : : SignDigitally )
{
Q_ASSERT ( ! m_scene . isEmpty ( ) ) ;
const pdf : : PDFInteger pageIndex = * m_scene . getPageIndices ( ) . begin ( ) ;
const pdf : : PDFPage * page = catalog - > getPage ( pageIndex ) ;
pdf : : PDFContentStreamBuilder contentBuilder ( page - > getMediaBox ( ) . size ( ) , pdf : : PDFContentStreamBuilder : : CoordinateSystem : : PDF ) ;
QPainter * painter = contentBuilder . begin ( ) ;
QList < pdf : : PDFRenderError > errors ;
pdf : : PDFTextLayoutGetter nullGetter ( nullptr , pageIndex ) ;
2022-08-20 17:43:33 +02:00
m_scene . drawPage ( painter , pageIndex , nullptr , nullGetter , QTransform ( ) , errors ) ;
2022-05-29 17:27:58 +02:00
pdf : : PDFContentStreamBuilder : : ContentStream contentStream = contentBuilder . end ( painter ) ;
QRectF boundingRect = m_scene . getBoundingBox ( pageIndex ) ;
std : : vector < pdf : : PDFObject > copiedObjects = builder . copyFrom ( { contentStream . resources , contentStream . contents } , contentStream . document . getStorage ( ) , true ) ;
Q_ASSERT ( copiedObjects . size ( ) = = 2 ) ;
pdf : : PDFObjectReference resourcesReference = copiedObjects [ 0 ] . getReference ( ) ;
pdf : : PDFObjectReference formReference = copiedObjects [ 1 ] . getReference ( ) ;
// Create form object
pdf : : PDFObjectFactory formFactory ;
formFactory . beginDictionary ( ) ;
formFactory . beginDictionaryItem ( " Type " ) ;
formFactory < < pdf : : WrapName ( " XObject " ) ;
formFactory . endDictionaryItem ( ) ;
formFactory . beginDictionaryItem ( " Subtype " ) ;
formFactory < < pdf : : WrapName ( " Form " ) ;
formFactory . endDictionaryItem ( ) ;
formFactory . beginDictionaryItem ( " BBox " ) ;
formFactory < < boundingRect ;
formFactory . endDictionaryItem ( ) ;
formFactory . beginDictionaryItem ( " Resources " ) ;
formFactory < < resourcesReference ;
formFactory . endDictionaryItem ( ) ;
formFactory . endDictionary ( ) ;
builder . mergeTo ( formReference , formFactory . takeObject ( ) ) ;
builder . createFormFieldWidget ( formField , page - > getPageReference ( ) , formReference , boundingRect ) ;
}
2022-05-28 19:42:52 +02:00
QString reasonText = dialog . getReasonText ( ) ;
if ( ! reasonText . isEmpty ( ) )
{
builder . setSignatureReason ( signatureDictionary , reasonText ) ;
}
QString contactInfoText = dialog . getContactInfoText ( ) ;
if ( ! contactInfoText . isEmpty ( ) )
{
builder . setSignatureContactInfo ( signatureDictionary , contactInfoText ) ;
}
2022-05-22 17:17:06 +02:00
pdf : : PDFDocument signedDocument = builder . build ( ) ;
// 1) Save the document with incorrect signature
QBuffer buffer ;
pdf : : PDFDocumentWriter writer ( m_widget - > getDrawWidgetProxy ( ) - > getProgress ( ) ) ;
buffer . open ( QBuffer : : ReadWrite ) ;
writer . write ( & buffer , & signedDocument ) ;
const int indexOfSignature = buffer . data ( ) . indexOf ( signature . toHex ( ) ) ;
if ( indexOfSignature = = - 1 )
2022-05-20 19:57:35 +02:00
{
2022-05-22 17:17:06 +02:00
QMessageBox : : critical ( m_widget , tr ( " Error " ) , tr ( " Failed to create digital signature. " ) ) ;
buffer . close ( ) ;
return ;
2022-05-20 19:57:35 +02:00
}
2022-05-22 17:17:06 +02:00
// 2) Write ranges to be checked
const pdf : : PDFInteger i1 = 0 ;
2022-05-28 19:42:52 +02:00
const pdf : : PDFInteger i2 = indexOfSignature - 1 ;
const pdf : : PDFInteger i3 = i2 + signature . size ( ) * 2 + 2 ;
2022-05-22 17:17:06 +02:00
const pdf : : PDFInteger i4 = buffer . data ( ) . size ( ) - i3 ;
auto writeInt = [ & ] ( pdf : : PDFInteger offset )
{
QString offsetString = QString : : number ( offset ) ;
offsetString = offsetString . leftJustified ( static_cast < int > ( offsetMarkStringLength ) , ' ' , true ) ;
2022-08-21 18:03:06 +02:00
const auto index = buffer . data ( ) . lastIndexOf ( QByteArray ( offsetMarkString , offsetMarkStringLength ) , indexOfSignature ) ;
2022-05-22 17:17:06 +02:00
buffer . seek ( index ) ;
buffer . write ( offsetString . toLocal8Bit ( ) ) ;
} ;
writeInt ( i4 ) ;
writeInt ( i3 ) ;
writeInt ( i2 ) ;
writeInt ( i1 ) ;
// 3) Sign the data
QByteArray dataToBeSigned ;
buffer . seek ( i1 ) ;
dataToBeSigned . append ( buffer . read ( i2 ) ) ;
buffer . seek ( i3 ) ;
dataToBeSigned . append ( buffer . read ( i4 ) ) ;
2023-12-22 19:12:35 +01:00
if ( ! pdf : : PDFSignatureFactory : : sign ( * certificate , dialog . getPassword ( ) , dataToBeSigned , signature ) )
2022-05-22 17:17:06 +02:00
{
QMessageBox : : critical ( m_widget , tr ( " Error " ) , tr ( " Failed to create digital signature. " ) ) ;
buffer . close ( ) ;
return ;
}
2022-05-28 19:42:52 +02:00
buffer . seek ( i2 + 1 ) ;
2022-05-22 17:17:06 +02:00
buffer . write ( signature . toHex ( ) ) ;
buffer . close ( ) ;
2022-05-28 19:42:52 +02:00
QString fileName = QFileDialog : : getSaveFileName ( m_dataExchangeInterface - > getMainWindow ( ) , tr ( " Save Signed Document " ) , getSignedFileName ( ) , tr ( " Portable Document (*.pdf);;All files (*.*) " ) ) ;
if ( ! fileName . isEmpty ( ) )
{
QFile signedFile ( fileName ) ;
if ( signedFile . open ( QFile : : WriteOnly | QFile : : Truncate ) )
{
signedFile . write ( buffer . data ( ) ) ;
signedFile . close ( ) ;
}
}
2022-05-14 17:38:28 +02:00
}
}
2022-05-28 19:42:52 +02:00
QString SignaturePlugin : : getSignedFileName ( ) const
{
QFileInfo fileInfo ( m_dataExchangeInterface - > getOriginalFileName ( ) ) ;
return fileInfo . path ( ) + " / " + fileInfo . baseName ( ) + " _SIGNED.pdf " ;
}
2022-04-30 18:12:14 +02:00
void SignaturePlugin : : onOpenCertificatesManager ( )
{
2022-06-12 15:45:32 +02:00
pdf : : PDFCertificateManagerDialog dialog ( m_dataExchangeInterface - > getMainWindow ( ) ) ;
2022-04-30 18:12:14 +02:00
dialog . exec ( ) ;
}
2022-04-10 19:30:12 +02:00
void SignaturePlugin : : onPenChanged ( const QPen & pen )
{
if ( pdf : : PDFCreatePCElementTool * activeTool = qobject_cast < pdf : : PDFCreatePCElementTool * > ( getActiveTool ( ) ) )
{
activeTool - > setPen ( pen ) ;
}
}
void SignaturePlugin : : onBrushChanged ( const QBrush & brush )
{
if ( pdf : : PDFCreatePCElementTool * activeTool = qobject_cast < pdf : : PDFCreatePCElementTool * > ( getActiveTool ( ) ) )
{
activeTool - > setBrush ( brush ) ;
}
}
void SignaturePlugin : : onFontChanged ( const QFont & font )
{
if ( pdf : : PDFCreatePCElementTool * activeTool = qobject_cast < pdf : : PDFCreatePCElementTool * > ( getActiveTool ( ) ) )
{
activeTool - > setFont ( font ) ;
}
}
void SignaturePlugin : : onAlignmentChanged ( Qt : : Alignment alignment )
{
if ( pdf : : PDFCreatePCElementTool * activeTool = qobject_cast < pdf : : PDFCreatePCElementTool * > ( getActiveTool ( ) ) )
{
activeTool - > setAlignment ( alignment ) ;
}
}
void SignaturePlugin : : onTextAngleChanged ( pdf : : PDFReal angle )
{
if ( pdf : : PDFCreatePCElementTool * activeTool = qobject_cast < pdf : : PDFCreatePCElementTool * > ( getActiveTool ( ) ) )
{
activeTool - > setTextAngle ( angle ) ;
}
}
2022-02-24 20:25:18 +01:00
void SignaturePlugin : : setActive ( bool active )
{
if ( m_scene . isActive ( ) ! = active )
{
// Abort active tool, if we are deactivating the plugin
if ( ! active )
{
if ( pdf : : PDFWidgetTool * tool = m_widget - > getToolManager ( ) - > getActiveTool ( ) )
{
auto it = std : : find ( m_tools . cbegin ( ) , m_tools . cend ( ) , tool ) ;
2022-04-15 17:59:24 +02:00
if ( it ! = m_tools . cend ( ) )
2022-02-24 20:25:18 +01:00
{
m_widget - > getToolManager ( ) - > setActiveTool ( nullptr ) ;
}
}
}
m_scene . setActive ( active ) ;
if ( ! active )
{
m_scene . clear ( ) ;
}
2022-02-26 19:46:13 +01:00
else
{
updateDockWidget ( ) ;
}
2022-02-24 20:25:18 +01:00
m_actions [ Activate ] - > setChecked ( active ) ;
updateActions ( ) ;
}
}
2022-02-11 19:15:57 +01:00
void SignaturePlugin : : updateActions ( )
{
2022-02-24 20:25:18 +01:00
m_actions [ Activate ] - > setEnabled ( m_document ) ;
if ( ! m_scene . isActive ( ) | | ! m_document )
{
// Inactive scene - disable all except activate action and certificates
for ( QAction * action : m_actions )
{
if ( action = = m_actions [ Activate ] | |
action = = m_actions [ Certificates ] )
{
continue ;
}
action - > setEnabled ( false ) ;
}
return ;
}
const bool isSceneNonempty = ! m_scene . isEmpty ( ) ;
// Tool actions
for ( auto actionId : { Text , FreehandCurve , AcceptMark , RejectMark ,
Rectangle , RoundedRectangle , HorizontalLine ,
VerticalLine , Line , Dot , SvgImage } )
{
m_actions [ actionId ] - > setEnabled ( true ) ;
}
// Clear action
2022-02-13 19:46:09 +01:00
QAction * clearAction = m_actions [ Clear ] ;
2022-02-24 20:25:18 +01:00
clearAction - > setEnabled ( isSceneNonempty ) ;
// Sign actions
QAction * signElectronicallyAction = m_actions [ SignElectronically ] ;
signElectronicallyAction - > setEnabled ( isSceneNonempty ) ;
QAction * signDigitallyAction = m_actions [ SignDigitally ] ;
2022-05-14 17:38:28 +02:00
signDigitallyAction - > setEnabled ( m_document ) ;
2022-02-11 19:15:57 +01:00
}
void SignaturePlugin : : updateGraphics ( )
{
if ( m_widget )
{
m_widget - > getDrawWidget ( ) - > getWidget ( ) - > update ( ) ;
}
}
2022-02-26 19:46:13 +01:00
void SignaturePlugin : : updateDockWidget ( )
{
if ( m_editorWidget )
{
return ;
}
m_editorWidget = new pdf : : PDFPageContentEditorWidget ( m_dataExchangeInterface - > getMainWindow ( ) ) ;
m_editorWidget - > setAllowedAreas ( Qt : : LeftDockWidgetArea | Qt : : RightDockWidgetArea ) ;
m_dataExchangeInterface - > getMainWindow ( ) - > addDockWidget ( Qt : : RightDockWidgetArea , m_editorWidget , Qt : : Vertical ) ;
m_editorWidget - > setFloating ( false ) ;
2022-02-27 17:08:24 +01:00
m_editorWidget - > setWindowTitle ( tr ( " Signature Toolbox " ) ) ;
2022-04-02 16:29:31 +02:00
m_editorWidget - > setScene ( & m_scene ) ;
2022-03-13 19:37:36 +01:00
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : operationTriggered , & m_scene , & pdf : : PDFPageContentScene : : performOperation ) ;
2022-04-02 16:29:31 +02:00
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : itemSelectionChangedByUser , this , & SignaturePlugin : : onWidgetSelectionChanged ) ;
2022-02-26 19:46:13 +01:00
2022-03-20 19:26:54 +01:00
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : AlignTop ) ) - > setIcon ( QIcon ( " :/resources/pce-align-top.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : AlignCenterVertically ) ) - > setIcon ( QIcon ( " :/resources/pce-align-v-center.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : AlignBottom ) ) - > setIcon ( QIcon ( " :/resources/pce-align-bottom.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : AlignLeft ) ) - > setIcon ( QIcon ( " :/resources/pce-align-left.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : AlignCenterHorizontally ) ) - > setIcon ( QIcon ( " :/resources/pce-align-h-center.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : AlignRight ) ) - > setIcon ( QIcon ( " :/resources/pce-align-right.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : SetSameHeight ) ) - > setIcon ( QIcon ( " :/resources/pce-same-height.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : SetSameWidth ) ) - > setIcon ( QIcon ( " :/resources/pce-same-width.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : SetSameSize ) ) - > setIcon ( QIcon ( " :/resources/pce-same-size.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : CenterHorizontally ) ) - > setIcon ( QIcon ( " :/resources/pce-center-h.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : CenterVertically ) ) - > setIcon ( QIcon ( " :/resources/pce-center-v.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : CenterHorAndVert ) ) - > setIcon ( QIcon ( " :/resources/pce-center-vh.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : LayoutVertically ) ) - > setIcon ( QIcon ( " :/resources/pce-layout-v.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : LayoutHorizontally ) ) - > setIcon ( QIcon ( " :/resources/pce-layout-h.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : LayoutForm ) ) - > setIcon ( QIcon ( " :/resources/pce-layout-form.svg " ) ) ;
m_editorWidget - > getToolButtonForOperation ( static_cast < int > ( pdf : : PDFPageContentElementManipulator : : Operation : : LayoutGrid ) ) - > setIcon ( QIcon ( " :/resources/pce-layout-grid.svg " ) ) ;
2022-02-26 19:46:13 +01:00
for ( QAction * action : m_actions )
{
m_editorWidget - > addAction ( action ) ;
}
2022-04-10 19:30:12 +02:00
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : penChanged , this , & SignaturePlugin : : onPenChanged ) ;
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : brushChanged , this , & SignaturePlugin : : onBrushChanged ) ;
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : fontChanged , this , & SignaturePlugin : : onFontChanged ) ;
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : alignmentChanged , this , & SignaturePlugin : : onAlignmentChanged ) ;
connect ( m_editorWidget , & pdf : : PDFPageContentEditorWidget : : textAngleChanged , this , & SignaturePlugin : : onTextAngleChanged ) ;
2022-02-26 19:46:13 +01:00
}
2022-02-11 19:15:57 +01:00
}