/* -*- 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 .
*/
#include <sal/config.h>
#include <o3tl/any.hxx>
#include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/types.h>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/container/XEnumeration.hpp>
#include <com/sun/star/container/XIndexReplace.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/beans/UnknownPropertyException.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/text/XTextSectionsSupplier.hpp>
#include <com/sun/star/text/XTextTablesSupplier.hpp>
#include <com/sun/star/text/XNumberingRulesSupplier.hpp>
#include <com/sun/star/text/XChapterNumberingSupplier.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/text/XTextContent.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
#include <com/sun/star/text/XTextFrame.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/text/SizeType.hpp>
#include <com/sun/star/text/HoriOrientation.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <com/sun/star/text/XTextFramesSupplier.hpp>
#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/document/XEventsSupplier.hpp>
#include <com/sun/star/document/XRedlinesSupplier.hpp>
#include <com/sun/star/text/XFormField.hpp>
#include <com/sun/star/text/XTextSection.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/style/XAutoStylesSupplier.hpp>
#include <com/sun/star/style/XAutoStyleFamily.hpp>
#include <com/sun/star/text/XTextFieldsSupplier.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <sax/tools/converter.hxx>
#include <xmloff/xmlnamespace.hxx>
#include <xmloff/xmlaustp.hxx>
#include <xmloff/families.hxx>
#include "txtexppr.hxx"
#include <xmloff/xmluconv.hxx>
#include "XMLAnchorTypePropHdl.hxx"
#include <xexptran.hxx>
#include <xmloff/ProgressBarHelper.hxx>
#include <xmloff/namespacemap.hxx>
#include <xmloff/xmlexp.hxx>
#include <txtflde.hxx>
#include <xmloff/txtprmap.hxx>
#include <XMLImageMapExport.hxx>
#include "XMLTextNumRuleInfo.hxx"
#include <xmloff/XMLTextListAutoStylePool.hxx>
#include <xmloff/txtparae.hxx>
#include "XMLSectionExport.hxx"
#include "XMLIndexMarkExport.hxx"
#include <xmloff/XMLEventExport.hxx>
#include "XMLRedlineExport.hxx"
#include <MultiPropertySetHelper.hxx>
#include <xmloff/formlayerexport.hxx>
#include "XMLTextCharStyleNamesElementExport.hxx"
#include <xmloff/odffields.hxx>
#include <xmloff/maptype.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XTransactedObject.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <txtlists.hxx>
#include <com/sun/star/rdf/XMetadatable.hpp>
#include <list>
#include <unordered_map>
#include <memory>
#include <vector>
#include <algorithm>
#include <iterator>
#include <officecfg/Office/Common.hxx>
#include <o3tl/safeint.hxx>
#include <comphelper/scopeguard.hxx>
#include <comphelper/sequenceashashmap.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::style;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::document;
using namespace ::com::sun::star::graphic;
using namespace ::xmloff;
using namespace ::xmloff::token;
// Implement Title/Description Elements UI (#i73249#)
constexpr OUString gsTitle(u
"Title" _ustr);
constexpr OUString gsDescription(u
"Description" _ustr);
constexpr OUString gsAnchorPageNo(u
"AnchorPageNo" _ustr);
constexpr OUString gsAnchorType(u
"AnchorType" _ustr);
constexpr OUString gsBookmark(u
"Bookmark" _ustr);
constexpr OUString gsChainNextName(u
"ChainNextName" _ustr);
constexpr OUString gsContourPolyPolygon(u
"ContourPolyPolygon" _ustr);
constexpr OUString gsDocumentIndexMark(u
"DocumentIndexMark" _ustr);
constexpr OUString gsFrame(u
"Frame" _ustr);
constexpr OUString gsGraphicFilter(u
"GraphicFilter" _ustr);
constexpr OUString gsGraphicRotation(u
"GraphicRotation" _ustr);
constexpr OUString gsHeight(u
"Height" _ustr);
constexpr OUString gsHoriOrient(u
"HoriOrient" _ustr);
constexpr OUString gsHoriOrientPosition(u
"HoriOrientPosition" _ustr);
constexpr OUString gsHyperLinkName(u
"HyperLinkName" _ustr);
constexpr OUString gsHyperLinkTarget(u
"HyperLinkTarget" _ustr);
constexpr OUString gsHyperLinkURL(u
"HyperLinkURL" _ustr);
constexpr OUString gsIsAutomaticContour(u
"IsAutomaticContour" _ustr);
constexpr OUString gsIsCollapsed(u
"IsCollapsed" _ustr);
constexpr OUString gsIsPixelContour(u
"IsPixelContour" _ustr);
constexpr OUString gsIsStart(u
"IsStart" _ustr);
constexpr OUString gsIsSyncHeightToWidth(u
"IsSyncHeightToWidth" _ustr);
constexpr OUString gsIsSyncWidthToHeight(u
"IsSyncWidthToHeight" _ustr);
constexpr OUString gsNumberingRules(u
"NumberingRules" _ustr);
constexpr OUString gsParaConditionalStyleName(u
"ParaConditionalStyleName" _ustr);
constexpr OUString gsParagraphService(u
"com.sun.star.text.Paragraph" _ustr);
constexpr OUString gsRedline(u
"Redline" _ustr);
constexpr OUString gsReferenceMark(u
"ReferenceMark" _ustr);
constexpr OUString gsRelativeHeight(u
"RelativeHeight" _ustr);
constexpr OUString gsRelativeWidth(u
"RelativeWidth" _ustr);
constexpr OUString gsRuby(u
"Ruby" _ustr);
constexpr OUString gsRubyCharStyleName(u
"RubyCharStyleName" _ustr);
constexpr OUString gsRubyText(u
"RubyText" _ustr);
constexpr OUString gsServerMap(u
"ServerMap" _ustr);
constexpr OUString gsShapeService(u
"com.sun.star.drawing.Shape" _ustr);
constexpr OUString gsSizeType(u
"SizeType" _ustr);
constexpr OUString gsSoftPageBreak(u
"SoftPageBreak" _ustr);
constexpr OUString gsTableService(u
"com.sun.star.text.TextTable" _ustr);
constexpr OUString gsText(u
"Text" _ustr);
constexpr OUString gsTextContentService(u
"com.sun.star.text.TextContent" _ustr);
constexpr OUString gsTextEmbeddedService(u
"com.sun.star.text.TextEmbeddedObject" _u
str);
constexpr OUString gsTextField(u"TextField" _ustr);
constexpr OUString gsTextFieldService(u"com.sun.star.text.TextField" _ustr);
constexpr OUString gsTextFrameService(u"com.sun.star.text.TextFrame" _ustr);
constexpr OUString gsTextGraphicService(u"com.sun.star.text.TextGraphicObject" _ustr);
constexpr OUString gsTextPortionType(u"TextPortionType" _ustr);
constexpr OUString gsUnvisitedCharStyleName(u"UnvisitedCharStyleName" _ustr);
constexpr OUString gsVertOrient(u"VertOrient" _ustr);
constexpr OUString gsVertOrientPosition(u"VertOrientPosition" _ustr);
constexpr OUString gsVisitedCharStyleName(u"VisitedCharStyleName" _ustr);
constexpr OUString gsWidth(u"Width" _ustr);
constexpr OUString gsWidthType( u"WidthType" _ustr );
constexpr OUString gsTextFieldStart(u"TextFieldStart" _ustr);
constexpr OUString gsTextFieldSep(u"TextFieldSeparator" _ustr);
constexpr OUString gsTextFieldEnd(u"TextFieldEnd" _ustr);
constexpr OUString gsTextFieldStartEnd(u"TextFieldStartEnd" _ustr);
constexpr OUString gsPropertyCharStyleNames(u"CharStyleNames" _ustr);
namespace
{
class TextContentSet
{
public :
typedef std::list<Reference<XTextContent>> contents_t;
typedef std::back_insert_iterator<contents_t> inserter_t;
typedef contents_t::const_iterator const_iterator_t;
inserter_t getInserter()
{ return std::back_insert_iterator<contents_t>(m_vTextContents); };
const_iterator_t getBegin() const
{ return m_vTextContents.begin(); };
const_iterator_t getEnd() const
{ return m_vTextContents.end(); };
private :
contents_t m_vTextContents;
};
struct FrameRefHash
{
size_t operator ()(const Reference<XTextFrame>& rFrame) const
{ return sal::static_int_cast<size_t>(reinterpret_cast <sal_uIntPtr>(rFrame.get())); }
};
bool lcl_TextContentsUnfiltered(const Reference<XTextContent>&)
{ return true ; };
bool lcl_ShapeFilter(const Reference<XTextContent>& xTxtContent)
{
Reference<XShape> xShape(xTxtContent, UNO_QUERY);
if (!xShape.is())
return false ;
Reference<XServiceInfo> xServiceInfo(xTxtContent, UNO_QUERY);
return !xServiceInfo->supportsService(u"com.sun.star.text.TextFrame" _ustr) &&
!xServiceInfo->supportsService(u"com.sun.star.text.TextGraphicObject" _ustr) &&
!xServiceInfo->supportsService(u"com.sun.star.text.TextEmbeddedObject" _ustr);
};
class BoundFrames
{
public :
typedef bool (*filter_t)(const Reference<XTextContent>&);
BoundFrames(
const Reference<XEnumerationAccess>& rEnumAccess,
const filter_t& rFilter)
: m_xEnumAccess(rEnumAccess)
{
Fill(rFilter);
};
BoundFrames()
{};
const TextContentSet& GetPageBoundContents() const
{ return m_vPageBounds; };
const TextContentSet* GetFrameBoundContents(const Reference<XTextFrame>& rParentFrame) const
{
framebound_map_t::const_iterator it = m_vFrameBoundsOf.find(rParentFrame);
if (it == m_vFrameBoundsOf.end())
return nullptr;
return &(it->second);
};
Reference<XEnumeration> createEnumeration() const
{
if (!m_xEnumAccess.is())
return Reference<XEnumeration>();
return m_xEnumAccess->createEnumeration();
};
private :
typedef std::unordered_map<
Reference<XTextFrame>,
TextContentSet,
FrameRefHash> framebound_map_t;
TextContentSet m_vPageBounds;
framebound_map_t m_vFrameBoundsOf;
const Reference<XEnumerationAccess> m_xEnumAccess;
void Fill(const filter_t& rFilter);
};
class FieldParamExporter
{
public :
FieldParamExporter(SvXMLExport* const pExport, Reference<XNameContainer> const & xFieldParams)
: m_pExport(pExport)
, m_xFieldParams(xFieldParams)
{ };
void Export();
private :
SvXMLExport* const m_pExport;
const Reference<XNameContainer> m_xFieldParams;
void ExportParameter(const OUString& sKey, const OUString& sValue);
};
struct HyperlinkData
{
OUString href, name, targetFrame, ustyleName, vstyleName;
bool serverMap = false ;
css::uno::Reference<css::container::XNameReplace> events;
HyperlinkData() = default ;
HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet);
bool operator ==(const HyperlinkData&);
bool operator !=(const HyperlinkData& rOther) { return !operator ==(rOther); }
bool addHyperlinkAttributes(SvXMLExport& rExport);
void exportEvents(SvXMLExport& rExport);
};
HyperlinkData::HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet)
{
const css::uno::Reference<css::beans::XPropertyState> xPropState(rPropSet, UNO_QUERY);
const auto xPropSetInfo(rPropSet->getPropertySetInfo());
if (xPropSetInfo->hasPropertyByName(gsTextPortionType))
{
// No hyperlink for Ruby portions; the hyperlink will be added for their inner Text
if (OUString type;
(rPropSet->getPropertyValue(gsTextPortionType) >>= type) && type == gsRuby)
return ;
}
if (xPropSetInfo->hasPropertyByName(gsHyperLinkURL)
&& (!xPropState.is()
|| PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkURL)))
{
rPropSet->getPropertyValue(gsHyperLinkURL) >>= href;
}
if (href.isEmpty())
return ;
if (xPropSetInfo->hasPropertyByName(gsHyperLinkName)
&& (!xPropState.is()
|| PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkName)))
{
rPropSet->getPropertyValue(gsHyperLinkName) >>= name;
}
if (xPropSetInfo->hasPropertyByName(gsHyperLinkTarget)
&& (!xPropState.is()
|| PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkTarget)))
{
rPropSet->getPropertyValue(gsHyperLinkTarget) >>= targetFrame;
}
if (xPropSetInfo->hasPropertyByName(gsServerMap)
&& (!xPropState.is()
|| PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsServerMap)))
{
serverMap = *o3tl::doAccess<bool >(rPropSet->getPropertyValue(gsServerMap));
}
if (xPropSetInfo->hasPropertyByName(gsUnvisitedCharStyleName)
&& (!xPropState.is()
|| PropertyState_DIRECT_VALUE
== xPropState->getPropertyState(gsUnvisitedCharStyleName)))
{
rPropSet->getPropertyValue(gsUnvisitedCharStyleName) >>= ustyleName;
}
if (xPropSetInfo->hasPropertyByName(gsVisitedCharStyleName)
&& (!xPropState.is()
|| PropertyState_DIRECT_VALUE
== xPropState->getPropertyState(gsVisitedCharStyleName)))
{
rPropSet->getPropertyValue(gsVisitedCharStyleName) >>= vstyleName;
}
static constexpr OUString sHyperLinkEvents(u"HyperLinkEvents" _ustr);
if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents))
{
events.set(rPropSet->getPropertyValue(sHyperLinkEvents), uno::UNO_QUERY);
}
}
bool HyperlinkData::operator ==(const HyperlinkData& rOther)
{
if (href != rOther.href || name != rOther.name || targetFrame != rOther.targetFrame
|| ustyleName != rOther.ustyleName || vstyleName != rOther.vstyleName
|| serverMap != rOther.serverMap)
return false ;
if (events == rOther.events)
return true ;
if (!events || !rOther.events)
return false ;
const css::uno::Sequence<OUString> aNames = events->getElementNames();
if (aNames != rOther.events->getElementNames())
return false ;
for (const auto & rName : aNames)
{
const css::uno::Any aAny = events->getByName(rName);
const css::uno::Any aOtherAny = rOther.events->getByName(rName);
if (aAny != aOtherAny)
return false ;
}
return true ;
}
bool HyperlinkData::addHyperlinkAttributes(SvXMLExport& rExport)
{
if (href.isEmpty())
{
// hyperlink without a URL does not make sense
OSL_ENSURE(false , "hyperlink without a URL --> no export to ODF" );
return false ;
}
rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(href));
if (!name.isEmpty())
rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, name);
if (!targetFrame.isEmpty())
{
rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, targetFrame);
enum XMLTokenEnum eTok = targetFrame == "_blank" ? XML_NEW : XML_REPLACE;
rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, eTok);
}
if (serverMap)
rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_SERVER_MAP, XML_TRUE);
if (!ustyleName.isEmpty())
rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME,
rExport.EncodeStyleName(ustyleName));
if (!vstyleName.isEmpty())
rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_VISITED_STYLE_NAME,
rExport.EncodeStyleName(vstyleName));
return true ;
}
void HyperlinkData::exportEvents(SvXMLExport& rExport)
{
// export events (if supported)
if (events)
rExport.GetEventExport().Export(events, false );
}
}
namespace xmloff
{
class BoundFrameSets
{
public :
explicit BoundFrameSets(const Reference<XInterface>& rModel);
const BoundFrames* GetTexts() const
{ return m_pTexts.get(); };
const BoundFrames* GetGraphics() const
{ return m_pGraphics.get(); };
const BoundFrames* GetEmbeddeds() const
{ return m_pEmbeddeds.get(); };
const BoundFrames* GetShapes() const
{ return m_pShapes.get(); };
private :
std::unique_ptr<BoundFrames> m_pTexts;
std::unique_ptr<BoundFrames> m_pGraphics;
std::unique_ptr<BoundFrames> m_pEmbeddeds;
std::unique_ptr<BoundFrames> m_pShapes;
};
}
#ifdef DBG_UTIL
static bool txtparae_bContainsIllegalCharacters = false ;
#endif
// The following map shows which property values are required:
// property auto style pass export
// ParaStyleName if style exists always
// ParaConditionalStyleName if style exists always
// NumberingRules if style exists always
// TextSection always always
// ParaChapterNumberingLevel never always
// NumberingIsNumber never always
// The conclusion is that for auto styles the first three properties
// should be queried using a multi property set if, and only if, an
// auto style needs to be exported. TextSection should be queried by
// an individual call to getPropertyvalue, because this seems to be
// less expensive than querying the first three properties if they aren't
// required.
// For the export pass all properties can be queried using a multi property
// set.
constexpr OUString aParagraphPropertyNamesAuto[] =
{
u"NumberingRules" _ustr,
u"ParaConditionalStyleName" _ustr,
u"ParaStyleName" _ustr
};
namespace {
enum eParagraphPropertyNamesEnumAuto
{
NUMBERING_RULES_AUTO = 0,
PARA_CONDITIONAL_STYLE_NAME_AUTO = 1,
PARA_STYLE_NAME_AUTO = 2
};
}
constexpr OUString aParagraphPropertyNames[] =
{
u"NumberingIsNumber" _ustr,
u"NumberingStyleName" _ustr,
u"OutlineLevel" _ustr,
u"ParaConditionalStyleName" _ustr,
u"ParaStyleName" _ustr,
u"TextSection" _ustr,
u"OutlineContentVisible" _ustr
};
namespace {
enum eParagraphPropertyNamesEnum
{
NUMBERING_IS_NUMBER = 0,
PARA_NUMBERING_STYLENAME = 1,
PARA_OUTLINE_LEVEL=2,
PARA_CONDITIONAL_STYLE_NAME = 3,
PARA_STYLE_NAME = 4,
TEXT_SECTION = 5,
PARA_OUTLINE_CONTENT_VISIBLE = 6
};
}
void BoundFrames::Fill(const filter_t& rFilter)
{
if (!m_xEnumAccess.is())
return ;
const Reference< XEnumeration > xEnum = m_xEnumAccess->createEnumeration();
if (!xEnum.is())
return ;
static constexpr OUString our_sAnchorType(u"AnchorType" _ustr);
static constexpr OUString our_sAnchorFrame(u"AnchorFrame" _ustr);
while (xEnum->hasMoreElements())
{
Reference<XPropertySet> xPropSet(xEnum->nextElement(), UNO_QUERY);
Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY);
if (!xPropSet.is() || !xTextContent.is())
continue ;
TextContentAnchorType eAnchor;
xPropSet->getPropertyValue(our_sAnchorType) >>= eAnchor;
if (TextContentAnchorType_AT_PAGE != eAnchor && TextContentAnchorType_AT_FRAME != eAnchor)
continue ;
if (!rFilter(xTextContent))
continue ;
TextContentSet::inserter_t pInserter = m_vPageBounds.getInserter();
if (TextContentAnchorType_AT_FRAME == eAnchor)
{
Reference<XTextFrame> xAnchorTxtFrame(
xPropSet->getPropertyValue(our_sAnchorFrame),
uno::UNO_QUERY);
pInserter = m_vFrameBoundsOf[xAnchorTxtFrame].getInserter();
}
*pInserter++ = xTextContent;
}
}
BoundFrameSets::BoundFrameSets(const Reference<XInterface>& rModel)
: m_pTexts(new BoundFrames())
, m_pGraphics(new BoundFrames())
, m_pEmbeddeds(new BoundFrames())
, m_pShapes(new BoundFrames())
{
const Reference<XTextFramesSupplier> xTFS(rModel, UNO_QUERY);
const Reference<XTextGraphicObjectsSupplier> xGOS(rModel, UNO_QUERY);
const Reference<XTextEmbeddedObjectsSupplier> xEOS(rModel, UNO_QUERY);
const Reference<XDrawPageSupplier> xDPS(rModel, UNO_QUERY);
if (xTFS.is())
m_pTexts.reset(new BoundFrames(
Reference<XEnumerationAccess>(xTFS->getTextFrames(), UNO_QUERY),
&lcl_TextContentsUnfiltered));
if (xGOS.is())
m_pGraphics.reset(new BoundFrames(
Reference<XEnumerationAccess>(xGOS->getGraphicObjects(), UNO_QUERY),
&lcl_TextContentsUnfiltered));
if (xEOS.is())
m_pEmbeddeds.reset(new BoundFrames(
Reference<XEnumerationAccess>(xEOS->getEmbeddedObjects(), UNO_QUERY),
&lcl_TextContentsUnfiltered));
if (xDPS.is())
m_pShapes.reset(new BoundFrames(
Reference<XEnumerationAccess>(xDPS->getDrawPage(), UNO_QUERY),
&lcl_ShapeFilter));
};
void FieldParamExporter::Export()
{
const Type aStringType = ::cppu::UnoType<OUString>::get();
const Type aBoolType = cppu::UnoType<sal_Bool>::get();
const Type aSeqType = cppu::UnoType<Sequence<OUString>>::get();
const Type aIntType = ::cppu::UnoType<sal_Int32>::get();
const Sequence<OUString> vParameters(m_xFieldParams->getElementNames());
for (const auto & rParameter : vParameters)
{
const Any aValue = m_xFieldParams->getByName(rParameter);
const Type& aValueType = aValue.getValueType();
if (aValueType == aStringType)
{
OUString sValue;
aValue >>= sValue;
ExportParameter(rParameter,sValue);
if ( rParameter == ODF_OLE_PARAM )
{
// Save the OLE object
Reference< embed::XStorage > xTargetStg = m_pExport->GetTargetStorage();
if (xTargetStg.is()) {
Reference< embed::XStorage > xDstStg = xTargetStg->openStorageElement(
u"OLELinks" _ustr, embed::ElementModes::WRITE );
if ( !xDstStg->hasByName( sValue ) ) {
Reference< XStorageBasedDocument > xStgDoc (
m_pExport->GetModel( ), UNO_QUERY );
Reference< embed::XStorage > xDocStg = xStgDoc->getDocumentStorage();
Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement(
u"OLELinks" _ustr, embed::ElementModes::READ );
xOleStg->copyElementTo( sValue, xDstStg, sValue );
Reference< embed::XTransactedObject > xTransact( xDstStg, UNO_QUERY );
if ( xTransact.is( ) )
xTransact->commit( );
}
} else {
SAL_WARN("xmloff" , "no target storage" );
}
}
}
else if (aValueType == aBoolType)
{
bool bValue = false ;
aValue >>= bValue;
ExportParameter(rParameter, OUString::boolean(bValue) );
}
else if (aValueType == aSeqType)
{
Sequence<OUString> vValue;
aValue >>= vValue;
for (const OUString& i : vValue)
{
ExportParameter(rParameter, i);
}
}
else if (aValueType == aIntType)
{
sal_Int32 nValue = 0;
aValue >>= nValue;
ExportParameter(rParameter, OUString::number(nValue));
}
}
}
void FieldParamExporter::ExportParameter(const OUString& sKey, const OUString& sValue)
{
m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_NAME, sKey);
m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_VALUE, sValue);
m_pExport->StartElement(XML_NAMESPACE_FIELD, XML_PARAM, false );
m_pExport->EndElement(XML_NAMESPACE_FIELD, XML_PARAM, false );
}
void XMLTextParagraphExport::Add( XmlStyleFamily nFamily,
const Reference < XPropertySet > & rPropSet,
const std::span<const XMLPropertyState> aAddStates,
bool bCheckParent )
{
rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
switch ( nFamily )
{
case XmlStyleFamily::TEXT_PARAGRAPH:
xPropMapper = GetParaPropMapper();
break ;
case XmlStyleFamily::TEXT_TEXT:
xPropMapper = GetTextPropMapper();
break ;
case XmlStyleFamily::TEXT_FRAME:
xPropMapper = GetAutoFramePropMapper();
break ;
case XmlStyleFamily::TEXT_SECTION:
xPropMapper = GetSectionPropMapper();
break ;
case XmlStyleFamily::TEXT_RUBY:
xPropMapper = GetRubyPropMapper();
break ;
default : break ;
}
SAL_WARN_IF( !xPropMapper.is(), "xmloff" , "There is the property mapper?" );
std::vector< XMLPropertyState > aPropStates =
xPropMapper->Filter(GetExport(), rPropSet);
aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() );
if ( aPropStates.empty() )
return ;
Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo());
OUString sParent, sCondParent;
switch ( nFamily )
{
case XmlStyleFamily::TEXT_PARAGRAPH:
if ( xPropSetInfo->hasPropertyByName( gsParaStyleName ) )
{
rPropSet->getPropertyValue( gsParaStyleName ) >>= sParent;
}
if ( xPropSetInfo->hasPropertyByName( gsParaConditionalStyleName ) )
{
rPropSet->getPropertyValue( gsParaConditionalStyleName ) >>= sCondParent;
}
if ( xPropSetInfo->hasPropertyByName( gsNumberingRules ) )
{
Reference < XIndexReplace > xNumRule(rPropSet->getPropertyValue( gsNumberingRules ), uno::UNO_QUERY);
if ( xNumRule.is() && xNumRule->getCount() )
{
Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
OUString sName;
if ( xNamed.is() )
sName = xNamed->getName();
bool bAdd = sName.isEmpty();
if ( !bAdd )
{
Reference < XPropertySet > xNumPropSet( xNumRule,
UNO_QUERY );
if ( xNumPropSet.is() &&
xNumPropSet->getPropertySetInfo()
->hasPropertyByName( u"IsAutomatic" _ustr ) )
{
bAdd = *o3tl::doAccess<bool >(xNumPropSet->getPropertyValue( u"IsAutomatic" _ustr ));
// Check on outline style (#i73361#)
if ( bAdd &&
xNumPropSet->getPropertySetInfo()
->hasPropertyByName( u"NumberingIsOutline" _ustr ) )
{
bAdd = !(*o3tl::doAccess<bool >(xNumPropSet->getPropertyValue( u"NumberingIsOutline" _ustr )));
}
}
else
{
bAdd = true ;
}
}
if ( bAdd )
maListAutoPool.Add( xNumRule );
}
}
break ;
case XmlStyleFamily::TEXT_TEXT:
{
if (bCheckParent && xPropSetInfo->hasPropertyByName(gsCharStyleName))
{
rPropSet->getPropertyValue(gsCharStyleName) >>= sParent;
}
// Get parent and remove hyperlinks (they aren't of interest)
rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
sal_uInt16 nIgnoreProps = 0;
for ( ::std::vector< XMLPropertyState >::iterator i(aPropStates.begin());
nIgnoreProps < 2 && i != aPropStates.end(); )
{
if ( i->mnIndex == -1 )
{
++i;
continue ;
}
switch ( xPM->GetEntryContextId(i->mnIndex) )
{
case CTF_CHAR_STYLE_NAME:
case CTF_HYPERLINK_URL:
i->mnIndex = -1;
nIgnoreProps++;
i = aPropStates.erase( i );
break ;
default :
++i;
break ;
}
}
}
break ;
case XmlStyleFamily::TEXT_FRAME:
if ( xPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
{
rPropSet->getPropertyValue( gsFrameStyleName ) >>= sParent;
}
break ;
case XmlStyleFamily::TEXT_SECTION:
case XmlStyleFamily::TEXT_RUBY:
; // section styles have no parents
break ;
default : break ;
}
if (aPropStates.size()) // could change after the previous check
{
GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates), /*bDontSeek*/false );
if ( !sCondParent.isEmpty() && sParent != sCondParent )
GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) );
}
}
static bool lcl_validPropState( const XMLPropertyState& rState )
{
return rState.mnIndex != -1;
}
void XMLTextParagraphExport::Add( XmlStyleFamily nFamily,
MultiPropertySetHelper& rPropSetHelper,
const Reference < XPropertySet > & rPropSet)
{
rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
switch ( nFamily )
{
case XmlStyleFamily::TEXT_PARAGRAPH:
xPropMapper = GetParaPropMapper();
break ;
default : break ;
}
SAL_WARN_IF( !xPropMapper.is(), "xmloff" , "There is the property mapper?" );
std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
if ( rPropSetHelper.hasProperty( NUMBERING_RULES_AUTO ) )
{
Reference < XIndexReplace > xNumRule(rPropSetHelper.getValue( NUMBERING_RULES_AUTO,
rPropSet, true ), uno::UNO_QUERY);
if ( xNumRule.is() && xNumRule->getCount() )
{
Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
OUString sName;
if ( xNamed.is() )
sName = xNamed->getName();
bool bAdd = sName.isEmpty();
if ( !bAdd )
{
Reference < XPropertySet > xNumPropSet( xNumRule,
UNO_QUERY );
if ( xNumPropSet.is() &&
xNumPropSet->getPropertySetInfo()
->hasPropertyByName( u"IsAutomatic" _ustr ) )
{
bAdd = *o3tl::doAccess<bool >(xNumPropSet->getPropertyValue( u"IsAutomatic" _ustr ));
// Check on outline style (#i73361#)
if ( bAdd &&
xNumPropSet->getPropertySetInfo()
->hasPropertyByName( u"NumberingIsOutline" _ustr ) )
{
bAdd = !(*o3tl::doAccess<bool >(xNumPropSet->getPropertyValue( u"NumberingIsOutline" _ustr )));
}
}
else
{
bAdd = true ;
}
}
if ( bAdd )
maListAutoPool.Add( xNumRule );
}
}
if ( aPropStates.empty() )
return ;
OUString sParent, sCondParent;
switch ( nFamily )
{
case XmlStyleFamily::TEXT_PARAGRAPH:
if ( rPropSetHelper.hasProperty( PARA_STYLE_NAME_AUTO ) )
{
rPropSetHelper.getValue( PARA_STYLE_NAME_AUTO, rPropSet,
true ) >>= sParent;
}
if ( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME_AUTO ) )
{
rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME_AUTO,
rPropSet, true ) >>= sCondParent;
}
break ;
default : break ;
}
if ( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) )
{
GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates) );
if ( !sCondParent.isEmpty() && sParent != sCondParent )
GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) );
}
}
OUString XMLTextParagraphExport::Find(
XmlStyleFamily nFamily,
const Reference < XPropertySet > & rPropSet,
const OUString& rParent,
const std::span<const XMLPropertyState> aAddStates) const
{
OUString sName( rParent );
rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
switch ( nFamily )
{
case XmlStyleFamily::TEXT_PARAGRAPH:
xPropMapper = GetParaPropMapper();
break ;
case XmlStyleFamily::TEXT_FRAME:
xPropMapper = GetAutoFramePropMapper();
break ;
case XmlStyleFamily::TEXT_SECTION:
xPropMapper = GetSectionPropMapper();
break ;
case XmlStyleFamily::TEXT_RUBY:
xPropMapper = GetRubyPropMapper();
break ;
default : break ;
}
SAL_WARN_IF( !xPropMapper.is(), "xmloff" , "There is the property mapper?" );
if ( !xPropMapper.is() )
return sName;
std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() );
if ( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) )
sName = GetAutoStylePool().Find( nFamily, sName, aPropStates );
return sName;
}
OUString XMLTextParagraphExport::FindTextStyle(
const Reference < XPropertySet > & rPropSet,
bool & rbHasCharStyle,
bool & rbHasAutoStyle,
const XMLPropertyState** ppAddStates,
const OUString* pParentName) const
{
rtl::Reference < SvXMLExportPropertyMapper > xPropMapper(GetTextPropMapper());
std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
// Get parent and remove hyperlinks (they aren't of interest)
OUString sName;
rbHasCharStyle = rbHasAutoStyle = false ;
sal_uInt16 nIgnoreProps = 0;
rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
::std::vector< XMLPropertyState >::iterator aFirstDel = aPropStates.end();
::std::vector< XMLPropertyState >::iterator aSecondDel = aPropStates.end();
for ( ::std::vector< XMLPropertyState >::iterator
i = aPropStates.begin();
nIgnoreProps < 2 && i != aPropStates.end();
++i )
{
if ( i->mnIndex == -1 )
continue ;
switch ( xPM->GetEntryContextId(i->mnIndex) )
{
case CTF_CHAR_STYLE_NAME:
i->maValue >>= sName;
i->mnIndex = -1;
rbHasCharStyle = !sName.isEmpty();
if ( nIgnoreProps )
aSecondDel = i;
else
aFirstDel = i;
nIgnoreProps++;
break ;
case CTF_HYPERLINK_URL:
i->mnIndex = -1;
if ( nIgnoreProps )
aSecondDel = i;
else
aFirstDel = i;
nIgnoreProps++;
break ;
}
}
if ( ppAddStates )
{
while ( *ppAddStates )
{
aPropStates.push_back( **ppAddStates );
ppAddStates++;
}
}
if (aPropStates.size() - nIgnoreProps)
{
// erase the character style, otherwise the autostyle cannot be found!
// erase the hyperlink, otherwise the autostyle cannot be found!
if ( nIgnoreProps )
{
// If two elements of a vector have to be deleted,
// we should delete the second one first.
if ( --nIgnoreProps )
aPropStates.erase( aSecondDel );
aPropStates.erase( aFirstDel );
}
OUString aParentName;
if (pParentName)
{
// Format redlines can have an autostyle with a parent.
aParentName = *pParentName;
}
sName = GetAutoStylePool().Find(
XmlStyleFamily::TEXT_TEXT,
aParentName,
aPropStates );
rbHasAutoStyle = true ;
}
return sName;
}
// adjustments to support lists independent from list style
void XMLTextParagraphExport::exportListChange(
const XMLTextNumRuleInfo& rPrevInfo,
const XMLTextNumRuleInfo& rNextInfo )
{
// end a list
if ( rPrevInfo.GetLevel() > 0 )
{
sal_uInt32 nListLevelsToBeClosed = 0; // unsigned larger type to safely multiply and compare
if ( !rNextInfo.BelongsToSameList( rPrevInfo ) ||
rNextInfo.GetLevel() <= 0 )
{
// close complete previous list
nListLevelsToBeClosed = rPrevInfo.GetLevel();
}
else if ( rPrevInfo.GetLevel() > rNextInfo.GetLevel() )
{
// close corresponding sub lists
nListLevelsToBeClosed = rPrevInfo.GetLevel() - rNextInfo.GetLevel();
}
if ( nListLevelsToBeClosed > 0 &&
maListElements.size() >= 2 * nListLevelsToBeClosed )
{
do {
for (size_t j = 0; j < 2; ++j)
{
OUString aElem(maListElements.back());
maListElements.pop_back();
GetExport().EndElement(aElem, true );
}
// remove closed list from list stack
mpTextListsHelper->PopListFromStack();
--nListLevelsToBeClosed;
} while ( nListLevelsToBeClosed > 0 );
}
}
// start a new list
if ( rNextInfo.GetLevel() > 0 )
{
bool bRootListToBeStarted = false ;
sal_Int16 nListLevelsToBeOpened = 0;
if ( !rPrevInfo.BelongsToSameList( rNextInfo ) ||
rPrevInfo.GetLevel() <= 0 )
{
// new root list
bRootListToBeStarted = true ;
nListLevelsToBeOpened = rNextInfo.GetLevel();
}
else if ( rNextInfo.GetLevel() > rPrevInfo.GetLevel() )
{
// open corresponding sub lists
nListLevelsToBeOpened = rNextInfo.GetLevel() - rPrevInfo.GetLevel();
}
if ( nListLevelsToBeOpened > 0 )
{
const OUString& sListStyleName( rNextInfo.GetNumRulesName() );
// Currently only the text documents support <ListId>.
// Thus, for other document types <sListId> is empty.
const OUString& sListId( rNextInfo.GetListId() );
bool bExportListStyle( true );
bool bRestartNumberingAtContinuedList( false );
sal_Int32 nRestartValueForContinuedList( -1 );
bool bContinueingPreviousSubList = !bRootListToBeStarted &&
rNextInfo.IsContinueingPreviousSubTree();
do {
GetExport().CheckAttrList();
if ( bRootListToBeStarted )
{
if ( !mpTextListsHelper->IsListProcessed( sListId ) )
{
if ( ExportListId() &&
!sListId.isEmpty() && !rNextInfo.IsListIdDefault() )
{
/* Property text:id at element <text:list> has to be
replaced by property xml:id (#i92221#)
*/
GetExport().AddAttribute( XML_NAMESPACE_XML,
XML_ID,
sListId );
}
mpTextListsHelper->KeepListAsProcessed( sListId,
sListStyleName,
OUString() );
}
else
{
const OUString sNewListId(
mpTextListsHelper->GenerateNewListId() );
if ( ExportListId() &&
!sListId.isEmpty() && !rNextInfo.IsListIdDefault() )
{
/* Property text:id at element <text:list> has to be
replaced by property xml:id (#i92221#)
*/
GetExport().AddAttribute( XML_NAMESPACE_XML,
XML_ID,
sNewListId );
}
const OUString sContinueListId =
mpTextListsHelper->GetLastContinuingListId( sListId );
// store that list with list id <sNewListId> is last list,
// which has continued list with list id <sListId>
mpTextListsHelper->StoreLastContinuingList( sListId,
sNewListId );
if ( sListStyleName ==
mpTextListsHelper->GetListStyleOfLastProcessedList() &&
// Inconsistent behavior regarding lists (#i92811#)
sContinueListId ==
mpTextListsHelper->GetLastProcessedListId() )
{
GetExport().AddAttribute( XML_NAMESPACE_TEXT,
XML_CONTINUE_NUMBERING,
XML_TRUE );
}
else
{
if ( ExportListId() &&
!sListId.isEmpty() )
{
GetExport().AddAttribute( XML_NAMESPACE_TEXT,
XML_CONTINUE_LIST,
sContinueListId );
}
}
if ( rNextInfo.IsRestart() &&
( nListLevelsToBeOpened != 1 ||
!rNextInfo.HasStartValue() ) )
{
bRestartNumberingAtContinuedList = true ;
nRestartValueForContinuedList =
rNextInfo.GetListLevelStartValue();
}
mpTextListsHelper->KeepListAsProcessed( sNewListId,
sListStyleName,
sContinueListId );
}
GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
GetExport().EncodeStyleName( sListStyleName ) );
bExportListStyle = false ;
bRootListToBeStarted = false ;
}
else if ( bExportListStyle &&
!mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) )
{
GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
GetExport().EncodeStyleName( sListStyleName ) );
bExportListStyle = false ;
}
else
{
// rhbz#746174: also export list restart for non root list
if (rNextInfo.IsRestart() && !rNextInfo.HasStartValue())
{
bRestartNumberingAtContinuedList = true ;
nRestartValueForContinuedList =
rNextInfo.GetListLevelStartValue();
}
}
if ( bContinueingPreviousSubList )
{
GetExport().AddAttribute( XML_NAMESPACE_TEXT,
XML_CONTINUE_NUMBERING, XML_TRUE );
bContinueingPreviousSubList = false ;
}
enum XMLTokenEnum eLName = XML_LIST;
OUString aElem(GetExport().GetNamespaceMap().GetQNameByKey(
XML_NAMESPACE_TEXT,
GetXMLToken(eLName) ) );
GetExport().IgnorableWhitespace();
GetExport().StartElement(aElem, false );
maListElements.push_back(aElem);
mpTextListsHelper->PushListOnStack( sListId,
sListStyleName );
// <text:list-header> or <text:list-item>
GetExport().CheckAttrList();
/* Export start value at correct list item (#i97309#) */
if ( nListLevelsToBeOpened == 1 )
{
if ( rNextInfo.HasStartValue() )
{
OUString aTmp = OUString::number( static_cast <sal_Int32>(rNextInfo.GetStartValue()) );
GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE,
aTmp );
}
else if (bRestartNumberingAtContinuedList)
{
GetExport().AddAttribute( XML_NAMESPACE_TEXT,
XML_START_VALUE,
OUString::number(nRestartValueForContinuedList) );
bRestartNumberingAtContinuedList = false ;
}
}
eLName = ( rNextInfo.IsNumbered() || nListLevelsToBeOpened > 1 )
? XML_LIST_ITEM
: XML_LIST_HEADER;
aElem = GetExport().GetNamespaceMap().GetQNameByKey(
XML_NAMESPACE_TEXT,
GetXMLToken(eLName) );
GetExport().IgnorableWhitespace();
GetExport().StartElement(aElem, false );
maListElements.push_back(aElem);
// export of <text:number> element for last opened <text:list-item>, if requested
if ( GetExport().exportTextNumberElement() &&
eLName == XML_LIST_ITEM && nListLevelsToBeOpened == 1 && // last iteration --> last opened <text:list-item>
!rNextInfo.ListLabelString().isEmpty() )
{
const OUString aTextNumberElem =
GetExport().GetNamespaceMap().GetQNameByKey(
XML_NAMESPACE_TEXT,
GetXMLToken(XML_NUMBER) );
GetExport().IgnorableWhitespace();
GetExport().StartElement( aTextNumberElem, false );
GetExport().Characters( rNextInfo.ListLabelString() );
GetExport().EndElement( aTextNumberElem, true );
}
--nListLevelsToBeOpened;
} while ( nListLevelsToBeOpened > 0 );
}
}
bool bEndElement = false ;
if ( rNextInfo.GetLevel() > 0 &&
rNextInfo.IsNumbered() &&
rPrevInfo.BelongsToSameList( rNextInfo ) &&
rPrevInfo.GetLevel() >= rNextInfo.GetLevel() )
{
assert(maListElements.size() >= 2 && "list elements missing" );
bEndElement = maListElements.size() >= 2;
}
if (!bEndElement)
return ;
// close previous list-item
GetExport().EndElement(maListElements.back(), true );
maListElements.pop_back();
// Only for sub lists (#i103745#)
if ( rNextInfo.IsRestart() && !rNextInfo.HasStartValue() &&
rNextInfo.GetLevel() != 1 )
{
// start new sub list respectively list on same list level
GetExport().EndElement(maListElements.back(), true );
GetExport().IgnorableWhitespace();
GetExport().StartElement(maListElements.back(), false );
}
// open new list-item
GetExport().CheckAttrList();
if ( rNextInfo.HasStartValue() )
{
OUString aTmp = OUString::number( static_cast <sal_Int32>(rNextInfo.GetStartValue()) );
GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, aTmp );
}
// Handle restart without start value on list level 1 (#i103745#)
else if ( rNextInfo.IsRestart() && /*!rNextInfo.HasStartValue() &&*/
rNextInfo.GetLevel() == 1 )
{
OUString aTmp = OUString::number( static_cast <sal_Int32>(rNextInfo.GetListLevelStartValue()) );
GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, aTmp );
}
if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
{
const OUString& sListStyleName( rNextInfo.GetNumRulesName() );
if ( !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) )
{
GetExport().AddAttribute( XML_NAMESPACE_TEXT,
XML_STYLE_OVERRIDE,
GetExport().EncodeStyleName( sListStyleName ) );
}
}
OUString aElem( GetExport().GetNamespaceMap().GetQNameByKey(
XML_NAMESPACE_TEXT,
GetXMLToken(XML_LIST_ITEM) ) );
GetExport().IgnorableWhitespace();
GetExport().StartElement(aElem, false );
maListElements.push_back(aElem);
// export of <text:number> element for <text:list-item>, if requested
if ( GetExport().exportTextNumberElement() &&
!rNextInfo.ListLabelString().isEmpty() )
{
const OUString aTextNumberElem =
GetExport().GetNamespaceMap().GetQNameByKey(
XML_NAMESPACE_TEXT,
GetXMLToken(XML_NUMBER) );
GetExport().IgnorableWhitespace();
GetExport().StartElement( aTextNumberElem, false );
GetExport().Characters( rNextInfo.ListLabelString() );
GetExport().EndElement( aTextNumberElem, true );
}
}
struct XMLTextParagraphExport::Impl
{
typedef ::std::map<Reference<XFormField>, sal_Int32> FieldMarkMap_t;
FieldMarkMap_t m_FieldMarkMap;
explicit Impl() {}
sal_Int32 AddFieldMarkStart(Reference<XFormField> const & i_xFieldMark)
{
assert(m_FieldMarkMap.find(i_xFieldMark) == m_FieldMarkMap.end());
sal_Int32 const ret(m_FieldMarkMap.size());
m_FieldMarkMap.insert(::std::make_pair(i_xFieldMark, ret));
return ret;
}
sal_Int32 GetFieldMarkIndex(Reference<XFormField> const & i_xFieldMark)
{
FieldMarkMap_t::const_iterator const it(
m_FieldMarkMap.find(i_xFieldMark));
// rely on SwXFieldmark::CreateXFieldmark returning the same instance
// because the Reference in m_FieldMarkMap will keep it alive
assert(it != m_FieldMarkMap.end());
return it->second;
}
};
struct XMLTextParagraphExport::DocumentListNodes
{
struct NodeData
{
std::ptrdiff_t order;
sal_Int32 index; // see SwNode::GetIndex and SwNodeOffset
sal_uInt64 style_id; // actually a pointer to NumRule
OUString list_id;
};
std::vector<NodeData> docListNodes;
DocumentListNodes(const css::uno::Reference<css::frame::XModel>& xModel,
const std::vector<sal_Int32>& aDocumentNodeOrder)
{
// Sequence of nodes, each of them represented by three-element sequence,
// corresponding to NodeData members
css::uno::Sequence<css::uno::Sequence<css::uno::Any>> nodes;
if (auto xPropSet = xModel.query<css::beans::XPropertySet>())
{
try
{
// See SwXTextDocument::getPropertyValue
xPropSet->getPropertyValue(u"ODFExport_ListNodes" _ustr) >>= nodes;
}
catch (css::beans::UnknownPropertyException&)
{
// That's absolutely fine!
}
}
docListNodes.reserve(nodes.getLength());
for (const auto & node : nodes)
{
assert(node.getLength() == 3);
sal_Int32 nodeIndex = node[0].get<sal_Int32>();
auto nodeOrder = std::distance(
aDocumentNodeOrder.begin(),
std::find(aDocumentNodeOrder.begin(), aDocumentNodeOrder.end(), nodeIndex));
docListNodes.push_back({ .order = nodeOrder,
.index = nodeIndex,
.style_id = node[1].get<sal_uInt64>(),
.list_id = node[2].get<OUString>() });
}
std::sort(docListNodes.begin(), docListNodes.end(),
[](const NodeData& lhs, const NodeData& rhs) { return lhs.order < rhs.order; });
}
bool ShouldSkipListId(const Reference<XTextContent>& xTextContent) const
{
if (docListNodes.empty())
return false ;
if (auto xPropSet = xTextContent.query<css::beans::XPropertySet>())
{
sal_Int32 index = 0;
try
{
// See SwXParagraph::Impl::GetPropertyValues_Impl
xPropSet->getPropertyValue(u"ODFExport_NodeIndex" _ustr) >>= index;
}
catch (css::beans::UnknownPropertyException&)
{
// That's absolutely fine!
return false ;
}
auto it = std::find_if(docListNodes.begin(), docListNodes.end(),
[index](const NodeData& el) { return el.index == index; });
if (it == docListNodes.end())
return false ;
// We need to write the id, when there will be continuation of the list either with
// a different list style, or after another list.
for (auto next = it + 1; next != docListNodes.end(); ++next)
{
if (it->list_id != next->list_id)
{
// List changed. We will have to refer to this id, only if there will
// appear a continuation of this list
return std::find_if(next + 1, docListNodes.end(),
[list_id = it->list_id](const NodeData& data)
{ return data.list_id == list_id; })
== docListNodes.end();
}
if (it->style_id != next->style_id)
{
// Same list, new style -> this "next" will refer to the id, no skipping
return false ;
}
if (it->index + 1 != next->index)
{
// we have a gap before the next node with the same list and style,
// with no other lists in between. There will be a continuation with a
// simple 'text:continue-numbering="true"'.
return true ;
}
it = next; // walk through adjacent nodes of the same list
}
// all nodes were adjacent and of the same list and style -> no continuation, skip id
return true ;
}
return false ;
}
};
XMLTextParagraphExport::XMLTextParagraphExport(
SvXMLExport& rExp,
SvXMLAutoStylePoolP & rASP
) :
XMLStyleExport( rExp, &rASP ),
m_xImpl(new Impl),
m_rAutoStylePool( rASP ),
m_pBoundFrameSets(new BoundFrameSets(GetExport().GetModel())),
maListAutoPool( GetExport() ),
m_bProgress( false ),
m_bBlock( false ),
m_bOpenRuby( false ),
mpTextListsHelper( nullptr ),
mbCollected(false ),
m_aCharStyleNamesPropInfoCache( gsCharStyleNames )
{
rtl::Reference < XMLPropertySetMapper > xPropMapper(new XMLTextPropertySetMapper( TextPropMap::PARA, true ));
m_xParaPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
GetExport() );
OUString sFamily( GetXMLToken(XML_PARAGRAPH) );
OUString aPrefix(u'P' );
m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_PARAGRAPH, sFamily,
m_xParaPropMapper, aPrefix );
xPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, true );
m_xTextPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
GetExport() );
sFamily = GetXMLToken(XML_TEXT);
aPrefix = "T" ;
m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_TEXT, sFamily,
m_xTextPropMapper, aPrefix );
xPropMapper = new XMLTextPropertySetMapper( TextPropMap::AUTO_FRAME, true );
m_xAutoFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
GetExport() );
sFamily = XML_STYLE_FAMILY_SD_GRAPHICS_NAME;
aPrefix = "fr" ;
m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_FRAME, sFamily,
m_xAutoFramePropMapper, aPrefix );
xPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, true );
m_xSectionPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
GetExport() );
sFamily = GetXMLToken( XML_SECTION );
aPrefix = "Sect" ;
m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_SECTION, sFamily,
m_xSectionPropMapper, aPrefix );
xPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, true );
m_xRubyPropMapper = new SvXMLExportPropertyMapper( xPropMapper );
sFamily = GetXMLToken( XML_RUBY );
aPrefix = "Ru" ;
m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_RUBY, sFamily,
m_xRubyPropMapper, aPrefix );
xPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, true );
m_xFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
GetExport() );
m_pSectionExport.reset( new XMLSectionExport( rExp, *this ) );
m_pIndexMarkExport.reset( new XMLIndexMarkExport( rExp ) );
if ( ! IsBlockMode() &&
Reference<XRedlinesSupplier>( GetExport().GetModel(), UNO_QUERY ).is())
m_pRedlineExport.reset( new XMLRedlineExport( rExp ) );
// The text field helper needs a pre-constructed XMLPropertyState
// to export the combined characters field. We construct that
// here, because we need the text property mapper to do it.
// construct Any value, then find index
sal_Int32 nIndex = m_xTextPropMapper->getPropertySetMapper()->FindEntryIndex(
"" , XML_NAMESPACE_STYLE,
GetXMLToken(XML_TEXT_COMBINE));
m_pFieldExport.reset( new XMLTextFieldExport( rExp, std::make_unique<XMLPropertyState>( nIndex, uno::Any(true ) ) ) );
PushNewTextListsHelper();
}
XMLTextParagraphExport::~XMLTextParagraphExport()
{
m_pRedlineExport.reset();
m_pIndexMarkExport.reset();
m_pSectionExport.reset();
m_pFieldExport.reset();
#ifdef DBG_UTIL
txtparae_bContainsIllegalCharacters = false ;
#endif
PopTextListsHelper();
SAL_WARN_IF( !maTextListsHelperStack.empty(), "xmloff" ,
"misusage of text lists helper stack - it is not empty. Serious defect" );
}
SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateShapeExtPropMapper(
SvXMLExport& rExport )
{
rtl::Reference < XMLPropertySetMapper > xPropMapper =
new XMLTextPropertySetMapper( TextPropMap::SHAPE, true );
return new XMLTextExportPropertySetMapper( xPropMapper, rExport );
}
SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateCharExtPropMapper(
SvXMLExport& rExport)
{
XMLPropertySetMapper *pPropMapper =
new XMLTextPropertySetMapper( TextPropMap::TEXT, true );
return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
}
SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaExtPropMapper(
SvXMLExport& rExport)
{
XMLPropertySetMapper *pPropMapper =
new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, true );
return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
}
SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaDefaultExtPropMapper(
SvXMLExport& rExport)
{
XMLPropertySetMapper *pPropMapper =
new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, true );
return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
}
void XMLTextParagraphExport::exportPageFrames( bool bIsProgress )
{
const TextContentSet& rTexts = m_pBoundFrameSets->GetTexts()->GetPageBoundContents();
const TextContentSet& rGraphics = m_pBoundFrameSets->GetGraphics()->GetPageBoundContents();
const TextContentSet& rEmbeddeds = m_pBoundFrameSets->GetEmbeddeds()->GetPageBoundContents();
const TextContentSet& rShapes = m_pBoundFrameSets->GetShapes()->GetPageBoundContents();
for (TextContentSet::const_iterator_t it = rTexts.getBegin();
it != rTexts.getEnd();
++it)
exportTextFrame(*it, false /*bAutoStyles*/, bIsProgress, true);
for (TextContentSet::const_iterator_t it = rGraphics.getBegin();
it != rGraphics.getEnd();
++it)
exportTextGraphic(*it, false /*bAutoStyles*/);
for (TextContentSet::const_iterator_t it = rEmbeddeds.getBegin();
it != rEmbeddeds.getEnd();
++it)
exportTextEmbedded(*it, false /*bAutoStyles*/);
for (TextContentSet::const_iterator_t it = rShapes.getBegin();
it != rShapes.getEnd();
++it)
exportShape(*it, false /*bAutoStyles*/);
}
void XMLTextParagraphExport::exportFrameFrames(
bool bAutoStyles,
bool bIsProgress,
const Reference < XTextFrame >& rParentTxtFrame )
{
const TextContentSet* const pTexts = m_pBoundFrameSets->GetTexts()->GetFrameBoundContents(rParentTxtFrame);
if (pTexts)
for (TextContentSet::const_iterator_t it = pTexts->getBegin();
it != pTexts->getEnd();
++it)
exportTextFrame(*it, bAutoStyles, bIsProgress, true );
const TextContentSet* const pGraphics = m_pBoundFrameSets->GetGraphics()->GetFrameBoundContents(rParentTxtFrame);
if (pGraphics)
for (TextContentSet::const_iterator_t it = pGraphics->getBegin();
it != pGraphics->getEnd();
++it)
exportTextGraphic(*it, bAutoStyles);
const TextContentSet* const pEmbeddeds = m_pBoundFrameSets->GetEmbeddeds()->GetFrameBoundContents(rParentTxtFrame);
if (pEmbeddeds)
for (TextContentSet::const_iterator_t it = pEmbeddeds->getBegin();
it != pEmbeddeds->getEnd();
++it)
exportTextEmbedded(*it, bAutoStyles);
const TextContentSet* const pShapes = m_pBoundFrameSets->GetShapes()->GetFrameBoundContents(rParentTxtFrame);
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=95 H=96 G=95
¤ Dauer der Verarbeitung: 0.44 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland