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 <sfx2/docfile.hxx>
22 #include <sfx2/docfilt.hxx>
23 #include <sfx2/objsh.hxx>
24 #include <svx/xoutbmp.hxx>
25 #include <tools/date.hxx>
26 #include <tools/stream.hxx>
27 #include <unotools/localedatawrapper.hxx>
28 #include <unotools/streamwrap.hxx>
29 #include <unotools/syslocale.hxx>
31 #include <vcl/graph.hxx>
32 #include <vcl/weld.hxx>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/graphic/GraphicProvider.hpp>
36 #include <com/sun/star/graphic/XGraphic.hpp>
37 #include <com/sun/star/graphic/XGraphicProvider.hpp>
38 #include <com/sun/star/io/XInputStream.hpp>
39 #include <com/sun/star/security/CertificateKind.hpp>
40 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
41 #include <com/sun/star/security/XCertificate.hpp>
42 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
43 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
44 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
45 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
47 using namespace comphelper
;
49 using namespace css::uno
;
50 using namespace css::beans
;
51 using namespace css::frame
;
52 using namespace css::io
;
53 using namespace css::lang
;
54 using namespace css::frame
;
55 using namespace css::text
;
56 using namespace css::graphic
;
57 using namespace css::security
;
58 using namespace css::ui::dialogs
;
60 SignSignatureLineDialog::SignSignatureLineDialog(weld::Widget
* pParent
, Reference
<XModel
> xModel
)
61 : SignatureLineDialogBase(pParent
, std::move(xModel
), "cui/ui/signsignatureline.ui",
62 "SignSignatureLineDialog")
63 , m_xEditName(m_xBuilder
->weld_entry("edit_name"))
64 , m_xEditComment(m_xBuilder
->weld_text_view("edit_comment"))
65 , m_xBtnLoadImage(m_xBuilder
->weld_button("btn_load_image"))
66 , m_xBtnClearImage(m_xBuilder
->weld_button("btn_clear_image"))
67 , m_xBtnChooseCertificate(m_xBuilder
->weld_button("btn_select_certificate"))
68 , m_xBtnSign(m_xBuilder
->weld_button("ok"))
69 , m_xLabelHint(m_xBuilder
->weld_label("label_hint"))
70 , m_xLabelHintText(m_xBuilder
->weld_label("label_hint_text"))
71 , m_xLabelAddComment(m_xBuilder
->weld_label("label_add_comment"))
72 , m_bShowSignDate(false)
74 Reference
<container::XIndexAccess
> xIndexAccess(m_xModel
->getCurrentSelection(),
76 m_xShapeProperties
.set(xIndexAccess
->getByIndex(0), UNO_QUERY_THROW
);
78 bool bIsSignatureLine(false);
79 m_xShapeProperties
->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine
;
80 if (!bIsSignatureLine
)
82 SAL_WARN("cui.dialogs", "No signature line selected!");
86 m_xBtnLoadImage
->connect_clicked(LINK(this, SignSignatureLineDialog
, loadImage
));
87 m_xBtnClearImage
->connect_clicked(LINK(this, SignSignatureLineDialog
, clearImage
));
88 m_xBtnChooseCertificate
->connect_clicked(
89 LINK(this, SignSignatureLineDialog
, chooseCertificate
));
90 m_xEditName
->connect_changed(LINK(this, SignSignatureLineDialog
, entryChanged
));
92 // Read properties from selected signature line
93 m_xShapeProperties
->getPropertyValue("SignatureLineId") >>= m_aSignatureLineId
;
94 m_xShapeProperties
->getPropertyValue("SignatureLineSuggestedSignerName")
95 >>= m_aSuggestedSignerName
;
96 m_xShapeProperties
->getPropertyValue("SignatureLineSuggestedSignerTitle")
97 >>= m_aSuggestedSignerTitle
;
98 OUString aSigningInstructions
;
99 m_xShapeProperties
->getPropertyValue("SignatureLineSigningInstructions")
100 >>= aSigningInstructions
;
101 m_xShapeProperties
->getPropertyValue("SignatureLineShowSignDate") >>= m_bShowSignDate
;
102 bool bCanAddComment(false);
103 m_xShapeProperties
->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment
;
105 if (aSigningInstructions
.isEmpty())
107 m_xLabelHint
->hide();
108 m_xLabelHintText
->hide();
112 m_xLabelHintText
->set_label(aSigningInstructions
);
117 m_xEditComment
->set_size_request(m_xEditComment
->get_approximate_digit_width() * 48,
118 m_xEditComment
->get_text_height() * 5);
122 m_xLabelAddComment
->hide();
123 m_xEditComment
->hide();
124 m_xEditComment
->set_size_request(0, 0);
130 IMPL_LINK_NOARG(SignSignatureLineDialog
, loadImage
, weld::Button
&, void)
132 Reference
<XComponentContext
> xContext
= comphelper::getProcessComponentContext();
133 Reference
<XFilePicker3
> xFilePicker
134 = FilePicker::createWithMode(xContext
, TemplateDescription::FILEOPEN_PREVIEW
);
135 if (xFilePicker
->execute())
137 Sequence
<OUString
> aSelectedFiles
= xFilePicker
->getSelectedFiles();
138 if (!aSelectedFiles
.hasElements())
141 Reference
<XGraphicProvider
> xProvider
= GraphicProvider::create(xContext
);
142 Sequence
<PropertyValue
> aMediaProperties(1);
143 aMediaProperties
[0].Name
= "URL";
144 aMediaProperties
[0].Value
<<= aSelectedFiles
[0];
145 m_xSignatureImage
= xProvider
->queryGraphic(aMediaProperties
);
146 m_sOriginalImageBtnLabel
= m_xBtnLoadImage
->get_label();
148 INetURLObject
aObj(aSelectedFiles
[0]);
149 m_xBtnLoadImage
->set_label(aObj
.GetLastName());
155 IMPL_LINK_NOARG(SignSignatureLineDialog
, clearImage
, weld::Button
&, void)
157 m_xSignatureImage
.set(nullptr);
158 m_xBtnLoadImage
->set_label(m_sOriginalImageBtnLabel
);
162 IMPL_LINK_NOARG(SignSignatureLineDialog
, chooseCertificate
, weld::Button
&, void)
164 // Document needs to be saved before selecting a certificate
165 SfxObjectShell
* pShell
= SfxObjectShell::Current();
166 if (!pShell
->PrepareForSigning(m_xDialog
.get()))
169 Reference
<XDocumentDigitalSignatures
> xSigner(DocumentDigitalSignatures::createWithVersion(
170 comphelper::getProcessComponentContext(), "1.2"));
171 xSigner
->setParentWindow(m_xDialog
->GetXWindow());
172 OUString aDescription
;
173 CertificateKind certificateKind
= CertificateKind_NONE
;
174 // When signing ooxml, we only want X.509 certificates
175 if (pShell
->GetMedium()->GetFilter()->IsAlienFormat())
176 certificateKind
= CertificateKind_X509
;
177 Reference
<XCertificate
> xSignCertificate
178 = xSigner
->selectSigningCertificateWithType(certificateKind
, aDescription
);
180 if (xSignCertificate
.is())
182 m_xSelectedCertifate
= xSignCertificate
;
183 m_xBtnChooseCertificate
->set_label(
184 xmlsec::GetContentPart(xSignCertificate
->getSubjectName()));
189 IMPL_LINK_NOARG(SignSignatureLineDialog
, entryChanged
, weld::Entry
&, void) { ValidateFields(); }
191 void SignSignatureLineDialog::ValidateFields()
193 bool bEnableSignBtn
= m_xSelectedCertifate
.is()
194 && (!m_xEditName
->get_text().isEmpty() || m_xSignatureImage
.is());
195 m_xBtnSign
->set_sensitive(bEnableSignBtn
);
197 m_xEditName
->set_sensitive(!m_xSignatureImage
.is());
198 m_xBtnLoadImage
->set_sensitive(m_xEditName
->get_text().isEmpty());
199 m_xBtnClearImage
->set_sensitive(m_xSignatureImage
.is());
202 void SignSignatureLineDialog::Apply()
204 if (!m_xSelectedCertifate
.is())
206 SAL_WARN("cui.dialogs", "No certificate selected!");
210 SfxObjectShell
* pShell
= SfxObjectShell::Current();
211 Reference
<XGraphic
> xValidGraphic
= getSignedGraphic(true);
212 Reference
<XGraphic
> xInvalidGraphic
= getSignedGraphic(false);
213 pShell
->SignSignatureLine(m_xDialog
.get(), m_aSignatureLineId
, m_xSelectedCertifate
,
214 xValidGraphic
, xInvalidGraphic
, m_xEditComment
->get_text());
217 css::uno::Reference
<css::graphic::XGraphic
> SignSignatureLineDialog::getSignedGraphic(bool bValid
)
219 // Read svg and replace placeholder texts
220 OUString
aSvgImage(getSignatureImage());
221 aSvgImage
= aSvgImage
.replaceAll("[SIGNER_NAME]", getCDataString(m_aSuggestedSignerName
));
222 aSvgImage
= aSvgImage
.replaceAll("[SIGNER_TITLE]", getCDataString(m_aSuggestedSignerTitle
));
225 = CuiResId(RID_SVXSTR_SIGNATURELINE_SIGNED_BY
)
226 .replaceFirst("%1", xmlsec::GetContentPart(m_xSelectedCertifate
->getSubjectName()));
227 aSvgImage
= aSvgImage
.replaceAll("[SIGNED_BY]", getCDataString(aIssuerLine
));
229 aSvgImage
= aSvgImage
.replaceAll("[INVALID_SIGNATURE]", "");
232 if (m_bShowSignDate
&& bValid
)
234 const SvtSysLocale aSysLocale
;
235 const LocaleDataWrapper
& rLocaleData
= aSysLocale
.GetLocaleData();
236 Date
aDateTime(Date::SYSTEM
);
237 aDate
= rLocaleData
.getDate(aDateTime
);
239 aSvgImage
= aSvgImage
.replaceAll("[DATE]", aDate
);
241 // Custom signature image
242 if (m_xSignatureImage
.is())
244 OUString aGraphicInBase64
;
245 Graphic
aGraphic(m_xSignatureImage
);
246 if (!XOutBitmap::GraphicToBase64(aGraphic
, aGraphicInBase64
, false))
247 SAL_WARN("cui.dialogs", "Could not convert graphic to base64");
249 OUString aImagePart
= "<image y=\"825\" x=\"1300\" "
250 "xlink:href=\"data:[MIMETYPE];base64,[BASE64_IMG]>\" "
251 "preserveAspectRatio=\"xMidYMid\" height=\"1520\" "
253 aImagePart
= aImagePart
.replaceAll(
254 "[MIMETYPE]", GraphicMimeTypeHelper::GetMimeTypeForXGraphic(m_xSignatureImage
));
255 aImagePart
= aImagePart
.replaceAll("[BASE64_IMG]", aGraphicInBase64
);
256 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE_IMAGE]", aImagePart
);
258 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE]", "");
262 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE_IMAGE]", "");
263 aSvgImage
= aSvgImage
.replaceAll("[SIGNATURE]", getCDataString(m_xEditName
->get_text()));
267 SvMemoryStream
aSvgStream(4096, 4096);
268 aSvgStream
.WriteOString(OUStringToOString(aSvgImage
, RTL_TEXTENCODING_UTF8
));
269 Reference
<XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(aSvgStream
));
270 Reference
<XComponentContext
> xContext(comphelper::getProcessComponentContext());
271 Reference
<XGraphicProvider
> xProvider
= css::graphic::GraphicProvider::create(xContext
);
273 Sequence
<PropertyValue
> aMediaProperties(1);
274 aMediaProperties
[0].Name
= "InputStream";
275 aMediaProperties
[0].Value
<<= xInputStream
;
276 return xProvider
->queryGraphic(aMediaProperties
);
279 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */