1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <sal/config.h>
21
22 #include <o3tl/any.hxx>
23 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
24 #include <rtl/ustrbuf.hxx>
25 #include <sal/types.h>
26 #include <sal/log.hxx>
27 #include <osl/diagnose.h>
28 #include <com/sun/star/frame/XModel.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/container/XEnumerationAccess.hpp>
31 #include <com/sun/star/container/XEnumeration.hpp>
32 #include <com/sun/star/container/XIndexReplace.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/XMultiPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertyState.hpp>
36 #include <com/sun/star/beans/UnknownPropertyException.hpp>
37 #include <com/sun/star/graphic/XGraphic.hpp>
38 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
39 #include <com/sun/star/text/XTextTablesSupplier.hpp>
40 #include <com/sun/star/text/XNumberingRulesSupplier.hpp>
41 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
42 #include <com/sun/star/text/XTextDocument.hpp>
43 #include <com/sun/star/text/XTextTable.hpp>
44 #include <com/sun/star/text/XText.hpp>
45 #include <com/sun/star/text/XTextContent.hpp>
46 #include <com/sun/star/text/XTextRange.hpp>
47 #include <com/sun/star/text/XTextField.hpp>
48 #include <com/sun/star/container/XNamed.hpp>
49 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
50 #include <com/sun/star/text/XTextFrame.hpp>
51 #include <com/sun/star/container/XNameAccess.hpp>
52 #include <com/sun/star/text/SizeType.hpp>
53 #include <com/sun/star/text/HoriOrientation.hpp>
54 #include <com/sun/star/text/VertOrientation.hpp>
55 #include <com/sun/star/text/TextContentAnchorType.hpp>
56 #include <com/sun/star/text/XTextFramesSupplier.hpp>
57 #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
58 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
59 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
60 #include <com/sun/star/document/XEventsSupplier.hpp>
61 #include <com/sun/star/document/XRedlinesSupplier.hpp>
62 #include <com/sun/star/text/XFormField.hpp>
63 #include <com/sun/star/text/XTextSection.hpp>
64 #include <com/sun/star/drawing/XShape.hpp>
65 #include <com/sun/star/style/XAutoStylesSupplier.hpp>
66 #include <com/sun/star/style/XAutoStyleFamily.hpp>
67 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
68 #include <com/sun/star/drawing/XControlShape.hpp>
69
70 #include <sax/tools/converter.hxx>
71
72 #include <xmloff/xmlnamespace.hxx>
73 #include <xmloff/xmlaustp.hxx>
74 #include <xmloff/families.hxx>
75 #include "txtexppr.hxx"
76 #include <xmloff/xmluconv.hxx>
77 #include "XMLAnchorTypePropHdl.hxx"
78 #include <xexptran.hxx>
79 #include <xmloff/ProgressBarHelper.hxx>
80 #include <xmloff/namespacemap.hxx>
81 #include <xmloff/xmlexp.hxx>
82 #include <txtflde.hxx>
83 #include <xmloff/txtprmap.hxx>
84 #include <XMLImageMapExport.hxx>
85 #include "XMLTextNumRuleInfo.hxx"
86 #include <xmloff/XMLTextListAutoStylePool.hxx>
87 #include <xmloff/txtparae.hxx>
88 #include "XMLSectionExport.hxx"
89 #include "XMLIndexMarkExport.hxx"
90 #include <xmloff/XMLEventExport.hxx>
91 #include "XMLRedlineExport.hxx"
92 #include <MultiPropertySetHelper.hxx>
93 #include <xmloff/formlayerexport.hxx>
94 #include "XMLTextCharStyleNamesElementExport.hxx"
95 #include <xmloff/odffields.hxx>
96 #include <xmloff/maptype.hxx>
97 #include <basegfx/polygon/b2dpolypolygon.hxx>
98 #include <basegfx/polygon/b2dpolypolygontools.hxx>
99 #include <basegfx/polygon/b2dpolygontools.hxx>
100 #include <com/sun/star/embed/ElementModes.hpp>
101 #include <com/sun/star/embed/XTransactedObject.hpp>
102 #include <com/sun/star/document/XStorageBasedDocument.hpp>
103 #include <txtlists.hxx>
104 #include <com/sun/star/rdf/XMetadatable.hpp>
105 #include <list>
106 #include <unordered_map>
107 #include <memory>
108 #include <vector>
109 #include <algorithm>
110 #include <iterator>
111 #include <officecfg/Office/Common.hxx>
112 #include <o3tl/safeint.hxx>
113 #include <comphelper/scopeguard.hxx>
114 #include <comphelper/sequenceashashmap.hxx>
115
116 using namespace ::com::sun::star;
117 using namespace ::com::sun::star::uno;
118 using namespace ::com::sun::star::lang;
119 using namespace ::com::sun::star::beans;
120 using namespace ::com::sun::star::container;
121 using namespace ::com::sun::star::text;
122 using namespace ::com::sun::star::style;
123 using namespace ::com::sun::star::drawing;
124 using namespace ::com::sun::star::document;
125 using namespace ::com::sun::star::graphic;
126 using namespace ::xmloff;
127 using namespace ::xmloff::token;
128
129 // Implement Title/Description Elements UI (#i73249#)
130 constexpr OUString gsTitle(u"Title"_ustr);
131 constexpr OUString gsDescription(u"Description"_ustr);
132 constexpr OUStringLiteral gsAnchorPageNo(u"AnchorPageNo");
133 constexpr OUStringLiteral gsAnchorType(u"AnchorType");
134 constexpr OUString gsBookmark(u"Bookmark"_ustr);
135 constexpr OUString gsChainNextName(u"ChainNextName"_ustr);
136 constexpr OUString gsContourPolyPolygon(u"ContourPolyPolygon"_ustr);
137 constexpr OUStringLiteral gsDocumentIndexMark(u"DocumentIndexMark");
138 constexpr OUStringLiteral gsFrame(u"Frame");
139 constexpr OUStringLiteral gsGraphicFilter(u"GraphicFilter");
140 constexpr OUStringLiteral gsGraphicRotation(u"GraphicRotation");
141 constexpr OUString gsHeight(u"Height"_ustr);
142 constexpr OUStringLiteral gsHoriOrient(u"HoriOrient");
143 constexpr OUStringLiteral gsHoriOrientPosition(u"HoriOrientPosition");
144 constexpr OUString gsHyperLinkName(u"HyperLinkName"_ustr);
145 constexpr OUString gsHyperLinkTarget(u"HyperLinkTarget"_ustr);
146 constexpr OUString gsHyperLinkURL(u"HyperLinkURL"_ustr);
147 constexpr OUString gsIsAutomaticContour(u"IsAutomaticContour"_ustr);
148 constexpr OUString gsIsCollapsed(u"IsCollapsed"_ustr);
149 constexpr OUString gsIsPixelContour(u"IsPixelContour"_ustr);
150 constexpr OUString gsIsStart(u"IsStart"_ustr);
151 constexpr OUString gsIsSyncHeightToWidth(u"IsSyncHeightToWidth"_ustr);
152 constexpr OUString gsIsSyncWidthToHeight(u"IsSyncWidthToHeight"_ustr);
153 constexpr OUString gsNumberingRules(u"NumberingRules"_ustr);
154 constexpr OUString gsParaConditionalStyleName(u"ParaConditionalStyleName"_ustr);
155 constexpr OUStringLiteral gsParagraphService(u"com.sun.star.text.Paragraph");
156 constexpr OUStringLiteral gsRedline(u"Redline");
157 constexpr OUString gsReferenceMark(u"ReferenceMark"_ustr);
158 constexpr OUString gsRelativeHeight(u"RelativeHeight"_ustr);
159 constexpr OUString gsRelativeWidth(u"RelativeWidth"_ustr);
160 constexpr OUStringLiteral gsRuby(u"Ruby");
161 constexpr OUStringLiteral gsRubyCharStyleName(u"RubyCharStyleName");
162 constexpr OUStringLiteral gsRubyText(u"RubyText");
163 constexpr OUString gsServerMap(u"ServerMap"_ustr);
164 constexpr OUString gsShapeService(u"com.sun.star.drawing.Shape"_ustr);
165 constexpr OUString gsSizeType(u"SizeType"_ustr);
166 constexpr OUStringLiteral gsSoftPageBreak( u"SoftPageBreak" );
167 constexpr OUStringLiteral gsTableService(u"com.sun.star.text.TextTable");
168 constexpr OUStringLiteral gsText(u"Text");
169 constexpr OUString gsTextContentService(u"com.sun.star.text.TextContent"_ustr);
170 constexpr OUStringLiteral gsTextEmbeddedService(u"com.sun.star.text.TextEmbeddedObject");
171 constexpr OUString gsTextField(u"TextField"_ustr);
172 constexpr OUStringLiteral gsTextFieldService(u"com.sun.star.text.TextField");
173 constexpr OUStringLiteral gsTextFrameService(u"com.sun.star.text.TextFrame");
174 constexpr OUStringLiteral gsTextGraphicService(u"com.sun.star.text.TextGraphicObject");
175 constexpr OUString gsTextPortionType(u"TextPortionType"_ustr);
176 constexpr OUString gsUnvisitedCharStyleName(u"UnvisitedCharStyleName"_ustr);
177 constexpr OUStringLiteral gsVertOrient(u"VertOrient");
178 constexpr OUStringLiteral gsVertOrientPosition(u"VertOrientPosition");
179 constexpr OUString gsVisitedCharStyleName(u"VisitedCharStyleName"_ustr);
180 constexpr OUString gsWidth(u"Width"_ustr);
181 constexpr OUString gsWidthType( u"WidthType"_ustr );
182 constexpr OUStringLiteral gsTextFieldStart( u"TextFieldStart" );
183 constexpr OUStringLiteral gsTextFieldSep(u"TextFieldSeparator");
184 constexpr OUStringLiteral gsTextFieldEnd( u"TextFieldEnd" );
185 constexpr OUStringLiteral gsTextFieldStartEnd( u"TextFieldStartEnd" );
186 constexpr OUStringLiteral gsPropertyCharStyleNames(u"CharStyleNames");
187
188 namespace
189 {
190 class TextContentSet
191 {
192 public:
193 typedef std::list<Reference<XTextContent>> contents_t;
194 typedef std::back_insert_iterator<contents_t> inserter_t;
195 typedef contents_t::const_iterator const_iterator_t;
196
getInserter()197 inserter_t getInserter()
198 { return std::back_insert_iterator<contents_t>(m_vTextContents); };
getBegin() const199 const_iterator_t getBegin() const
200 { return m_vTextContents.begin(); };
getEnd() const201 const_iterator_t getEnd() const
202 { return m_vTextContents.end(); };
203
204 private:
205 contents_t m_vTextContents;
206 };
207
208 struct FrameRefHash
209 {
operator ()__anonc8a009ae0111::FrameRefHash210 size_t operator()(const Reference<XTextFrame>& rFrame) const
211 { return sal::static_int_cast<size_t>(reinterpret_cast<sal_uIntPtr>(rFrame.get())); }
212 };
213
lcl_TextContentsUnfiltered(const Reference<XTextContent> &)214 bool lcl_TextContentsUnfiltered(const Reference<XTextContent>&)
215 { return true; };
216
lcl_ShapeFilter(const Reference<XTextContent> & xTxtContent)217 bool lcl_ShapeFilter(const Reference<XTextContent>& xTxtContent)
218 {
219 Reference<XShape> xShape(xTxtContent, UNO_QUERY);
220 if(!xShape.is())
221 return false;
222 Reference<XServiceInfo> xServiceInfo(xTxtContent, UNO_QUERY);
223 return !xServiceInfo->supportsService(u"com.sun.star.text.TextFrame"_ustr) &&
224 !xServiceInfo->supportsService(u"com.sun.star.text.TextGraphicObject"_ustr) &&
225 !xServiceInfo->supportsService(u"com.sun.star.text.TextEmbeddedObject"_ustr);
226 };
227
228 class BoundFrames
229 {
230 public:
231 typedef bool (*filter_t)(const Reference<XTextContent>&);
BoundFrames(const Reference<XEnumerationAccess> & rEnumAccess,const filter_t & rFilter)232 BoundFrames(
233 const Reference<XEnumerationAccess>& rEnumAccess,
234 const filter_t& rFilter)
235 : m_xEnumAccess(rEnumAccess)
236 {
237 Fill(rFilter);
238 };
BoundFrames()239 BoundFrames()
240 {};
GetPageBoundContents() const241 const TextContentSet& GetPageBoundContents() const
242 { return m_vPageBounds; };
GetFrameBoundContents(const Reference<XTextFrame> & rParentFrame) const243 const TextContentSet* GetFrameBoundContents(const Reference<XTextFrame>& rParentFrame) const
244 {
245 framebound_map_t::const_iterator it = m_vFrameBoundsOf.find(rParentFrame);
246 if(it == m_vFrameBoundsOf.end())
247 return nullptr;
248 return &(it->second);
249 };
createEnumeration() const250 Reference<XEnumeration> createEnumeration() const
251 {
252 if(!m_xEnumAccess.is())
253 return Reference<XEnumeration>();
254 return m_xEnumAccess->createEnumeration();
255 };
256
257 private:
258 typedef std::unordered_map<
259 Reference<XTextFrame>,
260 TextContentSet,
261 FrameRefHash> framebound_map_t;
262 TextContentSet m_vPageBounds;
263 framebound_map_t m_vFrameBoundsOf;
264 const Reference<XEnumerationAccess> m_xEnumAccess;
265 void Fill(const filter_t& rFilter);
266 };
267
268 class FieldParamExporter
269 {
270 public:
FieldParamExporter(SvXMLExport * const pExport,Reference<XNameContainer> const & xFieldParams)271 FieldParamExporter(SvXMLExport* const pExport, Reference<XNameContainer> const & xFieldParams)
272 : m_pExport(pExport)
273 , m_xFieldParams(xFieldParams)
274 { };
275 void Export();
276
277 private:
278 SvXMLExport* const m_pExport;
279 const Reference<XNameContainer> m_xFieldParams;
280
281 void ExportParameter(const OUString& sKey, const OUString& sValue);
282 };
283
284 struct HyperlinkData
285 {
286 OUString href, name, targetFrame, ustyleName, vstyleName;
287 bool serverMap = false;
288 css::uno::Reference<css::container::XNameReplace> events;
289
290 HyperlinkData() = default;
291 HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet);
292
293 bool operator==(const HyperlinkData&);
operator !=__anonc8a009ae0111::HyperlinkData294 bool operator!=(const HyperlinkData& rOther) { return !operator==(rOther); }
295
296 bool addHyperlinkAttributes(SvXMLExport& rExport);
297 void exportEvents(SvXMLExport& rExport);
298 };
299
HyperlinkData(const css::uno::Reference<css::beans::XPropertySet> & rPropSet)300 HyperlinkData::HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet)
301 {
302 const css::uno::Reference<css::beans::XPropertyState> xPropState(rPropSet, UNO_QUERY);
303 const auto xPropSetInfo(rPropSet->getPropertySetInfo());
304 if (xPropSetInfo->hasPropertyByName(gsHyperLinkURL)
305 && (!xPropState.is()
306 || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkURL)))
307 {
308 rPropSet->getPropertyValue(gsHyperLinkURL) >>= href;
309 }
310
311 if (href.isEmpty())
312 return;
313
314 if (xPropSetInfo->hasPropertyByName(gsHyperLinkName)
315 && (!xPropState.is()
316 || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkName)))
317 {
318 rPropSet->getPropertyValue(gsHyperLinkName) >>= name;
319 }
320
321 if (xPropSetInfo->hasPropertyByName(gsHyperLinkTarget)
322 && (!xPropState.is()
323 || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkTarget)))
324 {
325 rPropSet->getPropertyValue(gsHyperLinkTarget) >>= targetFrame;
326 }
327
328 if (xPropSetInfo->hasPropertyByName(gsServerMap)
329 && (!xPropState.is()
330 || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsServerMap)))
331 {
332 serverMap = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsServerMap));
333 }
334
335 if (xPropSetInfo->hasPropertyByName(gsUnvisitedCharStyleName)
336 && (!xPropState.is()
337 || PropertyState_DIRECT_VALUE
338 == xPropState->getPropertyState(gsUnvisitedCharStyleName)))
339 {
340 rPropSet->getPropertyValue(gsUnvisitedCharStyleName) >>= ustyleName;
341 }
342
343 if (xPropSetInfo->hasPropertyByName(gsVisitedCharStyleName)
344 && (!xPropState.is()
345 || PropertyState_DIRECT_VALUE
346 == xPropState->getPropertyState(gsVisitedCharStyleName)))
347 {
348 rPropSet->getPropertyValue(gsVisitedCharStyleName) >>= vstyleName;
349 }
350
351 static constexpr OUString sHyperLinkEvents(u"HyperLinkEvents"_ustr);
352 if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents))
353 {
354 events.set(rPropSet->getPropertyValue(sHyperLinkEvents), uno::UNO_QUERY);
355 }
356 }
357
operator ==(const HyperlinkData & rOther)358 bool HyperlinkData::operator==(const HyperlinkData& rOther)
359 {
360 if (href != rOther.href || name != rOther.name || targetFrame != rOther.targetFrame
361 || ustyleName != rOther.ustyleName || vstyleName != rOther.vstyleName
362 || serverMap != rOther.serverMap)
363 return false;
364
365 if (events == rOther.events)
366 return true;
367 if (!events || !rOther.events)
368 return false;
369
370 const css::uno::Sequence<OUString> aNames = events->getElementNames();
371 if (aNames != rOther.events->getElementNames())
372 return false;
373 for (const auto& rName : aNames)
374 {
375 const css::uno::Any aAny = events->getByName(rName);
376 const css::uno::Any aOtherAny = rOther.events->getByName(rName);
377 if (aAny != aOtherAny)
378 return false;
379 }
380 return true;
381 }
382
addHyperlinkAttributes(SvXMLExport & rExport)383 bool HyperlinkData::addHyperlinkAttributes(SvXMLExport& rExport)
384 {
385 if (href.isEmpty())
386 {
387 // hyperlink without a URL does not make sense
388 OSL_ENSURE(false, "hyperlink without a URL --> no export to ODF");
389 return false;
390 }
391
392 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
393 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(href));
394
395 if (!name.isEmpty())
396 rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, name);
397
398 if (!targetFrame.isEmpty())
399 {
400 rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, targetFrame);
401 enum XMLTokenEnum eTok = targetFrame == "_blank" ? XML_NEW : XML_REPLACE;
402 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, eTok);
403 }
404
405 if (serverMap)
406 rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_SERVER_MAP, XML_TRUE);
407
408 if (!ustyleName.isEmpty())
409 rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME,
410 rExport.EncodeStyleName(ustyleName));
411
412 if (!vstyleName.isEmpty())
413 rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_VISITED_STYLE_NAME,
414 rExport.EncodeStyleName(vstyleName));
415
416 return true;
417 }
418
exportEvents(SvXMLExport & rExport)419 void HyperlinkData::exportEvents(SvXMLExport& rExport)
420 {
421 // export events (if supported)
422 if (events)
423 rExport.GetEventExport().Export(events, false);
424 }
425 }
426
427 namespace xmloff
428 {
429 class BoundFrameSets
430 {
431 public:
432 explicit BoundFrameSets(const Reference<XInterface>& rModel);
GetTexts() const433 const BoundFrames* GetTexts() const
434 { return m_pTexts.get(); };
GetGraphics() const435 const BoundFrames* GetGraphics() const
436 { return m_pGraphics.get(); };
GetEmbeddeds() const437 const BoundFrames* GetEmbeddeds() const
438 { return m_pEmbeddeds.get(); };
GetShapes() const439 const BoundFrames* GetShapes() const
440 { return m_pShapes.get(); };
441 private:
442 std::unique_ptr<BoundFrames> m_pTexts;
443 std::unique_ptr<BoundFrames> m_pGraphics;
444 std::unique_ptr<BoundFrames> m_pEmbeddeds;
445 std::unique_ptr<BoundFrames> m_pShapes;
446 };
447 }
448
449 #ifdef DBG_UTIL
450 static bool txtparae_bContainsIllegalCharacters = false;
451 #endif
452
453 // The following map shows which property values are required:
454
455 // property auto style pass export
456
457 // ParaStyleName if style exists always
458 // ParaConditionalStyleName if style exists always
459 // NumberingRules if style exists always
460 // TextSection always always
461 // ParaChapterNumberingLevel never always
462 // NumberingIsNumber never always
463
464 // The conclusion is that for auto styles the first three properties
465 // should be queried using a multi property set if, and only if, an
466 // auto style needs to be exported. TextSection should be queried by
467 // an individual call to getPropertyvalue, because this seems to be
468 // less expensive than querying the first three properties if they aren't
469 // required.
470
471 // For the export pass all properties can be queried using a multi property
472 // set.
473
474 constexpr OUString aParagraphPropertyNamesAuto[] =
475 {
476 u"NumberingRules"_ustr,
477 u"ParaConditionalStyleName"_ustr,
478 u"ParaStyleName"_ustr
479 };
480
481 namespace {
482
483 enum eParagraphPropertyNamesEnumAuto
484 {
485 NUMBERING_RULES_AUTO = 0,
486 PARA_CONDITIONAL_STYLE_NAME_AUTO = 1,
487 PARA_STYLE_NAME_AUTO = 2
488 };
489
490 }
491
492 constexpr OUString aParagraphPropertyNames[] =
493 {
494 u"NumberingIsNumber"_ustr,
495 u"NumberingStyleName"_ustr,
496 u"OutlineLevel"_ustr,
497 u"ParaConditionalStyleName"_ustr,
498 u"ParaStyleName"_ustr,
499 u"TextSection"_ustr,
500 u"OutlineContentVisible"_ustr
501 };
502
503 namespace {
504
505 enum eParagraphPropertyNamesEnum
506 {
507 NUMBERING_IS_NUMBER = 0,
508 PARA_NUMBERING_STYLENAME = 1,
509 PARA_OUTLINE_LEVEL=2,
510 PARA_CONDITIONAL_STYLE_NAME = 3,
511 PARA_STYLE_NAME = 4,
512 TEXT_SECTION = 5,
513 PARA_OUTLINE_CONTENT_VISIBLE = 6
514 };
515
516 }
517
Fill(const filter_t & rFilter)518 void BoundFrames::Fill(const filter_t& rFilter)
519 {
520 if(!m_xEnumAccess.is())
521 return;
522 const Reference< XEnumeration > xEnum = m_xEnumAccess->createEnumeration();
523 if(!xEnum.is())
524 return;
525 static constexpr OUStringLiteral our_sAnchorType(u"AnchorType");
526 static constexpr OUStringLiteral our_sAnchorFrame(u"AnchorFrame");
527 while(xEnum->hasMoreElements())
528 {
529 Reference<XPropertySet> xPropSet(xEnum->nextElement(), UNO_QUERY);
530 Reference<XTextContent> xTextContent(xPropSet, UNO_QUERY);
531 if(!xPropSet.is() || !xTextContent.is())
532 continue;
533 TextContentAnchorType eAnchor;
534 xPropSet->getPropertyValue(our_sAnchorType) >>= eAnchor;
535 if(TextContentAnchorType_AT_PAGE != eAnchor && TextContentAnchorType_AT_FRAME != eAnchor)
536 continue;
537 if(!rFilter(xTextContent))
538 continue;
539
540 TextContentSet::inserter_t pInserter = m_vPageBounds.getInserter();
541 if(TextContentAnchorType_AT_FRAME == eAnchor)
542 {
543 Reference<XTextFrame> xAnchorTxtFrame(
544 xPropSet->getPropertyValue(our_sAnchorFrame),
545 uno::UNO_QUERY);
546 pInserter = m_vFrameBoundsOf[xAnchorTxtFrame].getInserter();
547 }
548 *pInserter++ = xTextContent;
549 }
550 }
551
BoundFrameSets(const Reference<XInterface> & rModel)552 BoundFrameSets::BoundFrameSets(const Reference<XInterface>& rModel)
553 : m_pTexts(new BoundFrames())
554 , m_pGraphics(new BoundFrames())
555 , m_pEmbeddeds(new BoundFrames())
556 , m_pShapes(new BoundFrames())
557 {
558 const Reference<XTextFramesSupplier> xTFS(rModel, UNO_QUERY);
559 const Reference<XTextGraphicObjectsSupplier> xGOS(rModel, UNO_QUERY);
560 const Reference<XTextEmbeddedObjectsSupplier> xEOS(rModel, UNO_QUERY);
561 const Reference<XDrawPageSupplier> xDPS(rModel, UNO_QUERY);
562 if(xTFS.is())
563 m_pTexts.reset(new BoundFrames(
564 Reference<XEnumerationAccess>(xTFS->getTextFrames(), UNO_QUERY),
565 &lcl_TextContentsUnfiltered));
566 if(xGOS.is())
567 m_pGraphics.reset(new BoundFrames(
568 Reference<XEnumerationAccess>(xGOS->getGraphicObjects(), UNO_QUERY),
569 &lcl_TextContentsUnfiltered));
570 if(xEOS.is())
571 m_pEmbeddeds.reset(new BoundFrames(
572 Reference<XEnumerationAccess>(xEOS->getEmbeddedObjects(), UNO_QUERY),
573 &lcl_TextContentsUnfiltered));
574 if(xDPS.is())
575 m_pShapes.reset(new BoundFrames(
576 Reference<XEnumerationAccess>(xDPS->getDrawPage(), UNO_QUERY),
577 &lcl_ShapeFilter));
578 };
579
Export()580 void FieldParamExporter::Export()
581 {
582 const Type aStringType = ::cppu::UnoType<OUString>::get();
583 const Type aBoolType = cppu::UnoType<sal_Bool>::get();
584 const Type aSeqType = cppu::UnoType<Sequence<OUString>>::get();
585 const Type aIntType = ::cppu::UnoType<sal_Int32>::get();
586 const Sequence<OUString> vParameters(m_xFieldParams->getElementNames());
587 for(const auto & rParameter : vParameters)
588 {
589 const Any aValue = m_xFieldParams->getByName(rParameter);
590 const Type& aValueType = aValue.getValueType();
591 if(aValueType == aStringType)
592 {
593 OUString sValue;
594 aValue >>= sValue;
595 ExportParameter(rParameter,sValue);
596
597 if ( rParameter == ODF_OLE_PARAM )
598 {
599 // Save the OLE object
600 Reference< embed::XStorage > xTargetStg = m_pExport->GetTargetStorage();
601 if (xTargetStg.is()) {
602 Reference< embed::XStorage > xDstStg = xTargetStg->openStorageElement(
603 u"OLELinks"_ustr, embed::ElementModes::WRITE );
604
605 if ( !xDstStg->hasByName( sValue ) ) {
606 Reference< XStorageBasedDocument > xStgDoc (
607 m_pExport->GetModel( ), UNO_QUERY );
608 Reference< embed::XStorage > xDocStg = xStgDoc->getDocumentStorage();
609 Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement(
610 u"OLELinks"_ustr, embed::ElementModes::READ );
611
612 xOleStg->copyElementTo( sValue, xDstStg, sValue );
613 Reference< embed::XTransactedObject > xTransact( xDstStg, UNO_QUERY );
614 if ( xTransact.is( ) )
615 xTransact->commit( );
616 }
617 } else {
618 SAL_WARN("xmloff", "no target storage");
619 }
620 }
621 }
622 else if(aValueType == aBoolType)
623 {
624 bool bValue = false;
625 aValue >>= bValue;
626 ExportParameter(rParameter, OUString::boolean(bValue) );
627 }
628 else if(aValueType == aSeqType)
629 {
630 Sequence<OUString> vValue;
631 aValue >>= vValue;
632 for (const OUString& i : vValue)
633 {
634 ExportParameter(rParameter, i);
635 }
636 }
637 else if(aValueType == aIntType)
638 {
639 sal_Int32 nValue = 0;
640 aValue >>= nValue;
641 ExportParameter(rParameter, OUString::number(nValue));
642 }
643 }
644 }
645
ExportParameter(const OUString & sKey,const OUString & sValue)646 void FieldParamExporter::ExportParameter(const OUString& sKey, const OUString& sValue)
647 {
648 m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_NAME, sKey);
649 m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_VALUE, sValue);
650 m_pExport->StartElement(XML_NAMESPACE_FIELD, XML_PARAM, false);
651 m_pExport->EndElement(XML_NAMESPACE_FIELD, XML_PARAM, false);
652 }
653
Add(XmlStyleFamily nFamily,const Reference<XPropertySet> & rPropSet,const std::span<const XMLPropertyState> aAddStates,bool bCheckParent)654 void XMLTextParagraphExport::Add( XmlStyleFamily nFamily,
655 const Reference < XPropertySet > & rPropSet,
656 const std::span<const XMLPropertyState> aAddStates,
657 bool bCheckParent )
658 {
659 rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
660 switch( nFamily )
661 {
662 case XmlStyleFamily::TEXT_PARAGRAPH:
663 xPropMapper = GetParaPropMapper();
664 break;
665 case XmlStyleFamily::TEXT_TEXT:
666 xPropMapper = GetTextPropMapper();
667 break;
668 case XmlStyleFamily::TEXT_FRAME:
669 xPropMapper = GetAutoFramePropMapper();
670 break;
671 case XmlStyleFamily::TEXT_SECTION:
672 xPropMapper = GetSectionPropMapper();
673 break;
674 case XmlStyleFamily::TEXT_RUBY:
675 xPropMapper = GetRubyPropMapper();
676 break;
677 default: break;
678 }
679 SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" );
680
681 std::vector< XMLPropertyState > aPropStates =
682 xPropMapper->Filter(GetExport(), rPropSet);
683
684 aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() );
685
686 if( aPropStates.empty() )
687 return;
688
689 Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo());
690 OUString sParent, sCondParent;
691 switch( nFamily )
692 {
693 case XmlStyleFamily::TEXT_PARAGRAPH:
694 if( xPropSetInfo->hasPropertyByName( gsParaStyleName ) )
695 {
696 rPropSet->getPropertyValue( gsParaStyleName ) >>= sParent;
697 }
698 if( xPropSetInfo->hasPropertyByName( gsParaConditionalStyleName ) )
699 {
700 rPropSet->getPropertyValue( gsParaConditionalStyleName ) >>= sCondParent;
701 }
702 if( xPropSetInfo->hasPropertyByName( gsNumberingRules ) )
703 {
704 Reference < XIndexReplace > xNumRule(rPropSet->getPropertyValue( gsNumberingRules ), uno::UNO_QUERY);
705 if( xNumRule.is() && xNumRule->getCount() )
706 {
707 Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
708 OUString sName;
709 if( xNamed.is() )
710 sName = xNamed->getName();
711 bool bAdd = sName.isEmpty();
712 if( !bAdd )
713 {
714 Reference < XPropertySet > xNumPropSet( xNumRule,
715 UNO_QUERY );
716 if( xNumPropSet.is() &&
717 xNumPropSet->getPropertySetInfo()
718 ->hasPropertyByName( u"IsAutomatic"_ustr ) )
719 {
720 bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( u"IsAutomatic"_ustr ));
721 // Check on outline style (#i73361#)
722 if ( bAdd &&
723 xNumPropSet->getPropertySetInfo()
724 ->hasPropertyByName( u"NumberingIsOutline"_ustr ) )
725 {
726 bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( u"NumberingIsOutline"_ustr )));
727 }
728 }
729 else
730 {
731 bAdd = true;
732 }
733 }
734 if( bAdd )
735 maListAutoPool.Add( xNumRule );
736 }
737 }
738 break;
739 case XmlStyleFamily::TEXT_TEXT:
740 {
741 if (bCheckParent && xPropSetInfo->hasPropertyByName(gsCharStyleName))
742 {
743 rPropSet->getPropertyValue(gsCharStyleName) >>= sParent;
744 }
745
746 // Get parent and remove hyperlinks (they aren't of interest)
747 rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
748 sal_uInt16 nIgnoreProps = 0;
749 for( ::std::vector< XMLPropertyState >::iterator i(aPropStates.begin());
750 nIgnoreProps < 2 && i != aPropStates.end(); )
751 {
752 if( i->mnIndex == -1 )
753 {
754 ++i;
755 continue;
756 }
757
758 switch( xPM->GetEntryContextId(i->mnIndex) )
759 {
760 case CTF_CHAR_STYLE_NAME:
761 case CTF_HYPERLINK_URL:
762 i->mnIndex = -1;
763 nIgnoreProps++;
764 i = aPropStates.erase( i );
765 break;
766 default:
767 ++i;
768 break;
769 }
770 }
771 }
772 break;
773 case XmlStyleFamily::TEXT_FRAME:
774 if( xPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
775 {
776 rPropSet->getPropertyValue( gsFrameStyleName ) >>= sParent;
777 }
778 break;
779 case XmlStyleFamily::TEXT_SECTION:
780 case XmlStyleFamily::TEXT_RUBY:
781 ; // section styles have no parents
782 break;
783 default: break;
784 }
785 if (aPropStates.size()) // could change after the previous check
786 {
787 GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates), /*bDontSeek*/false );
788 if( !sCondParent.isEmpty() && sParent != sCondParent )
789 GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) );
790 }
791 }
792
lcl_validPropState(const XMLPropertyState & rState)793 static bool lcl_validPropState( const XMLPropertyState& rState )
794 {
795 return rState.mnIndex != -1;
796 }
797
Add(XmlStyleFamily nFamily,MultiPropertySetHelper & rPropSetHelper,const Reference<XPropertySet> & rPropSet)798 void XMLTextParagraphExport::Add( XmlStyleFamily nFamily,
799 MultiPropertySetHelper& rPropSetHelper,
800 const Reference < XPropertySet > & rPropSet)
801 {
802 rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
803 switch( nFamily )
804 {
805 case XmlStyleFamily::TEXT_PARAGRAPH:
806 xPropMapper = GetParaPropMapper();
807 break;
808 default: break;
809 }
810 SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" );
811
812 std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
813
814 if( rPropSetHelper.hasProperty( NUMBERING_RULES_AUTO ) )
815 {
816 Reference < XIndexReplace > xNumRule(rPropSetHelper.getValue( NUMBERING_RULES_AUTO,
817 rPropSet, true ), uno::UNO_QUERY);
818 if( xNumRule.is() && xNumRule->getCount() )
819 {
820 Reference < XNamed > xNamed( xNumRule, UNO_QUERY );
821 OUString sName;
822 if( xNamed.is() )
823 sName = xNamed->getName();
824 bool bAdd = sName.isEmpty();
825 if( !bAdd )
826 {
827 Reference < XPropertySet > xNumPropSet( xNumRule,
828 UNO_QUERY );
829 if( xNumPropSet.is() &&
830 xNumPropSet->getPropertySetInfo()
831 ->hasPropertyByName( u"IsAutomatic"_ustr ) )
832 {
833 bAdd = *o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( u"IsAutomatic"_ustr ));
834 // Check on outline style (#i73361#)
835 if ( bAdd &&
836 xNumPropSet->getPropertySetInfo()
837 ->hasPropertyByName( u"NumberingIsOutline"_ustr ) )
838 {
839 bAdd = !(*o3tl::doAccess<bool>(xNumPropSet->getPropertyValue( u"NumberingIsOutline"_ustr )));
840 }
841 }
842 else
843 {
844 bAdd = true;
845 }
846 }
847 if( bAdd )
848 maListAutoPool.Add( xNumRule );
849 }
850 }
851
852 if( aPropStates.empty() )
853 return;
854
855 OUString sParent, sCondParent;
856 switch( nFamily )
857 {
858 case XmlStyleFamily::TEXT_PARAGRAPH:
859 if( rPropSetHelper.hasProperty( PARA_STYLE_NAME_AUTO ) )
860 {
861 rPropSetHelper.getValue( PARA_STYLE_NAME_AUTO, rPropSet,
862 true ) >>= sParent;
863 }
864 if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME_AUTO ) )
865 {
866 rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME_AUTO,
867 rPropSet, true ) >>= sCondParent;
868 }
869
870 break;
871 default: break;
872 }
873
874 if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) )
875 {
876 GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates) );
877 if( !sCondParent.isEmpty() && sParent != sCondParent )
878 GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) );
879 }
880 }
881
Find(XmlStyleFamily nFamily,const Reference<XPropertySet> & rPropSet,const OUString & rParent,const std::span<const XMLPropertyState> aAddStates) const882 OUString XMLTextParagraphExport::Find(
883 XmlStyleFamily nFamily,
884 const Reference < XPropertySet > & rPropSet,
885 const OUString& rParent,
886 const std::span<const XMLPropertyState> aAddStates) const
887 {
888 OUString sName( rParent );
889 rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
890 switch( nFamily )
891 {
892 case XmlStyleFamily::TEXT_PARAGRAPH:
893 xPropMapper = GetParaPropMapper();
894 break;
895 case XmlStyleFamily::TEXT_FRAME:
896 xPropMapper = GetAutoFramePropMapper();
897 break;
898 case XmlStyleFamily::TEXT_SECTION:
899 xPropMapper = GetSectionPropMapper();
900 break;
901 case XmlStyleFamily::TEXT_RUBY:
902 xPropMapper = GetRubyPropMapper();
903 break;
904 default: break;
905 }
906 SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" );
907 if( !xPropMapper.is() )
908 return sName;
909 std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
910 aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() );
911 if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) )
912 sName = GetAutoStylePool().Find( nFamily, sName, aPropStates );
913
914 return sName;
915 }
916
FindTextStyle(const Reference<XPropertySet> & rPropSet,bool & rbHasCharStyle,bool & rbHasAutoStyle,const XMLPropertyState ** ppAddStates,const OUString * pParentName) const917 OUString XMLTextParagraphExport::FindTextStyle(
918 const Reference < XPropertySet > & rPropSet,
919 bool& rbHasCharStyle,
920 bool& rbHasAutoStyle,
921 const XMLPropertyState** ppAddStates,
922 const OUString* pParentName) const
923 {
924 rtl::Reference < SvXMLExportPropertyMapper > xPropMapper(GetTextPropMapper());
925 std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
926
927 // Get parent and remove hyperlinks (they aren't of interest)
928 OUString sName;
929 rbHasCharStyle = rbHasAutoStyle = false;
930 sal_uInt16 nIgnoreProps = 0;
931 rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
932 ::std::vector< XMLPropertyState >::iterator aFirstDel = aPropStates.end();
933 ::std::vector< XMLPropertyState >::iterator aSecondDel = aPropStates.end();
934
935 for( ::std::vector< XMLPropertyState >::iterator
936 i = aPropStates.begin();
937 nIgnoreProps < 2 && i != aPropStates.end();
938 ++i )
939 {
940 if( i->mnIndex == -1 )
941 continue;
942
943 switch( xPM->GetEntryContextId(i->mnIndex) )
944 {
945 case CTF_CHAR_STYLE_NAME:
946 i->maValue >>= sName;
947 i->mnIndex = -1;
948 rbHasCharStyle = !sName.isEmpty();
949 if( nIgnoreProps )
950 aSecondDel = i;
951 else
952 aFirstDel = i;
953 nIgnoreProps++;
954 break;
955 case CTF_HYPERLINK_URL:
956 i->mnIndex = -1;
957 if( nIgnoreProps )
958 aSecondDel = i;
959 else
960 aFirstDel = i;
961 nIgnoreProps++;
962 break;
963 }
964 }
965 if( ppAddStates )
966 {
967 while( *ppAddStates )
968 {
969 aPropStates.push_back( **ppAddStates );
970 ppAddStates++;
971 }
972 }
973 if (aPropStates.size() - nIgnoreProps)
974 {
975 // erase the character style, otherwise the autostyle cannot be found!
976 // erase the hyperlink, otherwise the autostyle cannot be found!
977 if ( nIgnoreProps )
978 {
979 // If two elements of a vector have to be deleted,
980 // we should delete the second one first.
981 if( --nIgnoreProps )
982 aPropStates.erase( aSecondDel );
983 aPropStates.erase( aFirstDel );
984 }
985 OUString aParentName;
986 if (pParentName)
987 {
988 // Format redlines can have an autostyle with a parent.
989 aParentName = *pParentName;
990 }
991 sName = GetAutoStylePool().Find(
992 XmlStyleFamily::TEXT_TEXT,
993 aParentName,
994 aPropStates );
995 rbHasAutoStyle = true;
996 }
997
998 return sName;
999 }
1000
1001 // adjustments to support lists independent from list style
exportListChange(const XMLTextNumRuleInfo & rPrevInfo,const XMLTextNumRuleInfo & rNextInfo)1002 void XMLTextParagraphExport::exportListChange(
1003 const XMLTextNumRuleInfo& rPrevInfo,
1004 const XMLTextNumRuleInfo& rNextInfo )
1005 {
1006 // end a list
1007 if ( rPrevInfo.GetLevel() > 0 )
1008 {
1009 sal_uInt32 nListLevelsToBeClosed = 0; // unsigned larger type to safely multiply and compare
1010 if ( !rNextInfo.BelongsToSameList( rPrevInfo ) ||
1011 rNextInfo.GetLevel() <= 0 )
1012 {
1013 // close complete previous list
1014 nListLevelsToBeClosed = rPrevInfo.GetLevel();
1015 }
1016 else if ( rPrevInfo.GetLevel() > rNextInfo.GetLevel() )
1017 {
1018 // close corresponding sub lists
1019 nListLevelsToBeClosed = rPrevInfo.GetLevel() - rNextInfo.GetLevel();
1020 }
1021
1022 if ( nListLevelsToBeClosed > 0 &&
1023 maListElements.size() >= 2 * nListLevelsToBeClosed )
1024 {
1025 do {
1026 for(size_t j = 0; j < 2; ++j)
1027 {
1028 OUString aElem(maListElements.back());
1029 maListElements.pop_back();
1030 GetExport().EndElement(aElem, true);
1031 }
1032
1033 // remove closed list from list stack
1034 mpTextListsHelper->PopListFromStack();
1035
1036 --nListLevelsToBeClosed;
1037 } while ( nListLevelsToBeClosed > 0 );
1038 }
1039 }
1040
1041 // start a new list
1042 if ( rNextInfo.GetLevel() > 0 )
1043 {
1044 bool bRootListToBeStarted = false;
1045 sal_Int16 nListLevelsToBeOpened = 0;
1046 if ( !rPrevInfo.BelongsToSameList( rNextInfo ) ||
1047 rPrevInfo.GetLevel() <= 0 )
1048 {
1049 // new root list
1050 bRootListToBeStarted = true;
1051 nListLevelsToBeOpened = rNextInfo.GetLevel();
1052 }
1053 else if ( rNextInfo.GetLevel() > rPrevInfo.GetLevel() )
1054 {
1055 // open corresponding sub lists
1056 nListLevelsToBeOpened = rNextInfo.GetLevel() - rPrevInfo.GetLevel();
1057 }
1058
1059 if ( nListLevelsToBeOpened > 0 )
1060 {
1061 const OUString& sListStyleName( rNextInfo.GetNumRulesName() );
1062 // Currently only the text documents support <ListId>.
1063 // Thus, for other document types <sListId> is empty.
1064 const OUString& sListId( rNextInfo.GetListId() );
1065 bool bExportListStyle( true );
1066 bool bRestartNumberingAtContinuedList( false );
1067 sal_Int32 nRestartValueForContinuedList( -1 );
1068 bool bContinueingPreviousSubList = !bRootListToBeStarted &&
1069 rNextInfo.IsContinueingPreviousSubTree();
1070 do {
1071 GetExport().CheckAttrList();
1072
1073 if ( bRootListToBeStarted )
1074 {
1075 if ( !mpTextListsHelper->IsListProcessed( sListId ) )
1076 {
1077 if ( ExportListId() &&
1078 !sListId.isEmpty() && !rNextInfo.IsListIdDefault() )
1079 {
1080 /* Property text:id at element <text:list> has to be
1081 replaced by property xml:id (#i92221#)
1082 */
1083 GetExport().AddAttribute( XML_NAMESPACE_XML,
1084 XML_ID,
1085 sListId );
1086 }
1087 mpTextListsHelper->KeepListAsProcessed( sListId,
1088 sListStyleName,
1089 OUString() );
1090 }
1091 else
1092 {
1093 const OUString sNewListId(
1094 mpTextListsHelper->GenerateNewListId() );
1095 if ( ExportListId() &&
1096 !sListId.isEmpty() && !rNextInfo.IsListIdDefault() )
1097 {
1098 /* Property text:id at element <text:list> has to be
1099 replaced by property xml:id (#i92221#)
1100 */
1101 GetExport().AddAttribute( XML_NAMESPACE_XML,
1102 XML_ID,
1103 sNewListId );
1104 }
1105
1106 const OUString sContinueListId =
1107 mpTextListsHelper->GetLastContinuingListId( sListId );
1108 // store that list with list id <sNewListId> is last list,
1109 // which has continued list with list id <sListId>
1110 mpTextListsHelper->StoreLastContinuingList( sListId,
1111 sNewListId );
1112 if ( sListStyleName ==
1113 mpTextListsHelper->GetListStyleOfLastProcessedList() &&
1114 // Inconsistent behavior regarding lists (#i92811#)
1115 sContinueListId ==
1116 mpTextListsHelper->GetLastProcessedListId() )
1117 {
1118 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1119 XML_CONTINUE_NUMBERING,
1120 XML_TRUE );
1121 }
1122 else
1123 {
1124 if ( ExportListId() &&
1125 !sListId.isEmpty() )
1126 {
1127 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1128 XML_CONTINUE_LIST,
1129 sContinueListId );
1130 }
1131 }
1132
1133 if ( rNextInfo.IsRestart() &&
1134 ( nListLevelsToBeOpened != 1 ||
1135 !rNextInfo.HasStartValue() ) )
1136 {
1137 bRestartNumberingAtContinuedList = true;
1138 nRestartValueForContinuedList =
1139 rNextInfo.GetListLevelStartValue();
1140 }
1141
1142 mpTextListsHelper->KeepListAsProcessed( sNewListId,
1143 sListStyleName,
1144 sContinueListId );
1145 }
1146
1147 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
1148 GetExport().EncodeStyleName( sListStyleName ) );
1149 bExportListStyle = false;
1150
1151 bRootListToBeStarted = false;
1152 }
1153 else if ( bExportListStyle &&
1154 !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) )
1155 {
1156 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
1157 GetExport().EncodeStyleName( sListStyleName ) );
1158 bExportListStyle = false;
1159
1160 }
1161 else
1162 {
1163 // rhbz#746174: also export list restart for non root list
1164 if (rNextInfo.IsRestart() && !rNextInfo.HasStartValue())
1165 {
1166 bRestartNumberingAtContinuedList = true;
1167 nRestartValueForContinuedList =
1168 rNextInfo.GetListLevelStartValue();
1169 }
1170 }
1171
1172 if ( bContinueingPreviousSubList )
1173 {
1174 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1175 XML_CONTINUE_NUMBERING, XML_TRUE );
1176 bContinueingPreviousSubList = false;
1177 }
1178
1179 enum XMLTokenEnum eLName = XML_LIST;
1180
1181 OUString aElem(GetExport().GetNamespaceMap().GetQNameByKey(
1182 XML_NAMESPACE_TEXT,
1183 GetXMLToken(eLName) ) );
1184 GetExport().IgnorableWhitespace();
1185 GetExport().StartElement(aElem, false);
1186
1187 maListElements.push_back(aElem);
1188
1189 mpTextListsHelper->PushListOnStack( sListId,
1190 sListStyleName );
1191
1192 // <text:list-header> or <text:list-item>
1193 GetExport().CheckAttrList();
1194
1195 /* Export start value at correct list item (#i97309#) */
1196 if ( nListLevelsToBeOpened == 1 )
1197 {
1198 if ( rNextInfo.HasStartValue() )
1199 {
1200 OUString aTmp = OUString::number( static_cast<sal_Int32>(rNextInfo.GetStartValue()) );
1201 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE,
1202 aTmp );
1203 }
1204 else if (bRestartNumberingAtContinuedList)
1205 {
1206 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1207 XML_START_VALUE,
1208 OUString::number(nRestartValueForContinuedList) );
1209 bRestartNumberingAtContinuedList = false;
1210 }
1211 }
1212
1213 eLName = ( rNextInfo.IsNumbered() || nListLevelsToBeOpened > 1 )
1214 ? XML_LIST_ITEM
1215 : XML_LIST_HEADER;
1216 aElem = GetExport().GetNamespaceMap().GetQNameByKey(
1217 XML_NAMESPACE_TEXT,
1218 GetXMLToken(eLName) );
1219 GetExport().IgnorableWhitespace();
1220 GetExport().StartElement(aElem, false);
1221 maListElements.push_back(aElem);
1222
1223 // export of <text:number> element for last opened <text:list-item>, if requested
1224 if ( GetExport().exportTextNumberElement() &&
1225 eLName == XML_LIST_ITEM && nListLevelsToBeOpened == 1 && // last iteration --> last opened <text:list-item>
1226 !rNextInfo.ListLabelString().isEmpty() )
1227 {
1228 const OUString aTextNumberElem =
1229 GetExport().GetNamespaceMap().GetQNameByKey(
1230 XML_NAMESPACE_TEXT,
1231 GetXMLToken(XML_NUMBER) );
1232 GetExport().IgnorableWhitespace();
1233 GetExport().StartElement( aTextNumberElem, false );
1234 GetExport().Characters( rNextInfo.ListLabelString() );
1235 GetExport().EndElement( aTextNumberElem, true );
1236 }
1237 --nListLevelsToBeOpened;
1238 } while ( nListLevelsToBeOpened > 0 );
1239 }
1240 }
1241
1242 bool bEndElement = false;
1243
1244 if ( rNextInfo.GetLevel() > 0 &&
1245 rNextInfo.IsNumbered() &&
1246 rPrevInfo.BelongsToSameList( rNextInfo ) &&
1247 rPrevInfo.GetLevel() >= rNextInfo.GetLevel() )
1248 {
1249 assert(maListElements.size() >= 2 && "list elements missing");
1250 bEndElement = maListElements.size() >= 2;
1251 }
1252
1253 if (!bEndElement)
1254 return;
1255
1256 // close previous list-item
1257 GetExport().EndElement(maListElements.back(), true );
1258 maListElements.pop_back();
1259
1260 // Only for sub lists (#i103745#)
1261 if ( rNextInfo.IsRestart() && !rNextInfo.HasStartValue() &&
1262 rNextInfo.GetLevel() != 1 )
1263 {
1264 // start new sub list respectively list on same list level
1265 GetExport().EndElement(maListElements.back(), true );
1266 GetExport().IgnorableWhitespace();
1267 GetExport().StartElement(maListElements.back(), false);
1268 }
1269
1270 // open new list-item
1271 GetExport().CheckAttrList();
1272 if( rNextInfo.HasStartValue() )
1273 {
1274 OUString aTmp = OUString::number( static_cast<sal_Int32>(rNextInfo.GetStartValue()) );
1275 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, aTmp );
1276 }
1277 // Handle restart without start value on list level 1 (#i103745#)
1278 else if ( rNextInfo.IsRestart() && /*!rNextInfo.HasStartValue() &&*/
1279 rNextInfo.GetLevel() == 1 )
1280 {
1281 OUString aTmp = OUString::number( static_cast<sal_Int32>(rNextInfo.GetListLevelStartValue()) );
1282 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, aTmp );
1283 }
1284 if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1285 GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
1286 {
1287 const OUString& sListStyleName( rNextInfo.GetNumRulesName() );
1288 if ( !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) )
1289 {
1290 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
1291 XML_STYLE_OVERRIDE,
1292 GetExport().EncodeStyleName( sListStyleName ) );
1293 }
1294 }
1295 OUString aElem( GetExport().GetNamespaceMap().GetQNameByKey(
1296 XML_NAMESPACE_TEXT,
1297 GetXMLToken(XML_LIST_ITEM) ) );
1298 GetExport().IgnorableWhitespace();
1299 GetExport().StartElement(aElem, false );
1300 maListElements.push_back(aElem);
1301
1302 // export of <text:number> element for <text:list-item>, if requested
1303 if ( GetExport().exportTextNumberElement() &&
1304 !rNextInfo.ListLabelString().isEmpty() )
1305 {
1306 const OUString aTextNumberElem =
1307 GetExport().GetNamespaceMap().GetQNameByKey(
1308 XML_NAMESPACE_TEXT,
1309 GetXMLToken(XML_NUMBER) );
1310 GetExport().IgnorableWhitespace();
1311 GetExport().StartElement( aTextNumberElem, false );
1312 GetExport().Characters( rNextInfo.ListLabelString() );
1313 GetExport().EndElement( aTextNumberElem, true );
1314 }
1315
1316 }
1317
1318 struct XMLTextParagraphExport::Impl
1319 {
1320 typedef ::std::map<Reference<XFormField>, sal_Int32> FieldMarkMap_t;
1321 FieldMarkMap_t m_FieldMarkMap;
1322
ImplXMLTextParagraphExport::Impl1323 explicit Impl() {}
AddFieldMarkStartXMLTextParagraphExport::Impl1324 sal_Int32 AddFieldMarkStart(Reference<XFormField> const& i_xFieldMark)
1325 {
1326 assert(m_FieldMarkMap.find(i_xFieldMark) == m_FieldMarkMap.end());
1327 sal_Int32 const ret(m_FieldMarkMap.size());
1328 m_FieldMarkMap.insert(::std::make_pair(i_xFieldMark, ret));
1329 return ret;
1330 }
GetFieldMarkIndexXMLTextParagraphExport::Impl1331 sal_Int32 GetFieldMarkIndex(Reference<XFormField> const& i_xFieldMark)
1332 {
1333 FieldMarkMap_t::const_iterator const it(
1334 m_FieldMarkMap.find(i_xFieldMark));
1335 // rely on SwXFieldmark::CreateXFieldmark returning the same instance
1336 // because the Reference in m_FieldMarkMap will keep it alive
1337 assert(it != m_FieldMarkMap.end());
1338 return it->second;
1339 }
1340 };
1341
1342 struct XMLTextParagraphExport::DocumentListNodes
1343 {
1344 struct NodeData
1345 {
1346 std::ptrdiff_t order;
1347 sal_Int32 index; // see SwNode::GetIndex and SwNodeOffset
1348 sal_uInt64 style_id; // actually a pointer to NumRule
1349 OUString list_id;
1350 };
1351 std::vector<NodeData> docListNodes;
DocumentListNodesXMLTextParagraphExport::DocumentListNodes1352 DocumentListNodes(const css::uno::Reference<css::frame::XModel>& xModel,
1353 const std::vector<sal_Int32>& aDocumentNodeOrder)
1354 {
1355 // Sequence of nodes, each of them represented by three-element sequence,
1356 // corresponding to NodeData members
1357 css::uno::Sequence<css::uno::Sequence<css::uno::Any>> nodes;
1358 if (auto xPropSet = xModel.query<css::beans::XPropertySet>())
1359 {
1360 try
1361 {
1362 // See SwXTextDocument::getPropertyValue
1363 xPropSet->getPropertyValue(u"ODFExport_ListNodes"_ustr) >>= nodes;
1364 }
1365 catch (css::beans::UnknownPropertyException&)
1366 {
1367 // That's absolutely fine!
1368 }
1369 }
1370
1371 docListNodes.reserve(nodes.getLength());
1372 for (const auto& node : nodes)
1373 {
1374 assert(node.getLength() == 3);
1375 sal_Int32 nodeIndex = node[0].get<sal_Int32>();
1376 auto nodeOrder = std::distance(
1377 aDocumentNodeOrder.begin(),
1378 std::find(aDocumentNodeOrder.begin(), aDocumentNodeOrder.end(), nodeIndex));
1379 docListNodes.push_back({ .order = nodeOrder,
1380 .index = nodeIndex,
1381 .style_id = node[1].get<sal_uInt64>(),
1382 .list_id = node[2].get<OUString>() });
1383 }
1384
1385 std::sort(docListNodes.begin(), docListNodes.end(),
1386 [](const NodeData& lhs, const NodeData& rhs) { return lhs.order < rhs.order; });
1387 }
ShouldSkipListIdXMLTextParagraphExport::DocumentListNodes1388 bool ShouldSkipListId(const Reference<XTextContent>& xTextContent) const
1389 {
1390 if (docListNodes.empty())
1391 return false;
1392
1393 if (auto xPropSet = xTextContent.query<css::beans::XPropertySet>())
1394 {
1395 sal_Int32 index = 0;
1396 try
1397 {
1398 // See SwXParagraph::Impl::GetPropertyValues_Impl
1399 xPropSet->getPropertyValue(u"ODFExport_NodeIndex"_ustr) >>= index;
1400 }
1401 catch (css::beans::UnknownPropertyException&)
1402 {
1403 // That's absolutely fine!
1404 return false;
1405 }
1406
1407 auto it = std::find_if(docListNodes.begin(), docListNodes.end(),
1408 [index](const NodeData& el) { return el.index == index; });
1409 if (it == docListNodes.end())
1410 return false;
1411
1412 // We need to write the id, when there will be continuation of the list either with
1413 // a different list style, or after another list.
1414
1415 for (auto next = it + 1; next != docListNodes.end(); ++next)
1416 {
1417 if (it->list_id != next->list_id)
1418 {
1419 // List changed. We will have to refer to this id, only if there will
1420 // appear a continuation of this list
1421 return std::find_if(next + 1, docListNodes.end(),
1422 [list_id = it->list_id](const NodeData& data)
1423 { return data.list_id == list_id; })
1424 == docListNodes.end();
1425 }
1426
1427 if (it->style_id != next->style_id)
1428 {
1429 // Same list, new style -> this "next" will refer to the id, no skipping
1430 return false;
1431 }
1432 if (it->index + 1 != next->index)
1433 {
1434 // we have a gap before the next node with the same list and style,
1435 // with no other lists in between. There will be a continuation with a
1436 // simple 'text:continue-numbering="true"'.
1437 return true;
1438 }
1439 it = next; // walk through adjacent nodes of the same list
1440 }
1441 // all nodes were adjacent and of the same list and style -> no continuation, skip id
1442 return true;
1443 }
1444
1445 return false;
1446 }
1447 };
1448
XMLTextParagraphExport(SvXMLExport & rExp,SvXMLAutoStylePoolP & rASP)1449 XMLTextParagraphExport::XMLTextParagraphExport(
1450 SvXMLExport& rExp,
1451 SvXMLAutoStylePoolP & rASP
1452 ) :
1453 XMLStyleExport( rExp, &rASP ),
1454 m_xImpl(new Impl),
1455 m_rAutoStylePool( rASP ),
1456 m_pBoundFrameSets(new BoundFrameSets(GetExport().GetModel())),
1457 maListAutoPool( GetExport() ),
1458 m_bProgress( false ),
1459 m_bBlock( false ),
1460 m_bOpenRuby( false ),
1461 mpTextListsHelper( nullptr ),
1462 mbCollected(false),
1463 m_aCharStyleNamesPropInfoCache( gsCharStyleNames )
1464 {
1465 rtl::Reference < XMLPropertySetMapper > xPropMapper(new XMLTextPropertySetMapper( TextPropMap::PARA, true ));
1466 m_xParaPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1467 GetExport() );
1468
1469 OUString sFamily( GetXMLToken(XML_PARAGRAPH) );
1470 OUString aPrefix(u'P');
1471 m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_PARAGRAPH, sFamily,
1472 m_xParaPropMapper, aPrefix );
1473
1474 xPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, true );
1475 m_xTextPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1476 GetExport() );
1477 sFamily = GetXMLToken(XML_TEXT);
1478 aPrefix = "T";
1479 m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_TEXT, sFamily,
1480 m_xTextPropMapper, aPrefix );
1481
1482 xPropMapper = new XMLTextPropertySetMapper( TextPropMap::AUTO_FRAME, true );
1483 m_xAutoFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1484 GetExport() );
1485 sFamily = XML_STYLE_FAMILY_SD_GRAPHICS_NAME;
1486 aPrefix = "fr";
1487 m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_FRAME, sFamily,
1488 m_xAutoFramePropMapper, aPrefix );
1489
1490 xPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, true );
1491 m_xSectionPropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1492 GetExport() );
1493 sFamily = GetXMLToken( XML_SECTION );
1494 aPrefix = "Sect" ;
1495 m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_SECTION, sFamily,
1496 m_xSectionPropMapper, aPrefix );
1497
1498 xPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, true );
1499 m_xRubyPropMapper = new SvXMLExportPropertyMapper( xPropMapper );
1500 sFamily = GetXMLToken( XML_RUBY );
1501 aPrefix = "Ru";
1502 m_rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_RUBY, sFamily,
1503 m_xRubyPropMapper, aPrefix );
1504
1505 xPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, true );
1506 m_xFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper,
1507 GetExport() );
1508
1509 m_pSectionExport.reset( new XMLSectionExport( rExp, *this ) );
1510 m_pIndexMarkExport.reset( new XMLIndexMarkExport( rExp ) );
1511
1512 if( ! IsBlockMode() &&
1513 Reference<XRedlinesSupplier>( GetExport().GetModel(), UNO_QUERY ).is())
1514 m_pRedlineExport.reset( new XMLRedlineExport( rExp ) );
1515
1516 // The text field helper needs a pre-constructed XMLPropertyState
1517 // to export the combined characters field. We construct that
1518 // here, because we need the text property mapper to do it.
1519
1520 // construct Any value, then find index
1521 sal_Int32 nIndex = m_xTextPropMapper->getPropertySetMapper()->FindEntryIndex(
1522 "", XML_NAMESPACE_STYLE,
1523 GetXMLToken(XML_TEXT_COMBINE));
1524 m_pFieldExport.reset( new XMLTextFieldExport( rExp, std::make_unique<XMLPropertyState>( nIndex, uno::Any(true) ) ) );
1525 PushNewTextListsHelper();
1526 }
1527
~XMLTextParagraphExport()1528 XMLTextParagraphExport::~XMLTextParagraphExport()
1529 {
1530 m_pRedlineExport.reset();
1531 m_pIndexMarkExport.reset();
1532 m_pSectionExport.reset();
1533 m_pFieldExport.reset();
1534 #ifdef DBG_UTIL
1535 txtparae_bContainsIllegalCharacters = false;
1536 #endif
1537 PopTextListsHelper();
1538 SAL_WARN_IF( !maTextListsHelperStack.empty(), "xmloff",
1539 "misusage of text lists helper stack - it is not empty. Serious defect" );
1540 }
1541
CreateShapeExtPropMapper(SvXMLExport & rExport)1542 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateShapeExtPropMapper(
1543 SvXMLExport& rExport )
1544 {
1545 rtl::Reference < XMLPropertySetMapper > xPropMapper =
1546 new XMLTextPropertySetMapper( TextPropMap::SHAPE, true );
1547 return new XMLTextExportPropertySetMapper( xPropMapper, rExport );
1548 }
1549
CreateCharExtPropMapper(SvXMLExport & rExport)1550 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateCharExtPropMapper(
1551 SvXMLExport& rExport)
1552 {
1553 XMLPropertySetMapper *pPropMapper =
1554 new XMLTextPropertySetMapper( TextPropMap::TEXT, true );
1555 return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
1556 }
1557
CreateParaExtPropMapper(SvXMLExport & rExport)1558 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaExtPropMapper(
1559 SvXMLExport& rExport)
1560 {
1561 XMLPropertySetMapper *pPropMapper =
1562 new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, true );
1563 return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
1564 }
1565
CreateParaDefaultExtPropMapper(SvXMLExport & rExport)1566 SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaDefaultExtPropMapper(
1567 SvXMLExport& rExport)
1568 {
1569 XMLPropertySetMapper *pPropMapper =
1570 new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, true );
1571 return new XMLTextExportPropertySetMapper( pPropMapper, rExport );
1572 }
1573
exportPageFrames(bool bIsProgress)1574 void XMLTextParagraphExport::exportPageFrames( bool bIsProgress )
1575 {
1576 const TextContentSet& rTexts = m_pBoundFrameSets->GetTexts()->GetPageBoundContents();
1577 const TextContentSet& rGraphics = m_pBoundFrameSets->GetGraphics()->GetPageBoundContents();
1578 const TextContentSet& rEmbeddeds = m_pBoundFrameSets->GetEmbeddeds()->GetPageBoundContents();
1579 const TextContentSet& rShapes = m_pBoundFrameSets->GetShapes()->GetPageBoundContents();
1580 for(TextContentSet::const_iterator_t it = rTexts.getBegin();
1581 it != rTexts.getEnd();
1582 ++it)
1583 exportTextFrame(*it, false/*bAutoStyles*/, bIsProgress, true);
1584 for(TextContentSet::const_iterator_t it = rGraphics.getBegin();
1585 it != rGraphics.getEnd();
1586 ++it)
1587 exportTextGraphic(*it, false/*bAutoStyles*/);
1588 for(TextContentSet::const_iterator_t it = rEmbeddeds.getBegin();
1589 it != rEmbeddeds.getEnd();
1590 ++it)
1591 exportTextEmbedded(*it, false/*bAutoStyles*/);
1592 for(TextContentSet::const_iterator_t it = rShapes.getBegin();
1593 it != rShapes.getEnd();
1594 ++it)
1595 exportShape(*it, false/*bAutoStyles*/);
1596 }
1597
exportFrameFrames(bool bAutoStyles,bool bIsProgress,const Reference<XTextFrame> & rParentTxtFrame)1598 void XMLTextParagraphExport::exportFrameFrames(
1599 bool bAutoStyles,
1600 bool bIsProgress,
1601 const Reference < XTextFrame >& rParentTxtFrame )
1602 {
1603 const TextContentSet* const pTexts = m_pBoundFrameSets->GetTexts()->GetFrameBoundContents(rParentTxtFrame);
1604 if(pTexts)
1605 for(TextContentSet::const_iterator_t it = pTexts->getBegin();
1606 it != pTexts->getEnd();
1607 ++it)
1608 exportTextFrame(*it, bAutoStyles, bIsProgress, true);
1609 const TextContentSet* const pGraphics = m_pBoundFrameSets->GetGraphics()->GetFrameBoundContents(rParentTxtFrame);
1610 if(pGraphics)
1611 for(TextContentSet::const_iterator_t it = pGraphics->getBegin();
1612 it != pGraphics->getEnd();
1613 ++it)
1614 exportTextGraphic(*it, bAutoStyles);
1615 const TextContentSet* const pEmbeddeds = m_pBoundFrameSets->GetEmbeddeds()->GetFrameBoundContents(rParentTxtFrame);
1616 if(pEmbeddeds)
1617 for(TextContentSet::const_iterator_t it = pEmbeddeds->getBegin();
1618 it != pEmbeddeds->getEnd();
1619 ++it)
1620 exportTextEmbedded(*it, bAutoStyles);
1621 const TextContentSet* const pShapes = m_pBoundFrameSets->GetShapes()->GetFrameBoundContents(rParentTxtFrame);
1622 if(pShapes)
1623 for(TextContentSet::const_iterator_t it = pShapes->getBegin();
1624 it != pShapes->getEnd();
1625 ++it)
1626 exportShape(*it, bAutoStyles);
1627 }
1628
1629 // bookmarks, reference marks (and TOC marks) are the same except for the
1630 // element names. We use the same method for export and it an array with
1631 // the proper element names
1632 const enum XMLTokenEnum lcl_XmlReferenceElements[] = {
1633 XML_REFERENCE_MARK, XML_REFERENCE_MARK_START, XML_REFERENCE_MARK_END };
1634 const enum XMLTokenEnum lcl_XmlBookmarkElements[] = {
1635 XML_BOOKMARK, XML_BOOKMARK_START, XML_BOOKMARK_END };
1636
collectTextAutoStylesAndNodeExportOrder(bool bIsProgress)1637 void XMLTextParagraphExport::collectTextAutoStylesAndNodeExportOrder(bool bIsProgress)
1638 {
1639 GetExport().GetShapeExport(); // make sure the graphics styles family is added
1640
1641 if (mbCollected)
1642 return;
1643
1644 const bool bAutoStyles = true;
1645 const bool bExportContent = true;
1646
1647 if (auto xTextDocument = GetExport().GetModel().query<XTextDocument>())
1648 {
1649 bInDocumentNodeOrderCollection = true;
1650 collectTextAutoStyles(xTextDocument->getText(), bIsProgress);
1651 bInDocumentNodeOrderCollection = false;
1652 }
1653
1654 // Export text frames:
1655 Reference<XEnumeration> xTextFramesEnum = m_pBoundFrameSets->GetTexts()->createEnumeration();
1656 if(xTextFramesEnum.is())
1657 while(xTextFramesEnum->hasMoreElements())
1658 {
1659 Reference<XTextContent> xTxtCntnt(xTextFramesEnum->nextElement(), UNO_QUERY);
1660 if(xTxtCntnt.is())
1661 exportTextFrame(xTxtCntnt, bAutoStyles, bIsProgress, bExportContent);
1662 }
1663
1664 // Export graphic objects:
1665 Reference<XEnumeration> xGraphicsEnum = m_pBoundFrameSets->GetGraphics()->createEnumeration();
1666 if(xGraphicsEnum.is())
1667 while(xGraphicsEnum->hasMoreElements())
1668 {
1669 Reference<XTextContent> xTxtCntnt(xGraphicsEnum->nextElement(), UNO_QUERY);
1670 if(xTxtCntnt.is())
1671 exportTextGraphic(xTxtCntnt, true);
1672 }
1673
1674 // Export embedded objects:
1675 Reference<XEnumeration> xEmbeddedsEnum = m_pBoundFrameSets->GetEmbeddeds()->createEnumeration();
1676 if(xEmbeddedsEnum.is())
1677 while(xEmbeddedsEnum->hasMoreElements())
1678 {
1679 Reference<XTextContent> xTxtCntnt(xEmbeddedsEnum->nextElement(), UNO_QUERY);
1680 if(xTxtCntnt.is())
1681 exportTextEmbedded(xTxtCntnt, true);
1682 }
1683
1684 // Export shapes:
1685 Reference<XEnumeration> xShapesEnum = m_pBoundFrameSets->GetShapes()->createEnumeration();
1686 if(xShapesEnum.is())
1687 while(xShapesEnum->hasMoreElements())
1688 {
1689 Reference<XTextContent> xTxtCntnt(xShapesEnum->nextElement(), UNO_QUERY);
1690 if(xTxtCntnt.is())
1691 {
1692 Reference<XServiceInfo> xServiceInfo(xTxtCntnt, UNO_QUERY);
1693 if( xServiceInfo->supportsService(gsShapeService))
1694 exportShape(xTxtCntnt, true);
1695 }
1696 }
1697
1698 if (GetExport().getExportFlags() & SvXMLExportFlags::CONTENT)
1699 exportTrackedChanges(true);
1700
1701 mbCollected = true;
1702 }
1703
exportText(const Reference<XText> & rText,bool bAutoStyles,bool bIsProgress,bool bExportParagraph,TextPNS eExtensionNS)1704 void XMLTextParagraphExport::exportText(
1705 const Reference < XText > & rText,
1706 bool bAutoStyles,
1707 bool bIsProgress,
1708 bool bExportParagraph,
1709 TextPNS eExtensionNS)
1710 {
1711 if( bAutoStyles )
1712 GetExport().GetShapeExport(); // make sure the graphics styles family
1713 // is added
1714 Reference < XEnumerationAccess > xEA( rText, UNO_QUERY );
1715 if( ! xEA.is() )
1716 return;
1717
1718 Reference < XEnumeration > xParaEnum(xEA->createEnumeration());
1719 Reference < XPropertySet > xPropertySet( rText, UNO_QUERY );
1720 Reference < XTextSection > xBaseSection;
1721
1722 // #97718# footnotes don't supply paragraph enumerations in some cases
1723 // This is always a bug, but at least we don't want to crash.
1724 SAL_WARN_IF( !xParaEnum.is(), "xmloff", "We need a paragraph enumeration" );
1725 if( ! xParaEnum.is() )
1726 return;
1727
1728 if (xPropertySet.is())
1729 {
1730 Reference < XPropertySetInfo > xInfo ( xPropertySet->getPropertySetInfo() );
1731
1732 if( xInfo.is() )
1733 {
1734 if (xInfo->hasPropertyByName( gsTextSection ))
1735 {
1736 xPropertySet->getPropertyValue(gsTextSection) >>= xBaseSection ;
1737 }
1738 }
1739 }
1740
1741 // #96530# Export redlines at start & end of XText before & after
1742 // exporting the text content enumeration
1743 if( !bAutoStyles && (m_pRedlineExport != nullptr) )
1744 m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, true );
1745 exportTextContentEnumeration( xParaEnum, bAutoStyles, xBaseSection,
1746 bIsProgress, bExportParagraph, nullptr, eExtensionNS );
1747 if( !bAutoStyles && (m_pRedlineExport != nullptr) )
1748 m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, false );
1749 }
1750
exportText(const Reference<XText> & rText,const Reference<XTextSection> & rBaseSection,bool bAutoStyles,bool bIsProgress,bool bExportParagraph)1751 void XMLTextParagraphExport::exportText(
1752 const Reference < XText > & rText,
1753 const Reference < XTextSection > & rBaseSection,
1754 bool bAutoStyles,
1755 bool bIsProgress,
1756 bool bExportParagraph)
1757 {
1758 if( bAutoStyles )
1759 GetExport().GetShapeExport(); // make sure the graphics styles family
1760 // is added
1761 Reference < XEnumerationAccess > xEA( rText, UNO_QUERY );
1762 Reference < XEnumeration > xParaEnum(xEA->createEnumeration());
1763
1764 // #98165# don't continue without a paragraph enumeration
1765 if( ! xParaEnum.is() )
1766 return;
1767
1768 // #96530# Export redlines at start & end of XText before & after
1769 // exporting the text content enumeration
1770 Reference<XPropertySet> xPropertySet;
1771 if( !bAutoStyles && (m_pRedlineExport != nullptr) )
1772 {
1773 xPropertySet.set(rText, uno::UNO_QUERY );
1774 m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, true );
1775 }
1776 exportTextContentEnumeration( xParaEnum, bAutoStyles, rBaseSection,
1777 bIsProgress, bExportParagraph );
1778 if( !bAutoStyles && (m_pRedlineExport != nullptr) )
1779 m_pRedlineExport->ExportStartOrEndRedline( xPropertySet, false );
1780 }
1781
ExportListId() const1782 bool XMLTextParagraphExport::ExportListId() const
1783 {
1784 return (GetExport().getExportFlags() & SvXMLExportFlags::OASIS)
1785 && GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012;
1786 }
1787
1788 #ifndef NDEBUG
isInShapesTextFrame(const css::uno::Reference<css::text::XTextContent> & xTextContent)1789 static bool isInShapesTextFrame(const css::uno::Reference<css::text::XTextContent>& xTextContent)
1790 {
1791 auto xTextRange = xTextContent.query<css::text::XTextRange>();
1792 if (!xTextRange)
1793 return false;
1794 auto xParentTextProps = xTextRange->getText().query<css::beans::XPropertySet>();
1795 if (!xParentTextProps)
1796 return false;
1797 try
1798 {
1799 // see SwXTextFrame::getEvents
1800 css::uno::Any ret = xParentTextProps->getPropertyValue(u"DbgIsShapesTextFrame"_ustr);
1801 if (bool result; ret >>= result)
1802 return result;
1803 return false;
1804 }
1805 catch (css::beans::UnknownPropertyException&)
1806 {
1807 return false;
1808 }
1809 }
1810 #endif
1811
RecordNodeIndex(const css::uno::Reference<css::text::XTextContent> & xTextContent)1812 void XMLTextParagraphExport::RecordNodeIndex(const css::uno::Reference<css::text::XTextContent>& xTextContent)
1813 {
1814 if (!bInDocumentNodeOrderCollection)
1815 return;
1816 if (auto xPropSet = xTextContent.query<css::beans::XPropertySet>())
1817 {
1818 try
1819 {
1820 sal_Int32 index = 0;
1821 // See SwXParagraph::Impl::GetPropertyValues_Impl
1822 xPropSet->getPropertyValue(u"ODFExport_NodeIndex"_ustr) >>= index;
1823 auto it = std::find(maDocumentNodeOrder.begin(), maDocumentNodeOrder.end(), index);
1824 assert(it == maDocumentNodeOrder.end() || isInShapesTextFrame(xTextContent));
1825 if (it == maDocumentNodeOrder.end())
1826 maDocumentNodeOrder.push_back(index);
1827 }
1828 catch (css::beans::UnknownPropertyException&)
1829 {
1830 // That's absolutely fine!
1831 }
1832 }
1833 }
1834
ShouldSkipListId(const Reference<XTextContent> & xTextContent)1835 bool XMLTextParagraphExport::ShouldSkipListId(const Reference<XTextContent>& xTextContent)
1836 {
1837 if (!mpDocumentListNodes)
1838 {
1839 if (ExportListId())
1840 mpDocumentListNodes.reset(new DocumentListNodes(GetExport().GetModel(), maDocumentNodeOrder));
1841 else
1842 mpDocumentListNodes.reset(new DocumentListNodes({}, {}));
1843 }
1844
1845 return mpDocumentListNodes->ShouldSkipListId(xTextContent);
1846 }
1847
exportTextContentEnumeration(const Reference<XEnumeration> & rContEnum,bool bAutoStyles,const Reference<XTextSection> & rBaseSection,bool bIsProgress,bool bExportParagraph,const Reference<XPropertySet> * pRangePropSet,TextPNS eExtensionNS)1848 void XMLTextParagraphExport::exportTextContentEnumeration(
1849 const Reference < XEnumeration > & rContEnum,
1850 bool bAutoStyles,
1851 const Reference < XTextSection > & rBaseSection,
1852 bool bIsProgress,
1853 bool bExportParagraph,
1854 const Reference < XPropertySet > *pRangePropSet,
1855 TextPNS eExtensionNS )
1856 {
1857 SAL_WARN_IF( !rContEnum.is(), "xmloff", "No enumeration to export!" );
1858 bool bHasMoreElements = rContEnum->hasMoreElements();
1859 if( !bHasMoreElements )
1860 return;
1861
1862 XMLTextNumRuleInfo aPrevNumInfo;
1863 XMLTextNumRuleInfo aNextNumInfo;
1864
1865 bool bHasContent = false;
1866 Reference<XTextSection> xCurrentTextSection(rBaseSection);
1867
1868 MultiPropertySetHelper aPropSetHelper(
1869 bAutoStyles ? std::span<const OUString>(aParagraphPropertyNamesAuto) :
1870 std::span<const OUString>(aParagraphPropertyNames) );
1871
1872 bool bHoldElement = false;
1873 Reference < XTextContent > xTxtCntnt;
1874 while( bHoldElement || bHasMoreElements )
1875 {
1876 if (bHoldElement)
1877 {
1878 bHoldElement = false;
1879 }
1880 else
1881 {
1882 xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY);
1883
1884 aPropSetHelper.resetValues();
1885
1886 }
1887
1888 Reference<XServiceInfo> xServiceInfo( xTxtCntnt, UNO_QUERY );
1889 if( xServiceInfo->supportsService( gsParagraphService ) )
1890 {
1891 if( bAutoStyles )
1892 {
1893 RecordNodeIndex(xTxtCntnt);
1894 exportListAndSectionChange( xCurrentTextSection, xTxtCntnt,
1895 aPrevNumInfo, aNextNumInfo,
1896 bAutoStyles );
1897 }
1898 else
1899 {
1900 /* Pass list auto style pool to <XMLTextNumRuleInfo> instance
1901 Pass info about request to export <text:number> element
1902 to <XMLTextNumRuleInfo> instance (#i69627#)
1903 */
1904 aNextNumInfo.Set( xTxtCntnt,
1905 GetExport().writeOutlineStyleAsNormalListStyle(),
1906 GetListAutoStylePool(),
1907 GetExport().exportTextNumberElement(),
1908 ShouldSkipListId(xTxtCntnt) );
1909
1910 exportListAndSectionChange( xCurrentTextSection, aPropSetHelper,
1911 TEXT_SECTION, xTxtCntnt,
1912 aPrevNumInfo, aNextNumInfo,
1913 bAutoStyles );
1914 }
1915
1916 // if we found a mute section: skip all section content
1917 if (m_pSectionExport->IsMuteSection(xCurrentTextSection))
1918 {
1919 // Make sure headings are exported anyway.
1920 if( !bAutoStyles )
1921 m_pSectionExport->ExportMasterDocHeadingDummies();
1922
1923 while (rContEnum->hasMoreElements() &&
1924 XMLSectionExport::IsInSection( xCurrentTextSection,
1925 xTxtCntnt, true ))
1926 {
1927 xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY);
1928 aPropSetHelper.resetValues();
1929 aNextNumInfo.Reset();
1930 }
1931 // the first non-mute element still needs to be processed
1932 bHoldElement =
1933 ! XMLSectionExport::IsInSection( xCurrentTextSection,
1934 xTxtCntnt, false );
1935 }
1936 else
1937 exportParagraph( xTxtCntnt, bAutoStyles, bIsProgress,
1938 bExportParagraph, aPropSetHelper, eExtensionNS );
1939 bHasContent = true;
1940 }
1941 else if( xServiceInfo->supportsService( gsTableService ) )
1942 {
1943 if( !bAutoStyles )
1944 {
1945 aNextNumInfo.Reset();
1946 }
1947
1948 exportListAndSectionChange( xCurrentTextSection, xTxtCntnt,
1949 aPrevNumInfo, aNextNumInfo,
1950 bAutoStyles );
1951
1952 if (! m_pSectionExport->IsMuteSection(xCurrentTextSection))
1953 {
1954 // export start + end redlines (for wholly redlined tables)
1955 if ((! bAutoStyles) && (nullptr != m_pRedlineExport))
1956 m_pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, true);
1957
1958 exportTable( xTxtCntnt, bAutoStyles, bIsProgress );
1959
1960 if ((! bAutoStyles) && (nullptr != m_pRedlineExport))
1961 m_pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, false);
1962 }
1963 else if( !bAutoStyles )
1964 {
1965 // Make sure headings are exported anyway.
1966 m_pSectionExport->ExportMasterDocHeadingDummies();
1967 }
1968
1969 bHasContent = true;
1970 }
1971 else if( xServiceInfo->supportsService( gsTextFrameService ) )
1972 {
1973 exportTextFrame( xTxtCntnt, bAutoStyles, bIsProgress, true, pRangePropSet );
1974 }
1975 else if( xServiceInfo->supportsService( gsTextGraphicService ) )
1976 {
1977 exportTextGraphic( xTxtCntnt, bAutoStyles, pRangePropSet );
1978 }
1979 else if( xServiceInfo->supportsService( gsTextEmbeddedService ) )
1980 {
1981 exportTextEmbedded( xTxtCntnt, bAutoStyles, pRangePropSet );
1982 }
1983 else if( xServiceInfo->supportsService( gsShapeService ) )
1984 {
1985 exportShape( xTxtCntnt, bAutoStyles, pRangePropSet );
1986 }
1987 else
1988 {
1989 SAL_WARN_IF( xTxtCntnt.is(), "xmloff", "unknown text content" );
1990 }
1991
1992 if( !bAutoStyles )
1993 {
1994 aPrevNumInfo = aNextNumInfo;
1995 }
1996
1997 bHasMoreElements = rContEnum->hasMoreElements();
1998 }
1999
2000 if( bHasContent && !bAutoStyles )
2001 {
2002 aNextNumInfo.Reset();
2003
2004 // close open lists and sections; no new styles
2005 exportListAndSectionChange( xCurrentTextSection, rBaseSection,
2006 aPrevNumInfo, aNextNumInfo,
2007 bAutoStyles );
2008 }
2009 }
2010
exportParagraph(const Reference<XTextContent> & rTextContent,bool bAutoStyles,bool bIsProgress,bool bExportParagraph,MultiPropertySetHelper & rPropSetHelper,TextPNS eExtensionNS)2011 void XMLTextParagraphExport::exportParagraph(
2012 const Reference < XTextContent > & rTextContent,
2013 bool bAutoStyles, bool bIsProgress, bool bExportParagraph,
2014 MultiPropertySetHelper& rPropSetHelper, TextPNS eExtensionNS)
2015 {
2016 sal_Int16 nOutlineLevel = -1;
2017
2018 if( bIsProgress )
2019 {
2020 ProgressBarHelper *pProgress = GetExport().GetProgressBarHelper();
2021 pProgress->SetValue( pProgress->GetValue()+1 );
2022 }
2023
2024 // get property set or multi property set and initialize helper
2025 Reference<XMultiPropertySet> xMultiPropSet( rTextContent, UNO_QUERY );
2026 Reference<XPropertySet> xPropSet( rTextContent, UNO_QUERY );
2027
2028 // check for supported properties
2029 if( !rPropSetHelper.checkedProperties() )
2030 rPropSetHelper.hasProperties( xPropSet->getPropertySetInfo() );
2031
2032 // if( xMultiPropSet.is() )
2033 // rPropSetHelper.getValues( xMultiPropSet );
2034 // else
2035 // rPropSetHelper.getValues( xPropSet );
2036
2037 if( bExportParagraph )
2038 {
2039 if( bAutoStyles )
2040 {
2041 Add( XmlStyleFamily::TEXT_PARAGRAPH, rPropSetHelper, xPropSet );
2042 }
2043 else
2044 {
2045 // xml:id for RDF metadata
2046 GetExport().AddAttributeXmlId(rTextContent);
2047 GetExport().AddAttributesRDFa(rTextContent);
2048
2049 OUString sStyle;
2050 if( rPropSetHelper.hasProperty( PARA_STYLE_NAME ) )
2051 {
2052 if( xMultiPropSet.is() )
2053 rPropSetHelper.getValue( PARA_STYLE_NAME,
2054 xMultiPropSet ) >>= sStyle;
2055 else
2056 rPropSetHelper.getValue( PARA_STYLE_NAME,
2057 xPropSet ) >>= sStyle;
2058 }
2059
2060 if( rTextContent.is() )
2061 {
2062 const OUString& rIdentifier = GetExport().getInterfaceToIdentifierMapper().getIdentifier( rTextContent );
2063 if( !rIdentifier.isEmpty() )
2064 {
2065 // FIXME: this is just temporary until EditEngine
2066 // paragraphs implement XMetadatable.
2067 // then that must be used and not the mapper, because
2068 // when both can be used we get two xml:id!
2069 uno::Reference<rdf::XMetadatable> const xMeta(rTextContent,
2070 uno::UNO_QUERY);
2071 OSL_ENSURE(!xMeta.is(), "paragraph that implements "
2072 "XMetadatable used in interfaceToIdentifierMapper?");
2073 GetExport().AddAttributeIdLegacy(XML_NAMESPACE_TEXT,
2074 rIdentifier);
2075 }
2076 }
2077
2078 OUString sAutoStyle = Find( XmlStyleFamily::TEXT_PARAGRAPH, xPropSet, sStyle );
2079 if ( sAutoStyle.isEmpty() )
2080 sAutoStyle = sStyle;
2081 if( !sAutoStyle.isEmpty() )
2082 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
2083 GetExport().EncodeStyleName( sAutoStyle ) );
2084
2085 if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME ) )
2086 {
2087 OUString sCondStyle;
2088 if( xMultiPropSet.is() )
2089 rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME,
2090 xMultiPropSet ) >>= sCondStyle;
2091 else
2092 rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME,
2093 xPropSet ) >>= sCondStyle;
2094 if( sCondStyle != sStyle )
2095 {
2096 sCondStyle = Find( XmlStyleFamily::TEXT_PARAGRAPH, xPropSet,
2097 sCondStyle );
2098 if( !sCondStyle.isEmpty() )
2099 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
2100 XML_COND_STYLE_NAME,
2101 GetExport().EncodeStyleName( sCondStyle ) );
2102 }
2103 }
2104
2105 if( rPropSetHelper.hasProperty( PARA_OUTLINE_LEVEL ) )
2106 {
2107 if( xMultiPropSet.is() )
2108 rPropSetHelper.getValue( PARA_OUTLINE_LEVEL,
2109 xMultiPropSet ) >>= nOutlineLevel;
2110 else
2111 rPropSetHelper.getValue( PARA_OUTLINE_LEVEL,
2112 xPropSet ) >>= nOutlineLevel;
2113
2114 if( 0 < nOutlineLevel )
2115 {
2116 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
2117 XML_OUTLINE_LEVEL,
2118 OUString::number( sal_Int32( nOutlineLevel) ) );
2119
2120 if ( rPropSetHelper.hasProperty( PARA_OUTLINE_CONTENT_VISIBLE ) )
2121 {
2122 uno::Sequence<beans::PropertyValue> propList;
2123 bool bIsOutlineContentVisible = true;
2124 if( xMultiPropSet.is() )
2125 rPropSetHelper.getValue(
2126 PARA_OUTLINE_CONTENT_VISIBLE, xMultiPropSet ) >>= propList;
2127 else
2128 rPropSetHelper.getValue(
2129 PARA_OUTLINE_CONTENT_VISIBLE, xPropSet ) >>= propList;
2130 for (const auto& rProp : propList)
2131 {
2132 OUString propName = rProp.Name;
2133 if (propName == "OutlineContentVisibleAttr")
2134 {
2135 rProp.Value >>= bIsOutlineContentVisible;
2136 break;
2137 }
2138 }
2139 if (!bIsOutlineContentVisible)
2140 {
2141 GetExport().AddAttribute( XML_NAMESPACE_LO_EXT,
2142 XML_OUTLINE_CONTENT_VISIBLE,
2143 XML_FALSE);
2144 }
2145 }
2146
2147 if( rPropSetHelper.hasProperty( NUMBERING_IS_NUMBER ) )
2148 {
2149 bool bIsNumber = false;
2150 if( xMultiPropSet.is() )
2151 rPropSetHelper.getValue(
2152 NUMBERING_IS_NUMBER, xMultiPropSet ) >>= bIsNumber;
2153 else
2154 rPropSetHelper.getValue(
2155 NUMBERING_IS_NUMBER, xPropSet ) >>= bIsNumber;
2156
2157 OUString sListStyleName;
2158 if( xMultiPropSet.is() )
2159 rPropSetHelper.getValue(
2160 PARA_NUMBERING_STYLENAME, xMultiPropSet ) >>= sListStyleName;
2161 else
2162 rPropSetHelper.getValue(
2163 PARA_NUMBERING_STYLENAME, xPropSet ) >>= sListStyleName;
2164
2165 bool bAssignedtoOutlineStyle = false;
2166 {
2167 Reference< XChapterNumberingSupplier > xCNSupplier( GetExport().GetModel(), UNO_QUERY );
2168
2169 if (xCNSupplier.is())
2170 {
2171 Reference< XIndexReplace > xNumRule ( xCNSupplier->getChapterNumberingRules() );
2172 SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" );
2173
2174 if (xNumRule.is())
2175 {
2176 Reference< XPropertySet > xNumRulePropSet( xNumRule, UNO_QUERY );
2177 OUString sOutlineName;
2178 xNumRulePropSet->getPropertyValue(
2179 u"Name"_ustr ) >>= sOutlineName;
2180 bAssignedtoOutlineStyle = ( sListStyleName == sOutlineName );
2181 }
2182 }
2183 }
2184
2185 if( ! bIsNumber && bAssignedtoOutlineStyle )
2186 GetExport().AddAttribute( XML_NAMESPACE_TEXT,
2187 XML_IS_LIST_HEADER,
2188 XML_TRUE );
2189 }
2190
2191 {
2192 bool bIsRestartNumbering = false;
2193
2194 Reference< XPropertySetInfo >
2195 xPropSetInfo(xMultiPropSet.is() ?
2196 xMultiPropSet->getPropertySetInfo():
2197 xPropSet->getPropertySetInfo());
2198
2199 if (xPropSetInfo->
2200 hasPropertyByName(u"ParaIsNumberingRestart"_ustr))
2201 {
2202 xPropSet->getPropertyValue(u"ParaIsNumberingRestart"_ustr)
2203 >>= bIsRestartNumbering;
2204 }
2205
2206 if (bIsRestartNumbering)
2207 {
2208 GetExport().AddAttribute(XML_NAMESPACE_TEXT,
2209 XML_RESTART_NUMBERING,
2210 XML_TRUE);
2211
2212 if (xPropSetInfo->
2213 hasPropertyByName(u"NumberingStartValue"_ustr))
2214 {
2215 sal_Int32 nStartValue = 0;
2216
2217 xPropSet->getPropertyValue(u"NumberingStartValue"_ustr)
2218 >>= nStartValue;
2219
2220 GetExport().
2221 AddAttribute(XML_NAMESPACE_TEXT,
2222 XML_START_VALUE,
2223 OUString::number(nStartValue));
2224 }
2225 }
2226 }
2227 }
2228 }
2229 }
2230
2231 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2232 {
2233 try
2234 {
2235 // ParaMarkerAutoStyleSpan is a hidden property, just to pass the autostyle here
2236 // See SwXParagraph::Impl::GetPropertyValues_Impl
2237 css::uno::Any aVal = xPropSet->getPropertyValue(u"ParaMarkerAutoStyleSpan"_ustr);
2238 if (auto xFakeSpan = aVal.query<css::beans::XPropertySet>())
2239 {
2240 if (bAutoStyles)
2241 {
2242 Add(XmlStyleFamily::TEXT_TEXT, xFakeSpan);
2243 }
2244 else
2245 {
2246 bool bIsUICharStyle, bHasAutoStyle;
2247 OUString sStyle = FindTextStyle(xFakeSpan, bIsUICharStyle, bHasAutoStyle);
2248 if (!sStyle.isEmpty())
2249 {
2250 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_MARKER_STYLE_NAME,
2251 sStyle);
2252 }
2253 }
2254 }
2255 }
2256 catch (const css::beans::UnknownPropertyException&)
2257 {
2258 // No problem
2259 }
2260 }
2261 }
2262
2263 Reference < XEnumerationAccess > xEA( rTextContent, UNO_QUERY );
2264 Reference < XEnumeration > xTextEnum = xEA->createEnumeration();
2265
2266 Reference < XEnumeration> xContentEnum;
2267 Reference < XContentEnumerationAccess > xCEA( rTextContent, UNO_QUERY );
2268 if( xCEA.is() )
2269 xContentEnum.set(xCEA->createContentEnumeration( gsTextContentService ));
2270 const bool bHasContentEnum = xContentEnum.is() &&
2271 xContentEnum->hasMoreElements();
2272
2273 Reference < XTextSection > xSection;
2274 if( bHasContentEnum )
2275 {
2276 // For the auto styles, the multi property set helper is only used
2277 // if hard attributes are existing. Therefore, it seems to be a better
2278 // strategy to have the TextSection property separate, because otherwise
2279 // we always retrieve the style names even if they are not required.
2280 if( bAutoStyles )
2281 {
2282 if( xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextSection ) )
2283 {
2284 xSection.set(xPropSet->getPropertyValue( gsTextSection ), uno::UNO_QUERY);
2285 }
2286 }
2287 else
2288 {
2289 if( rPropSetHelper.hasProperty( TEXT_SECTION ) )
2290 {
2291 xSection.set(rPropSetHelper.getValue( TEXT_SECTION ), uno::UNO_QUERY);
2292 }
2293 }
2294 }
2295
2296 bool bPrevCharIsSpace(true); // true because whitespace at start is ignored
2297
2298 {
2299 enum XMLTokenEnum eElem =
2300 0 < nOutlineLevel ? XML_H : XML_P;
2301 SvXMLElementExport aElem( GetExport(), !bAutoStyles, eExtensionNS == TextPNS::EXTENSION ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_TEXT, eElem,
2302 true, false );
2303 if( bHasContentEnum )
2304 {
2305 exportTextContentEnumeration(
2306 xContentEnum, bAutoStyles, xSection,
2307 bIsProgress );
2308 }
2309 exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace);
2310 }
2311 }
2312
exportTextRangeEnumeration(const Reference<XEnumeration> & rTextEnum,bool bAutoStyles,bool bIsProgress,bool & rPrevCharIsSpace)2313 void XMLTextParagraphExport::exportTextRangeEnumeration(
2314 const Reference < XEnumeration > & rTextEnum,
2315 bool bAutoStyles, bool bIsProgress,
2316 bool & rPrevCharIsSpace)
2317 {
2318 static const char sFieldMarkName[] = "__FieldMark_";
2319
2320 /* This is used for exporting to strict OpenDocument 1.2, in which case traditional
2321 * bookmarks are used instead of fieldmarks. */
2322 FieldmarkType openFieldMark = NONE;
2323
2324 std::optional<SvXMLElementExport> oTextA;
2325 HyperlinkData aHyperlinkData;
2326
2327 while( rTextEnum->hasMoreElements() )
2328 {
2329 Reference<XPropertySet> xPropSet(rTextEnum->nextElement(), UNO_QUERY);
2330 Reference < XTextRange > xTxtRange(xPropSet, uno::UNO_QUERY);
2331 Reference<XPropertySetInfo> xPropInfo(xPropSet->getPropertySetInfo());
2332
2333 if (!bAutoStyles)
2334 {
2335 if (HyperlinkData aNewHyperlinkData(xPropSet); aNewHyperlinkData != aHyperlinkData)
2336 {
2337 aHyperlinkData = std::move(aNewHyperlinkData);
2338 oTextA.reset();
2339 if (aHyperlinkData.addHyperlinkAttributes(GetExport()))
2340 {
2341 oTextA.emplace(GetExport(), true, XML_NAMESPACE_TEXT, XML_A, false, false);
2342 aHyperlinkData.exportEvents(GetExport());
2343 }
2344 }
2345 }
2346
2347 if (xPropInfo->hasPropertyByName(gsTextPortionType))
2348 {
2349 OUString sType;
2350 xPropSet->getPropertyValue(gsTextPortionType) >>= sType;
2351
2352 if( sType == gsText)
2353 {
2354 exportTextRange( xTxtRange, bAutoStyles,
2355 rPrevCharIsSpace, openFieldMark);
2356 }
2357 else if( sType == gsTextField)
2358 {
2359 exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace);
2360 }
2361 else if ( sType == "Annotation" )
2362 {
2363 exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace);
2364 }
2365 else if ( sType == "AnnotationEnd" )
2366 {
2367 if (!bAutoStyles)
2368 {
2369 Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2370 const OUString aName = xBookmark->getName();
2371 if (!aName.isEmpty())
2372 {
2373 GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, aName);
2374 }
2375 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_OFFICE, XML_ANNOTATION_END, false, false );
2376 }
2377 }
2378 else if( sType == gsFrame )
2379 {
2380 Reference < XEnumeration> xContentEnum;
2381 Reference < XContentEnumerationAccess > xCEA( xTxtRange,
2382 UNO_QUERY );
2383 if( xCEA.is() )
2384 xContentEnum.set(xCEA->createContentEnumeration(
2385 gsTextContentService ));
2386 // frames are never in sections
2387 Reference<XTextSection> xSection;
2388 if( xContentEnum.is() )
2389 exportTextContentEnumeration( xContentEnum,
2390 bAutoStyles,
2391 xSection, bIsProgress, true,
2392 &xPropSet );
2393
2394 }
2395 else if (sType == gsFootnote)
2396 {
2397 exportTextFootnote(xPropSet,
2398 xTxtRange->getString(),
2399 bAutoStyles, bIsProgress );
2400 }
2401 else if (sType == gsBookmark)
2402 {
2403 exportTextMark(xPropSet,
2404 gsBookmark,
2405 lcl_XmlBookmarkElements,
2406 bAutoStyles);
2407 }
2408 else if (sType == gsReferenceMark)
2409 {
2410 exportTextMark(xPropSet,
2411 gsReferenceMark,
2412 lcl_XmlReferenceElements,
2413 bAutoStyles);
2414 }
2415 else if (sType == gsDocumentIndexMark)
2416 {
2417 m_pIndexMarkExport->ExportIndexMark(xPropSet, bAutoStyles);
2418 }
2419 else if (sType == gsRedline)
2420 {
2421 if (nullptr != m_pRedlineExport)
2422 m_pRedlineExport->ExportChange(xPropSet, bAutoStyles);
2423 }
2424 else if (sType == gsRuby)
2425 {
2426 exportRuby(xPropSet, bAutoStyles);
2427 }
2428 else if (sType == "InContentMetadata")
2429 {
2430 exportMeta(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace);
2431 }
2432 else if (sType == "ContentControl")
2433 {
2434 ExportContentControl(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace);
2435 }
2436 else if (sType == gsTextFieldStart)
2437 {
2438 Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2439
2440 /* As of now, textmarks are a proposed extension to the OpenDocument standard. */
2441 if (!bAutoStyles)
2442 {
2443 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2444 {
2445 Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2446 if (xBookmark.is())
2447 {
2448 GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName());
2449 }
2450
2451 if (xFormField.is())
2452 {
2453 GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType());
2454 }
2455
2456 GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false);
2457 if (xFormField.is())
2458 {
2459 FieldParamExporter(&GetExport(), xFormField->getParameters()).Export();
2460 }
2461 GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false);
2462 }
2463 /* The OpenDocument standard does not include support for TextMarks for now, so use bookmarks instead. */
2464 else
2465 {
2466 if (xFormField.is())
2467 {
2468 OUString sName;
2469 Reference< css::container::XNameAccess > xParameters = xFormField->getParameters();
2470 if (xParameters.is() && xParameters->hasByName(u"Name"_ustr))
2471 {
2472 const Any aValue = xParameters->getByName(u"Name"_ustr);
2473 aValue >>= sName;
2474 }
2475 if (sName.isEmpty())
2476 { // name attribute is mandatory, so have to pull a
2477 // rabbit out of the hat here
2478 sName = sFieldMarkName + OUString::number(
2479 m_xImpl->AddFieldMarkStart(xFormField));
2480 }
2481 GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME,
2482 sName);
2483 SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2484 XML_NAMESPACE_TEXT, XML_BOOKMARK_START,
2485 false, false );
2486 const OUString sFieldType = xFormField->getFieldType();
2487 if (sFieldType == ODF_FORMTEXT)
2488 {
2489 openFieldMark = TEXT;
2490 }
2491 else if (sFieldType == ODF_FORMCHECKBOX)
2492 {
2493 openFieldMark = CHECK;
2494 }
2495 else
2496 {
2497 openFieldMark = NONE;
2498 }
2499 }
2500 }
2501 }
2502 }
2503 else if (sType == gsTextFieldSep)
2504 {
2505 if (!bAutoStyles)
2506 {
2507 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2508 {
2509 SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2510 XML_NAMESPACE_FIELD, XML_FIELDMARK_SEPARATOR,
2511 false, false );
2512 }
2513 }
2514 }
2515 else if (sType == gsTextFieldEnd)
2516 {
2517 if (!bAutoStyles)
2518 {
2519 Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2520
2521 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2522 {
2523 SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2524 XML_NAMESPACE_FIELD, XML_FIELDMARK_END,
2525 false, false );
2526 }
2527 else
2528 {
2529 if (xFormField.is())
2530 {
2531 OUString sName;
2532 Reference< css::container::XNameAccess > xParameters = xFormField->getParameters();
2533 if (xParameters.is() && xParameters->hasByName(u"Name"_ustr))
2534 {
2535 const Any aValue = xParameters->getByName(u"Name"_ustr);
2536 aValue >>= sName;
2537 }
2538 if (sName.isEmpty())
2539 { // name attribute is mandatory, so have to pull a
2540 // rabbit out of the hat here
2541 sName = sFieldMarkName + OUString::number(
2542 m_xImpl->GetFieldMarkIndex(xFormField));
2543 }
2544 GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME,
2545 sName);
2546 SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2547 XML_NAMESPACE_TEXT, XML_BOOKMARK_END,
2548 false, false );
2549 }
2550 }
2551 }
2552 }
2553 else if (sType == gsTextFieldStartEnd)
2554 {
2555 exportTextFieldStartEnd(xPropSet, bAutoStyles);
2556 }
2557 else if (sType == gsSoftPageBreak)
2558 {
2559 if (!bAutoStyles)
2560 exportSoftPageBreak();
2561 }
2562 else if (sType == "LineBreak")
2563 {
2564 if (!bAutoStyles)
2565 exportTextLineBreak(xPropSet);
2566 }
2567 else {
2568 OSL_FAIL("unknown text portion type");
2569 }
2570 }
2571 else
2572 {
2573 Reference<XServiceInfo> xServiceInfo( xTxtRange, UNO_QUERY );
2574 if( xServiceInfo->supportsService( gsTextFieldService ) )
2575 {
2576 exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace);
2577 }
2578 else
2579 {
2580 // no TextPortionType property -> non-Writer app -> text
2581 exportTextRange(xTxtRange, bAutoStyles, rPrevCharIsSpace, openFieldMark);
2582 }
2583 }
2584 }
2585
2586 // now that there are nested enumerations for meta(-field), this may be valid!
2587 // SAL_WARN_IF( bOpenRuby, "xmloff", "Red Alert: Ruby still open!" );
2588 }
2589
exportTable(const Reference<XTextContent> &,bool,bool)2590 void XMLTextParagraphExport::exportTable(
2591 const Reference < XTextContent > &,
2592 bool /*bAutoStyles*/, bool /*bIsProgress*/ )
2593 {
2594 }
2595
exportTextField(const Reference<XTextRange> & rTextRange,bool bAutoStyles,bool bIsProgress,bool * const pPrevCharIsSpace)2596 void XMLTextParagraphExport::exportTextField(
2597 const Reference < XTextRange > & rTextRange,
2598 bool bAutoStyles, bool bIsProgress, bool *const pPrevCharIsSpace)
2599 {
2600 Reference < XPropertySet > xPropSet( rTextRange, UNO_QUERY );
2601 // non-Writer apps need not support Property TextField, so test first
2602 if (!xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextField ))
2603 return;
2604
2605 Reference < XTextField > xTxtFld(xPropSet->getPropertyValue( gsTextField ), uno::UNO_QUERY);
2606 SAL_WARN_IF( !xTxtFld.is(), "xmloff", "text field missing" );
2607 if( xTxtFld.is() )
2608 {
2609 exportTextField(xTxtFld, bAutoStyles, bIsProgress, pPrevCharIsSpace);
2610 }
2611 else
2612 {
2613 // write only characters
2614 GetExport().Characters(rTextRange->getString());
2615 }
2616 }
2617
exportTextField(const Reference<XTextField> & xTextField,const bool bAutoStyles,const bool bIsProgress,bool * const pPrevCharIsSpace)2618 void XMLTextParagraphExport::exportTextField(
2619 const Reference < XTextField > & xTextField,
2620 const bool bAutoStyles, const bool bIsProgress,
2621 bool *const pPrevCharIsSpace)
2622 {
2623 if ( bAutoStyles )
2624 {
2625 m_pFieldExport->ExportFieldAutoStyle( xTextField, bIsProgress );
2626 }
2627 else
2628 {
2629 assert(pPrevCharIsSpace);
2630 m_pFieldExport->ExportField(xTextField, bIsProgress, *pPrevCharIsSpace);
2631 }
2632 }
2633
exportTextFieldStartEnd(const Reference<XPropertySet> & xPropSet,const bool bAutoStyles)2634 void XMLTextParagraphExport::exportTextFieldStartEnd(const Reference < XPropertySet >& xPropSet, const bool bAutoStyles)
2635 {
2636 if (!bAutoStyles)
2637 {
2638 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2639 {
2640 bool bHasStyle = false;
2641 Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2642 if (xBookmark.is())
2643 {
2644 Reference<XTextContent> xBookmarkContent(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2645 Reference<XPropertySet> xRangePropSet(xBookmarkContent->getAnchor(), UNO_QUERY);
2646 const XMLPropertyState **pStates = nullptr;
2647 // find out whether we need to set the style
2648 bool bIsUICharStyle;
2649 bool bHasAutoStyle;
2650 OUString sStyle = GetExport().GetTextParagraphExport()->
2651 FindTextStyle( xRangePropSet, bIsUICharStyle, bHasAutoStyle, pStates );
2652 bHasStyle = !sStyle.isEmpty();
2653 Reference<XPropertySetInfo> xRangePropSetInfo;
2654 XMLTextCharStyleNamesElementExport aCharStylesExport(
2655 GetExport(), bIsUICharStyle &&
2656 GetExport().GetTextParagraphExport()
2657 ->GetCharStyleNamesPropInfoCache().hasProperty(
2658 xRangePropSet, xRangePropSetInfo ), bHasAutoStyle,
2659 xRangePropSet, gsPropertyCharStyleNames );
2660
2661 if( bHasStyle )
2662 {
2663 // export <text:span> element
2664 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
2665 GetExport().EncodeStyleName( sStyle ) );
2666 }
2667 }
2668 SvXMLElementExport aSpan( GetExport(), bHasStyle,
2669 XML_NAMESPACE_TEXT, XML_SPAN,
2670 false, false);
2671 if (xBookmark.is())
2672 {
2673 GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName());
2674 }
2675 Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2676 if (xFormField.is())
2677 {
2678 GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType());
2679 }
2680 GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false);
2681 if (xFormField.is())
2682 {
2683 FieldParamExporter(&GetExport(), xFormField->getParameters()).Export();
2684 }
2685 GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false);
2686 }
2687 else
2688 {
2689 Reference<XNamed> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2690 if (xBookmark.is())
2691 {
2692 GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName());
2693 SvXMLElementExport aElem( GetExport(), !bAutoStyles,
2694 XML_NAMESPACE_TEXT, XML_BOOKMARK,
2695 false, false );
2696 }
2697 }
2698 }
2699 else
2700 {
2701 Reference<XTextContent> xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY);
2702 if (xBookmark.is())
2703 {
2704 Reference<XPropertySet> xRangePropSet(xBookmark->getAnchor(), UNO_QUERY);
2705 GetExport().GetTextParagraphExport()->Add(XmlStyleFamily::TEXT_TEXT,
2706 xRangePropSet);
2707 }
2708 }
2709 }
2710
exportSoftPageBreak()2711 void XMLTextParagraphExport::exportSoftPageBreak()
2712 {
2713 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
2714 XML_SOFT_PAGE_BREAK, false,
2715 false );
2716 }
2717
exportTextLineBreak(const uno::Reference<beans::XPropertySet> & xPropSet)2718 void XMLTextParagraphExport::exportTextLineBreak(
2719 const uno::Reference<beans::XPropertySet>& xPropSet)
2720 {
2721 static const XMLTokenEnum aLineBreakClears[] = {
2722 XML_NONE,
2723 XML_LEFT,
2724 XML_RIGHT,
2725 XML_ALL,
2726 };
2727
2728 uno::Reference<text::XTextContent> xLineBreak;
2729 xPropSet->getPropertyValue(u"LineBreak"_ustr) >>= xLineBreak;
2730 if (!xLineBreak.is())
2731 {
2732 return;
2733 }
2734
2735 uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
2736 if (!xLineBreakProps.is())
2737 {
2738 return;
2739 }
2740
2741 sal_Int16 eClear{};
2742 xLineBreakProps->getPropertyValue(u"Clear"_ustr) >>= eClear;
2743 if (eClear >= 0 && o3tl::make_unsigned(eClear) < SAL_N_ELEMENTS(aLineBreakClears))
2744 {
2745 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CLEAR,
2746 GetXMLToken(aLineBreakClears[eClear]));
2747 }
2748 SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, XML_LINE_BREAK,
2749 /*bIgnWSOutside=*/false, /*bIgnWSInside=*/false);
2750 }
2751
exportTextMark(const Reference<XPropertySet> & rPropSet,const OUString & rProperty,const::xmloff::token::XMLTokenEnum pElements[],bool bAutoStyles)2752 void XMLTextParagraphExport::exportTextMark(
2753 const Reference<XPropertySet> & rPropSet,
2754 const OUString& rProperty,
2755 const ::xmloff::token::XMLTokenEnum pElements[],
2756 bool bAutoStyles)
2757 {
2758 // mib said: "Hau wech!"
2759
2760 // (Originally, I'd export a span element in case the (book|reference)mark
2761 // was formatted. This actually makes a difference in case some pervert
2762 // sets a point reference mark in the document and, say, formats it bold.
2763 // This basically meaningless formatting will now been thrown away
2764 // (aka cleaned up), since mib said: ... dvo
2765
2766 if (bAutoStyles)
2767 return;
2768
2769 // name element
2770 Reference<XNamed> xName(rPropSet->getPropertyValue(rProperty), UNO_QUERY);
2771 GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME,
2772 xName->getName());
2773
2774 // start, end, or point-reference?
2775 sal_Int8 nElement;
2776 if( *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsCollapsed)) )
2777 {
2778 nElement = 0;
2779 }
2780 else
2781 {
2782 nElement = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsStart)) ? 1 : 2;
2783 }
2784
2785 // bookmark, bookmark-start: xml:id and RDFa for RDF metadata
2786 if( nElement < 2 ) {
2787 GetExport().AddAttributeXmlId(xName);
2788 const uno::Reference<text::XTextContent> xTextContent(
2789 xName, uno::UNO_QUERY_THROW);
2790 GetExport().AddAttributesRDFa(xTextContent);
2791 }
2792
2793 // bookmark-start: add attributes hidden and condition
2794 if (nElement == 1)
2795 {
2796 Reference<XPropertySet> bkmkProps(rPropSet->getPropertyValue(rProperty), UNO_QUERY);
2797 Reference<XPropertySetInfo> bkmkPropInfo = bkmkProps->getPropertySetInfo();
2798 OUString sHidden(u"BookmarkHidden"_ustr);
2799 if (bkmkPropInfo->hasPropertyByName(sHidden))
2800 {
2801 bool bHidden = false;
2802 bkmkProps->getPropertyValue(sHidden) >>= bHidden;
2803 if (bHidden)
2804 {
2805 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, u"hidden"_ustr, u"true"_ustr);
2806 OUString sCondition(u"BookmarkCondition"_ustr);
2807 if (bkmkPropInfo->hasPropertyByName(sCondition))
2808 {
2809 OUString sBookmarkCondition;
2810 bkmkProps->getPropertyValue(sCondition) >>= sBookmarkCondition;
2811 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, u"condition"_ustr, sBookmarkCondition);
2812 }
2813 }
2814 }
2815 }
2816
2817 // export element
2818 assert(pElements != nullptr);
2819 assert(0 <= nElement && nElement <= 2);
2820 SvXMLElementExport aElem(GetExport(),
2821 XML_NAMESPACE_TEXT, pElements[nElement],
2822 false, false);
2823 // else: no styles. (see above)
2824 }
2825
lcl_txtpara_isBoundAsChar(const Reference<XPropertySet> & rPropSet,const Reference<XPropertySetInfo> & rPropSetInfo)2826 static bool lcl_txtpara_isBoundAsChar(
2827 const Reference < XPropertySet > & rPropSet,
2828 const Reference < XPropertySetInfo > & rPropSetInfo )
2829 {
2830 bool bIsBoundAsChar = false;
2831 OUString sAnchorType( u"AnchorType"_ustr );
2832 if( rPropSetInfo->hasPropertyByName( sAnchorType ) )
2833 {
2834 TextContentAnchorType eAnchor;
2835 rPropSet->getPropertyValue( sAnchorType ) >>= eAnchor;
2836 bIsBoundAsChar = TextContentAnchorType_AS_CHARACTER == eAnchor;
2837 }
2838
2839 return bIsBoundAsChar;
2840 }
2841
addTextFrameAttributes(const Reference<XPropertySet> & rPropSet,bool bShape,basegfx::B2DPoint * pCenter,OUString * pMinHeightValue,OUString * pMinWidthValue)2842 XMLShapeExportFlags XMLTextParagraphExport::addTextFrameAttributes(
2843 const Reference < XPropertySet >& rPropSet,
2844 bool bShape,
2845 basegfx::B2DPoint* pCenter,
2846 OUString* pMinHeightValue,
2847 OUString* pMinWidthValue)
2848 {
2849 XMLShapeExportFlags nShapeFeatures = SEF_DEFAULT;
2850
2851 // draw:name (#97662#: not for shapes, since those names will be
2852 // treated in the shape export)
2853 if( !bShape )
2854 {
2855 Reference < XNamed > xNamed( rPropSet, UNO_QUERY );
2856 if( xNamed.is() )
2857 {
2858 OUString sName( xNamed->getName() );
2859 if( !sName.isEmpty() )
2860 GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_NAME,
2861 xNamed->getName() );
2862 }
2863 }
2864
2865 OUStringBuffer sValue;
2866
2867 // text:anchor-type
2868 TextContentAnchorType eAnchor = TextContentAnchorType_AT_PARAGRAPH;
2869 rPropSet->getPropertyValue( gsAnchorType ) >>= eAnchor;
2870 {
2871 XMLAnchorTypePropHdl aAnchorTypeHdl;
2872 OUString sTmp;
2873 aAnchorTypeHdl.exportXML( sTmp, uno::Any(eAnchor),
2874 GetExport().GetMM100UnitConverter() );
2875 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_TYPE, sTmp );
2876 }
2877
2878 // text:anchor-page-number
2879 if( TextContentAnchorType_AT_PAGE == eAnchor )
2880 {
2881 sal_Int16 nPage = 0;
2882 rPropSet->getPropertyValue( gsAnchorPageNo ) >>= nPage;
2883 SAL_WARN_IF(nPage <= 0, "xmloff",
2884 "ERROR: writing invalid anchor-page-number 0");
2885 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_PAGE_NUMBER,
2886 OUString::number( nPage ) );
2887 }
2888 else
2889 {
2890 nShapeFeatures |= XMLShapeExportFlags::NO_WS;
2891 }
2892
2893 // OD 2004-06-01 #i27691# - correction: no export of svg:x, if object
2894 // is anchored as-character.
2895 if ( !bShape &&
2896 eAnchor != TextContentAnchorType_AS_CHARACTER )
2897 {
2898 // svg:x
2899 sal_Int16 nHoriOrient = HoriOrientation::NONE;
2900 rPropSet->getPropertyValue( gsHoriOrient ) >>= nHoriOrient;
2901 if( HoriOrientation::NONE == nHoriOrient )
2902 {
2903 sal_Int32 nPos = 0;
2904 rPropSet->getPropertyValue( gsHoriOrientPosition ) >>= nPos;
2905 GetExport().GetMM100UnitConverter().convertMeasureToXML(
2906 sValue, nPos );
2907 GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_X,
2908 sValue.makeStringAndClear() );
2909 if(nullptr != pCenter)
2910 {
2911 // add left edge to Center
2912 pCenter->setX(pCenter->getX() + nPos);
2913 }
2914 }
2915 }
2916 else if( TextContentAnchorType_AS_CHARACTER == eAnchor )
2917 nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::X);
2918
2919 if( !bShape || TextContentAnchorType_AS_CHARACTER == eAnchor )
2920 {
2921 // svg:y
2922 sal_Int16 nVertOrient = VertOrientation::NONE;
2923 rPropSet->getPropertyValue( gsVertOrient ) >>= nVertOrient;
2924 if( VertOrientation::NONE == nVertOrient )
2925 {
2926 sal_Int32 nPos = 0;
2927 rPropSet->getPropertyValue( gsVertOrientPosition ) >>= nPos;
2928 GetExport().GetMM100UnitConverter().convertMeasureToXML(
2929 sValue, nPos );
2930 GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_Y,
2931 sValue.makeStringAndClear() );
2932 if(nullptr != pCenter)
2933 {
2934 // add top edge to Center
2935 pCenter->setY(pCenter->getY() + nPos);
2936 }
2937 }
2938 if( bShape )
2939 nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::Y);
2940 }
2941
2942 Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo());
2943
2944 bool bSyncWidth = false;
2945 if (xPropSetInfo->hasPropertyByName(gsIsSyncWidthToHeight))
2946 {
2947 bSyncWidth = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsSyncWidthToHeight));
2948 }
2949 sal_Int16 nRelWidth = 0;
2950 if (!bSyncWidth && xPropSetInfo->hasPropertyByName(gsRelativeWidth))
2951 {
2952 rPropSet->getPropertyValue(gsRelativeWidth) >>= nRelWidth;
2953 }
2954 bool bSyncHeight = false;
2955 if (xPropSetInfo->hasPropertyByName(gsIsSyncHeightToWidth))
2956 {
2957 bSyncHeight = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsSyncHeightToWidth));
2958 }
2959 sal_Int16 nRelHeight = 0;
2960 if (!bSyncHeight && xPropSetInfo->hasPropertyByName(gsRelativeHeight))
2961 {
2962 rPropSet->getPropertyValue(gsRelativeHeight) >>= nRelHeight;
2963 }
2964 awt::Size aLayoutSize;
2965 if ((nRelWidth > 0 || nRelHeight > 0) && xPropSetInfo->hasPropertyByName(u"LayoutSize"_ustr))
2966 {
2967 rPropSet->getPropertyValue(u"LayoutSize"_ustr) >>= aLayoutSize;
2968 }
2969
2970 bool bUseLayoutSize = true;
2971 if (bSyncWidth && bSyncHeight)
2972 {
2973 // This is broken, width depends on height and height depends on width. Don't use the
2974 // invalid layout size we got.
2975 bUseLayoutSize = false;
2976 }
2977 if (aLayoutSize.Width <= 0 || aLayoutSize.Height <= 0)
2978 {
2979 // This is broken, Writer frames have a minimal size, see MINFLY.
2980 bUseLayoutSize = false;
2981 }
2982
2983 // svg:width
2984 sal_Int16 nWidthType = SizeType::FIX;
2985 if( xPropSetInfo->hasPropertyByName( gsWidthType ) )
2986 {
2987 rPropSet->getPropertyValue( gsWidthType ) >>= nWidthType;
2988 }
2989 if( xPropSetInfo->hasPropertyByName( gsWidth ) )
2990 {
2991 sal_Int32 nWidth = 0;
2992 // VAR size will be written as zero min-size
2993 if( SizeType::VARIABLE != nWidthType )
2994 {
2995 rPropSet->getPropertyValue( gsWidth ) >>= nWidth;
2996 }
2997 GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, nWidth);
2998 if( SizeType::FIX != nWidthType )
2999 {
3000 assert(pMinWidthValue);
3001 if (pMinWidthValue)
3002 {
3003 *pMinWidthValue = sValue.makeStringAndClear();
3004 }
3005 }
3006 else
3007 {
3008 if ((nRelWidth > 0 || bSyncWidth) && bUseLayoutSize)
3009 {
3010 // Relative width: write the layout size for the fallback width.
3011 sValue.setLength(0);
3012 GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, aLayoutSize.Width);
3013 }
3014
3015 GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH,
3016 sValue.makeStringAndClear() );
3017 if(nullptr != pCenter)
3018 {
3019 // add half width to Center
3020 pCenter->setX(pCenter->getX() + (0.5 * nWidth));
3021 }
3022 }
3023 }
3024 if( xPropSetInfo->hasPropertyByName( gsIsSyncWidthToHeight ) )
3025 {
3026 if( bSyncWidth )
3027 GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH,
3028 XML_SCALE );
3029 }
3030 if( !bSyncWidth && xPropSetInfo->hasPropertyByName( gsRelativeWidth ) )
3031 {
3032 SAL_WARN_IF( nRelWidth < 0 || nRelWidth > 254, "xmloff",
3033 "Got illegal relative width from API" );
3034 if( nRelWidth > 0 )
3035 {
3036 ::sax::Converter::convertPercent( sValue, nRelWidth );
3037 GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH,
3038 sValue.makeStringAndClear() );
3039 }
3040 }
3041
3042 // svg:height, fo:min-height or style:rel-height
3043 sal_Int16 nSizeType = SizeType::FIX;
3044 if( xPropSetInfo->hasPropertyByName( gsSizeType ) )
3045 {
3046 rPropSet->getPropertyValue( gsSizeType ) >>= nSizeType;
3047 }
3048 if( xPropSetInfo->hasPropertyByName( gsHeight ) )
3049 {
3050 sal_Int32 nHeight = 0;
3051 if( SizeType::VARIABLE != nSizeType )
3052 {
3053 rPropSet->getPropertyValue( gsHeight ) >>= nHeight;
3054 }
3055 GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue,
3056 nHeight );
3057 if( SizeType::FIX != nSizeType && 0==nRelHeight && !bSyncHeight &&
3058 pMinHeightValue )
3059 {
3060 *pMinHeightValue = sValue.makeStringAndClear();
3061 }
3062 else
3063 {
3064 if ((nRelHeight > 0 || bSyncHeight) && bUseLayoutSize)
3065 {
3066 // Relative height: write the layout size for the fallback height.
3067 sValue.setLength(0);
3068 GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, aLayoutSize.Height);
3069 }
3070
3071 GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT,
3072 sValue.makeStringAndClear() );
3073 if(nullptr != pCenter)
3074 {
3075 // add half height to Center
3076 pCenter->setY(pCenter->getY() + (0.5 * nHeight));
3077 }
3078 }
3079 }
3080 if( bSyncHeight )
3081 {
3082 GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT,
3083 SizeType::MIN == nSizeType ? XML_SCALE_MIN : XML_SCALE );
3084
3085 }
3086 else if( nRelHeight > 0 )
3087 {
3088 ::sax::Converter::convertPercent( sValue, nRelHeight );
3089 if( SizeType::MIN == nSizeType )
3090 {
3091 assert(pMinHeightValue);
3092 if (pMinHeightValue)
3093 {
3094 *pMinHeightValue = sValue.makeStringAndClear();
3095 }
3096 }
3097 else
3098 GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT,
3099 sValue.makeStringAndClear() );
3100 }
3101
3102 OUString sZOrder( u"ZOrder"_ustr );
3103 if( xPropSetInfo->hasPropertyByName( sZOrder ) )
3104 {
3105 sal_Int32 nZIndex = 0;
3106 rPropSet->getPropertyValue( sZOrder ) >>= nZIndex;
3107 if( -1 != nZIndex )
3108 {
3109 GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_ZINDEX,
3110 OUString::number( nZIndex ) );
3111 }
3112 }
3113
3114 if (xPropSetInfo->hasPropertyByName(u"IsSplitAllowed"_ustr)
3115 && rPropSet->getPropertyValue(u"IsSplitAllowed"_ustr).get<bool>())
3116 {
3117 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_MAY_BREAK_BETWEEN_PAGES, XML_TRUE);
3118 }
3119
3120 return nShapeFeatures;
3121 }
3122
exportAnyTextFrame(const Reference<XTextContent> & rTxtCntnt,FrameType eType,bool bAutoStyles,bool bIsProgress,bool bExportContent,const Reference<XPropertySet> * pRangePropSet)3123 void XMLTextParagraphExport::exportAnyTextFrame(
3124 const Reference < XTextContent > & rTxtCntnt,
3125 FrameType eType,
3126 bool bAutoStyles,
3127 bool bIsProgress,
3128 bool bExportContent,
3129 const Reference < XPropertySet > *pRangePropSet)
3130 {
3131 Reference < XPropertySet > xPropSet( rTxtCntnt, UNO_QUERY );
3132
3133 if( bAutoStyles )
3134 {
3135 if( FrameType::Embedded == eType )
3136 _collectTextEmbeddedAutoStyles( xPropSet );
3137 // No text frame style for shapes (#i28745#)
3138 else if ( FrameType::Shape != eType )
3139 Add( XmlStyleFamily::TEXT_FRAME, xPropSet );
3140
3141 if( pRangePropSet && lcl_txtpara_isBoundAsChar( xPropSet,
3142 xPropSet->getPropertySetInfo() ) )
3143 Add( XmlStyleFamily::TEXT_TEXT, *pRangePropSet );
3144
3145 switch( eType )
3146 {
3147 case FrameType::Text:
3148 {
3149 // frame bound frames
3150 if ( bExportContent )
3151 {
3152 Reference < XTextFrame > xTxtFrame( rTxtCntnt, UNO_QUERY );
3153 bool bAlreadySeen = !maFrameRecurseGuard.insert(xTxtFrame).second;
3154 if (bAlreadySeen)
3155 {
3156 SAL_WARN("xmloff", "loop in frame export, ditching");
3157 }
3158 else
3159 {
3160 comphelper::ScopeGuard const g([this, xTxtFrame]() {
3161 maFrameRecurseGuard.erase(xTxtFrame);
3162 });
3163 Reference < XText > xTxt(xTxtFrame->getText());
3164 exportFrameFrames( true, bIsProgress, xTxtFrame );
3165 exportText( xTxt, bAutoStyles, bIsProgress, true );
3166 }
3167 }
3168 }
3169 break;
3170 case FrameType::Shape:
3171 {
3172 Reference < XShape > xShape( rTxtCntnt, UNO_QUERY );
3173 bool bAlreadySeen = !maShapeRecurseGuard.insert(xShape).second;
3174 if (bAlreadySeen)
3175 {
3176 SAL_WARN("xmloff", "loop in shape export, ditching");
3177 }
3178 else
3179 {
3180 comphelper::ScopeGuard const g([this, xShape]() {
3181 maShapeRecurseGuard.erase(xShape);
3182 });
3183 GetExport().GetShapeExport()->collectShapeAutoStyles( xShape );
3184 }
3185 }
3186 break;
3187 default:
3188 break;
3189 }
3190 }
3191 else
3192 {
3193 Reference< XPropertySetInfo > xPropSetInfo(xPropSet->getPropertySetInfo());
3194 {
3195 bool bAddCharStyles = pRangePropSet &&
3196 lcl_txtpara_isBoundAsChar( xPropSet, xPropSetInfo );
3197
3198 bool bIsUICharStyle;
3199 bool bHasAutoStyle = false;
3200
3201 OUString sStyle;
3202
3203 if( bAddCharStyles )
3204 sStyle = FindTextStyle( *pRangePropSet, bIsUICharStyle, bHasAutoStyle );
3205 else
3206 bIsUICharStyle = false;
3207
3208 bool bDoSomething = bIsUICharStyle
3209 && m_aCharStyleNamesPropInfoCache.hasProperty( *pRangePropSet );
3210 XMLTextCharStyleNamesElementExport aCharStylesExport(
3211 GetExport(), bDoSomething, bHasAutoStyle,
3212 bDoSomething ? *pRangePropSet : Reference<XPropertySet>(),
3213 gsCharStyleNames );
3214
3215 if( !sStyle.isEmpty() )
3216 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME,
3217 GetExport().EncodeStyleName( sStyle ) );
3218 {
3219 SvXMLElementExport aElem( GetExport(), !sStyle.isEmpty(),
3220 XML_NAMESPACE_TEXT, XML_SPAN, false, false );
3221 {
3222 SvXMLElementExport aElement( GetExport(),
3223 FrameType::Shape != eType &&
3224 HyperlinkData(xPropSet).addHyperlinkAttributes(GetExport()),
3225 XML_NAMESPACE_DRAW, XML_A, false, false );
3226 switch( eType )
3227 {
3228 case FrameType::Text:
3229 _exportTextFrame( xPropSet, xPropSetInfo, bIsProgress );
3230 break;
3231 case FrameType::Graphic:
3232 _exportTextGraphic( xPropSet, xPropSetInfo );
3233 break;
3234 case FrameType::Embedded:
3235 _exportTextEmbedded( xPropSet, xPropSetInfo );
3236 break;
3237 case FrameType::Shape:
3238 {
3239 Reference < XShape > xShape( rTxtCntnt, UNO_QUERY );
3240 XMLShapeExportFlags nFeatures =
3241 addTextFrameAttributes( xPropSet, true );
3242 GetExport().GetShapeExport()
3243 ->exportShape( xShape, nFeatures );
3244 }
3245 break;
3246 }
3247 }
3248 }
3249 }
3250 }
3251 }
3252
_exportTextFrame(const Reference<XPropertySet> & rPropSet,const Reference<XPropertySetInfo> & rPropSetInfo,bool bIsProgress)3253 void XMLTextParagraphExport::_exportTextFrame(
3254 const Reference < XPropertySet > & rPropSet,
3255 const Reference < XPropertySetInfo > & rPropSetInfo,
3256 bool bIsProgress )
3257 {
3258 Reference < XTextFrame > xTxtFrame( rPropSet, UNO_QUERY );
3259 Reference < XText > xTxt(xTxtFrame->getText());
3260
3261 OUString sStyle;
3262 if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
3263 {
3264 rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle;
3265 }
3266
3267 OUString aMinHeightValue;
3268 OUString sMinWidthValue;
3269 OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME, rPropSet, sStyle );
3270 if ( sAutoStyle.isEmpty() )
3271 sAutoStyle = sStyle;
3272 if( !sAutoStyle.isEmpty() )
3273 GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME,
3274 GetExport().EncodeStyleName( sAutoStyle ) );
3275 addTextFrameAttributes(rPropSet, false, nullptr, &aMinHeightValue, &sMinWidthValue);
3276
3277 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
3278 XML_FRAME, false, true );
3279
3280 if( !aMinHeightValue.isEmpty() )
3281 GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_HEIGHT,
3282 aMinHeightValue );
3283
3284 if (!sMinWidthValue.isEmpty())
3285 {
3286 GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_WIDTH,
3287 sMinWidthValue );
3288 }
3289
3290 // draw:chain-next-name
3291 if( rPropSetInfo->hasPropertyByName( gsChainNextName ) )
3292 {
3293 OUString sNext;
3294 if( (rPropSet->getPropertyValue( gsChainNextName ) >>= sNext) && !sNext.isEmpty() )
3295 GetExport().AddAttribute( XML_NAMESPACE_DRAW,
3296 XML_CHAIN_NEXT_NAME,
3297 sNext );
3298 }
3299
3300 {
3301 SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_DRAW,
3302 XML_TEXT_BOX, true, true );
3303
3304 // frames bound to frame
3305 exportFrameFrames( false, bIsProgress, xTxtFrame );
3306
3307 exportText( xTxt, false, bIsProgress, true );
3308 }
3309
3310 // script:events
3311 Reference<XEventsSupplier> xEventsSupp( xTxtFrame, UNO_QUERY );
3312 GetExport().GetEventExport().Export(xEventsSupp);
3313
3314 // image map
3315 GetExport().GetImageMapExport().Export( rPropSet );
3316
3317 // svg:title and svg:desc (#i73249#)
3318 exportTitleAndDescription( rPropSet, rPropSetInfo );
3319 }
3320
exportContour(const Reference<XPropertySet> & rPropSet,const Reference<XPropertySetInfo> & rPropSetInfo)3321 void XMLTextParagraphExport::exportContour(
3322 const Reference < XPropertySet > & rPropSet,
3323 const Reference < XPropertySetInfo > & rPropSetInfo )
3324 {
3325 if( !rPropSetInfo->hasPropertyByName( gsContourPolyPolygon ) )
3326 {
3327 return;
3328 }
3329
3330 PointSequenceSequence aSourcePolyPolygon;
3331 rPropSet->getPropertyValue( gsContourPolyPolygon ) >>= aSourcePolyPolygon;
3332 const basegfx::B2DPolyPolygon aPolyPolygon(
3333 basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
3334 aSourcePolyPolygon));
3335 const sal_uInt32 nPolygonCount(aPolyPolygon.count());
3336
3337 if(!nPolygonCount)
3338 {
3339 return;
3340 }
3341
3342 const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
3343 bool bPixel(false);
3344
3345 if( rPropSetInfo->hasPropertyByName( gsIsPixelContour ) )
3346 {
3347 bPixel = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsIsPixelContour ));
3348 }
3349
3350 // svg: width
3351 OUStringBuffer aStringBuffer( 10 );
3352
3353 if(bPixel)
3354 {
3355 ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth()));
3356 }
3357 else
3358 {
3359 GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth()));
3360 }
3361
3362 GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStringBuffer.makeStringAndClear());
3363
3364 // svg: height
3365 if(bPixel)
3366 {
3367 ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight()));
3368 }
3369 else
3370 {
3371 GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight()));
3372 }
3373
3374 GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStringBuffer.makeStringAndClear());
3375
3376 // svg:viewbox
3377 SdXMLImExViewBox aViewBox(0.0, 0.0, aPolyPolygonRange.getWidth(), aPolyPolygonRange.getHeight());
3378 GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
3379 enum XMLTokenEnum eElem = XML_TOKEN_INVALID;
3380
3381 if(1 == nPolygonCount )
3382 {
3383 // simple polygon shape, can be written as svg:points sequence
3384 const OUString aPointString(
3385 basegfx::utils::exportToSvgPoints(
3386 aPolyPolygon.getB2DPolygon(0)));
3387
3388 // write point array
3389 GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
3390 eElem = XML_CONTOUR_POLYGON;
3391 }
3392 else
3393 {
3394 // polypolygon, needs to be written as a svg:path sequence
3395 const OUString aPolygonString(
3396 basegfx::utils::exportToSvgD(
3397 aPolyPolygon,
3398 true, // bUseRelativeCoordinates
3399 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
3400 true)); // bHandleRelativeNextPointCompatible
3401
3402 // write point array
3403 GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_D, aPolygonString);
3404 eElem = XML_CONTOUR_PATH;
3405 }
3406
3407 if( rPropSetInfo->hasPropertyByName( gsIsAutomaticContour ) )
3408 {
3409 bool bTmp = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(
3410 gsIsAutomaticContour ));
3411 GetExport().AddAttribute( XML_NAMESPACE_DRAW,
3412 XML_RECREATE_ON_EDIT, bTmp ? XML_TRUE : XML_FALSE );
3413 }
3414
3415 // write object now
3416 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, eElem,
3417 true, true );
3418 }
3419
_exportTextGraphic(const Reference<XPropertySet> & rPropSet,const Reference<XPropertySetInfo> & rPropSetInfo)3420 void XMLTextParagraphExport::_exportTextGraphic(
3421 const Reference < XPropertySet > & rPropSet,
3422 const Reference < XPropertySetInfo > & rPropSetInfo )
3423 {
3424 // skip objects anchored at page in master documents,
3425 // if they are imported from the subdocuments
3426 TextContentAnchorType eAnchor;
3427 rPropSet->getPropertyValue(u"AnchorType"_ustr) >>= eAnchor;
3428 if( TextContentAnchorType_AT_PAGE == eAnchor )
3429 {
3430 Reference<XServiceInfo> xServiceInfo(GetExport().GetModel(), UNO_QUERY);
3431 if( xServiceInfo->supportsService(u"com.sun.star.text.GlobalDocument"_ustr) )
3432 {
3433 Reference<XNamed> xNamed( rPropSet, UNO_QUERY );
3434 if( xNamed.is() && xNamed->getName().indexOf(" (file://") > -1 )
3435 return;
3436 }
3437 }
3438
3439 OUString sStyle;
3440 if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) )
3441 {
3442 rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle;
3443 }
3444
3445 OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME, rPropSet, sStyle );
3446 if ( sAutoStyle.isEmpty() )
3447 sAutoStyle = sStyle;
3448 if( !sAutoStyle.isEmpty() )
3449 GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME,
3450 GetExport().EncodeStyleName( sAutoStyle ) );
3451
3452 // check if we need to use svg:transform
3453 sal_Int16 nRotation(0);
3454 rPropSet->getPropertyValue( gsGraphicRotation ) >>= nRotation;
3455 const bool bUseRotation(0 != nRotation);
3456 basegfx::B2DPoint aCenter(0.0, 0.0);
3457
3458 // add TextFrame attributes like svg:x/y/width/height, also get back
3459 // object's center point if rotation is used and has to be exported
3460 addTextFrameAttributes(rPropSet, false, bUseRotation ? &aCenter : nullptr);
3461
3462 // svg:transform
3463 if(bUseRotation)
3464 {
3465 // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling.
3466 // Currently only rotation is used, but combinations with 'draw:transform'
3467 // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height
3468 // may be extended/replaced with 'draw:transform' (see draw objects)
3469 SdXMLImExTransform2D aSdXMLImExTransform2D;
3470
3471 // Convert from 10th degree integer to deg.
3472 // CAUTION: internal rotation is classically mathematically 'wrong' defined by ignoring that
3473 // we have a right-handed coordinate system, so need to correct this by mirroring
3474 // the rotation to get the correct transformation. See also case XML_TOK_TEXT_FRAME_TRANSFORM
3475 // in XMLTextFrameContext_Impl::XMLTextFrameContext_Impl and #i78696#
3476 // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed write it with the wrong
3477 // orientation as in all other cases - ARGH! We will need to correct this in future ODF ASAP!
3478 const double fRotate(basegfx::deg2rad<10>(nRotation));
3479
3480 // transform to rotation center which is the object's center
3481 aSdXMLImExTransform2D.AddTranslate(-aCenter);
3482
3483 // add rotation itself
3484 // tdf#115529 but correct value modulo 2PI to have it positive and in the range of [0.0 .. 2PI[
3485 aSdXMLImExTransform2D.AddRotate(basegfx::normalizeToRange(fRotate, 2 * M_PI));
3486
3487 // back-transform after rotation
3488 aSdXMLImExTransform2D.AddTranslate(aCenter);
3489
3490 // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed,
3491 // but is not generally available (as it should be, a 'current' UnitConverter should
3492 // be available at GetExport() - and maybe was once). May have to be addressed as soon
3493 // as translate transformations are used here.
3494 GetExport().AddAttribute(
3495 XML_NAMESPACE_DRAW,
3496 XML_TRANSFORM,
3497 aSdXMLImExTransform2D.GetExportString(GetExport().GetMM100UnitConverter()));
3498 }
3499
3500 // original content
3501 SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_DRAW, XML_FRAME, false, true);
3502
3503 {
3504 // xlink:href
3505 uno::Reference<graphic::XGraphic> xGraphic;
3506 rPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
3507
3508 OUString sInternalURL;
3509 OUString sOutMimeType;
3510
3511 if (xGraphic.is())
3512 {
3513 sInternalURL = GetExport().AddEmbeddedXGraphic(xGraphic, sOutMimeType);
3514 }
3515
3516 // If there still is no url, then graphic is empty
3517 if (!sInternalURL.isEmpty())
3518 {
3519 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
3520 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3521 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3522 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3523 }
3524
3525 // draw:filter-name
3526 OUString sGrfFilter;
3527 rPropSet->getPropertyValue( gsGraphicFilter ) >>= sGrfFilter;
3528 if( !sGrfFilter.isEmpty() )
3529 GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_FILTER_NAME,
3530 sGrfFilter );
3531
3532 if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
3533 {
3534 if (sOutMimeType.isEmpty())
3535 {
3536 GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
3537 }
3538 if (!sOutMimeType.isEmpty())
3539 { // ODF 1.3 OFFICE-3943
3540 GetExport().AddAttribute(
3541 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
3542 ? XML_NAMESPACE_DRAW
3543 : XML_NAMESPACE_LO_EXT,
3544 u"mime-type"_ustr, sOutMimeType);
3545 }
3546 }
3547
3548
3549 // optional office:binary-data
3550 if (xGraphic.is())
3551 {
3552 SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
3553 GetExport().AddEmbeddedXGraphicAsBase64(xGraphic);
3554 }
3555 }
3556
3557 const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get();
3558 if (bAddReplacementImages)
3559 {
3560 // replacement graphic for backwards compatibility, but
3561 // only for SVG and metafiles currently
3562 uno::Reference<graphic::XGraphic> xReplacementGraphic;
3563 rPropSet->getPropertyValue(u"ReplacementGraphic"_ustr) >>= xReplacementGraphic;
3564
3565 OUString sInternalURL;
3566 OUString sOutMimeType;
3567
3568 //Resolves: fdo#62461 put preferred image first above, followed by
3569 //fallback here
3570 if (xReplacementGraphic.is())
3571 {
3572 sInternalURL = GetExport().AddEmbeddedXGraphic(xReplacementGraphic, sOutMimeType);
3573 }
3574
3575 // If there is no url, then graphic is empty
3576 if (!sInternalURL.isEmpty())
3577 {
3578 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
3579 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3580 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3581 GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3582 }
3583
3584 if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
3585 {
3586 if (sOutMimeType.isEmpty())
3587 {
3588 GetExport().GetGraphicMimeTypeFromStream(xReplacementGraphic, sOutMimeType);
3589 }
3590 if (!sOutMimeType.isEmpty())
3591 { // ODF 1.3 OFFICE-3943
3592 GetExport().AddAttribute(
3593 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
3594 ? XML_NAMESPACE_DRAW
3595 : XML_NAMESPACE_LO_EXT,
3596 u"mime-type"_ustr, sOutMimeType);
3597 }
3598 }
3599
3600
3601 // optional office:binary-data
3602 if (xReplacementGraphic.is())
3603 {
3604 SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
3605 GetExport().AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
3606 }
3607 }
3608
3609 // script:events
3610 Reference<XEventsSupplier> xEventsSupp( rPropSet, UNO_QUERY );
3611 GetExport().GetEventExport().Export(xEventsSupp);
3612
3613 // image map
3614 GetExport().GetImageMapExport().Export( rPropSet );
3615
3616 // svg:title and svg:desc (#i73249#)
3617 exportTitleAndDescription( rPropSet, rPropSetInfo );
3618
3619 // draw:contour
3620 exportContour( rPropSet, rPropSetInfo );
3621 }
3622
_collectTextEmbeddedAutoStyles(const Reference<XPropertySet> &)3623 void XMLTextParagraphExport::_collectTextEmbeddedAutoStyles(const Reference < XPropertySet > & )
3624 {
3625 SAL_WARN( "xmloff", "no API implementation available" );
3626 }
3627
_exportTextEmbedded(const Reference<XPropertySet> &,const Reference<XPropertySetInfo> &)3628 void XMLTextParagraphExport::_exportTextEmbedded(
3629 const Reference < XPropertySet > &,
3630 const Reference < XPropertySetInfo > & )
3631 {
3632 SAL_WARN( "xmloff", "no API implementation available" );
3633 }
3634
exportEvents(const Reference<XPropertySet> & rPropSet)3635 void XMLTextParagraphExport::exportEvents( const Reference < XPropertySet > & rPropSet )
3636 {
3637 // script:events
3638 Reference<XEventsSupplier> xEventsSupp( rPropSet, UNO_QUERY );
3639 GetExport().GetEventExport().Export(xEventsSupp);
3640
3641 // image map
3642 if (rPropSet->getPropertySetInfo()->hasPropertyByName(u"ImageMap"_ustr))
3643 GetExport().GetImageMapExport().Export( rPropSet );
3644 }
3645
3646 // Implement Title/Description Elements UI (#i73249#)
exportTitleAndDescription(const Reference<XPropertySet> & rPropSet,const Reference<XPropertySetInfo> & rPropSetInfo)3647 void XMLTextParagraphExport::exportTitleAndDescription(
3648 const Reference < XPropertySet > & rPropSet,
3649 const Reference < XPropertySetInfo > & rPropSetInfo )
3650 {
3651 // svg:title
3652 if( rPropSetInfo->hasPropertyByName( gsTitle ) )
3653 {
3654 OUString sObjTitle;
3655 rPropSet->getPropertyValue( gsTitle ) >>= sObjTitle;
3656 if( !sObjTitle.isEmpty() )
3657 {
3658 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG,
3659 XML_TITLE, true, false );
3660 GetExport().Characters( sObjTitle );
3661 }
3662 }
3663
3664 // svg:description
3665 if( rPropSetInfo->hasPropertyByName( gsDescription ) )
3666 {
3667 OUString sObjDesc;
3668 rPropSet->getPropertyValue( gsDescription ) >>= sObjDesc;
3669 if( !sObjDesc.isEmpty() )
3670 {
3671 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG,
3672 XML_DESC, true, false );
3673 GetExport().Characters( sObjDesc );
3674 }
3675 }
3676 }
3677
exportTextRangeSpan(const css::uno::Reference<css::text::XTextRange> & rTextRange,Reference<XPropertySet> const & xPropSet,Reference<XPropertySetInfo> & xPropSetInfo,const bool bIsUICharStyle,const bool bHasAutoStyle,const OUString & sStyle,bool & rPrevCharIsSpace,FieldmarkType & openFieldMark)3678 void XMLTextParagraphExport::exportTextRangeSpan(
3679 const css::uno::Reference< css::text::XTextRange > & rTextRange,
3680 Reference< XPropertySet > const & xPropSet,
3681 Reference < XPropertySetInfo > & xPropSetInfo,
3682 const bool bIsUICharStyle,
3683 const bool bHasAutoStyle,
3684 const OUString& sStyle,
3685 bool& rPrevCharIsSpace,
3686 FieldmarkType& openFieldMark )
3687 {
3688 XMLTextCharStyleNamesElementExport aCharStylesExport(
3689 GetExport(),
3690 bIsUICharStyle && m_aCharStyleNamesPropInfoCache.hasProperty( xPropSet, xPropSetInfo ),
3691 bHasAutoStyle,
3692 xPropSet,
3693 gsCharStyleNames );
3694
3695 if ( !sStyle.isEmpty() )
3696 {
3697 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, GetExport().EncodeStyleName( sStyle ) );
3698 }
3699 {
3700 SvXMLElementExport aElement( GetExport(), !sStyle.isEmpty(), XML_NAMESPACE_TEXT, XML_SPAN, false, false );
3701 const OUString aText( rTextRange->getString() );
3702 SvXMLElementExport aElem2( GetExport(), TEXT == openFieldMark,
3703 XML_NAMESPACE_TEXT, XML_TEXT_INPUT,
3704 false, false );
3705 exportCharacterData(aText, rPrevCharIsSpace);
3706 openFieldMark = NONE;
3707 }
3708 }
3709
exportTextRange(const Reference<XTextRange> & rTextRange,bool bAutoStyles,bool & rPrevCharIsSpace,FieldmarkType & openFieldMark)3710 void XMLTextParagraphExport::exportTextRange(
3711 const Reference< XTextRange > & rTextRange,
3712 bool bAutoStyles,
3713 bool& rPrevCharIsSpace,
3714 FieldmarkType& openFieldMark )
3715 {
3716 Reference< XPropertySet > xPropSet( rTextRange, UNO_QUERY );
3717 if ( bAutoStyles )
3718 {
3719 Add( XmlStyleFamily::TEXT_TEXT, xPropSet );
3720 }
3721 else
3722 {
3723 bool bIsUICharStyle = false;
3724 bool bHasAutoStyle = false;
3725 const OUString sStyle(
3726 FindTextStyle( xPropSet, bIsUICharStyle, bHasAutoStyle ) );
3727
3728 Reference < XPropertySetInfo > xPropSetInfo;
3729 exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark );
3730 }
3731 }
3732
exportCharacterData(const OUString & rText,bool & rPrevCharIsSpace)3733 void XMLTextParagraphExport::exportCharacterData(const OUString& rText,
3734 bool& rPrevCharIsSpace )
3735 {
3736 sal_Int32 nExpStartPos = 0;
3737 sal_Int32 nEndPos = rText.getLength();
3738 sal_Int32 nSpaceChars = 0;
3739 for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ )
3740 {
3741 sal_Unicode cChar = rText[nPos];
3742 bool bExpCharAsText = true;
3743 bool bExpCharAsElement = false;
3744 bool bCurrCharIsSpace = false;
3745 switch( cChar )
3746 {
3747 case 0x0009: // Tab
3748 case 0x000A: // LF
3749 // These characters are exported as text.
3750 bExpCharAsElement = true;
3751 bExpCharAsText = false;
3752 break;
3753 case 0x000D:
3754 break; // legal character
3755 case 0x0020: // Blank
3756 if( rPrevCharIsSpace )
3757 {
3758 // If the previous character is a space character,
3759 // too, export a special space element.
3760 bExpCharAsText = false;
3761 }
3762 bCurrCharIsSpace = true;
3763 break;
3764 default:
3765 if( cChar < 0x0020 )
3766 {
3767 #ifdef DBG_UTIL
3768 OSL_ENSURE( txtparae_bContainsIllegalCharacters ||
3769 cChar >= 0x0020,
3770 "illegal character in text content" );
3771 txtparae_bContainsIllegalCharacters = true;
3772 #endif
3773 bExpCharAsText = false;
3774 }
3775 break;
3776 }
3777
3778 // If the current character is not exported as text
3779 // the text that has not been exported by now has to be exported now.
3780 if( nPos > nExpStartPos && !bExpCharAsText )
3781 {
3782 SAL_WARN_IF( 0 != nSpaceChars, "xmloff", "pending spaces" );
3783 OUString sExp( rText.copy( nExpStartPos, nPos - nExpStartPos ) );
3784 GetExport().Characters( sExp );
3785 nExpStartPos = nPos;
3786 }
3787
3788 // If there are spaces left that have not been exported and the
3789 // current character is not a space , the pending spaces have to be
3790 // exported now.
3791 if( nSpaceChars > 0 && !bCurrCharIsSpace )
3792 {
3793 SAL_WARN_IF( nExpStartPos != nPos, "xmloff", " pending characters" );
3794
3795 if( nSpaceChars > 1 )
3796 {
3797 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C,
3798 OUString::number(nSpaceChars) );
3799 }
3800
3801 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
3802 XML_S, false, false );
3803
3804 nSpaceChars = 0;
3805 }
3806
3807 // If the current character has to be exported as a special
3808 // element, the element will be exported now.
3809 if( bExpCharAsElement )
3810 {
3811 switch( cChar )
3812 {
3813 case 0x0009: // Tab
3814 {
3815 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
3816 XML_TAB, false,
3817 false );
3818 }
3819 break;
3820 case 0x000A: // LF
3821 {
3822 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT,
3823 XML_LINE_BREAK, false,
3824 false );
3825 }
3826 break;
3827 }
3828 }
3829
3830 // If the current character is a space, and the previous one
3831 // is a space, too, the number of pending spaces is incremented
3832 // only.
3833 if( bCurrCharIsSpace && rPrevCharIsSpace )
3834 nSpaceChars++;
3835 rPrevCharIsSpace = bCurrCharIsSpace;
3836
3837 // If the current character is not exported as text, the start
3838 // position for text is the position behind the current position.
3839 if( !bExpCharAsText )
3840 {
3841 SAL_WARN_IF( nExpStartPos != nPos, "xmloff", "wrong export start pos" );
3842 nExpStartPos = nPos+1;
3843 }
3844 }
3845
3846 if( nExpStartPos < nEndPos )
3847 {
3848 SAL_WARN_IF( 0 != nSpaceChars, "xmloff", " pending spaces " );
3849 OUString sExp( rText.copy( nExpStartPos, nEndPos - nExpStartPos ) );
3850 GetExport().Characters( sExp );
3851 }
3852
3853 // If there are some spaces left, they have to be exported now.
3854 if( nSpaceChars > 0 )
3855 {
3856 if( nSpaceChars > 1 )
3857 {
3858 GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C,
3859 OUString::number(nSpaceChars) );
3860 }
3861
3862 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_S,
3863 false, false );
3864 }
3865 }
3866
exportTextDeclarations()3867 void XMLTextParagraphExport::exportTextDeclarations()
3868 {
3869 m_pFieldExport->ExportFieldDeclarations();
3870
3871 // get XPropertySet from the document and ask for AutoMarkFileURL.
3872 // If it exists, export the auto-mark-file element.
3873 Reference<XPropertySet> xPropertySet( GetExport().GetModel(), UNO_QUERY );
3874 if (!xPropertySet.is())
3875 return;
3876
3877 OUString sUrl;
3878 OUString sIndexAutoMarkFileURL(
3879 u"IndexAutoMarkFileURL"_ustr);
3880 if (!xPropertySet->getPropertySetInfo()->hasPropertyByName(
3881 sIndexAutoMarkFileURL))
3882 return;
3883
3884 xPropertySet->getPropertyValue(sIndexAutoMarkFileURL) >>= sUrl;
3885 if (!sUrl.isEmpty())
3886 {
3887 GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF,
3888 GetExport().GetRelativeReference(sUrl) );
3889 SvXMLElementExport aAutoMarkElement(
3890 GetExport(), XML_NAMESPACE_TEXT,
3891 XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE,
3892 true, true );
3893 }
3894 }
3895
exportTextDeclarations(const Reference<XText> & rText)3896 void XMLTextParagraphExport::exportTextDeclarations(
3897 const Reference<XText> & rText )
3898 {
3899 m_pFieldExport->ExportFieldDeclarations(rText);
3900 }
3901
exportUsedDeclarations()3902 void XMLTextParagraphExport::exportUsedDeclarations()
3903 {
3904 m_pFieldExport->SetExportOnlyUsedFieldDeclarations( false/*bOnlyUsed*/ );
3905 }
3906
exportTrackedChanges(bool bAutoStyles)3907 void XMLTextParagraphExport::exportTrackedChanges(bool bAutoStyles)
3908 {
3909 if (nullptr != m_pRedlineExport)
3910 m_pRedlineExport->ExportChangesList( bAutoStyles );
3911 }
3912
exportTrackedChanges(const Reference<XText> & rText,bool bAutoStyle)3913 void XMLTextParagraphExport::exportTrackedChanges(
3914 const Reference<XText> & rText,
3915 bool bAutoStyle)
3916 {
3917 if (nullptr != m_pRedlineExport)
3918 m_pRedlineExport->ExportChangesList(rText, bAutoStyle);
3919 }
3920
recordTrackedChangesForXText(const Reference<XText> & rText)3921 void XMLTextParagraphExport::recordTrackedChangesForXText(
3922 const Reference<XText> & rText )
3923 {
3924 if (nullptr != m_pRedlineExport)
3925 m_pRedlineExport->SetCurrentXText(rText);
3926 }
3927
recordTrackedChangesNoXText()3928 void XMLTextParagraphExport::recordTrackedChangesNoXText()
3929 {
3930 if (nullptr != m_pRedlineExport)
3931 m_pRedlineExport->SetCurrentXText();
3932 }
3933
exportTableAutoStyles()3934 void XMLTextParagraphExport::exportTableAutoStyles() {}
3935
exportTextAutoStyles()3936 void XMLTextParagraphExport::exportTextAutoStyles()
3937 {
3938 // tdf#135942: do not collect styles during their export: this may modify iterated containers
3939 mbCollected = true;
3940 exportTableAutoStyles();
3941
3942 GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_PARAGRAPH );
3943
3944 GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_TEXT );
3945
3946 GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_FRAME );
3947
3948 GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_SECTION );
3949
3950 GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_RUBY );
3951
3952 maListAutoPool.exportXML();
3953 }
3954
exportRuby(const Reference<XPropertySet> & rPropSet,bool bAutoStyles)3955 void XMLTextParagraphExport::exportRuby(
3956 const Reference<XPropertySet> & rPropSet,
3957 bool bAutoStyles )
3958 {
3959 // early out: a collapsed ruby makes no sense
3960 if (*o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsCollapsed)))
3961 return;
3962
3963 // start value ?
3964 bool bStart = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsIsStart));
3965
3966 if (bAutoStyles)
3967 {
3968 // ruby auto styles
3969 if (bStart)
3970 Add( XmlStyleFamily::TEXT_RUBY, rPropSet );
3971 }
3972 else
3973 {
3974 if (bStart)
3975 {
3976 // ruby start
3977
3978 // we can only start a ruby if none is open
3979 assert(!m_bOpenRuby && "Can't open a ruby inside of ruby!");
3980 if( m_bOpenRuby )
3981 return;
3982
3983 // save ruby text + ruby char style
3984 rPropSet->getPropertyValue(gsRubyText) >>= m_sOpenRubyText;
3985 rPropSet->getPropertyValue(gsRubyCharStyleName) >>= m_sOpenRubyCharStyle;
3986
3987 // ruby style
3988 GetExport().CheckAttrList();
3989 OUString sStyleName(Find(XmlStyleFamily::TEXT_RUBY, rPropSet, u""_ustr));
3990 SAL_WARN_IF(sStyleName.isEmpty(), "xmloff", "Can't find ruby style!");
3991 GetExport().AddAttribute(XML_NAMESPACE_TEXT,
3992 XML_STYLE_NAME, sStyleName);
3993
3994 // export <text:ruby> and <text:ruby-base> start elements
3995 GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY, false);
3996 GetExport().ClearAttrList();
3997 GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY_BASE,
3998 false );
3999 m_bOpenRuby = true;
4000 }
4001 else
4002 {
4003 // ruby end
4004
4005 // check for an open ruby
4006 assert(m_bOpenRuby && "Can't close a ruby if none is open!");
4007 if( !m_bOpenRuby )
4008 return;
4009
4010 // close <text:ruby-base>
4011 GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY_BASE,
4012 false);
4013
4014 // write the ruby text (with char style)
4015 {
4016 if (!m_sOpenRubyCharStyle.isEmpty())
4017 GetExport().AddAttribute(
4018 XML_NAMESPACE_TEXT, XML_STYLE_NAME,
4019 GetExport().EncodeStyleName( m_sOpenRubyCharStyle) );
4020
4021 SvXMLElementExport aRubyElement(
4022 GetExport(), XML_NAMESPACE_TEXT, XML_RUBY_TEXT,
4023 false, false);
4024
4025 GetExport().Characters(m_sOpenRubyText);
4026 }
4027
4028 // and finally, close the ruby
4029 GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY, false);
4030 m_bOpenRuby = false;
4031 }
4032 }
4033 }
4034
exportMeta(const Reference<XPropertySet> & i_xPortion,bool i_bAutoStyles,bool i_isProgress,bool & rPrevCharIsSpace)4035 void XMLTextParagraphExport::exportMeta(
4036 const Reference<XPropertySet> & i_xPortion,
4037 bool i_bAutoStyles, bool i_isProgress, bool & rPrevCharIsSpace)
4038 {
4039 bool doExport(!i_bAutoStyles); // do not export element if autostyles
4040 // check version >= 1.2
4041 switch (GetExport().getSaneDefaultVersion()) {
4042 case SvtSaveOptions::ODFSVER_011: // fall through
4043 case SvtSaveOptions::ODFSVER_010: doExport = false; break;
4044 default: break;
4045 }
4046
4047 const Reference< XTextContent > xTextContent(
4048 i_xPortion->getPropertyValue(u"InContentMetadata"_ustr), UNO_QUERY_THROW);
4049 const Reference< XEnumerationAccess > xEA( xTextContent, UNO_QUERY_THROW );
4050 const Reference< XEnumeration > xTextEnum( xEA->createEnumeration() );
4051
4052 if (doExport)
4053 {
4054 const Reference<rdf::XMetadatable> xMeta(xTextContent, UNO_QUERY_THROW);
4055
4056 // text:meta with neither xml:id nor RDFa is invalid
4057 xMeta->ensureMetadataReference();
4058
4059 // xml:id and RDFa for RDF metadata
4060 GetExport().AddAttributeXmlId(xMeta);
4061 GetExport().AddAttributesRDFa(xTextContent);
4062 }
4063
4064 SvXMLElementExport aElem( GetExport(), doExport,
4065 XML_NAMESPACE_TEXT, XML_META, false, false );
4066
4067 // recurse to export content
4068 exportTextRangeEnumeration(xTextEnum, i_bAutoStyles, i_isProgress, rPrevCharIsSpace);
4069 }
4070
ExportContentControl(const uno::Reference<beans::XPropertySet> & xPortion,bool bAutoStyles,bool isProgress,bool & rPrevCharIsSpace)4071 void XMLTextParagraphExport::ExportContentControl(
4072 const uno::Reference<beans::XPropertySet>& xPortion, bool bAutoStyles, bool isProgress,
4073 bool& rPrevCharIsSpace)
4074 {
4075 // Do not export the element in the autostyle case.
4076 bool bExport = !bAutoStyles;
4077 if (!(GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
4078 {
4079 bExport = false;
4080 }
4081
4082 uno::Reference<text::XTextContent> xTextContent(xPortion->getPropertyValue(u"ContentControl"_ustr),
4083 uno::UNO_QUERY_THROW);
4084 uno::Reference<container::XEnumerationAccess> xEA(xTextContent, uno::UNO_QUERY_THROW);
4085 uno::Reference<container::XEnumeration> xTextEnum = xEA->createEnumeration();
4086
4087 uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY_THROW);
4088 if (bExport)
4089 {
4090 bool bShowingPlaceHolder = false;
4091 xPropertySet->getPropertyValue(u"ShowingPlaceHolder"_ustr) >>= bShowingPlaceHolder;
4092 if (bShowingPlaceHolder)
4093 {
4094 OUStringBuffer aBuffer;
4095 sax::Converter::convertBool(aBuffer, bShowingPlaceHolder);
4096 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOWING_PLACE_HOLDER,
4097 aBuffer.makeStringAndClear());
4098 }
4099
4100 bool bCheckbox = false;
4101 xPropertySet->getPropertyValue(u"Checkbox"_ustr) >>= bCheckbox;
4102 if (bCheckbox)
4103 {
4104 OUStringBuffer aBuffer;
4105 sax::Converter::convertBool(aBuffer, bCheckbox);
4106 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKBOX, aBuffer.makeStringAndClear());
4107 }
4108
4109 bool bChecked = false;
4110 xPropertySet->getPropertyValue(u"Checked"_ustr) >>= bChecked;
4111 if (bChecked)
4112 {
4113 OUStringBuffer aBuffer;
4114 sax::Converter::convertBool(aBuffer, bChecked);
4115 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED, aBuffer.makeStringAndClear());
4116 }
4117
4118 OUString aCheckedState;
4119 xPropertySet->getPropertyValue(u"CheckedState"_ustr) >>= aCheckedState;
4120 if (!aCheckedState.isEmpty())
4121 {
4122 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED_STATE, aCheckedState);
4123 }
4124
4125 OUString aUncheckedState;
4126 xPropertySet->getPropertyValue(u"UncheckedState"_ustr) >>= aUncheckedState;
4127 if (!aUncheckedState.isEmpty())
4128 {
4129 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_UNCHECKED_STATE, aUncheckedState);
4130 }
4131
4132 bool bPicture = false;
4133 xPropertySet->getPropertyValue(u"Picture"_ustr) >>= bPicture;
4134 if (bPicture)
4135 {
4136 OUStringBuffer aBuffer;
4137 sax::Converter::convertBool(aBuffer, bPicture);
4138 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PICTURE,
4139 aBuffer.makeStringAndClear());
4140 }
4141
4142 bool bDate = false;
4143 xPropertySet->getPropertyValue(u"Date"_ustr) >>= bDate;
4144 if (bDate)
4145 {
4146 OUStringBuffer aBuffer;
4147 sax::Converter::convertBool(aBuffer, bDate);
4148 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE, aBuffer.makeStringAndClear());
4149 }
4150
4151 OUString aDateFormat;
4152 xPropertySet->getPropertyValue(u"DateFormat"_ustr) >>= aDateFormat;
4153 if (!aDateFormat.isEmpty())
4154 {
4155 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_FORMAT, aDateFormat);
4156 }
4157
4158 OUString aDateLanguage;
4159 xPropertySet->getPropertyValue(u"DateLanguage"_ustr) >>= aDateLanguage;
4160 if (!aDateLanguage.isEmpty())
4161 {
4162 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_RFC_LANGUAGE_TAG, aDateLanguage);
4163 }
4164 OUString aCurrentDate;
4165 xPropertySet->getPropertyValue(u"CurrentDate"_ustr) >>= aCurrentDate;
4166 if (!aCurrentDate.isEmpty())
4167 {
4168 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CURRENT_DATE, aCurrentDate);
4169 }
4170
4171 bool bPlainText = false;
4172 xPropertySet->getPropertyValue(u"PlainText"_ustr) >>= bPlainText;
4173 if (bPlainText)
4174 {
4175 OUStringBuffer aBuffer;
4176 sax::Converter::convertBool(aBuffer, bPlainText);
4177 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PLAIN_TEXT, aBuffer.makeStringAndClear());
4178 }
4179
4180 bool bComboBox = false;
4181 xPropertySet->getPropertyValue(u"ComboBox"_ustr) >>= bComboBox;
4182 if (bComboBox)
4183 {
4184 OUStringBuffer aBuffer;
4185 sax::Converter::convertBool(aBuffer, bComboBox);
4186 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_COMBOBOX, aBuffer.makeStringAndClear());
4187 }
4188
4189 bool bDropDown = false;
4190 xPropertySet->getPropertyValue(u"DropDown"_ustr) >>= bDropDown;
4191 if (bDropDown)
4192 {
4193 OUStringBuffer aBuffer;
4194 sax::Converter::convertBool(aBuffer, bDropDown);
4195 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DROPDOWN, aBuffer.makeStringAndClear());
4196 }
4197
4198 OUString aAlias;
4199 xPropertySet->getPropertyValue(u"Alias"_ustr) >>= aAlias;
4200 if (!aAlias.isEmpty())
4201 {
4202 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_ALIAS, aAlias);
4203 }
4204
4205 OUString aTag;
4206 xPropertySet->getPropertyValue(u"Tag"_ustr) >>= aTag;
4207 if (!aTag.isEmpty())
4208 {
4209 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAG, aTag);
4210 }
4211
4212 sal_Int32 nId = 0;
4213 xPropertySet->getPropertyValue(u"Id"_ustr) >>= nId;
4214 if (nId)
4215 {
4216 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, OUString::number(nId));
4217 }
4218
4219 sal_uInt32 nTabIndex = 0;
4220 if ((xPropertySet->getPropertyValue(u"TabIndex"_ustr) >>= nTabIndex) && nTabIndex)
4221 {
4222 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAB_INDEX,
4223 OUString::number(nTabIndex));
4224 }
4225
4226 OUString aLock;
4227 xPropertySet->getPropertyValue(u"Lock"_ustr) >>= aLock;
4228 if (!aLock.isEmpty())
4229 {
4230 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_LOCK, aLock);
4231 }
4232 }
4233
4234 SvXMLElementExport aElem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_CONTENT_CONTROL, false,
4235 false);
4236
4237 if (bExport)
4238 {
4239 // Export list items of dropdowns.
4240 uno::Sequence<beans::PropertyValues> aListItems;
4241 xPropertySet->getPropertyValue(u"ListItems"_ustr) >>= aListItems;
4242 for (const auto& rListItem : aListItems)
4243 {
4244 comphelper::SequenceAsHashMap aMap(rListItem);
4245 auto it = aMap.find(u"DisplayText"_ustr);
4246 OUString aValue;
4247 if (it != aMap.end() && (it->second >>= aValue) && !aValue.isEmpty())
4248 {
4249 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DISPLAY_TEXT, aValue);
4250 }
4251
4252 it = aMap.find(u"Value"_ustr);
4253 if (it != aMap.end() && (it->second >>= aValue))
4254 {
4255 GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_VALUE, aValue);
4256 }
4257
4258 SvXMLElementExport aItem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_LIST_ITEM, false,
4259 false);
4260 }
4261 }
4262
4263 // Recurse to export content.
4264 exportTextRangeEnumeration(xTextEnum, bAutoStyles, isProgress, rPrevCharIsSpace);
4265 }
4266
PreventExportOfControlsInMuteSections(const Reference<XIndexAccess> & rShapes,const rtl::Reference<xmloff::OFormLayerXMLExport> & xFormExport)4267 void XMLTextParagraphExport::PreventExportOfControlsInMuteSections(
4268 const Reference<XIndexAccess> & rShapes,
4269 const rtl::Reference<xmloff::OFormLayerXMLExport>& xFormExport )
4270 {
4271 // check parameters ad pre-conditions
4272 if( ( ! rShapes.is() ) || ( ! xFormExport.is() ) )
4273 {
4274 // if we don't have shapes or a form export, there's nothing to do
4275 return;
4276 }
4277 SAL_WARN_IF( m_pSectionExport == nullptr, "xmloff", "We need the section export." );
4278
4279 Reference<XEnumeration> xShapesEnum = m_pBoundFrameSets->GetShapes()->createEnumeration();
4280 if(!xShapesEnum.is())
4281 return;
4282 while( xShapesEnum->hasMoreElements() )
4283 {
4284 // now we need to check
4285 // 1) if this is a control shape, and
4286 // 2) if it's in a mute section
4287 // if both answers are 'yes', notify the form layer export
4288
4289 // we join accessing the shape and testing for control
4290 Reference<XControlShape> xControlShape(xShapesEnum->nextElement(), UNO_QUERY);
4291 if( xControlShape.is() )
4292 {
4293 // Reference<XPropertySet> xPropSet( xControlShape, UNO_QUERY );
4294 // Reference<XTextContent> xTextContent;
4295 // xPropSet->getPropertyValue("TextRange") >>= xTextContent;
4296
4297 Reference<XTextContent> xTextContent( xControlShape, UNO_QUERY );
4298 if( xTextContent.is() )
4299 {
4300 if( m_pSectionExport->IsMuteSection( xTextContent, false ) )
4301 {
4302 // Ah, we've found a shape that
4303 // 1) is a control shape
4304 // 2) is anchored in a mute section
4305 // so: don't export it!
4306 xFormExport->excludeFromExport(
4307 xControlShape->getControl() );
4308 }
4309 // else: not in mute section -> should be exported -> nothing
4310 // to do
4311 }
4312 // else: no anchor -> ignore
4313 }
4314 // else: no control shape -> nothing to do
4315 }
4316 }
4317
PushNewTextListsHelper()4318 void XMLTextParagraphExport::PushNewTextListsHelper()
4319 {
4320 maTextListsHelperStack.emplace_back( new XMLTextListsHelper() );
4321 mpTextListsHelper = maTextListsHelperStack.back().get();
4322 }
4323
PopTextListsHelper()4324 void XMLTextParagraphExport::PopTextListsHelper()
4325 {
4326 mpTextListsHelper = nullptr;
4327 maTextListsHelperStack.pop_back();
4328 if ( !maTextListsHelperStack.empty() )
4329 {
4330 mpTextListsHelper = maTextListsHelperStack.back().get();
4331 }
4332 }
4333
4334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4335