tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / filter / xml / xmlexprt.cxx
blobe41e3ece60c49e9db9707521f9842eb49c4a903d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include "xmlexprt.hxx"
24 #include "XMLConverter.hxx"
25 #include "xmlstyle.hxx"
26 #include <unonames.hxx>
27 #include <document.hxx>
28 #include <olinetab.hxx>
29 #include <formulacell.hxx>
30 #include <rangenam.hxx>
31 #include "XMLTableMasterPageExport.hxx"
32 #include <drwlayer.hxx>
33 #include "XMLExportDataPilot.hxx"
34 #include "XMLExportDatabaseRanges.hxx"
35 #include "XMLExportDDELinks.hxx"
36 #include "XMLColumnRowGroupExport.hxx"
37 #include "XMLStylesExportHelper.hxx"
38 #include "XMLChangeTrackingExportHelper.hxx"
39 #include <sheetdata.hxx>
40 #include <docoptio.hxx>
41 #include "XMLExportSharedData.hxx"
42 #include <chgviset.hxx>
43 #include <docuno.hxx>
44 #include <textuno.hxx>
45 #include <chartlis.hxx>
46 #include <scitems.hxx>
47 #include <docpool.hxx>
48 #include <userdat.hxx>
49 #include <chgtrack.hxx>
50 #include <rangeutl.hxx>
51 #include <postit.hxx>
52 #include <externalrefmgr.hxx>
53 #include <editutil.hxx>
54 #include <tabprotection.hxx>
55 #include "cachedattraccess.hxx"
56 #include <colorscale.hxx>
57 #include <conditio.hxx>
58 #include <cellvalue.hxx>
59 #include <stylehelper.hxx>
60 #include <edittextiterator.hxx>
61 #include "editattributemap.hxx"
62 #include <arealink.hxx>
63 #include <datastream.hxx>
64 #include <documentlinkmgr.hxx>
65 #include <tokenstringcontext.hxx>
66 #include <cellform.hxx>
67 #include <datamapper.hxx>
68 #include <datatransformation.hxx>
69 #include "SparklineGroupsExport.hxx"
70 #include <SparklineList.hxx>
72 #include <xmloff/xmltoken.hxx>
73 #include <xmloff/xmlnamespace.hxx>
74 #include <xmloff/xmluconv.hxx>
75 #include <xmloff/namespacemap.hxx>
76 #include <xmloff/families.hxx>
77 #include <xmloff/numehelp.hxx>
78 #include <xmloff/txtparae.hxx>
79 #include <editeng/autokernitem.hxx>
80 #include <editeng/charreliefitem.hxx>
81 #include <editeng/charscaleitem.hxx>
82 #include <editeng/colritem.hxx>
83 #include <editeng/contouritem.hxx>
84 #include <editeng/crossedoutitem.hxx>
85 #include <editeng/emphasismarkitem.hxx>
86 #include <editeng/escapementitem.hxx>
87 #include <editeng/fhgtitem.hxx>
88 #include <editeng/fontitem.hxx>
89 #include <editeng/kernitem.hxx>
90 #include <editeng/langitem.hxx>
91 #include <editeng/postitem.hxx>
92 #include <editeng/section.hxx>
93 #include <editeng/shdditem.hxx>
94 #include <editeng/udlnitem.hxx>
95 #include <editeng/wghtitem.hxx>
96 #include <editeng/wrlmitem.hxx>
97 #include <editeng/xmlcnitm.hxx>
98 #include <editeng/flditem.hxx>
99 #include <editeng/eeitem.hxx>
100 #include <formula/errorcodes.hxx>
101 #include <xmloff/xmlerror.hxx>
102 #include <xmloff/XMLEventExport.hxx>
103 #include <xmloff/xmlprmap.hxx>
104 #include <xmloff/ProgressBarHelper.hxx>
105 #include <xmloff/table/XMLTableExport.hxx>
107 #include <sax/tools/converter.hxx>
108 #include <tools/fldunit.hxx>
110 #include <rtl/ustring.hxx>
112 #include <tools/color.hxx>
113 #include <comphelper/diagnose_ex.hxx>
114 #include <rtl/math.hxx>
115 #include <svl/numformat.hxx>
116 #include <svl/zforlist.hxx>
117 #include <comphelper/base64.hxx>
118 #include <comphelper/extract.hxx>
119 #include <svx/svdoashp.hxx>
120 #include <svx/svdobj.hxx>
121 #include <svx/svdocapt.hxx>
122 #include <svx/svdomeas.hxx>
123 #include <svx/svdmodel.hxx>
124 #include <vcl/svapp.hxx>
125 #include <docmodel/theme/Theme.hxx>
127 #include <comphelper/processfactory.hxx>
128 #include <com/sun/star/beans/XPropertySet.hpp>
129 #include <com/sun/star/container/XNamed.hpp>
130 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
131 #include <com/sun/star/form/XFormsSupplier2.hpp>
132 #include <com/sun/star/io/XActiveDataSource.hpp>
133 #include <com/sun/star/io/XSeekable.hpp>
134 #include <com/sun/star/sheet/XUsedAreaCursor.hpp>
135 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
136 #include <com/sun/star/sheet/XPrintAreas.hpp>
137 #include <com/sun/star/sheet/XUniqueCellFormatRangesSupplier.hpp>
138 #include <com/sun/star/sheet/XLabelRange.hpp>
139 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
140 #include <com/sun/star/sheet/XSheetCellCursor.hpp>
141 #include <com/sun/star/sheet/XSheetCellRanges.hpp>
142 #include <com/sun/star/sheet/XSheetLinkable.hpp>
143 #include <com/sun/star/sheet/GlobalSheetSettings.hpp>
144 #include <com/sun/star/table/XColumnRowRange.hpp>
145 #include <com/sun/star/util/XProtectable.hpp>
146 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
147 #include <com/sun/star/chart2/XChartDocument.hpp>
148 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
149 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
151 #include <com/sun/star/document/XDocumentProperties.hpp>
152 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
154 #include "XMLCodeNameProvider.hxx"
156 #include <sfx2/linkmgr.hxx>
157 #include <sfx2/objsh.hxx>
159 #include <memory>
160 #include <vector>
161 #include <vbahelper/vbaaccesshelper.hxx>
162 #include <officecfg/Office/Common.hxx>
164 namespace com::sun::star::uno { class XComponentContext; }
168 //! not found in unonames.hxx
169 constexpr OUString SC_LAYERID = u"LayerID"_ustr;
171 #define SC_VIEWCHANGES_COUNT 13
172 #define SC_SHOW_CHANGES 0
173 #define SC_SHOW_ACCEPTED_CHANGES 1
174 #define SC_SHOW_REJECTED_CHANGES 2
175 #define SC_SHOW_CHANGES_BY_DATETIME 3
176 #define SC_SHOW_CHANGES_BY_DATETIME_MODE 4
177 #define SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME 5
178 #define SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME 6
179 #define SC_SHOW_CHANGES_BY_AUTHOR 7
180 #define SC_SHOW_CHANGES_BY_AUTHOR_NAME 8
181 #define SC_SHOW_CHANGES_BY_COMMENT 9
182 #define SC_SHOW_CHANGES_BY_COMMENT_TEXT 10
183 #define SC_SHOW_CHANGES_BY_RANGES 11
184 #define SC_SHOW_CHANGES_BY_RANGES_LIST 12
186 using namespace formula;
187 using namespace com::sun::star;
188 using namespace xmloff::token;
189 using ::std::vector;
190 using ::com::sun::star::uno::UNO_QUERY;
192 namespace
194 OUString lcl_RangeSequenceToString(
195 const uno::Sequence< OUString > & rRanges,
196 const uno::Reference< chart2::data::XRangeXMLConversion > & xFormatConverter )
198 OUStringBuffer aResult;
199 const sal_Int32 nMaxIndex( rRanges.getLength() - 1 );
200 const sal_Unicode cSep(' ');
201 for( sal_Int32 i=0; i<=nMaxIndex; ++i )
203 OUString aRange( rRanges[i] );
204 if( xFormatConverter.is())
205 aRange = xFormatConverter->convertRangeToXML( aRange );
206 aResult.append( aRange );
207 if( i < nMaxIndex )
208 aResult.append( cSep );
210 return aResult.makeStringAndClear();
213 OUString lcl_GetFormattedString(ScDocument& rDoc, const ScRefCellValue& rCell, const ScAddress& rAddr)
215 // return text/edit cell string content, with line feeds in edit cells
217 switch (rCell.getType())
219 case CELLTYPE_STRING:
221 const Color* pColor;
222 sal_uInt32 nFormat = rDoc.GetNumberFormat(ScRange(rAddr));
223 return ScCellFormat::GetString(rCell, nFormat, &pColor, nullptr, rDoc);
225 case CELLTYPE_EDIT:
227 const EditTextObject* pData = rCell.getEditText();
228 if (!pData)
229 return OUString();
231 EditEngine& rEngine = rDoc.GetEditEngine();
232 rEngine.SetText(*pData);
233 return rEngine.GetText();
235 break;
236 default:
240 return OUString();
243 } // anonymous namespace
245 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
246 Calc_XMLExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
248 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLExporter"_ustr, SvXMLExportFlags::ALL));
251 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
252 Calc_XMLMetaExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
254 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLMetaExporter"_ustr, SvXMLExportFlags::META));
257 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
258 Calc_XMLStylesExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
260 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLStylesExporter"_ustr, SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS));
263 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
264 Calc_XMLContentExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
266 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLContentExporter"_ustr, SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::FONTDECLS));
269 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
270 Calc_XMLSettingsExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
272 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLSettingsExporter"_ustr, SvXMLExportFlags::SETTINGS));
275 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
276 Calc_XMLOasisExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
278 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLOasisExporter"_ustr, SvXMLExportFlags::ALL|SvXMLExportFlags::OASIS));
281 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
282 Calc_XMLOasisMetaExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
284 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLOasisMetaExporter"_ustr, SvXMLExportFlags::META|SvXMLExportFlags::OASIS));
287 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
288 Calc_XMLOasisStylesExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
290 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLOasisStylesExporter"_ustr, SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::OASIS));
293 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
294 Calc_XMLOasisContentExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
296 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLOasisContentExporter"_ustr, SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::OASIS));
299 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
300 Calc_XMLOasisSettingsExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
302 return cppu::acquire(new ScXMLExport(context, u"com.sun.star.comp.Calc.XMLOasisSettingsExporter"_ustr, SvXMLExportFlags::SETTINGS|SvXMLExportFlags::OASIS));
305 namespace {
307 class ScXMLShapeExport : public XMLShapeExport
309 public:
310 explicit ScXMLShapeExport(SvXMLExport& rExp)
311 : XMLShapeExport(rExp,
312 // chain text attributes
313 XMLTextParagraphExport::CreateParaExtPropMapper(rExp))
317 /** is called before a shape element for the given XShape is exported */
318 virtual void onExport( const uno::Reference < drawing::XShape >& xShape ) override;
323 void ScXMLShapeExport::onExport( const uno::Reference < drawing::XShape >& xShape )
325 uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY );
326 if( xShapeProp.is() )
328 sal_Int16 nLayerID = 0;
329 if( (xShapeProp->getPropertyValue( SC_LAYERID ) >>= nLayerID) && (SdrLayerID(nLayerID) == SC_LAYER_BACK) )
330 GetExport().AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_BACKGROUND, XML_TRUE);
334 sal_Int16 ScXMLExport::GetMeasureUnit()
336 css::uno::Reference<css::sheet::XGlobalSheetSettings> xProperties =
337 css::sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() );
338 const FieldUnit eFieldUnit = static_cast<FieldUnit>(xProperties->getMetric());
339 return SvXMLUnitConverter::GetMeasureUnit(eFieldUnit);
342 ScXMLExport::ScXMLExport(
343 const css::uno::Reference< css::uno::XComponentContext >& rContext,
344 OUString const & implementationName, SvXMLExportFlags nExportFlag)
345 : SvXMLExport(
346 rContext, implementationName, GetMeasureUnit(), XML_SPREADSHEET, nExportFlag ),
347 nSourceStreamPos(0),
348 pCurrentCell(nullptr),
349 nOpenRow(-1),
350 nProgressCount(0),
351 nCurrentTable(0),
352 bHasRowHeader(false),
353 bRowHeaderOpen(false)
355 if (getExportFlags() & SvXMLExportFlags::CONTENT)
357 pGroupColumns.reset( new ScMyOpenCloseColumnRowGroup(*this, XML_TABLE_COLUMN_GROUP) );
358 pGroupRows.reset( new ScMyOpenCloseColumnRowGroup(*this, XML_TABLE_ROW_GROUP) );
359 pColumnStyles.reset( new ScColumnStyles() );
360 pRowStyles.reset( new ScRowStyles() );
361 pRowFormatRanges.reset( new ScRowFormatRanges() );
362 pMergedRangesContainer.reset( new ScMyMergedRangesContainer() );
363 pValidationsContainer.reset( new ScMyValidationsContainer() );
364 mpCellsItr.reset(new ScMyNotEmptyCellsIterator(*this));
365 pDefaults.reset( new ScMyDefaultStyles );
367 pCellStyles.reset( new ScFormatRangeStyles() );
369 // document is not set here - create ScChangeTrackingExportHelper later
371 xScPropHdlFactory = new XMLScPropHdlFactory;
372 xCellStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScCellStylesProperties, xScPropHdlFactory, true);
373 xColumnStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScColumnStylesProperties, xScPropHdlFactory, true);
374 xRowStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScRowStylesProperties, xScPropHdlFactory, true);
375 xTableStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScTableStylesProperties, xScPropHdlFactory, true);
376 xCellStylesExportPropertySetMapper = new ScXMLCellExportPropertyMapper(xCellStylesPropertySetMapper);
377 xCellStylesExportPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(*this));
378 xColumnStylesExportPropertySetMapper = new ScXMLColumnExportPropertyMapper(xColumnStylesPropertySetMapper);
379 xRowStylesExportPropertySetMapper = new ScXMLRowExportPropertyMapper(xRowStylesPropertySetMapper);
380 xTableStylesExportPropertySetMapper = new ScXMLTableExportPropertyMapper(xTableStylesPropertySetMapper);
382 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_CELL, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME,
383 xCellStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX);
384 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_COLUMN, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME,
385 xColumnStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX);
386 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_ROW, XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME,
387 xRowStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX);
388 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_TABLE, XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME,
389 xTableStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_TABLE_STYLES_PREFIX);
391 GetShapeExport(); // make sure the graphics styles family is added
393 if( !(getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT)) )
394 return;
396 // This name is reserved for the external ref cache tables. This
397 // should not conflict with user-defined styles since this name is
398 // used for a table style which is not available in the UI.
399 sExternalRefTabStyleName = "ta_extref";
400 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_TABLE, sExternalRefTabStyleName);
402 sAttrName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NAME));
403 sAttrStyleName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_STYLE_NAME));
404 sAttrColumnsRepeated = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NUMBER_COLUMNS_REPEATED));
405 sAttrFormula = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_FORMULA));
406 sAttrStringValue = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_STRING_VALUE));
407 sAttrValueType = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_VALUE_TYPE));
408 sElemCell = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_CELL));
409 sElemCoveredCell = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_COVERED_TABLE_CELL));
410 sElemCol = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_COLUMN));
411 sElemRow = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_ROW));
412 sElemTab = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE));
413 sElemP = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TEXT, GetXMLToken(XML_P));
416 ScXMLExport::~ScXMLExport()
418 pGroupColumns.reset();
419 pGroupRows.reset();
420 pColumnStyles.reset();
421 pRowStyles.reset();
422 pCellStyles.reset();
423 pRowFormatRanges.reset();
424 pMergedRangesContainer.reset();
425 pValidationsContainer.reset();
426 pChangeTrackingExportHelper.reset();
427 pDefaults.reset();
428 pNumberFormatAttributesExportHelper.reset();
431 void ScXMLExport::SetSourceStream( const uno::Reference<io::XInputStream>& xNewStream )
433 xSourceStream = xNewStream;
435 if ( !xSourceStream.is() )
436 return;
438 // make sure it's a plain UTF-8 stream as written by OOo itself
440 const char pXmlHeader[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
441 sal_Int32 nLen = strlen(pXmlHeader);
443 uno::Sequence<sal_Int8> aFileStart(nLen);
444 sal_Int32 nRead = xSourceStream->readBytes( aFileStart, nLen );
446 if ( nRead != nLen || memcmp( aFileStart.getConstArray(), pXmlHeader, nLen ) != 0 )
448 // invalid - ignore stream, save normally
449 xSourceStream.clear();
451 else
453 // keep track of the bytes already read
454 nSourceStreamPos = nRead;
456 const ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(GetModel())->GetSheetSaveData();
457 if (pSheetData)
459 // add the loaded namespaces to the name space map
461 if ( !pSheetData->AddLoadedNamespaces( GetNamespaceMap_() ) )
463 // conflicts in the namespaces - ignore the stream, save normally
464 xSourceStream.clear();
470 sal_Int32 ScXMLExport::GetNumberFormatStyleIndex(sal_Int32 nNumFmt) const
472 NumberFormatIndexMap::const_iterator itr = aNumFmtIndexMap.find(nNumFmt);
473 if (itr == aNumFmtIndexMap.end())
474 return -1;
476 return itr->second;
479 ScDocument* ScXMLExport::GetDocument()
481 return ScXMLConverter::GetScDocument(GetModel());
484 void ScXMLExport::CollectSharedData(SCTAB& nTableCount, sal_Int32& nShapesCount)
486 if (!GetModel().is())
487 return;
489 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc(GetModel(), uno::UNO_QUERY);
490 if (!xSpreadDoc.is())
491 return;
493 uno::Reference<container::XIndexAccess> xIndex(xSpreadDoc->getSheets(), uno::UNO_QUERY);
494 if (!xIndex.is())
495 return;
497 nTableCount = xIndex->getCount();
498 if (!pSharedData)
499 pSharedData.reset(new ScMySharedData(nTableCount));
501 ScDocument* pDoc = GetDocument();
503 for (SCTAB nTable = 0; nTable < nTableCount; ++nTable)
505 nCurrentTable = sal::static_int_cast<sal_uInt16>(nTable);
506 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xIndex->getByIndex(nTable), uno::UNO_QUERY);
507 if (!xDrawPageSupplier.is())
508 continue;
510 uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage());
511 ScMyDrawPage aDrawPage;
512 aDrawPage.bHasForms = false;
513 aDrawPage.xDrawPage.set(xDrawPage);
514 pSharedData->AddDrawPage(aDrawPage, nTable);
515 if (!xDrawPage.is())
516 continue;
518 sal_Int32 nShapes = xDrawPage->getCount();
519 for (sal_Int32 nShape = 0; nShape < nShapes; ++nShape)
521 uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShape), uno::UNO_QUERY);
522 if (!xShape.is())
523 continue;
525 uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
526 if (!xShapeProp.is())
527 continue;
529 sal_Int16 nLayerID = 0;
530 bool bExtracted = xShapeProp->getPropertyValue(SC_LAYERID) >>= nLayerID;
531 if (!bExtracted)
532 continue;
534 if ((SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN))
536 if (pDoc)
537 CollectInternalShape(*pDoc, xShape);
538 continue;
541 ++nShapesCount;
543 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape);
544 if (!pSdrObj)
545 continue;
547 if (ScDrawObjData *pAnchor = ScDrawLayer::GetNonRotatedObjData(pSdrObj))
549 ScMyShape aMyShape;
550 aMyShape.aAddress = pAnchor->maStart;
551 SAL_WARN_IF(aMyShape.aAddress.Tab() != nTable, "sc", "not anchored to current sheet!");
552 aMyShape.aAddress.SetTab(nTable);
553 aMyShape.aEndAddress = pAnchor->maEnd;
554 aMyShape.aEndAddress.SetTab( nTable );
555 aMyShape.nEndX = pAnchor->maEndOffset.X();
556 aMyShape.nEndY = pAnchor->maEndOffset.Y();
557 aMyShape.xShape = std::move(xShape);
558 pSharedData->AddNewShape(aMyShape);
559 pSharedData->SetLastColumn(nTable, pAnchor->maStart.Col());
560 pSharedData->SetLastRow(nTable, pAnchor->maStart.Row());
562 else
563 pSharedData->AddTableShape(nTable, xShape);
568 void ScXMLExport::CollectShapesAutoStyles(SCTAB nTableCount)
570 // #i84077# To avoid compiler warnings about uninitialized aShapeItr,
571 // it's initialized using this dummy list. The iterator contains shapes
572 // from all sheets, so it can't be declared inside the nTable loop where
573 // it is used.
574 ScMyShapeList aDummyInitList;
576 pSharedData->SortShapesContainer();
577 pSharedData->SortNoteShapes();
578 const ScMyShapeList* pShapeList(nullptr);
579 ScMyShapeList::const_iterator aShapeItr = aDummyInitList.end();
580 if (pSharedData->GetShapesContainer())
582 pShapeList = &pSharedData->GetShapesContainer()->GetShapes();
583 aShapeItr = pShapeList->begin();
585 if (pSharedData->HasDrawPage())
587 for (SCTAB nTable = 0; nTable < nTableCount; ++nTable)
589 uno::Reference<drawing::XDrawPage> xDrawPage(pSharedData->GetDrawPage(nTable));
591 if (xDrawPage.is())
593 GetShapeExport()->seekShapes(xDrawPage);
594 uno::Reference< form::XFormsSupplier2 > xFormsSupplier( xDrawPage, uno::UNO_QUERY );
595 if( xFormsSupplier.is() && xFormsSupplier->hasForms() )
597 GetFormExport()->examineForms(xDrawPage);
598 pSharedData->SetDrawPageHasForms(nTable, true);
600 ScMyTableShapes* pTableShapes(pSharedData->GetTableShapes());
601 if (pTableShapes)
603 for (const auto& rxShape : (*pTableShapes)[nTable])
605 GetShapeExport()->collectShapeAutoStyles(rxShape);
606 IncrementProgressBar(false);
609 if (pShapeList)
611 ScMyShapeList::const_iterator aEndItr(pShapeList->end());
612 while ( aShapeItr != aEndItr && ( aShapeItr->aAddress.Tab() == nTable ) )
614 GetShapeExport()->collectShapeAutoStyles(aShapeItr->xShape);
615 IncrementProgressBar(false);
616 ++aShapeItr;
619 if (pSharedData->GetNoteShapes())
621 const ScMyNoteShapeList& rNoteShapes = pSharedData->GetNoteShapes()->GetNotes();
622 for (const auto& rNoteShape : rNoteShapes)
624 if ( rNoteShape.aPos.Tab() == nTable )
625 GetShapeExport()->collectShapeAutoStyles(rNoteShape.xShape);
631 pSharedData->SortNoteShapes(); // sort twice, because some more shapes are added
634 void ScXMLExport::ExportMeta_()
636 ScDocument* pDoc = GetDocument();
637 sal_Int32 nCellCount(pDoc ? pDoc->GetCellCount() : 0);
638 SCTAB nTableCount(0);
639 sal_Int32 nShapesCount(0);
640 GetAutoStylePool()->ClearEntries();
641 CollectSharedData(nTableCount, nShapesCount);
643 uno::Sequence<beans::NamedValue> stats
645 { u"TableCount"_ustr, uno::Any(static_cast<sal_Int32>(nTableCount)) },
646 { u"CellCount"_ustr, uno::Any(nCellCount) },
647 { u"ObjectCount"_ustr, uno::Any(nShapesCount) }
650 // update document statistics at the model
651 uno::Reference<document::XDocumentPropertiesSupplier> xPropSup(GetModel(),
652 uno::UNO_QUERY_THROW);
653 uno::Reference<document::XDocumentProperties> xDocProps(
654 xPropSup->getDocumentProperties());
655 if (xDocProps.is()) {
656 xDocProps->setDocumentStatistics(stats);
659 // export document properties
660 SvXMLExport::ExportMeta_();
663 void ScXMLExport::ExportFontDecls_()
665 GetFontAutoStylePool(); // make sure the pool is created
666 SvXMLExport::ExportFontDecls_();
669 table::CellRangeAddress ScXMLExport::GetEndAddress(const uno::Reference<sheet::XSpreadsheet>& xTable)
671 table::CellRangeAddress aCellAddress;
672 uno::Reference<sheet::XSheetCellCursor> xCursor(xTable->createCursor());
673 uno::Reference<sheet::XUsedAreaCursor> xUsedArea (xCursor, uno::UNO_QUERY);
674 uno::Reference<sheet::XCellRangeAddressable> xCellAddress (xCursor, uno::UNO_QUERY);
675 if (xUsedArea.is() && xCellAddress.is())
677 xUsedArea->gotoEndOfUsedArea(true);
678 aCellAddress = xCellAddress->getRangeAddress();
680 return aCellAddress;
683 //static
684 ScMyAreaLinksContainer ScXMLExport::GetAreaLinks(ScDocument& rDoc)
686 sfx2::LinkManager* pManager = rDoc.GetLinkManager();
687 if (!pManager)
688 return {};
690 ScMyAreaLinkList aAreaLinks;
691 for (const auto& rLink : pManager->GetLinks())
693 if (ScAreaLink* pLink = dynamic_cast<ScAreaLink*>(rLink.get()))
695 ScMyAreaLink aAreaLink;
696 aAreaLink.aDestRange = pLink->GetDestArea();
697 aAreaLink.sSourceStr = pLink->GetSource();
698 aAreaLink.sFilter = pLink->GetFilter();
699 aAreaLink.sFilterOptions = pLink->GetOptions();
700 aAreaLink.sURL = pLink->GetFile();
701 aAreaLink.nRefreshDelaySeconds = pLink->GetRefreshDelaySeconds();
702 aAreaLinks.push_back(aAreaLink);
705 return ScMyAreaLinksContainer(std::move(aAreaLinks));
708 // core implementation
709 ScMyDetectiveOpContainer ScXMLExport::GetDetectiveOpList(ScDocument& rDoc)
711 ScDetOpList* pOpList(rDoc.GetDetOpList());
712 if( !pOpList )
713 return {};
715 ScMyDetectiveOpList aDetOp;
716 size_t nCount = pOpList->Count();
717 for (size_t nIndex = 0; nIndex < nCount; ++nIndex )
719 const ScDetOpData& rDetData = pOpList->GetObject( nIndex);
720 const ScAddress& rDetPos = rDetData.GetPos();
721 SCTAB nTab = rDetPos.Tab();
722 if ( nTab < rDoc.GetTableCount() )
724 aDetOp.push_back({ rDetPos, rDetData.GetOperation(), static_cast<sal_Int32>(nIndex) });
726 // cells with detective operations are written even if empty
727 pSharedData->SetLastColumn( nTab, rDetPos.Col() );
728 pSharedData->SetLastRow( nTab, rDetPos.Row() );
731 return ScMyDetectiveOpContainer(std::move(aDetOp));
734 void ScXMLExport::WriteSingleColumn(const sal_Int32 nRepeatColumns, const sal_Int32 nStyleIndex,
735 const sal_Int32 nIndex, const bool bIsAutoStyle, const bool bIsVisible)
737 CheckAttrList();
738 // tdf#138466
739 if (nStyleIndex != -1)
740 AddAttribute(sAttrStyleName, pColumnStyles->GetStyleNameByIndex(nStyleIndex));
741 if (!bIsVisible)
742 AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_COLLAPSE);
743 if (nRepeatColumns > 1)
745 OUString sOUEndCol(OUString::number(nRepeatColumns));
746 AddAttribute(sAttrColumnsRepeated, sOUEndCol);
748 if (nIndex != -1)
749 AddAttribute(XML_NAMESPACE_TABLE, XML_DEFAULT_CELL_STYLE_NAME, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle));
750 SvXMLElementExport aElemC(*this, sElemCol, true, true);
753 void ScXMLExport::WriteColumn(const sal_Int32 nColumn, const sal_Int32 nRepeatColumns,
754 const sal_Int32 nStyleIndex, const bool bIsVisible)
756 sal_Int32 nRepeat(1);
757 sal_Int32 nPrevIndex(pDefaults->GetColDefaults()[nColumn].nIndex);
758 bool bPrevAutoStyle(pDefaults->GetColDefaults()[nColumn].bIsAutoStyle);
759 for (sal_Int32 i = nColumn + 1; i < nColumn + nRepeatColumns; ++i)
761 if ((pDefaults->GetColDefaults()[i].nIndex != nPrevIndex) ||
762 (pDefaults->GetColDefaults()[i].bIsAutoStyle != bPrevAutoStyle))
764 WriteSingleColumn(nRepeat, nStyleIndex, nPrevIndex, bPrevAutoStyle, bIsVisible);
765 nPrevIndex = pDefaults->GetColDefaults()[i].nIndex;
766 bPrevAutoStyle = pDefaults->GetColDefaults()[i].bIsAutoStyle;
767 nRepeat = 1;
769 else
770 ++nRepeat;
772 WriteSingleColumn(nRepeat, nStyleIndex, nPrevIndex, bPrevAutoStyle, bIsVisible);
775 void ScXMLExport::OpenHeaderColumn()
777 StartElement( XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true );
780 void ScXMLExport::CloseHeaderColumn()
782 EndElement(XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true);
785 void ScXMLExport::ExportColumns(const sal_Int32 nTable, const ScRange& aColumnHeaderRange, const bool bHasColumnHeader)
787 sal_Int32 nColsRepeated (1);
788 sal_Int32 nIndex;
789 sal_Int32 nPrevColumn(0);
790 bool bPrevIsVisible (true);
791 bool bWasHeader (false);
792 bool bIsClosed (true);
793 sal_Int32 nPrevIndex (-1);
794 sal_Int32 nColumn;
795 for (nColumn = 0; nColumn <= pSharedData->GetLastColumn(nTable); ++nColumn)
797 CheckAttrList();
798 bool bIsVisible(true);
799 nIndex = pColumnStyles->GetStyleNameIndex(nTable, nColumn, bIsVisible);
801 const bool bIsHeader = bHasColumnHeader && (aColumnHeaderRange.aStart.Col() <= nColumn) && (nColumn <= aColumnHeaderRange.aEnd.Col());
802 if (bIsHeader != bWasHeader)
804 if (bIsHeader)
806 if (nColumn > 0)
808 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
809 if (pGroupColumns->IsGroupEnd(nColumn - 1))
810 pGroupColumns->CloseGroups(nColumn - 1);
812 bPrevIsVisible = bIsVisible;
813 nPrevIndex = nIndex;
814 nPrevColumn = nColumn;
815 nColsRepeated = 1;
816 if(pGroupColumns->IsGroupStart(nColumn))
817 pGroupColumns->OpenGroups(nColumn);
818 OpenHeaderColumn();
819 bWasHeader = true;
820 bIsClosed = false;
822 else
824 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
825 CloseHeaderColumn();
826 if (pGroupColumns->IsGroupEnd(nColumn - 1))
827 pGroupColumns->CloseGroups(nColumn - 1);
828 if(pGroupColumns->IsGroupStart(nColumn))
829 pGroupColumns->OpenGroups(nColumn);
830 bPrevIsVisible = bIsVisible;
831 nPrevIndex = nIndex;
832 nPrevColumn = nColumn;
833 nColsRepeated = 1;
834 bWasHeader = false;
835 bIsClosed = true;
838 else if (nColumn == 0)
840 if (pGroupColumns->IsGroupStart(nColumn))
841 pGroupColumns->OpenGroups(nColumn);
842 bPrevIsVisible = bIsVisible;
843 nPrevIndex = nIndex;
845 else if ((bIsVisible == bPrevIsVisible) && (nIndex == nPrevIndex) &&
846 !pGroupColumns->IsGroupStart(nColumn) && !pGroupColumns->IsGroupEnd(nColumn - 1))
847 ++nColsRepeated;
848 else
850 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
851 if (pGroupColumns->IsGroupEnd(nColumn - 1))
853 if (bIsHeader)
854 CloseHeaderColumn();
855 pGroupColumns->CloseGroups(nColumn - 1);
856 if (bIsHeader)
857 OpenHeaderColumn();
859 if (pGroupColumns->IsGroupStart(nColumn))
861 if (bIsHeader)
862 CloseHeaderColumn();
863 pGroupColumns->OpenGroups(nColumn);
864 if (bIsHeader)
865 OpenHeaderColumn();
867 bPrevIsVisible = bIsVisible;
868 nPrevIndex = nIndex;
869 nPrevColumn = nColumn;
870 nColsRepeated = 1;
873 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
874 if (!bIsClosed)
875 CloseHeaderColumn();
876 if (pGroupColumns->IsGroupEnd(nColumn - 1))
877 pGroupColumns->CloseGroups(nColumn - 1);
880 void ScXMLExport::ExportExternalRefCacheStyles(ScDocument& rDoc)
882 sal_Int32 nEntryIndex = GetCellStylesPropertySetMapper()->FindEntryIndex(
883 "NumberFormat", XML_NAMESPACE_STYLE, u"data-style-name");
885 if (nEntryIndex < 0)
886 // No entry index for the number format is found.
887 return;
889 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
890 if (!pRefMgr->hasExternalData())
891 // No external reference data cached.
892 return;
894 // Export each unique number format used in the external ref cache.
895 vector<sal_uInt32> aNumFmts;
896 pRefMgr->getAllCachedNumberFormats(aNumFmts);
897 static constexpr OUString aDefaultStyle(u"Default"_ustr);
898 for (const auto& rNumFmt : aNumFmts)
900 sal_Int32 nNumFmt = static_cast<sal_Int32>(rNumFmt);
902 addDataStyle(nNumFmt);
904 uno::Any aVal;
905 aVal <<= nNumFmt;
906 vector<XMLPropertyState> aProps;
907 aVal <<= aDefaultStyle;
908 aProps.emplace_back(nEntryIndex, aVal);
910 OUString aName;
911 sal_Int32 nIndex;
912 if (GetAutoStylePool()->Add(aName, XmlStyleFamily::TABLE_CELL, aDefaultStyle, std::move(aProps)))
914 pCellStyles->AddStyleName(aName, nIndex);
916 else
918 bool bIsAuto;
919 nIndex = pCellStyles->GetIndexOfStyleName(
920 aName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX, bIsAuto);
923 // store the number format to index mapping for later use.
924 aNumFmtIndexMap.emplace(nNumFmt, nIndex);
928 namespace {
930 void handleFont(
931 SvXMLExport & rExport,
932 std::vector<XMLPropertyState>& rPropStates,
933 const SfxPoolItem* p, const rtl::Reference<XMLPropertySetMapper>& xMapper, std::u16string_view rXMLName )
935 sal_Int32 nEntryCount = xMapper->GetEntryCount();
937 // Apparently font info needs special handling.
938 const SvxFontItem* pItem = static_cast<const SvxFontItem*>(p);
940 sal_Int32 nIndexFontName = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, rXMLName, 0);
942 if (nIndexFontName == -1 || nIndexFontName >= nEntryCount)
943 return;
945 OUString const sFamilyName(pItem->GetFamilyName());
946 OUString const sStyleName(pItem->GetStyleName());
947 auto const nFamily(pItem->GetFamily());
948 auto const nPitch(pItem->GetPitch());
949 auto const eEnc(pItem->GetCharSet());
950 OUString const sName(rExport.GetFontAutoStylePool()->Find(
951 sFamilyName, sStyleName, nFamily, nPitch, eEnc));
952 if (sName.isEmpty())
954 assert(false); // fallback to fo:font-family etc. probably not needed
957 rPropStates.emplace_back(nIndexFontName, uno::Any(sName));
960 const SvxFieldData* toXMLPropertyStates(
961 SvXMLExport & rExport,
962 std::vector<XMLPropertyState>& rPropStates, const std::vector<const SfxPoolItem*>& rSecAttrs,
963 const rtl::Reference<XMLPropertySetMapper>& xMapper, const ScXMLEditAttributeMap& rAttrMap )
965 const SvxFieldData* pField = nullptr;
966 sal_Int32 nEntryCount = xMapper->GetEntryCount();
967 rPropStates.reserve(rSecAttrs.size());
968 for (const SfxPoolItem* p : rSecAttrs)
970 if (p->Which() == EE_FEATURE_FIELD)
972 pField = static_cast<const SvxFieldItem*>(p)->GetField();
973 continue;
976 const ScXMLEditAttributeMap::Entry* pEntry = rAttrMap.getEntryByItemID(p->Which());
977 if (!pEntry)
978 continue;
980 sal_Int32 nIndex = xMapper->GetEntryIndex(pEntry->nmXMLNS, pEntry->maXMLName, 0);
982 if (nIndex == -1 || nIndex >= nEntryCount)
983 continue;
985 uno::Any aAny;
986 switch (p->Which())
988 case EE_CHAR_FONTINFO:
989 handleFont(rExport, rPropStates, p, xMapper, u"font-name");
990 break;
991 case EE_CHAR_FONTINFO_CJK:
992 handleFont(rExport, rPropStates, p, xMapper, u"font-name-asian");
993 break;
994 case EE_CHAR_FONTINFO_CTL:
995 handleFont(rExport, rPropStates, p, xMapper, u"font-name-complex");
996 break;
997 case EE_CHAR_WEIGHT:
998 case EE_CHAR_WEIGHT_CJK:
999 case EE_CHAR_WEIGHT_CTL:
1001 if (!static_cast<const SvxWeightItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1002 continue;
1004 rPropStates.emplace_back(nIndex, aAny);
1006 break;
1007 case EE_CHAR_FONTHEIGHT:
1008 case EE_CHAR_FONTHEIGHT_CJK:
1009 case EE_CHAR_FONTHEIGHT_CTL:
1011 if (!static_cast<const SvxFontHeightItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1012 continue;
1014 rPropStates.emplace_back(nIndex, aAny);
1016 break;
1017 case EE_CHAR_ITALIC:
1018 case EE_CHAR_ITALIC_CJK:
1019 case EE_CHAR_ITALIC_CTL:
1021 if (!static_cast<const SvxPostureItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1022 continue;
1024 rPropStates.emplace_back(nIndex, aAny);
1026 break;
1027 case EE_CHAR_UNDERLINE:
1029 // Underline attribute needs to export multiple entries.
1030 sal_Int32 nIndexStyle = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-style", 0);
1031 if (nIndexStyle == -1 || nIndexStyle > nEntryCount)
1032 break;
1034 sal_Int32 nIndexWidth = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-width", 0);
1035 if (nIndexWidth == -1 || nIndexWidth > nEntryCount)
1036 break;
1038 sal_Int32 nIndexType = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-type", 0);
1039 if (nIndexType == -1 || nIndexType > nEntryCount)
1040 break;
1042 sal_Int32 nIndexColor = xMapper->FindEntryIndex("CharUnderlineColor", XML_NAMESPACE_STYLE, u"text-underline-color");
1043 if (nIndexColor == -1 || nIndexColor > nEntryCount)
1044 break;
1046 sal_Int32 nIndexHasColor = xMapper->FindEntryIndex("CharUnderlineHasColor", XML_NAMESPACE_STYLE, u"text-underline-color");
1047 if (nIndexHasColor == -1 || nIndexHasColor > nEntryCount)
1048 break;
1050 const SvxUnderlineItem* pUL = static_cast<const SvxUnderlineItem*>(p);
1051 pUL->QueryValue(aAny, MID_TL_STYLE);
1052 rPropStates.emplace_back(nIndexStyle, aAny);
1053 rPropStates.emplace_back(nIndexType, aAny);
1054 rPropStates.emplace_back(nIndexWidth, aAny);
1056 pUL->QueryValue(aAny, MID_TL_COLOR);
1057 rPropStates.emplace_back(nIndexColor, aAny);
1059 pUL->QueryValue(aAny, MID_TL_HASCOLOR);
1060 rPropStates.emplace_back(nIndexHasColor, aAny);
1062 break;
1063 case EE_CHAR_OVERLINE:
1065 // Same with overline. Do just as we do with underline attributes.
1066 sal_Int32 nIndexStyle = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-style", 0);
1067 if (nIndexStyle == -1 || nIndexStyle > nEntryCount)
1068 break;
1070 sal_Int32 nIndexWidth = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-width", 0);
1071 if (nIndexWidth == -1 || nIndexWidth > nEntryCount)
1072 break;
1074 sal_Int32 nIndexType = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-type", 0);
1075 if (nIndexType == -1 || nIndexType > nEntryCount)
1076 break;
1078 sal_Int32 nIndexColor = xMapper->FindEntryIndex("CharOverlineColor", XML_NAMESPACE_STYLE, u"text-overline-color");
1079 if (nIndexColor == -1 || nIndexColor > nEntryCount)
1080 break;
1082 sal_Int32 nIndexHasColor = xMapper->FindEntryIndex("CharOverlineHasColor", XML_NAMESPACE_STYLE, u"text-overline-color");
1083 if (nIndexHasColor == -1 || nIndexHasColor > nEntryCount)
1084 break;
1086 const SvxOverlineItem* pOL = static_cast<const SvxOverlineItem*>(p);
1087 pOL->QueryValue(aAny, MID_TL_STYLE);
1088 rPropStates.emplace_back(nIndexStyle, aAny);
1089 rPropStates.emplace_back(nIndexType, aAny);
1090 rPropStates.emplace_back(nIndexWidth, aAny);
1092 pOL->QueryValue(aAny, MID_TL_COLOR);
1093 rPropStates.emplace_back(nIndexColor, aAny);
1095 pOL->QueryValue(aAny, MID_TL_HASCOLOR);
1096 rPropStates.emplace_back(nIndexHasColor, aAny);
1098 break;
1099 case EE_CHAR_COLOR:
1101 if (!static_cast<const SvxColorItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1102 continue;
1104 ::Color nColor;
1105 if ( aAny >>= nColor )
1107 sal_Int32 nIndexColor = ( nColor == COL_AUTO ) ? xMapper->GetEntryIndex(
1108 XML_NAMESPACE_STYLE, GetXMLToken( XML_USE_WINDOW_FONT_COLOR ), 0 ) : nIndex;
1109 rPropStates.emplace_back( nIndexColor, aAny );
1112 break;
1113 case EE_CHAR_WLM:
1115 if (!static_cast<const SvxWordLineModeItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1116 continue;
1118 rPropStates.emplace_back(nIndex, aAny);
1120 break;
1121 case EE_CHAR_STRIKEOUT:
1123 if (!static_cast<const SvxCrossedOutItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1124 continue;
1126 rPropStates.emplace_back(nIndex, aAny);
1128 break;
1129 case EE_CHAR_RELIEF:
1131 if (!static_cast<const SvxCharReliefItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1132 continue;
1134 rPropStates.emplace_back(nIndex, aAny);
1136 break;
1137 case EE_CHAR_OUTLINE:
1139 if (!static_cast<const SvxContourItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1140 continue;
1142 rPropStates.emplace_back(nIndex, aAny);
1144 break;
1145 case EE_CHAR_SHADOW:
1147 if (!static_cast<const SvxShadowedItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1148 continue;
1150 rPropStates.emplace_back(nIndex, aAny);
1152 break;
1153 case EE_CHAR_KERNING:
1155 if (!static_cast<const SvxKerningItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1156 continue;
1158 rPropStates.emplace_back(nIndex, aAny);
1160 break;
1161 case EE_CHAR_PAIRKERNING:
1163 if (!static_cast<const SvxAutoKernItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1164 continue;
1166 rPropStates.emplace_back(nIndex, aAny);
1168 break;
1169 case EE_CHAR_FONTWIDTH:
1171 if (!static_cast<const SvxCharScaleWidthItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1172 continue;
1174 rPropStates.emplace_back(nIndex, aAny);
1176 break;
1177 case EE_CHAR_ESCAPEMENT:
1179 sal_Int32 nIndexEsc = xMapper->FindEntryIndex("CharEscapement", XML_NAMESPACE_STYLE, u"text-position");
1180 if (nIndexEsc == -1 || nIndexEsc > nEntryCount)
1181 break;
1183 sal_Int32 nIndexEscHeight = xMapper->FindEntryIndex("CharEscapementHeight", XML_NAMESPACE_STYLE, u"text-position");
1184 if (nIndexEscHeight == -1 || nIndexEscHeight > nEntryCount)
1185 break;
1187 const SvxEscapementItem* pEsc = static_cast<const SvxEscapementItem*>(p);
1189 pEsc->QueryValue(aAny);
1190 rPropStates.emplace_back(nIndexEsc, aAny);
1192 pEsc->QueryValue(aAny, MID_ESC_HEIGHT);
1193 rPropStates.emplace_back(nIndexEscHeight, aAny);
1196 break;
1197 case EE_CHAR_EMPHASISMARK:
1199 if (!static_cast<const SvxEmphasisMarkItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1200 continue;
1202 rPropStates.emplace_back(nIndex, aAny);
1204 break;
1205 case EE_CHAR_LANGUAGE:
1206 case EE_CHAR_LANGUAGE_CJK:
1207 case EE_CHAR_LANGUAGE_CTL:
1209 if (!static_cast<const SvxLanguageItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1210 continue;
1212 // Export multiple entries.
1213 sal_Int32 nIndexLanguage, nIndexCountry, nIndexScript, nIndexTag;
1214 switch (p->Which())
1216 case EE_CHAR_LANGUAGE:
1217 nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"language", 0);
1218 nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"country", 0);
1219 nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"script", 0);
1220 nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag", 0);
1221 break;
1222 case EE_CHAR_LANGUAGE_CJK:
1223 nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"language-asian", 0);
1224 nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"country-asian", 0);
1225 nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"script-asian", 0);
1226 nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag-asian", 0);
1227 break;
1228 case EE_CHAR_LANGUAGE_CTL:
1229 nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"language-complex", 0);
1230 nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"country-complex", 0);
1231 nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"script-complex", 0);
1232 nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag-complex", 0);
1233 break;
1234 default:
1235 nIndexLanguage = nIndexCountry = nIndexScript = nIndexTag = -1;
1237 assert( nIndexLanguage >= 0 && nIndexCountry >= 0 && nIndexScript >= 0 && nIndexTag >= 0);
1238 rPropStates.emplace_back( nIndexLanguage, aAny);
1239 rPropStates.emplace_back( nIndexCountry, aAny);
1240 rPropStates.emplace_back( nIndexScript, aAny);
1241 rPropStates.emplace_back( nIndexTag, aAny);
1243 break;
1244 default:
1245 continue;
1249 return pField;
1254 void ScXMLExport::ExportCellTextAutoStyles(ScDocument& rDoc, sal_Int32 nTable)
1256 if (!ValidTab(nTable))
1257 return;
1259 rtl::Reference<XMLPropertySetMapper> xMapper = GetTextParagraphExport()->GetTextPropMapper()->getPropertySetMapper();
1260 rtl::Reference<SvXMLAutoStylePoolP> xStylePool = GetAutoStylePool();
1261 const ScXMLEditAttributeMap& rAttrMap = GetEditAttributeMap();
1263 sc::EditTextIterator aIter(rDoc, nTable);
1264 sal_Int32 nCellCount = 0;
1265 for (const EditTextObject* pEdit = aIter.first(); pEdit; pEdit = aIter.next(), ++nCellCount)
1267 std::vector<editeng::Section> aAttrs;
1268 pEdit->GetAllSections(aAttrs);
1269 if (aAttrs.empty())
1270 continue;
1272 for (const auto& rSec : aAttrs)
1274 const std::vector<const SfxPoolItem*>& rSecAttrs = rSec.maAttributes;
1275 if (rSecAttrs.empty())
1276 // No formats applied to this section. Skip it.
1277 continue;
1279 std::vector<XMLPropertyState> aPropStates;
1280 toXMLPropertyStates(*this, aPropStates, rSecAttrs, xMapper, rAttrMap);
1281 if (!aPropStates.empty())
1282 xStylePool->Add(XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates));
1286 GetProgressBarHelper()->ChangeReference(GetProgressBarHelper()->GetReference() + nCellCount);
1289 void ScXMLExport::WriteRowContent()
1291 ScMyRowFormatRange aRange;
1292 sal_Int32 nIndex(-1);
1293 #if OSL_DEBUG_LEVEL > 0
1294 sal_Int32 nPrevCol(0);
1295 #endif
1296 sal_Int32 nCols(0);
1297 sal_Int32 nPrevValidationIndex(-1);
1298 bool bIsAutoStyle(true);
1299 bool bIsFirst(true);
1300 while (pRowFormatRanges->GetNext(aRange))
1302 #if OSL_DEBUG_LEVEL > 0
1303 OSL_ENSURE(bIsFirst || (!bIsFirst && (nPrevCol + nCols == aRange.nStartColumn)), "here are some columns missing");
1304 #endif
1305 if (bIsFirst)
1307 nIndex = aRange.nIndex;
1308 nPrevValidationIndex = aRange.nValidationIndex;
1309 bIsAutoStyle = aRange.bIsAutoStyle;
1310 nCols = aRange.nRepeatColumns;
1311 bIsFirst = false;
1312 #if OSL_DEBUG_LEVEL > 0
1313 nPrevCol = aRange.nStartColumn;
1314 #endif
1316 else
1318 if (((aRange.nIndex == nIndex && aRange.bIsAutoStyle == bIsAutoStyle) ||
1319 (aRange.nIndex == nIndex && nIndex == -1)) &&
1320 nPrevValidationIndex == aRange.nValidationIndex)
1321 nCols += aRange.nRepeatColumns;
1322 else
1324 if (nIndex != -1)
1325 AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle));
1326 if (nPrevValidationIndex > -1)
1327 AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(nPrevValidationIndex));
1328 if (nCols > 1)
1330 AddAttribute(sAttrColumnsRepeated, OUString::number(nCols));
1332 SvXMLElementExport aElemC(*this, sElemCell, true, true);
1333 nIndex = aRange.nIndex;
1334 bIsAutoStyle = aRange.bIsAutoStyle;
1335 nCols = aRange.nRepeatColumns;
1336 nPrevValidationIndex = aRange.nValidationIndex;
1337 #if OSL_DEBUG_LEVEL > 0
1338 nPrevCol = aRange.nStartColumn;
1339 #endif
1343 if (!bIsFirst)
1345 if (nIndex != -1)
1346 AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle));
1347 if (nPrevValidationIndex > -1)
1348 AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(nPrevValidationIndex));
1349 if (nCols > 1)
1351 AddAttribute(sAttrColumnsRepeated, OUString::number(nCols));
1353 SvXMLElementExport aElemC(*this, sElemCell, true, true);
1357 void ScXMLExport::WriteRowStartTag(
1358 const sal_Int32 nIndex, const sal_Int32 nEqualRows,
1359 bool bHidden, bool bFiltered)
1361 // tdf#143940
1362 if (nIndex != -1)
1363 AddAttribute(sAttrStyleName, pRowStyles->GetStyleNameByIndex(nIndex));
1364 if (bHidden)
1366 if (bFiltered)
1367 AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_FILTER);
1368 else
1369 AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_COLLAPSE);
1371 if (nEqualRows > 1)
1373 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, OUString::number(nEqualRows));
1376 StartElement( sElemRow, true);
1379 void ScXMLExport::OpenHeaderRows()
1381 StartElement( XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true);
1382 bRowHeaderOpen = true;
1385 void ScXMLExport::CloseHeaderRows()
1387 EndElement(XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true);
1390 void ScXMLExport::OpenNewRow(
1391 const sal_Int32 nIndex, const sal_Int32 nStartRow, const sal_Int32 nEqualRows,
1392 bool bHidden, bool bFiltered)
1394 nOpenRow = nStartRow;
1395 if (pGroupRows->IsGroupStart(nStartRow))
1397 if (bHasRowHeader && bRowHeaderOpen)
1398 CloseHeaderRows();
1399 pGroupRows->OpenGroups(nStartRow);
1400 if (bHasRowHeader && bRowHeaderOpen)
1401 OpenHeaderRows();
1403 if (bHasRowHeader && !bRowHeaderOpen && nStartRow >= aRowHeaderRange.aStart.Row() && nStartRow <= aRowHeaderRange.aEnd.Row())
1405 if (nStartRow == aRowHeaderRange.aStart.Row())
1406 OpenHeaderRows();
1407 sal_Int32 nEquals;
1408 if (aRowHeaderRange.aEnd.Row() < nStartRow + nEqualRows - 1)
1409 nEquals = aRowHeaderRange.aEnd.Row() - nStartRow + 1;
1410 else
1411 nEquals = nEqualRows;
1412 WriteRowStartTag(nIndex, nEquals, bHidden, bFiltered);
1413 nOpenRow = nStartRow + nEquals - 1;
1414 if (nEquals < nEqualRows)
1416 CloseRow(nStartRow + nEquals - 1);
1417 WriteRowStartTag(nIndex, nEqualRows - nEquals, bHidden, bFiltered);
1418 nOpenRow = nStartRow + nEqualRows - 1;
1421 else
1422 WriteRowStartTag(nIndex, nEqualRows, bHidden, bFiltered);
1425 void ScXMLExport::OpenAndCloseRow(
1426 const sal_Int32 nIndex, const sal_Int32 nStartRow, const sal_Int32 nEqualRows,
1427 bool bHidden, bool bFiltered)
1429 OpenNewRow(nIndex, nStartRow, nEqualRows, bHidden, bFiltered);
1430 WriteRowContent();
1431 CloseRow(nStartRow + nEqualRows - 1);
1432 pRowFormatRanges->Clear();
1435 void ScXMLExport::OpenRow(const sal_Int32 nTable, const sal_Int32 nStartRow, const sal_Int32 nRepeatRow, ScXMLCachedRowAttrAccess& rRowAttr)
1437 if (nRepeatRow > 1)
1439 sal_Int32 nPrevIndex(0), nIndex;
1440 bool bPrevHidden = false;
1441 bool bPrevFiltered = false;
1442 bool bHidden = false;
1443 bool bFiltered = false;
1444 sal_Int32 nEqualRows(1);
1445 sal_Int32 nEndRow(nStartRow + nRepeatRow);
1446 sal_Int32 nEndRowHidden = nStartRow - 1;
1447 sal_Int32 nEndRowFiltered = nStartRow - 1;
1448 sal_Int32 nRow;
1449 for (nRow = nStartRow; nRow < nEndRow; ++nRow)
1451 if (nRow == nStartRow)
1453 nPrevIndex = pRowStyles->GetStyleNameIndex(nTable, nRow);
1454 if (nRow > nEndRowHidden)
1456 bPrevHidden = rRowAttr.rowHidden(nTable, nRow, nEndRowHidden);
1457 bHidden = bPrevHidden;
1459 if (nRow > nEndRowFiltered)
1461 bPrevFiltered = rRowAttr.rowFiltered(nTable, nRow, nEndRowFiltered);
1462 bFiltered = bPrevFiltered;
1466 else
1468 nIndex = pRowStyles->GetStyleNameIndex(nTable, nRow);
1469 if (nRow > nEndRowHidden)
1470 bHidden = rRowAttr.rowHidden(nTable, nRow, nEndRowHidden);
1471 if (nRow > nEndRowFiltered)
1472 bFiltered = rRowAttr.rowFiltered(nTable, nRow, nEndRowFiltered);
1473 if (nIndex == nPrevIndex && bHidden == bPrevHidden && bFiltered == bPrevFiltered &&
1474 !(bHasRowHeader && ((nRow == aRowHeaderRange.aStart.Row()) || (nRow - 1 == aRowHeaderRange.aEnd.Row()))) &&
1475 !(pGroupRows->IsGroupStart(nRow)) &&
1476 !(pGroupRows->IsGroupEnd(nRow - 1)))
1477 ++nEqualRows;
1478 else
1480 assert(nPrevIndex >= 0 && "coverity#1438402");
1481 ScRowFormatRanges* pTempRowFormatRanges = new ScRowFormatRanges(pRowFormatRanges.get());
1482 OpenAndCloseRow(nPrevIndex, nRow - nEqualRows, nEqualRows, bPrevHidden, bPrevFiltered);
1483 pRowFormatRanges.reset(pTempRowFormatRanges);
1484 nEqualRows = 1;
1485 nPrevIndex = nIndex;
1486 bPrevHidden = bHidden;
1487 bPrevFiltered = bFiltered;
1491 assert(nPrevIndex >= 0 && "coverity#1438402");
1492 OpenNewRow(nPrevIndex, nRow - nEqualRows, nEqualRows, bPrevHidden, bPrevFiltered);
1494 else
1496 sal_Int32 nIndex = pRowStyles->GetStyleNameIndex(nTable, nStartRow);
1497 bool bHidden = false;
1498 bool bFiltered = false;
1499 sal_Int32 nEndRowHidden;
1500 sal_Int32 nEndRowFiltered;
1501 bHidden = rRowAttr.rowHidden(nTable, nStartRow, nEndRowHidden);
1502 bFiltered = rRowAttr.rowFiltered(nTable, nStartRow, nEndRowFiltered);
1503 assert(nIndex >= 0 && "coverity#1438402");
1504 OpenNewRow(nIndex, nStartRow, 1, bHidden, bFiltered);
1506 nOpenRow = nStartRow + nRepeatRow - 1;
1509 void ScXMLExport::CloseRow(const sal_Int32 nRow)
1511 if (nOpenRow > -1)
1513 EndElement(sElemRow, true);
1514 if (bHasRowHeader && nRow == aRowHeaderRange.aEnd.Row())
1516 CloseHeaderRows();
1517 bRowHeaderOpen = false;
1519 if (pGroupRows->IsGroupEnd(nRow))
1521 if (bHasRowHeader && bRowHeaderOpen)
1522 CloseHeaderRows();
1523 pGroupRows->CloseGroups(nRow);
1524 if (bHasRowHeader && bRowHeaderOpen)
1525 OpenHeaderRows();
1528 nOpenRow = -1;
1531 void ScXMLExport::ExportFormatRanges(ScDocument& rDoc, const sal_Int32 nStartCol, const sal_Int32 nStartRow,
1532 const sal_Int32 nEndCol, const sal_Int32 nEndRow, const sal_Int32 nSheet)
1534 pRowFormatRanges->Clear();
1535 ScXMLCachedRowAttrAccess aRowAttr(&rDoc);
1536 if (nStartRow == nEndRow)
1538 pCellStyles->GetFormatRanges(nStartCol, nEndCol, nStartRow, nSheet, pRowFormatRanges.get());
1539 if (nOpenRow == - 1)
1540 OpenRow(nSheet, nStartRow, 1, aRowAttr);
1541 WriteRowContent();
1542 pRowFormatRanges->Clear();
1544 else
1546 if (nOpenRow > -1)
1548 pCellStyles->GetFormatRanges(nStartCol, pSharedData->GetLastColumn(nSheet), nStartRow, nSheet, pRowFormatRanges.get());
1549 WriteRowContent();
1550 CloseRow(nStartRow);
1551 sal_Int32 nRows(1);
1552 sal_Int32 nTotalRows(nEndRow - nStartRow + 1 - 1);
1553 while (nRows < nTotalRows)
1555 pRowFormatRanges->Clear();
1556 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1557 sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows();
1558 assert(nMaxRows && "ScXMLExport::ExportFormatRanges cannot make progress with zero rows, something went wrong");
1559 if (!nMaxRows)
1561 uno::Sequence<OUString> aEmptySeq;
1562 SetError(XMLERROR_CANCEL|XMLERROR_FLAG_SEVERE, aEmptySeq);
1563 break;
1565 if (nMaxRows >= nTotalRows - nRows)
1567 OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, aRowAttr);
1568 nRows += nTotalRows - nRows;
1570 else
1572 OpenRow(nSheet, nStartRow + nRows, nMaxRows, aRowAttr);
1573 nRows += nMaxRows;
1575 if (!pRowFormatRanges->GetSize())
1576 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1577 WriteRowContent();
1578 CloseRow(nStartRow + nRows - 1);
1580 if (nTotalRows == 1)
1581 CloseRow(nStartRow);
1582 OpenRow(nSheet, nEndRow, 1, aRowAttr);
1583 pRowFormatRanges->Clear();
1584 pCellStyles->GetFormatRanges(0, nEndCol, nEndRow, nSheet, pRowFormatRanges.get());
1585 WriteRowContent();
1587 else
1589 sal_Int32 nRows(0);
1590 sal_Int32 nTotalRows(nEndRow - nStartRow + 1 - 1);
1591 while (nRows < nTotalRows)
1593 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1594 sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows();
1595 OSL_ENSURE(nMaxRows, "something went wrong");
1596 if (nMaxRows >= nTotalRows - nRows)
1598 OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, aRowAttr);
1599 nRows += nTotalRows - nRows;
1601 else
1603 OpenRow(nSheet, nStartRow + nRows, nMaxRows, aRowAttr);
1604 nRows += nMaxRows;
1606 if (!pRowFormatRanges->GetSize())
1607 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1608 WriteRowContent();
1609 CloseRow(nStartRow + nRows - 1);
1611 OpenRow(nSheet, nEndRow, 1, aRowAttr);
1612 pRowFormatRanges->Clear();
1613 pCellStyles->GetFormatRanges(0, nEndCol, nEndRow, nSheet, pRowFormatRanges.get());
1614 WriteRowContent();
1619 void ScXMLExport::GetColumnRowHeader(ScDocument& rDoc, bool& rHasColumnHeader, ScRange& rColumnHeaderRange,
1620 bool& rHasRowHeader, ScRange& rRowHeaderRange,
1621 OUString& rPrintRanges) const
1623 uno::Reference <sheet::XPrintAreas> xPrintAreas (xCurrentTable, uno::UNO_QUERY);
1624 if (!xPrintAreas.is())
1625 return;
1627 rHasRowHeader = xPrintAreas->getPrintTitleRows();
1628 rHasColumnHeader = xPrintAreas->getPrintTitleColumns();
1629 table::CellRangeAddress rTempRowHeaderRange = xPrintAreas->getTitleRows();
1630 rRowHeaderRange = ScRange(rTempRowHeaderRange.StartColumn,
1631 rTempRowHeaderRange.StartRow,
1632 rTempRowHeaderRange.Sheet,
1633 rTempRowHeaderRange.EndColumn,
1634 rTempRowHeaderRange.EndRow,
1635 rTempRowHeaderRange.Sheet);
1636 table::CellRangeAddress rTempColumnHeaderRange = xPrintAreas->getTitleColumns();
1637 rColumnHeaderRange = ScRange(rTempColumnHeaderRange.StartColumn,
1638 rTempColumnHeaderRange.StartRow,
1639 rTempColumnHeaderRange.Sheet,
1640 rTempColumnHeaderRange.EndColumn,
1641 rTempColumnHeaderRange.EndRow,
1642 rTempColumnHeaderRange.Sheet);
1643 uno::Sequence< table::CellRangeAddress > aRangeList( xPrintAreas->getPrintAreas() );
1644 ScRangeStringConverter::GetStringFromRangeList( rPrintRanges, aRangeList, &rDoc, FormulaGrammar::CONV_OOO );
1647 void ScXMLExport::FillFieldGroup(ScOutlineArray* pFields, ScMyOpenCloseColumnRowGroup* pGroups)
1649 size_t nDepth = pFields->GetDepth();
1650 for (size_t i = 0; i < nDepth; ++i)
1652 size_t nFields = pFields->GetCount(i);
1653 for (size_t j = 0; j < nFields; ++j)
1655 ScMyColumnRowGroup aGroup;
1656 const ScOutlineEntry* pEntry = pFields->GetEntry(i, j);
1657 aGroup.nField = pEntry->GetStart();
1658 aGroup.nLevel = static_cast<sal_Int16>(i);
1659 aGroup.bDisplay = !(pEntry->IsHidden());
1660 pGroups->AddGroup(aGroup, pEntry->GetEnd());
1663 if (nDepth)
1664 pGroups->Sort();
1667 void ScXMLExport::FillColumnRowGroups(ScDocument& rDoc)
1669 ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable( static_cast<SCTAB>(nCurrentTable) );
1670 if(pOutlineTable)
1672 ScOutlineArray& rCols(pOutlineTable->GetColArray());
1673 ScOutlineArray& rRows(pOutlineTable->GetRowArray());
1674 FillFieldGroup(&rCols, pGroupColumns.get());
1675 FillFieldGroup(&rRows, pGroupRows.get());
1676 pSharedData->SetLastColumn(nCurrentTable, pGroupColumns->GetLast());
1677 pSharedData->SetLastRow(nCurrentTable, pGroupRows->GetLast());
1681 void ScXMLExport::SetBodyAttributes()
1683 ScDocument* pDoc = GetDocument();
1684 if (!(pDoc && pDoc->IsDocProtected()))
1685 return;
1687 AddAttribute(XML_NAMESPACE_TABLE, XML_STRUCTURE_PROTECTED, XML_TRUE);
1688 OUStringBuffer aBuffer;
1689 uno::Sequence<sal_Int8> aPassHash;
1690 ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED;
1691 const ScDocProtection* p = pDoc->GetDocProtection();
1692 if (p)
1694 if (p->hasPasswordHash(PASSHASH_SHA1))
1696 aPassHash = p->getPasswordHash(PASSHASH_SHA1);
1697 eHashUsed = PASSHASH_SHA1;
1699 else if (p->hasPasswordHash(PASSHASH_SHA256))
1701 aPassHash = p->getPasswordHash(PASSHASH_SHA256);
1702 eHashUsed = PASSHASH_SHA256;
1704 else if (p->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
1706 aPassHash = p->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
1707 eHashUsed = PASSHASH_XL;
1710 ::comphelper::Base64::encode(aBuffer, aPassHash);
1711 if (aBuffer.isEmpty())
1712 return;
1714 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
1715 if (getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012)
1716 return;
1718 if (eHashUsed == PASSHASH_XL)
1720 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
1721 ScPassHashHelper::getHashURI(PASSHASH_XL));
1722 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
1723 AddAttribute(XML_NAMESPACE_LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2,
1724 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
1726 else if (eHashUsed == PASSHASH_SHA1)
1728 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
1729 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
1731 else if (eHashUsed == PASSHASH_SHA256)
1733 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
1734 ScPassHashHelper::getHashURI(PASSHASH_SHA256));
1738 static bool lcl_CopyStreamElement( const uno::Reference< io::XInputStream >& xInput,
1739 const uno::Reference< io::XOutputStream >& xOutput,
1740 sal_Int64 nCount )
1742 const sal_Int32 nBufSize = 16*1024;
1743 uno::Sequence<sal_Int8> aSequence(nBufSize);
1745 sal_Int64 nRemaining = nCount;
1746 bool bFirst = true;
1748 while ( nRemaining > 0 )
1750 sal_Int32 nRead = xInput->readBytes( aSequence, std::min( nRemaining, static_cast<sal_Int64>(nBufSize) ) );
1751 if (bFirst)
1753 // safety check: Make sure the copied part actually points to the start of an element
1754 if ( nRead < 1 || aSequence[0] != static_cast<sal_Int8>('<') )
1756 return false; // abort and set an error
1758 bFirst = false;
1760 if (nRead == nRemaining)
1762 // safety check: Make sure the copied part also ends at the end of an element
1763 if ( aSequence[nRead-1] != static_cast<sal_Int8>('>') )
1765 return false; // abort and set an error
1769 if ( nRead == nBufSize )
1771 xOutput->writeBytes( aSequence );
1772 nRemaining -= nRead;
1774 else
1776 if ( nRead > 0 )
1778 uno::Sequence<sal_Int8> aTempBuf( aSequence.getConstArray(), nRead );
1779 xOutput->writeBytes( aTempBuf );
1781 nRemaining = 0;
1784 return true; // successful
1787 static void lcl_SkipBytesInBlocks( const uno::Reference< io::XInputStream >& xInput, sal_Int64 nBytesToSkip )
1789 // skipBytes in zip stream is implemented as reading.
1790 // For now, split into several calls to avoid allocating a large buffer.
1791 // Later, skipBytes should be changed.
1793 const sal_Int64 nMaxSize = 32*1024;
1795 if ( nBytesToSkip > 0 )
1797 sal_Int64 nRemaining = nBytesToSkip;
1798 while ( nRemaining > 0 )
1800 sal_Int32 nSkip = std::min( nRemaining, nMaxSize );
1801 xInput->skipBytes( nSkip );
1802 nRemaining -= nSkip;
1807 void ScXMLExport::CopySourceStream( sal_Int64 nStartOffset, sal_Int64 nEndOffset, sal_Int64& rNewStart, sal_Int64& rNewEnd )
1809 uno::Reference<xml::sax::XDocumentHandler> xHandler = GetDocHandler();
1810 uno::Reference<io::XActiveDataSource> xDestSource( xHandler, uno::UNO_QUERY );
1811 if ( !xDestSource.is() )
1812 return;
1814 uno::Reference<io::XOutputStream> xDestStream = xDestSource->getOutputStream();
1815 uno::Reference<io::XSeekable> xDestSeek( xDestStream, uno::UNO_QUERY );
1816 if ( !xDestSeek.is() )
1817 return;
1819 // temporary: set same stream again to clear buffer
1820 xDestSource->setOutputStream( xDestStream );
1822 if ( getExportFlags() & SvXMLExportFlags::PRETTY )
1824 static constexpr OString aOutStr("\n "_ostr);
1825 uno::Sequence<sal_Int8> aOutSeq( reinterpret_cast<sal_Int8 const *>(aOutStr.getStr()), aOutStr.getLength() );
1826 xDestStream->writeBytes( aOutSeq );
1829 rNewStart = xDestSeek->getPosition();
1831 if ( nStartOffset > nSourceStreamPos )
1832 lcl_SkipBytesInBlocks( xSourceStream, nStartOffset - nSourceStreamPos );
1834 if ( !lcl_CopyStreamElement( xSourceStream, xDestStream, nEndOffset - nStartOffset ) )
1836 // If copying went wrong, set an error.
1837 // ScXMLImportWrapper then resets all stream flags, so the next save attempt will use normal saving.
1839 uno::Sequence<OUString> aEmptySeq;
1840 SetError(XMLERROR_CANCEL|XMLERROR_FLAG_SEVERE, aEmptySeq);
1842 nSourceStreamPos = nEndOffset;
1844 rNewEnd = xDestSeek->getPosition();
1847 const ScXMLEditAttributeMap& ScXMLExport::GetEditAttributeMap() const
1849 if (!mpEditAttrMap)
1850 mpEditAttrMap.reset(new ScXMLEditAttributeMap);
1851 return *mpEditAttrMap;
1854 void ScXMLExport::RegisterDefinedStyleNames( const uno::Reference< css::sheet::XSpreadsheetDocument > & xSpreadDoc )
1856 ScFormatSaveData* pFormatData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetFormatSaveData();
1857 auto xAutoStylePool = GetAutoStylePool();
1858 for (const auto& rFormatInfo : pFormatData->maIDToName)
1860 xAutoStylePool->RegisterDefinedName(XmlStyleFamily::TABLE_CELL, rFormatInfo.second);
1864 void ScXMLExport::ExportContent_()
1866 nCurrentTable = 0;
1867 if (!pSharedData)
1869 SCTAB nTableCount(0);
1870 sal_Int32 nShapesCount(0);
1871 CollectSharedData(nTableCount, nShapesCount);
1872 OSL_FAIL("no shared data set");
1873 if (!pSharedData)
1874 return;
1876 ScXMLExportDatabaseRanges aExportDatabaseRanges(*this);
1877 if (!GetModel().is())
1878 return;
1880 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
1881 if ( !xSpreadDoc.is() )
1882 return;
1884 ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc);
1886 ScDocument* pDoc = pModel->GetDocument();
1887 if (!pDoc)
1889 SAL_WARN("sc", "no ScDocument!");
1890 return;
1893 ScSheetSaveData* pSheetData = pModel->GetSheetSaveData();
1894 if (pSheetData)
1895 pSheetData->ResetSaveEntries();
1897 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
1898 if ( xIndex.is() )
1900 //_GetNamespaceMap().ClearQNamesCache();
1901 pChangeTrackingExportHelper->CollectAndWriteChanges();
1902 WriteCalculationSettings(*pDoc, xSpreadDoc);
1903 sal_Int32 nTableCount(xIndex->getCount());
1904 ScMyAreaLinksContainer aAreaLinks = GetAreaLinks(*pDoc);
1905 ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges());
1906 ScMyDetectiveOpContainer aDetectiveOpContainer = GetDetectiveOpList(*pDoc);
1908 pMergedRangesContainer->Sort();
1909 pSharedData->GetDetectiveObjContainer()->Sort();
1911 mpCellsItr->Clear();
1912 mpCellsItr->SetShapes( pSharedData->GetShapesContainer() );
1913 mpCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() );
1914 mpCellsItr->SetMergedRanges( pMergedRangesContainer.get() );
1915 mpCellsItr->SetAreaLinks( &aAreaLinks );
1916 mpCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges );
1917 mpCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() );
1918 mpCellsItr->SetDetectiveOp( &aDetectiveOpContainer );
1920 if (nTableCount > 0)
1921 pValidationsContainer->WriteValidations(*pDoc, *this);
1922 WriteTheLabelRanges(*pDoc, xSpreadDoc);
1923 for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable)
1925 sal_Int64 nStartOffset = -1;
1926 sal_Int64 nEndOffset = -1;
1927 if (pSheetData && pDoc->IsStreamValid(static_cast<SCTAB>(nTable)) && !pDoc->GetChangeTrack())
1928 pSheetData->GetStreamPos( nTable, nStartOffset, nEndOffset );
1930 if ( nStartOffset >= 0 && nEndOffset >= 0 && xSourceStream.is() )
1932 sal_Int64 nNewStart = -1;
1933 sal_Int64 nNewEnd = -1;
1934 CopySourceStream( nStartOffset, nEndOffset, nNewStart, nNewEnd );
1936 // store position of copied sheet in output
1937 pSheetData->AddSavePos( nTable, nNewStart, nNewEnd );
1939 // skip iterator entries for this sheet
1940 mpCellsItr->SkipTable(static_cast<SCTAB>(nTable));
1942 else
1944 uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
1945 WriteTable(*pDoc, nTable, xTable);
1947 IncrementProgressBar(false);
1950 WriteExternalRefCaches(*pDoc);
1951 WriteNamedExpressions(*pDoc);
1952 WriteDataStream(*pDoc);
1953 aExportDatabaseRanges.WriteDatabaseRanges(*pDoc);
1954 WriteExternalDataMapping(*pDoc);
1955 ScXMLExportDataPilot aExportDataPilot(*this);
1956 aExportDataPilot.WriteDataPilots(*pDoc);
1957 WriteConsolidation(*pDoc);
1958 ScXMLExportDDELinks aExportDDELinks(*pDoc, *this);
1959 aExportDDELinks.WriteDDELinks(xSpreadDoc);
1960 IncrementProgressBar(true, 0);
1961 GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference());
1964 void ScXMLExport::ExportStyles_( bool bUsed )
1966 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
1967 if (xSpreadDoc.is())
1968 RegisterDefinedStyleNames( xSpreadDoc);
1970 if (!pSharedData)
1972 SCTAB nTableCount(0);
1973 sal_Int32 nShapesCount(0);
1974 CollectSharedData(nTableCount, nShapesCount);
1976 rtl::Reference<XMLCellStyleExport> aStylesExp(new XMLCellStyleExport(*this, GetAutoStylePool().get()));
1977 if (GetModel().is())
1979 uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetModel(), uno::UNO_QUERY);
1980 if (xMultiServiceFactory.is())
1982 uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance(u"com.sun.star.sheet.Defaults"_ustr), uno::UNO_QUERY);
1983 if (xProperties.is())
1984 aStylesExp->exportDefaultStyle(xProperties, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, xCellStylesExportPropertySetMapper);
1985 GetShapeExport()->ExportGraphicDefaults();
1987 collectDataStyles(false);
1989 exportDataStyles();
1991 aStylesExp->exportStyleFamily(u"CellStyles"_ustr,
1992 XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, xCellStylesExportPropertySetMapper, false, XmlStyleFamily::TABLE_CELL);
1994 SvXMLExport::ExportStyles_(bUsed);
1996 exportTheme();
1999 void ScXMLExport::exportTheme()
2001 if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
2002 return;
2004 ScDocument* pDoc = GetDocument();
2005 if (!pDoc)
2006 return;
2008 SdrModel* pModel = pDoc->GetDrawLayer();
2009 if (!pModel)
2010 return;
2012 auto const& pTheme = pModel->getTheme();
2013 if (!pTheme)
2014 return;
2016 ExportThemeElement(pTheme);
2019 void ScXMLExport::AddStyleFromCells(const uno::Reference<beans::XPropertySet>& xProperties,
2020 const uno::Reference<sheet::XSpreadsheet>& xTable,
2021 sal_Int32 nTable, const OUString* pOldName)
2023 css::uno::Any aAny = xProperties->getPropertyValue(u"FormatID"_ustr);
2024 sal_uInt64 nKey = 0;
2025 aAny >>= nKey;
2027 //! pass xCellRanges instead
2028 uno::Reference<sheet::XSheetCellRanges> xCellRanges( xProperties, uno::UNO_QUERY );
2030 OUString sStyleName;
2031 sal_Int32 nNumberFormat(-1);
2032 sal_Int32 nValidationIndex(-1);
2033 std::vector<XMLPropertyState> aPropStates(xCellStylesExportPropertySetMapper->Filter(*this, xProperties));
2034 std::vector< XMLPropertyState >::iterator aItr(aPropStates.begin());
2035 std::vector< XMLPropertyState >::iterator aEndItr(aPropStates.end());
2036 sal_Int32 nCount(0);
2037 while (aItr != aEndItr)
2039 if (aItr->mnIndex != -1)
2041 switch (xCellStylesPropertySetMapper->GetEntryContextId(aItr->mnIndex))
2043 case CTF_SC_VALIDATION :
2045 pValidationsContainer->AddValidation(aItr->maValue, nValidationIndex);
2046 // this is not very slow, because it is most the last property or
2047 // if it is not the last property it is the property before the last property,
2048 // so in the worst case only one property has to be copied, but in the best case no
2049 // property has to be copied
2050 aItr = aPropStates.erase(aItr);
2051 aEndItr = aPropStates.end(); // old aEndItr is invalidated!
2053 break;
2054 case CTF_SC_CELLSTYLE :
2056 aItr->maValue >>= sStyleName;
2057 aItr->mnIndex = -1;
2058 ++aItr;
2059 ++nCount;
2061 break;
2062 case CTF_SC_NUMBERFORMAT :
2064 if (aItr->maValue >>= nNumberFormat)
2065 addDataStyle(nNumberFormat);
2066 ++aItr;
2067 ++nCount;
2069 break;
2070 default:
2072 ++aItr;
2073 ++nCount;
2075 break;
2078 else
2080 ++aItr;
2081 ++nCount;
2084 if (nCount == 1) // this is the CellStyle and should be removed if alone
2085 aPropStates.clear();
2086 if (nNumberFormat == -1)
2087 xProperties->getPropertyValue(SC_UNONAME_NUMFMT) >>= nNumberFormat;
2088 if (sStyleName.isEmpty())
2089 return;
2091 if (!aPropStates.empty())
2093 sal_Int32 nIndex;
2094 if (pOldName)
2096 if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates)))
2098 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_CELL, *pOldName);
2099 // add to pCellStyles, so the name is found for normal sheets
2100 pCellStyles->AddStyleName(*pOldName, nIndex);
2103 else
2105 OUString sName;
2106 bool bAdded = false;
2107 if (nKey)
2109 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
2110 ScFormatSaveData* pFormatData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetFormatSaveData();
2111 auto itr = pFormatData->maIDToName.find(nKey);
2112 if (itr != pFormatData->maIDToName.end())
2114 sName = itr->second;
2115 bAdded = GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TABLE_CELL, sStyleName, aPropStates);
2116 if (bAdded)
2117 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_CELL, sName);
2120 bool bIsAutoStyle(true);
2121 if (bAdded || GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates)))
2123 pCellStyles->AddStyleName(sName, nIndex);
2125 else
2126 nIndex = pCellStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX, bIsAutoStyle);
2128 const uno::Sequence<table::CellRangeAddress> aAddresses(xCellRanges->getRangeAddresses());
2129 bool bGetMerge(true);
2130 for (table::CellRangeAddress const & address : aAddresses)
2132 pSharedData->SetLastColumn(nTable, address.EndColumn);
2133 pSharedData->SetLastRow(nTable, address.EndRow);
2134 pCellStyles->AddRangeStyleName(address, nIndex, bIsAutoStyle, nValidationIndex, nNumberFormat);
2135 if (bGetMerge)
2136 bGetMerge = GetMerged(&address, xTable);
2140 else
2142 OUString sEncodedStyleName(EncodeStyleName(sStyleName));
2143 sal_Int32 nIndex(0);
2144 pCellStyles->AddStyleName(sEncodedStyleName, nIndex, false);
2145 if ( !pOldName )
2147 const uno::Sequence<table::CellRangeAddress> aAddresses(xCellRanges->getRangeAddresses());
2148 bool bGetMerge(true);
2149 for (table::CellRangeAddress const & address : aAddresses)
2151 if (bGetMerge)
2152 bGetMerge = GetMerged(&address, xTable);
2153 pCellStyles->AddRangeStyleName(address, nIndex, false, nValidationIndex, nNumberFormat);
2154 if( sStyleName != "Default" || nValidationIndex != -1 )
2156 pSharedData->SetLastColumn(nTable, address.EndColumn);
2157 pSharedData->SetLastRow(nTable, address.EndRow);
2164 void ScXMLExport::AddStyleFromColumn(const uno::Reference<beans::XPropertySet>& xColumnProperties,
2165 const OUString* pOldName, sal_Int32& rIndex, bool& rIsVisible)
2167 std::vector<XMLPropertyState> aPropStates(xColumnStylesExportPropertySetMapper->Filter(*this, xColumnProperties));
2168 if(aPropStates.empty())
2169 return;
2171 auto aItr = std::find_if(aPropStates.begin(), aPropStates.end(),
2172 [this](const XMLPropertyState& rPropState) {
2173 return xColumnStylesPropertySetMapper->GetEntryContextId(rPropState.mnIndex) == CTF_SC_ISVISIBLE; });
2174 if (aItr != aPropStates.end())
2176 aItr->maValue >>= rIsVisible;
2179 const OUString sParent;
2180 if (pOldName)
2182 if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_COLUMN, sParent, std::move(aPropStates)))
2184 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_COLUMN, *pOldName);
2185 // add to pColumnStyles, so the name is found for normal sheets
2186 rIndex = pColumnStyles->AddStyleName(*pOldName);
2189 else
2191 OUString sName;
2192 if (GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_COLUMN, sParent, std::move(aPropStates)))
2194 rIndex = pColumnStyles->AddStyleName(sName);
2196 else
2197 rIndex = pColumnStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX);
2201 void ScXMLExport::AddStyleFromRow(const uno::Reference<beans::XPropertySet>& xRowProperties,
2202 const OUString* pOldName, sal_Int32& rIndex)
2204 std::vector<XMLPropertyState> aPropStates(xRowStylesExportPropertySetMapper->Filter(*this, xRowProperties));
2205 if(aPropStates.empty())
2206 return;
2208 const OUString sParent;
2209 if (pOldName)
2211 if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_ROW, sParent, std::move(aPropStates)))
2213 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_ROW, *pOldName);
2214 // add to pRowStyles, so the name is found for normal sheets
2215 rIndex = pRowStyles->AddStyleName(*pOldName);
2218 else
2220 OUString sName;
2221 if (GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_ROW, sParent, std::move(aPropStates)))
2223 rIndex = pRowStyles->AddStyleName(sName);
2225 else
2226 rIndex = pRowStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX);
2230 static uno::Any lcl_GetEnumerated( uno::Reference<container::XEnumerationAccess> const & xEnumAccess, sal_Int32 nIndex )
2232 uno::Any aRet;
2233 uno::Reference<container::XEnumeration> xEnum( xEnumAccess->createEnumeration() );
2236 sal_Int32 nSkip = nIndex;
2237 while ( nSkip > 0 )
2239 (void) xEnum->nextElement();
2240 --nSkip;
2242 aRet = xEnum->nextElement();
2244 catch (container::NoSuchElementException&)
2246 // leave aRet empty
2248 return aRet;
2251 void ScXMLExport::collectAutoStyles()
2253 SvXMLExport::collectAutoStyles();
2255 if (mbAutoStylesCollected)
2256 return;
2258 if (!GetModel().is())
2259 return;
2261 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
2262 if (!xSpreadDoc.is())
2263 return;
2265 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
2266 if (!xIndex.is())
2267 return;
2269 if (getExportFlags() & SvXMLExportFlags::CONTENT)
2271 // Reserve the loaded cell style names.
2272 RegisterDefinedStyleNames( xSpreadDoc);
2274 ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc);
2275 ScDocument* pDoc = pModel->GetDocument();
2276 if (pDoc)
2278 // re-create automatic styles with old names from stored data
2279 ScSheetSaveData* pSheetData = pModel->GetSheetSaveData();
2280 if (pSheetData)
2282 // formulas have to be calculated now, to detect changed results
2283 // (during normal save, they will be calculated anyway)
2284 SCTAB nTabCount = pDoc->GetTableCount();
2285 for (SCTAB nTab=0; nTab<nTabCount; ++nTab)
2286 if (pDoc->IsStreamValid(nTab))
2287 pDoc->InterpretDirtyCells(ScRange(0, 0, nTab, pDoc->MaxCol(), pDoc->MaxRow(), nTab));
2289 // stored cell styles
2290 const std::vector<ScCellStyleEntry>& rCellEntries = pSheetData->GetCellStyles();
2291 for (const auto& rCellEntry : rCellEntries)
2293 ScAddress aPos = rCellEntry.maCellPos;
2294 sal_Int32 nTable = aPos.Tab();
2295 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2296 if (bCopySheet)
2298 uno::Reference <sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2299 uno::Reference <beans::XPropertySet> xProperties(
2300 xTable->getCellByPosition( aPos.Col(), aPos.Row() ), uno::UNO_QUERY );
2302 AddStyleFromCells(xProperties, xTable, nTable, &rCellEntry.maName);
2306 // stored column styles
2307 const std::vector<ScCellStyleEntry>& rColumnEntries = pSheetData->GetColumnStyles();
2308 for (const auto& rColumnEntry : rColumnEntries)
2310 ScAddress aPos = rColumnEntry.maCellPos;
2311 sal_Int32 nTable = aPos.Tab();
2312 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2313 if (bCopySheet)
2315 uno::Reference<table::XColumnRowRange> xColumnRowRange(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2316 uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns());
2317 uno::Reference<beans::XPropertySet> xColumnProperties(xTableColumns->getByIndex( aPos.Col() ), uno::UNO_QUERY);
2319 sal_Int32 nIndex(-1);
2320 bool bIsVisible(true);
2321 AddStyleFromColumn( xColumnProperties, &rColumnEntry.maName, nIndex, bIsVisible );
2325 // stored row styles
2326 const std::vector<ScCellStyleEntry>& rRowEntries = pSheetData->GetRowStyles();
2327 for (const auto& rRowEntry : rRowEntries)
2329 ScAddress aPos = rRowEntry.maCellPos;
2330 sal_Int32 nTable = aPos.Tab();
2331 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2332 if (bCopySheet)
2334 uno::Reference<table::XColumnRowRange> xColumnRowRange(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2335 uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows());
2336 uno::Reference<beans::XPropertySet> xRowProperties(xTableRows->getByIndex( aPos.Row() ), uno::UNO_QUERY);
2338 sal_Int32 nIndex(-1);
2339 AddStyleFromRow( xRowProperties, &rRowEntry.maName, nIndex );
2343 // stored table styles
2344 const std::vector<ScCellStyleEntry>& rTableEntries = pSheetData->GetTableStyles();
2345 for (const auto& rTableEntry : rTableEntries)
2347 ScAddress aPos = rTableEntry.maCellPos;
2348 sal_Int32 nTable = aPos.Tab();
2349 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2350 if (bCopySheet)
2352 //! separate method AddStyleFromTable needed?
2353 uno::Reference<beans::XPropertySet> xTableProperties(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2354 if (xTableProperties.is())
2356 std::vector<XMLPropertyState> aPropStates(xTableStylesExportPropertySetMapper->Filter(*this, xTableProperties));
2357 OUString sName( rTableEntry.maName );
2358 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TABLE_TABLE, OUString(), std::move(aPropStates));
2359 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_TABLE, sName);
2364 // stored styles for notes
2366 rtl::Reference<SvXMLExportPropertyMapper> xShapeMapper = XMLShapeExport::CreateShapePropMapper( *this );
2368 const std::vector<ScNoteStyleEntry>& rNoteEntries = pSheetData->GetNoteStyles();
2369 for (const auto& rNoteEntry : rNoteEntries)
2371 ScAddress aPos = rNoteEntry.maCellPos;
2372 SCTAB nTable = aPos.Tab();
2373 bool bCopySheet = pDoc->IsStreamValid( nTable );
2374 if (bCopySheet)
2376 //! separate method AddStyleFromNote needed?
2378 ScPostIt* pNote = pDoc->GetNote(aPos);
2379 OSL_ENSURE( pNote, "note not found" );
2380 if (pNote)
2382 SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
2383 // all uno shapes are created anyway in CollectSharedData
2384 uno::Reference<beans::XPropertySet> xShapeProperties( pDrawObj->getUnoShape(), uno::UNO_QUERY );
2385 if (xShapeProperties.is())
2387 if ( !rNoteEntry.maStyleName.isEmpty() )
2389 std::vector<XMLPropertyState> aPropStates(xShapeMapper->Filter(*this, xShapeProperties));
2390 OUString sName( rNoteEntry.maStyleName );
2391 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::SD_GRAPHICS_ID, OUString(), std::move(aPropStates));
2392 GetAutoStylePool()->RegisterName(XmlStyleFamily::SD_GRAPHICS_ID, sName);
2394 if ( !rNoteEntry.maTextStyle.isEmpty() )
2396 std::vector<XMLPropertyState> aPropStates(
2397 GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(*this, xShapeProperties));
2398 OUString sName( rNoteEntry.maTextStyle );
2399 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_PARAGRAPH, OUString(), std::move(aPropStates));
2400 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_PARAGRAPH, sName);
2407 // note paragraph styles
2409 rtl::Reference<SvXMLExportPropertyMapper> xParaPropMapper = GetTextParagraphExport()->GetParagraphPropertyMapper();
2411 const std::vector<ScTextStyleEntry>& rNoteParaEntries = pSheetData->GetNoteParaStyles();
2412 for (const auto& rNoteParaEntry : rNoteParaEntries)
2414 ScAddress aPos = rNoteParaEntry.maCellPos;
2415 SCTAB nTable = aPos.Tab();
2416 bool bCopySheet = pDoc->IsStreamValid( nTable );
2417 if (bCopySheet)
2419 ScPostIt* pNote = pDoc->GetNote( aPos );
2420 OSL_ENSURE( pNote, "note not found" );
2421 if (pNote)
2423 SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
2424 uno::Reference<container::XEnumerationAccess> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY);
2425 uno::Reference<beans::XPropertySet> xParaProp(
2426 lcl_GetEnumerated( xCellText, rNoteParaEntry.maSelection.start.nPara ), uno::UNO_QUERY );
2427 if ( xParaProp.is() )
2429 std::vector<XMLPropertyState> aPropStates(xParaPropMapper->Filter(*this, xParaProp));
2430 OUString sName( rNoteParaEntry.maName );
2431 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_PARAGRAPH, OUString(), std::move(aPropStates));
2432 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_PARAGRAPH, sName);
2438 // note text styles
2440 rtl::Reference<SvXMLExportPropertyMapper> xTextPropMapper = XMLTextParagraphExport::CreateCharExtPropMapper( *this );
2442 const std::vector<ScTextStyleEntry>& rNoteTextEntries = pSheetData->GetNoteTextStyles();
2443 for (const auto& rNoteTextEntry : rNoteTextEntries)
2445 ScAddress aPos = rNoteTextEntry.maCellPos;
2446 SCTAB nTable = aPos.Tab();
2447 bool bCopySheet = pDoc->IsStreamValid( nTable );
2448 if (bCopySheet)
2450 ScPostIt* pNote = pDoc->GetNote( aPos );
2451 OSL_ENSURE( pNote, "note not found" );
2452 if (pNote)
2454 SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
2455 uno::Reference<text::XSimpleText> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY);
2456 uno::Reference<beans::XPropertySet> xCursorProp(xCellText->createTextCursor(), uno::UNO_QUERY);
2457 ScDrawTextCursor* pCursor = comphelper::getFromUnoTunnel<ScDrawTextCursor>( xCursorProp );
2458 if (pCursor)
2460 pCursor->SetSelection( rNoteTextEntry.maSelection );
2462 std::vector<XMLPropertyState> aPropStates(xTextPropMapper->Filter(*this, xCursorProp));
2463 OUString sName( rNoteTextEntry.maName );
2464 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates));
2465 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_TEXT, sName);
2471 // stored text styles
2473 // Calling createTextCursor fires up editeng, which is very slow, and often subsequent style entries
2474 // refer to the same cell, so cache it.
2475 ScAddress aPrevPos;
2476 uno::Reference<beans::XPropertySet> xPrevCursorProp;
2477 const std::vector<ScTextStyleEntry>& rTextEntries = pSheetData->GetTextStyles();
2478 for (const auto& rTextEntry : rTextEntries)
2480 ScAddress aPos = rTextEntry.maCellPos;
2481 sal_Int32 nTable = aPos.Tab();
2482 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2483 if (!bCopySheet)
2484 continue;
2486 //! separate method AddStyleFromText needed?
2487 //! cache sheet object
2489 uno::Reference<beans::XPropertySet> xCursorProp;
2490 if (xPrevCursorProp && aPrevPos == aPos)
2491 xCursorProp = xPrevCursorProp;
2492 else
2494 uno::Reference<table::XCellRange> xCellRange(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2495 uno::Reference<text::XSimpleText> xCellText(xCellRange->getCellByPosition(aPos.Col(), aPos.Row()), uno::UNO_QUERY);
2496 xCursorProp.set(xCellText->createTextCursor(), uno::UNO_QUERY);
2498 ScCellTextCursor* pCursor = comphelper::getFromUnoTunnel<ScCellTextCursor>( xCursorProp );
2499 if (!pCursor)
2500 continue;
2501 pCursor->SetSelection( rTextEntry.maSelection );
2503 std::vector<XMLPropertyState> aPropStates(xTextPropMapper->Filter(*this, xCursorProp));
2504 OUString sName( rTextEntry.maName );
2505 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates));
2506 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_TEXT, sName);
2507 xPrevCursorProp = std::move(xCursorProp);
2508 aPrevPos = aPos;
2512 ExportExternalRefCacheStyles(*pDoc);
2515 if (!pSharedData)
2517 SCTAB nTableCount(0);
2518 sal_Int32 nShapesCount(0);
2519 CollectSharedData(nTableCount, nShapesCount);
2521 sal_Int32 nTableCount(xIndex->getCount());
2522 CollectShapesAutoStyles(nTableCount);
2523 for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable, IncrementProgressBar(false))
2525 uno::Reference <sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2526 if (!xTable.is())
2527 continue;
2529 // table styles array must be complete, including copied tables - Add should find the stored style
2530 uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
2531 if (xTableProperties.is())
2533 std::vector<XMLPropertyState> aPropStates(xTableStylesExportPropertySetMapper->Filter(*this, xTableProperties));
2534 if(!aPropStates.empty())
2536 OUString sName;
2537 GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_TABLE, OUString(), std::move(aPropStates));
2538 aTableStyles.push_back(sName);
2542 // collect other auto-styles only for non-copied sheets
2543 uno::Reference<sheet::XUniqueCellFormatRangesSupplier> xCellFormatRanges ( xTable, uno::UNO_QUERY );
2544 if ( xCellFormatRanges.is() )
2546 uno::Reference<container::XIndexAccess> xFormatRangesIndex(xCellFormatRanges->getUniqueCellFormatRanges());
2547 if (xFormatRangesIndex.is())
2549 sal_Int32 nFormatRangesCount(xFormatRangesIndex->getCount());
2550 GetProgressBarHelper()->ChangeReference(GetProgressBarHelper()->GetReference() + nFormatRangesCount);
2551 for (sal_Int32 nFormatRange = 0; nFormatRange < nFormatRangesCount; ++nFormatRange)
2553 uno::Reference< sheet::XSheetCellRanges> xCellRanges(xFormatRangesIndex->getByIndex(nFormatRange), uno::UNO_QUERY);
2554 if (xCellRanges.is())
2556 uno::Reference <beans::XPropertySet> xProperties (xCellRanges, uno::UNO_QUERY);
2557 if (xProperties.is())
2559 AddStyleFromCells(xProperties, xTable, nTable, nullptr);
2560 IncrementProgressBar(false);
2566 if (pDoc)
2568 uno::Reference<table::XColumnRowRange> xColumnRowRange (xTable, uno::UNO_QUERY);
2569 if (xColumnRowRange.is())
2571 pDoc->SyncColRowFlags();
2572 uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns());
2573 if (xTableColumns.is())
2575 sal_Int32 nColumns(pDoc->GetLastChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable)));
2576 pSharedData->SetLastColumn(nTable, nColumns);
2577 table::CellRangeAddress aCellAddress(GetEndAddress(xTable));
2578 if (aCellAddress.EndColumn > nColumns)
2580 ++nColumns;
2581 pColumnStyles->AddNewTable(nTable, aCellAddress.EndColumn);
2583 else
2584 pColumnStyles->AddNewTable(nTable, nColumns);
2585 sal_Int32 nColumn = 0;
2586 while (nColumn <= pDoc->MaxCol())
2588 sal_Int32 nIndex(-1);
2589 bool bIsVisible(true);
2590 uno::Reference <beans::XPropertySet> xColumnProperties(xTableColumns->getByIndex(nColumn), uno::UNO_QUERY);
2591 if (xColumnProperties.is())
2593 AddStyleFromColumn( xColumnProperties, nullptr, nIndex, bIsVisible );
2594 pColumnStyles->AddFieldStyleName(nTable, nColumn, nIndex, bIsVisible);
2596 sal_Int32 nOld(nColumn);
2597 nColumn = pDoc->GetNextDifferentChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCCOL>(nColumn));
2598 for (sal_Int32 i = nOld + 1; i < nColumn; ++i)
2599 pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible);
2601 if (aCellAddress.EndColumn > nColumns)
2603 bool bIsVisible(true);
2604 sal_Int32 nIndex(pColumnStyles->GetStyleNameIndex(nTable, nColumns, bIsVisible));
2605 for (sal_Int32 i = nColumns + 1; i <= aCellAddress.EndColumn; ++i)
2606 pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible);
2609 uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows());
2610 if (xTableRows.is())
2612 sal_Int32 nRows(pDoc->GetLastChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable)));
2613 pSharedData->SetLastRow(nTable, nRows);
2615 pRowStyles->AddNewTable(nTable, pDoc->MaxRow());
2616 sal_Int32 nRow = 0;
2617 while (nRow <= pDoc->MaxRow())
2619 sal_Int32 nIndex = 0;
2620 uno::Reference <beans::XPropertySet> xRowProperties(xTableRows->getByIndex(nRow), uno::UNO_QUERY);
2621 if(xRowProperties.is())
2623 AddStyleFromRow( xRowProperties, nullptr, nIndex );
2624 pRowStyles->AddFieldStyleName(nTable, nRow, nIndex);
2626 sal_Int32 nOld(nRow);
2627 nRow = pDoc->GetNextDifferentChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCROW>(nRow));
2628 if (nRow > nOld + 1)
2629 pRowStyles->AddFieldStyleName(nTable, nOld + 1, nIndex, nRow - 1);
2633 ExportCellTextAutoStyles(*pDoc, nTable);
2637 pChangeTrackingExportHelper->CollectAutoStyles();
2640 if (getExportFlags() & SvXMLExportFlags::MASTERSTYLES)
2641 // tdf#154445 - export all page styles even if they are not in use
2642 GetPageExport()->collectAutoStyles(false);
2644 mbAutoStylesCollected = true;
2647 void ScXMLExport::ExportAutoStyles_()
2649 if (!GetModel().is())
2650 return;
2652 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
2653 if (!xSpreadDoc.is())
2654 return;
2656 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
2657 if (!xIndex.is())
2658 return;
2660 collectAutoStyles();
2662 if (getExportFlags() & SvXMLExportFlags::CONTENT)
2664 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_COLUMN);
2665 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_ROW);
2666 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_TABLE);
2667 exportAutoDataStyles();
2668 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_CELL);
2670 GetShapeExport()->exportAutoStyles();
2671 GetFormExport()->exportAutoStyles( );
2673 if (ScDocument* pDoc = GetDocument())
2675 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
2676 // #i100879# write the table style for cached tables only if there are cached tables
2677 // (same logic as in ExportExternalRefCacheStyles)
2678 if (pRefMgr->hasExternalData())
2680 // Special table style for the external ref cache tables.
2681 AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sExternalRefTabStyleName);
2682 AddAttribute(XML_NAMESPACE_STYLE, XML_FAMILY, XML_TABLE);
2683 SvXMLElementExport aElemStyle(*this, XML_NAMESPACE_STYLE, XML_STYLE, true, true);
2684 AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, XML_FALSE);
2685 SvXMLElementExport aElemStyleTabProps(*this, XML_NAMESPACE_STYLE, XML_TABLE_PROPERTIES, true, true);
2690 if (getExportFlags() & SvXMLExportFlags::MASTERSTYLES)
2692 exportAutoDataStyles();
2693 GetPageExport()->exportAutoStyles();
2696 // #i30251#; only write Text Styles once
2698 if ((getExportFlags() & SvXMLExportFlags::CONTENT) || (getExportFlags() & SvXMLExportFlags::MASTERSTYLES))
2699 GetTextParagraphExport()->exportTextAutoStyles();
2702 void ScXMLExport::ExportMasterStyles_()
2704 // tdf#154445 - export all page styles even if they are not in use
2705 GetPageExport()->exportMasterStyles( false );
2708 void ScXMLExport::CollectInternalShape(ScDocument& rDoc, uno::Reference< drawing::XShape > const & xShape )
2710 // detective objects and notes
2711 SdrObject* pObject = SdrObject::getSdrObjectFromXShape( xShape );
2712 if( !pObject )
2713 return;
2715 // collect note caption objects from all layers (internal or hidden)
2716 if( ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObject, static_cast< SCTAB >( nCurrentTable ) ) )
2718 if (rDoc.GetNote(pCaptData->maStart))
2720 pSharedData->AddNoteObj( xShape, pCaptData->maStart );
2722 // #i60851# When the file is saved while editing a new note,
2723 // the cell is still empty -> last column/row must be updated
2724 OSL_ENSURE( pCaptData->maStart.Tab() == nCurrentTable, "invalid table in object data" );
2725 pSharedData->SetLastColumn( nCurrentTable, pCaptData->maStart.Col() );
2726 pSharedData->SetLastRow( nCurrentTable, pCaptData->maStart.Row() );
2729 // other objects from internal layer only (detective)
2730 else if( pObject->GetLayer() == SC_LAYER_INTERN )
2732 ScDetectiveFunc aDetFunc(rDoc, static_cast<SCTAB>(nCurrentTable));
2733 ScAddress aPosition;
2734 ScRange aSourceRange;
2735 bool bRedLine;
2736 ScDetectiveObjType eObjType = aDetFunc.GetDetectiveObjectType(
2737 pObject, nCurrentTable, aPosition, aSourceRange, bRedLine );
2738 pSharedData->GetDetectiveObjContainer()->AddObject( eObjType, static_cast<SCTAB>(nCurrentTable), aPosition, aSourceRange, bRedLine );
2742 static uno::Reference<sheet::XSheetCellRange> lclGetSheetRange(const uno::Reference <sheet::XSpreadsheet>& xTable, sal_Int32 nCol, sal_Int32 nRow)
2746 return uno::Reference<sheet::XSheetCellRange>(xTable->getCellRangeByPosition(nCol, nRow, nCol, nRow), uno::UNO_QUERY);
2748 catch (const uno::Exception&)
2750 TOOLS_WARN_EXCEPTION("sc", "Exception in getCellRangeByPosition, col: " << nCol << ", row: " << nRow);
2751 assert(false && "try and capture this in crashtesting");
2753 return nullptr;
2756 bool ScXMLExport::GetMerged (const table::CellRangeAddress* pCellAddress,
2757 const uno::Reference <sheet::XSpreadsheet>& xTable)
2759 bool bReady(false);
2760 sal_Int32 nRow(pCellAddress->StartRow);
2761 sal_Int32 nCol(pCellAddress->StartColumn);
2762 sal_Int32 nEndRow(pCellAddress->EndRow);
2763 sal_Int32 nEndCol(pCellAddress->EndColumn);
2764 bool bRowInc(nEndRow > nRow);
2765 while(!bReady && nRow <= nEndRow && nCol <= nEndCol)
2767 uno::Reference<sheet::XSheetCellRange> xSheetCellRange(lclGetSheetRange(xTable, nCol, nRow));
2768 if (xSheetCellRange.is())
2770 uno::Reference<sheet::XSheetCellCursor> xCursor(xTable->createCursorByRange(xSheetCellRange));
2771 if(xCursor.is())
2773 uno::Reference<sheet::XCellRangeAddressable> xCellAddress (xCursor, uno::UNO_QUERY);
2774 xCursor->collapseToMergedArea();
2775 table::CellRangeAddress aCellAddress2(xCellAddress->getRangeAddress());
2776 ScRange aScRange( aCellAddress2.StartColumn, aCellAddress2.StartRow, aCellAddress2.Sheet,
2777 aCellAddress2.EndColumn, aCellAddress2.EndRow, aCellAddress2.Sheet );
2779 if ((aScRange.aEnd.Row() > nRow ||
2780 aScRange.aEnd.Col() > nCol) &&
2781 aScRange.aStart.Row() == nRow &&
2782 aScRange.aStart.Col() == nCol)
2784 pMergedRangesContainer->AddRange(aScRange);
2785 pSharedData->SetLastColumn(aScRange.aEnd.Tab(), aScRange.aEnd.Col());
2786 pSharedData->SetLastRow(aScRange.aEnd.Tab(), aScRange.aEnd.Row());
2788 else
2789 bReady = true;
2792 if (!bReady)
2794 if (bRowInc)
2795 ++nRow;
2796 else
2797 ++nCol;
2800 OSL_ENSURE(!(!bReady && nEndRow > nRow && nEndCol > nCol), "should not be possible");
2801 return !bReady;
2804 //static
2805 bool ScXMLExport::IsMatrix (ScDocument& rDoc, const ScAddress& aCell,
2806 ScRange& aCellAddress, bool& bIsFirst)
2808 bIsFirst = false;
2810 ScRange aMatrixRange;
2812 if (rDoc.GetMatrixFormulaRange(aCell, aMatrixRange))
2814 aCellAddress = aMatrixRange;
2815 if ((aCellAddress.aStart.Col() == aCell.Col() && aCellAddress.aStart.Row() == aCell.Row()) &&
2816 (aCellAddress.aEnd.Col() > aCell.Col() || aCellAddress.aEnd.Row() > aCell.Row()))
2818 bIsFirst = true;
2819 return true;
2821 else if (aCellAddress.aStart.Col() != aCell.Col() || aCellAddress.aStart.Row() != aCell.Row() ||
2822 aCellAddress.aEnd.Col() != aCell.Col() || aCellAddress.aEnd.Row()!= aCell.Row())
2823 return true;
2824 else
2826 bIsFirst = true;
2827 return true;
2831 return false;
2834 void ScXMLExport::WriteTable(ScDocument& rDoc, sal_Int32 nTable, const uno::Reference<sheet::XSpreadsheet>& xTable)
2836 if (!xTable.is())
2837 return;
2839 xCurrentTable.set(xTable);
2840 uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY );
2841 if (!xName.is())
2842 return;
2844 nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable );
2845 OUString sOUTableName(xName->getName());
2846 AddAttribute(sAttrName, sOUTableName);
2847 AddAttribute(sAttrStyleName, aTableStyles[nTable]);
2849 uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY);
2850 const ScTableProtection* pProtect = nullptr;
2851 if (xProtectable.is() && xProtectable->isProtected())
2853 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
2854 pProtect = rDoc.GetTabProtection(nTable);
2855 if (pProtect)
2857 OUStringBuffer aBuffer;
2858 ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED;
2859 if (pProtect->hasPasswordHash(PASSHASH_SHA1))
2861 ::comphelper::Base64::encode(aBuffer,
2862 pProtect->getPasswordHash(PASSHASH_SHA1));
2863 eHashUsed = PASSHASH_SHA1;
2865 else if (pProtect->hasPasswordHash(PASSHASH_SHA256))
2867 ::comphelper::Base64::encode(aBuffer,
2868 pProtect->getPasswordHash(PASSHASH_SHA256));
2869 eHashUsed = PASSHASH_SHA256;
2871 else if (pProtect->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
2873 // Double-hash this by SHA1 on top of the legacy xls hash.
2874 uno::Sequence<sal_Int8> aHash = pProtect->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
2875 ::comphelper::Base64::encode(aBuffer, aHash);
2876 eHashUsed = PASSHASH_XL;
2878 if (!aBuffer.isEmpty())
2880 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
2881 if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
2883 if (eHashUsed == PASSHASH_XL)
2885 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
2886 ScPassHashHelper::getHashURI(PASSHASH_XL));
2887 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2888 AddAttribute(XML_NAMESPACE_LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2,
2889 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
2891 else if (eHashUsed == PASSHASH_SHA1)
2893 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
2894 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
2896 else if (eHashUsed == PASSHASH_SHA256)
2898 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
2899 ScPassHashHelper::getHashURI(PASSHASH_SHA256));
2905 OUString sPrintRanges;
2906 ScRange aColumnHeaderRange;
2907 bool bHasColumnHeader;
2908 GetColumnRowHeader(rDoc, bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges);
2909 if( !sPrintRanges.isEmpty() )
2910 AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges );
2911 else if (!rDoc.IsPrintEntireSheet(static_cast<SCTAB>(nTable)))
2912 AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE);
2913 SvXMLElementExport aElemT(*this, sElemTab, true, true);
2915 if (pProtect && pProtect->isProtected() && getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2917 if (pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS))
2918 AddAttribute(XML_NAMESPACE_LO_EXT, XML_SELECT_PROTECTED_CELLS, XML_TRUE);
2919 if (pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS))
2920 AddAttribute(XML_NAMESPACE_LO_EXT, XML_SELECT_UNPROTECTED_CELLS, XML_TRUE);
2922 if (pProtect->isOptionEnabled(ScTableProtection::INSERT_COLUMNS))
2923 AddAttribute(XML_NAMESPACE_LO_EXT, XML_INSERT_COLUMNS, XML_TRUE);
2924 if (pProtect->isOptionEnabled(ScTableProtection::INSERT_ROWS))
2925 AddAttribute(XML_NAMESPACE_LO_EXT, XML_INSERT_ROWS, XML_TRUE);
2927 if (pProtect->isOptionEnabled(ScTableProtection::DELETE_COLUMNS))
2928 AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_COLUMNS, XML_TRUE);
2929 if (pProtect->isOptionEnabled(ScTableProtection::DELETE_ROWS))
2930 AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_ROWS, XML_TRUE);
2932 if (pProtect->isOptionEnabled(ScTableProtection::AUTOFILTER))
2933 AddAttribute(XML_NAMESPACE_LO_EXT, XML_USE_AUTOFILTER, XML_TRUE);
2934 if (pProtect->isOptionEnabled(ScTableProtection::PIVOT_TABLES))
2935 AddAttribute(XML_NAMESPACE_LO_EXT, XML_USE_PIVOT, XML_TRUE);
2937 OUString aElemName = GetNamespaceMap().GetQNameByKey(
2938 XML_NAMESPACE_LO_EXT, GetXMLToken(XML_TABLE_PROTECTION));
2940 SvXMLElementExport aElemProtected(*this, aElemName, true, true);
2943 CheckAttrList();
2945 if (rDoc.GetSheetEvents( static_cast<SCTAB>(nTable) ) &&
2946 getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
2948 // store sheet events
2949 uno::Reference<document::XEventsSupplier> xSupplier(xTable, uno::UNO_QUERY);
2950 uno::Reference<container::XNameAccess> xEvents = xSupplier->getEvents();
2951 GetEventExport().ExportExt( xEvents );
2954 WriteTableSource();
2955 WriteScenario(rDoc);
2956 uno::Reference<drawing::XDrawPage> xDrawPage;
2957 if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is())
2959 ::xmloff::OOfficeFormsExport aForms(*this);
2960 GetFormExport()->exportForms( xDrawPage );
2961 bool bRet(GetFormExport()->seekPage( xDrawPage ));
2962 OSL_ENSURE( bRet, "OFormLayerXMLExport::seekPage failed!" );
2964 if (pSharedData->HasDrawPage())
2966 GetShapeExport()->seekShapes(pSharedData->GetDrawPage(nTable));
2967 WriteTableShapes(rDoc);
2969 table::CellRangeAddress aRange(GetEndAddress(xTable));
2970 pSharedData->SetLastColumn(nTable, aRange.EndColumn);
2971 pSharedData->SetLastRow(nTable, aRange.EndRow);
2972 mpCellsItr->SetCurrentTable(rDoc, static_cast<SCTAB>(nTable), xCurrentTable);
2973 pGroupColumns->NewTable();
2974 pGroupRows->NewTable();
2975 FillColumnRowGroups(rDoc);
2976 if (bHasColumnHeader)
2977 pSharedData->SetLastColumn(nTable, aColumnHeaderRange.aEnd.Col());
2978 bRowHeaderOpen = false;
2979 if (bHasRowHeader)
2980 pSharedData->SetLastRow(nTable, aRowHeaderRange.aEnd.Row());
2981 pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable),
2982 pSharedData->GetLastColumn(nTable), pCellStyles.get(), &rDoc);
2983 pRowFormatRanges->SetColDefaults(&pDefaults->GetColDefaults());
2984 pCellStyles->SetColDefaults(&pDefaults->GetColDefaults());
2985 ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader);
2986 bool bIsFirst(true);
2987 sal_Int32 nEqualCells(0);
2988 ScMyCell aCell;
2989 ScMyCell aPrevCell;
2990 while (mpCellsItr->GetNext(rDoc, aCell, pCellStyles.get()))
2992 if (bIsFirst)
2994 ExportFormatRanges(rDoc, 0, 0, aCell.maCellAddress.Col()-1, aCell.maCellAddress.Row(), nTable);
2995 aPrevCell = aCell;
2996 bIsFirst = false;
2998 else
3000 if ((aPrevCell.maCellAddress.Row() == aCell.maCellAddress.Row()) &&
3001 (aPrevCell.maCellAddress.Col() + nEqualCells + 1 == aCell.maCellAddress.Col()))
3003 if (IsCellEqual(rDoc, aPrevCell, aCell))
3004 ++nEqualCells;
3005 else
3007 WriteCell(rDoc, aPrevCell, nEqualCells);
3008 nEqualCells = 0;
3009 aPrevCell = aCell;
3012 else
3014 WriteCell(rDoc, aPrevCell, nEqualCells);
3015 ExportFormatRanges(rDoc, aPrevCell.maCellAddress.Col() + nEqualCells + 1, aPrevCell.maCellAddress.Row(),
3016 aCell.maCellAddress.Col()-1, aCell.maCellAddress.Row(), nTable);
3017 nEqualCells = 0;
3018 aPrevCell = aCell;
3022 if (!bIsFirst)
3024 WriteCell(rDoc, aPrevCell, nEqualCells);
3025 ExportFormatRanges(rDoc, aPrevCell.maCellAddress.Col() + nEqualCells + 1, aPrevCell.maCellAddress.Row(),
3026 pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
3028 else
3029 ExportFormatRanges(rDoc, 0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
3031 CloseRow(pSharedData->GetLastRow(nTable));
3033 // Export sheet-local named ranges.
3034 ScRangeName* pRangeName = rDoc.GetRangeName(nTable);
3035 if (pRangeName && !pRangeName->empty())
3037 WriteNamedRange(rDoc, pRangeName);
3040 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3042 //export new conditional format information
3043 ExportConditionalFormat(rDoc, nTable);
3044 exportSparklineGroups(rDoc, nTable);
3048 namespace {
3050 void writeContent(ScDocument& rDoc, ScXMLExport& rExport, const OUString& rStyleName,
3051 const OUString& rContent, const SvxFieldData* pField)
3053 std::unique_ptr<SvXMLElementExport> pElem;
3054 if (!rStyleName.isEmpty())
3056 // Formatted section with automatic style.
3057 rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, rStyleName);
3058 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3059 XML_NAMESPACE_TEXT, GetXMLToken(XML_SPAN));
3060 pElem.reset(new SvXMLElementExport(rExport, aElemName, false, false));
3063 if (pField)
3065 // Write a field item.
3066 OUString aFieldVal = ScEditUtil::GetCellFieldValue(*pField, &rDoc, nullptr, nullptr);
3067 switch (pField->GetClassId())
3069 case text::textfield::Type::URL:
3071 // <text:a xlink:href="url" xlink:type="simple">value</text:a>
3073 const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
3074 const OUString& aURL = pURLField->GetURL();
3075 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(aURL));
3076 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, u"simple"_ustr);
3077 const OUString& aTargetFrame = pURLField->GetTargetFrame();
3078 if (!aTargetFrame.isEmpty())
3079 rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, aTargetFrame);
3081 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3082 XML_NAMESPACE_TEXT, GetXMLToken(XML_A));
3083 SvXMLElementExport aElem(rExport, aElemName, false, false);
3084 rExport.Characters(aFieldVal);
3086 break;
3087 case text::textfield::Type::DATE:
3089 // <text:date style:data-style-name="N2" text:date-value="YYYY-MM-DD">value</text:date>
3091 Date aDate(Date::SYSTEM);
3092 OUStringBuffer aBuf;
3093 sal_Int32 nVal = aDate.GetYear();
3094 aBuf.append(OUString::number(nVal) + "-");
3095 nVal = aDate.GetMonth();
3096 if (nVal < 10)
3097 aBuf.append('0');
3098 aBuf.append(OUString::number(nVal) + "-");
3099 nVal = aDate.GetDay();
3100 if (nVal < 10)
3101 aBuf.append('0');
3102 aBuf.append(nVal);
3103 rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, u"N2"_ustr);
3104 rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_DATE_VALUE, aBuf.makeStringAndClear());
3106 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3107 XML_NAMESPACE_TEXT, GetXMLToken(XML_DATE));
3108 SvXMLElementExport aElem(rExport, aElemName, false, false);
3109 rExport.Characters(aFieldVal);
3111 break;
3112 case text::textfield::Type::DOCINFO_TITLE:
3114 // <text:title>value</text:title>
3116 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3117 XML_NAMESPACE_TEXT, GetXMLToken(XML_TITLE));
3118 SvXMLElementExport aElem(rExport, aElemName, false, false);
3119 rExport.Characters(aFieldVal);
3121 break;
3122 case text::textfield::Type::TABLE:
3124 // <text:sheet-name>value</text:sheet-name>
3126 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3127 XML_NAMESPACE_TEXT, GetXMLToken(XML_SHEET_NAME));
3128 SvXMLElementExport aElem(rExport, aElemName, false, false);
3129 rExport.Characters(aFieldVal);
3131 break;
3132 default:
3133 rExport.Characters(aFieldVal);
3136 else
3137 rExport.Characters(rContent);
3140 void flushParagraph(
3141 ScDocument& rDoc,
3142 ScXMLExport& rExport, std::u16string_view rParaText,
3143 rtl::Reference<XMLPropertySetMapper> const & xMapper, rtl::Reference<SvXMLAutoStylePoolP> const & xStylePool,
3144 const ScXMLEditAttributeMap& rAttrMap,
3145 std::vector<editeng::Section>::const_iterator it, std::vector<editeng::Section>::const_iterator const & itEnd )
3147 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3148 XML_NAMESPACE_TEXT, GetXMLToken(XML_P));
3149 SvXMLElementExport aElemP(rExport, aElemName, false, false);
3151 for (; it != itEnd; ++it)
3153 const editeng::Section& rSec = *it;
3155 OUString aContent(rParaText.substr(rSec.mnStart, rSec.mnEnd - rSec.mnStart));
3157 std::vector<XMLPropertyState> aPropStates;
3158 const SvxFieldData* pField = toXMLPropertyStates(rExport, aPropStates, rSec.maAttributes, xMapper, rAttrMap);
3159 OUString aStyleName = xStylePool->Find(XmlStyleFamily::TEXT_TEXT, OUString(), aPropStates);
3160 if (aContent == "\x001" && !pField)
3162 for (const SfxPoolItem* p : rSec.maAttributes)
3164 if (p->Which() == EE_FEATURE_TAB)
3166 SvXMLElementExport Tab(rExport, XML_NAMESPACE_TEXT, XML_TAB, false, false);
3167 break;
3169 else if (p->Which() == EE_FEATURE_LINEBR)
3171 SvXMLElementExport L(rExport, XML_NAMESPACE_TEXT, XML_LINE_BREAK, false, false);
3172 break;
3176 else
3177 writeContent(rDoc, rExport, aStyleName, aContent, pField);
3183 void ScXMLExport::WriteCell(ScDocument& rDoc, ScMyCell& aCell, sal_Int32 nEqualCellCount)
3185 // nEqualCellCount is the number of additional cells
3186 SetRepeatAttribute(nEqualCellCount, (aCell.nType != table::CellContentType_EMPTY));
3188 if (aCell.nStyleIndex != -1)
3189 AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(aCell.nStyleIndex, aCell.bIsAutoStyle));
3190 if (aCell.nValidationIndex > -1)
3191 AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(aCell.nValidationIndex));
3192 const bool bIsFirstMatrixCell(aCell.bIsMatrixBase);
3193 if (bIsFirstMatrixCell)
3195 SCCOL nColumns( aCell.aMatrixRange.aEnd.Col() - aCell.aMatrixRange.aStart.Col() + 1 );
3196 SCROW nRows( aCell.aMatrixRange.aEnd.Row() - aCell.aMatrixRange.aStart.Row() + 1 );
3197 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED, OUString::number(nColumns));
3198 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED, OUString::number(nRows));
3200 bool bIsEmpty(false);
3201 switch (aCell.nType)
3203 case table::CellContentType_EMPTY :
3205 bIsEmpty = true;
3207 break;
3208 case table::CellContentType_VALUE :
3210 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3211 aCell.nNumberFormat, aCell.maBaseCell.getDouble());
3212 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3213 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3214 aCell.nNumberFormat, aCell.maBaseCell.getDouble(), false, XML_NAMESPACE_CALC_EXT, false);
3216 break;
3217 case table::CellContentType_TEXT :
3219 OUString sFormattedString(lcl_GetFormattedString(rDoc, aCell.maBaseCell, aCell.maCellAddress));
3220 OUString sCellString = aCell.maBaseCell.getString(&rDoc);
3221 bool bExportValue = sCellString.indexOf('\x001') == -1;
3222 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3223 sCellString, sFormattedString, bExportValue);
3224 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3225 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3226 sCellString, sFormattedString, false, XML_NAMESPACE_CALC_EXT);
3228 break;
3229 case table::CellContentType_FORMULA :
3231 if (aCell.maBaseCell.getType() == CELLTYPE_FORMULA)
3233 const bool bIsMatrix(bIsFirstMatrixCell || aCell.bIsMatrixCovered);
3234 ScFormulaCell* pFormulaCell = aCell.maBaseCell.getFormula();
3235 if (!bIsMatrix || bIsFirstMatrixCell)
3237 if (!mpCompileFormulaCxt)
3239 const formula::FormulaGrammar::Grammar eGrammar = rDoc.GetStorageGrammar();
3240 mpCompileFormulaCxt.reset(new sc::CompileFormulaContext(rDoc, eGrammar));
3242 mpCompileFormulaCxt->setODFSavingVersion(getSaneDefaultVersion());
3243 OUString aFormula = pFormulaCell->GetFormula(*mpCompileFormulaCxt);
3244 sal_uInt16 nNamespacePrefix =
3245 (mpCompileFormulaCxt->getGrammar() == formula::FormulaGrammar::GRAM_ODFF ? XML_NAMESPACE_OF : XML_NAMESPACE_OOOC);
3247 if (!bIsMatrix)
3249 AddAttribute(sAttrFormula, GetNamespaceMap().GetQNameByKey(nNamespacePrefix, aFormula, false));
3251 else
3253 AddAttribute(sAttrFormula, GetNamespaceMap().GetQNameByKey(nNamespacePrefix, aFormula.copy(1, aFormula.getLength()-2), false));
3256 if (pFormulaCell->GetErrCode() != FormulaError::NONE)
3258 AddAttribute(sAttrValueType, XML_STRING);
3259 AddAttribute(sAttrStringValue, aCell.maBaseCell.getString(&rDoc));
3260 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3262 //export calcext:value-type="error"
3263 AddAttribute(XML_NAMESPACE_CALC_EXT,XML_VALUE_TYPE, u"error"_ustr);
3266 else if (pFormulaCell->IsValue())
3268 bool bIsStandard;
3269 OUString sCurrency;
3270 GetNumberFormatAttributesExportHelper()->GetCellType(aCell.nNumberFormat, sCurrency, bIsStandard);
3271 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3272 aCell.nNumberFormat, rDoc.GetValue(aCell.maCellAddress));
3273 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3275 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3276 aCell.nNumberFormat, rDoc.GetValue(aCell.maCellAddress), false, XML_NAMESPACE_CALC_EXT, false );
3279 else
3281 if (!aCell.maBaseCell.getString(&rDoc).isEmpty())
3283 AddAttribute(sAttrValueType, XML_STRING);
3284 AddAttribute(sAttrStringValue, aCell.maBaseCell.getString(&rDoc));
3285 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3287 AddAttribute(XML_NAMESPACE_CALC_EXT,XML_VALUE_TYPE, XML_STRING);
3293 break;
3294 default:
3295 break;
3297 OUString* pCellString(&sElemCell);
3298 if (aCell.bIsCovered)
3300 pCellString = &sElemCoveredCell;
3302 else
3304 if (aCell.bIsMergedBase)
3306 SCCOL nColumns( aCell.aMergeRange.aEnd.Col() - aCell.aMergeRange.aStart.Col() + 1 );
3307 SCROW nRows( aCell.aMergeRange.aEnd.Row() - aCell.aMergeRange.aStart.Row() + 1 );
3308 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, OUString::number(nColumns));
3309 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, OUString::number(nRows));
3312 SvXMLElementExport aElemC(*this, *pCellString, true, true);
3313 CheckAttrList();
3314 WriteAreaLink(aCell);
3315 WriteAnnotation(rDoc, aCell);
3316 WriteDetective(rDoc, aCell);
3318 if (!bIsEmpty)
3320 if (aCell.maBaseCell.getType() == CELLTYPE_EDIT)
3322 WriteEditCell(rDoc, aCell.maBaseCell.getEditText());
3324 else if (aCell.maBaseCell.getType() == CELLTYPE_FORMULA && aCell.maBaseCell.getFormula()->IsMultilineResult())
3326 WriteMultiLineFormulaResult(aCell.maBaseCell.getFormula());
3328 else
3330 SvXMLElementExport aElemP(*this, sElemP, true, false);
3332 OUString aParaStr =
3333 ScCellFormat::GetOutputString(rDoc, aCell.maCellAddress, aCell.maBaseCell);
3335 bool bPrevCharWasSpace = true;
3336 GetTextParagraphExport()->exportCharacterData(aParaStr, bPrevCharWasSpace);
3339 WriteShapes(rDoc, aCell);
3340 if (!bIsEmpty)
3341 IncrementProgressBar(false);
3344 void ScXMLExport::WriteEditCell(ScDocument& rDoc, const EditTextObject* pText)
3346 rtl::Reference<XMLPropertySetMapper> xMapper = GetTextParagraphExport()->GetTextPropMapper()->getPropertySetMapper();
3347 rtl::Reference<SvXMLAutoStylePoolP> xStylePool = GetAutoStylePool();
3348 const ScXMLEditAttributeMap& rAttrMap = GetEditAttributeMap();
3350 // Get raw paragraph texts first.
3351 std::vector<OUString> aParaTexts;
3352 sal_Int32 nParaCount = pText->GetParagraphCount();
3353 aParaTexts.reserve(nParaCount);
3354 for (sal_Int32 i = 0; i < nParaCount; ++i)
3355 aParaTexts.push_back(pText->GetText(i));
3357 // Get all section data and iterate through them.
3358 std::vector<editeng::Section> aAttrs;
3359 pText->GetAllSections(aAttrs);
3360 std::vector<editeng::Section>::const_iterator itSec = aAttrs.begin(), itSecEnd = aAttrs.end();
3361 std::vector<editeng::Section>::const_iterator itPara = itSec;
3362 sal_Int32 nCurPara = 0; // current paragraph
3363 for (; itSec != itSecEnd; ++itSec)
3365 const editeng::Section& rSec = *itSec;
3366 if (nCurPara == rSec.mnParagraph)
3367 // Still in the same paragraph.
3368 continue;
3370 // Start of a new paragraph. Flush the old paragraph.
3371 flushParagraph(rDoc, *this, aParaTexts[nCurPara], xMapper, xStylePool, rAttrMap, itPara, itSec);
3372 nCurPara = rSec.mnParagraph;
3373 itPara = itSec;
3376 flushParagraph(rDoc, *this, aParaTexts[nCurPara], xMapper, xStylePool, rAttrMap, itPara, itSecEnd);
3379 void ScXMLExport::WriteMultiLineFormulaResult(const ScFormulaCell* pCell)
3381 OUString aElemName = GetNamespaceMap().GetQNameByKey(XML_NAMESPACE_TEXT, GetXMLToken(XML_P));
3383 OUString aResStr = pCell->GetResultString().getString();
3384 const sal_Unicode* p = aResStr.getStr();
3385 const sal_Unicode* pEnd = p + static_cast<size_t>(aResStr.getLength());
3386 const sal_Unicode* pPara = p; // paragraph head.
3387 for (; p != pEnd; ++p)
3389 if (*p != '\n')
3390 continue;
3392 // flush the paragraph.
3393 OUString aContent;
3394 if (*pPara == '\n')
3395 ++pPara;
3396 if (p > pPara)
3397 aContent = OUString(pPara, p-pPara);
3399 SvXMLElementExport aElem(*this, aElemName, false, false);
3400 Characters(aContent);
3402 pPara = p;
3405 OUString aContent;
3406 if (*pPara == '\n')
3407 ++pPara;
3408 if (pEnd > pPara)
3409 aContent = OUString(pPara, pEnd-pPara);
3411 SvXMLElementExport aElem(*this, aElemName, false, false);
3412 Characters(aContent);
3415 void ScXMLExport::ExportShape(ScDocument& rDoc, const uno::Reference < drawing::XShape >& xShape, awt::Point* pPoint)
3417 uno::Reference < beans::XPropertySet > xShapeProps ( xShape, uno::UNO_QUERY );
3418 bool bIsChart( false );
3419 if (xShapeProps.is())
3421 sal_Int32 nZOrder = 0;
3422 if (xShapeProps->getPropertyValue(u"ZOrder"_ustr) >>= nZOrder)
3424 AddAttribute(XML_NAMESPACE_DRAW, XML_ZINDEX, OUString::number(nZOrder));
3426 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xShapeProps->getPropertySetInfo();
3427 OUString sPropCLSID (u"CLSID"_ustr);
3428 if( xPropSetInfo->hasPropertyByName( sPropCLSID ) )
3430 OUString sCLSID;
3431 if (xShapeProps->getPropertyValue( sPropCLSID ) >>= sCLSID)
3433 if ( sCLSID.equalsIgnoreAsciiCase(GetChartExport()->getChartCLSID()) )
3435 // we have a chart
3436 OUString sRanges;
3437 OUString aChartName;
3438 xShapeProps->getPropertyValue( u"PersistName"_ustr ) >>= aChartName;
3439 ScChartListenerCollection* pCollection = rDoc.GetChartListenerCollection();
3440 if (pCollection)
3442 ScChartListener* pListener = pCollection->findByName(aChartName);
3443 if (pListener)
3445 const ScRangeListRef xRangeList = pListener->GetRangeList();
3446 if ( xRangeList.is() )
3448 ScRangeStringConverter::GetStringFromRangeList( sRanges, xRangeList.get(), &rDoc, FormulaGrammar::CONV_OOO );
3449 if ( !sRanges.isEmpty() )
3451 bIsChart = true;
3452 rtl::Reference<comphelper::AttributeList> pAttrList = new comphelper::AttributeList();
3453 pAttrList->AddAttribute(
3454 GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, GetXMLToken( XML_NOTIFY_ON_UPDATE_OF_RANGES ) ), sRanges );
3455 GetShapeExport()->exportShape( xShape, SEF_DEFAULT, pPoint, pAttrList.get() );
3461 if ( sRanges.isEmpty() )
3463 uno::Reference< frame::XModel > xChartModel;
3464 if( ( xShapeProps->getPropertyValue( u"Model"_ustr ) >>= xChartModel ) &&
3465 xChartModel.is())
3467 uno::Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY );
3468 uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartModel, uno::UNO_QUERY );
3469 if( xChartDoc.is() && xReceiver.is() &&
3470 ! xChartDoc->hasInternalDataProvider())
3472 // we have a chart that gets its data from Calc
3473 bIsChart = true;
3474 uno::Sequence< OUString > aRepresentations(
3475 xReceiver->getUsedRangeRepresentations());
3476 rtl::Reference<comphelper::AttributeList> pAttrList;
3479 if (aRepresentations.hasElements())
3481 // add the ranges used by the chart to the shape
3482 // element to be able to start listening after
3483 // load (when the chart is not yet loaded)
3484 uno::Reference< chart2::data::XRangeXMLConversion > xRangeConverter( xChartDoc->getDataProvider(), uno::UNO_QUERY );
3485 sRanges = lcl_RangeSequenceToString( aRepresentations, xRangeConverter );
3486 pAttrList = new comphelper::AttributeList();
3487 pAttrList->AddAttribute(
3488 GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, GetXMLToken(XML_NOTIFY_ON_UPDATE_OF_RANGES) ), sRanges );
3491 catch (const lang::IllegalArgumentException&)
3493 TOOLS_WARN_EXCEPTION("sc", "Exception in lcl_RangeSequenceToString - invalid range?");
3495 GetShapeExport()->exportShape(xShape, SEF_DEFAULT, pPoint, pAttrList.get());
3503 if (!bIsChart)
3504 GetShapeExport()->exportShape(xShape, SEF_DEFAULT, pPoint);
3506 IncrementProgressBar(false);
3509 void ScXMLExport::WriteShapes(ScDocument& rDoc, const ScMyCell& rMyCell)
3511 if( !(rMyCell.bHasShape && !rMyCell.aShapeList.empty()) )
3512 return;
3514 // Reference point to turn absolute coordinates in reference point + offset. That happens in most
3515 // cases in XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint, which gets the absolute
3516 // coordinates as translation from matrix in property "Transformation". For cell anchored shapes
3517 // the reference point is left-top (in LTR mode) of that cell, which contains the shape.
3518 tools::Rectangle aCellRectFull = rDoc.GetMMRect(
3519 rMyCell.maCellAddress.Col(), rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Col(),
3520 rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Tab(), false /*bHiddenAsZero*/);
3521 awt::Point aPoint;
3522 bool bNegativePage = rDoc.IsNegativePage(rMyCell.maCellAddress.Tab());
3523 if (bNegativePage)
3524 aPoint.X = aCellRectFull.Right();
3525 else
3526 aPoint.X = aCellRectFull.Left();
3527 aPoint.Y = aCellRectFull.Top();
3529 for (const auto& rShape : rMyCell.aShapeList)
3531 // Skip the shape if requirements are not met. The tests should not fail, but allow
3532 // shorter conditions in main part below.
3533 if (!rShape.xShape.is())
3534 continue;
3535 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rShape.xShape);
3536 if (!pObj)
3537 continue;
3538 ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj);
3539 if (!pObjData)
3540 continue;
3541 ScAddress aSnapStartAddress = pObjData->maStart;
3542 if (!aSnapStartAddress.IsValid())
3543 continue;
3545 // The current object geometry is based on bHiddenAsZero=true, but ODF file format
3546 // needs it as if there were no hidden rows or columns. We determine a fictive snap
3547 // rectangle from the anchor as if all column/rows are shown. Then we move and resize
3548 // (in case of "resize with cell") the object to meet this snap rectangle. We need to
3549 // manipulate the object itself, because the used methods in xmloff do not evaluate the
3550 // ObjData. We remember the transformations and restore them later.
3551 Point aMoveBy(0, 0);
3552 bool bNeedsRestorePosition = false;
3553 Fraction aScaleWidth(1, 1);
3554 Fraction aScaleHeight(1, 1);
3555 bool bNeedsRestoreSize = false;
3557 // Determine top point of fictive snap rectangle ('Full' rectangle).
3558 SCTAB aTab(aSnapStartAddress.Tab());
3559 SCCOL aCol(aSnapStartAddress.Col());
3560 SCROW aRow(aSnapStartAddress.Row());
3561 tools::Rectangle aFullStartCellRect
3562 = rDoc.GetMMRect(aCol, aRow, aCol, aRow, aTab, false /*bHiddenAsZero*/);
3563 // The reference corner for the offset is top-left in case of LTR and top-right for RTL.
3564 Point aFullTopPoint;
3565 if (bNegativePage)
3566 aFullTopPoint.setX(aFullStartCellRect.Right() - pObjData->maStartOffset.X());
3567 else
3568 aFullTopPoint.setX(aFullStartCellRect.Left() + pObjData->maStartOffset.X());
3569 aFullTopPoint.setY(aFullStartCellRect.Top() + pObjData->maStartOffset.Y());
3571 // Compare actual top point and full top point and move object accordingly.
3572 tools::Rectangle aOrigSnapRect(pObj->GetSnapRect());
3573 Point aActualTopPoint = bNegativePage ? aOrigSnapRect.TopRight() : aOrigSnapRect.TopLeft();
3574 if (aFullTopPoint != aActualTopPoint)
3576 bNeedsRestorePosition = true;
3577 aMoveBy = aFullTopPoint - aActualTopPoint;
3578 pObj->NbcMove(Size(aMoveBy.X(), aMoveBy.Y()));
3581 ScAddress aSnapEndAddress = pObjData->maEnd;
3582 // tdf#154005: We treat the combination of "To cell (resize with cell)" with 'size protected'
3583 // as being "To cell".
3584 if (pObjData->mbResizeWithCell && aSnapEndAddress.IsValid() && !pObj->IsResizeProtect())
3586 // Object is anchored "To cell (resize with cell)". Compare size of actual snap rectangle
3587 // and fictive full one. Resize object accordingly.
3588 tools::Rectangle aActualSnapRect(pObj->GetSnapRect());
3590 Point aSnapEndOffset(pObjData->maEndOffset);
3591 aCol = aSnapEndAddress.Col();
3592 aRow = aSnapEndAddress.Row();
3593 tools::Rectangle aFullEndCellRect
3594 = rDoc.GetMMRect(aCol, aRow, aCol, aRow, aTab, false /*bHiddenAsZero*/);
3595 Point aFullBottomPoint;
3596 if (bNegativePage)
3597 aFullBottomPoint.setX(aFullEndCellRect.Right() - aSnapEndOffset.X());
3598 else
3599 aFullBottomPoint.setX(aFullEndCellRect.Left() + aSnapEndOffset.X());
3600 aFullBottomPoint.setY(aFullEndCellRect.Top() + aSnapEndOffset.Y());
3601 tools::Rectangle aFullSnapRect(aFullTopPoint, aFullBottomPoint);
3602 aFullSnapRect.Normalize();
3604 if (aFullSnapRect != aActualSnapRect)
3606 bNeedsRestoreSize = true;
3607 aScaleWidth
3608 = Fraction(aFullSnapRect.getOpenWidth(), aActualSnapRect.getOpenWidth());
3609 if (!aScaleWidth.IsValid())
3610 aScaleWidth = Fraction(1, 1);
3611 aScaleHeight
3612 = Fraction(aFullSnapRect.getOpenHeight(), aActualSnapRect.getOpenHeight());
3613 if (!aScaleHeight.IsValid())
3614 aScaleHeight = Fraction(1, 1);
3615 pObj->NbcResize(aFullTopPoint, aScaleWidth, aScaleHeight);
3619 // The existence of an end address is equivalent to anchor mode "To Cell (resize with cell)".
3620 // XML needs end address in regard of untransformed shape. Those are contained in rShape but
3621 // could be received from NonRotatedObjData as well.
3622 // tdf#154005: We treat the combination of "To Cell (resize with cell)" anchor with 'size
3623 // protected' property as being "To cell" anchor.
3624 if (pObjData->mbResizeWithCell && !pObj->IsResizeProtect())
3626 OUString sEndAddress;
3627 ScRangeStringConverter::GetStringFromAddress(sEndAddress, rShape.aEndAddress, &rDoc,
3628 FormulaGrammar::CONV_OOO);
3629 AddAttribute(XML_NAMESPACE_TABLE, XML_END_CELL_ADDRESS, sEndAddress);
3630 OUStringBuffer sBuffer;
3631 GetMM100UnitConverter().convertMeasureToXML(sBuffer, rShape.nEndX);
3632 AddAttribute(XML_NAMESPACE_TABLE, XML_END_X, sBuffer.makeStringAndClear());
3633 GetMM100UnitConverter().convertMeasureToXML(sBuffer, rShape.nEndY);
3634 AddAttribute(XML_NAMESPACE_TABLE, XML_END_Y, sBuffer.makeStringAndClear());
3637 // Correct above calculated reference point for these cases:
3638 // a) For a RTL-sheet translate from matrix is not suitable, because the shape
3639 // from xml (which is always LTR) is not mirrored to negative page but shifted.
3640 // b) In case of horizontal mirrored, 'resize with cell' anchored custom shape, translate from
3641 // matrix has wrong values. FixMe: Why is translate wrong?
3642 if (bNegativePage
3643 || (pObj->GetObjIdentifier() == SdrObjKind::CustomShape
3644 && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX()
3645 && pObjData->mbResizeWithCell))
3647 // In these cases we set reference point so that the offset calculation in XML export
3648 // (= matrix translate - reference point) results in maStartOffset.
3649 ScDrawObjData* pNRObjData = ScDrawLayer::GetNonRotatedObjData(pObj);
3650 if (pNRObjData)
3652 awt::Point aMatrixTranslate = rShape.xShape->getPosition();
3653 aPoint.X = aMatrixTranslate.X - pNRObjData->maStartOffset.X();
3654 aPoint.Y = aMatrixTranslate.Y - pNRObjData->maStartOffset.Y();
3658 ExportShape(rDoc, rShape.xShape, &aPoint);
3660 if (bNeedsRestoreSize)
3662 Fraction aScaleWidthInvers(aScaleWidth.GetDenominator(), aScaleWidth.GetNumerator());
3663 if (!aScaleWidthInvers.IsValid())
3664 aScaleWidthInvers = Fraction(1, 1);
3665 Fraction aScaleHeightInvers(aScaleHeight.GetDenominator(), aScaleHeight.GetNumerator());
3666 if (!aScaleHeightInvers.IsValid())
3667 aScaleHeightInvers = Fraction(1, 1);
3668 pObj->NbcResize(aFullTopPoint, aScaleWidthInvers, aScaleHeightInvers);
3670 if (bNeedsRestorePosition)
3672 pObj->NbcMove(Size(-aMoveBy.X(), -aMoveBy.Y()));
3677 void ScXMLExport::WriteTableShapes(ScDocument& rDoc)
3679 ScMyTableShapes* pTableShapes(pSharedData->GetTableShapes());
3680 if (!pTableShapes || (*pTableShapes)[nCurrentTable].empty())
3681 return;
3683 OSL_ENSURE(pTableShapes->size() > static_cast<size_t>(nCurrentTable), "wrong Table");
3684 SvXMLElementExport aShapesElem(*this, XML_NAMESPACE_TABLE, XML_SHAPES, true, false);
3685 for (const auto& rxShape : (*pTableShapes)[nCurrentTable])
3687 if (rxShape.is())
3689 if (rDoc.IsNegativePage(static_cast<SCTAB>(nCurrentTable)))
3691 // RTL-mirroring refers to snap rectangle, not to logic rectangle, therefore cannot use
3692 // getPosition() and getSize(), but need property "FrameRect" from rxShape or
3693 // GetSnapRect() from associated SdrObject.
3694 uno::Reference<beans::XPropertySet> xShapeProp(rxShape, uno::UNO_QUERY);
3695 awt::Rectangle aFrameRect;
3696 if (!xShapeProp.is())
3698 SAL_WARN("sc", "no shape propertyset");
3699 continue;
3701 uno::Reference<beans::XPropertySetInfo> xPropSetInfo = xShapeProp->getPropertySetInfo();
3702 if (!xPropSetInfo->hasPropertyByName(u"FrameRect"_ustr))
3704 SAL_WARN("sc", "shape doesn't support FrameRect property");
3705 continue;
3707 if (xShapeProp->getPropertyValue(u"FrameRect"_ustr) >>= aFrameRect)
3709 // file format uses shape in LTR mode. newLeft = - oldRight = - (oldLeft + width).
3710 // newTranslate = oldTranslate - refPoint, oldTranslate from transformation matrix,
3711 // calculated in XMLShapeExport::exportShape common for all modules.
3712 // oldTranslate.X = oldLeft ==> refPoint.X = 2 * oldLeft + width
3713 awt::Point aRefPoint;
3714 aRefPoint.X = 2 * aFrameRect.X + aFrameRect.Width - 1;
3715 aRefPoint.Y = 0;
3716 ExportShape(rDoc, rxShape, &aRefPoint);
3718 // else should not happen
3720 else
3721 ExportShape(rDoc, rxShape, nullptr);
3724 (*pTableShapes)[nCurrentTable].clear();
3727 void ScXMLExport::WriteAreaLink( const ScMyCell& rMyCell )
3729 if( !rMyCell.bHasAreaLink )
3730 return;
3732 const ScMyAreaLink& rAreaLink = rMyCell.aAreaLink;
3733 AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, rAreaLink.sSourceStr );
3734 AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3735 AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(rAreaLink.sURL) );
3736 AddAttribute( XML_NAMESPACE_TABLE, XML_FILTER_NAME, rAreaLink.sFilter );
3737 if( !rAreaLink.sFilterOptions.isEmpty() )
3738 AddAttribute( XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, rAreaLink.sFilterOptions );
3739 AddAttribute( XML_NAMESPACE_TABLE, XML_LAST_COLUMN_SPANNED, OUString::number(rAreaLink.GetColCount()) );
3740 AddAttribute( XML_NAMESPACE_TABLE, XML_LAST_ROW_SPANNED, OUString::number(rAreaLink.GetRowCount()) );
3741 if( rAreaLink.nRefreshDelaySeconds )
3743 OUStringBuffer sValue;
3744 ::sax::Converter::convertDuration( sValue,
3745 static_cast<double>(rAreaLink.nRefreshDelaySeconds) / 86400 );
3746 AddAttribute( XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, sValue.makeStringAndClear() );
3748 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_CELL_RANGE_SOURCE, true, true );
3751 void ScXMLExport::exportAnnotationMeta( const uno::Reference < drawing::XShape >& xShape)
3753 ScPostIt* pNote = pCurrentCell->pNote;
3755 if (!pNote)
3756 return;
3758 // TODO : notes
3759 //is it still useful, as this call back is only called from ScXMLExport::WriteAnnotation
3760 // and should be in sync with pCurrentCell
3761 SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(pCurrentCell->maCellAddress);
3762 uno::Reference<drawing::XShape> xCurrentShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY );
3763 if (xCurrentShape.get()!=xShape.get())
3764 return;
3766 bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet(
3767 SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo) && !SvtSecurityOptions::IsOptionSet(
3768 SvtSecurityOptions::EOption::DocWarnKeepNoteAuthorDateInfo);
3770 const OUString& sAuthor(pNote->GetAuthor());
3771 if (!sAuthor.isEmpty())
3773 SvXMLElementExport aCreatorElem( *this, XML_NAMESPACE_DC,
3774 XML_CREATOR, true,
3775 false );
3776 Characters( bRemovePersonalInfo
3777 ? "Author" + OUString::number(SvXMLExport::GetInfoID(sAuthor))
3778 : sAuthor );
3781 const OUString aDate(bRemovePersonalInfo ? u"1970-01-01"_ustr : pNote->GetDate()); // Epoch time
3782 if (ScDocument* pDoc = GetDocument())
3784 SvNumberFormatter* pNumForm = pDoc->GetFormatTable();
3785 double fDate;
3786 sal_uInt32 nfIndex = pNumForm->GetFormatIndex(NF_DATE_SYS_DDMMYYYY, LANGUAGE_SYSTEM);
3787 if (pNumForm->IsNumberFormat(aDate, nfIndex, fDate))
3789 OUStringBuffer sBuf;
3790 GetMM100UnitConverter().convertDateTime(sBuf, fDate,true);
3791 SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC,
3792 XML_DATE, true,
3793 false );
3794 Characters(sBuf.makeStringAndClear());
3796 else
3798 SvXMLElementExport aDateElem( *this, XML_NAMESPACE_META,
3799 XML_DATE_STRING, true,
3800 false );
3801 Characters(aDate);
3804 else
3806 SvXMLElementExport aDateElem( *this, XML_NAMESPACE_META,
3807 XML_DATE_STRING, true,
3808 false );
3809 Characters(aDate);
3813 void ScXMLExport::WriteAnnotation(ScDocument& rDoc, const ScMyCell& rMyCell)
3815 ScPostIt* pNote = rDoc.GetNote(rMyCell.maCellAddress);
3816 if (!pNote)
3817 return;
3819 if (pNote->IsCaptionShown())
3820 AddAttribute(XML_NAMESPACE_OFFICE, XML_DISPLAY, XML_TRUE);
3822 pCurrentCell = &rMyCell;
3824 SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(rMyCell.maCellAddress);
3825 if (pNoteCaption)
3827 uno::Reference<drawing::XShape> xShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY );
3828 if (xShape.is())
3829 GetShapeExport()->exportShape(xShape, SEF_DEFAULT|XMLShapeExportFlags::ANNOTATION);
3832 pCurrentCell = nullptr;
3835 void ScXMLExport::WriteDetective(ScDocument& rDoc, const ScMyCell& rMyCell)
3837 if( !(rMyCell.bHasDetectiveObj || rMyCell.bHasDetectiveOp) )
3838 return;
3840 const ScMyDetectiveObjVec& rObjVec = rMyCell.aDetectiveObjVec;
3841 const ScMyDetectiveOpVec& rOpVec = rMyCell.aDetectiveOpVec;
3842 sal_Int32 nObjCount(rObjVec.size());
3843 sal_Int32 nOpCount(rOpVec.size());
3844 if( !(nObjCount || nOpCount) )
3845 return;
3847 SvXMLElementExport aDetElem( *this, XML_NAMESPACE_TABLE, XML_DETECTIVE, true, true );
3848 OUString sString;
3849 for(const auto& rObj : rObjVec)
3851 if (rObj.eObjType != SC_DETOBJ_CIRCLE)
3853 if( (rObj.eObjType == SC_DETOBJ_ARROW) || (rObj.eObjType == SC_DETOBJ_TOOTHERTAB))
3855 ScRangeStringConverter::GetStringFromRange( sString, rObj.aSourceRange, &rDoc, FormulaGrammar::CONV_OOO );
3856 AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sString );
3858 sString = ScXMLConverter::GetStringFromDetObjType( rObj.eObjType );
3859 AddAttribute( XML_NAMESPACE_TABLE, XML_DIRECTION, sString );
3860 if( rObj.bHasError )
3861 AddAttribute( XML_NAMESPACE_TABLE, XML_CONTAINS_ERROR, XML_TRUE );
3863 else
3864 AddAttribute( XML_NAMESPACE_TABLE, XML_MARKED_INVALID, XML_TRUE );
3865 SvXMLElementExport aRangeElem( *this, XML_NAMESPACE_TABLE, XML_HIGHLIGHTED_RANGE, true, true );
3867 for(const auto& rOp : rOpVec)
3869 OUString sOpString = ScXMLConverter::GetStringFromDetOpType( rOp.eOpType );
3870 AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, sOpString );
3871 AddAttribute( XML_NAMESPACE_TABLE, XML_INDEX, OUString::number(rOp.nIndex) );
3872 SvXMLElementExport aRangeElem( *this, XML_NAMESPACE_TABLE, XML_OPERATION, true, true );
3876 void ScXMLExport::SetRepeatAttribute(sal_Int32 nEqualCellCount, bool bIncProgress)
3878 // nEqualCellCount is additional cells, so the attribute value is nEqualCellCount+1
3879 if (nEqualCellCount > 0)
3881 sal_Int32 nTemp(nEqualCellCount + 1);
3882 OUString sOUEqualCellCount(OUString::number(nTemp));
3883 AddAttribute(sAttrColumnsRepeated, sOUEqualCellCount);
3884 if (bIncProgress)
3885 IncrementProgressBar(false, nEqualCellCount);
3889 //static
3890 bool ScXMLExport::IsEditCell(const ScMyCell& rCell)
3892 return rCell.maBaseCell.getType() == CELLTYPE_EDIT;
3895 //static
3896 bool ScXMLExport::IsCellEqual(ScDocument& rDoc, const ScMyCell& aCell1, const ScMyCell& aCell2)
3898 bool bIsEqual = false;
3899 if( !aCell1.bIsMergedBase && !aCell2.bIsMergedBase &&
3900 aCell1.bIsCovered == aCell2.bIsCovered &&
3901 !aCell1.bIsMatrixBase && !aCell2.bIsMatrixBase &&
3902 aCell1.bIsMatrixCovered == aCell2.bIsMatrixCovered &&
3903 aCell1.bHasAnnotation == aCell2.bHasAnnotation &&
3904 !aCell1.bHasShape && !aCell2.bHasShape &&
3905 aCell1.bHasAreaLink == aCell2.bHasAreaLink &&
3906 !aCell1.bHasDetectiveObj && !aCell2.bHasDetectiveObj)
3908 if( (aCell1.bHasAreaLink &&
3909 (aCell1.aAreaLink.GetColCount() == 1) &&
3910 (aCell2.aAreaLink.GetColCount() == 1) &&
3911 aCell1.aAreaLink.Compare( aCell2.aAreaLink ) ) ||
3912 !aCell1.bHasAreaLink )
3914 if (!aCell1.bHasAnnotation)
3916 if ((((aCell1.nStyleIndex == aCell2.nStyleIndex) && (aCell1.bIsAutoStyle == aCell2.bIsAutoStyle)) ||
3917 ((aCell1.nStyleIndex == aCell2.nStyleIndex) && (aCell1.nStyleIndex == -1))) &&
3918 aCell1.nValidationIndex == aCell2.nValidationIndex &&
3919 aCell1.nType == aCell2.nType)
3921 switch ( aCell1.nType )
3923 case table::CellContentType_EMPTY :
3925 bIsEqual = true;
3927 break;
3928 case table::CellContentType_VALUE :
3930 // #i29101# number format may be different from column default styles,
3931 // but can lead to different value types, so it must also be compared
3932 bIsEqual = (aCell1.nNumberFormat == aCell2.nNumberFormat) &&
3933 (aCell1.maBaseCell.getDouble() == aCell2.maBaseCell.getDouble());
3935 break;
3936 case table::CellContentType_TEXT :
3938 if (IsEditCell(aCell1) || IsEditCell(aCell2))
3939 bIsEqual = false;
3940 else
3942 bIsEqual = (aCell1.maBaseCell.getString(&rDoc) == aCell2.maBaseCell.getString(&rDoc));
3945 break;
3946 case table::CellContentType_FORMULA :
3948 bIsEqual = false;
3950 break;
3951 default :
3953 bIsEqual = false;
3955 break;
3961 return bIsEqual;
3964 void ScXMLExport::WriteCalculationSettings(ScDocument& rDoc, const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc)
3966 uno::Reference<beans::XPropertySet> xPropertySet(xSpreadDoc, uno::UNO_QUERY);
3967 if (!xPropertySet.is())
3968 return;
3970 bool bCalcAsShown (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_CALCASSHOWN) ));
3971 bool bIgnoreCase (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_IGNORECASE) ));
3972 bool bLookUpLabels (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_LOOKUPLABELS) ));
3973 bool bMatchWholeCell (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_MATCHWHOLE) ));
3974 bool bUseRegularExpressions (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_REGEXENABLED) ));
3975 bool bUseWildcards (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_WILDCARDSENABLED) ));
3976 if (bUseWildcards && bUseRegularExpressions)
3977 bUseRegularExpressions = false; // mutually exclusive, wildcards take precedence
3978 bool bIsIterationEnabled (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_ITERENABLED) ));
3979 sal_uInt16 nYear2000 (rDoc.GetDocOptions().GetYear2000());
3980 sal_Int32 nIterationCount(100);
3981 xPropertySet->getPropertyValue( SC_UNO_ITERCOUNT ) >>= nIterationCount;
3982 double fIterationEpsilon = 0;
3983 xPropertySet->getPropertyValue( SC_UNO_ITEREPSILON ) >>= fIterationEpsilon;
3984 util::Date aNullDate;
3985 xPropertySet->getPropertyValue( SC_UNO_NULLDATE ) >>= aNullDate;
3986 if (!(bCalcAsShown || bIgnoreCase || !bLookUpLabels || !bMatchWholeCell || !bUseRegularExpressions ||
3987 bUseWildcards ||
3988 bIsIterationEnabled || nIterationCount != 100 || !::rtl::math::approxEqual(fIterationEpsilon, 0.001) ||
3989 aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 || nYear2000 != 1930))
3990 return;
3992 if (bIgnoreCase)
3993 AddAttribute(XML_NAMESPACE_TABLE, XML_CASE_SENSITIVE, XML_FALSE);
3994 if (bCalcAsShown)
3995 AddAttribute(XML_NAMESPACE_TABLE, XML_PRECISION_AS_SHOWN, XML_TRUE);
3996 if (!bMatchWholeCell)
3997 AddAttribute(XML_NAMESPACE_TABLE, XML_SEARCH_CRITERIA_MUST_APPLY_TO_WHOLE_CELL, XML_FALSE);
3998 if (!bLookUpLabels)
3999 AddAttribute(XML_NAMESPACE_TABLE, XML_AUTOMATIC_FIND_LABELS, XML_FALSE);
4000 if (!bUseRegularExpressions)
4001 AddAttribute(XML_NAMESPACE_TABLE, XML_USE_REGULAR_EXPRESSIONS, XML_FALSE);
4002 if (bUseWildcards)
4003 AddAttribute(XML_NAMESPACE_TABLE, XML_USE_WILDCARDS, XML_TRUE);
4004 if (nYear2000 != 1930)
4006 AddAttribute(XML_NAMESPACE_TABLE, XML_NULL_YEAR, OUString::number(nYear2000));
4008 SvXMLElementExport aCalcSettings(*this, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true);
4010 if (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899)
4012 OUStringBuffer sDate;
4013 SvXMLUnitConverter::convertDateTime(sDate, 0.0, aNullDate);
4014 AddAttribute(XML_NAMESPACE_TABLE, XML_DATE_VALUE, sDate.makeStringAndClear());
4015 SvXMLElementExport aElemNullDate(*this, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true);
4017 if (bIsIterationEnabled || nIterationCount != 100 || !::rtl::math::approxEqual(fIterationEpsilon, 0.001))
4019 if (bIsIterationEnabled)
4020 AddAttribute(XML_NAMESPACE_TABLE, XML_STATUS, XML_ENABLE);
4021 if (nIterationCount != 100)
4023 AddAttribute(XML_NAMESPACE_TABLE, XML_STEPS, OUString::number(nIterationCount));
4025 if (!::rtl::math::approxEqual(fIterationEpsilon, 0.001))
4027 OUStringBuffer sBuffer;
4028 ::sax::Converter::convertDouble(sBuffer,
4029 fIterationEpsilon);
4030 AddAttribute(XML_NAMESPACE_TABLE, XML_MAXIMUM_DIFFERENCE, sBuffer.makeStringAndClear());
4032 SvXMLElementExport aElemIteration(*this, XML_NAMESPACE_TABLE, XML_ITERATION, true, true);
4037 void ScXMLExport::WriteTableSource()
4039 uno::Reference <sheet::XSheetLinkable> xLinkable (xCurrentTable, uno::UNO_QUERY);
4040 if (!(xLinkable.is() && GetModel().is()))
4041 return;
4043 sheet::SheetLinkMode nMode (xLinkable->getLinkMode());
4044 if (nMode == sheet::SheetLinkMode_NONE)
4045 return;
4047 OUString sLink (xLinkable->getLinkUrl());
4048 uno::Reference <beans::XPropertySet> xProps (GetModel(), uno::UNO_QUERY);
4049 if (!xProps.is())
4050 return;
4052 uno::Reference <container::XIndexAccess> xIndex(xProps->getPropertyValue(SC_UNO_SHEETLINKS), uno::UNO_QUERY);
4053 if (!xIndex.is())
4054 return;
4056 sal_Int32 nCount(xIndex->getCount());
4057 if (!nCount)
4058 return;
4060 bool bFound(false);
4061 uno::Reference <beans::XPropertySet> xLinkProps;
4062 for (sal_Int32 i = 0; (i < nCount) && !bFound; ++i)
4064 xLinkProps.set(xIndex->getByIndex(i), uno::UNO_QUERY);
4065 if (xLinkProps.is())
4067 OUString sNewLink;
4068 if (xLinkProps->getPropertyValue(SC_UNONAME_LINKURL) >>= sNewLink)
4069 bFound = sLink == sNewLink;
4072 if (!(bFound && xLinkProps.is()))
4073 return;
4075 OUString sFilter;
4076 OUString sFilterOptions;
4077 OUString sTableName (xLinkable->getLinkSheetName());
4078 sal_Int32 nRefresh(0);
4079 xLinkProps->getPropertyValue(SC_UNONAME_FILTER) >>= sFilter;
4080 xLinkProps->getPropertyValue(SC_UNONAME_FILTOPT) >>= sFilterOptions;
4081 xLinkProps->getPropertyValue(SC_UNONAME_REFDELAY) >>= nRefresh;
4082 if (sLink.isEmpty())
4083 return;
4085 AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
4086 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(sLink));
4087 if (!sTableName.isEmpty())
4088 AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, sTableName);
4089 if (!sFilter.isEmpty())
4090 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, sFilter);
4091 if (!sFilterOptions.isEmpty())
4092 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, sFilterOptions);
4093 if (nMode != sheet::SheetLinkMode_NORMAL)
4094 AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY);
4095 if( nRefresh )
4097 OUStringBuffer sBuffer;
4098 ::sax::Converter::convertDuration( sBuffer,
4099 static_cast<double>(nRefresh) / 86400 );
4100 AddAttribute( XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, sBuffer.makeStringAndClear() );
4102 SvXMLElementExport aSourceElem(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, true, true);
4105 // core implementation
4106 void ScXMLExport::WriteScenario(ScDocument& rDoc)
4108 if (!rDoc.IsScenario(static_cast<SCTAB>(nCurrentTable)))
4109 return;
4111 OUString sComment;
4112 Color aColor;
4113 ScScenarioFlags nFlags;
4114 rDoc.GetScenarioData(static_cast<SCTAB>(nCurrentTable), sComment, aColor, nFlags);
4115 if (!(nFlags & ScScenarioFlags::ShowFrame))
4116 AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY_BORDER, XML_FALSE);
4117 OUStringBuffer aBuffer;
4118 ::sax::Converter::convertColor(aBuffer, aColor);
4119 AddAttribute(XML_NAMESPACE_TABLE, XML_BORDER_COLOR, aBuffer.makeStringAndClear());
4120 if (!(nFlags & ScScenarioFlags::TwoWay))
4121 AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_BACK, XML_FALSE);
4122 if (!(nFlags & ScScenarioFlags::Attrib))
4123 AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_STYLES, XML_FALSE);
4124 if (nFlags & ScScenarioFlags::Value)
4125 AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_FORMULAS, XML_FALSE);
4126 if (nFlags & ScScenarioFlags::Protected)
4127 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
4128 ::sax::Converter::convertBool(aBuffer,
4129 rDoc.IsActiveScenario(static_cast<SCTAB>(nCurrentTable)));
4130 AddAttribute(XML_NAMESPACE_TABLE, XML_IS_ACTIVE, aBuffer.makeStringAndClear());
4131 const ScRangeList* pRangeList = rDoc.GetScenarioRanges(static_cast<SCTAB>(nCurrentTable));
4132 OUString sRangeListStr;
4133 ScRangeStringConverter::GetStringFromRangeList( sRangeListStr, pRangeList, &rDoc, FormulaGrammar::CONV_OOO );
4134 AddAttribute(XML_NAMESPACE_TABLE, XML_SCENARIO_RANGES, sRangeListStr);
4135 if (!sComment.isEmpty())
4136 AddAttribute(XML_NAMESPACE_TABLE, XML_COMMENT, sComment);
4137 SvXMLElementExport aElem(*this, XML_NAMESPACE_TABLE, XML_SCENARIO, true, true);
4140 void ScXMLExport::WriteTheLabelRanges(ScDocument& rDoc, const uno::Reference< sheet::XSpreadsheetDocument >& xSpreadDoc)
4142 uno::Reference< beans::XPropertySet > xDocProp( xSpreadDoc, uno::UNO_QUERY );
4143 if( !xDocProp.is() ) return;
4145 sal_Int32 nCount(0);
4146 uno::Reference< container::XIndexAccess > xColRangesIAccess(xDocProp->getPropertyValue( SC_UNO_COLLABELRNG ), uno::UNO_QUERY);
4147 if( xColRangesIAccess.is() )
4148 nCount += xColRangesIAccess->getCount();
4150 uno::Reference< container::XIndexAccess > xRowRangesIAccess(xDocProp->getPropertyValue( SC_UNO_ROWLABELRNG ), uno::UNO_QUERY);
4151 if( xRowRangesIAccess.is() )
4152 nCount += xRowRangesIAccess->getCount();
4154 if( nCount )
4156 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGES, true, true );
4157 WriteLabelRanges(rDoc, xColRangesIAccess, true);
4158 WriteLabelRanges(rDoc, xRowRangesIAccess, false);
4162 void ScXMLExport::WriteLabelRanges(ScDocument& rDoc, const uno::Reference< container::XIndexAccess >& xRangesIAccess, bool bColumn)
4164 if( !xRangesIAccess.is() ) return;
4166 sal_Int32 nCount(xRangesIAccess->getCount());
4167 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
4169 uno::Reference< sheet::XLabelRange > xRange(xRangesIAccess->getByIndex( nIndex ), uno::UNO_QUERY);
4170 if( xRange.is() )
4172 OUString sRangeStr;
4173 table::CellRangeAddress aCellRange( xRange->getLabelArea() );
4174 ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, &rDoc, FormulaGrammar::CONV_OOO );
4175 AddAttribute( XML_NAMESPACE_TABLE, XML_LABEL_CELL_RANGE_ADDRESS, sRangeStr );
4176 aCellRange = xRange->getDataArea();
4177 ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, &rDoc, FormulaGrammar::CONV_OOO );
4178 AddAttribute( XML_NAMESPACE_TABLE, XML_DATA_CELL_RANGE_ADDRESS, sRangeStr );
4179 AddAttribute( XML_NAMESPACE_TABLE, XML_ORIENTATION, bColumn ? XML_COLUMN : XML_ROW );
4180 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGE, true, true );
4185 void ScXMLExport::WriteNamedExpressions(ScDocument& rDoc)
4187 ScRangeName* pNamedRanges = rDoc.GetRangeName();
4188 WriteNamedRange(rDoc, pNamedRanges);
4191 void ScXMLExport::WriteExternalDataMapping(ScDocument& rDoc)
4193 if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4194 // Export this only for 1.2 extended and above.
4195 return;
4197 sc::ExternalDataMapper& rDataMapper = rDoc.GetExternalDataMapper();
4198 auto& rDataSources = rDataMapper.getDataSources();
4200 if (rDataSources.empty())
4201 return;
4203 SvXMLElementExport aMappings(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPINGS, true, true);
4204 for (const auto& itr : rDataSources)
4206 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, itr.getURL());
4207 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PROVIDER, itr.getProvider());
4208 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATA_FREQUENCY, OUString::number(sc::ExternalDataSource::getUpdateFrequency()));
4209 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_ID, itr.getID());
4210 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATABASE_NAME, itr.getDBName());
4212 SvXMLElementExport aMapping(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPING, true, true);
4213 // Add the data transformations
4214 WriteExternalDataTransformations(rDoc, itr.getDataTransformation());
4218 void ScXMLExport::WriteExternalDataTransformations(ScDocument& rDoc, const std::vector<std::shared_ptr<sc::DataTransformation>>& aDataTransformations)
4220 SvXMLElementExport aTransformations(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_TRANSFORMATIONS, true, true);
4221 for (auto& itr : aDataTransformations)
4223 sc::TransformationType aTransformationType = itr->getTransformationType();
4225 switch(aTransformationType)
4227 case sc::TransformationType::DELETE_TRANSFORMATION:
4229 // Delete Columns Transformation
4230 std::shared_ptr<sc::ColumnRemoveTransformation> aDeleteTransformation = std::dynamic_pointer_cast<sc::ColumnRemoveTransformation>(itr);
4231 std::set<SCCOL> aColumns = aDeleteTransformation->getColumns();
4232 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_REMOVE_TRANSFORMATION, true, true);
4233 for(auto& col : aColumns)
4235 // Add Columns
4236 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4237 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4240 break;
4241 case sc::TransformationType::SPLIT_TRANSFORMATION:
4243 std::shared_ptr<sc::SplitColumnTransformation> aSplitTransformation = std::dynamic_pointer_cast<sc::SplitColumnTransformation>(itr);
4245 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(aSplitTransformation->getColumn()));
4246 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SEPARATOR, OUString::number(aSplitTransformation->getSeparator()));
4247 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_SPLIT_TRANSFORMATION, true, true);
4249 break;
4250 case sc::TransformationType::MERGE_TRANSFORMATION:
4252 // Merge Transformation
4253 std::shared_ptr<sc::MergeColumnTransformation> aMergeTransformation = std::dynamic_pointer_cast<sc::MergeColumnTransformation>(itr);
4254 std::set<SCCOL> aColumns = aMergeTransformation->getColumns();
4256 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MERGE_STRING, aMergeTransformation->getMergeString());
4257 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_MERGE_TRANSFORMATION, true, true);
4259 for(auto& col : aColumns)
4261 // Columns
4262 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4263 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4266 break;
4267 case sc::TransformationType::SORT_TRANSFORMATION:
4269 // Sort Transformation
4270 std::shared_ptr<sc::SortTransformation> aSortTransformation = std::dynamic_pointer_cast<sc::SortTransformation>(itr);
4271 ScSortParam aSortParam = aSortTransformation->getSortParam();
4272 const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
4273 const sc::DataStream* pStrm = rMgr.getDataStream();
4274 if (!pStrm)
4275 // No data stream.
4276 return;
4278 // Streamed range
4279 ScRange aRange = pStrm->GetRange();
4281 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_SORT_TRANSFORMATION, true, true);
4283 writeSort(*this, aSortParam, aRange, rDoc);
4285 break;
4286 case sc::TransformationType::TEXT_TRANSFORMATION:
4288 // Text Transformation
4289 std::shared_ptr<sc::TextTransformation> aTextTransformation = std::dynamic_pointer_cast<sc::TextTransformation>(itr);
4291 sc::TEXT_TRANSFORM_TYPE aTextTransformType = aTextTransformation->getTextTransformationType();
4293 switch ( aTextTransformType )
4295 case sc::TEXT_TRANSFORM_TYPE::TO_LOWER:
4296 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_LOWERCASE);
4297 break;
4298 case sc::TEXT_TRANSFORM_TYPE::TO_UPPER:
4299 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_UPPERCASE);
4300 break;
4301 case sc::TEXT_TRANSFORM_TYPE::CAPITALIZE:
4302 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_CAPITALIZE);
4303 break;
4304 case sc::TEXT_TRANSFORM_TYPE::TRIM:
4305 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_TRIM);
4306 break;
4309 std::set<SCCOL> aColumns = aTextTransformation->getColumns();
4311 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_TEXT_TRANSFORMATION, true, true);
4313 for(auto& col : aColumns)
4315 // Columns
4316 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4317 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4320 break;
4321 case sc::TransformationType::AGGREGATE_FUNCTION:
4323 // Aggregate Transformation
4324 std::shared_ptr<sc::AggregateFunction> aAggregateFunction = std::dynamic_pointer_cast<sc::AggregateFunction>(itr);
4325 std::set<SCCOL> aColumns = aAggregateFunction->getColumns();
4327 sc::AGGREGATE_FUNCTION aAggregateType = aAggregateFunction->getAggregateType();
4329 switch (aAggregateType)
4331 case sc::AGGREGATE_FUNCTION::SUM:
4332 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SUM);
4333 break;
4334 case sc::AGGREGATE_FUNCTION::AVERAGE:
4335 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_AVERAGE);
4336 break;
4337 case sc::AGGREGATE_FUNCTION::MIN:
4338 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MIN);
4339 break;
4340 case sc::AGGREGATE_FUNCTION::MAX:
4341 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MAX);
4342 break;
4345 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT,XML_COLUMN_AGGREGATE_TRANSFORMATION, true, true);
4347 for(auto& col : aColumns)
4349 // Columns
4350 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4351 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4354 break;
4355 case sc::TransformationType::NUMBER_TRANSFORMATION:
4357 // Number Transformation
4358 std::shared_ptr<sc::NumberTransformation> aNumberTransformation = std::dynamic_pointer_cast<sc::NumberTransformation>(itr);
4360 sc::NUMBER_TRANSFORM_TYPE aNumberTransformType = aNumberTransformation->getNumberTransformationType();
4362 switch ( aNumberTransformType )
4364 case sc::NUMBER_TRANSFORM_TYPE::ROUND:
4365 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND);
4366 break;
4367 case sc::NUMBER_TRANSFORM_TYPE::ROUND_UP:
4368 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND_UP);
4369 break;
4370 case sc::NUMBER_TRANSFORM_TYPE::ROUND_DOWN:
4371 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND_DOWN);
4372 break;
4373 case sc::NUMBER_TRANSFORM_TYPE::ABSOLUTE:
4374 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ABS);
4375 break;
4376 case sc::NUMBER_TRANSFORM_TYPE::LOG_E:
4377 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_LOG);
4378 break;
4379 case sc::NUMBER_TRANSFORM_TYPE::LOG_10:
4380 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_LOG_10);
4381 break;
4382 case sc::NUMBER_TRANSFORM_TYPE::CUBE:
4383 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CUBE);
4384 break;
4385 case sc::NUMBER_TRANSFORM_TYPE::SQUARE:
4386 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SQUARE);
4387 break;
4388 case sc::NUMBER_TRANSFORM_TYPE::SQUARE_ROOT:
4389 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SQUARE_ROOT);
4390 break;
4391 case sc::NUMBER_TRANSFORM_TYPE::EXPONENT:
4392 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_EXPONENTIAL);
4393 break;
4394 case sc::NUMBER_TRANSFORM_TYPE::IS_EVEN:
4395 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_EVEN);
4396 break;
4397 case sc::NUMBER_TRANSFORM_TYPE::IS_ODD:
4398 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ODD);
4399 break;
4400 case sc::NUMBER_TRANSFORM_TYPE::SIGN:
4401 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SIGN);
4402 break;
4405 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PRECISION, OUString::number(aNumberTransformation->getPrecision()));
4406 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_NUMBER_TRANSFORMATION, true, true);
4408 std::set<SCCOL> aColumns = aNumberTransformation->getColumn();
4409 for(auto& col : aColumns)
4411 // Columns
4412 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4413 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4416 break;
4417 case sc::TransformationType::REMOVE_NULL_TRANSFORMATION:
4419 // Replace Null Transformation
4420 std::shared_ptr<sc::ReplaceNullTransformation> aReplaceNullTransformation = std::dynamic_pointer_cast<sc::ReplaceNullTransformation>(itr);
4421 std::set<SCCOL> aColumns = aReplaceNullTransformation->getColumn();
4423 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_REPLACE_STRING, aReplaceNullTransformation->getReplaceString());
4424 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_REPLACENULL_TRANSFORMATION, true, true);
4426 for(auto& col : aColumns)
4428 // Columns
4429 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4430 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4433 break;
4434 case sc::TransformationType::DATETIME_TRANSFORMATION:
4436 // Number Transformation
4437 std::shared_ptr<sc::DateTimeTransformation> aDateTimeTransformation = std::dynamic_pointer_cast<sc::DateTimeTransformation>(itr);
4439 sc::DATETIME_TRANSFORMATION_TYPE aDateTimeTransformationType = aDateTimeTransformation->getDateTimeTransformationType();
4441 switch ( aDateTimeTransformationType )
4443 case sc::DATETIME_TRANSFORMATION_TYPE::DATE_STRING:
4444 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DATE_STRING);
4445 break;
4446 case sc::DATETIME_TRANSFORMATION_TYPE::YEAR:
4447 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_YEAR);
4448 break;
4449 case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR:
4450 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_YEAR);
4451 break;
4452 case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR:
4453 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_YEAR);
4454 break;
4455 case sc::DATETIME_TRANSFORMATION_TYPE::MONTH:
4456 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MONTH);
4457 break;
4458 case sc::DATETIME_TRANSFORMATION_TYPE::MONTH_NAME:
4459 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MONTH_NAME);
4460 break;
4461 case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH:
4462 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_MONTH);
4463 break;
4464 case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH:
4465 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_MONTH);
4466 break;
4467 case sc::DATETIME_TRANSFORMATION_TYPE::DAY:
4468 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY);
4469 break;
4470 case sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK:
4471 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY_OF_WEEK);
4472 break;
4473 case sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR:
4474 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY_OF_YEAR);
4475 break;
4476 case sc::DATETIME_TRANSFORMATION_TYPE::QUARTER:
4477 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_QUARTER);
4478 break;
4479 case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER:
4480 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_QUARTER);
4481 break;
4482 case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER:
4483 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_QUARTER);
4484 break;
4485 case sc::DATETIME_TRANSFORMATION_TYPE::TIME:
4486 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_TIME);
4487 break;
4488 case sc::DATETIME_TRANSFORMATION_TYPE::HOUR:
4489 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_HOUR);
4490 break;
4491 case sc::DATETIME_TRANSFORMATION_TYPE::MINUTE:
4492 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MINUTE);
4493 break;
4494 case sc::DATETIME_TRANSFORMATION_TYPE::SECOND:
4495 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SECONDS);
4496 break;
4499 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_DATETIME_TRANSFORMATION, true, true);
4501 std::set<SCCOL> aColumns = aDateTimeTransformation->getColumn();
4502 for(auto& col : aColumns)
4504 // Columns
4505 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4506 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4509 break;
4510 default:
4511 break;
4516 void ScXMLExport::WriteDataStream(ScDocument& rDoc)
4518 if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
4519 // Export this only in experimental mode.
4520 return;
4522 if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4523 // Export this only for 1.2 extended and above.
4524 return;
4526 const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
4527 const sc::DataStream* pStrm = rMgr.getDataStream();
4528 if (!pStrm)
4529 // No data stream.
4530 return;
4532 // Source URL
4533 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(pStrm->GetURL()));
4535 // Streamed range
4536 ScRange aRange = pStrm->GetRange();
4537 OUString aRangeStr;
4538 ScRangeStringConverter::GetStringFromRange(
4539 aRangeStr, aRange, &rDoc, formula::FormulaGrammar::CONV_OOO);
4540 AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aRangeStr);
4542 // Empty line refresh option.
4543 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_EMPTY_LINE_REFRESH, pStrm->IsRefreshOnEmptyLine() ? XML_TRUE : XML_FALSE);
4545 // New data insertion position. Either top of bottom. Default to bottom.
4546 xmloff::token::XMLTokenEnum eInsertPosition = XML_BOTTOM;
4547 if (pStrm->GetMove() == sc::DataStream::MOVE_DOWN)
4548 eInsertPosition = XML_TOP;
4550 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_INSERTION_POSITION, eInsertPosition);
4552 SvXMLElementExport aElem(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_STREAM_SOURCE, true, true);
4555 void ScXMLExport::WriteNamedRange(ScDocument& rDoc, ScRangeName* pRangeName)
4557 //write a global or local ScRangeName
4558 SvXMLElementExport aElemNEs(*this, XML_NAMESPACE_TABLE, XML_NAMED_EXPRESSIONS, true, true);
4559 for (const auto& rxEntry : *pRangeName)
4561 AddAttribute(sAttrName, rxEntry.second->GetName());
4563 OUString sBaseCellAddress;
4564 rxEntry.second->ValidateTabRefs();
4565 ScRangeStringConverter::GetStringFromAddress( sBaseCellAddress, rxEntry.second->GetPos(), &rDoc,
4566 FormulaGrammar::CONV_OOO, ' ', false, ScRefFlags::ADDR_ABS_3D);
4567 assert(!sBaseCellAddress.isEmpty());
4568 AddAttribute(XML_NAMESPACE_TABLE, XML_BASE_CELL_ADDRESS, sBaseCellAddress);
4570 OUString sTempSymbol(rxEntry.second->GetSymbol(rDoc.GetStorageGrammar()));
4571 ScRange aRange;
4572 if (rxEntry.second->IsReference(aRange))
4575 OUString sContent(sTempSymbol.copy(1, sTempSymbol.getLength() -2 ));
4576 AddAttribute(XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sContent);
4578 sal_Int32 nRangeType = rxEntry.second->GetUnoType();
4579 OUStringBuffer sBufferRangeType;
4580 if ((nRangeType & sheet::NamedRangeFlag::COLUMN_HEADER) == sheet::NamedRangeFlag::COLUMN_HEADER)
4581 sBufferRangeType.append(GetXMLToken(XML_REPEAT_COLUMN));
4582 if ((nRangeType & sheet::NamedRangeFlag::ROW_HEADER) == sheet::NamedRangeFlag::ROW_HEADER)
4584 if (!sBufferRangeType.isEmpty())
4585 sBufferRangeType.append(" ");
4586 sBufferRangeType.append(GetXMLToken(XML_REPEAT_ROW));
4588 if ((nRangeType & sheet::NamedRangeFlag::FILTER_CRITERIA) == sheet::NamedRangeFlag::FILTER_CRITERIA)
4590 if (!sBufferRangeType.isEmpty())
4591 sBufferRangeType.append(" ");
4592 sBufferRangeType.append(GetXMLToken(XML_FILTER));
4594 if ((nRangeType & sheet::NamedRangeFlag::PRINT_AREA) == sheet::NamedRangeFlag::PRINT_AREA)
4596 if (!sBufferRangeType.isEmpty())
4597 sBufferRangeType.append(" ");
4598 sBufferRangeType.append(GetXMLToken(XML_PRINT_RANGE));
4600 if ((nRangeType & sheet::NamedRangeFlag::HIDDEN) == sheet::NamedRangeFlag::HIDDEN)
4602 if (!sBufferRangeType.isEmpty())
4603 sBufferRangeType.append(" ");
4604 sBufferRangeType.append(GetXMLToken(XML_HIDDEN));
4606 OUString sRangeType = sBufferRangeType.makeStringAndClear();
4607 if (!sRangeType.isEmpty())
4608 AddAttribute(XML_NAMESPACE_TABLE, XML_RANGE_USABLE_AS, sRangeType);
4609 SvXMLElementExport aElemNR(*this, XML_NAMESPACE_TABLE, XML_NAMED_RANGE, true, true);
4612 else
4614 AddAttribute(XML_NAMESPACE_TABLE, XML_EXPRESSION, sTempSymbol);
4615 // Check if it is a hidden named expression
4616 sal_Int32 nRangeType = rxEntry.second->GetUnoType();
4617 if ((nRangeType & sheet::NamedRangeFlag::HIDDEN) == sheet::NamedRangeFlag::HIDDEN)
4618 AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, XML_TRUE);
4619 SvXMLElementExport aElemNE(*this, XML_NAMESPACE_TABLE, XML_NAMED_EXPRESSION, true, true);
4624 void ScXMLExport::exportSparklineGroups(ScDocument& rDoc, SCTAB nTable)
4626 sc::SparklineGroupsExport aSparklineGroupExport(rDoc, *this, nTable);
4627 aSparklineGroupExport.write();
4630 namespace {
4632 OUString getCondFormatEntryType(const ScColorScaleEntry& rEntry, bool bFirst = true)
4634 switch(rEntry.GetType())
4636 case COLORSCALE_MIN:
4637 return u"minimum"_ustr;
4638 case COLORSCALE_MAX:
4639 return u"maximum"_ustr;
4640 case COLORSCALE_PERCENT:
4641 return u"percent"_ustr;
4642 case COLORSCALE_PERCENTILE:
4643 return u"percentile"_ustr;
4644 case COLORSCALE_FORMULA:
4645 return u"formula"_ustr;
4646 case COLORSCALE_VALUE:
4647 return u"number"_ustr;
4648 case COLORSCALE_AUTO:
4649 // only important for data bars
4650 if(bFirst)
4651 return u"auto-minimum"_ustr;
4652 else
4653 return u"auto-maximum"_ustr;
4655 return OUString();
4658 OUString getDateStringForType(condformat::ScCondFormatDateType eType)
4660 switch(eType)
4662 case condformat::TODAY:
4663 return u"today"_ustr;
4664 case condformat::YESTERDAY:
4665 return u"yesterday"_ustr;
4666 case condformat::TOMORROW:
4667 return u"tomorrow"_ustr;
4668 case condformat::LAST7DAYS:
4669 return u"last-7-days"_ustr;
4670 case condformat::THISWEEK:
4671 return u"this-week"_ustr;
4672 case condformat::LASTWEEK:
4673 return u"last-week"_ustr;
4674 case condformat::NEXTWEEK:
4675 return u"next-week"_ustr;
4676 case condformat::THISMONTH:
4677 return u"this-month"_ustr;
4678 case condformat::LASTMONTH:
4679 return u"last-month"_ustr;
4680 case condformat::NEXTMONTH:
4681 return u"next-month"_ustr;
4682 case condformat::THISYEAR:
4683 return u"this-year"_ustr;
4684 case condformat::LASTYEAR:
4685 return u"last-year"_ustr;
4686 case condformat::NEXTYEAR:
4687 return u"next-year"_ustr;
4690 return OUString();
4695 void ScXMLExport::ExportConditionalFormat(ScDocument& rDoc, SCTAB nTab)
4697 ScConditionalFormatList* pCondFormatList = rDoc.GetCondFormList(nTab);
4698 if(!pCondFormatList)
4699 return;
4701 if (pCondFormatList->empty())
4702 return;
4704 SvXMLElementExport aElementCondFormats(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITIONAL_FORMATS, true, true);
4706 for(const auto& rxCondFormat : *pCondFormatList)
4708 OUString sRanges;
4709 const ScRangeList& rRangeList = rxCondFormat->GetRange();
4710 ScRangeStringConverter::GetStringFromRangeList( sRanges, &rRangeList, &rDoc, formula::FormulaGrammar::CONV_OOO );
4711 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TARGET_RANGE_ADDRESS, sRanges);
4712 SvXMLElementExport aElementCondFormat(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITIONAL_FORMAT, true, true);
4713 size_t nEntries = rxCondFormat->size();
4714 for(size_t i = 0; i < nEntries; ++i)
4716 const ScFormatEntry* pFormatEntry = rxCondFormat->GetEntry(i);
4717 if(pFormatEntry->GetType()==ScFormatEntry::Type::Condition)
4719 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
4720 OUStringBuffer aCond;
4721 ScAddress aPos = pEntry->GetSrcPos();
4722 switch(pEntry->GetOperation())
4724 case ScConditionMode::Equal:
4725 aCond.append("=" + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4726 break;
4727 case ScConditionMode::Less:
4728 aCond.append("<" + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4729 break;
4730 case ScConditionMode::Greater:
4731 aCond.append(">" + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4732 break;
4733 case ScConditionMode::EqLess:
4734 aCond.append("<=" + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4735 break;
4736 case ScConditionMode::EqGreater:
4737 aCond.append(">=" + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4738 break;
4739 case ScConditionMode::NotEqual:
4740 aCond.append("!=" + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4741 break;
4742 case ScConditionMode::Between:
4743 aCond.append("between("
4744 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4745 + ","
4746 + pEntry->GetExpression(aPos, 1, 0, formula::FormulaGrammar::GRAM_ODFF)
4747 + ")");
4748 break;
4749 case ScConditionMode::NotBetween:
4750 aCond.append("not-between("
4751 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4752 + ","
4753 + pEntry->GetExpression(aPos, 1, 0, formula::FormulaGrammar::GRAM_ODFF)
4754 + ")");
4755 break;
4756 case ScConditionMode::Duplicate:
4757 aCond.append("duplicate");
4758 break;
4759 case ScConditionMode::NotDuplicate:
4760 aCond.append("unique");
4761 break;
4762 case ScConditionMode::Direct:
4763 aCond.append("formula-is("
4764 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4765 + ")");
4766 break;
4767 case ScConditionMode::Top10:
4768 aCond.append("top-elements("
4769 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4770 + ")");
4771 break;
4772 case ScConditionMode::Bottom10:
4773 aCond.append("bottom-elements("
4774 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4775 + ")");
4776 break;
4777 case ScConditionMode::TopPercent:
4778 aCond.append("top-percent("
4779 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4780 + ")");
4781 break;
4782 case ScConditionMode::BottomPercent:
4783 aCond.append("bottom-percent("
4784 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4785 + ")");
4786 break;
4787 case ScConditionMode::AboveAverage:
4788 aCond.append("above-average");
4789 break;
4790 case ScConditionMode::BelowAverage:
4791 aCond.append("below-average");
4792 break;
4793 case ScConditionMode::AboveEqualAverage:
4794 aCond.append("above-equal-average");
4795 break;
4796 case ScConditionMode::BelowEqualAverage:
4797 aCond.append("below-equal-average");
4798 break;
4799 case ScConditionMode::Error:
4800 aCond.append("is-error");
4801 break;
4802 case ScConditionMode::NoError:
4803 aCond.append("is-no-error");
4804 break;
4805 case ScConditionMode::BeginsWith:
4806 aCond.append("begins-with("
4807 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4808 + ")");
4809 break;
4810 case ScConditionMode::EndsWith:
4811 aCond.append("ends-with("
4812 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4813 + ")");
4814 break;
4815 case ScConditionMode::ContainsText:
4816 aCond.append("contains-text("
4817 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4818 + ")");
4819 break;
4820 case ScConditionMode::NotContainsText:
4821 aCond.append("not-contains-text("
4822 + pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)
4823 + ")");
4824 break;
4825 case ScConditionMode::NONE:
4826 continue;
4827 default:
4828 SAL_WARN("sc", "unimplemented conditional format export");
4830 OUString sStyle = ScStyleNameConversion::DisplayToProgrammaticName(pEntry->GetStyle(), SfxStyleFamily::Para);
4831 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_APPLY_STYLE_NAME, sStyle);
4832 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, aCond.makeStringAndClear());
4834 OUString sBaseAddress;
4835 ScRangeStringConverter::GetStringFromAddress( sBaseAddress, aPos, &rDoc, formula::FormulaGrammar::CONV_ODF );
4836 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_BASE_CELL_ADDRESS, sBaseAddress);
4837 SvXMLElementExport aElementCondEntry(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITION, true, true);
4839 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Colorscale)
4841 SvXMLElementExport aElementColorScale(*this, XML_NAMESPACE_CALC_EXT, XML_COLOR_SCALE, true, true);
4842 const ScColorScaleFormat& rColorScale = static_cast<const ScColorScaleFormat&>(*pFormatEntry);
4843 for(const auto& rxItem : rColorScale)
4845 if(rxItem->GetType() == COLORSCALE_FORMULA)
4847 OUString sFormula = rxItem->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4848 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4850 else
4851 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(rxItem->GetValue()));
4853 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*rxItem));
4854 OUStringBuffer aBuffer;
4855 ::sax::Converter::convertColor(aBuffer, rxItem->GetColor());
4856 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLOR, aBuffer.makeStringAndClear());
4857 SvXMLElementExport aElementColorScaleEntry(*this, XML_NAMESPACE_CALC_EXT, XML_COLOR_SCALE_ENTRY, true, true);
4860 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Databar)
4862 const ScDataBarFormatData* pFormatData = static_cast<const ScDataBarFormat&>(*pFormatEntry).GetDataBarData();
4863 if(!pFormatData->mbGradient)
4864 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_GRADIENT, XML_FALSE);
4865 if(pFormatData->mbOnlyBar)
4866 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SHOW_VALUE, XML_FALSE);
4868 if (pFormatData->mnMinLength != 0.0)
4869 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MIN_LENGTH, OUString::number(pFormatData->mnMinLength));
4871 if (pFormatData->mnMaxLength != 0.0)
4872 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MAX_LENGTH, OUString::number(pFormatData->mnMaxLength));
4874 if(pFormatData->mbNeg)
4876 if(pFormatData->mxNegativeColor)
4878 OUStringBuffer aBuffer;
4879 ::sax::Converter::convertColor(aBuffer, *pFormatData->mxNegativeColor);
4880 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_NEGATIVE_COLOR, aBuffer.makeStringAndClear());
4882 else
4884 OUStringBuffer aBuffer;
4885 ::sax::Converter::convertColor(aBuffer, COL_LIGHTRED);
4886 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_NEGATIVE_COLOR, aBuffer.makeStringAndClear());
4890 if(pFormatData->meAxisPosition != databar::AUTOMATIC)
4892 if(pFormatData->meAxisPosition == databar::NONE)
4894 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_POSITION, u"none"_ustr);
4896 else
4898 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_POSITION, u"middle"_ustr);
4902 OUStringBuffer aBuffer;
4903 ::sax::Converter::convertColor(aBuffer, pFormatData->maPositiveColor);
4904 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_POSITIVE_COLOR, aBuffer.makeStringAndClear());
4906 aBuffer.truncate();
4907 ::sax::Converter::convertColor(aBuffer, pFormatData->maAxisColor);
4908 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_COLOR, aBuffer.makeStringAndClear());
4909 SvXMLElementExport aElementDataBar(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_BAR, true, true);
4912 if(pFormatData->mpLowerLimit->GetType() == COLORSCALE_FORMULA)
4914 OUString sFormula = pFormatData->mpLowerLimit->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4915 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4917 else
4918 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(pFormatData->mpLowerLimit->GetValue()));
4919 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*pFormatData->mpLowerLimit));
4920 SvXMLElementExport aElementDataBarEntryLower(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true);
4924 if(pFormatData->mpUpperLimit->GetType() == COLORSCALE_FORMULA)
4926 OUString sFormula = pFormatData->mpUpperLimit->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4927 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4929 else
4930 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(pFormatData->mpUpperLimit->GetValue()));
4931 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*pFormatData->mpUpperLimit, false));
4932 SvXMLElementExport aElementDataBarEntryUpper(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true);
4935 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Iconset)
4937 const ScIconSetFormat& rIconSet = static_cast<const ScIconSetFormat&>(*pFormatEntry);
4938 OUString aIconSetName = ScIconSetFormat::getIconSetName(rIconSet.GetIconSetData()->eIconSetType);
4939 AddAttribute( XML_NAMESPACE_CALC_EXT, XML_ICON_SET_TYPE, aIconSetName );
4940 if (rIconSet.GetIconSetData()->mbCustom)
4941 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM, OUString::boolean(true));
4943 SvXMLElementExport aElementColorScale(*this, XML_NAMESPACE_CALC_EXT, XML_ICON_SET, true, true);
4945 if (rIconSet.GetIconSetData()->mbCustom)
4947 for (const auto& [rType, rIndex] : rIconSet.GetIconSetData()->maCustomVector)
4949 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET_NAME, ScIconSetFormat::getIconSetName(rType));
4950 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET_INDEX, OUString::number(rIndex));
4951 SvXMLElementExport aCustomIcon(*this, XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET, true, true);
4956 if(!rIconSet.GetIconSetData()->mbShowValue)
4957 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SHOW_VALUE, XML_FALSE);
4958 for (auto const& it : rIconSet)
4960 if(it->GetType() == COLORSCALE_FORMULA)
4962 OUString sFormula = it->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4963 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4965 else
4966 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(it->GetValue()));
4968 if (!it->GetGreaterThanOrEqual())
4969 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_GREATER_EQUAL, OUString::boolean(false));
4971 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*it));
4972 SvXMLElementExport aElementColorScaleEntry(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true);
4975 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Date)
4977 const ScCondDateFormatEntry& rDateFormat = static_cast<const ScCondDateFormatEntry&>(*pFormatEntry);
4978 OUString aDateType = getDateStringForType(rDateFormat.GetDateType());
4979 OUString aStyleName = ScStyleNameConversion::DisplayToProgrammaticName(rDateFormat.GetStyleName(), SfxStyleFamily::Para );
4980 AddAttribute( XML_NAMESPACE_CALC_EXT, XML_STYLE, aStyleName);
4981 AddAttribute( XML_NAMESPACE_CALC_EXT, XML_DATE, aDateType);
4982 SvXMLElementExport aElementDateFormat(*this, XML_NAMESPACE_CALC_EXT, XML_DATE_IS, true, true);
4988 void ScXMLExport::WriteExternalRefCaches(ScDocument& rDoc)
4990 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
4991 pRefMgr->resetSrcFileData(GetOrigFileName());
4992 sal_uInt16 nCount = pRefMgr->getExternalFileCount();
4993 for (sal_uInt16 nFileId = 0; nFileId < nCount; ++nFileId)
4995 const OUString* pUrl = pRefMgr->getExternalFileName(nFileId);
4996 if (!pUrl)
4997 continue;
4999 vector<OUString> aTabNames;
5000 pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
5001 if (aTabNames.empty())
5002 continue;
5004 for (const auto& rTabName : aTabNames)
5006 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, rTabName, false);
5007 if (!pTable || !pTable->isReferenced())
5008 continue;
5010 AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, "'" + *pUrl + "'#" + rTabName);
5011 AddAttribute(XML_NAMESPACE_TABLE, XML_PRINT, GetXMLToken(XML_FALSE));
5012 AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sExternalRefTabStyleName);
5013 SvXMLElementExport aElemTable(*this, XML_NAMESPACE_TABLE, XML_TABLE, true, true);
5015 const ScExternalRefManager::SrcFileData* pExtFileData = pRefMgr->getExternalFileData(nFileId);
5016 if (pExtFileData)
5018 OUString aRelUrl;
5019 if (!pExtFileData->maRelativeName.isEmpty())
5020 aRelUrl = pExtFileData->maRelativeName;
5021 else
5022 aRelUrl = GetRelativeReference(pExtFileData->maRelativeName);
5023 AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
5024 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aRelUrl);
5025 AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, rTabName);
5026 if (!pExtFileData->maFilterName.isEmpty())
5027 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, pExtFileData->maFilterName);
5028 if (!pExtFileData->maFilterOptions.isEmpty())
5029 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, pExtFileData->maFilterOptions);
5030 AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY);
5032 SvXMLElementExport aElemTableSource(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, true, true);
5035 // Determine maximum column count of used area, for repeated cells.
5036 SCCOL nMaxColsUsed = 1; // assume that there is at least one cell somewhere...
5037 vector<SCROW> aRows;
5038 pTable->getAllRows(aRows);
5039 for (SCROW nRow : aRows)
5041 vector<SCCOL> aCols;
5042 pTable->getAllCols(nRow, aCols);
5043 if (!aCols.empty())
5045 SCCOL nCol = aCols.back();
5046 if (nMaxColsUsed <= nCol)
5047 nMaxColsUsed = nCol + 1;
5051 // Column definitions have to be present to make a valid file
5053 if (nMaxColsUsed > 1)
5054 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
5055 OUString::number(nMaxColsUsed));
5056 SvXMLElementExport aElemColumn(*this, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true);
5059 // Write cache content for this table.
5060 SCROW nLastRow = 0;
5061 bool bFirstRow = true;
5062 for (SCROW nRow : aRows)
5064 if (bFirstRow)
5066 if (nRow > 0)
5068 if (nRow > 1)
5070 OUString aVal = OUString::number(nRow);
5071 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal);
5073 SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true);
5074 OUString aVal = OUString::number(static_cast<sal_Int32>(nMaxColsUsed));
5075 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5076 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5079 else
5081 SCROW nRowGap = nRow - nLastRow;
5082 if (nRowGap > 1)
5084 if (nRowGap > 2)
5086 OUString aVal = OUString::number(static_cast<sal_Int32>(nRowGap-1));
5087 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal);
5089 SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true);
5090 OUString aVal = OUString::number(static_cast<sal_Int32>(nMaxColsUsed));
5091 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5092 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5095 SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true);
5097 vector<SCCOL> aCols;
5098 pTable->getAllCols(nRow, aCols);
5099 SCCOL nLastCol = 0;
5100 bool bFirstCol = true;
5101 for (SCCOL nCol : aCols)
5103 if (bFirstCol)
5105 if (nCol > 0)
5107 if (nCol > 1)
5109 OUString aVal = OUString::number(static_cast<sal_Int32>(nCol));
5110 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5112 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5115 else
5117 SCCOL nColGap = nCol - nLastCol;
5118 if (nColGap > 1)
5120 if (nColGap > 2)
5122 OUString aVal = OUString::number(static_cast<sal_Int32>(nColGap-1));
5123 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5125 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5129 // Write out this cell.
5130 sal_uInt32 nNumFmt = 0;
5131 ScExternalRefCache::TokenRef pToken = pTable->getCell(nCol, nRow, &nNumFmt);
5132 OUString aStrVal;
5133 if (pToken)
5135 sal_Int32 nIndex = GetNumberFormatStyleIndex(nNumFmt);
5136 if (nIndex >= 0)
5138 const OUString & aStyleName = pCellStyles->GetStyleNameByIndex(nIndex, true);
5139 AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, aStyleName);
5142 switch(pToken->GetType())
5144 case svDouble:
5146 AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT);
5147 aStrVal = OUString::number(pToken->GetDouble());
5148 AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, aStrVal);
5150 break;
5151 case svString:
5153 AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING);
5154 aStrVal = pToken->GetString().getString();
5156 break;
5157 default:
5161 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5162 SvXMLElementExport aElemText(*this, XML_NAMESPACE_TEXT, XML_P, true, false);
5163 Characters(aStrVal);
5165 nLastCol = nCol;
5166 bFirstCol = false;
5168 nLastRow = nRow;
5169 bFirstRow = false;
5175 // core implementation
5176 void ScXMLExport::WriteConsolidation(ScDocument& rDoc)
5178 const ScConsolidateParam* pCons(rDoc.GetConsolidateDlgData());
5179 if( !pCons )
5180 return;
5182 OUString sStrData = ScXMLConverter::GetStringFromFunction( pCons->eFunction );
5183 AddAttribute( XML_NAMESPACE_TABLE, XML_FUNCTION, sStrData );
5185 sStrData.clear();
5186 for( sal_Int32 nIndex = 0; nIndex < pCons->nDataAreaCount; ++nIndex )
5187 ScRangeStringConverter::GetStringFromArea( sStrData, pCons->pDataAreas[ nIndex ], &rDoc, FormulaGrammar::CONV_OOO, ' ', true );
5188 AddAttribute( XML_NAMESPACE_TABLE, XML_SOURCE_CELL_RANGE_ADDRESSES, sStrData );
5190 ScRangeStringConverter::GetStringFromAddress( sStrData, ScAddress( pCons->nCol, pCons->nRow, pCons->nTab ), &rDoc, FormulaGrammar::CONV_OOO );
5191 AddAttribute( XML_NAMESPACE_TABLE, XML_TARGET_CELL_ADDRESS, sStrData );
5193 if( pCons->bByCol && !pCons->bByRow )
5194 AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_COLUMN );
5195 else if( !pCons->bByCol && pCons->bByRow )
5196 AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_ROW );
5197 else if( pCons->bByCol && pCons->bByRow )
5198 AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_BOTH );
5200 if( pCons->bReferenceData )
5201 AddAttribute( XML_NAMESPACE_TABLE, XML_LINK_TO_SOURCE_DATA, XML_TRUE );
5203 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_CONSOLIDATION, true, true );
5206 SvXMLAutoStylePoolP* ScXMLExport::CreateAutoStylePool()
5208 return new ScXMLAutoStylePoolP(*this);
5211 XMLPageExport* ScXMLExport::CreatePageExport()
5213 return new XMLTableMasterPageExport( *this );
5216 //static
5217 void ScXMLExport::GetChangeTrackViewSettings(ScDocument& rDoc, uno::Sequence<beans::PropertyValue>& rProps)
5219 ScChangeViewSettings* pViewSettings(rDoc.GetChangeViewSettings());
5220 if (!pViewSettings)
5221 return;
5223 sal_Int32 nChangePos(rProps.getLength());
5224 rProps.realloc(nChangePos + 1);
5225 beans::PropertyValue* pProps(rProps.getArray());
5227 uno::Sequence<beans::PropertyValue> aChangeProps(SC_VIEWCHANGES_COUNT);
5228 beans::PropertyValue* pChangeProps(aChangeProps.getArray());
5229 pChangeProps[SC_SHOW_CHANGES].Name = "ShowChanges";
5230 pChangeProps[SC_SHOW_CHANGES].Value <<= pViewSettings->ShowChanges();
5231 pChangeProps[SC_SHOW_ACCEPTED_CHANGES].Name = "ShowAcceptedChanges";
5232 pChangeProps[SC_SHOW_ACCEPTED_CHANGES].Value <<= pViewSettings->IsShowAccepted();
5233 pChangeProps[SC_SHOW_REJECTED_CHANGES].Name = "ShowRejectedChanges";
5234 pChangeProps[SC_SHOW_REJECTED_CHANGES].Value <<= pViewSettings->IsShowRejected();
5235 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME].Name = "ShowChangesByDatetime";
5236 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME].Value <<= pViewSettings->HasDate();
5237 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_MODE].Name = "ShowChangesByDatetimeMode";
5238 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_MODE].Value <<= static_cast<sal_Int16>(pViewSettings->GetTheDateMode());
5239 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME].Name = "ShowChangesByDatetimeFirstDatetime";
5240 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME].Value <<= pViewSettings->GetTheFirstDateTime().GetUNODateTime();
5241 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME].Name = "ShowChangesByDatetimeSecondDatetime";
5242 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME].Value <<= pViewSettings->GetTheLastDateTime().GetUNODateTime();
5243 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR].Name = "ShowChangesByAuthor";
5244 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR].Value <<= pViewSettings->HasAuthor();
5245 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR_NAME].Name = "ShowChangesByAuthorName";
5246 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR_NAME].Value <<= pViewSettings->GetTheAuthorToShow();
5247 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT].Name = "ShowChangesByComment";
5248 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT].Value <<= pViewSettings->HasComment();
5249 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT_TEXT].Name = "ShowChangesByCommentText";
5250 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT_TEXT].Value <<= pViewSettings->GetTheComment();
5251 pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Name = "ShowChangesByRanges";
5252 pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Value <<= pViewSettings->HasRange();
5253 OUString sRangeList;
5254 ScRangeStringConverter::GetStringFromRangeList(sRangeList, &(pViewSettings->GetTheRangeList()), &rDoc, FormulaGrammar::CONV_OOO);
5255 pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Name = "ShowChangesByRangesList";
5256 pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Value <<= sRangeList;
5258 pProps[nChangePos].Name = "TrackedChangesViewSettings";
5259 pProps[nChangePos].Value <<= aChangeProps;
5262 void ScXMLExport::GetViewSettings(uno::Sequence<beans::PropertyValue>& rProps)
5264 if (!GetModel().is())
5265 return;
5267 ScModelObj* pDocObj(comphelper::getFromUnoTunnel<ScModelObj>( GetModel() ));
5268 if (!pDocObj)
5269 return;
5271 SfxObjectShell* pEmbeddedObj = pDocObj->GetEmbeddedObject();
5272 if (pEmbeddedObj)
5274 rProps.realloc(4);
5275 beans::PropertyValue* pProps(rProps.getArray());
5277 tools::Rectangle aRect(pEmbeddedObj->GetVisArea());
5278 sal_uInt16 i(0);
5279 pProps[i].Name = "VisibleAreaTop";
5280 pProps[i].Value <<= static_cast<sal_Int32>(aRect.Top());
5281 pProps[++i].Name = "VisibleAreaLeft";
5282 pProps[i].Value <<= static_cast<sal_Int32>(aRect.Left());
5283 pProps[++i].Name = "VisibleAreaWidth";
5284 pProps[i].Value <<= static_cast<sal_Int32>(aRect.getOpenWidth());
5285 pProps[++i].Name = "VisibleAreaHeight";
5286 pProps[i].Value <<= static_cast<sal_Int32>(aRect.getOpenHeight());
5289 ScDocument* pDoc = pDocObj->GetDocument();
5290 if (!pDoc)
5292 SAL_WARN("sc", "no ScDocument!");
5293 return;
5295 GetChangeTrackViewSettings(*pDoc, rProps);
5298 void ScXMLExport::GetConfigurationSettings(uno::Sequence<beans::PropertyValue>& rProps)
5300 if (!GetModel().is())
5301 return;
5303 uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetModel(), uno::UNO_QUERY);
5304 if (!xMultiServiceFactory.is())
5305 return;
5307 uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance(u"com.sun.star.comp.SpreadsheetSettings"_ustr), uno::UNO_QUERY);
5308 if (xProperties.is())
5309 SvXMLUnitConverter::convertPropertySet(rProps, xProperties);
5311 ScDocument* pDoc = GetDocument();
5313 sal_Int32 nPropsToAdd = 0;
5314 OUStringBuffer aTrackedChangesKey;
5315 if (pDoc && pDoc->GetChangeTrack() && pDoc->GetChangeTrack()->IsProtected())
5317 ::comphelper::Base64::encode(aTrackedChangesKey,
5318 pDoc->GetChangeTrack()->GetProtection());
5319 if (!aTrackedChangesKey.isEmpty())
5320 ++nPropsToAdd;
5323 bool bVBACompat = false;
5324 uno::Reference <container::XNameAccess> xCodeNameAccess;
5325 OSL_ENSURE( pDoc, "ScXMLExport::GetConfigurationSettings - no ScDocument!" );
5326 // tdf#71271 - add code names regardless of VBA compatibility mode
5327 if (pDoc)
5329 // VBA compatibility mode
5330 if (bVBACompat = pDoc->IsInVBAMode(); bVBACompat)
5331 ++nPropsToAdd;
5333 // code names
5334 xCodeNameAccess = new XMLCodeNameProvider( pDoc );
5335 if( xCodeNameAccess->hasElements() )
5336 ++nPropsToAdd;
5337 else
5338 xCodeNameAccess.clear();
5341 if( nPropsToAdd <= 0 )
5342 return;
5344 sal_Int32 nCount(rProps.getLength());
5345 rProps.realloc(nCount + nPropsToAdd);
5346 auto pProps = rProps.getArray();
5347 if (!aTrackedChangesKey.isEmpty())
5349 pProps[nCount].Name = "TrackedChangesProtectionKey";
5350 pProps[nCount].Value <<= aTrackedChangesKey.makeStringAndClear();
5351 ++nCount;
5353 if( bVBACompat )
5355 pProps[nCount].Name = "VBACompatibilityMode";
5356 pProps[nCount].Value <<= bVBACompat;
5357 ++nCount;
5359 if( xCodeNameAccess.is() )
5361 pProps[nCount].Name = "ScriptConfiguration";
5362 pProps[nCount].Value <<= xCodeNameAccess;
5363 ++nCount;
5367 XMLShapeExport* ScXMLExport::CreateShapeExport()
5369 return new ScXMLShapeExport(*this);
5372 XMLNumberFormatAttributesExportHelper* ScXMLExport::GetNumberFormatAttributesExportHelper()
5374 if (!pNumberFormatAttributesExportHelper)
5375 pNumberFormatAttributesExportHelper.reset(new XMLNumberFormatAttributesExportHelper(GetNumberFormatsSupplier(), *this ));
5376 return pNumberFormatAttributesExportHelper.get();
5379 void ScXMLExport::CollectUserDefinedNamespaces(const SfxItemPool* pPool, sal_uInt16 nAttrib)
5381 ItemSurrogates aSurrogates;
5382 pPool->GetItemSurrogates(aSurrogates, nAttrib);
5383 for (const SfxPoolItem* pItem : aSurrogates)
5385 const SvXMLAttrContainerItem *pUnknown(static_cast<const SvXMLAttrContainerItem *>(pItem));
5386 if( pUnknown->GetAttrCount() > 0 )
5388 sal_uInt16 nIdx(pUnknown->GetFirstNamespaceIndex());
5389 while( USHRT_MAX != nIdx )
5391 if( (XML_NAMESPACE_UNKNOWN_FLAG & nIdx) != 0 )
5393 const OUString& rPrefix = pUnknown->GetPrefix( nIdx );
5394 // Add namespace declaration for unknown attributes if
5395 // there aren't existing ones for the prefix used by the
5396 // attributes
5397 GetNamespaceMap_().Add( rPrefix,
5398 pUnknown->GetNamespace( nIdx ) );
5400 nIdx = pUnknown->GetNextNamespaceIndex( nIdx );
5405 // #i66550# needed for 'presentation:event-listener' element for URLs in shapes
5406 GetNamespaceMap_().Add(
5407 GetXMLToken( XML_NP_PRESENTATION ),
5408 GetXMLToken( XML_N_PRESENTATION ),
5409 XML_NAMESPACE_PRESENTATION );
5412 void ScXMLExport::IncrementProgressBar(bool bFlush, sal_Int32 nInc)
5414 nProgressCount += nInc;
5415 if (bFlush || nProgressCount > 100)
5417 GetProgressBarHelper()->Increment(nProgressCount);
5418 nProgressCount = 0;
5422 ErrCode ScXMLExport::exportDoc( enum XMLTokenEnum eClass )
5424 if( getExportFlags() & (SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::STYLES|
5425 SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) )
5427 uno::Reference< frame::XModel > xModel = GetModel();
5428 if (ScDocument* pDoc = GetDocument())
5430 // if source doc was Excel then
5431 auto pFoundShell = comphelper::getFromUnoTunnel<SfxObjectShell>(xModel);
5432 if ( pFoundShell && ooo::vba::isAlienExcelDoc( *pFoundShell ) )
5434 xRowStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScFromXLSRowStylesProperties, xScPropHdlFactory, true);
5435 xRowStylesExportPropertySetMapper = new ScXMLRowExportPropertyMapper(xRowStylesPropertySetMapper);
5436 GetAutoStylePool()->SetFamilyPropSetMapper( XmlStyleFamily::TABLE_ROW,
5437 xRowStylesExportPropertySetMapper );
5440 CollectUserDefinedNamespaces(pDoc->GetPool(), ATTR_USERDEF);
5441 CollectUserDefinedNamespaces(pDoc->GetEditPool(), EE_PARA_XMLATTRIBS);
5442 CollectUserDefinedNamespaces(pDoc->GetEditPool(), EE_CHAR_XMLATTRIBS);
5443 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
5444 if (pDrawLayer)
5446 CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), EE_PARA_XMLATTRIBS);
5447 CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), EE_CHAR_XMLATTRIBS);
5448 CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), SDRATTR_XMLATTRIBUTES);
5451 // sheet events use officeooo namespace
5452 if( (getExportFlags() & SvXMLExportFlags::CONTENT) &&
5453 getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
5455 bool bAnySheetEvents = false;
5456 SCTAB nTabCount = pDoc->GetTableCount();
5457 for (SCTAB nTab=0; nTab<nTabCount; ++nTab)
5458 if (pDoc->GetSheetEvents(nTab))
5459 bAnySheetEvents = true;
5460 if (bAnySheetEvents)
5461 GetNamespaceMap_().Add(
5462 GetXMLToken( XML_NP_OFFICE_EXT ),
5463 GetXMLToken( XML_N_OFFICE_EXT ),
5464 XML_NAMESPACE_OFFICE_EXT );
5468 return SvXMLExport::exportDoc( eClass );
5471 // XExporter
5472 void SAL_CALL ScXMLExport::setSourceDocument( const uno::Reference<lang::XComponent>& xComponent )
5474 SolarMutexGuard aGuard;
5475 SvXMLExport::setSourceDocument( xComponent );
5477 ScDocument* pDoc = GetDocument();
5478 OSL_ENSURE( pDoc, "ScXMLExport::setSourceDocument - no ScDocument!" );
5479 if (!pDoc)
5480 throw lang::IllegalArgumentException();
5482 // create ScChangeTrackingExportHelper after document is known
5483 pChangeTrackingExportHelper.reset(new ScChangeTrackingExportHelper(*pDoc, *this));
5485 // Set the document's storage grammar corresponding to the ODF version that
5486 // is to be written.
5487 SvtSaveOptions::ODFSaneDefaultVersion meODFDefaultVersion = getSaneDefaultVersion();
5488 switch (meODFDefaultVersion)
5490 // ODF 1.0 and 1.1 use GRAM_PODF, everything later or unspecified GRAM_ODFF
5491 case SvtSaveOptions::ODFSVER_010:
5492 case SvtSaveOptions::ODFSVER_011:
5493 pDoc->SetStorageGrammar( formula::FormulaGrammar::GRAM_PODF);
5494 break;
5495 default:
5496 pDoc->SetStorageGrammar( formula::FormulaGrammar::GRAM_ODFF);
5500 // XFilter
5501 sal_Bool SAL_CALL ScXMLExport::filter( const css::uno::Sequence< css::beans::PropertyValue >& aDescriptor )
5503 SolarMutexGuard aGuard;
5504 ScDocument* pDoc = GetDocument();
5505 if (pDoc)
5506 pDoc->EnableIdle(true);
5507 bool bReturn(SvXMLExport::filter(aDescriptor));
5508 if (pDoc)
5509 pDoc->EnableIdle(true);
5510 return bReturn;
5513 void SAL_CALL ScXMLExport::cancel()
5515 SolarMutexGuard aGuard;
5516 if (ScDocument* pDoc = GetDocument())
5517 pDoc->EnableIdle(true);
5518 SvXMLExport::cancel();
5521 // XInitialization
5522 void SAL_CALL ScXMLExport::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
5524 SolarMutexGuard aGuard;
5525 SvXMLExport::initialize(aArguments);
5528 void ScXMLExport::DisposingModel()
5530 SvXMLExport::DisposingModel();
5531 xCurrentTable = nullptr;
5534 void ScXMLExport::SetSharedData(std::unique_ptr<ScMySharedData> pTemp) { pSharedData = std::move(pTemp); }
5536 std::unique_ptr<ScMySharedData> ScXMLExport::ReleaseSharedData() { return std::move(pSharedData); }
5537 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */