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