1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <SignSignatureLineDialog.hxx>
12 #include <sal/log.hxx>
13 #include <sal/types.h>
15 #include <dialmgr.hxx>
16 #include <strings.hrc>
18 #include <comphelper/graphicmimetype.hxx>
19 #include <comphelper/processfactory.hxx>
20 #include <comphelper/xmlsechelper.hxx>
21 #include <osl/file.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <sfx2/docfilt.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <svx/xoutbmp.hxx>
26 #include <tools/date.hxx>
27 #include <tools/stream.hxx>
28 #include <unotools/localedatawrapper.hxx>
29 #include <unotools/streamwrap.hxx>
30 #include <unotools/syslocale.hxx>
32 #include <vcl/graph.hxx>
33 #include <vcl/weld.hxx>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/drawing/XShape.hpp>
37 #include <com/sun/star/graphic/GraphicProvider.hpp>
38 #include <com/sun/star/graphic/XGraphic.hpp>
39 #include <com/sun/star/graphic/XGraphicProvider.hpp>
40 #include <com/sun/star/io/XInputStream.hpp>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/security/CertificateKind.hpp>
43 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
44 #include <com/sun/star/security/XCertificate.hpp>
45 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
46 #include <com/sun/star/text/TextContentAnchorType.hpp>
47 #include <com/sun/star/text/XTextContent.hpp>
48 #include <com/sun/star/text/XTextDocument.hpp>
49 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
50 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
51 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
53 using namespace comphelper
;
55 using namespace css::uno
;
56 using namespace css::beans
;
57 using namespace css::frame
;
58 using namespace css::io
;
59 using namespace css::lang
;
60 using namespace css::frame
;
61 using namespace css::text
;
62 using namespace css::drawing
;
63 using namespace css::graphic
;
64 using namespace css::security
;
65 using namespace css::ui::dialogs
;
67 SignSignatureLineDialog::SignSignatureLineDialog(weld::Widget
* pParent
, Reference
<XModel
> xModel
)
68 : SignatureLineDialogBase(pParent
, std::move(xModel
), "cui/ui/signsignatureline.ui",
69 "SignSignatureLineDialog")
70 , m_xEditName(m_xBuilder
->weld_entry("edit_name"))
71 , m_xEditComment(m_xBuilder
->weld_text_view("edit_comment"))
72 , m_xBtnLoadImage(m_xBuilder
->weld_button("btn_load_image"))
73 , m_xBtnClearImage(m_xBuilder
->weld_button("btn_clear_image"))
74 , m_xBtnChooseCertificate(m_xBuilder
->weld_button("btn_select_certificate"))
75 , m_xBtnSign(m_xBuilder
->weld_button("ok"))
76 , m_xLabelHint(m_xBuilder
->weld_label("label_hint"))
77 , m_xLabelHintText(m_xBuilder
->weld_label("label_hint_text"))
78 , m_xLabelAddComment(m_xBuilder
->weld_label("label_add_comment"))
79 , m_bShowSignDate(false)
81 Reference
<container::XIndexAccess
> xIndexAccess(m_xModel
->getCurrentSelection(),
83 m_xShapeProperties
.set(xIndexAccess
->getByIndex(0), UNO_QUERY_THROW
);
85 bool bIsSignatureLine(false);
86 m_xShapeProperties
->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine
;
87 if (!bIsSignatureLine
)
89 SAL_WARN("cui.dialogs", "No signature line selected!");
93 m_xBtnLoadImage
->connect_clicked(LINK(this, SignSignatureLineDialog
, loadImage
));
94 m_xBtnClearImage
->connect_clicked(LINK(this, SignSignatureLineDialog
, clearImage
));
95 m_xBtnChooseCertificate
->connect_clicked(
96 LINK(this, SignSignatureLineDialog
, chooseCertificate
));
97 m_xEditName
->connect_changed(LINK(this, SignSignatureLineDialog
, entryChanged
));
99 // Read properties from selected signature line
100 m_xShapeProperties
->getPropertyValue("SignatureLineId") >>= m_aSignatureLineId
;
101 m_xShapeProperties
->getPropertyValue("SignatureLineSuggestedSignerName")
102 >>= m_aSuggestedSignerName
;
103 m_xShapeProperties
->getPropertyValue("SignatureLineSuggestedSignerTitle")
104 >>= m_aSuggestedSignerTitle
;
105 OUString aSigningInstructions
;
106 m_xShapeProperties
->getPropertyValue("SignatureLineSigningInstructions")
107 >>= aSigningInstructions
;
108 m_xShapeProperties
->getPropertyValue("SignatureLineShowSignDate") >>= m_bShowSignDate
;
109 bool bCanAddComment(false);
110 m_xShapeProperties
->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment
;
112 if (aSigningInstructions
.isEmpty())
114 m_xLabelHint
->hide();
115 m_xLabelHintText
->hide();
119 m_xLabelHintText
->set_label(aSigningInstructions
);
124 m_xEditComment
->set_size_request(m_xEditComment
->get_approximate_digit_width() * 48,
125 m_xEditComment
->get_text_height() * 5);
129 m_xLabelAddComment
->hide();
130 m_xEditComment
->hide();
131 m_xEditComment
->set_size_request(0, 0);
137 IMPL_LINK_NOARG(SignSignatureLineDialog
, loadImage
, weld::Button
&, void)
139 Reference
<XComponentContext
> xContext
= comphelper::getProcessComponentContext();
140 Reference
<XFilePicker3
> xFilePicker
141 = FilePicker::createWithMode(xContext
, TemplateDescription::FILEOPEN_PREVIEW
);
142 if (xFilePicker
->execute())
144 Sequence
<OUString
> aSelectedFiles
= xFilePicker
->getSelectedFiles();
145 if (aSelectedFiles
.getLength() < 1)
148 Reference
<XGraphicProvider
> xProvider
= GraphicProvider::create(xContext
);
149 Sequence
<PropertyValue
> aMediaProperties(1);
150 aMediaProperties
[0].Name
= "URL";
151 aMediaProperties
[0].Value
<<= aSelectedFiles
[0];
152 m_xSignatureImage
= xProvider
->queryGraphic(aMediaProperties
);
153 m_sOriginalImageBtnLabel
= m_xBtnLoadImage
->get_label();
155 INetURLObject
aObj(aSelectedFiles
[0]);
156 m_xBtnLoadImage
->set_label(aObj
.GetLastName());
162 IMPL_LINK_NOARG(SignSignatureLineDialog
, clearImage
, weld::Button
&, void)
164 m_xSignatureImage
.set(nullptr);
165 m_xBtnLoadImage
->set_label(m_sOriginalImageBtnLabel
);
169 IMPL_LINK_NOARG(SignSignatureLineDialog
, chooseCertificate
, weld::Button
&, void)
171 // Document needs to be saved before selecting a certificate
172 SfxObjectShell
* pShell
= SfxObjectShell::Current();
173 if (!pShell
->PrepareForSigning(m_xDialog
.get()))
176 Reference
<XDocumentDigitalSignatures
> xSigner(DocumentDigitalSignatures::createWithVersion(
177 comphelper::getProcessComponentContext(), "1.2"));
178 xSigner
->setParentWindow(m_xDialog
->GetXWindow());
179 OUString aDescription
;
180 CertificateKind certificateKind
= CertificateKind_NONE
;
181 // When signing ooxml, we only want X.509 certificates
182 if (pShell
->GetMedium()->GetFilter()->IsAlienFormat())
183 certificateKind
= CertificateKind_X509
;
184 Reference
<XCertificate
> xSignCertificate
185 = xSigner
->selectSigningCertificateWithType(certificateKind
, aDescription
);
187 if (xSignCertificate
.is())
189 m_xSelectedCertifate
= xSignCertificate
;
190 m_xBtnChooseCertificate
->set_label(
191 xmlsec::GetContentPart(xSignCertificate
->getSubjectName()));
196 IMPL_LINK_NOARG(SignSignatureLineDialog
, entryChanged
, weld::Entry
&, void) { ValidateFields(); }
198 void SignSignatureLineDialog::ValidateFields()
200 bool bEnableSignBtn
= m_xSelectedCertifate
.is()
201 && (!m_xEditName
->get_text().isEmpty() || m_xSignatureImage
.is());
202 m_xBtnSign
->set_sensitive(bEnableSignBtn
);
204 m_xEditName
->set_sensitive(!m_xSignatureImage
.is());
205 m_xBtnLoadImage
->set_sensitive(m_xEditName
->get_text().isEmpty());
206 m_xBtnClearImage
->set_sensitive(m_xSignatureImage
.is());
209 void SignSignatureLineDialog::Apply()
211 if (!m_xSelectedCertifate
.is())
213 SAL_WARN("cui.dialogs", "No certificate selected!");
217 SfxObjectShell
* pShell
= SfxObjectShell::Current();
218 Reference
<XGraphic
> xValidGraphic
= getSignedGraphic(true);
219 Reference
<XGraphic
> xInvalidGraphic
= getSignedGraphic(false);
220 pShell
->SignSignatureLine(m_xDialog
.get(), m_aSignatureLineId
, m_xSelectedCertifate
,
221 xValidGraphic
, xInvalidGraphic
, m_xEditComment
->get_text());
224 const css::uno::Reference
<css::graphic::XGraphic
>
225 SignSignatureLineDialog::getSignedGraphic(bool bValid
)
227 // Read svg and replace placeholder texts
228 OUString
aSvgImage(getSignatureImage());
229 aSvgImage
= aSvgImage
.replaceAll("[SIGNER_NAME]", getCDataString(m_aSuggestedSignerName
));
230 aSvgImage
= aSvgImage
.replaceAll("[SIGNER_TITLE]", getCDataString(m_aSuggestedSignerTitle
));
233 = CuiResId(RID_SVXSTR_SIGNATURELINE_SIGNED_BY
)
234 .replaceFirst("%1", xmlsec::GetContentPart(m_xSelectedCertifate
->getSubjectName()));
235 aSvgImage
= aSvgImage
.replaceAll("[SIGNED_BY]", getCDataString(aIssuerLine
));
237 aSvgImage
= aSvgImage
.replaceAll("[INVALID_SIGNATURE]", "");
240 if (m_bShowSignDate
&& bValid
)
242 const SvtSysLocale aSysLocale
;
243 const LocaleDataWrapper
& rLocaleData
= aSysLocale
.GetLocaleData();
244 Date
aDateTime(Date::SYSTEM
);
245 aDate
= rLocaleData
.getDate(aDateTime
);
247 aSvgImage
= aSvgImage
.replaceAll("[DATE]", aDate
);
249 // Custom signature image
250 if (m_xSignatureImage
.is())
252 OUString aGraphicInBase64
;
253 Graphic
aGraphic(m_xSignatureImage
);
254 if (!XOutBitmap::GraphicToBase64(aGraphic
, aGraphicInBase64
, false))
255 SAL_WARN("cui.dialogs", "Could not convert graphic to base64");
257 OUString aImagePart
= "<image y=\"825\" x=\"1300\" "
258 "xlink:href=\"data:[MIMETYPE];base64,[BASE64_IMG]>\" "
259 "preserveAspectRatio=\"xMidYMid\" height=\"1520\" "
261 aImagePart
= aImagePart
.replaceAll(
262 "[MIMETYPE]", GraphicMimeTypeHelper::GetMimeTypeForXGraphic(m_xSignatureImage
));
263 aImagePart
= aImagePart
.replaceAll("[BASE64_IMG]", aGraphicInBase64
);
264 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE_IMAGE]", aImagePart
);
266 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE]", "");
270 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE_IMAGE]", "");
271 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE]", getCDataString(m_xEditName
->get_text()));
275 SvMemoryStream
aSvgStream(4096, 4096);
276 aSvgStream
.WriteOString(OUStringToOString(aSvgImage
, RTL_TEXTENCODING_UTF8
));
277 Reference
<XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream
));
278 Reference
<XComponentContext
> xContext(comphelper::getProcessComponentContext());
279 Reference
<XGraphicProvider
> xProvider
= css::graphic::GraphicProvider::create(xContext
);
281 Sequence
<PropertyValue
> aMediaProperties(1);
282 aMediaProperties
[0].Name
= "InputStream";
283 aMediaProperties
[0].Value
<<= xInputStream
;
284 Reference
<XGraphic
> xGraphic
= xProvider
->queryGraphic(aMediaProperties
);
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */