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