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 
57 #include <comphelper/sequence.hxx>
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>
89 #include <sfx2/watermarkitem.hxx>
90 
91 #include <unoparagraph.hxx>
92 #include <strings.hrc>
93 #include <undobj.hxx>
95 #include <txtatr.hxx>
96 #include <fmtmeta.hxx>
97 
98 #include <tools/diagnose_ex.h>
100 #include <SwStyleNameMapper.hxx>
101 #include <comphelper/lok.hxx>
102 
103 constexpr OUStringLiteral WATERMARK_NAME = u"PowerPlusWaterMarkObject";
104 #define WATERMARK_AUTO_SIZE sal_uInt32(1)
105 
106 namespace
107 {
108 constexpr OUStringLiteral MetaFilename(u"tscp/bails.rdf");
109 constexpr OUStringLiteral MetaNS(u"urn:bails");
110 constexpr OUStringLiteral ParagraphSignatureRDFNamespace = u"urn:bails:loext:paragraph:signature:";
111 constexpr OUStringLiteral ParagraphSignatureIdRDFName = u"urn:bails:loext:paragraph:signature:id";
112 constexpr OUStringLiteral ParagraphSignatureDigestRDFName = u":digest";
113 constexpr OUStringLiteral ParagraphSignatureDateRDFName = u":date";
114 constexpr OUStringLiteral ParagraphSignatureUsageRDFName = u":usage";
115 constexpr OUStringLiteral ParagraphSignatureLastIdRDFName = u"urn:bails:loext:paragraph:signature:lastid";
116 constexpr OUStringLiteral ParagraphClassificationNameRDFName = u"urn:bails:loext:paragraph:classification:name";
117 constexpr OUStringLiteral ParagraphClassificationValueRDFName = u"urn:bails:loext:paragraph:classification:value";
118 constexpr OUStringLiteral ParagraphClassificationAbbrRDFName = u"urn:bails:loext:paragraph:classification:abbreviation";
119 constexpr OUStringLiteral ParagraphClassificationFieldNamesRDFName = u"urn:bails:loext:paragraph:classification:fields";
120 constexpr OUStringLiteral MetadataFieldServiceName = u"com.sun.star.text.textfield.MetadataField";
121 constexpr OUStringLiteral DocInfoServiceName = u"com.sun.star.text.TextField.DocInfo.Custom";
122 
124 std::vector<OUString> lcl_getUsedPageStyles(SwViewShell const * pShell)
125 {
126  std::vector<OUString> aReturn;
127 
128  SwRootFrame* pLayout = pShell->GetLayout();
129  for (SwFrame* pFrame = pLayout->GetLower(); pFrame; pFrame = pFrame->GetNext())
130  {
131  SwPageFrame* pPage = static_cast<SwPageFrame*>(pFrame);
132  if (const SwPageDesc *pDesc = pPage->FindPageDesc())
133  aReturn.push_back(pDesc->GetName());
134  }
135 
136  return aReturn;
137 }
138 
140 uno::Reference<text::XTextField> lcl_findField(const uno::Reference<text::XText>& xText, const OUString& rServiceName, std::u16string_view rFieldName)
141 {
142  uno::Reference<text::XTextField> xField;
143  uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xText, uno::UNO_QUERY);
144  uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
145  while (xParagraphs->hasMoreElements())
146  {
147  uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
148  uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
149  while (xTextPortions->hasMoreElements())
150  {
151  uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
152  OUString aTextPortionType;
153  xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
154  if (aTextPortionType != UNO_NAME_TEXT_FIELD)
155  continue;
156 
157  uno::Reference<lang::XServiceInfo> xTextField;
158  xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
159  if (!xTextField->supportsService(rServiceName))
160  continue;
161 
162  OUString aName;
163  uno::Reference<beans::XPropertySet> xPropertySet(xTextField, uno::UNO_QUERY);
164  xPropertySet->getPropertyValue(UNO_NAME_NAME) >>= aName;
165  if (aName == rFieldName)
166  {
167  xField = uno::Reference<text::XTextField>(xTextField, uno::UNO_QUERY);
168  break;
169  }
170  }
171  }
172 
173  return xField;
174 }
175 
177 bool lcl_hasField(const uno::Reference<text::XText>& xText, const OUString& rServiceName, std::u16string_view rFieldName)
178 {
179  return lcl_findField(xText, rServiceName, rFieldName).is();
180 }
181 
183 uno::Reference<drawing::XShape> lcl_getWatermark(const uno::Reference<text::XText>& xText,
184  const OUString& rServiceName, OUString& rShapeName, bool& bSuccess)
185 {
186  bSuccess = false;
187  uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xText, uno::UNO_QUERY);
188  uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
189  while (xParagraphs->hasMoreElements())
190  {
191  uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
192  if (!xTextPortionEnumerationAccess.is())
193  continue;
194 
195  bSuccess = true;
196 
197  uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
198  while (xTextPortions->hasMoreElements())
199  {
200  uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
201  OUString aTextPortionType;
202  xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
203  if (aTextPortionType != "Frame")
204  continue;
205 
206  uno::Reference<container::XContentEnumerationAccess> xContentEnumerationAccess(xTextPortion, uno::UNO_QUERY);
207  if (!xContentEnumerationAccess.is())
208  continue;
209 
210  uno::Reference<container::XEnumeration> xEnumeration = xContentEnumerationAccess->createContentEnumeration("com.sun.star.text.TextContent");
211  if (!xEnumeration->hasMoreElements())
212  continue;
213 
214  uno::Reference<lang::XServiceInfo> xWatermark(xEnumeration->nextElement(), uno::UNO_QUERY);
215  if (!xWatermark->supportsService(rServiceName))
216  continue;
217 
218  uno::Reference<container::XNamed> xNamed(xWatermark, uno::UNO_QUERY);
219 
220  if (!xNamed->getName().match(WATERMARK_NAME))
221  continue;
222 
223  rShapeName = xNamed->getName();
224 
225  uno::Reference<drawing::XShape> xShape(xWatermark, uno::UNO_QUERY);
226  return xShape;
227  }
228  }
229 
230  return uno::Reference<drawing::XShape>();
231 }
232 
235 OString lcl_getParagraphBodyText(const uno::Reference<text::XTextContent>& xText)
236 {
237  OUStringBuffer strBuf;
238  uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xText, uno::UNO_QUERY);
239  if (!xTextPortionEnumerationAccess.is())
240  return OString();
241 
242  uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
243  while (xTextPortions->hasMoreElements())
244  {
245  uno::Any elem = xTextPortions->nextElement();
246 
247  //TODO: Consider including hidden and conditional texts/portions.
248  OUString aTextPortionType;
249  uno::Reference<beans::XPropertySet> xPropertySet(elem, uno::UNO_QUERY);
250  xPropertySet->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
251  if (aTextPortionType == "Text")
252  {
253  uno::Reference<text::XTextRange> xTextRange(elem, uno::UNO_QUERY);
254  if (xTextRange.is())
255  strBuf.append(xTextRange->getString());
256  }
257  }
258 
259  // Cleanup the dummy characters added by fields (which we exclude).
263 
264  return strBuf.makeStringAndClear().trim().toUtf8();
265 }
266 
267 template <typename T>
268 std::map<OUString, OUString> lcl_getRDFStatements(const uno::Reference<frame::XModel>& xModel,
269  const T& xRef)
270 {
271  try
272  {
273  const css::uno::Reference<css::rdf::XResource> xSubject(xRef, uno::UNO_QUERY);
274  return SwRDFHelper::getStatements(xModel, MetaNS, xSubject);
275  }
276  catch (const ::css::uno::Exception&)
277  {
278  }
279 
280  return std::map<OUString, OUString>();
281 }
282 
284 std::pair<OUString, OUString> lcl_getFieldRDFByPrefix(const uno::Reference<frame::XModel>& xModel,
285  const uno::Reference<css::text::XTextField>& xField,
286  std::u16string_view sPrefix)
287 {
288  for (const auto& pair : lcl_getRDFStatements(xModel, xField))
289  {
290  if (pair.first.startsWith(sPrefix))
291  return pair;
292  }
293 
294  return std::make_pair(OUString(), OUString());
295 }
296 
298 template <typename T>
299 std::pair<OUString, OUString> lcl_getRDF(const uno::Reference<frame::XModel>& xModel,
300  const T& xRef,
301  const OUString& sRDFName)
302 {
303  const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xRef);
304  const auto it = aStatements.find(sRDFName);
305  return (it != aStatements.end()) ? std::make_pair(it->first, it->second) : std::make_pair(OUString(), OUString());
306 }
307 
310 bool lcl_IsParagraphSignatureField(const uno::Reference<frame::XModel>& xModel,
311  const uno::Reference<css::text::XTextField>& xField)
312 {
313  return (lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName).first == ParagraphSignatureIdRDFName);
314 }
315 
316 uno::Reference<text::XTextField> lcl_findFieldByRDF(const uno::Reference<frame::XModel>& xModel,
317  const uno::Reference<text::XTextContent>& xParagraph,
318  const OUString& sRDFName,
319  std::u16string_view sRDFValue)
320 {
321  uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraph, uno::UNO_QUERY);
322  if (!xTextPortionEnumerationAccess.is())
323  return uno::Reference<text::XTextField>();
324 
325  uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
326  if (!xTextPortions.is())
327  return uno::Reference<text::XTextField>();
328 
329  while (xTextPortions->hasMoreElements())
330  {
331  uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
332  OUString aTextPortionType;
333  xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType;
334  if (aTextPortionType != UNO_NAME_TEXT_FIELD)
335  continue;
336 
337  uno::Reference<lang::XServiceInfo> xTextField;
338  xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField;
339  if (!xTextField->supportsService(MetadataFieldServiceName))
340  continue;
341 
342  uno::Reference<text::XTextField> xField(xTextField, uno::UNO_QUERY);
343  const std::pair<OUString, OUString> pair = lcl_getRDF(xModel, xField, sRDFName);
344  if (pair.first == sRDFName && (sRDFValue.empty() || sRDFValue == pair.second))
345  return xField;
346  }
347 
348  return uno::Reference<text::XTextField>();
349 }
350 
351 struct SignatureDescr
352 {
353  OUString msSignature;
354  OUString msUsage;
355  OUString msDate;
356 
357  bool isValid() const { return !msSignature.isEmpty(); }
358 };
359 
360 SignatureDescr lcl_getSignatureDescr(const uno::Reference<frame::XModel>& xModel,
361  const uno::Reference<css::text::XTextContent>& xParagraph,
362  std::u16string_view sFieldId)
363 {
364  SignatureDescr aDescr;
365 
366  const OUString prefix = ParagraphSignatureRDFNamespace + sFieldId;
367  const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xParagraph);
368 
369  const auto itSig = aStatements.find(prefix + ParagraphSignatureDigestRDFName);
370  aDescr.msSignature = (itSig != aStatements.end() ? itSig->second : OUString());
371 
372  const auto itDate = aStatements.find(prefix + ParagraphSignatureDateRDFName);
373  aDescr.msDate = (itDate != aStatements.end() ? itDate->second : OUString());
374 
375  const auto itUsage = aStatements.find(prefix + ParagraphSignatureUsageRDFName);
376  aDescr.msUsage = (itUsage != aStatements.end() ? itUsage->second : OUString());
377 
378  return aDescr;
379 }
380 
381 SignatureDescr lcl_getSignatureDescr(const uno::Reference<frame::XModel>& xModel,
382  const uno::Reference<css::text::XTextContent>& xParagraph,
383  const uno::Reference<css::text::XTextField>& xField)
384 {
385  const OUString sFieldId = lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName).second;
386  if (!sFieldId.isEmpty())
387  return lcl_getSignatureDescr(xModel, xParagraph, sFieldId);
388 
389  return SignatureDescr();
390 }
391 
393 std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr,
394  const OString& utf8Text)
395 {
396  OUString msg = SwResId(STR_INVALID_SIGNATURE);
397  bool valid = false;
398 
399  if (aDescr.isValid())
400  {
401  const char* pData = utf8Text.getStr();
402  const std::vector<unsigned char> data(pData, pData + utf8Text.getLength());
403 
404  OString encSignature;
405  if (aDescr.msSignature.convertToString(&encSignature, RTL_TEXTENCODING_UTF8, 0))
406  {
407  const std::vector<unsigned char> sig(svl::crypto::DecodeHexString(encSignature));
408  SignatureInformation aInfo(0);
409  valid = svl::crypto::Signing::Verify(data, false, sig, aInfo);
410  valid = valid
411  && aInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
412 
413  assert(aInfo.GetSigningCertificate()); // it was valid
414  msg = SwResId(STR_SIGNED_BY) + ": " + aInfo.GetSigningCertificate()->X509Subject + ", " +
415  aDescr.msDate;
416  msg += (!aDescr.msUsage.isEmpty() ? (" (" + aDescr.msUsage + "): ") : OUString(": "));
417  msg += (valid ? SwResId(STR_VALID) : SwResId(STR_INVALID));
418  }
419  }
420 
421  return std::make_pair(valid, msg);
422 }
423 
425 std::pair<bool, OUString>
426 lcl_MakeParagraphSignatureFieldText(const uno::Reference<frame::XModel>& xModel,
427  const uno::Reference<css::text::XTextContent>& xParagraph,
428  const uno::Reference<css::text::XTextField>& xField,
429  const OString& utf8Text)
430 {
431  const SignatureDescr aDescr = lcl_getSignatureDescr(xModel, xParagraph, xField);
432  return lcl_MakeParagraphSignatureFieldText(aDescr, utf8Text);
433 }
434 
436 OUString lcl_getNextSignatureId(const uno::Reference<frame::XModel>& xModel,
437  const uno::Reference<text::XTextContent>& xParagraph)
438 {
439  const OUString sFieldId = lcl_getRDF(xModel, xParagraph, ParagraphSignatureLastIdRDFName).second;
440  return OUString::number(!sFieldId.isEmpty() ? sFieldId.toInt32() + 1 : 1);
441 }
442 
444 uno::Reference<text::XTextField> lcl_InsertParagraphSignature(const uno::Reference<frame::XModel>& xModel,
445  const uno::Reference<text::XTextContent>& xParagraph,
446  const OUString& signature,
447  const OUString& usage)
448 {
449  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
450  auto xField = uno::Reference<text::XTextField>(xMultiServiceFactory->createInstance(MetadataFieldServiceName), uno::UNO_QUERY);
451 
452  // Add the signature at the end.
453  xField->attach(xParagraph->getAnchor()->getEnd());
454 
455  const OUString sId = lcl_getNextSignatureId(xModel, xParagraph);
456 
457  const css::uno::Reference<css::rdf::XResource> xSubject(xField, uno::UNO_QUERY);
458  SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xSubject, ParagraphSignatureIdRDFName, sId);
459 
460  // First convert the UTC UNIX timestamp to a tools::DateTime then to local time.
461  DateTime aDateTime = DateTime::CreateFromUnixTime(time(nullptr));
462  aDateTime.ConvertToLocalTime();
463  OUStringBuffer rBuffer;
464  rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
465  rBuffer.append('-');
466  if (aDateTime.GetMonth() < 10)
467  rBuffer.append('0');
468  rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
469  rBuffer.append('-');
470  if (aDateTime.GetDay() < 10)
471  rBuffer.append('0');
472  rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
473 
474  // Now set the RDF on the paragraph, since that's what is preserved in .doc(x).
475  const css::uno::Reference<css::rdf::XResource> xParaSubject(xParagraph, uno::UNO_QUERY);
476  const OUString prefix = ParagraphSignatureRDFNamespace + sId;
477  SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureLastIdRDFName, sId);
478  SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDigestRDFName, signature);
479  SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureUsageRDFName, usage);
480  SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDateRDFName, rBuffer.makeStringAndClear());
481 
482  return xField;
483 }
484 
486 bool lcl_DoUpdateParagraphSignatureField(SwDoc& rDoc,
487  const uno::Reference<css::text::XTextField>& xField,
488  const OUString& sDisplayText)
489 {
490  // Disable undo to avoid introducing noise when we edit the metadata field.
491  const bool isUndoEnabled = rDoc.GetIDocumentUndoRedo().DoesUndo();
492  rDoc.GetIDocumentUndoRedo().DoUndo(false);
493  comphelper::ScopeGuard const g([&rDoc, isUndoEnabled]() {
494  rDoc.GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
495  });
496 
497  try
498  {
499  uno::Reference<css::text::XTextRange> xText(xField, uno::UNO_QUERY);
500  const OUString curText = xText->getString();
501  if (curText != sDisplayText)
502  {
503  xText->setString(sDisplayText);
504  return true;
505  }
506  }
507  catch (const uno::Exception&)
508  {
509  // We failed; avoid crashing.
510  DBG_UNHANDLED_EXCEPTION("sw.uno", "Failed to update paragraph signature");
511  }
512 
513  return false;
514 }
515 
517 bool lcl_UpdateParagraphSignatureField(SwDoc& rDoc,
518  const uno::Reference<frame::XModel>& xModel,
519  const uno::Reference<css::text::XTextContent>& xParagraph,
520  const uno::Reference<css::text::XTextField>& xField,
521  const OString& utf8Text)
522 {
523  const OUString sDisplayText
524  = lcl_MakeParagraphSignatureFieldText(xModel, xParagraph, xField, utf8Text).second;
525  return lcl_DoUpdateParagraphSignatureField(rDoc, xField, sDisplayText);
526 }
527 
528 void lcl_RemoveParagraphMetadataField(const uno::Reference<css::text::XTextField>& xField)
529 {
530  uno::Reference<css::text::XTextRange> xParagraph(xField->getAnchor());
531  xParagraph->getText()->removeTextContent(xField);
532 }
533 
536 bool lcl_IsParagraphClassificationField(const uno::Reference<frame::XModel>& xModel,
537  const uno::Reference<css::text::XTextField>& xField,
538  std::u16string_view sKey)
539 {
540  const std::pair<OUString, OUString> rdfPair = lcl_getRDF(xModel, xField, ParagraphClassificationNameRDFName);
541  return rdfPair.first == ParagraphClassificationNameRDFName && (sKey.empty() || rdfPair.second == sKey);
542 }
543 
544 uno::Reference<text::XTextField> lcl_FindParagraphClassificationField(const uno::Reference<frame::XModel>& xModel,
545  const uno::Reference<text::XTextContent>& xParagraph,
546  std::u16string_view sKey = u"")
547 {
548  uno::Reference<text::XTextField> xTextField;
549 
550  uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraph, uno::UNO_QUERY);
551  if (!xTextPortionEnumerationAccess.is())
552  return xTextField;
553 
554  // Enumerate text portions to find metadata fields. This is expensive, best to enumerate fields only.
555  uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration();
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 
581 uno::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 
593 bool 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 
620 void 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 
699 SwTextFormatColl& SwEditShell::GetTextFormatColl(sal_uInt16 nFormatColl) const
700 {
701  return *((*(GetDoc()->GetTextFormatColls()))[nFormatColl]);
702 }
703 
704 static 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::makeAny(rsKey));
710  uno::Reference<text::XTextContent> xTextContent(xField, uno::UNO_QUERY);
711 
712  rxText->insertTextContent(rxParagraphCursor, xTextContent, false);
713 }
714 
715 static 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 
748 static 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 
761 static 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 
777 void 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();
819  svx::classification::removeAllProperties(xPropertyContainer);
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
838  svx::classification::insertFullTextualRepresentationAsDocumentProperty(xPropertyContainer, aCreator, rResults);
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::makeAny(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::makeAny(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::makeAny(awt::FontWeight::BOLD));
930  xFooterPropertySet->setPropertyValue("CharWeight", uno::makeAny(awt::FontWeight::BOLD));
931  }
932  else
933  {
934  xHeaderPropertySet->setPropertyValue("CharWeight", uno::makeAny(awt::FontWeight::NORMAL));
935  xFooterPropertySet->setPropertyValue("CharWeight", uno::makeAny(awt::FontWeight::NORMAL));
936  }
937  }
938  break;
939 
940  default:
941  break;
942  }
943  }
944  }
945 }
946 
947 std::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::makeAny(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, OUStringConcatenation(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::makeAny(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::makeAny(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 uno::Reference<text::XTextContent>& 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 
1264 void 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()->nNode.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();
1281  uno::Reference<text::XTextContent> xParent = SwXParagraph::CreateXParagraph(pNode->GetDoc(), pNode);
1282  lcl_ApplyParagraphClassification(GetDoc(), xModel, xParent, css::uno::Reference<css::rdf::XResource>(xParent, uno::UNO_QUERY), std::move(aResults));
1283 }
1284 
1285 static 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 
1343 std::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()->nNode.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();
1357  return lcl_CollectParagraphClassification(xModel, xParent);
1358 }
1359 
1360 static 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 
1437 static 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::makeAny(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::makeAny(static_cast<sal_Int32>(nColor)));
1560  xPropertySet->setPropertyValue(UNO_NAME_FILLSTYLE, uno::makeAny(drawing::FillStyle_SOLID));
1561  xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::makeAny(nTransparency));
1562  xPropertySet->setPropertyValue(UNO_NAME_LINESTYLE, uno::makeAny(drawing::LineStyle_NONE));
1563  xPropertySet->setPropertyValue(UNO_NAME_OPAQUE, uno::makeAny(false));
1564  xPropertySet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::makeAny(false));
1565  xPropertySet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::makeAny(false));
1566  xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEHEIGHT, uno::makeAny(nHeight));
1567  xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEWIDTH, uno::makeAny(nWidth));
1568  xPropertySet->setPropertyValue(UNO_NAME_TEXT_WRAP, uno::makeAny(text::WrapTextMode_THROUGH));
1569  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION, uno::makeAny(text::RelOrientation::PAGE_PRINT_AREA));
1570  xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION, uno::makeAny(text::RelOrientation::PAGE_PRINT_AREA));
1571  xPropertySet->setPropertyValue(UNO_NAME_CHAR_FONT_NAME, uno::makeAny(sFont));
1572  xPropertySet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::makeAny(WATERMARK_AUTO_SIZE));
1573  xPropertySet->setPropertyValue("Transformation", uno::makeAny(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::makeAny(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::makeAny(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::makeAny(aMatrix));
1601 
1602  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT, uno::makeAny(text::HoriOrientation::CENTER));
1603  xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT, uno::makeAny(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::makeAny(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::makeAny(sal_Int32(11)));
1664  xPageStyle->setPropertyValue(UNO_NAME_HEADER_HEIGHT, uno::makeAny(nOldValue));
1665  xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT, uno::Any(bDynamicHeight));
1666  }
1667 }
1668 
1670  const uno::Reference<text::XTextField>& xField,
1671  const uno::Reference<text::XTextContent>& xParent,
1672  const bool bRemove)
1673  : SwUndo(SwUndoId::PARA_SIGN_ADD, &rDoc),
1674  m_rDoc(rDoc),
1675  m_xField(xField),
1676  m_xParent(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->nNode.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.makeStringAndClear(), RTL_TEXTENCODING_UTF8, 0);
1793 
1794  std::vector<css::beans::PropertyValue> vec = comphelper::sequenceToContainer<std::vector<css::beans::PropertyValue>>(aProperties);
1795  auto it = std::find_if(vec.begin(), vec.end(), [](const beans::PropertyValue& rValue)
1796  {
1797  return rValue.Name == "Usage";
1798  });
1799 
1800  OUString aUsage;
1801  if (it != vec.end())
1802  it->Value >>= aUsage;
1803 
1804  // 4. Add metadata
1805  // Prevent validation since this will trigger a premature validation
1806  // upon inserting, but before setting the metadata.
1807  const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1808  comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1809  SetParagraphSignatureValidation(bOldValidationFlag);
1810  });
1811 
1813 
1814  const uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1815  uno::Reference<css::text::XTextField> xField = lcl_InsertParagraphSignature(xModel, xParagraph, signature, aUsage);
1816 
1817  lcl_UpdateParagraphSignatureField(*GetDoc(), xModel, xParagraph, xField, utf8Text);
1818 
1820  std::make_unique<SwUndoParagraphSigning>(rDoc, xField, xParagraph, true));
1821 
1823 }
1824 
1825 void SwEditShell::ValidateParagraphSignatures(SwTextNode* pNode, bool updateDontRemove)
1826 {
1827  if (!pNode || !IsParagraphSignatureValidationEnabled())
1828  return;
1829 
1830  // Table text signing is not supported.
1831  if (pNode->FindTableNode() != nullptr)
1832  return;
1833 
1834  // Prevent recursive validation since this is triggered on node updates, which we do below.
1835  const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1836  comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1837  SetParagraphSignatureValidation(bOldValidationFlag);
1838  });
1839 
1840  uno::Reference<text::XTextContent> xParentText = SwXParagraph::CreateXParagraph(*GetDoc(), pNode);
1841  lcl_ValidateParagraphSignatures(*GetDoc(), xParentText, updateDontRemove);
1842 }
1843 
1845 {
1846  SwDocShell* pDocShell = GetDoc()->GetDocShell();
1847  if (!pDocShell || !GetCursor() || !GetCursor()->Start() || !IsParagraphSignatureValidationEnabled())
1848  return;
1849 
1850  SwPaM* pPaM = GetCursor();
1851  const SwPosition* pPosStart = pPaM->Start();
1852  SwTextNode* pNode = pPosStart->nNode.GetNode().GetTextNode();
1853  ValidateParagraphSignatures(pNode, updateDontRemove);
1854 }
1855 
1857 {
1858  SwDocShell* pDocShell = GetDoc()->GetDocShell();
1859  if (!pDocShell || !IsParagraphSignatureValidationEnabled())
1860  return;
1861 
1862  // Prevent recursive validation since this is triggered on node updates, which we do below.
1863  const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1864  comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1865  SetParagraphSignatureValidation(bOldValidationFlag);
1866  });
1867 
1868  uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1869  const uno::Reference<text::XTextDocument> xDoc(xModel, uno::UNO_QUERY);
1870  uno::Reference<text::XText> xParent = xDoc->getText();
1871  uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xParent, uno::UNO_QUERY);
1872  if (!xParagraphEnumerationAccess.is())
1873  return;
1874  uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
1875  if (!xParagraphs.is())
1876  return;
1877  while (xParagraphs->hasMoreElements())
1878  {
1879  uno::Reference<text::XTextContent> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
1880  lcl_ValidateParagraphSignatures(*GetDoc(), xParagraph, updateDontRemove);
1881  }
1882 }
1883 
1884 static uno::Reference<text::XTextField> lcl_GetParagraphMetadataFieldAtIndex(const SwDocShell* pDocSh, SwTextNode const * pNode, const sal_uLong index)
1885 {
1886  uno::Reference<text::XTextField> xTextField;
1887  if (pNode != nullptr && pDocSh != nullptr)
1888  {
1889  SwTextAttr* pAttr = pNode->GetTextAttrAt(index, RES_TXTATR_METAFIELD);
1890  SwTextMeta* pTextMeta = static_txtattr_cast<SwTextMeta*>(pAttr);
1891  if (pTextMeta != nullptr)
1892  {
1893  SwFormatMeta& rFormatMeta(static_cast<SwFormatMeta&>(pTextMeta->GetAttr()));
1894  if (::sw::Meta* pMeta = rFormatMeta.GetMeta())
1895  {
1896  const css::uno::Reference<css::rdf::XResource> xSubject = pMeta->MakeUnoObject();
1897  uno::Reference<frame::XModel> xModel = pDocSh->GetBaseModel();
1898  const std::map<OUString, OUString> aStatements = lcl_getRDFStatements(xModel, xSubject);
1899  if (aStatements.find(ParagraphSignatureIdRDFName) != aStatements.end() ||
1900  aStatements.find(ParagraphClassificationNameRDFName) != aStatements.end())
1901  {
1902  xTextField = uno::Reference<text::XTextField>(xSubject, uno::UNO_QUERY);
1903  }
1904  }
1905  }
1906  }
1907 
1908  return xTextField;
1909 }
1910 
1912 {
1913  SwDocShell* pDocShell = GetDoc()->GetDocShell();
1914  if (!pDocShell || !IsParagraphSignatureValidationEnabled())
1915  return;
1916 
1917  // Prevent recursive validation since this is triggered on node updates, which we do below.
1918  const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
1919  comphelper::ScopeGuard const g([this, bOldValidationFlag] () {
1920  SetParagraphSignatureValidation(bOldValidationFlag);
1921  });
1922 
1923  uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
1924  const uno::Reference<text::XTextDocument> xDoc(xModel, uno::UNO_QUERY);
1925  uno::Reference<text::XText> xParent = xDoc->getText();
1926  uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xParent, uno::UNO_QUERY);
1927  if (!xParagraphEnumerationAccess.is())
1928  return;
1929  uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
1930  if (!xParagraphs.is())
1931  return;
1932 
1933  static constexpr OUStringLiteral sBlank(u"");
1935  const css::uno::Sequence<css::uno::Reference<rdf::XURI>> aGraphNames = SwRDFHelper::getGraphNames(xModel, MetaNS);
1936 
1937  while (xParagraphs->hasMoreElements())
1938  {
1939  uno::Reference<text::XTextContent> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
1940 
1941  try
1942  {
1943  const css::uno::Reference<css::rdf::XResource> xSubject(xParagraph, uno::UNO_QUERY);
1944  const std::map<OUString, OUString> aStatements = SwRDFHelper::getStatements(xModel, aGraphNames, xSubject);
1945 
1946  const auto it = aStatements.find(ParagraphClassificationFieldNamesRDFName);
1947  const OUString sFieldNames = (it != aStatements.end() ? it->second : sBlank);
1948  std::vector<svx::ClassificationResult> aResults;
1949  if (!sFieldNames.isEmpty())
1950  {
1951  assert(it != aStatements.end() && "can only be non-empty if it was valid");
1952  // Order the fields
1953  sal_Int32 nIndex = 0;
1954  do
1955  {
1956  const OUString sCurFieldName = sFieldNames.getToken(0, '/', nIndex);
1957  if (sCurFieldName.isEmpty())
1958  break;
1959 
1960  const auto it2 = aStatements.find(sCurFieldName);
1961  bool bStatementFound = it2 != aStatements.end();
1962  const OUString sName = bStatementFound ? it->first : sBlank;
1963  const OUString sValue = bStatementFound ? it->second : sBlank;
1964 
1965  if (aKeyCreator.isMarkingTextKey(sName))
1966  {
1967  aResults.push_back({ svx::ClassificationType::TEXT, sValue, sValue, sBlank });
1968  }
1969  else if (aKeyCreator.isCategoryNameKey(sName))
1970  {
1971  const auto it3 = aStatements.find(ParagraphClassificationAbbrRDFName);
1972  const OUString sAbbreviatedName = (it3 != aStatements.end() && !it3->second.isEmpty() ? it3->second : sValue);
1973  aResults.push_back({ svx::ClassificationType::CATEGORY, sValue, sAbbreviatedName, sBlank });
1974  }
1975  else if (aKeyCreator.isCategoryIdentifierKey(sName))
1976  {
1977  const auto it3 = aStatements.find(ParagraphClassificationAbbrRDFName);
1978  const OUString sAbbreviatedName = (it3 != aStatements.end() && !it3->second.isEmpty() ? it3->second : sValue);
1979  aResults.push_back({ svx::ClassificationType::CATEGORY, sBlank, sAbbreviatedName, sValue });
1980  }
1981  else if (aKeyCreator.isMarkingKey(sName))
1982  {
1983  aResults.push_back({ svx::ClassificationType::MARKING, sValue, sValue, sBlank });
1984  }
1985  else if (aKeyCreator.isIntellectualPropertyPartKey(sName))
1986  {
1987  aResults.push_back({ svx::ClassificationType::INTELLECTUAL_PROPERTY_PART, sValue, sValue, sBlank });
1988  }
1989  }
1990  while (nIndex >= 0);
1991  }
1992 
1993  // Update classification based on results.
1994  lcl_ApplyParagraphClassification(GetDoc(), xModel, xParagraph, xSubject, aResults);
1995 
1996  // Get Signatures
1997  std::map<OUString, SignatureDescr> aSignatures;
1998  for (const auto& pair : lcl_getRDFStatements(xModel, xParagraph))
1999  {
2000  const OUString& sName = pair.first;
2001  if (sName.startsWith(ParagraphSignatureRDFNamespace))
2002  {
2003  const OUString sSuffix = sName.copy(ParagraphSignatureRDFNamespace.getLength());
2004  const sal_Int32 index = sSuffix.indexOf(":");
2005  if (index >= 0)
2006  {
2007  const OUString id = sSuffix.copy(0, index);
2008  const OUString type = sSuffix.copy(index);
2009  const OUString& sValue = pair.second;
2010  if (type == ParagraphSignatureDateRDFName)
2011  aSignatures[id].msDate = sValue;
2012  else if (type == ParagraphSignatureUsageRDFName)
2013  aSignatures[id].msUsage = sValue;
2014  else if (type == ParagraphSignatureDigestRDFName)
2015  aSignatures[id].msSignature = sValue;
2016  }
2017  }
2018  }
2019 
2020  for (const auto& pair : aSignatures)
2021  {
2022  uno::Reference<text::XTextField> xField = lcl_findFieldByRDF(xModel, xParagraph, ParagraphSignatureIdRDFName, pair.first);
2023  if (!xField.is())
2024  {
2025  uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xModel, uno::UNO_QUERY);
2026  xField = uno::Reference<text::XTextField>(xMultiServiceFactory->createInstance(MetadataFieldServiceName), uno::UNO_QUERY);
2027 
2028  // Add the signature at the end.
2029  xField->attach(xParagraph->getAnchor()->getEnd());
2030 
2031  const css::uno::Reference<css::rdf::XResource> xFieldSubject(xField, uno::UNO_QUERY);
2032  SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xFieldSubject, ParagraphSignatureIdRDFName, pair.first);
2033 
2034  const OString utf8Text = lcl_getParagraphBodyText(xParagraph);
2035  lcl_UpdateParagraphSignatureField(*GetDoc(), xModel, xParagraph, xField, utf8Text);
2036  }
2037  }
2038 
2039  lcl_ValidateParagraphSignatures(*GetDoc(), xParagraph, true); // Validate and Update signatures.
2040  }
2041  catch (const std::exception&)
2042  {
2043  }
2044  }
2045 }
2046 
2048 {
2049  if (GetCursor() && GetCursor()->Start())
2050  {
2051  SwTextNode* pNode = GetCursor()->Start()->nNode.GetNode().GetTextNode();
2052  const sal_uLong index = GetCursor()->Start()->nContent.GetIndex();
2053  uno::Reference<text::XTextField> xField = lcl_GetParagraphMetadataFieldAtIndex(GetDoc()->GetDocShell(), pNode, index);
2054  return xField.is();
2055  }
2056 
2057  return false;
2058 }
2059 
2061 {
2062  if (GetCursor() && GetCursor()->Start())
2063  {
2064  SwTextNode* pNode = GetCursor()->Start()->nNode.GetNode().GetTextNode();
2066  uno::Reference<text::XTextField> xField = lcl_GetParagraphMetadataFieldAtIndex(GetDoc()->GetDocShell(), pNode, index);
2067  if (!xField.is())
2068  {
2069  // Try moving the cursor to see if we're _facing_ a metafield or not,
2070  // as opposed to being within one.
2071  index--; // Backspace moves left
2072 
2073  xField = lcl_GetParagraphMetadataFieldAtIndex(GetDoc()->GetDocShell(), pNode, index);
2074  }
2075 
2076  if (xField.is())
2077  {
2078  lcl_RemoveParagraphMetadataField(xField);
2079  return true;
2080  }
2081  }
2082 
2083  return false;
2084 }
2085 
2087  const uno::Reference<frame::XModel>& xModel, const uno::Reference<text::XTextContent>& xParagraph)
2088 {
2089  uno::Reference<text::XTextField> xTextField;
2090  xTextField = lcl_FindParagraphClassificationField(xModel, xParagraph, rKeyCreator.makeCategoryIdentifierKey());
2091  if (xTextField.is())
2092  {
2093  const std::pair<OUString, OUString> rdfValuePair = lcl_getRDF(xModel, xTextField, ParagraphClassificationValueRDFName);
2094  return rHelper.GetBACNameForIdentifier(rdfValuePair.second);
2095  }
2096 
2097  xTextField = lcl_FindParagraphClassificationField(xModel, xParagraph, rKeyCreator.makeCategoryNameKey());
2098  if (xTextField.is())
2099  {
2100  return lcl_getRDF(xModel, xTextField, ParagraphClassificationNameRDFName).second;
2101  }
2102 
2103  return OUString();
2104 }
2105 
2107 {
2108  OUString sHighestClass;
2109 
2110  SwTextNode* pNode = pCursor->Start()->nNode.GetNode().GetTextNode();
2111  if (pNode == nullptr)
2112  return sHighestClass;
2113 
2114  SwDocShell* pDocShell = pNode->GetDoc().GetDocShell();
2115  if (!pDocShell)
2116  return sHighestClass;
2117 
2120 
2121  uno::Reference<frame::XModel> xModel = pDocShell->GetBaseModel();
2122  const uno::Reference< text::XTextDocument > xDoc(xModel, uno::UNO_QUERY);
2123  uno::Reference<text::XText> xParent = xDoc->getText();
2124 
2125  uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xParent, uno::UNO_QUERY);
2126  uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration();
2127  while (xParagraphs->hasMoreElements())
2128  {
2129  uno::Reference<text::XTextContent> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
2130  const OUString sCurrentClass = lcl_GetParagraphClassification(aHelper, aKeyCreator, xModel, xParagraph);
2131  sHighestClass = aHelper.GetHigherClass(sHighestClass, sCurrentClass);
2132  }
2133 
2134  return sHighestClass;
2135 }
2136 
2138 {
2139  SwDocShell* pDocShell = GetDoc()->GetDocShell();
2140  if (!pDocShell)
2141  return;
2142 
2143  // Bail out as early as possible if we don't have paragraph classification.
2144  if (!SwRDFHelper::hasMetadataGraph(pDocShell->GetBaseModel(), MetaNS))
2145  return;
2146 
2147  uno::Reference<document::XDocumentProperties> xDocumentProperties = pDocShell->getDocProperties();
2148  uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
2149 
2151  SfxClassificationHelper aHelper(xDocumentProperties);
2152 
2153  OUString sHighestClass = lcl_GetHighestClassificationParagraphClass(GetCursor());
2154 
2155  const OUString aClassificationCategory = svx::classification::getProperty(xPropertyContainer, aKeyCreator.makeCategoryNameKey());
2156 
2157  if (!aClassificationCategory.isEmpty())
2158  {
2159  sHighestClass = aHelper.GetHigherClass(sHighestClass, aClassificationCategory);
2160  }
2161 
2162  if (aClassificationCategory != sHighestClass)
2163  {
2164  std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
2165  VclMessageType::Question, VclButtonsType::Ok,
2166  SwResId(STR_CLASSIFICATION_LEVEL_CHANGED)));
2167  xQueryBox->run();
2168  }
2169 
2170  const SfxClassificationPolicyType eHighestClassType = SfxClassificationHelper::stringToPolicyType(sHighestClass);
2171 
2172  // Prevent paragraph signature validation since the below changes (f.e. watermarking) are benign.
2173  const bool bOldValidationFlag = SetParagraphSignatureValidation(false);
2174  comphelper::ScopeGuard const g([this, bOldValidationFlag]() {
2175  SetParagraphSignatureValidation(bOldValidationFlag);
2176  });
2177 
2178  // Check the origin, if "manual" (created via advanced classification dialog),
2179  // then we just need to set the category name.
2180  if (sfx::getCreationOriginProperty(xPropertyContainer, aKeyCreator) == sfx::ClassificationCreationOrigin::MANUAL)
2181  {
2182  aHelper.SetBACName(sHighestClass, eHighestClassType);
2184  }
2185  else
2186  {
2187  SetClassification(sHighestClass, eHighestClassType);
2188  }
2189 }
2190 
2191 // #i62675#
2193  const bool bResetListAttrs)
2194 {
2195  SwTextFormatColl *pLocal = pFormat? pFormat: (*GetDoc()->GetTextFormatColls())[0];
2196  StartAllAction();
2197 
2198  RedlineFlags eRedlMode = GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags(), eOldMode = eRedlMode;
2199 
2200  SwRewriter aRewriter;
2201 
2202  aRewriter.AddRule(UndoArg1, pLocal->GetName());
2203 
2205  for(SwPaM& rPaM : GetCursor()->GetRingContainer())
2206  {
2207  // If in table cells select mode, ignore the cells that aren't actually selected
2208  if (IsTableMode() && !rPaM.HasMark())
2209  continue;
2210 
2211  if ( !rPaM.HasReadonlySel( GetViewOptions()->IsFormView() ) )
2212  {
2213  // tdf#105413 turn off ShowChanges mode for the next loops to apply styles permanently with redlining,
2214  // ie. in all directly preceding deleted paragraphs at the actual cursor positions
2215  if ( IDocumentRedlineAccess::IsShowChanges(eRedlMode) &&
2216  // is there redlining at beginning of the position (possible redline block before the modified node)
2217  GetDoc()->getIDocumentRedlineAccess().GetRedlinePos( (*rPaM.Start()).nNode.GetNode(), RedlineType::Any ) <
2219  {
2222  }
2223 
2224  // store previous paragraph style for track changes
2225  OUString sParaStyleName;
2226  sal_uInt16 nPoolId = USHRT_MAX;
2227  SwContentNode * pCnt = rPaM.Start()->nNode.GetNode().GetContentNode();
2228  if ( pCnt && pCnt->GetTextNode() && GetDoc()->getIDocumentRedlineAccess().IsRedlineOn() )
2229  {
2230  const SwTextFormatColl* pTextFormatColl = pCnt->GetTextNode()->GetTextColl();
2231  sal_uInt16 nStylePoolId = pTextFormatColl->GetPoolFormatId();
2232  // default paragraph style
2233  if ( nStylePoolId == RES_POOLCOLL_STANDARD )
2234  nPoolId = nStylePoolId;
2235  else
2236  sParaStyleName = pTextFormatColl->GetName();
2237  }
2238 
2239  // Change the paragraph style to pLocal and remove all direct paragraph formatting.
2240  GetDoc()->SetTextFormatColl(rPaM, pLocal, true, bResetListAttrs, GetLayout());
2241 
2242  // If there are hints on the nodes which cover the whole node, then remove those, too.
2243  SwPaM aPaM(*rPaM.Start(), *rPaM.End());
2244  if (SwTextNode* pEndTextNode = aPaM.End()->nNode.GetNode().GetTextNode())
2245  {
2246  aPaM.Start()->nContent = 0;
2247  aPaM.End()->nContent = pEndTextNode->GetText().getLength();
2248  }
2249  GetDoc()->RstTextAttrs(aPaM, /*bInclRefToxMark=*/false, /*bExactRange=*/true, GetLayout());
2250 
2251  // add redline tracking the previous paragraph style
2253  // multi-paragraph ParagraphFormat redline ranges
2254  // haven't supported by AppendRedline(), yet
2255  // TODO handle multi-paragraph selections, too,
2256  // e.g. by breaking them to single paragraphs
2257  aPaM.Start()->nNode == aPaM.End()->nNode )
2258  {
2259  SwRangeRedline * pRedline = new SwRangeRedline( RedlineType::ParagraphFormat, aPaM );
2260  auto const result(GetDoc()->getIDocumentRedlineAccess().AppendRedline( pRedline, true));
2261  // store original paragraph style to reject formatting change
2263  ( nPoolId == RES_POOLCOLL_STANDARD || !sParaStyleName.isEmpty() ) )
2264  {
2265  std::unique_ptr<SwRedlineExtraData_FormatColl> xExtra;
2266  xExtra.reset(new SwRedlineExtraData_FormatColl(sParaStyleName, nPoolId, nullptr));
2267  if (xExtra)
2268  pRedline->SetExtraData( xExtra.get() );
2269  }
2270  }
2271  }
2272 
2273  }
2275  EndAllAction();
2276 
2278 }
2279 
2280 SwTextFormatColl* SwEditShell::MakeTextFormatColl(const OUString& rFormatCollName,
2281  SwTextFormatColl* pParent)
2282 {
2283  SwTextFormatColl *pColl;
2284  if ( pParent == nullptr )
2285  pParent = &GetTextFormatColl(0);
2286  pColl = GetDoc()->MakeTextFormatColl(rFormatCollName, pParent);
2287  if ( pColl == nullptr )
2288  {
2289  OSL_FAIL( "MakeTextFormatColl failed" );
2290  }
2291  return pColl;
2292 
2293 }
2294 
2296 {
2297  SwPaM * pCursor = GetCursor();
2298  SwContentNode * pCnt = pCursor->GetContentNode();
2299  if (pCnt->IsTextNode()) // uhm... what nonsense would happen if not?
2300  { // only need properties-node because BREAK/PAGEDESC filtered anyway!
2301  pCnt = sw::GetParaPropsNode(*GetLayout(), pCursor->GetPoint()->nNode);
2302  }
2303  const SfxItemSet* pSet = pCnt->GetpSwAttrSet();
2304  if( !pSet )
2305  return;
2306 
2307  // JP 05.10.98: Special treatment if one of the attributes Break/PageDesc/NumRule(auto) is
2308  // in the ItemSet. Otherwise there will be too much or wrong processing (NumRules!)
2309  // Bug 57568
2310 
2311  // Do NOT copy AutoNumRules into the template
2312  const SfxPoolItem* pItem;
2313  const SwNumRule* pRule = nullptr;
2314  if (SfxItemState::SET == pSet->GetItemState(RES_BREAK, false)
2315  || SfxItemState::SET == pSet->GetItemState(RES_PAGEDESC, false)
2316  || (SfxItemState::SET == pSet->GetItemState(RES_PARATR_NUMRULE, false, &pItem)
2317  && nullptr != (pRule = GetDoc()->FindNumRulePtr(
2318  static_cast<const SwNumRuleItem*>(pItem)->GetValue()))
2319  && pRule->IsAutoRule()))
2320  {
2321  SfxItemSet aSet( *pSet );
2322  aSet.ClearItem( RES_BREAK );
2323  aSet.ClearItem( RES_PAGEDESC );
2324 
2325  if (pRule
2326  || (SfxItemState::SET == pSet->GetItemState(RES_PARATR_NUMRULE, false, &pItem)
2327  && nullptr != (pRule = GetDoc()->FindNumRulePtr(
2328  static_cast<const SwNumRuleItem*>(pItem)->GetValue()))
2329  && pRule->IsAutoRule()))
2330  aSet.ClearItem( RES_PARATR_NUMRULE );
2331 
2332  if( aSet.Count() )
2333  GetDoc()->ChgFormat(*pColl, aSet );
2334  }
2335  else
2336  GetDoc()->ChgFormat(*pColl, *pSet );
2337 }
2338 
2339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::Long const nBottomMargin
SwTextFormatColl * MakeTextFormatColl(const OUString &rFormatName, SwTextFormatColl *pDerivedFrom, bool bBroadcast=false)
Create the FormatCollections.
Definition: docfmt.cxx:890
void SetText(const OUString &aText)
OUString makeNumberedIntellectualPropertyPartKey()
Base class of the Writer layout elements.
Definition: frame.hxx:315
constexpr TypedWhichId< SwFormatPageDesc > RES_PAGEDESC(93)
sal_Int32 nIndex
void SetFontSize(const Size &)
static const OUString & policyTypeToString(SfxClassificationPolicyType eType)
Represents the style of a paragraph.
Definition: fmtcol.hxx:56
void insertCreationOrigin(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator, sfx::ClassificationCreationOrigin eOrigin)
Marks a position in the document model.
Definition: pam.hxx:36
#define UNO_NAME_TEXT_MINFRAMEHEIGHT
SwPageDesc * FindPageDesc()
Definition: pagechg.cxx:747
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
static const OUString & PROP_DOCFOOTER()
std::vector< svx::ClassificationResult > CollectParagraphClassification()
Definition: edfcol.cxx:1343
SfxWatermarkItem GetWatermark() const
Definition: edfcol.cxx:1383
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
static SfxClassificationPolicyType stringToPolicyType(std::u16string_view rType)
SwUndoId
Definition: swundo.hxx:29
#define UNO_NAME_CHAR_FONT_NAME
Definition: unoprnms.hxx:84
SwDocShell * GetDocShell()
Definition: doc.hxx:1352
std::unique_ptr< ContentProperties > pData
std::string GetValue
css::uno::Reference< css::text::XTextField > m_xField
#define UNO_NAME_TEXT_FIELD
Definition: unoprnms.hxx:342
SwNodeIndex nNode
Definition: pam.hxx:38
bool IsTableMode() const
Definition: crsrsh.hxx:643
sal_uInt16 GetTextFormatCollCount() const
Definition: edfcol.cxx:694
sal_uInt16 char char * pDesc
tools::Long const nLeftMargin
OUStringBuffer & remove(OUStringBuffer &rIn, sal_Unicode c)
sal_uIntPtr sal_uLong
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
static css::uno::Reference< css::text::XTextContent > CreateXParagraph(SwDoc &rDoc, SwTextNode *pTextNode, css::uno::Reference< css::text::XText > const &xParentText=nullptr, const sal_Int32 nSelStart=-1, const sal_Int32 nSelEnd=-1)
constexpr TypedWhichId< SwNumRuleItem > RES_PARATR_NUMRULE(72)
bool IsAutoRule() const
Definition: numrule.hxx:230
#define UNO_NAME_FILLSTYLE
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
static const OUString & PROP_PREFIX_INTELLECTUALPROPERTY()
Definition: doc.hxx:188
void ValidateCurrentParagraphSignatures(bool updateDontRemove)
Validate the current paragraph signatures, if any, at the cursor start.
Definition: edfcol.cxx:1844
sal_Int16 GetTransparency() const
std::vector< unsigned char > DecodeHexString(const OString &rHex)
constexpr TypedWhichId< SvxFormatBreakItem > RES_BREAK(94)
X509CertInfo const * GetSigningCertificate() const
SwNode & GetNode() const
Definition: ndindex.hxx:121
void RestoreMetadataFieldsAndValidateParagraphSignatures()
Restore the metadata fields, if missing, from the RDF metadata and validate the signatures and update...
Definition: edfcol.cxx:1911
#define UNO_NAME_BOTTOM_MARGIN
Definition: unoprnms.hxx:322
static uno::Reference< text::XTextField > lcl_GetParagraphMetadataFieldAtIndex(const SwDocShell *pDocSh, SwTextNode const *pNode, const sal_uLong index)
Definition: edfcol.cxx:1884
static SfxObjectShell * Current()
#define UNO_NAME_VERT_ORIENT
Definition: unoprnms.hxx:330
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
bool SetParagraphSignatureValidation(const bool bEnable)
Enable/Disable paragraph signature validation and return the previous value.
Definition: editsh.hxx:970
bool isCategoryIdentifierKey(std::u16string_view aKey) const
void SignParagraph()
Sign the paragraph at the cursor.
Definition: edfcol.cxx:1751
SwTextAttr * GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich, enum GetTextAttrMode const eMode=DEFAULT) const
get the innermost text attribute covering position nIndex.
Definition: ndtxt.cxx:1691
static OUString lcl_GetParagraphClassification(SfxClassificationHelper &rHelper, sfx::ClassificationKeyCreator const &rKeyCreator, const uno::Reference< frame::XModel > &xModel, const uno::Reference< text::XTextContent > &xParagraph)
Definition: edfcol.cxx:2086
void EndAllAction()
Definition: edws.cxx:97
The root element of a Writer document layout.
Definition: rootfrm.hxx:82
bool isIntellectualPropertyPartKey(std::u16string_view aKey) const
constexpr double rad2deg(double v)
#define UNO_NAME_TEXT_WRAP
Definition: unoprnms.hxx:314
css::uno::Reference< css::document::XDocumentProperties > getDocProperties() const
bool isCategoryNameKey(std::u16string_view aKey) const
static bool IsShowChanges(const RedlineFlags eM)
#define UNO_NAME_TEXT_AUTOGROWWIDTH
double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
show all inserts
size_type size() const
Definition: docary.hxx:268
bool RemoveParagraphMetadataFieldAtCursor()
Removes the paragraph metadata field at the current cursor, if any.
Definition: edfcol.cxx:2060
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:230
#define UNO_NAME_FILLCOLOR
bool IsRedlineOn() const
Definition: edredln.cxx:43
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:165
SwDoc & m_rDoc
Definition: docbm.cxx:1204
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:170
void SetWatermark(const SfxWatermarkItem &rText)
Definition: edfcol.cxx:1608
SwTextFormatColl & GetTextFormatColl(sal_uInt16 nTextFormatColl) const
Definition: edfcol.cxx:699
void FillByEx(SwCharFormat *)
Definition: edfmt.cxx:52
PropertiesInfo aProperties
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.
SwIndex nContent
Definition: pam.hxx:39
static sal_Int16 lcl_GetAngle(const drawing::HomogenMatrix3 &rMatrix)
Definition: edfcol.cxx:1360
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter .
Definition: docfmt.cxx:1085
sal_uInt16 GetMonth() const
A wrapper around SfxPoolItem to store the start position of (usually) a text portion, with an optional end.
Definition: txatbase.hxx:41
OUString sSuffix
static OUString lcl_GetHighestClassificationParagraphClass(SwPaM *pCursor)
Definition: edfcol.cxx:2106
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:776
static bool IsRedlineOn(const RedlineFlags eM)
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:174
void removeAllProperties(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer)
const OUString & GetName() const
Definition: format.hxx:115
void ApplyAdvancedClassification(std::vector< svx::ClassificationResult > const &rResult)
Definition: edfcol.cxx:777
sfx::ClassificationCreationOrigin getCreationOriginProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator)
#define UNO_NAME_SIZE
Definition: unoprnms.hxx:304
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
constexpr OUStringLiteral WATERMARK_NAME
Definition: edfcol.cxx:103
void SetTransparency(const sal_Int16 nTransparency)
::sw::Meta * GetMeta()
Definition: fmtmeta.hxx:122
SwDoc * GetDoc() const
Definition: viewsh.hxx:282
#define UNO_NAME_VERT_ORIENT_RELATION
Definition: unoprnms.hxx:333
css::uno::Reference< css::text::XTextContent > m_xParent
OUString getProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, OUString const &rName)
const IDocumentRedlineAccess & getIDocumentRedlineAccess() const
Provides access to the document redline interface.
Definition: viewsh.cxx:2724
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
virtual bool DoesUndo() const =0
Is Undo enabled?
void SetExtraData(const SwRedlineExtraData *pData)
ExtraData gets copied, the pointer is therefore not taken over by the RedLineObject.
Definition: redline.hxx:213
ClassificationType meType
const char * sName
static DateTime CreateFromUnixTime(const double fSecondsSinceEpoch)
sal_uInt16 GetPoolFormatId() const
Get and set Pool style IDs.
Definition: format.hxx:147
#define UNO_NAME_TOP_MARGIN
Definition: unoprnms.hxx:321
static sal_Int32 getNumberOfParagraphs(uno::Reference< text::XText > const &xText)
Definition: edfcol.cxx:748
sal_Int16 GetYear() const
static void removeAllClassificationFields(std::u16string_view rPolicy, uno::Reference< text::XText > const &rxText)
Definition: edfcol.cxx:715
#define UNO_NAME_HORI_ORIENT
Definition: unoprnms.hxx:261
#define UNO_NAME_HEADER_TEXT_LEFT
Definition: unoprnms.hxx:368
#define WATERMARK_AUTO_SIZE
Definition: edfcol.cxx:104
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:451
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const =0
SwNumRule * FindNumRulePtr(const OUString &rName) const
Definition: docnum.cxx:2415
#define DBG_UNHANDLED_EXCEPTION(...)
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
void ValidateParagraphSignatures(SwTextNode *pNode, bool updateDontRemove)
Validate the paragraph signatures, if any, of the current text node.
Definition: edfcol.cxx:1825
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
void SetTextFormatColl(SwTextFormatColl *, const bool bResetListAttrs=false)
Add 2nd optional parameter - see also
Definition: edfcol.cxx:2192
OUString const & GetText() const
css::xml::crypto::SecurityOperationStatus nStatus
bool IsParagraphSignatureValidationEnabled() const
Returns true iff paragraph signature validation is enabled.
Definition: editsh.hxx:968
#define UNO_NAME_HEADER_IS_DYNAMIC_HEIGHT
Definition: unoprnms.hxx:382
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
void SetFamilyName(const OUString &rFamilyName)
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
SwDoc & GetDoc()
Definition: node.hxx:213
const SwPosition * GetPoint() const
Definition: pam.hxx:208
SfxClassificationPolicyType
#define UNO_NAME_FILL_TRANSPARENCE
OUString makeCategoryIdentifierKey() const
virtual void RepeatImpl(::sw::RepeatContext &) override
Definition: edfcol.cxx:1710
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
void rotate(double fRadiant)
SwEditShell const * GetEditShell() const
Definition: doccorr.cxx:328
void SetColor(Color nColor)
static std::vector< svx::ClassificationResult > lcl_CollectParagraphClassification(const uno::Reference< frame::XModel > &xModel, const uno::Reference< text::XTextContent > &xParagraph)
Definition: edfcol.cxx:1285
void insertFullTextualRepresentationAsDocumentProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, sfx::ClassificationKeyCreator const &rKeyCreator, std::vector< svx::ClassificationResult > const &rResults)
#define UNO_NAME_HEADER_HEIGHT
Definition: unoprnms.hxx:384
bool isMarkingKey(std::u16string_view aKey) const
SwContentNode * GetContentNode()
Definition: node.hxx:617
Any aHelper
sal_uInt16 Count() const
OUString GetDocumentWatermark()
static const OUString & PROP_DOCHEADER()
void ApplyParagraphClassification(std::vector< svx::ClassificationResult > aResult)
Apply the classification to the paragraph at cursor.
Definition: edfcol.cxx:1264
float u
#define UNO_NAME_FOOTER_IS_ON
Definition: unoprnms.hxx:401
size_t size() const
Definition: docary.hxx:88
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:25
void scale(double fX, double fY)
css::uno::Reference< css::frame::XModel3 > GetBaseModel() const
sal_uInt16 GetDay() const
void ConvertToLocalTime()
constexpr double deg2rad(double v)
static SfxClassificationPolicyType getPolicyType()
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:241
ring_container GetRingContainer()
PropertyValueVector_t aPropertyValues
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
void SetClassification(const OUString &rName, SfxClassificationPolicyType eType)
Definition: edfcol.cxx:1068
tuple index
OUString sPrefix
A page of the document layout.
Definition: pagefrm.hxx:57
#define UNO_NAME_HEADER_TEXT_RIGHT
Definition: unoprnms.hxx:369
const SwPosition * Start() const
Definition: pam.hxx:213
void RstTextAttrs(const SwPaM &rRg, bool bInclRefToxMark=false, bool bExactRange=false, SwRootFrame const *pLayout=nullptr)
Definition: docfmt.cxx:221
#define UNO_NAME_RIGHT_MARGIN
Definition: unoprnms.hxx:69
#define UNO_NAME_LINESTYLE
exports com.sun.star.chart2. data
SwTextNode * GetParaPropsNode(SwRootFrame const &rLayout, SwNodeIndex const &rNode)
Definition: txtfrm.cxx:328
#define UNO_NAME_TEXT_PORTION_TYPE
Definition: unoprnms.hxx:475
OUString const & GetFont() const
ignore Redlines
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:175
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
tools::Long const nTopMargin
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:194
OUString GetBACNameForIdentifier(std::u16string_view sIdentifier)
#define UNO_NAME_LEFT_MARGIN
Definition: unoprnms.hxx:68
const SwTextFormatColls * GetTextFormatColls() const
Definition: doc.hxx:778
#define UNO_NAME_ANCHOR_TYPE
Definition: unoprnms.hxx:226
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:424
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
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
virtual void SetRedlineFlags(RedlineFlags eMode)=0
Set a new redline mode.
OUString aName
OUString GetHigherClass(const OUString &first, const OUString &second)
sal_Int32 GetIndex() const
Definition: index.hxx:91
void SetBACName(const OUString &rName, SfxClassificationPolicyType eType)
void ValidateAllParagraphSignatures(bool updateDontRemove)
Validate all paragraph signatures.
Definition: edfcol.cxx:1856
#define UNO_NAME_HORI_ORIENT_RELATION
Definition: unoprnms.hxx:264
SwFrame * GetLower()
Definition: findfrm.cxx:170
#define UNO_NAME_TEXT_AUTOGROWHEIGHT
Reference< XComponentContext > getProcessComponentContext()
void SetFont(const OUString &aFont)
virtual void UndoImpl(::sw::UndoRedoContext &) override
Definition: edfcol.cxx:1694
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
#define UNO_NAME_HEADER_IS_ON
Definition: unoprnms.hxx:385
tools::Long const nRightMargin
bool Sign(OStringBuffer &rCMSHexBuffer)
#define UNO_NAME_FOOTER_TEXT
Definition: unoprnms.hxx:370
OUString makeCategoryNameKey() const
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
Color GetColor() const
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:357
#define UNO_NAME_HEADER_TEXT
Definition: unoprnms.hxx:367
SwUndoParagraphSigning(SwDoc &rDoc, const css::uno::Reference< css::text::XTextField > &xField, const css::uno::Reference< css::text::XTextContent > &xParent, const bool bRemove)
Definition: edfcol.cxx:1669
void ChgFormat(SwFormat &rFormat, const SfxItemSet &rSet)
Definition: docfmt.cxx:1874
static void equaliseNumberOfParagraph(std::vector< svx::ClassificationResult > const &rResults, uno::Reference< text::XText > const &xText)
Definition: edfcol.cxx:761
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:163
#define UNO_NAME_CHAR_HEIGHT
Any result
ResultType type
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
bool IsCursorInParagraphMetadataField() const
Returns true iff the cursor is within a paragraph metadata field.
Definition: edfcol.cxx:2047
SwTextFormatColl & GetDfltTextFormatColl() const
Definition: edfcol.cxx:689
Reference< XModel > xModel
static void lcl_ApplyParagraphClassification(SwDoc *pDoc, const uno::Reference< frame::XModel > &xModel, const uno::Reference< text::XTextContent > &xParent, const css::uno::Reference< css::rdf::XResource > &xNodeSubject, std::vector< svx::ClassificationResult > aResults)
Definition: edfcol.cxx:1160
bool addOrInsertDocumentProperty(uno::Reference< beans::XPropertyContainer > const &rxPropertyContainer, OUString const &rsKey, OUString const &rsValue)
std::vector< svx::ClassificationResult > CollectAdvancedClassification()
Definition: edfcol.cxx:947
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.
const char *const aFieldNames[]
Definition: authfld.cxx:649
SwTextFormatColl * MakeTextFormatColl(const OUString &rFormatCollName, SwTextFormatColl *pDerivedFrom=nullptr)
Definition: edfcol.cxx:2280
virtual const SwRedlineTable & GetRedlineTable() const =0
void AddDataRange(const void *pData, sal_Int32 size)
void SetAngle(const sal_Int16 nAngle)
constexpr OUStringLiteral first
void StartAllAction()
For all views of this document.
Definition: edws.cxx:86
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2122
void ClassifyDocPerHighestParagraphClass()
Ensure that the classification of the doc is never lower than the paragraph with the highest classifi...
Definition: edfcol.cxx:2137
bool IsTextNode() const
Definition: node.hxx:638
virtual void RedoImpl(::sw::UndoRedoContext &) override
Definition: edfcol.cxx:1702
static bool Verify(const std::vector< unsigned char > &aData, const bool bNonDetached, const std::vector< unsigned char > &aSignature, SignatureInformation &rInformation)
#define UNO_NAME_OPAQUE
Definition: unoprnms.hxx:283
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, bool bMobile=false)
sal_Int16 GetAngle() const
bool isMarkingTextKey(std::u16string_view aKey) const
#define UNO_NAME_NAME
Definition: unoprnms.hxx:77
#define UNO_NAME_TEXT_MINFRAMEWIDTH
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:856
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
#define UNO_NAME_HEADER_TEXT_FIRST
Definition: unoprnms.hxx:831
SwFrame * GetNext()
Definition: frame.hxx:677
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:850
OUString sId