/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/// Find all page styles which are currently used in the document.
std::vector<ProgName> lcl_getUsedPageStyles(SwViewShell const * pShell)
{
std::vector<ProgName> aReturn;
/// Search for a field named rFieldName of type rServiceName in xText and return it.
uno::Reference<text::XTextField> lcl_findField(const uno::Reference<text::XText>& xText, const OUString& rServiceName, std::u16string_view rFieldName)
{
uno::Reference<text::XTextField> xField;
uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xText, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration(); while (xParagraphs->hasMoreElements())
{
uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration(); while (xTextPortions->hasMoreElements())
{
uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
OUString aTextPortionType;
xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType; if (aTextPortionType != UNO_NAME_TEXT_FIELD) continue;
uno::Reference<lang::XServiceInfo> xTextField;
xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xTextField; if (!xTextField->supportsService(rServiceName)) continue;
/// Search for a field named rFieldName of type rServiceName in xText and return true iff found. bool lcl_hasField(const uno::Reference<text::XText>& xText, const OUString& rServiceName, std::u16string_view rFieldName)
{ return lcl_findField(xText, rServiceName, rFieldName).is();
}
/// Search for a frame with WATERMARK_NAME in name of type rServiceName in xText. Returns found name in rShapeName.
uno::Reference<drawing::XShape> lcl_getWatermark(const uno::Reference<text::XText>& xText, const OUString& rServiceName, OUString& rShapeName, bool& bSuccess)
{
bSuccess = false;
uno::Reference<container::XEnumerationAccess> xParagraphEnumerationAccess(xText, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xParagraphs = xParagraphEnumerationAccess->createEnumeration(); while (xParagraphs->hasMoreElements())
{
uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xParagraphs->nextElement(), uno::UNO_QUERY); if (!xTextPortionEnumerationAccess.is()) continue;
bSuccess = true;
uno::Reference<container::XEnumeration> xTextPortions = xTextPortionEnumerationAccess->createEnumeration(); while (xTextPortions->hasMoreElements())
{
uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
OUString aTextPortionType;
xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType; if (aTextPortionType != "Frame") continue;
uno::Reference<container::XContentEnumerationAccess> xContentEnumerationAccess(xTextPortion, uno::UNO_QUERY); if (!xContentEnumerationAccess.is()) continue;
uno::Reference<container::XEnumeration> xEnumeration = xContentEnumerationAccess->createContentEnumeration(u"com.sun.star.text.TextContent"_ustr); if (!xEnumeration->hasMoreElements()) continue;
uno::Reference<lang::XServiceInfo> xWatermark(xEnumeration->nextElement(), uno::UNO_QUERY); if (!xWatermark->supportsService(rServiceName)) continue;
/// Extract the text of the paragraph without any of the fields. /// TODO: Consider moving to SwTextNode, or extend ModelToViewHelper.
OString lcl_getParagraphBodyText(const uno::Reference<text::XTextContent>& xText)
{
OUStringBuffer strBuf;
uno::Reference<container::XEnumerationAccess> xTextPortionEnumerationAccess(xText, uno::UNO_QUERY); if (!xTextPortionEnumerationAccess.is()) return OString();
/// Returns true iff the field in question is paragraph signature. /// Note: must have associated RDF, since signatures are otherwise just metadata fields. bool lcl_IsParagraphSignatureField(const rtl::Reference<SwXTextDocument>& xModel, const uno::Reference<css::text::XTextField>& xField)
{ return (lcl_getRDF(xModel, xField, ParagraphSignatureIdRDFName).first == ParagraphSignatureIdRDFName);
}
/// Validate and create the signature field display text from the fields.
std::pair<bool, OUString> lcl_MakeParagraphSignatureFieldText(const SignatureDescr& aDescr, const OString& utf8Text)
{
OUString msg = SwResId(STR_INVALID_SIGNATURE); bool valid = false;
/// Validate and return validation result and signature field display text.
std::pair<bool, OUString>
lcl_MakeParagraphSignatureFieldText(const rtl::Reference<SwXTextDocument>& xModel, const uno::Reference<css::text::XTextContent>& xParagraph, const uno::Reference<css::text::XTextField>& xField, const OString& utf8Text)
{ const SignatureDescr aDescr = lcl_getSignatureDescr(xModel, xParagraph, xField); return lcl_MakeParagraphSignatureFieldText(aDescr, utf8Text);
}
/// Generate the next valid ID for the new signature on this paragraph.
OUString lcl_getNextSignatureId(const rtl::Reference<SwXTextDocument>& xModel, const uno::Reference<text::XTextContent>& xParagraph)
{ const OUString sFieldId = lcl_getRDF(xModel, xParagraph, ParagraphSignatureLastIdRDFName).second; return OUString::number(!sFieldId.isEmpty() ? sFieldId.toInt32() + 1 : 1);
}
/// Creates and inserts Paragraph Signature Metadata field and creates the RDF entry
uno::Reference<text::XTextField> lcl_InsertParagraphSignature(const rtl::Reference<SwXTextDocument>& xModel, const uno::Reference<text::XTextContent>& xParagraph, const OUString& signature, const OUString& usage)
{ auto xField = uno::Reference<text::XTextField>(xModel->createInstance(MetadataFieldServiceName), uno::UNO_QUERY);
// Add the signature at the end.
xField->attach(xParagraph->getAnchor()->getEnd());
// First convert the UTC UNIX timestamp to a tools::DateTime then to local time.
DateTime aDateTime = DateTime::CreateFromUnixTime(time(nullptr));
aDateTime.ConvertToLocalTime();
OUStringBuffer rBuffer;
rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
rBuffer.append('-'); if (aDateTime.GetMonth() < 10)
rBuffer.append('0');
rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
rBuffer.append('-'); if (aDateTime.GetDay() < 10)
rBuffer.append('0');
rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
// Now set the RDF on the paragraph, since that's what is preserved in .doc(x). const css::uno::Reference<css::rdf::XResource> xParaSubject(xParagraph, uno::UNO_QUERY); const OUString prefix = ParagraphSignatureRDFNamespace + sId;
SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, ParagraphSignatureLastIdRDFName, sId);
SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDigestRDFName, signature);
SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureUsageRDFName, usage);
SwRDFHelper::addStatement(xModel, MetaNS, MetaFilename, xParaSubject, prefix + ParagraphSignatureDateRDFName, rBuffer.makeStringAndClear());
return xField;
}
/// Updates the signature field text if changed and returns true only iff updated. bool lcl_DoUpdateParagraphSignatureField(SwDoc& rDoc, const uno::Reference<css::text::XTextField>& xField, const OUString& sDisplayText)
{ // Disable undo to avoid introducing noise when we edit the metadata field. constbool isUndoEnabled = rDoc.GetIDocumentUndoRedo().DoesUndo();
rDoc.GetIDocumentUndoRedo().DoUndo(false);
comphelper::ScopeGuard const g([&rDoc, isUndoEnabled]() {
rDoc.GetIDocumentUndoRedo().DoUndo(isUndoEnabled);
});
// Enumerate text portions to find metadata fields. This is expensive, best to enumerate fields only.
rtl::Reference<SwXTextPortionEnumeration> xTextPortions = xParagraph->createTextFieldsEnumeration(); while (xTextPortions->hasMoreElements())
{
uno::Reference<beans::XPropertySet> xTextPortion(xTextPortions->nextElement(), uno::UNO_QUERY);
OUString aTextPortionType;
xTextPortion->getPropertyValue(UNO_NAME_TEXT_PORTION_TYPE) >>= aTextPortionType; if (aTextPortionType != UNO_NAME_TEXT_FIELD) continue;
uno::Reference<lang::XServiceInfo> xServiceInfo;
xTextPortion->getPropertyValue(UNO_NAME_TEXT_FIELD) >>= xServiceInfo; if (!xServiceInfo->supportsService(MetadataFieldServiceName)) continue;
// Apply properties from the BA policy for (svx::ClassificationResult const & rResult : rResults)
{ if (rResult.meType == svx::ClassificationType::CATEGORY)
{
aHelper.SetBACName(rResult.msName, SfxClassificationHelper::getPolicyType());
}
}
// Insert full text as document property
svx::classification::insertFullTextualRepresentationAsDocumentProperty(xPropertyContainer, aCreator, rResults);
for (const ProgName& rPageStyleName : aUsedPageStyles)
{
uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName.toString()), uno::UNO_QUERY);
case svx::ClassificationType::PARAGRAPH:
{
nParagraph++;
if (nParagraph != 0) // only jump to next paragraph, if we aren't at the first paragraph
{
xHeaderParagraphCursor->gotoNextParagraph(false);
xFooterParagraphCursor->gotoNextParagraph(false);
}
for (const OUString& rPageStyleName : aStyles)
{
uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(rPageStyleName), uno::UNO_QUERY);
if (bHeaderIsNeeded || bWatermarkIsNeeded || bHadWatermark)
{ // If the header is off, turn it on. bool bHeaderIsOn = false;
xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn; if (!bHeaderIsOn)
xPageStyle->setPropertyValue(UNO_NAME_HEADER_IS_ON, uno::Any(true));
// If the header already contains a document header field, no need to do anything.
uno::Reference<text::XText> xHeaderText;
xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
if (bHeaderIsNeeded)
{ if (!lcl_hasField(xHeaderText, DocInfoServiceName, Concat2View(SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY() + SfxClassificationHelper::PROP_DOCHEADER())))
{ // Append a field to the end of the header text.
uno::Reference<beans::XPropertySet> xField(xModel->createInstance(DocInfoServiceName), uno::UNO_QUERY);
xField->setPropertyValue(UNO_NAME_NAME, uno::Any(SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY() + SfxClassificationHelper::PROP_DOCHEADER()));
uno::Reference<text::XTextContent> xTextContent(xField, uno::UNO_QUERY);
xHeaderText->insertTextContent(xHeaderText->getEnd(), xTextContent, /*bAbsorb=*/false);
}
}
if (bFooterIsNeeded)
{ // If the footer is off, turn it on. bool bFooterIsOn = false;
xPageStyle->getPropertyValue(UNO_NAME_FOOTER_IS_ON) >>= bFooterIsOn; if (!bFooterIsOn)
xPageStyle->setPropertyValue(UNO_NAME_FOOTER_IS_ON, uno::Any(true));
// If the footer already contains a document header field, no need to do anything.
uno::Reference<text::XText> xFooterText;
xPageStyle->getPropertyValue(UNO_NAME_FOOTER_TEXT) >>= xFooterText; static OUString sFooter = SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY() + SfxClassificationHelper::PROP_DOCFOOTER(); if (!lcl_hasField(xFooterText, DocInfoServiceName, sFooter))
{ // Append a field to the end of the footer text.
uno::Reference<beans::XPropertySet> xField(xModel->createInstance(DocInfoServiceName), uno::UNO_QUERY);
xField->setPropertyValue(UNO_NAME_NAME, uno::Any(sFooter));
uno::Reference<text::XTextContent> xTextContent(xField, uno::UNO_QUERY);
xFooterText->insertTextContent(xFooterText->getEnd(), xTextContent, /*bAbsorb=*/false);
}
}
}
}
// We pass xParent and xNodeSubject even though they point to the same thing because the UNO_QUERY is // on a performance-sensitive path. staticvoid lcl_ApplyParagraphClassification(SwDoc* pDoc, const rtl::Reference<SwXTextDocument>& xModel, const rtl::Reference<SwXParagraph>& xParent, const css::uno::Reference<css::rdf::XResource>& xNodeSubject,
std::vector<svx::ClassificationResult> aResults)
{ if (!xNodeSubject.is()) return;
// Remove all paragraph classification fields. for (;;)
{
uno::Reference<text::XTextField> xTextField = lcl_FindParagraphClassificationField(xModel, xParent); if (!xTextField.is()) break;
lcl_RemoveParagraphMetadataField(xTextField);
}
if (aResults.empty()) return;
// Since we always insert at the start of the paragraph, // need to insert in reverse order.
std::reverse(aResults.begin(), aResults.end()); // Ignore "PARAGRAPH" types
std::erase_if(aResults,
[](const svx::ClassificationResult& rResult)-> bool
{ return rResult.meType == svx::ClassificationType::PARAGRAPH; });
// Correct the order
std::reverse(aFieldNames.begin(), aFieldNames.end());
OUStringBuffer sFieldNames; bool first = true; for (const OUString& rFieldName : aFieldNames)
{ if (!first)
sFieldNames.append("/");
sFieldNames.append(rFieldName);
first = false;
}
SwTextNode* pNode = GetCursor()->Start()->GetNode().GetTextNode(); if (pNode == nullptr) return;
// Prevent recursive validation since this is triggered on node updates, which we do below. constbool bOldValidationFlag = SetParagraphSignatureValidation(false);
comphelper::ScopeGuard const g([this, bOldValidationFlag]() {
SetParagraphSignatureValidation(bOldValidationFlag);
});
if (xWatermark.is())
{
SfxWatermarkItem aItem;
uno::Reference<text::XTextRange> xTextRange(xWatermark, uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPropertySet(xWatermark, uno::UNO_QUERY);
Color nColor;
sal_Int16 nTransparency;
OUString aFont;
drawing::HomogenMatrix3 aMatrix;
aItem.SetText(xTextRange->getString());
if (xPropertySet->getPropertyValue(UNO_NAME_CHAR_FONT_NAME) >>= aFont)
aItem.SetFont(aFont); if (xPropertySet->getPropertyValue(UNO_NAME_FILLCOLOR) >>= nColor)
aItem.SetColor(nColor); if (xPropertySet->getPropertyValue(u"Transformation"_ustr) >>= aMatrix)
aItem.SetAngle(lcl_GetAngle(aMatrix)); if (xPropertySet->getPropertyValue(UNO_NAME_FILL_TRANSPARENCE) >>= nTransparency)
aItem.SetTransparency(nTransparency);
// If the header already contains a watermark, see if it its text is up to date.
uno::Reference<text::XTextRange> xTextRange(xWatermark, uno::UNO_QUERY);
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.