LibreOffice Module sw (master) 1
edfcol.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
24#include <editsh.hxx>
25
26#include <com/sun/star/container/XEnumerationAccess.hpp>
27#include <com/sun/star/container/XContentEnumerationAccess.hpp>
28#include <com/sun/star/document/XActionLockable.hpp>
29#include <com/sun/star/document/XDocumentProperties.hpp>
30#include <com/sun/star/drawing/FillStyle.hpp>
31#include <com/sun/star/drawing/HomogenMatrix3.hpp>
32#include <com/sun/star/drawing/LineStyle.hpp>
33#include <com/sun/star/drawing/XShape.hpp>
34#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
35#include <com/sun/star/lang/XMultiServiceFactory.hpp>
36#include <com/sun/star/lang/XServiceInfo.hpp>
37#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
38#include <com/sun/star/text/RelOrientation.hpp>
39#include <com/sun/star/text/TextContentAnchorType.hpp>
40#include <com/sun/star/text/VertOrientation.hpp>
41#include <com/sun/star/text/WrapTextMode.hpp>
42#include <com/sun/star/text/XTextContent.hpp>
43#include <com/sun/star/text/XTextDocument.hpp>
44#include <com/sun/star/text/XTextField.hpp>
45#include <com/sun/star/text/XTextRange.hpp>
46#include <com/sun/star/text/XParagraphAppend.hpp>
47#include <com/sun/star/text/XParagraphCursor.hpp>
48#include <com/sun/star/awt/FontWeight.hpp>
49#include <com/sun/star/rdf/XMetadatable.hpp>
50#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
51#include <com/sun/star/security/XCertificate.hpp>
52
59#include <comphelper/string.hxx>
60#include <editeng/unoprnms.hxx>
64#include <svl/cryptosign.hxx>
65#include <svl/sigstruct.hxx>
66#include <utility>
67#include <vcl/svapp.hxx>
68#include <vcl/weld.hxx>
69#include <vcl/virdev.hxx>
70
71#include <redline.hxx>
72#include <poolfmt.hxx>
73#include <hintids.hxx>
74#include <doc.hxx>
75#include <IDocumentUndoRedo.hxx>
76#include <ndtxt.hxx>
77#include <paratr.hxx>
78#include <viewopt.hxx>
79#include <SwRewriter.hxx>
80#include <numrule.hxx>
81#include <swundo.hxx>
82#include <docary.hxx>
83#include <docsh.hxx>
84#include <unoprnms.hxx>
85#include <rootfrm.hxx>
86#include <pagefrm.hxx>
87#include <txtfrm.hxx>
88#include <rdfhelper.hxx>
90
91#include <unoparagraph.hxx>
92#include <strings.hrc>
93#include <undobj.hxx>
95#include <txtatr.hxx>
96#include <fmtmeta.hxx>
97#include <unotxdoc.hxx>
98#include <unotextbodyhf.hxx>
99#include <unoport.hxx>
100
103
104constexpr OUStringLiteral WATERMARK_NAME = u"PowerPlusWaterMarkObject";
105#define WATERMARK_AUTO_SIZE sal_uInt32(1)
106
107namespace
108{
109constexpr OUStringLiteral MetaFilename(u"tscp/bails.rdf");
110constexpr OUStringLiteral MetaNS(u"urn:bails");
111constexpr OUStringLiteral ParagraphSignatureRDFNamespace = u"urn:bails:loext:paragraph:signature:";
112constexpr OUStringLiteral ParagraphSignatureIdRDFName = u"urn:bails:loext:paragraph:signature:id";
113constexpr OUStringLiteral ParagraphSignatureDigestRDFName = u":digest";
114constexpr OUStringLiteral ParagraphSignatureDateRDFName = u":date";
115constexpr OUStringLiteral ParagraphSignatureUsageRDFName = u":usage";
116constexpr OUStringLiteral ParagraphSignatureLastIdRDFName = u"urn:bails:loext:paragraph:signature:lastid";
117constexpr OUStringLiteral ParagraphClassificationNameRDFName = u"urn:bails:loext:paragraph:classification:name";
118constexpr OUStringLiteral ParagraphClassificationValueRDFName = u"urn:bails:loext:paragraph:classification:value";
119constexpr OUStringLiteral ParagraphClassificationAbbrRDFName = u"urn:bails:loext:paragraph:classification:abbreviation";
120constexpr OUStringLiteral ParagraphClassificationFieldNamesRDFName = u"urn:bails:loext:paragraph:classification:fields";
121constexpr OUStringLiteral MetadataFieldServiceName = u"com.sun.star.text.textfield.MetadataField";
122constexpr OUStringLiteral DocInfoServiceName = u"com.sun.star.text.TextField.DocInfo.Custom";
123
125std::vector<OUString> lcl_getUsedPageStyles(SwViewShell const * pShell)
126{
127 std::vector<OUString> aReturn;
128
129 SwRootFrame* pLayout = pShell->GetLayout();
130 for (SwFrame* pFrame = pLayout->GetLower(); pFrame; pFrame = pFrame->GetNext())
131 {
132 SwPageFrame* pPage = static_cast<SwPageFrame*>(pFrame);
133 if (const SwPageDesc *pDesc = pPage->FindPageDesc())
134 aReturn.push_back(pDesc->GetName());
135 }
136
137 return aReturn;
138}
139
141uno::Reference<text::XTextField> lcl_findField(const uno::Reference<text::XText>& xText, const OUString& rServiceName, std::u16string_view rFieldName)
142{
143 uno::Reference<text::XTextField> xField;
144 uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xText, uno::UNO_QUERY);
145 uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
146 while (xParagraphs->hasMoreElements())
147 {
148 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
149 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
150 while (xTextPortions->hasMoreElements())
151 {
152 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
153 OUString aTextPortionType;
154 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
155 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
156 continue;
157
158 uno::Reference<lang::XServiceInfo> xTextField;
159 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
160 if (!xTextField->supportsService(rServiceName))
161 continue;
162
163 OUString aName;
164 uno::Reference<beans::XPropertySet> xPropertySet(xTextField, uno::UNO_QUERY);
165 xPropertySet->getPropertyValue(UNO_NAME_NAME) >>= aName;
166 if (aName == rFieldName)
167 {
168 xField = uno::Reference<text::XTextField>(xTextField, uno::UNO_QUERY);
169 break;
170 }
171 }
172 }
173
174 return xField;
175}
176
178bool lcl_hasField(const uno::Reference<text::XText>& xText, const OUString& rServiceName, std::u16string_view rFieldName)
179{
180 return lcl_findField(xText, rServiceName, rFieldName).is();
181}
182
184uno::Reference<drawing::XShape> lcl_getWatermark(const uno::Reference<text::XText>& xText,
185 const OUString& rServiceName, OUString& rShapeName, bool& bSuccess)
186{
187 bSuccess = false;
188 uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xText, uno::UNO_QUERY);
189 uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
190 while (xParagraphs->hasMoreElements())
191 {
192 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
193 if (!xTextPortionEnumerationAccess.is())
194 continue;
195
196 bSuccess = true;
197
198 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
199 while (xTextPortions->hasMoreElements())
200 {
201 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
202 OUString aTextPortionType;
203 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
204 if (aTextPortionType != "Frame")
205 continue;
206
207 uno::Reference<container::XContentEnumerationAccess> xContentEnumerationAccess(xTextPortion, uno::UNO_QUERY);
208 if (!xContentEnumerationAccess.is())
209 continue;
210
211 uno::Reference<container::XEnumeration> xEnumeration = xContentEnumerationAccess->createContentEnumeration("com.sun.star.text.TextContent");
212 if (!xEnumeration->hasMoreElements())
213 continue;
214
215 uno::Reference<lang::XServiceInfo> xWatermark(xEnumeration->nextElement(), uno::UNO_QUERY);
216 if (!xWatermark->supportsService(rServiceName))
217 continue;
218
219 uno::Reference<container::XNamed> xNamed(xWatermark, uno::UNO_QUERY);
220
221 if (!xNamed->getName().match(WATERMARK_NAME))
222 continue;
223
224 rShapeName = xNamed->getName();
225
226 uno::Reference<drawing::XShape> xShape(xWatermark, uno::UNO_QUERY);
227 return xShape;
228 }
229 }
230
231 return uno::Reference<drawing::XShape>();
232}
233
236OString lcl_getParagraphBodyText(const uno::Reference<text::XTextContent>& xText)
237{
238 OUStringBuffer strBuf;
239 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xText, uno::UNO_QUERY);
240 if (!xTextPortionEnumerationAccess.is())
241 return OString();
242
243 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
244 while (xTextPortions->hasMoreElements())
245 {
246 uno::Any elem = xTextPortions->nextElement();
247
248 //TODO: Consider including hidden and conditional texts/portions.
249 OUString aTextPortionType;
250 uno::Reference<beans::XPropertySet> xPropertySet(elem, uno::UNO_QUERY);
251 xPropertySet->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
252 if (aTextPortionType == "Text")
253 {
254 uno::Reference<text::XTextRange> xTextRange(elem, uno::UNO_QUERY);
255 if (xTextRange.is())
256 strBuf.append(xTextRange->getString());
257 }
258 }
259
260 // Cleanup the dummy characters added by fields (which we exclude).
264
265 return strBuf.makeStringAndClear().trim().toUtf8();
266}
267
268template <typename T>
269std::map<OUString, OUString> lcl_getRDFStatements(const uno::Reference<frame::XModel>& xModel,
270 const T& xRef)
271{
272 try
273 {
274 const css::uno::Reference<css::rdf::XResource> xSubject(xRef, uno::UNO_QUERY);
275 return SwRDFHelper::getStatements(xModel, MetaNS, xSubject);
276 }
277 catch (const ::css::uno::Exception&)
278 {
279 }
280
281 return std::map<OUString, OUString>();
282}
283
285std::pair<OUString, OUString> lcl_getFieldRDFByPrefix(const uno::Reference<frame::XModel>& xModel,
286 const uno::Reference<css::text::XTextField>& xField,
287 std::u16string_view sPrefix)
288{
289 for (const auto& pair : lcl_getRDFStatements(xModel, xField))
290 {
291 if (pair.first.startsWith(sPrefix))
292 return pair;
293 }
294
295 return std::make_pair(OUString(), OUString());
296}
297
299template <typename T>
300std::pair<OUString, OUString> lcl_getRDF(const uno::Reference<frame::XModel>& xModel,
301 const T& xRef,
302 const OUString& sRDFName)
303{
304 const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xRef);
305 const auto it = aStatements.find(sRDFName);
306 return (it != aStatements.end()) ? std::make_pair(it->first, it->second) : std::make_pair(OUString(), OUString());
307}
308
311bool lcl_IsParagraphSignatureField(const uno::Reference<frame::XModel>& xModel,
312 const uno::Reference<css::text::XTextField>& xField)
313{
314 return (lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName).first == ParagraphSignatureIdRDFName);
315}
316
317uno::Reference<text::XTextField> lcl_findFieldByRDF(const uno::Reference<frame::XModel>& xModel,
318 const uno::Reference<text::XTextContent>& xParagraph,
319 const OUString& sRDFName,
320 std::u16string_view sRDFValue)
321{
322 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraph, uno::UNO_QUERY);
323 if (!xTextPortionEnumerationAccess.is())
324 return uno::Reference<text::XTextField>();
325
326 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
327 if (!xTextPortions.is())
328 return uno::Reference<text::XTextField>();
329
330 while (xTextPortions->hasMoreElements())
331 {
332 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
333 OUString aTextPortionType;
334 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
335 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
336 continue;
337
338 uno::Reference<lang::XServiceInfo> xTextField;
339 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
340 if (!xTextField->supportsService(MetadataFieldServiceName))
341 continue;
342
343 uno::Reference<text::XTextField> xField(xTextField, uno::UNO_QUERY);
344 const std::pair<OUString, OUString> pair = lcl_getRDF(xModel, xField, sRDFName);
345 if (pair.first == sRDFName && (sRDFValue.empty() || sRDFValue == pair.second))
346 return xField;
347 }
348
349 return uno::Reference<text::XTextField>();
350}
351
352struct SignatureDescr
353{
354 OUString msSignature;
355 OUString msUsage;
356 OUString msDate;
357
358 bool isValid() const { return !msSignature.isEmpty(); }
359};
360
361SignatureDescr lcl_getSignatureDescr(const uno::Reference<frame::XModel>& xModel,
362 const uno::Reference<css::text::XTextContent>& xParagraph,
363 std::u16string_view sFieldId)
364{
365 SignatureDescr aDescr;
366
367 const OUString prefix = ParagraphSignatureRDFNamespace + sFieldId;
368 const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xParagraph);
369
370 const auto itSig = aStatements.find(prefix + ParagraphSignatureDigestRDFName);
371 aDescr.msSignature = (itSig != aStatements.end() ? itSig->second : OUString());
372
373 const auto itDate = aStatements.find(prefix + ParagraphSignatureDateRDFName);
374 aDescr.msDate = (itDate != aStatements.end() ? itDate->second : OUString());
375
376 const auto itUsage = aStatements.find(prefix + ParagraphSignatureUsageRDFName);
377 aDescr.msUsage = (itUsage != aStatements.end() ? itUsage->second : OUString());
378
379 return aDescr;
380}
381
382SignatureDescr lcl_getSignatureDescr(const uno::Reference<frame::XModel>& xModel,
383 const uno::Reference<css::text::XTextContent>& xParagraph,
384 const uno::Reference<css::text::XTextField>& xField)
385{
386 const OUString sFieldId = lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName).second;
387 if (!sFieldId.isEmpty())
388 return lcl_getSignatureDescr(xModel, xParagraph, sFieldId);
389
390 return SignatureDescr();
391}
392
394std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr,
395 const OString& utf8Text)
396{
397 OUString msg = SwResId(STR_INVALID_SIGNATURE);
398 bool valid = false;
399
400 if (aDescr.isValid())
401 {
402 const char* pData = utf8Text.getStr();
403 const std::vector<unsigned char> data(pData, pData + utf8Text.getLength());
404
405 OString encSignature;
406 if (aDescr.msSignature.convertToString(&encSignature, RTL_TEXTENCODING_UTF8, 0))
407 {
408 const std::vector<unsigned char> sig(svl::crypto::DecodeHexString(encSignature));
409 SignatureInformation aInfo(0);
410 valid = svl::crypto::Signing::Verify(data, false, sig, aInfo);
411 valid = valid
412 && aInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
413
414 assert(aInfo.GetSigningCertificate()); // it was valid
415 msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.GetSigningCertificate()->X509Subject + ", " +
416 aDescr.msDate;
417 msg += (!aDescr.msUsage.isEmpty() ? (" (" + aDescr.msUsage + "): ") : OUString(": "));
418 msg += (valid ? SwResId(STR_VALID) : SwResId(STR_INVALID));
419 }
420 }
421
422 return std::make_pair(valid, msg);
423}
424
426std::pair<bool, OUString>
427lcl_MakeParagraphSignatureFieldText(const uno::Reference<frame::XModel>& xModel,
428 const uno::Reference<css::text::XTextContent>& xParagraph,
429 const uno::Reference<css::text::XTextField>& xField,
430 const OString& utf8Text)
431{
432 const SignatureDescr aDescr = lcl_getSignatureDescr(xModel, xParagraph, xField);
433 return lcl_MakeParagraphSignatureFieldText(aDescr, utf8Text);
434}
435
437OUString lcl_getNextSignatureId(const uno::Reference<frame::XModel>& xModel,
438 const uno::Reference<text::XTextContent>& xParagraph)
439{
440 const OUString sFieldId = lcl_getRDF(xModel, xParagraph, ParagraphSignatureLastIdRDFName).second;
441 return OUString::number(!sFieldId.isEmpty() ? sFieldId.toInt32() + 1 : 1);
442}
443
445uno::Reference<text::XTextField> lcl_InsertParagraphSignature(const uno::Reference<frame::XModel>& xModel,
446 const uno::Reference<text::XTextContent>& xParagraph,
447 const OUString& signature,
448 const OUString& usage)
449{
450 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
451 auto xField = uno::Reference<text::XTextField>(xMultiServiceFactory->createInstance(MetadataFieldServiceName), uno::UNO_QUERY);
452
453 // Add the signature at the end.
454 xField->attach(xParagraph->getAnchor()->getEnd());
455
456 const OUString sId = lcl_getNextSignatureId(xModel, xParagraph);
457
458 const css::uno::Reference<css::rdf::XResource> xSubject(xField, uno::UNO_QUERY);
459 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xSubject, ParagraphSignatureIdRDFName, sId);
460
461 // First convert the UTC UNIX timestamp to a tools::DateTime then to local time.
462 DateTime aDateTime = DateTime::CreateFromUnixTime(time(nullptr));
463 aDateTime.ConvertToLocalTime();
464 OUStringBuffer rBuffer;
465 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
466 rBuffer.append('-');
467 if (aDateTime.GetMonth() < 10)
468 rBuffer.append('0');
469 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
470 rBuffer.append('-');
471 if (aDateTime.GetDay() < 10)
472 rBuffer.append('0');
473 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
474
475 // Now set the RDF on the paragraph, since that's what is preserved in .doc(x).
476 const css::uno::Reference<css::rdf::XResource> xParaSubject(xParagraph, uno::UNO_QUERY);
477 const OUString prefix = ParagraphSignatureRDFNamespace + sId;
478 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureLastIdRDFName, sId);
479 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDigestRDFName, signature);
480 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureUsageRDFName, usage);
481 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDateRDFName, rBuffer.makeStringAndClear());
482
483 return xField;
484}
485
487bool lcl_DoUpdateParagraphSignatureField(SwDoc& rDoc,
488 const uno::Reference<css::text::XTextField>& xField,
489 const OUString& sDisplayText)
490{
491 // Disable undo to avoid introducing noise when we edit the metadata field.
492 const bool isUndoEnabled = rDoc.GetIDocumentUndoRedo().DoesUndo();
493 rDoc.GetIDocumentUndoRedo().DoUndo(false);
494 comphelper::ScopeGuard const g([&rDoc, isUndoEnabled]() {
495 rDoc.GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
496 });
497
498 try
499 {
500 uno::Reference<css::text::XTextRange> xText(xField, uno::UNO_QUERY);
501 const OUString curText = xText->getString();
502 if (curText != sDisplayText)
503 {
504 xText->setString(sDisplayText);
505 return true;
506 }
507 }
508 catch (const uno::Exception&)
509 {
510 // We failed; avoid crashing.
511 DBG_UNHANDLED_EXCEPTION("sw.uno", "Failed to update paragraph signature");
512 }
513
514 return false;
515}
516
518bool lcl_UpdateParagraphSignatureField(SwDoc& rDoc,
519 const uno::Reference<frame::XModel>& xModel,
520 const uno::Reference<css::text::XTextContent>& xParagraph,
521 const uno::Reference<css::text::XTextField>& xField,
522 const OString& utf8Text)
523{
524 const OUString sDisplayText
525 = lcl_MakeParagraphSignatureFieldText(xModel, xParagraph, xField, utf8Text).second;
526 return lcl_DoUpdateParagraphSignatureField(rDoc, xField, sDisplayText);
527}
528
529void lcl_RemoveParagraphMetadataField(const uno::Reference<css::text::XTextField>& xField)
530{
531 uno::Reference<css::text::XTextRange> xParagraph(xField->getAnchor());
532 xParagraph->getText()->removeTextContent(xField);
533}
534
537bool lcl_IsParagraphClassificationField(const uno::Reference<frame::XModel>& xModel,
538 const uno::Reference<css::text::XTextField>& xField,
539 std::u16string_view sKey)
540{
541 const std::pair<OUString, OUString> rdfPair = lcl_getRDF(xModel, xField, ParagraphClassificationNameRDFName);
542 return rdfPair.first == ParagraphClassificationNameRDFName && (sKey.empty() || rdfPair.second == sKey);
543}
544
545uno::Reference<text::XTextField> lcl_FindParagraphClassificationField(const uno::Reference<frame::XModel>& xModel,
546 const rtl::Reference<SwXParagraph>& xParagraph,
547 std::u16string_view sKey = u"")
548{
549 uno::Reference<text::XTextField> xTextField;
550
551 if (!xParagraph.is())
552 return xTextField;
553
554 // Enumerate text portions to find metadata fields. This is expensive, best to enumerate fields only.
555 rtl::Reference<SwXTextPortionEnumeration> xTextPortions = xParagraph->createTextFieldsEnumeration();
556 while (xTextPortions->hasMoreElements())
557 {
558 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
559 OUString aTextPortionType;
560 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
561 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
562 continue;
563
564 uno::Reference<lang::XServiceInfo> xServiceInfo;
565 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xServiceInfo;
566 if (!xServiceInfo->supportsService(MetadataFieldServiceName))
567 continue;
568
569 uno::Reference<text::XTextField> xField(xServiceInfo, uno::UNO_QUERY);
570 if (lcl_IsParagraphClassificationField(xModel, xField, sKey))
571 {
572 xTextField = xField;
573 break;
574 }
575 }
576
577 return xTextField;
578}
579
581uno::Reference<text::XTextField> lcl_InsertParagraphClassification(const uno::Reference<frame::XModel>& xModel,
582 const uno::Reference<text::XTextContent>& xParent)
583{
584 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
585 auto xField = uno::Reference<text::XTextField>(xMultiServiceFactory->createInstance(MetadataFieldServiceName), uno::UNO_QUERY);
586
587 // Add the classification at the start.
588 xField->attach(xParent->getAnchor()->getStart());
589 return xField;
590}
591
593bool lcl_UpdateParagraphClassificationField(SwDoc* pDoc,
594 const uno::Reference<frame::XModel>& xModel,
595 const uno::Reference<css::text::XTextContent>& xTextNode,
596 const OUString& sKey,
597 const OUString& sValue,
598 const OUString& sDisplayText)
599{
600 // Disable undo to avoid introducing noise when we edit the metadata field.
601 const bool isUndoEnabled = pDoc->GetIDocumentUndoRedo().DoesUndo();
602 pDoc->GetIDocumentUndoRedo().DoUndo(false);
603 comphelper::ScopeGuard const g([pDoc, isUndoEnabled] () {
604 pDoc->GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
605 });
606
607 uno::Reference<text::XTextField> xField = lcl_InsertParagraphClassification(xModel, xTextNode);
608
609 css::uno::Reference<css::rdf::XResource> xFieldSubject(xField, uno::UNO_QUERY);
610 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xFieldSubject, sKey, sValue);
611 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xFieldSubject, ParagraphClassificationNameRDFName, sKey);
612 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xFieldSubject, ParagraphClassificationValueRDFName, sValue);
613
614 css::uno::Reference<css::rdf::XResource> xNodeSubject(xTextNode, uno::UNO_QUERY);
615 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xNodeSubject, sKey, sValue);
616
617 return lcl_DoUpdateParagraphSignatureField(*pDoc, xField, sDisplayText);
618}
619
620void lcl_ValidateParagraphSignatures(SwDoc& rDoc, const uno::Reference<text::XTextContent>& xParagraph, const bool updateDontRemove)
621{
622 SwDocShell* pDocShell = rDoc.GetDocShell();
623 if (!pDocShell)
624 return;
625
626 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
627
628 // Check if the paragraph is signed.
629 try
630 {
631 const std::pair<OUString, OUString> pair = lcl_getRDF(xModel, xParagraph, ParagraphSignatureLastIdRDFName);
632 if (pair.second.isEmpty())
633 return;
634 }
635 catch (const ::css::uno::Exception&)
636 {
637 return;
638 }
639
640 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraph, uno::UNO_QUERY);
641 if (!xTextPortionEnumerationAccess.is())
642 return;
643
644 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
645 if (!xTextPortions.is())
646 return;
647
648 // Get the text (without fields).
649 const OString utf8Text = lcl_getParagraphBodyText(xParagraph);
650 if (utf8Text.isEmpty())
651 return;
652
653 while (xTextPortions->hasMoreElements())
654 {
655 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
656 OUString aTextPortionType;
657 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
658 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
659 continue;
660
661 uno::Reference<lang::XServiceInfo> xTextField;
662 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
663 if (!xTextField->supportsService(MetadataFieldServiceName))
664 continue;
665
666 uno::Reference<text::XTextField> xField(xTextField, uno::UNO_QUERY);
667 if (!lcl_IsParagraphSignatureField(xModel, xField))
668 {
669 continue;
670 }
671
672 if (updateDontRemove)
673 {
674 lcl_UpdateParagraphSignatureField(rDoc, xModel, xParagraph, xField, utf8Text);
675 }
676 else if (!lcl_MakeParagraphSignatureFieldText(xModel, xParagraph, xField, utf8Text).first)
677 {
680 std::make_unique<SwUndoParagraphSigning>(rDoc, xField, xParagraph, false));
681 lcl_RemoveParagraphMetadataField(xField);
683 }
684 }
685}
686
687} // anonymous namespace
688
690{
691 return *GetDoc()->GetDfltTextFormatColl();
692}
693
695{
696 return GetDoc()->GetTextFormatColls()->size();
697}
698
700{
701 return *((*(GetDoc()->GetTextFormatColls()))[nFormatColl]);
702}
703
704static void insertFieldToDocument(uno::Reference<lang::XMultiServiceFactory> const & rxMultiServiceFactory,
705 uno::Reference<text::XText> const & rxText, uno::Reference<text::XParagraphCursor> const & rxParagraphCursor,
706 OUString const & rsKey)
707{
708 uno::Reference<beans::XPropertySet> xField(rxMultiServiceFactory->createInstance(DocInfoServiceName), uno::UNO_QUERY);
709 xField->setPropertyValue(UNO_NAME_NAME, uno::Any(rsKey));
710 uno::Reference<text::XTextContent> xTextContent(xField, uno::UNO_QUERY);
711
712 rxText->insertTextContent(rxParagraphCursor, xTextContent, false);
713}
714
715static void removeAllClassificationFields(std::u16string_view rPolicy, uno::Reference<text::XText> const & rxText)
716{
717 uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(rxText, uno::UNO_QUERY);
718 uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
719 while (xParagraphs->hasMoreElements())
720 {
721 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
722 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
723 while (xTextPortions->hasMoreElements())
724 {
725 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
726 OUString aTextPortionType;
727 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
728 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
729 continue;
730
731 uno::Reference<lang::XServiceInfo> xTextField;
732 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
733 if (!xTextField->supportsService(DocInfoServiceName))
734 continue;
735
736 OUString aName;
737 uno::Reference<beans::XPropertySet> xPropertySet(xTextField, uno::UNO_QUERY);
738 xPropertySet->getPropertyValue(UNO_NAME_NAME) >>= aName;
739 if (aName.startsWith(rPolicy))
740 {
741 uno::Reference<text::XTextField> xField(xTextField, uno::UNO_QUERY);
742 rxText->removeTextContent(xField);
743 }
744 }
745 }
746}
747
748static sal_Int32 getNumberOfParagraphs(uno::Reference<text::XText> const & xText)
749{
750 uno::Reference<container::XEnumerationAccess> xParagraphEnumAccess(xText, uno::UNO_QUERY);
751 uno::Reference<container::XEnumeration> xParagraphEnum = xParagraphEnumAccess->createEnumeration();
752 sal_Int32 nResult = 0;
753 while (xParagraphEnum->hasMoreElements())
754 {
755 xParagraphEnum->nextElement();
756 nResult++;
757 }
758 return nResult;
759}
760
761static void equaliseNumberOfParagraph(std::vector<svx::ClassificationResult> const & rResults, uno::Reference<text::XText> const & xText)
762{
763 sal_Int32 nNumberOfParagraphs = 0;
764 for (svx::ClassificationResult const & rResult : rResults)
765 {
766 if (rResult.meType == svx::ClassificationType::PARAGRAPH)
767 nNumberOfParagraphs++;
768 }
769
770 while (getNumberOfParagraphs(xText) < nNumberOfParagraphs)
771 {
772 uno::Reference<text::XParagraphAppend> xParagraphAppend(xText, uno::UNO_QUERY);
773 xParagraphAppend->finishParagraph(uno::Sequence<beans::PropertyValue>());
774 }
775}
776
777void SwEditShell::ApplyAdvancedClassification(std::vector<svx::ClassificationResult> const & rResults)
778{
779 SwDocShell* pDocShell = GetDoc()->GetDocShell();
780 if (!pDocShell || !SfxObjectShell::Current())
781 return;
782
783 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
784 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
785 uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
786 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
787
788 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
789
790 uno::Reference<document::XDocumentProperties> xDocumentProperties = SfxObjectShell::Current()->getDocProperties();
791
793 const std::vector<OUString> aUsedPageStyles = lcl_getUsedPageStyles(this);
794 for (const OUString& rPageStyleName : aUsedPageStyles)
795 {
796 uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
797
798 // HEADER
799 bool bHeaderIsOn = false;
800 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
801 uno::Reference<text::XText> xHeaderText;
802 if (bHeaderIsOn)
803 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
804 if (xHeaderText.is())
805 removeAllClassificationFields(sPolicy, xHeaderText);
806
807 // FOOTER
808 bool bFooterIsOn = false;
809 xPageStyle->getPropertyValue(UNO_NAME_FOOTER_IS_ON) >>= bFooterIsOn;
810 uno::Reference<text::XText> xFooterText;
811 if (bFooterIsOn)
812 xPageStyle->getPropertyValue(UNO_NAME_FOOTER_TEXT) >>= xFooterText;
813 if (xFooterText.is())
814 removeAllClassificationFields(sPolicy, xFooterText);
815 }
816
817 // Clear properties
818 uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
820
821 SfxClassificationHelper aHelper(xDocumentProperties);
822
823 // Apply properties from the BA policy
824 for (svx::ClassificationResult const & rResult : rResults)
825 {
826 if (rResult.meType == svx::ClassificationType::CATEGORY)
827 {
828 aHelper.SetBACName(rResult.msName, SfxClassificationHelper::getPolicyType());
829 }
830 }
831
833
834 // Insert origin document property
836
837 // Insert full text as document property
839
840 for (const OUString& rPageStyleName : aUsedPageStyles)
841 {
842 uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
843
844 // HEADER
845 bool bHeaderIsOn = false;
846 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
847 if (!bHeaderIsOn)
848 xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_ON, uno::Any(true));
849 uno::Reference<text::XText> xHeaderText;
850 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
851 equaliseNumberOfParagraph(rResults, xHeaderText);
852
853 // FOOTER
854 bool bFooterIsOn = false;
855 xPageStyle->getPropertyValue(UNO_NAME_FOOTER_IS_ON) >>= bFooterIsOn;
856 if (!bFooterIsOn)
857 xPageStyle->setPropertyValue(UNO_NAME_FOOTER_IS_ON, uno::Any(true));
858 uno::Reference<text::XText> xFooterText;
859 xPageStyle->getPropertyValue(UNO_NAME_FOOTER_TEXT) >>= xFooterText;
860 equaliseNumberOfParagraph(rResults, xFooterText);
861
862 // SET/DELETE WATERMARK
863 SfxWatermarkItem aWatermarkItem;
864 aWatermarkItem.SetText(aHelper.GetDocumentWatermark());
865 SetWatermark(aWatermarkItem);
866
867 uno::Reference<text::XParagraphCursor> xHeaderParagraphCursor(xHeaderText->createTextCursor(), uno::UNO_QUERY);
868 uno::Reference<text::XParagraphCursor> xFooterParagraphCursor(xFooterText->createTextCursor(), uno::UNO_QUERY);
869
870 sal_Int32 nParagraph = -1;
871
872 for (svx::ClassificationResult const & rResult : rResults)
873 {
874 switch(rResult.meType)
875 {
877 {
878 OUString sKey = aCreator.makeNumberedTextKey();
879
880 svx::classification::addOrInsertDocumentProperty(xPropertyContainer, sKey, rResult.msName);
881 insertFieldToDocument(xMultiServiceFactory, xHeaderText, xHeaderParagraphCursor, sKey);
882 insertFieldToDocument(xMultiServiceFactory, xFooterText, xFooterParagraphCursor, sKey);
883 }
884 break;
885
887 {
888 OUString sKey = aCreator.makeCategoryNameKey();
889 insertFieldToDocument(xMultiServiceFactory, xHeaderText, xHeaderParagraphCursor, sKey);
890 insertFieldToDocument(xMultiServiceFactory, xFooterText, xFooterParagraphCursor, sKey);
891 }
892 break;
893
895 {
896 OUString sKey = aCreator.makeNumberedMarkingKey();
897 svx::classification::addOrInsertDocumentProperty(xPropertyContainer, sKey, rResult.msName);
898 insertFieldToDocument(xMultiServiceFactory, xHeaderText, xHeaderParagraphCursor, sKey);
899 insertFieldToDocument(xMultiServiceFactory, xFooterText, xFooterParagraphCursor, sKey);
900 }
901 break;
902
904 {
905 OUString sKey = aCreator.makeNumberedIntellectualPropertyPartKey();
906 svx::classification::addOrInsertDocumentProperty(xPropertyContainer, sKey, rResult.msName);
907 insertFieldToDocument(xMultiServiceFactory, xHeaderText, xHeaderParagraphCursor, sKey);
908 insertFieldToDocument(xMultiServiceFactory, xFooterText, xFooterParagraphCursor, sKey);
909 }
910 break;
911
913 {
914 nParagraph++;
915
916 if (nParagraph != 0) // only jump to next paragraph, if we aren't at the first paragraph
917 {
918 xHeaderParagraphCursor->gotoNextParagraph(false);
919 xFooterParagraphCursor->gotoNextParagraph(false);
920 }
921
922 xHeaderParagraphCursor->gotoStartOfParagraph(false);
923 xFooterParagraphCursor->gotoStartOfParagraph(false);
924
925 uno::Reference<beans::XPropertySet> xHeaderPropertySet(xHeaderParagraphCursor, uno::UNO_QUERY_THROW);
926 uno::Reference<beans::XPropertySet> xFooterPropertySet(xFooterParagraphCursor, uno::UNO_QUERY_THROW);
927 if (rResult.msName == "BOLD")
928 {
929 xHeaderPropertySet->setPropertyValue("CharWeight", uno::Any(awt::FontWeight::BOLD));
930 xFooterPropertySet->setPropertyValue("CharWeight", uno::Any(awt::FontWeight::BOLD));
931 }
932 else
933 {
934 xHeaderPropertySet->setPropertyValue("CharWeight", uno::Any(awt::FontWeight::NORMAL));
935 xFooterPropertySet->setPropertyValue("CharWeight", uno::Any(awt::FontWeight::NORMAL));
936 }
937 }
938 break;
939
940 default:
941 break;
942 }
943 }
944 }
945}
946
947std::vector<svx::ClassificationResult> SwEditShell::CollectAdvancedClassification()
948{
949 std::vector<svx::ClassificationResult> aResult;
950
951 SwDocShell* pDocShell = GetDoc()->GetDocShell();
952 if (!pDocShell || !SfxObjectShell::Current())
953 return aResult;
954
955 const OUString sBlank;
956
957 uno::Reference<document::XDocumentProperties> xDocumentProperties = SfxObjectShell::Current()->getDocProperties();
958 uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
960
961 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
962 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
963 uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
964 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
965
966 std::vector<OUString> aPageStyles = lcl_getUsedPageStyles(this);
967 OUString aPageStyleString = aPageStyles.back();
968 uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(aPageStyleString), uno::UNO_QUERY);
969
970 bool bHeaderIsOn = false;
971 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
972 if (!bHeaderIsOn)
973 {
974 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aCreator.makeCategoryNameKey());
975 if (!aValue.isEmpty())
976 aResult.push_back({ svx::ClassificationType::CATEGORY, aValue, sBlank, sBlank });
977
978 return aResult;
979 }
980
981 uno::Reference<text::XText> xHeaderText;
982 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
983
984 uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xHeaderText, uno::UNO_QUERY);
985 uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
986
987 // set to true if category was found in the header
988 bool bFoundClassificationCategory = false;
989
990 while (xParagraphs->hasMoreElements())
991 {
992 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
993 if (!xTextPortionEnumerationAccess.is())
994 continue;
995 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
996
997 // Check font weight
998 uno::Reference<beans::XPropertySet> xParagraphPropertySet(xTextPortionEnumerationAccess, uno::UNO_QUERY_THROW);
999 uno::Any aAny = xParagraphPropertySet->getPropertyValue("CharWeight");
1000
1001 OUString sWeight = (aAny.get<float>() >= awt::FontWeight::BOLD) ? OUString("BOLD") : OUString("NORMAL");
1002
1003 aResult.push_back({ svx::ClassificationType::PARAGRAPH, sWeight, sBlank, sBlank });
1004
1005 // Process portions
1006 while (xTextPortions->hasMoreElements())
1007 {
1008 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
1009 OUString aTextPortionType;
1010 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
1011 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
1012 continue;
1013
1014 uno::Reference<lang::XServiceInfo> xTextField;
1015 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
1016 if (!xTextField->supportsService(DocInfoServiceName))
1017 continue;
1018
1019 OUString aName;
1020 uno::Reference<beans::XPropertySet> xPropertySet(xTextField, uno::UNO_QUERY);
1021 xPropertySet->getPropertyValue(UNO_NAME_NAME) >>= aName;
1022
1023 if (aCreator.isMarkingTextKey(aName))
1024 {
1025 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aName);
1026 if (!aValue.isEmpty())
1027 aResult.push_back({ svx::ClassificationType::TEXT, aValue, sBlank, sBlank });
1028 }
1029 else if (aCreator.isCategoryNameKey(aName))
1030 {
1031 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aName);
1032 if (!aValue.isEmpty())
1033 aResult.push_back({ svx::ClassificationType::CATEGORY, aValue, sBlank, sBlank });
1034 bFoundClassificationCategory = true;
1035 }
1036 else if (aCreator.isCategoryIdentifierKey(aName))
1037 {
1038 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aName);
1039 if (!aValue.isEmpty())
1040 aResult.push_back({ svx::ClassificationType::CATEGORY, sBlank, sBlank, aValue });
1041 bFoundClassificationCategory = true;
1042 }
1043 else if (aCreator.isMarkingKey(aName))
1044 {
1045 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aName);
1046 if (!aValue.isEmpty())
1047 aResult.push_back({ svx::ClassificationType::MARKING, aValue, sBlank, sBlank });
1048 }
1049 else if (aCreator.isIntellectualPropertyPartKey(aName))
1050 {
1051 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aName);
1052 if (!aValue.isEmpty())
1053 aResult.push_back({ svx::ClassificationType::INTELLECTUAL_PROPERTY_PART, aValue, sBlank, sBlank });
1054 }
1055 }
1056 }
1057
1058 if (!bFoundClassificationCategory)
1059 {
1060 const OUString aValue = svx::classification::getProperty(xPropertyContainer, aCreator.makeCategoryNameKey());
1061 if (!aValue.isEmpty())
1062 aResult.push_back({ svx::ClassificationType::CATEGORY, aValue, sBlank, sBlank });
1063 }
1064
1065 return aResult;
1066}
1067
1069{
1070 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1071 if (!pDocShell)
1072 return;
1073
1075
1076 const bool bHadWatermark = !aHelper.GetDocumentWatermark().isEmpty();
1077
1078 // This updates the infobar as well.
1079 aHelper.SetBACName(rName, eType);
1080
1081 // Insert origin document property
1082 uno::Reference<beans::XPropertyContainer> xPropertyContainer = pDocShell->getDocProperties()->getUserDefinedProperties();
1085
1086 bool bHeaderIsNeeded = aHelper.HasDocumentHeader();
1087 bool bFooterIsNeeded = aHelper.HasDocumentFooter();
1088 OUString aWatermark = aHelper.GetDocumentWatermark();
1089 bool bWatermarkIsNeeded = !aWatermark.isEmpty();
1090
1091 if (!bHeaderIsNeeded && !bFooterIsNeeded && !bWatermarkIsNeeded && !bHadWatermark)
1092 return;
1093
1094 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1095 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
1096 uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
1097 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
1098 const uno::Sequence<OUString> aStyles = xStyleFamily->getElementNames();
1099
1100 for (const OUString& rPageStyleName : aStyles)
1101 {
1102 uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
1103 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
1104
1105 if (bHeaderIsNeeded || bWatermarkIsNeeded || bHadWatermark)
1106 {
1107 // If the header is off, turn it on.
1108 bool bHeaderIsOn = false;
1109 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
1110 if (!bHeaderIsOn)
1111 xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_ON, uno::Any(true));
1112
1113 // If the header already contains a document header field, no need to do anything.
1114 uno::Reference<text::XText> xHeaderText;
1115 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
1116
1117 if (bHeaderIsNeeded)
1118 {
1119 if (!lcl_hasField(xHeaderText, DocInfoServiceName, Concat2View(SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY() + SfxClassificationHelper::PROP_DOCHEADER())))
1120 {
1121 // Append a field to the end of the header text.
1122 uno::Reference<beans::XPropertySet> xField(xMultiServiceFactory->createInstance(DocInfoServiceName), uno::UNO_QUERY);
1124 uno::Reference<text::XTextContent> xTextContent(xField, uno::UNO_QUERY);
1125 xHeaderText->insertTextContent(xHeaderText->getEnd(), xTextContent, /*bAbsorb=*/false);
1126 }
1127 }
1128
1129 SfxWatermarkItem aWatermarkItem;
1130 aWatermarkItem.SetText(aWatermark);
1131 SetWatermark(aWatermarkItem);
1132 }
1133
1134 if (bFooterIsNeeded)
1135 {
1136 // If the footer is off, turn it on.
1137 bool bFooterIsOn = false;
1138 xPageStyle->getPropertyValue(UNO_NAME_FOOTER_IS_ON) >>= bFooterIsOn;
1139 if (!bFooterIsOn)
1140 xPageStyle->setPropertyValue(UNO_NAME_FOOTER_IS_ON, uno::Any(true));
1141
1142 // If the footer already contains a document header field, no need to do anything.
1143 uno::Reference<text::XText> xFooterText;
1144 xPageStyle->getPropertyValue(UNO_NAME_FOOTER_TEXT) >>= xFooterText;
1146 if (!lcl_hasField(xFooterText, DocInfoServiceName, sFooter))
1147 {
1148 // Append a field to the end of the footer text.
1149 uno::Reference<beans::XPropertySet> xField(xMultiServiceFactory->createInstance(DocInfoServiceName), uno::UNO_QUERY);
1150 xField->setPropertyValue(UNO_NAME_NAME, uno::Any(sFooter));
1151 uno::Reference<text::XTextContent> xTextContent(xField, uno::UNO_QUERY);
1152 xFooterText->insertTextContent(xFooterText->getEnd(), xTextContent, /*bAbsorb=*/false);
1153 }
1154 }
1155 }
1156}
1157
1158// We pass xParent and xNodeSubject even though they point to the same thing because the UNO_QUERY is
1159// on a performance-sensitive path.
1161 const uno::Reference<frame::XModel>& xModel,
1162 const rtl::Reference<SwXParagraph>& xParent,
1163 const css::uno::Reference<css::rdf::XResource>& xNodeSubject,
1164 std::vector<svx::ClassificationResult> aResults)
1165{
1166 if (!xNodeSubject.is())
1167 return;
1168
1169 // Remove all paragraph classification fields.
1170 for (;;)
1171 {
1172 uno::Reference<text::XTextField> xTextField = lcl_FindParagraphClassificationField(xModel, xParent);
1173 if (!xTextField.is())
1174 break;
1175 lcl_RemoveParagraphMetadataField(xTextField);
1176 }
1177
1178 if (aResults.empty())
1179 return;
1180
1181 // Since we always insert at the start of the paragraph,
1182 // need to insert in reverse order.
1183 std::reverse(aResults.begin(), aResults.end());
1184 // Ignore "PARAGRAPH" types
1185 aResults.erase(std::remove_if(aResults.begin(),
1186 aResults.end(),
1187 [](const svx::ClassificationResult& rResult)-> bool
1188 { return rResult.meType == svx::ClassificationType::PARAGRAPH; }),
1189 aResults.end());
1190
1192 std::vector<OUString> aFieldNames;
1193 for (size_t nIndex = 0; nIndex < aResults.size(); ++nIndex)
1194 {
1195 const svx::ClassificationResult& rResult = aResults[nIndex];
1196
1197 const bool isLast = nIndex == 0;
1198 const bool isFirst = (nIndex == aResults.size() - 1);
1199 OUString sKey;
1200 OUString sValue = rResult.msName;
1201 switch (rResult.meType)
1202 {
1204 {
1205 sKey = aKeyCreator.makeNumberedTextKey();
1206 }
1207 break;
1208
1210 {
1211 if (rResult.msIdentifier.isEmpty())
1212 {
1213 sKey = aKeyCreator.makeCategoryNameKey();
1214 }
1215 else
1216 {
1217 sValue = rResult.msIdentifier;
1218 sKey = aKeyCreator.makeCategoryIdentifierKey();
1219 }
1220 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xNodeSubject, ParagraphClassificationAbbrRDFName, rResult.msAbbreviatedName);
1221 }
1222 break;
1223
1225 {
1226 sKey = aKeyCreator.makeNumberedMarkingKey();
1227 }
1228 break;
1229
1231 {
1232 sKey = aKeyCreator.makeNumberedIntellectualPropertyPartKey();
1233 }
1234 break;
1235
1236 default:
1237 break;
1238 }
1239
1240 OUString sDisplayText = (isFirst ? ("(" + rResult.msAbbreviatedName) : rResult.msAbbreviatedName);
1241 if (isLast)
1242 sDisplayText += ")";
1243 lcl_UpdateParagraphClassificationField(pDoc, xModel, xParent, sKey, sValue, sDisplayText);
1244 aFieldNames.emplace_back(sKey);
1245 }
1246
1247 // Correct the order
1248 std::reverse(aFieldNames.begin(), aFieldNames.end());
1249 OUStringBuffer sFieldNames;
1250 bool first = true;
1251 for (const OUString& rFieldName : aFieldNames)
1252 {
1253 if (!first)
1254 sFieldNames.append("/");
1255 sFieldNames.append(rFieldName);
1256 first = false;
1257 }
1258
1259 const OUString sOldFieldNames = lcl_getRDF(xModel, xNodeSubject, ParagraphClassificationFieldNamesRDFName).second;
1260 SwRDFHelper::removeStatement(xModel, MetaNS, xNodeSubject, ParagraphClassificationFieldNamesRDFName, sOldFieldNames);
1261 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xNodeSubject, ParagraphClassificationFieldNamesRDFName, sFieldNames.makeStringAndClear());
1262}
1263
1264void SwEditShell::ApplyParagraphClassification(std::vector<svx::ClassificationResult> aResults)
1265{
1266 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1267 if (!pDocShell || !GetCursor() || !GetCursor()->Start())
1268 return;
1269
1270 SwTextNode* pNode = GetCursor()->Start()->GetNode().GetTextNode();
1271 if (pNode == nullptr)
1272 return;
1273
1274 // Prevent recursive validation since this is triggered on node updates, which we do below.
1275 const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1276 comphelper::ScopeGuard const g([this, bOldValidationFlag]() {
1277 SetParagraphSignatureValidation(bOldValidationFlag);
1278 });
1279
1280 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1282 lcl_ApplyParagraphClassification(GetDoc(), xModel, xParent, css::uno::Reference<css::rdf::XResource>(xParent), std::move(aResults));
1283}
1284
1285static std::vector<svx::ClassificationResult> lcl_CollectParagraphClassification(const uno::Reference<frame::XModel>& xModel, const uno::Reference<text::XTextContent>& xParagraph)
1286{
1287 std::vector<svx::ClassificationResult> aResult;
1288
1289 uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraph, uno::UNO_QUERY);
1290 if (!xTextPortionEnumerationAccess.is())
1291 return aResult;
1292
1293 uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
1294
1296
1297 while (xTextPortions->hasMoreElements())
1298 {
1299 uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
1300 OUString aTextPortionType;
1301 xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
1302 if (aTextPortionType != UNO_NAME_TEXT_FIELD)
1303 continue;
1304
1305 uno::Reference<lang::XServiceInfo> xField;
1306 xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xField;
1307 if (!xField->supportsService(MetadataFieldServiceName))
1308 continue;
1309
1310 uno::Reference<text::XTextField> xTextField(xField, uno::UNO_QUERY);
1312 const std::pair<OUString, OUString> rdfNamePair = lcl_getFieldRDFByPrefix(xModel, xTextField, sPolicy);
1313
1314 uno::Reference<text::XTextRange> xTextRange(xField, uno::UNO_QUERY);
1315 const OUString aName = rdfNamePair.first;
1316 const OUString aValue = rdfNamePair.second;
1317 static const OUStringLiteral sBlank(u"");
1318 if (aKeyCreator.isMarkingTextKey(aName))
1319 {
1320 aResult.push_back({ svx::ClassificationType::TEXT, aValue, sBlank, sBlank });
1321 }
1322 else if (aKeyCreator.isCategoryNameKey(aName))
1323 {
1324 aResult.push_back({ svx::ClassificationType::CATEGORY, aValue, sBlank, sBlank });
1325 }
1326 else if (aKeyCreator.isCategoryIdentifierKey(aName))
1327 {
1328 aResult.push_back({ svx::ClassificationType::CATEGORY, sBlank, sBlank, aValue });
1329 }
1330 else if (aKeyCreator.isMarkingKey(aName))
1331 {
1332 aResult.push_back({ svx::ClassificationType::MARKING, aValue, sBlank, sBlank });
1333 }
1334 else if (aKeyCreator.isIntellectualPropertyPartKey(aName))
1335 {
1336 aResult.push_back({ svx::ClassificationType::INTELLECTUAL_PROPERTY_PART, xTextRange->getString(), sBlank, sBlank });
1337 }
1338 }
1339
1340 return aResult;
1341}
1342
1343std::vector<svx::ClassificationResult> SwEditShell::CollectParagraphClassification()
1344{
1345 std::vector<svx::ClassificationResult> aResult;
1346
1347 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1348 if (!pDocShell || !GetCursor() || !GetCursor()->Start())
1349 return aResult;
1350
1351 SwTextNode* pNode = GetCursor()->Start()->GetNode().GetTextNode();
1352 if (pNode == nullptr)
1353 return aResult;
1354
1355 uno::Reference<text::XTextContent> xParent = SwXParagraph::CreateXParagraph(pNode->GetDoc(), pNode);
1356 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1358}
1359
1360static sal_Int16 lcl_GetAngle(const drawing::HomogenMatrix3& rMatrix)
1361{
1362 basegfx::B2DHomMatrix aTransformation;
1363 basegfx::B2DTuple aScale;
1364 basegfx::B2DTuple aTranslate;
1365 double fRotate = 0;
1366 double fShear = 0;
1367
1368 aTransformation.set(0, 0, rMatrix.Line1.Column1);
1369 aTransformation.set(0, 1, rMatrix.Line1.Column2);
1370 aTransformation.set(0, 2, rMatrix.Line1.Column3);
1371 aTransformation.set(1, 0, rMatrix.Line2.Column1);
1372 aTransformation.set(1, 1, rMatrix.Line2.Column2);
1373 aTransformation.set(1, 2, rMatrix.Line2.Column3);
1374 aTransformation.set(2, 0, rMatrix.Line3.Column1);
1375 aTransformation.set(2, 1, rMatrix.Line3.Column2);
1376 aTransformation.set(2, 2, rMatrix.Line3.Column3);
1377
1378 aTransformation.decompose(aScale, aTranslate, fRotate, fShear);
1379 sal_Int16 nDeg = round(basegfx::rad2deg(fRotate));
1380 return nDeg < 0 ? round(nDeg) * -1 : round(360.0 - nDeg);
1381}
1382
1384{
1385 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1386 if (!pDocShell)
1387 return SfxWatermarkItem();
1388
1389 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1390 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
1391 uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
1392 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
1393 std::vector<OUString> aUsedPageStyles = lcl_getUsedPageStyles(this);
1394 for (const OUString& rPageStyleName : aUsedPageStyles)
1395 {
1396 uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
1397
1398 bool bHeaderIsOn = false;
1399 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
1400 if (!bHeaderIsOn)
1401 return SfxWatermarkItem();
1402
1403 uno::Reference<text::XText> xHeaderText;
1404 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
1405
1406 OUString sWatermark = "";
1407 bool bSuccess = false;
1408 uno::Reference<drawing::XShape> xWatermark = lcl_getWatermark(xHeaderText, "com.sun.star.drawing.CustomShape", sWatermark, bSuccess);
1409
1410 if (xWatermark.is())
1411 {
1412 SfxWatermarkItem aItem;
1413 uno::Reference<text::XTextRange> xTextRange(xWatermark, uno::UNO_QUERY);
1414 uno::Reference<beans::XPropertySet> xPropertySet(xWatermark, uno::UNO_QUERY);
1415 Color nColor;
1416 sal_Int16 nTransparency;
1417 OUString aFont;
1418 drawing::HomogenMatrix3 aMatrix;
1419
1420 aItem.SetText(xTextRange->getString());
1421
1422 if (xPropertySet->getPropertyValue(UNO_NAME_CHAR_FONT_NAME) >>= aFont)
1423 aItem.SetFont(aFont);
1424 if (xPropertySet->getPropertyValue(UNO_NAME_FILLCOLOR) >>= nColor)
1425 aItem.SetColor(nColor);
1426 if (xPropertySet->getPropertyValue("Transformation") >>= aMatrix)
1427 aItem.SetAngle(lcl_GetAngle(aMatrix));
1428 if (xPropertySet->getPropertyValue(UNO_NAME_FILL_TRANSPARENCE) >>= nTransparency)
1429 aItem.SetTransparency(nTransparency);
1430
1431 return aItem;
1432 }
1433 }
1434 return SfxWatermarkItem();
1435}
1436
1437static void lcl_placeWatermarkInHeader(const SfxWatermarkItem& rWatermark,
1438 const uno::Reference<frame::XModel>& xModel,
1439 const uno::Reference<beans::XPropertySet>& xPageStyle,
1440 const uno::Reference<text::XText>& xHeaderText)
1441{
1442 if (!xHeaderText.is())
1443 return;
1444
1445 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
1446 OUString aShapeServiceName = "com.sun.star.drawing.CustomShape";
1447 OUString sWatermark = WATERMARK_NAME;
1448 bool bSuccess = false;
1449 uno::Reference<drawing::XShape> xWatermark = lcl_getWatermark(xHeaderText, aShapeServiceName, sWatermark, bSuccess);
1450
1451 bool bDeleteWatermark = rWatermark.GetText().isEmpty();
1452 if (xWatermark.is())
1453 {
1454 drawing::HomogenMatrix3 aMatrix;
1455 Color nColor = 0xc0c0c0;
1456 sal_Int16 nTransparency = 50;
1457 sal_Int16 nAngle = 45;
1458 OUString aFont = "";
1459
1460 uno::Reference<beans::XPropertySet> xPropertySet(xWatermark, uno::UNO_QUERY);
1461 xPropertySet->getPropertyValue(UNO_NAME_CHAR_FONT_NAME) >>= aFont;
1462 xPropertySet->getPropertyValue(UNO_NAME_FILLCOLOR) >>= nColor;
1463 xPropertySet->getPropertyValue(UNO_NAME_FILL_TRANSPARENCE) >>= nTransparency;
1464 xPropertySet->getPropertyValue("Transformation") >>= aMatrix;
1465 nAngle = lcl_GetAngle(aMatrix);
1466
1467 // If the header already contains a watermark, see if it its text is up to date.
1468 uno::Reference<text::XTextRange> xTextRange(xWatermark, uno::UNO_QUERY);
1469 if (xTextRange->getString() != rWatermark.GetText()
1470 || aFont != rWatermark.GetFont()
1471 || nColor != rWatermark.GetColor()
1472 || nAngle != rWatermark.GetAngle()
1473 || nTransparency != rWatermark.GetTransparency()
1474 || bDeleteWatermark)
1475 {
1476 // No: delete it and we'll insert a replacement.
1477 uno::Reference<lang::XComponent> xComponent(xWatermark, uno::UNO_QUERY);
1478 xComponent->dispose();
1479 xWatermark.clear();
1480 }
1481 }
1482
1483 if (!bSuccess || xWatermark.is() || bDeleteWatermark)
1484 return;
1485
1486 const OUString& sFont = rWatermark.GetFont();
1487 sal_Int16 nAngle = rWatermark.GetAngle();
1488 sal_Int16 nTransparency = rWatermark.GetTransparency();
1489 Color nColor = rWatermark.GetColor();
1490
1491 // Calc the ratio.
1492 double fRatio = 0;
1493
1495 vcl::Font aFont = pDevice->GetFont();
1496 aFont.SetFamilyName(sFont);
1497 aFont.SetFontSize(Size(0, 96));
1498 pDevice->SetFont(aFont);
1499
1500 auto nTextWidth = pDevice->GetTextWidth(rWatermark.GetText());
1501 if (nTextWidth)
1502 {
1503 fRatio = pDevice->GetTextHeight();
1504 fRatio /= nTextWidth;
1505 }
1506
1507 // Calc the size.
1508 sal_Int32 nWidth = 0;
1509 awt::Size aSize;
1510 xPageStyle->getPropertyValue(UNO_NAME_SIZE) >>= aSize;
1511 if (aSize.Width < aSize.Height)
1512 {
1513 // Portrait.
1514 sal_Int32 nLeftMargin = 0;
1515 xPageStyle->getPropertyValue(UNO_NAME_LEFT_MARGIN) >>= nLeftMargin;
1516 sal_Int32 nRightMargin = 0;
1517 xPageStyle->getPropertyValue(UNO_NAME_RIGHT_MARGIN) >>= nRightMargin;
1518 nWidth = aSize.Width - nLeftMargin - nRightMargin;
1519 }
1520 else
1521 {
1522 // Landscape.
1523 sal_Int32 nTopMargin = 0;
1524 xPageStyle->getPropertyValue(UNO_NAME_TOP_MARGIN) >>= nTopMargin;
1525 sal_Int32 nBottomMargin = 0;
1526 xPageStyle->getPropertyValue(UNO_NAME_BOTTOM_MARGIN) >>= nBottomMargin;
1527 nWidth = aSize.Height - nTopMargin - nBottomMargin;
1528 }
1529 sal_Int32 nHeight = fRatio * nWidth;
1530
1531 // Create and insert the shape.
1532 uno::Reference<drawing::XShape> xShape(xMultiServiceFactory->createInstance(aShapeServiceName), uno::UNO_QUERY);
1533
1534 uno::Reference<container::XNamed> xNamed(xShape, uno::UNO_QUERY);
1535 xNamed->setName(sWatermark);
1536
1537 basegfx::B2DHomMatrix aTransformation;
1538 aTransformation.identity();
1539 aTransformation.scale(nWidth, nHeight);
1540 aTransformation.rotate(-basegfx::deg2rad(nAngle));
1541 drawing::HomogenMatrix3 aMatrix;
1542 aMatrix.Line1.Column1 = aTransformation.get(0, 0);
1543 aMatrix.Line1.Column2 = aTransformation.get(0, 1);
1544 aMatrix.Line1.Column3 = aTransformation.get(0, 2);
1545 aMatrix.Line2.Column1 = aTransformation.get(1, 0);
1546 aMatrix.Line2.Column2 = aTransformation.get(1, 1);
1547 aMatrix.Line2.Column3 = aTransformation.get(1, 2);
1548 aMatrix.Line3.Column1 = aTransformation.get(2, 0);
1549 aMatrix.Line3.Column2 = aTransformation.get(2, 1);
1550 aMatrix.Line3.Column3 = aTransformation.get(2, 2);
1551 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1552 xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1553 uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY);
1554 xHeaderText->insertTextContent(xHeaderText->getEnd(), xTextContent, false);
1555
1556 // The remaining properties have to be set after the shape is inserted: do that in one batch to avoid flickering.
1557 uno::Reference<document::XActionLockable> xLockable(xShape, uno::UNO_QUERY);
1558 xLockable->addActionLock();
1559 xPropertySet->setPropertyValue(UNO_NAME_FILLCOLOR, uno::Any(static_cast<sal_Int32>(nColor)));
1560 xPropertySet->setPropertyValue(UNO_NAME_FILLSTYLE, uno::Any(drawing::FillStyle_SOLID));
1561 xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::Any(nTransparency));
1562 xPropertySet->setPropertyValue(UNO_NAME_LINESTYLE, uno::Any(drawing::LineStyle_NONE));
1563 xPropertySet->setPropertyValue(UNO_NAME_OPAQUE, uno::Any(false));
1564 xPropertySet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any(false));
1565 xPropertySet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any(false));
1566 xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEHEIGHT, uno::Any(nHeight));
1567 xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEWIDTH, uno::Any(nWidth));
1568 xPropertySet->setPropertyValue(UNO_NAME_TEXT_WRAP, uno::Any(text::WrapTextMode_THROUGH));
1569 xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION, uno::Any(text::RelOrientation::PAGE_PRINT_AREA));
1570 xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION, uno::Any(text::RelOrientation::PAGE_PRINT_AREA));
1571 xPropertySet->setPropertyValue(UNO_NAME_CHAR_FONT_NAME, uno::Any(sFont));
1572 xPropertySet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::Any(WATERMARK_AUTO_SIZE));
1573 xPropertySet->setPropertyValue("Transformation", uno::Any(aMatrix));
1574
1575 uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
1576 xTextRange->setString(rWatermark.GetText());
1577
1578 uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
1579 xDefaulter->createCustomShapeDefaults("fontwork-plain-text");
1580
1581 auto aGeomPropSeq = xPropertySet->getPropertyValue("CustomShapeGeometry").get< uno::Sequence<beans::PropertyValue> >();
1582 auto aGeomPropVec = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aGeomPropSeq);
1583 uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
1584 {
1585 {"TextPath", uno::Any(true)},
1586 }));
1587 auto it = std::find_if(aGeomPropVec.begin(), aGeomPropVec.end(), [](const beans::PropertyValue& rValue)
1588 {
1589 return rValue.Name == "TextPath";
1590 });
1591 if (it == aGeomPropVec.end())
1592 aGeomPropVec.push_back(comphelper::makePropertyValue("TextPath", aPropertyValues));
1593 else
1594 it->Value <<= aPropertyValues;
1595 xPropertySet->setPropertyValue("CustomShapeGeometry", uno::Any(comphelper::containerToSequence(aGeomPropVec)));
1596
1597 // tdf#108494, tdf#109313 the header height was switched to height of a watermark
1598 // and shape was moved to the lower part of a page, force position update
1599 xPropertySet->getPropertyValue("Transformation") >>= aMatrix;
1600 xPropertySet->setPropertyValue("Transformation", uno::Any(aMatrix));
1601
1602 xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT, uno::Any(text::HoriOrientation::CENTER));
1603 xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT, uno::Any(text::VertOrientation::CENTER));
1604
1605 xLockable->removeActionLock();
1606}
1607
1609{
1610 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1611 if (!pDocShell)
1612 return;
1613 const bool bNoWatermark = rWatermark.GetText().isEmpty();
1614
1615 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1616 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
1617 uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
1618 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
1619 const uno::Sequence<OUString> aStyles = xStyleFamily->getElementNames();
1620
1621 for (const OUString& rPageStyleName : aStyles)
1622 {
1623 uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
1624
1625 // If the header is off, turn it on.
1626 bool bHeaderIsOn = false;
1627 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
1628 if (!bHeaderIsOn)
1629 {
1630 if (bNoWatermark)
1631 continue; // the style doesn't have any watermark - no need to do anything
1632
1633 xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_ON, uno::Any(true));
1634 }
1635
1636 // backup header height
1637 bool bDynamicHeight = true;
1638 sal_Int32 nOldValue;
1639 xPageStyle->getPropertyValue(UNO_NAME_HEADER_HEIGHT) >>= nOldValue;
1640 xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT) >>= bDynamicHeight;
1641 xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT, uno::Any(false));
1642
1643 // If the header already contains a document header field, no need to do anything.
1644 uno::Reference<text::XText> xHeaderText;
1645 uno::Reference<text::XText> xHeaderTextFirst;
1646 uno::Reference<text::XText> xHeaderTextLeft;
1647 uno::Reference<text::XText> xHeaderTextRight;
1648
1649 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
1650 lcl_placeWatermarkInHeader(rWatermark, xModel, xPageStyle, xHeaderText);
1651
1652 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT_FIRST) >>= xHeaderTextFirst;
1653 lcl_placeWatermarkInHeader(rWatermark, xModel, xPageStyle, xHeaderTextFirst);
1654
1655 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT_LEFT) >>= xHeaderTextLeft;
1656 lcl_placeWatermarkInHeader(rWatermark, xModel, xPageStyle, xHeaderTextLeft);
1657
1658 xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT_RIGHT) >>= xHeaderTextRight;
1659 lcl_placeWatermarkInHeader(rWatermark, xModel, xPageStyle, xHeaderTextRight);
1660
1661 // tdf#108494 the header height was switched to height of a watermark
1662 // and shape was moved to the lower part of a page
1663 xPageStyle->setPropertyValue(UNO_NAME_HEADER_HEIGHT, uno::Any(sal_Int32(11)));
1664 xPageStyle->setPropertyValue(UNO_NAME_HEADER_HEIGHT, uno::Any(nOldValue));
1665 xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT, uno::Any(bDynamicHeight));
1666 }
1667}
1668
1670 uno::Reference<text::XTextField> xField,
1671 uno::Reference<text::XTextContent> xParent,
1672 const bool bRemove)
1673 : SwUndo(SwUndoId::PARA_SIGN_ADD, &rDoc),
1674 m_rDoc(rDoc),
1675 m_xField(std::move(xField)),
1676 m_xParent(std::move(xParent)),
1677 m_bRemove(bRemove)
1678{
1679 // Save the metadata and field content to undo/redo.
1680 uno::Reference<frame::XModel> xModel = m_rDoc.GetDocShell()->GetBaseModel();
1681 const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, m_xField);
1682 const auto it = aStatements.find(ParagraphSignatureIdRDFName);
1683 if (it != aStatements.end())
1684 m_signature = it->second;
1685
1686 const auto it2 = aStatements.find(ParagraphSignatureUsageRDFName);
1687 if (it2 != aStatements.end())
1688 m_usage = it2->second;
1689
1690 uno::Reference<css::text::XTextRange> xText(m_xField, uno::UNO_QUERY);
1691 m_display = xText->getString();
1692}
1693
1695{
1696 if (m_bRemove)
1697 Remove();
1698 else
1699 Insert();
1700}
1701
1703{
1704 if (m_bRemove)
1705 Insert();
1706 else
1707 Remove();
1708}
1709
1711{
1712}
1713
1715{
1716 // Disable undo to avoid introducing noise when we edit the metadata field.
1717 const bool isUndoEnabled = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
1719
1720 // Prevent validation since this will trigger a premature validation
1721 // upon inserting, but before setting the metadata.
1722 SwEditShell* pEditSh = m_rDoc.GetEditShell();
1723 const bool bOldValidationFlag = pEditSh->SetParagraphSignatureValidation(false);
1724 comphelper::ScopeGuard const g([&] () {
1725 pEditSh->SetParagraphSignatureValidation(bOldValidationFlag);
1726 m_rDoc.GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
1727 });
1728
1729 m_xField = lcl_InsertParagraphSignature(m_rDoc.GetDocShell()->GetBaseModel(), m_xParent, m_signature, m_usage);
1730 lcl_DoUpdateParagraphSignatureField(m_rDoc, m_xField, m_display);
1731}
1732
1734{
1735 // Disable undo to avoid introducing noise when we edit the metadata field.
1736 const bool isUndoEnabled = m_rDoc.GetIDocumentUndoRedo().DoesUndo();
1738
1739 // Prevent validation since this will trigger a premature validation
1740 // upon removing.
1741 SwEditShell* pEditSh = m_rDoc.GetEditShell();
1742 const bool bOldValidationFlag = pEditSh->SetParagraphSignatureValidation(false);
1743 comphelper::ScopeGuard const g([&] () {
1744 pEditSh->SetParagraphSignatureValidation(bOldValidationFlag);
1745 m_rDoc.GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
1746 });
1747
1748 lcl_RemoveParagraphMetadataField(m_xField);
1749}
1750
1752{
1753 SwDoc& rDoc = *GetDoc();
1754 SwDocShell* pDocShell = rDoc.GetDocShell();
1755 if (!pDocShell || !GetCursor() || !GetCursor()->Start())
1756 return;
1757 const SwPosition* pPosStart = GetCursor()->Start();
1758 if (!pPosStart)
1759 return;
1760 SwTextNode* pNode = pPosStart->GetNode().GetTextNode();
1761 if (!pNode)
1762 return;
1763
1764 // Table text signing is not supported.
1765 if (pNode->FindTableNode() != nullptr)
1766 return;
1767
1768 // 1. Get the text (without fields).
1769 const uno::Reference<text::XTextContent> xParagraph = SwXParagraph::CreateXParagraph(pNode->GetDoc(), pNode);
1770 const OString utf8Text = lcl_getParagraphBodyText(xParagraph);
1771 if (utf8Text.isEmpty())
1772 return;
1773
1774 // 2. Get certificate.
1775 uno::Reference<security::XDocumentDigitalSignatures> xSigner(
1776 // here none of the version-dependent methods are called
1777 security::DocumentDigitalSignatures::createDefault(
1779
1780 uno::Sequence<css::beans::PropertyValue> aProperties;
1781 uno::Reference<security::XCertificate> xCertificate = xSigner->chooseCertificateWithProps(aProperties);
1782 if (!xCertificate.is())
1783 return;
1784
1785 // 3. Sign it.
1786 svl::crypto::Signing signing(xCertificate);
1787 signing.AddDataRange(utf8Text.getStr(), utf8Text.getLength());
1788 OStringBuffer sigBuf;
1789 if (!signing.Sign(sigBuf))
1790 return;
1791
1792 const OUString signature = OStringToOUString(sigBuf, RTL_TEXTENCODING_UTF8, 0);
1793
1794 auto it = std::find_if(std::as_const(aProperties).begin(), std::as_const(aProperties).end(), [](const beans::PropertyValue& rValue)
1795 {
1796 return rValue.Name == "Usage";
1797 });
1798
1799 OUString aUsage;
1800 if (it != std::as_const(aProperties).end())
1801 it->Value >>= aUsage;
1802
1803 // 4. Add metadata
1804 // Prevent validation since this will trigger a premature validation
1805 // upon inserting, but before setting the metadata.
1806 const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1807 comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1808 SetParagraphSignatureValidation(bOldValidationFlag);
1809 });
1810
1812
1813 const uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1814 uno::Reference<css::text::XTextField> xField = lcl_InsertParagraphSignature(xModel, xParagraph, signature, aUsage);
1815
1816 lcl_UpdateParagraphSignatureField(*GetDoc(), xModel, xParagraph, xField, utf8Text);
1817
1819 std::make_unique<SwUndoParagraphSigning>(rDoc, xField, xParagraph, true));
1820
1822}
1823
1824void SwEditShell::ValidateParagraphSignatures(SwTextNode* pNode, bool updateDontRemove)
1825{
1827 return;
1828
1829 // Table text signing is not supported.
1830 if (pNode->FindTableNode() != nullptr)
1831 return;
1832
1833 // Prevent recursive validation since this is triggered on node updates, which we do below.
1834 const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1835 comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1836 SetParagraphSignatureValidation(bOldValidationFlag);
1837 });
1838
1839 uno::Reference<text::XTextContent> xParentText = SwXParagraph::CreateXParagraph(*GetDoc(), pNode);
1840 lcl_ValidateParagraphSignatures(*GetDoc(), xParentText, updateDontRemove);
1841}
1842
1844{
1845 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1846 if (!pDocShell || !GetCursor() || !GetCursor()->Start() || !IsParagraphSignatureValidationEnabled())
1847 return;
1848
1849 SwPaM* pPaM = GetCursor();
1850 const SwPosition* pPosStart = pPaM->Start();
1851 SwTextNode* pNode = pPosStart->GetNode().GetTextNode();
1852 ValidateParagraphSignatures(pNode, updateDontRemove);
1853}
1854
1856{
1857 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1858 if (!pDocShell || !IsParagraphSignatureValidationEnabled())
1859 return;
1860
1861 // Prevent recursive validation since this is triggered on node updates, which we do below.
1862 const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1863 comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1864 SetParagraphSignatureValidation(bOldValidationFlag);
1865 });
1866
1867 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1868 const uno::Reference<text::XTextDocument> xDoc(xModel, uno::UNO_QUERY);
1869 uno::Reference<text::XText> xParent = xDoc->getText();
1870 uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xParent, uno::UNO_QUERY);
1871 if (!xParagraphEnumerationAccess.is())
1872 return;
1873 uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
1874 if (!xParagraphs.is())
1875 return;
1876 while (xParagraphs->hasMoreElements())
1877 {
1878 uno::Reference<text::XTextContent> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
1879 lcl_ValidateParagraphSignatures(*GetDoc(), xParagraph, updateDontRemove);
1880 }
1881}
1882
1883static uno::Reference<text::XTextField> lcl_GetParagraphMetadataFieldAtIndex(const SwDocShell* pDocSh, SwTextNode const * pNode, const sal_uLong index)
1884{
1885 uno::Reference<text::XTextField> xTextField;
1886 if (pNode != nullptr && pDocSh != nullptr)
1887 {
1889 SwTextMeta* pTextMeta = static_txtattr_cast<SwTextMeta*>(pAttr);
1890 if (pTextMeta != nullptr)
1891 {
1892 SwFormatMeta& rFormatMeta(static_cast<SwFormatMeta&>(pTextMeta->GetAttr()));
1893 if (::sw::Meta* pMeta = rFormatMeta.GetMeta())
1894 {
1895 const css::uno::Reference<css::rdf::XResource> xSubject = pMeta->MakeUnoObject();
1896 uno::Reference<frame::XModel> xModel = pDocSh->GetBaseModel();
1897 const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xSubject);
1898 if (aStatements.find(ParagraphSignatureIdRDFName) != aStatements.end() ||
1899 aStatements.find(ParagraphClassificationNameRDFName) != aStatements.end())
1900 {
1901 xTextField = uno::Reference<text::XTextField>(xSubject, uno::UNO_QUERY);
1902 }
1903 }
1904 }
1905 }
1906
1907 return xTextField;
1908}
1909
1911{
1912 SwDocShell* pDocShell = GetDoc()->GetDocShell();
1913 if (!pDocShell || !IsParagraphSignatureValidationEnabled())
1914 return;
1915
1916 // Prevent recursive validation since this is triggered on node updates, which we do below.
1917 const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1918 comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1919 SetParagraphSignatureValidation(bOldValidationFlag);
1920 });
1921
1922 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1923 const rtl::Reference<SwXTextDocument> xDoc(dynamic_cast<SwXTextDocument*>(xModel.get()));
1924 rtl::Reference<SwXBodyText> xBodyText = xDoc->getBodyText();
1925 if (!xBodyText.is())
1926 return;
1927 rtl::Reference<SwXParagraphEnumeration> xParagraphs = xBodyText->createParagraphEnumeration();
1928
1929 static constexpr OUStringLiteral sBlank(u"");
1931 const css::uno::Sequence<css::uno::Reference<rdf::XURI>> aGraphNames = SwRDFHelper::getGraphNames(xModel, MetaNS);
1932
1933 while (xParagraphs->hasMoreElements())
1934 {
1935 uno::Reference<text::XTextContent> xParaOrTable(xParagraphs->nextElement(), uno::UNO_QUERY);
1936 rtl::Reference<SwXParagraph> xParagraph(dynamic_cast<SwXParagraph*>(xParaOrTable.get()));
1937
1938 try
1939 {
1940 const css::uno::Reference<css::rdf::XResource> xSubject(xParagraph);
1941 const std::map<OUString, OUString> aStatements = SwRDFHelper::getStatements(xModel, aGraphNames, xSubject);
1942
1943 const auto it = aStatements.find(ParagraphClassificationFieldNamesRDFName);
1944 const OUString sFieldNames = (it != aStatements.end() ? it->second : sBlank);
1945 std::vector<svx::ClassificationResult> aResults;
1946 if (!sFieldNames.isEmpty())
1947 {
1948 assert(it != aStatements.end() && "can only be non-empty if it was valid");
1949 // Order the fields
1950 sal_Int32 nIndex = 0;
1951 do
1952 {
1953 const OUString sCurFieldName = sFieldNames.getToken(0, '/', nIndex);
1954 if (sCurFieldName.isEmpty())
1955 break;
1956
1957 const auto it2 = aStatements.find(sCurFieldName);
1958 bool bStatementFound = it2 != aStatements.end();
1959 const OUString sName = bStatementFound ? it->first : sBlank;
1960 const OUString sValue = bStatementFound ? it->second : sBlank;
1961
1962 if (aKeyCreator.isMarkingTextKey(sName))
1963 {
1964 aResults.push_back({ svx::ClassificationType::TEXT, sValue, sValue, sBlank });
1965 }
1966 else if (aKeyCreator.isCategoryNameKey(sName))
1967 {
1968 const auto it3 = aStatements.find(ParagraphClassificationAbbrRDFName);
1969 const OUString sAbbreviatedName = (it3 != aStatements.end() && !it3->second.isEmpty() ? it3->second : sValue);
1970 aResults.push_back({ svx::ClassificationType::CATEGORY, sValue, sAbbreviatedName, sBlank });
1971 }
1972 else if (aKeyCreator.isCategoryIdentifierKey(sName))
1973 {
1974 const auto it3 = aStatements.find(ParagraphClassificationAbbrRDFName);
1975 const OUString sAbbreviatedName = (it3 != aStatements.end() && !it3->second.isEmpty() ? it3->second : sValue);
1976 aResults.push_back({ svx::ClassificationType::CATEGORY, sBlank, sAbbreviatedName, sValue });
1977 }
1978 else if (aKeyCreator.isMarkingKey(sName))
1979 {
1980 aResults.push_back({ svx::ClassificationType::MARKING, sValue, sValue, sBlank });
1981 }
1982 else if (aKeyCreator.isIntellectualPropertyPartKey(sName))
1983 {
1984 aResults.push_back({ svx::ClassificationType::INTELLECTUAL_PROPERTY_PART, sValue, sValue, sBlank });
1985 }
1986 }
1987 while (nIndex >= 0);
1988 }
1989
1990 // Update classification based on results.
1991 lcl_ApplyParagraphClassification(GetDoc(), xModel, xParagraph, xSubject, aResults);
1992
1993 // Get Signatures
1994 std::map<OUString, SignatureDescr> aSignatures;
1995 for (const auto& pair : lcl_getRDFStatements(xModel, uno::Reference<css::text::XTextContent>(xParagraph)))
1996 {
1997 const OUString& sName = pair.first;
1998 if (sName.startsWith(ParagraphSignatureRDFNamespace))
1999 {
2000 const OUString sSuffix = sName.copy(ParagraphSignatureRDFNamespace.getLength());
2001 const sal_Int32 index = sSuffix.indexOf(":");
2002 if (index >= 0)
2003 {
2004 const OUString id = sSuffix.copy(0, index);
2005 const OUString type = sSuffix.copy(index);
2006 const OUString& sValue = pair.second;
2007 if (type == ParagraphSignatureDateRDFName)
2008 aSignatures[id].msDate = sValue;
2009 else if (type == ParagraphSignatureUsageRDFName)
2010 aSignatures[id].msUsage = sValue;
2011 else if (type == ParagraphSignatureDigestRDFName)
2012 aSignatures[id].msSignature = sValue;
2013 }
2014 }
2015 }
2016
2017 for (const auto& pair : aSignatures)
2018 {
2019 uno::Reference<text::XTextField> xField = lcl_findFieldByRDF(xModel, xParagraph, ParagraphSignatureIdRDFName, pair.first);
2020 if (!xField.is())
2021 {
2022 uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
2023 xField = uno::Reference<text::XTextField>(xMultiServiceFactory->createInstance(MetadataFieldServiceName), uno::UNO_QUERY);
2024
2025 // Add the signature at the end.
2026 xField->attach(xParagraph->getAnchor()->getEnd());
2027
2028 const css::uno::Reference<css::rdf::XResource> xFieldSubject(xField, uno::UNO_QUERY);
2029 SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xFieldSubject, ParagraphSignatureIdRDFName, pair.first);
2030
2031 const OString utf8Text = lcl_getParagraphBodyText(xParagraph);
2032 lcl_UpdateParagraphSignatureField(*GetDoc(), xModel, xParagraph, xField, utf8Text);
2033 }
2034 }
2035
2036 lcl_ValidateParagraphSignatures(*GetDoc(), xParagraph, true); // Validate and Update signatures.
2037 }
2038 catch (const std::exception&)
2039 {
2040 }
2041 }
2042}
2043
2045{
2046 if (GetCursor() && GetCursor()->Start())
2047 {
2048 SwTextNode* pNode = GetCursor()->Start()->GetNode().GetTextNode();
2050 uno::Reference<text::XTextField> xField = lcl_GetParagraphMetadataFieldAtIndex(GetDoc()->GetDocShell(), pNode, index);
2051 return xField.is();
2052 }
2053
2054 return false;
2055}
2056
2058{
2059 if (GetCursor() && GetCursor()->Start())
2060 {
2061 SwTextNode* pNode = GetCursor()->Start()->GetNode().GetTextNode();
2063 uno::Reference<text::XTextField> xField = lcl_GetParagraphMetadataFieldAtIndex(GetDoc()->GetDocShell(), pNode, index);
2064 if (!xField.is())
2065 {
2066 // Try moving the cursor to see if we're _facing_ a metafield or not,
2067 // as opposed to being within one.
2068 index--; // Backspace moves left
2069
2070 xField = lcl_GetParagraphMetadataFieldAtIndex(GetDoc()->GetDocShell(), pNode, index);
2071 }
2072
2073 if (xField.is())
2074 {
2075 lcl_RemoveParagraphMetadataField(xField);
2076 return true;
2077 }
2078 }
2079
2080 return false;
2081}
2082
2084 const uno::Reference<frame::XModel>& xModel, const rtl::Reference<SwXParagraph>& xParagraph)
2085{
2086 uno::Reference<text::XTextField> xTextField;
2087 xTextField = lcl_FindParagraphClassificationField(xModel, xParagraph, rKeyCreator.makeCategoryIdentifierKey());
2088 if (xTextField.is())
2089 {
2090 const std::pair<OUString, OUString> rdfValuePair = lcl_getRDF(xModel, xTextField, ParagraphClassificationValueRDFName);
2091 return rHelper.GetBACNameForIdentifier(rdfValuePair.second);
2092 }
2093
2094 xTextField = lcl_FindParagraphClassificationField(xModel, xParagraph, rKeyCreator.makeCategoryNameKey());
2095 if (xTextField.is())
2096 {
2097 return lcl_getRDF(xModel, xTextField, ParagraphClassificationNameRDFName).second;
2098 }
2099
2100 return OUString();
2101}
2102
2104{
2105 OUString sHighestClass;
2106
2107 SwTextNode* pNode = pCursor->Start()->GetNode().GetTextNode();
2108 if (pNode == nullptr)
2109 return sHighestClass;
2110
2111 SwDocShell* pDocShell = pNode->GetDoc().GetDocShell();
2112 if (!pDocShell)
2113 return sHighestClass;
2114
2117
2118 uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
2119 const rtl::Reference<SwXTextDocument> xDoc(dynamic_cast<SwXTextDocument*>(xModel.get()));
2120 rtl::Reference<SwXBodyText> xBodyText = xDoc->getBodyText();
2121
2122 rtl::Reference<SwXParagraphEnumeration> xParagraphs = xBodyText->createParagraphEnumeration();
2123 while (xParagraphs->hasMoreElements())
2124 {
2125 uno::Reference<text::XTextContent> xParaOrTable(xParagraphs->nextElement(), uno::UNO_QUERY);
2126 rtl::Reference<SwXParagraph> xParagraph(dynamic_cast<SwXParagraph*>(xParaOrTable.get()));
2127 const OUString sCurrentClass = lcl_GetParagraphClassification(aHelper, aKeyCreator, xModel, xParagraph);
2128 sHighestClass = aHelper.GetHigherClass(sHighestClass, sCurrentClass);
2129 }
2130
2131 return sHighestClass;
2132}
2133
2135{
2136 SwDocShell* pDocShell = GetDoc()->GetDocShell();
2137 if (!pDocShell)
2138 return;
2139
2140 // Bail out as early as possible if we don't have paragraph classification.
2141 if (!SwRDFHelper::hasMetadataGraph(pDocShell->GetBaseModel(), MetaNS))
2142 return;
2143
2144 uno::Reference<document::XDocumentProperties> xDocumentProperties = pDocShell->getDocProperties();
2145 uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
2146
2148 SfxClassificationHelper aHelper(xDocumentProperties);
2149
2150 OUString sHighestClass = lcl_GetHighestClassificationParagraphClass(GetCursor());
2151
2152 const OUString aClassificationCategory = svx::classification::getProperty(xPropertyContainer, aKeyCreator.makeCategoryNameKey());
2153
2154 if (!aClassificationCategory.isEmpty())
2155 {
2156 sHighestClass = aHelper.GetHigherClass(sHighestClass, aClassificationCategory);
2157 }
2158
2159 if (aClassificationCategory != sHighestClass)
2160 {
2161 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
2162 VclMessageType::Question, VclButtonsType::Ok,
2163 SwResId(STR_CLASSIFICATION_LEVEL_CHANGED)));
2164 xQueryBox->run();
2165 }
2166
2167 const SfxClassificationPolicyType eHighestClassType = SfxClassificationHelper::stringToPolicyType(sHighestClass);
2168
2169 // Prevent paragraph signature validation since the below changes (f.e. watermarking) are benign.
2170 const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
2171 comphelper::ScopeGuard const g([this, bOldValidationFlag]() {
2172 SetParagraphSignatureValidation(bOldValidationFlag);
2173 });
2174
2175 // Check the origin, if "manual" (created via advanced classification dialog),
2176 // then we just need to set the category name.
2177 if (sfx::getCreationOriginProperty(xPropertyContainer, aKeyCreator) == sfx::ClassificationCreationOrigin::MANUAL)
2178 {
2179 aHelper.SetBACName(sHighestClass, eHighestClassType);
2181 }
2182 else
2183 {
2184 SetClassification(sHighestClass, eHighestClassType);
2185 }
2186}
2187
2188// #i62675#
2190 const bool bResetListAttrs)
2191{
2192 SwTextFormatColl *pLocal = pFormat? pFormat: (*GetDoc()->GetTextFormatColls())[0];
2194
2195 SwRewriter aRewriter;
2196
2197 aRewriter.AddRule(UndoArg1, pLocal->GetName());
2198
2200 for(SwPaM& rPaM : GetCursor()->GetRingContainer())
2201 {
2202 if (!rPaM.HasReadonlySel( GetViewOptions()->IsFormView(), true))
2203 {
2204 // store previous paragraph style for track changes
2205 OUString sParaStyleName;
2206 sal_uInt16 nPoolId = USHRT_MAX;
2207 SwContentNode * pCnt = rPaM.Start()->GetNode().GetContentNode();
2208 if ( pCnt && pCnt->GetTextNode() && GetDoc()->getIDocumentRedlineAccess().IsRedlineOn() )
2209 {
2210 const SwTextFormatColl* pTextFormatColl = pCnt->GetTextNode()->GetTextColl();
2211 sal_uInt16 nStylePoolId = pTextFormatColl->GetPoolFormatId();
2212 // default paragraph style
2213 if ( nStylePoolId == RES_POOLCOLL_STANDARD )
2214 nPoolId = nStylePoolId;
2215 else
2216 sParaStyleName = pTextFormatColl->GetName();
2217 }
2218
2219 // Change the paragraph style to pLocal and remove all direct paragraph formatting.
2220 GetDoc()->SetTextFormatColl(rPaM, pLocal, true, bResetListAttrs, GetLayout());
2221
2222 // If there are hints on the nodes which cover the whole node, then remove those, too.
2223 SwPaM aPaM(*rPaM.Start(), *rPaM.End());
2224 if (SwTextNode* pEndTextNode = aPaM.End()->GetNode().GetTextNode())
2225 {
2226 aPaM.Start()->SetContent(0);
2227 aPaM.End()->SetContent(pEndTextNode->GetText().getLength());
2228 }
2229 GetDoc()->RstTextAttrs(aPaM, /*bInclRefToxMark=*/false, /*bExactRange=*/true, GetLayout());
2230
2231 // add redline tracking the previous paragraph style
2233 // multi-paragraph ParagraphFormat redline ranges
2234 // haven't supported by AppendRedline(), yet
2235 // TODO handle multi-paragraph selections, too,
2236 // e.g. by breaking them to single paragraphs
2237 aPaM.Start()->GetNode() == aPaM.End()->GetNode() )
2238 {
2239 SwRangeRedline * pRedline = new SwRangeRedline( RedlineType::ParagraphFormat, aPaM );
2240 auto const result(GetDoc()->getIDocumentRedlineAccess().AppendRedline( pRedline, true));
2241 // store original paragraph style to reject formatting change
2243 ( nPoolId == RES_POOLCOLL_STANDARD || !sParaStyleName.isEmpty() ) )
2244 {
2245 std::unique_ptr<SwRedlineExtraData_FormatColl> xExtra;
2246 xExtra.reset(new SwRedlineExtraData_FormatColl(sParaStyleName, nPoolId, nullptr));
2247 if (xExtra)
2248 pRedline->SetExtraData( xExtra.get() );
2249 }
2250 }
2251 }
2252
2253 }
2255 EndAllAction();
2256}
2257
2258SwTextFormatColl* SwEditShell::MakeTextFormatColl(const OUString& rFormatCollName,
2259 SwTextFormatColl* pParent)
2260{
2261 SwTextFormatColl *pColl;
2262 if ( pParent == nullptr )
2263 pParent = &GetTextFormatColl(0);
2264 pColl = GetDoc()->MakeTextFormatColl(rFormatCollName, pParent);
2265 if ( pColl == nullptr )
2266 {
2267 OSL_FAIL( "MakeTextFormatColl failed" );
2268 }
2269 return pColl;
2270
2271}
2272
2274{
2275 SwPaM * pCursor = GetCursor();
2276 SwContentNode * pCnt = pCursor->GetPointContentNode();
2277 if (pCnt->IsTextNode()) // uhm... what nonsense would happen if not?
2278 { // only need properties-node because BREAK/PAGEDESC filtered anyway!
2279 pCnt = sw::GetParaPropsNode(*GetLayout(), pCursor->GetPoint()->GetNode());
2280 }
2281 const SfxItemSet* pSet = pCnt->GetpSwAttrSet();
2282 if( !pSet )
2283 return;
2284
2285 // JP 05.10.98: Special treatment if one of the attributes Break/PageDesc/NumRule(auto) is
2286 // in the ItemSet. Otherwise there will be too much or wrong processing (NumRules!)
2287 // Bug 57568
2288
2289 // Do NOT copy AutoNumRules into the template
2290 const SwNumRuleItem* pItem;
2291 const SwNumRule* pRule = nullptr;
2292 if (SfxItemState::SET == pSet->GetItemState(RES_BREAK, false)
2293 || SfxItemState::SET == pSet->GetItemState(RES_PAGEDESC, false)
2294 || ((pItem = pSet->GetItemIfSet(RES_PARATR_NUMRULE, false))
2295 && nullptr != (pRule = GetDoc()->FindNumRulePtr(pItem->GetValue()))
2296 && pRule->IsAutoRule()))
2297 {
2298 SfxItemSet aSet( *pSet );
2299 aSet.ClearItem( RES_BREAK );
2300 aSet.ClearItem( RES_PAGEDESC );
2301
2302 if (pRule
2303 || ((pItem = pSet->GetItemIfSet(RES_PARATR_NUMRULE, false))
2304 && nullptr != (pRule = GetDoc()->FindNumRulePtr(pItem->GetValue()))
2305 && pRule->IsAutoRule()))
2307
2308 if( aSet.Count() )
2309 GetDoc()->ChgFormat(*pColl, aSet );
2310 }
2311 else
2312 GetDoc()->ChgFormat(*pColl, *pSet );
2313}
2314
2315/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertyValueVector_t aPropertyValues
@ UndoArg1
Definition: SwRewriter.hxx:29
PropertiesInfo aProperties
const char *const aFieldNames[]
Definition: authfld.cxx:650
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, bool bMobile=false)
const OUString & GetValue() const
static DateTime CreateFromUnixTime(const double fSecondsSinceEpoch)
void ConvertToLocalTime()
sal_Int16 GetYear() const
sal_uInt16 GetDay() const
sal_uInt16 GetMonth() const
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
virtual bool DoesUndo() const =0
Is Undo enabled?
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
static const OUString & PROP_DOCFOOTER()
static SfxClassificationPolicyType getPolicyType()
OUString GetBACNameForIdentifier(std::u16string_view sIdentifier)
static const OUString & PROP_DOCHEADER()
static SfxClassificationPolicyType stringToPolicyType(std::u16string_view rType)
static const OUString & policyTypeToString(SfxClassificationPolicyType eType)
static const OUString & PROP_PREFIX_INTELLECTUALPROPERTY()
sal_uInt16 Count() const
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
css::uno::Reference< css::document::XDocumentProperties > getDocProperties() const
css::uno::Reference< css::frame::XModel3 > GetBaseModel() const
static SfxObjectShell * Current()
void SetFont(const OUString &aFont)
sal_Int16 GetTransparency() const
OUString const & GetFont() const
void SetAngle(const sal_Int16 nAngle)
OUString const & GetText() const
void SetTransparency(const sal_Int16 nTransparency)
void SetColor(Color nColor)
void SetText(const OUString &aText)
sal_Int16 GetAngle() const
Color GetColor() const
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:493
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:194
Definition: doc.hxx:194
void RstTextAttrs(const SwPaM &rRg, bool bInclRefToxMark=false, bool bExactRange=false, SwRootFrame const *pLayout=nullptr)
Definition: docfmt.cxx:222
void ChgFormat(SwFormat &rFormat, const SfxItemSet &rSet)
Definition: docfmt.cxx:1868
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:150
SwEditShell const * GetEditShell() const
Definition: doccorr.cxx:329
const SwTextFormatColls * GetTextFormatColls() const
Definition: doc.hxx:786
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:784
SwTextFormatColl * MakeTextFormatColl(const OUString &rFormatName, SwTextFormatColl *pDerivedFrom, bool bBroadcast=false)
Create the FormatCollections.
Definition: docfmt.cxx:888
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter <bResetListAttrs>.
Definition: docfmt.cxx:1083
SwDocShell * GetDocShell()
Definition: doc.hxx:1359
std::vector< svx::ClassificationResult > CollectAdvancedClassification()
Definition: edfcol.cxx:947
void ApplyParagraphClassification(std::vector< svx::ClassificationResult > aResult)
Apply the classification to the paragraph at cursor.
Definition: edfcol.cxx:1264
void StartAllAction()
For all views of this document.
Definition: edws.cxx:86
void SetWatermark(const SfxWatermarkItem &rText)
Definition: edfcol.cxx:1608
void SignParagraph()
Sign the paragraph at the cursor.
Definition: edfcol.cxx:1751
bool IsRedlineOn() const
Definition: edredln.cxx:43
bool RemoveParagraphMetadataFieldAtCursor()
Removes the paragraph metadata field at the current cursor, if any.
Definition: edfcol.cxx:2057
void ValidateAllParagraphSignatures(bool updateDontRemove)
Validate all paragraph signatures.
Definition: edfcol.cxx:1855
bool IsCursorInParagraphMetadataField() const
Returns true iff the cursor is within a paragraph metadata field.
Definition: edfcol.cxx:2044
SwTextFormatColl & GetTextFormatColl(sal_uInt16 nTextFormatColl) const
Definition: edfcol.cxx:699
sal_uInt16 GetTextFormatCollCount() const
Definition: edfcol.cxx:694
bool SetParagraphSignatureValidation(const bool bEnable)
Enable/Disable paragraph signature validation and return the previous value.
Definition: editsh.hxx:976
void RestoreMetadataFieldsAndValidateParagraphSignatures()
Restore the metadata fields, if missing, from the RDF metadata and validate the signatures and update...
Definition: edfcol.cxx:1910
void SetTextFormatColl(SwTextFormatColl *, const bool bResetListAttrs=false)
Add 2nd optional parameter <bResetListAttrs> - see also <SwDoc::SetTextFormatColl(....
Definition: edfcol.cxx:2189
std::vector< svx::ClassificationResult > CollectParagraphClassification()
Definition: edfcol.cxx:1343
void ValidateCurrentParagraphSignatures(bool updateDontRemove)
Validate the current paragraph signatures, if any, at the cursor start.
Definition: edfcol.cxx:1843
void SetClassification(const OUString &rName, SfxClassificationPolicyType eType)
Definition: edfcol.cxx:1068
SwTextFormatColl & GetDfltTextFormatColl() const
Definition: edfcol.cxx:689
void ApplyAdvancedClassification(std::vector< svx::ClassificationResult > const &rResult)
Definition: edfcol.cxx:777
void ClassifyDocPerHighestParagraphClass()
Ensure that the classification of the doc is never lower than the paragraph with the highest classifi...
Definition: edfcol.cxx:2134
bool IsParagraphSignatureValidationEnabled() const
Returns true iff paragraph signature validation is enabled.
Definition: editsh.hxx:974
SfxWatermarkItem GetWatermark() const
Definition: edfcol.cxx:1383
SwTextFormatColl * MakeTextFormatColl(const OUString &rFormatCollName, SwTextFormatColl *pDerivedFrom=nullptr)
Definition: edfcol.cxx:2258
void FillByEx(SwCharFormat *)
Definition: edfmt.cxx:51
void ValidateParagraphSignatures(SwTextNode *pNode, bool updateDontRemove)
Validate the paragraph signatures, if any, of the current text node.
Definition: edfcol.cxx:1824
void EndAllAction()
Definition: edws.cxx:97
::sw::Meta * GetMeta()
Definition: fmtmeta.hxx:122
sal_uInt16 GetPoolFormatId() const
Get and set Pool style IDs.
Definition: format.hxx:163
const OUString & GetName() const
Definition: format.hxx:131
Base class of the Writer layout elements.
Definition: frame.hxx:315
SwFrame * GetNext()
Definition: frame.hxx:676
SwFrame * GetLower()
Definition: findfrm.cxx:194
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:897
SwDoc & GetDoc()
Definition: node.hxx:233
bool IsTextNode() const
Definition: node.hxx:685
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:381
SwContentNode * GetContentNode()
Definition: node.hxx:664
bool IsAutoRule() const
Definition: numrule.hxx:229
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:187
SwContentNode * GetPointContentNode() const
Definition: pam.hxx:287
const SwPosition * End() const
Definition: pam.hxx:271
const SwPosition * GetPoint() const
Definition: pam.hxx:261
const SwPosition * Start() const
Definition: pam.hxx:266
A page of the document layout.
Definition: pagefrm.hxx:58
SwPageDesc * FindPageDesc()
Definition: pagechg.cxx:755
static void removeStatement(const css::uno::Reference< css::frame::XModel > &xModel, const OUString &rType, const css::uno::Reference< css::rdf::XResource > &xSubject, const OUString &rKey, const OUString &rValue)
Remove an (XResource, key, value) statement in the graph of type rType, if it exists.
Definition: rdfhelper.cxx:131
static std::map< OUString, OUString > getStatements(const css::uno::Reference< css::frame::XModel > &xModel, const css::uno::Sequence< css::uno::Reference< css::rdf::XURI > > &rGraphNames, const css::uno::Reference< css::rdf::XResource > &xSubject)
Gets all (XResource, key, value) statements in RDF graphs given the graph-names.
static void addStatement(const css::uno::Reference< css::frame::XModel > &xModel, const OUString &rType, const OUString &rPath, const css::uno::Reference< css::rdf::XResource > &xSubject, const OUString &rKey, const OUString &rValue)
Add an (XResource, key, value) statement in the graph of type rType – or if it does not exist,...
Definition: rdfhelper.cxx:100
static css::uno::Sequence< css::uno::Reference< css::rdf::XURI > > getGraphNames(const css::uno::Reference< css::rdf::XDocumentMetadataAccess > &xDocumentMetadataAccess, const css::uno::Reference< css::rdf::XURI > &xType)
Gets all graph-names in RDF of a given type.
static bool hasMetadataGraph(const css::uno::Reference< css::frame::XModel > &xModel, const OUString &rType)
Check if a graph of type rType exists.
Definition: rdfhelper.cxx:123
void SetExtraData(const SwRedlineExtraData *pData)
ExtraData gets copied, the pointer is therefore not taken over by the RedLineObject.
Definition: redline.hxx:223
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:25
The root element of a Writer document layout.
Definition: rootfrm.hxx:82
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:167
Represents the style of a paragraph.
Definition: fmtcol.hxx:59
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:111
SwTextAttr * GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich, ::sw::GetTextAttrMode const eMode=::sw::GetTextAttrMode::Default) const
get the innermost text attribute covering position nIndex.
Definition: ndtxt.cxx:1790
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:891
virtual void UndoImpl(::sw::UndoRedoContext &) override
Definition: edfcol.cxx:1694
virtual void RedoImpl(::sw::UndoRedoContext &) override
Definition: edfcol.cxx:1702
SwUndoParagraphSigning(SwDoc &rDoc, css::uno::Reference< css::text::XTextField > xField, css::uno::Reference< css::text::XTextContent > xParent, const bool bRemove)
Definition: edfcol.cxx:1669
css::uno::Reference< css::text::XTextField > m_xField
virtual void RepeatImpl(::sw::RepeatContext &) override
Definition: edfcol.cxx:1710
css::uno::Reference< css::text::XTextContent > m_xParent
size_t size() const
Definition: docary.hxx:87
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:433
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2160
SwDoc * GetDoc() const
Definition: viewsh.hxx:290
const IDocumentRedlineAccess & getIDocumentRedlineAccess() const
Provides access to the document redline interface.
Definition: viewsh.cxx:2811
static rtl::Reference< SwXParagraph > CreateXParagraph(SwDoc &rDoc, SwTextNode *pTextNode, css::uno::Reference< css::text::XText > const &xParentText=nullptr, const sal_Int32 nSelStart=-1, const sal_Int32 nSelEnd=- 1)
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
void rotate(double fRadiant)
double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
void scale(double fX, double fY)
SfxClassificationPolicyType
bool isMarkingKey(std::u16string_view aKey) const
bool isMarkingTextKey(std::u16string_view aKey) const
OUString makeNumberedIntellectualPropertyPartKey()
bool isCategoryIdentifierKey(std::u16string_view aKey) const
bool isCategoryNameKey(std::u16string_view aKey) const
OUString makeCategoryNameKey() const
OUString makeCategoryIdentifierKey() const
bool isIntellectualPropertyPartKey(std::u16string_view aKey) const
void AddDataRange(const void *pData, sal_Int32 size)
bool Sign(OStringBuffer &rCMSHexBuffer)
static bool Verify(const std::vector< unsigned char > &aData, const bool bNonDetached, const std::vector< unsigned char > &aSignature, SignatureInformation &rInformation)
ClassificationType meType
ring_container GetRingContainer()
Definition: ring.hxx:240
void SetFontSize(const Size &)
void SetFamilyName(const OUString &rFamilyName)
#define DBG_UNHANDLED_EXCEPTION(...)
SwDoc & m_rDoc
Definition: docbm.cxx:1202
float u
static void lcl_placeWatermarkInHeader(const SfxWatermarkItem &rWatermark, const uno::Reference< frame::XModel > &xModel, const uno::Reference< beans::XPropertySet > &xPageStyle, const uno::Reference< text::XText > &xHeaderText)
Definition: edfcol.cxx:1437
static void insertFieldToDocument(uno::Reference< lang::XMultiServiceFactory > const &rxMultiServiceFactory, uno::Reference< text::XText > const &rxText, uno::Reference< text::XParagraphCursor > const &rxParagraphCursor, OUString const &rsKey)
Definition: edfcol.cxx:704
static void lcl_ApplyParagraphClassification(SwDoc *pDoc, const uno::Reference< frame::XModel > &xModel, const rtl::Reference< SwXParagraph > &xParent, const css::uno::Reference< css::rdf::XResource > &xNodeSubject, std::vector< svx::ClassificationResult > aResults)
Definition: edfcol.cxx:1160
static OUString lcl_GetParagraphClassification(SfxClassificationHelper &rHelper, sfx::ClassificationKeyCreator const &rKeyCreator, const uno::Reference< frame::XModel > &xModel, const rtl::Reference< SwXParagraph > &xParagraph)
Definition: edfcol.cxx:2083
static OUString lcl_GetHighestClassificationParagraphClass(SwPaM *pCursor)
Definition: edfcol.cxx:2103
static void equaliseNumberOfParagraph(std::vector< svx::ClassificationResult > const &rResults, uno::Reference< text::XText > const &xText)
Definition: edfcol.cxx:761
static sal_Int16 lcl_GetAngle(const drawing::HomogenMatrix3 &rMatrix)
Definition: edfcol.cxx:1360
static std::vector< svx::ClassificationResult > lcl_CollectParagraphClassification(const uno::Reference< frame::XModel > &xModel, const uno::Reference< text::XTextContent > &xParagraph)
Definition: edfcol.cxx:1285
static void removeAllClassificationFields(std::u16string_view rPolicy, uno::Reference< text::XText > const &rxText)
Definition: edfcol.cxx:715
static uno::Reference< text::XTextField > lcl_GetParagraphMetadataFieldAtIndex(const SwDocShell *pDocSh, SwTextNode const *pNode, const sal_uLong index)
Definition: edfcol.cxx:1883
constexpr OUStringLiteral WATERMARK_NAME
Definition: edfcol.cxx:104
static sal_Int32 getNumberOfParagraphs(uno::Reference< text::XText > const &xText)
Definition: edfcol.cxx:748
#define WATERMARK_AUTO_SIZE
Definition: edfcol.cxx:105
Any aHelper
DocumentType eType
constexpr TypedWhichId< SvxFormatBreakItem > RES_BREAK(94)
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:174
constexpr TypedWhichId< SwFormatPageDesc > RES_PAGEDESC(93)
constexpr TypedWhichId< SwNumRuleItem > RES_PARATR_NUMRULE(72)
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:175
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:170
sal_Int32 nIndex
OUString aName
OUString sSuffix
OUString sPrefix
std::unique_ptr< sal_Int32[]> pData
const char * sName
tools::Long const nRightMargin
tools::Long const nBottomMargin
tools::Long const nTopMargin
tools::Long const nLeftMargin
constexpr double rad2deg(double v)
constexpr double deg2rad(double v)
OUStringBuffer & remove(OUStringBuffer &rIn, sal_Unicode c)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
constexpr OUStringLiteral first
index
enumrange< T >::Iterator begin(enumrange< T >)
end
sfx::ClassificationCreationOrigin getCreationOriginProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator)
std::vector< unsigned char > DecodeHexString(std::string_view rHex)
OUString getProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, OUString const &rName)
void insertFullTextualRepresentationAsDocumentProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator, std::vector< svx::ClassificationResult > const &rResults)
void insertCreationOrigin(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator, sfx::ClassificationCreationOrigin eOrigin)
bool addOrInsertDocumentProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, OUString const &rsKey, OUString const &rsValue)
void removeAllProperties(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer)
SwTextNode * GetParaPropsNode(SwRootFrame const &rLayout, SwNode const &rNode)
Definition: txtfrm.cxx:330
@ RES_POOLCOLL_STANDARD
Standard.
Definition: poolfmt.hxx:250
sal_uIntPtr sal_uLong
css::xml::crypto::SecurityOperationStatus nStatus
X509CertInfo const * GetSigningCertificate() const
Marks a position in the document model.
Definition: pam.hxx:37
SwNode & GetNode() const
Definition: pam.hxx:80
void SetContent(sal_Int32 nContentIndex)
Set content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:266
sal_Int32 GetContentIndex() const
Definition: pam.hxx:84
Reference< XModel > xModel
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:165
SwUndoId
Definition: swundo.hxx:30
Any result
ResultType type
OUString sId
constexpr OUStringLiteral UNO_NAME_FILL_TRANSPARENCE
#define UNO_NAME_HEADER_IS_ON
Definition: unoprnms.hxx:389
#define UNO_NAME_NAME
Definition: unoprnms.hxx:81
#define UNO_NAME_HEADER_TEXT
Definition: unoprnms.hxx:371
#define UNO_NAME_SIZE
Definition: unoprnms.hxx:309
constexpr OUStringLiteral UNO_NAME_FILLCOLOR
#define UNO_NAME_BOTTOM_MARGIN
Definition: unoprnms.hxx:327
#define UNO_NAME_HEADER_HEIGHT
Definition: unoprnms.hxx:388
#define UNO_NAME_HORI_ORIENT_RELATION
Definition: unoprnms.hxx:269
constexpr OUStringLiteral UNO_NAME_TEXT_MINFRAMEHEIGHT
#define UNO_NAME_TOP_MARGIN
Definition: unoprnms.hxx:326
constexpr OUStringLiteral UNO_NAME_LINESTYLE
#define UNO_NAME_VERT_ORIENT_RELATION
Definition: unoprnms.hxx:338
#define UNO_NAME_TEXT_WRAP
Definition: unoprnms.hxx:319
#define UNO_NAME_RIGHT_MARGIN
Definition: unoprnms.hxx:72
#define UNO_NAME_TEXT_PORTION_TYPE
Definition: unoprnms.hxx:479
#define UNO_NAME_LEFT_MARGIN
Definition: unoprnms.hxx:71
constexpr OUStringLiteral UNO_NAME_FILLSTYLE
#define UNO_NAME_HORI_ORIENT
Definition: unoprnms.hxx:266
constexpr OUStringLiteral UNO_NAME_TEXT_AUTOGROWHEIGHT
#define UNO_NAME_HEADER_TEXT_LEFT
Definition: unoprnms.hxx:372
constexpr OUStringLiteral UNO_NAME_TEXT_AUTOGROWWIDTH
#define UNO_NAME_ANCHOR_TYPE
Definition: unoprnms.hxx:231
#define UNO_NAME_FOOTER_TEXT
Definition: unoprnms.hxx:374
constexpr OUStringLiteral UNO_NAME_CHAR_HEIGHT
#define UNO_NAME_CHAR_FONT_NAME
Definition: unoprnms.hxx:88
constexpr OUStringLiteral UNO_NAME_TEXT_MINFRAMEWIDTH
#define UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT
Definition: unoprnms.hxx:386
#define UNO_NAME_HEADER_TEXT_RIGHT
Definition: unoprnms.hxx:373
#define UNO_NAME_OPAQUE
Definition: unoprnms.hxx:288
#define UNO_NAME_VERT_ORIENT
Definition: unoprnms.hxx:335
#define UNO_NAME_HEADER_TEXT_FIRST
Definition: unoprnms.hxx:836
#define UNO_NAME_FOOTER_IS_ON
Definition: unoprnms.hxx:405
#define UNO_NAME_TEXT_FIELD
Definition: unoprnms.hxx:346