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