Version 7.5.1.1, tag libreoffice-7.5.1.1
[LibreOffice.git] / sc / source / filter / xml / xmlexprt.cxx
blob051c0ac251b374aa5ec79fc7877713f2fc7bc651
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 "XMLExportIterator.hxx"
37 #include "XMLColumnRowGroupExport.hxx"
38 #include "XMLStylesExportHelper.hxx"
39 #include "XMLChangeTrackingExportHelper.hxx"
40 #include <sheetdata.hxx>
41 #include <docoptio.hxx>
42 #include "XMLExportSharedData.hxx"
43 #include <chgviset.hxx>
44 #include <docuno.hxx>
45 #include <textuno.hxx>
46 #include <chartlis.hxx>
47 #include <scitems.hxx>
48 #include <docpool.hxx>
49 #include <userdat.hxx>
50 #include <chgtrack.hxx>
51 #include <rangeutl.hxx>
52 #include <postit.hxx>
53 #include <externalrefmgr.hxx>
54 #include <editutil.hxx>
55 #include <tabprotection.hxx>
56 #include "cachedattraccess.hxx"
57 #include <colorscale.hxx>
58 #include <conditio.hxx>
59 #include <cellvalue.hxx>
60 #include <stylehelper.hxx>
61 #include <edittextiterator.hxx>
62 #include "editattributemap.hxx"
63 #include <arealink.hxx>
64 #include <datastream.hxx>
65 #include <documentlinkmgr.hxx>
66 #include <tokenstringcontext.hxx>
67 #include <cellform.hxx>
68 #include <datamapper.hxx>
69 #include <datatransformation.hxx>
70 #include "SparklineGroupsExport.hxx"
71 #include <SparklineList.hxx>
73 #include <xmloff/xmltoken.hxx>
74 #include <xmloff/xmlnamespace.hxx>
75 #include <xmloff/xmluconv.hxx>
76 #include <xmloff/namespacemap.hxx>
77 #include <xmloff/families.hxx>
78 #include <xmloff/numehelp.hxx>
79 #include <xmloff/txtparae.hxx>
80 #include <editeng/autokernitem.hxx>
81 #include <editeng/charreliefitem.hxx>
82 #include <editeng/charscaleitem.hxx>
83 #include <editeng/colritem.hxx>
84 #include <editeng/contouritem.hxx>
85 #include <editeng/crossedoutitem.hxx>
86 #include <editeng/emphasismarkitem.hxx>
87 #include <editeng/escapementitem.hxx>
88 #include <editeng/fhgtitem.hxx>
89 #include <editeng/fontitem.hxx>
90 #include <editeng/kernitem.hxx>
91 #include <editeng/langitem.hxx>
92 #include <editeng/postitem.hxx>
93 #include <editeng/section.hxx>
94 #include <editeng/shdditem.hxx>
95 #include <editeng/udlnitem.hxx>
96 #include <editeng/wghtitem.hxx>
97 #include <editeng/wrlmitem.hxx>
98 #include <editeng/xmlcnitm.hxx>
99 #include <editeng/flditem.hxx>
100 #include <editeng/eeitem.hxx>
101 #include <formula/errorcodes.hxx>
102 #include <xmloff/xmlerror.hxx>
103 #include <xmloff/XMLEventExport.hxx>
104 #include <xmloff/xmlprmap.hxx>
105 #include <xmloff/ProgressBarHelper.hxx>
106 #include <xmloff/table/XMLTableExport.hxx>
108 #include <sax/tools/converter.hxx>
109 #include <tools/fldunit.hxx>
111 #include <rtl/ustring.hxx>
113 #include <tools/color.hxx>
114 #include <comphelper/diagnose_ex.hxx>
115 #include <rtl/math.hxx>
116 #include <svl/numformat.hxx>
117 #include <svl/zforlist.hxx>
118 #include <comphelper/base64.hxx>
119 #include <comphelper/extract.hxx>
120 #include <svx/svdoashp.hxx>
121 #include <svx/svdobj.hxx>
122 #include <svx/svdocapt.hxx>
123 #include <vcl/svapp.hxx>
125 #include <comphelper/processfactory.hxx>
126 #include <com/sun/star/beans/XPropertySet.hpp>
127 #include <com/sun/star/container/XNamed.hpp>
128 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
129 #include <com/sun/star/form/XFormsSupplier2.hpp>
130 #include <com/sun/star/io/XActiveDataSource.hpp>
131 #include <com/sun/star/io/XSeekable.hpp>
132 #include <com/sun/star/sheet/XUsedAreaCursor.hpp>
133 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
134 #include <com/sun/star/sheet/XPrintAreas.hpp>
135 #include <com/sun/star/sheet/XUniqueCellFormatRangesSupplier.hpp>
136 #include <com/sun/star/sheet/XLabelRange.hpp>
137 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
138 #include <com/sun/star/sheet/XSheetCellCursor.hpp>
139 #include <com/sun/star/sheet/XSheetCellRanges.hpp>
140 #include <com/sun/star/sheet/XSheetLinkable.hpp>
141 #include <com/sun/star/sheet/GlobalSheetSettings.hpp>
142 #include <com/sun/star/table/XColumnRowRange.hpp>
143 #include <com/sun/star/util/XProtectable.hpp>
144 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
145 #include <com/sun/star/chart2/XChartDocument.hpp>
146 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
147 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
149 #include <com/sun/star/document/XDocumentProperties.hpp>
150 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
152 #include "XMLCodeNameProvider.hxx"
154 #include <sfx2/linkmgr.hxx>
155 #include <sfx2/objsh.hxx>
157 #include <memory>
158 #include <vector>
159 #include <vbahelper/vbaaccesshelper.hxx>
160 #include <officecfg/Office/Common.hxx>
162 namespace com::sun::star::uno { class XComponentContext; }
166 //! not found in unonames.hxx
167 constexpr OUStringLiteral SC_LAYERID = u"LayerID";
169 #define SC_VIEWCHANGES_COUNT 13
170 #define SC_SHOW_CHANGES 0
171 #define SC_SHOW_ACCEPTED_CHANGES 1
172 #define SC_SHOW_REJECTED_CHANGES 2
173 #define SC_SHOW_CHANGES_BY_DATETIME 3
174 #define SC_SHOW_CHANGES_BY_DATETIME_MODE 4
175 #define SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME 5
176 #define SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME 6
177 #define SC_SHOW_CHANGES_BY_AUTHOR 7
178 #define SC_SHOW_CHANGES_BY_AUTHOR_NAME 8
179 #define SC_SHOW_CHANGES_BY_COMMENT 9
180 #define SC_SHOW_CHANGES_BY_COMMENT_TEXT 10
181 #define SC_SHOW_CHANGES_BY_RANGES 11
182 #define SC_SHOW_CHANGES_BY_RANGES_LIST 12
184 using namespace formula;
185 using namespace com::sun::star;
186 using namespace xmloff::token;
187 using ::std::vector;
188 using ::com::sun::star::uno::UNO_QUERY;
190 namespace
192 OUString lcl_RangeSequenceToString(
193 const uno::Sequence< OUString > & rRanges,
194 const uno::Reference< chart2::data::XRangeXMLConversion > & xFormatConverter )
196 OUStringBuffer aResult;
197 const sal_Int32 nMaxIndex( rRanges.getLength() - 1 );
198 const sal_Unicode cSep(' ');
199 for( sal_Int32 i=0; i<=nMaxIndex; ++i )
201 OUString aRange( rRanges[i] );
202 if( xFormatConverter.is())
203 aRange = xFormatConverter->convertRangeToXML( aRange );
204 aResult.append( aRange );
205 if( i < nMaxIndex )
206 aResult.append( cSep );
208 return aResult.makeStringAndClear();
211 OUString lcl_GetFormattedString(ScDocument* pDoc, const ScRefCellValue& rCell, const ScAddress& rAddr)
213 // return text/edit cell string content, with line feeds in edit cells
215 if (!pDoc)
216 return OUString();
218 switch (rCell.getType())
220 case CELLTYPE_STRING:
222 const Color* pColor;
223 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
225 sal_uInt32 nFormat = pDoc->GetNumberFormat(rAddr);
226 return ScCellFormat::GetString(rCell, nFormat, &pColor, *pFormatter, *pDoc);
228 case CELLTYPE_EDIT:
230 const EditTextObject* pData = rCell.getEditText();
231 if (!pData)
232 return OUString();
234 EditEngine& rEngine = pDoc->GetEditEngine();
235 rEngine.SetText(*pData);
236 return rEngine.GetText();
238 break;
239 default:
243 return OUString();
246 } // anonymous namespace
248 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
249 Calc_XMLExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
251 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLExporter", SvXMLExportFlags::ALL));
254 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
255 Calc_XMLMetaExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
257 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLMetaExporter", SvXMLExportFlags::META));
260 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
261 Calc_XMLStylesExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
263 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLStylesExporter", SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS));
266 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
267 Calc_XMLContentExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
269 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLContentExporter", SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::FONTDECLS));
272 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
273 Calc_XMLSettingsExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
275 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLSettingsExporter", SvXMLExportFlags::SETTINGS));
278 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
279 Calc_XMLOasisExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
281 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisExporter", SvXMLExportFlags::ALL|SvXMLExportFlags::OASIS));
284 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
285 Calc_XMLOasisMetaExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
287 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisMetaExporter", SvXMLExportFlags::META|SvXMLExportFlags::OASIS));
290 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
291 Calc_XMLOasisStylesExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
293 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisStylesExporter", SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::OASIS));
296 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
297 Calc_XMLOasisContentExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
299 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisContentExporter", SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::OASIS));
302 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
303 Calc_XMLOasisSettingsExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &)
305 return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisSettingsExporter", SvXMLExportFlags::SETTINGS|SvXMLExportFlags::OASIS));
308 namespace {
310 class ScXMLShapeExport : public XMLShapeExport
312 public:
313 explicit ScXMLShapeExport(SvXMLExport& rExp)
314 : XMLShapeExport(rExp,
315 // chain text attributes
316 XMLTextParagraphExport::CreateParaExtPropMapper(rExp))
320 /** is called before a shape element for the given XShape is exported */
321 virtual void onExport( const uno::Reference < drawing::XShape >& xShape ) override;
326 void ScXMLShapeExport::onExport( const uno::Reference < drawing::XShape >& xShape )
328 uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY );
329 if( xShapeProp.is() )
331 sal_Int16 nLayerID = 0;
332 if( (xShapeProp->getPropertyValue( SC_LAYERID ) >>= nLayerID) && (SdrLayerID(nLayerID) == SC_LAYER_BACK) )
333 GetExport().AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_BACKGROUND, XML_TRUE);
337 sal_Int16 ScXMLExport::GetMeasureUnit()
339 css::uno::Reference<css::sheet::XGlobalSheetSettings> xProperties =
340 css::sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() );
341 const FieldUnit eFieldUnit = static_cast<FieldUnit>(xProperties->getMetric());
342 return SvXMLUnitConverter::GetMeasureUnit(eFieldUnit);
345 ScXMLExport::ScXMLExport(
346 const css::uno::Reference< css::uno::XComponentContext >& rContext,
347 OUString const & implementationName, SvXMLExportFlags nExportFlag)
348 : SvXMLExport(
349 rContext, implementationName, GetMeasureUnit(), XML_SPREADSHEET, nExportFlag ),
350 pDoc(nullptr),
351 nSourceStreamPos(0),
352 pCurrentCell(nullptr),
353 nOpenRow(-1),
354 nProgressCount(0),
355 nCurrentTable(0),
356 bHasRowHeader(false),
357 bRowHeaderOpen(false)
359 if (getExportFlags() & SvXMLExportFlags::CONTENT)
361 pGroupColumns.reset( new ScMyOpenCloseColumnRowGroup(*this, XML_TABLE_COLUMN_GROUP) );
362 pGroupRows.reset( new ScMyOpenCloseColumnRowGroup(*this, XML_TABLE_ROW_GROUP) );
363 pColumnStyles.reset( new ScColumnStyles() );
364 pRowStyles.reset( new ScRowStyles() );
365 pRowFormatRanges.reset( new ScRowFormatRanges() );
366 pMergedRangesContainer.reset( new ScMyMergedRangesContainer() );
367 pValidationsContainer.reset( new ScMyValidationsContainer() );
368 mpCellsItr.reset(new ScMyNotEmptyCellsIterator(*this));
369 pDefaults.reset( new ScMyDefaultStyles );
371 pCellStyles.reset( new ScFormatRangeStyles() );
373 // document is not set here - create ScChangeTrackingExportHelper later
375 xScPropHdlFactory = new XMLScPropHdlFactory;
376 xCellStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScCellStylesProperties, xScPropHdlFactory, true);
377 xColumnStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScColumnStylesProperties, xScPropHdlFactory, true);
378 xRowStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScRowStylesProperties, xScPropHdlFactory, true);
379 xTableStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScTableStylesProperties, xScPropHdlFactory, true);
380 xCellStylesExportPropertySetMapper = new ScXMLCellExportPropertyMapper(xCellStylesPropertySetMapper);
381 xCellStylesExportPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(*this));
382 xColumnStylesExportPropertySetMapper = new ScXMLColumnExportPropertyMapper(xColumnStylesPropertySetMapper);
383 xRowStylesExportPropertySetMapper = new ScXMLRowExportPropertyMapper(xRowStylesPropertySetMapper);
384 xTableStylesExportPropertySetMapper = new ScXMLTableExportPropertyMapper(xTableStylesPropertySetMapper);
386 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_CELL, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME,
387 xCellStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX);
388 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_COLUMN, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME,
389 xColumnStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX);
390 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_ROW, XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME,
391 xRowStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX);
392 GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_TABLE, XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME,
393 xTableStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_TABLE_STYLES_PREFIX);
395 if( !(getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT)) )
396 return;
398 // This name is reserved for the external ref cache tables. This
399 // should not conflict with user-defined styles since this name is
400 // used for a table style which is not available in the UI.
401 sExternalRefTabStyleName = "ta_extref";
402 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_TABLE, sExternalRefTabStyleName);
404 sAttrName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NAME));
405 sAttrStyleName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_STYLE_NAME));
406 sAttrColumnsRepeated = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NUMBER_COLUMNS_REPEATED));
407 sAttrFormula = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_FORMULA));
408 sAttrStringValue = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_STRING_VALUE));
409 sAttrValueType = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_VALUE_TYPE));
410 sElemCell = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_CELL));
411 sElemCoveredCell = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_COVERED_TABLE_CELL));
412 sElemCol = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_COLUMN));
413 sElemRow = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_ROW));
414 sElemTab = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE));
415 sElemP = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TEXT, GetXMLToken(XML_P));
418 ScXMLExport::~ScXMLExport()
420 pGroupColumns.reset();
421 pGroupRows.reset();
422 pColumnStyles.reset();
423 pRowStyles.reset();
424 pCellStyles.reset();
425 pRowFormatRanges.reset();
426 pMergedRangesContainer.reset();
427 pValidationsContainer.reset();
428 pChangeTrackingExportHelper.reset();
429 pDefaults.reset();
430 pNumberFormatAttributesExportHelper.reset();
433 void ScXMLExport::SetSourceStream( const uno::Reference<io::XInputStream>& xNewStream )
435 xSourceStream = xNewStream;
437 if ( !xSourceStream.is() )
438 return;
440 // make sure it's a plain UTF-8 stream as written by OOo itself
442 const char pXmlHeader[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
443 sal_Int32 nLen = strlen(pXmlHeader);
445 uno::Sequence<sal_Int8> aFileStart(nLen);
446 sal_Int32 nRead = xSourceStream->readBytes( aFileStart, nLen );
448 if ( nRead != nLen || memcmp( aFileStart.getConstArray(), pXmlHeader, nLen ) != 0 )
450 // invalid - ignore stream, save normally
451 xSourceStream.clear();
453 else
455 // keep track of the bytes already read
456 nSourceStreamPos = nRead;
458 const ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(GetModel())->GetSheetSaveData();
459 if (pSheetData)
461 // add the loaded namespaces to the name space map
463 if ( !pSheetData->AddLoadedNamespaces( GetNamespaceMap_() ) )
465 // conflicts in the namespaces - ignore the stream, save normally
466 xSourceStream.clear();
472 sal_Int32 ScXMLExport::GetNumberFormatStyleIndex(sal_Int32 nNumFmt) const
474 NumberFormatIndexMap::const_iterator itr = aNumFmtIndexMap.find(nNumFmt);
475 if (itr == aNumFmtIndexMap.end())
476 return -1;
478 return itr->second;
481 void ScXMLExport::CollectSharedData(SCTAB& nTableCount, sal_Int32& nShapesCount)
483 if (!GetModel().is())
484 return;
486 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc(GetModel(), uno::UNO_QUERY);
487 if (!xSpreadDoc.is())
488 return;
490 uno::Reference<container::XIndexAccess> xIndex(xSpreadDoc->getSheets(), uno::UNO_QUERY);
491 if (!xIndex.is())
492 return;
494 nTableCount = xIndex->getCount();
495 if (!pSharedData)
496 pSharedData.reset(new ScMySharedData(nTableCount));
498 pCellStyles->AddNewTable(nTableCount - 1);
500 for (SCTAB nTable = 0; nTable < nTableCount; ++nTable)
502 nCurrentTable = sal::static_int_cast<sal_uInt16>(nTable);
503 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xIndex->getByIndex(nTable), uno::UNO_QUERY);
504 if (!xDrawPageSupplier.is())
505 continue;
507 uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage());
508 ScMyDrawPage aDrawPage;
509 aDrawPage.bHasForms = false;
510 aDrawPage.xDrawPage.set(xDrawPage);
511 pSharedData->AddDrawPage(aDrawPage, nTable);
512 if (!xDrawPage.is())
513 continue;
515 sal_Int32 nShapes = xDrawPage->getCount();
516 for (sal_Int32 nShape = 0; nShape < nShapes; ++nShape)
518 uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShape), uno::UNO_QUERY);
519 if (!xShape.is())
520 continue;
522 uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
523 if (!xShapeProp.is())
524 continue;
526 sal_Int16 nLayerID = 0;
527 bool bExtracted = xShapeProp->getPropertyValue(SC_LAYERID) >>= nLayerID;
528 if (!bExtracted)
529 continue;
531 if ((SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN))
533 CollectInternalShape(xShape);
534 continue;
537 ++nShapesCount;
539 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape);
540 if (!pSdrObj)
541 continue;
543 if (ScDrawObjData *pAnchor = ScDrawLayer::GetNonRotatedObjData(pSdrObj))
545 ScMyShape aMyShape;
546 aMyShape.aAddress = pAnchor->maStart;
547 SAL_WARN_IF(aMyShape.aAddress.Tab() != nTable, "sc", "not anchored to current sheet!");
548 aMyShape.aAddress.SetTab(nTable);
549 aMyShape.aEndAddress = pAnchor->maEnd;
550 aMyShape.aEndAddress.SetTab( nTable );
551 aMyShape.nEndX = pAnchor->maEndOffset.X();
552 aMyShape.nEndY = pAnchor->maEndOffset.Y();
553 aMyShape.xShape = xShape;
554 aMyShape.bResizeWithCell = ScDrawLayer::IsResizeWithCell(*pSdrObj);
555 pSharedData->AddNewShape(aMyShape);
556 pSharedData->SetLastColumn(nTable, pAnchor->maStart.Col());
557 pSharedData->SetLastRow(nTable, pAnchor->maStart.Row());
559 else
560 pSharedData->AddTableShape(nTable, xShape);
565 void ScXMLExport::CollectShapesAutoStyles(SCTAB nTableCount)
567 // #i84077# To avoid compiler warnings about uninitialized aShapeItr,
568 // it's initialized using this dummy list. The iterator contains shapes
569 // from all sheets, so it can't be declared inside the nTable loop where
570 // it is used.
571 ScMyShapeList aDummyInitList;
573 pSharedData->SortShapesContainer();
574 pSharedData->SortNoteShapes();
575 const ScMyShapeList* pShapeList(nullptr);
576 ScMyShapeList::const_iterator aShapeItr = aDummyInitList.end();
577 if (pSharedData->GetShapesContainer())
579 pShapeList = &pSharedData->GetShapesContainer()->GetShapes();
580 aShapeItr = pShapeList->begin();
582 if (pSharedData->HasDrawPage())
584 css::uno::Sequence<OUString> aAutoStylePropNames = GetAutoStylePool()->GetPropertyNames();
585 for (SCTAB nTable = 0; nTable < nTableCount; ++nTable)
587 uno::Reference<drawing::XDrawPage> xDrawPage(pSharedData->GetDrawPage(nTable));
589 if (xDrawPage.is())
591 GetShapeExport()->seekShapes(xDrawPage);
592 uno::Reference< form::XFormsSupplier2 > xFormsSupplier( xDrawPage, uno::UNO_QUERY );
593 if( xFormsSupplier.is() && xFormsSupplier->hasForms() )
595 GetFormExport()->examineForms(xDrawPage);
596 pSharedData->SetDrawPageHasForms(nTable, true);
598 ScMyTableShapes* pTableShapes(pSharedData->GetTableShapes());
599 if (pTableShapes)
601 for (const auto& rxShape : (*pTableShapes)[nTable])
603 GetShapeExport()->collectShapeAutoStyles(rxShape, aAutoStylePropNames);
604 IncrementProgressBar(false);
607 if (pShapeList)
609 ScMyShapeList::const_iterator aEndItr(pShapeList->end());
610 while ( aShapeItr != aEndItr && ( aShapeItr->aAddress.Tab() == nTable ) )
612 GetShapeExport()->collectShapeAutoStyles(aShapeItr->xShape, aAutoStylePropNames);
613 IncrementProgressBar(false);
614 ++aShapeItr;
617 if (pSharedData->GetNoteShapes())
619 const ScMyNoteShapeList& rNoteShapes = pSharedData->GetNoteShapes()->GetNotes();
620 for (const auto& rNoteShape : rNoteShapes)
622 if ( rNoteShape.aPos.Tab() == nTable )
623 GetShapeExport()->collectShapeAutoStyles(rNoteShape.xShape, aAutoStylePropNames);
629 pSharedData->SortNoteShapes(); // sort twice, because some more shapes are added
632 void ScXMLExport::ExportMeta_()
634 sal_Int32 nCellCount(pDoc ? pDoc->GetCellCount() : 0);
635 SCTAB nTableCount(0);
636 sal_Int32 nShapesCount(0);
637 GetAutoStylePool()->ClearEntries();
638 CollectSharedData(nTableCount, nShapesCount);
640 uno::Sequence<beans::NamedValue> stats
642 { "TableCount", uno::Any(static_cast<sal_Int32>(nTableCount)) },
643 { "CellCount", uno::Any(nCellCount) },
644 { "ObjectCount", uno::Any(nShapesCount) }
647 // update document statistics at the model
648 uno::Reference<document::XDocumentPropertiesSupplier> xPropSup(GetModel(),
649 uno::UNO_QUERY_THROW);
650 uno::Reference<document::XDocumentProperties> xDocProps(
651 xPropSup->getDocumentProperties());
652 if (xDocProps.is()) {
653 xDocProps->setDocumentStatistics(stats);
656 // export document properties
657 SvXMLExport::ExportMeta_();
660 void ScXMLExport::ExportFontDecls_()
662 GetFontAutoStylePool(); // make sure the pool is created
663 SvXMLExport::ExportFontDecls_();
666 table::CellRangeAddress ScXMLExport::GetEndAddress(const uno::Reference<sheet::XSpreadsheet>& xTable)
668 table::CellRangeAddress aCellAddress;
669 uno::Reference<sheet::XSheetCellCursor> xCursor(xTable->createCursor());
670 uno::Reference<sheet::XUsedAreaCursor> xUsedArea (xCursor, uno::UNO_QUERY);
671 uno::Reference<sheet::XCellRangeAddressable> xCellAddress (xCursor, uno::UNO_QUERY);
672 if (xUsedArea.is() && xCellAddress.is())
674 xUsedArea->gotoEndOfUsedArea(true);
675 aCellAddress = xCellAddress->getRangeAddress();
677 return aCellAddress;
680 void ScXMLExport::GetAreaLinks( ScMyAreaLinksContainer& rAreaLinks )
682 if (pDoc->GetLinkManager())
684 const sfx2::SvBaseLinks& rLinks = pDoc->GetLinkManager()->GetLinks();
685 for (const auto & rLink : rLinks)
687 ScAreaLink *pLink = dynamic_cast<ScAreaLink*>(rLink.get());
688 if (pLink)
690 ScMyAreaLink aAreaLink;
691 aAreaLink.aDestRange = pLink->GetDestArea();
692 aAreaLink.sSourceStr = pLink->GetSource();
693 aAreaLink.sFilter = pLink->GetFilter();
694 aAreaLink.sFilterOptions = pLink->GetOptions();
695 aAreaLink.sURL = pLink->GetFile();
696 aAreaLink.nRefreshDelaySeconds = pLink->GetRefreshDelaySeconds();
697 rAreaLinks.AddNewAreaLink( aAreaLink );
701 rAreaLinks.Sort();
704 // core implementation
705 void ScXMLExport::GetDetectiveOpList( ScMyDetectiveOpContainer& rDetOp )
707 if (!pDoc)
708 return;
710 ScDetOpList* pOpList(pDoc->GetDetOpList());
711 if( !pOpList )
712 return;
714 size_t nCount = pOpList->Count();
715 for (size_t nIndex = 0; nIndex < nCount; ++nIndex )
717 const ScDetOpData& rDetData = pOpList->GetObject( nIndex);
718 const ScAddress& rDetPos = rDetData.GetPos();
719 SCTAB nTab = rDetPos.Tab();
720 if ( nTab < pDoc->GetTableCount() )
722 rDetOp.AddOperation( rDetData.GetOperation(), rDetPos, static_cast<sal_uInt32>( nIndex) );
724 // cells with detective operations are written even if empty
725 pSharedData->SetLastColumn( nTab, rDetPos.Col() );
726 pSharedData->SetLastRow( nTab, rDetPos.Row() );
729 rDetOp.Sort();
732 void ScXMLExport::WriteSingleColumn(const sal_Int32 nRepeatColumns, const sal_Int32 nStyleIndex,
733 const sal_Int32 nIndex, const bool bIsAutoStyle, const bool bIsVisible)
735 CheckAttrList();
736 // tdf#138466
737 if (nStyleIndex != -1)
738 AddAttribute(sAttrStyleName, pColumnStyles->GetStyleNameByIndex(nStyleIndex));
739 if (!bIsVisible)
740 AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_COLLAPSE);
741 if (nRepeatColumns > 1)
743 OUString sOUEndCol(OUString::number(nRepeatColumns));
744 AddAttribute(sAttrColumnsRepeated, sOUEndCol);
746 if (nIndex != -1)
747 AddAttribute(XML_NAMESPACE_TABLE, XML_DEFAULT_CELL_STYLE_NAME, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle));
748 SvXMLElementExport aElemC(*this, sElemCol, true, true);
751 void ScXMLExport::WriteColumn(const sal_Int32 nColumn, const sal_Int32 nRepeatColumns,
752 const sal_Int32 nStyleIndex, const bool bIsVisible)
754 sal_Int32 nRepeat(1);
755 sal_Int32 nPrevIndex(pDefaults->GetColDefaults()[nColumn].nIndex);
756 bool bPrevAutoStyle(pDefaults->GetColDefaults()[nColumn].bIsAutoStyle);
757 for (sal_Int32 i = nColumn + 1; i < nColumn + nRepeatColumns; ++i)
759 if ((pDefaults->GetColDefaults()[i].nIndex != nPrevIndex) ||
760 (pDefaults->GetColDefaults()[i].bIsAutoStyle != bPrevAutoStyle))
762 WriteSingleColumn(nRepeat, nStyleIndex, nPrevIndex, bPrevAutoStyle, bIsVisible);
763 nPrevIndex = pDefaults->GetColDefaults()[i].nIndex;
764 bPrevAutoStyle = pDefaults->GetColDefaults()[i].bIsAutoStyle;
765 nRepeat = 1;
767 else
768 ++nRepeat;
770 WriteSingleColumn(nRepeat, nStyleIndex, nPrevIndex, bPrevAutoStyle, bIsVisible);
773 void ScXMLExport::OpenHeaderColumn()
775 StartElement( XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true );
778 void ScXMLExport::CloseHeaderColumn()
780 EndElement(XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true);
783 void ScXMLExport::ExportColumns(const sal_Int32 nTable, const ScRange& aColumnHeaderRange, const bool bHasColumnHeader)
785 sal_Int32 nColsRepeated (1);
786 sal_Int32 nIndex;
787 sal_Int32 nPrevColumn(0);
788 bool bPrevIsVisible (true);
789 bool bWasHeader (false);
790 bool bIsClosed (true);
791 sal_Int32 nPrevIndex (-1);
792 sal_Int32 nColumn;
793 for (nColumn = 0; nColumn <= pSharedData->GetLastColumn(nTable); ++nColumn)
795 CheckAttrList();
796 bool bIsVisible(true);
797 nIndex = pColumnStyles->GetStyleNameIndex(nTable, nColumn, bIsVisible);
799 const bool bIsHeader = bHasColumnHeader && (aColumnHeaderRange.aStart.Col() <= nColumn) && (nColumn <= aColumnHeaderRange.aEnd.Col());
800 if (bIsHeader != bWasHeader)
802 if (bIsHeader)
804 if (nColumn > 0)
806 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
807 if (pGroupColumns->IsGroupEnd(nColumn - 1))
808 pGroupColumns->CloseGroups(nColumn - 1);
810 bPrevIsVisible = bIsVisible;
811 nPrevIndex = nIndex;
812 nPrevColumn = nColumn;
813 nColsRepeated = 1;
814 if(pGroupColumns->IsGroupStart(nColumn))
815 pGroupColumns->OpenGroups(nColumn);
816 OpenHeaderColumn();
817 bWasHeader = true;
818 bIsClosed = false;
820 else
822 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
823 CloseHeaderColumn();
824 if (pGroupColumns->IsGroupEnd(nColumn - 1))
825 pGroupColumns->CloseGroups(nColumn - 1);
826 if(pGroupColumns->IsGroupStart(nColumn))
827 pGroupColumns->OpenGroups(nColumn);
828 bPrevIsVisible = bIsVisible;
829 nPrevIndex = nIndex;
830 nPrevColumn = nColumn;
831 nColsRepeated = 1;
832 bWasHeader = false;
833 bIsClosed = true;
836 else if (nColumn == 0)
838 if (pGroupColumns->IsGroupStart(nColumn))
839 pGroupColumns->OpenGroups(nColumn);
840 bPrevIsVisible = bIsVisible;
841 nPrevIndex = nIndex;
843 else if ((bIsVisible == bPrevIsVisible) && (nIndex == nPrevIndex) &&
844 !pGroupColumns->IsGroupStart(nColumn) && !pGroupColumns->IsGroupEnd(nColumn - 1))
845 ++nColsRepeated;
846 else
848 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
849 if (pGroupColumns->IsGroupEnd(nColumn - 1))
851 if (bIsHeader)
852 CloseHeaderColumn();
853 pGroupColumns->CloseGroups(nColumn - 1);
854 if (bIsHeader)
855 OpenHeaderColumn();
857 if (pGroupColumns->IsGroupStart(nColumn))
859 if (bIsHeader)
860 CloseHeaderColumn();
861 pGroupColumns->OpenGroups(nColumn);
862 if (bIsHeader)
863 OpenHeaderColumn();
865 bPrevIsVisible = bIsVisible;
866 nPrevIndex = nIndex;
867 nPrevColumn = nColumn;
868 nColsRepeated = 1;
871 WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible);
872 if (!bIsClosed)
873 CloseHeaderColumn();
874 if (pGroupColumns->IsGroupEnd(nColumn - 1))
875 pGroupColumns->CloseGroups(nColumn - 1);
878 void ScXMLExport::ExportExternalRefCacheStyles()
880 sal_Int32 nEntryIndex = GetCellStylesPropertySetMapper()->FindEntryIndex(
881 "NumberFormat", XML_NAMESPACE_STYLE, u"data-style-name");
883 if (nEntryIndex < 0)
884 // No entry index for the number format is found.
885 return;
887 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
888 if (!pRefMgr->hasExternalData())
889 // No external reference data cached.
890 return;
892 // Export each unique number format used in the external ref cache.
893 vector<sal_uInt32> aNumFmts;
894 pRefMgr->getAllCachedNumberFormats(aNumFmts);
895 const OUString aDefaultStyle = OUString("Default").intern();
896 for (const auto& rNumFmt : aNumFmts)
898 sal_Int32 nNumFmt = static_cast<sal_Int32>(rNumFmt);
900 addDataStyle(nNumFmt);
902 uno::Any aVal;
903 aVal <<= nNumFmt;
904 vector<XMLPropertyState> aProps;
905 aVal <<= aDefaultStyle;
906 aProps.emplace_back(nEntryIndex, aVal);
908 OUString aName;
909 sal_Int32 nIndex;
910 if (GetAutoStylePool()->Add(aName, XmlStyleFamily::TABLE_CELL, aDefaultStyle, std::move(aProps)))
912 pCellStyles->AddStyleName(aName, nIndex);
914 else
916 bool bIsAuto;
917 nIndex = pCellStyles->GetIndexOfStyleName(
918 aName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX, bIsAuto);
921 // store the number format to index mapping for later use.
922 aNumFmtIndexMap.emplace(nNumFmt, nIndex);
926 namespace {
928 void handleFont(
929 SvXMLExport & rExport,
930 std::vector<XMLPropertyState>& rPropStates,
931 const SfxPoolItem* p, const rtl::Reference<XMLPropertySetMapper>& xMapper, std::u16string_view rXMLName )
933 sal_Int32 nEntryCount = xMapper->GetEntryCount();
935 // Apparently font info needs special handling.
936 const SvxFontItem* pItem = static_cast<const SvxFontItem*>(p);
938 sal_Int32 nIndexFontName = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, rXMLName, 0);
940 if (nIndexFontName == -1 || nIndexFontName >= nEntryCount)
941 return;
943 OUString const sFamilyName(pItem->GetFamilyName());
944 OUString const sStyleName(pItem->GetStyleName());
945 auto const nFamily(pItem->GetFamily());
946 auto const nPitch(pItem->GetPitch());
947 auto const eEnc(pItem->GetCharSet());
948 OUString const sName(rExport.GetFontAutoStylePool()->Find(
949 sFamilyName, sStyleName, nFamily, nPitch, eEnc));
950 if (sName.isEmpty())
952 assert(false); // fallback to fo:font-family etc. probably not needed
955 rPropStates.emplace_back(nIndexFontName, uno::Any(sName));
958 const SvxFieldData* toXMLPropertyStates(
959 SvXMLExport & rExport,
960 std::vector<XMLPropertyState>& rPropStates, const std::vector<const SfxPoolItem*>& rSecAttrs,
961 const rtl::Reference<XMLPropertySetMapper>& xMapper, const ScXMLEditAttributeMap& rAttrMap )
963 const SvxFieldData* pField = nullptr;
964 sal_Int32 nEntryCount = xMapper->GetEntryCount();
965 rPropStates.reserve(rSecAttrs.size());
966 for (const SfxPoolItem* p : rSecAttrs)
968 if (p->Which() == EE_FEATURE_FIELD)
970 pField = static_cast<const SvxFieldItem*>(p)->GetField();
971 continue;
974 const ScXMLEditAttributeMap::Entry* pEntry = rAttrMap.getEntryByItemID(p->Which());
975 if (!pEntry)
976 continue;
978 sal_Int32 nIndex = xMapper->GetEntryIndex(
979 pEntry->nmXMLNS, OUString::createFromAscii(pEntry->mpXMLName), 0);
981 if (nIndex == -1 || nIndex >= nEntryCount)
982 continue;
984 uno::Any aAny;
985 switch (p->Which())
987 case EE_CHAR_FONTINFO:
988 handleFont(rExport, rPropStates, p, xMapper, u"font-name");
989 break;
990 case EE_CHAR_FONTINFO_CJK:
991 handleFont(rExport, rPropStates, p, xMapper, u"font-name-asian");
992 break;
993 case EE_CHAR_FONTINFO_CTL:
994 handleFont(rExport, rPropStates, p, xMapper, u"font-name-complex");
995 break;
996 case EE_CHAR_WEIGHT:
997 case EE_CHAR_WEIGHT_CJK:
998 case EE_CHAR_WEIGHT_CTL:
1000 if (!static_cast<const SvxWeightItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1001 continue;
1003 rPropStates.emplace_back(nIndex, aAny);
1005 break;
1006 case EE_CHAR_FONTHEIGHT:
1007 case EE_CHAR_FONTHEIGHT_CJK:
1008 case EE_CHAR_FONTHEIGHT_CTL:
1010 if (!static_cast<const SvxFontHeightItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1011 continue;
1013 rPropStates.emplace_back(nIndex, aAny);
1015 break;
1016 case EE_CHAR_ITALIC:
1017 case EE_CHAR_ITALIC_CJK:
1018 case EE_CHAR_ITALIC_CTL:
1020 if (!static_cast<const SvxPostureItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1021 continue;
1023 rPropStates.emplace_back(nIndex, aAny);
1025 break;
1026 case EE_CHAR_UNDERLINE:
1028 // Underline attribute needs to export multiple entries.
1029 sal_Int32 nIndexStyle = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-style", 0);
1030 if (nIndexStyle == -1 || nIndexStyle > nEntryCount)
1031 break;
1033 sal_Int32 nIndexWidth = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-width", 0);
1034 if (nIndexWidth == -1 || nIndexWidth > nEntryCount)
1035 break;
1037 sal_Int32 nIndexType = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-type", 0);
1038 if (nIndexType == -1 || nIndexType > nEntryCount)
1039 break;
1041 sal_Int32 nIndexColor = xMapper->FindEntryIndex("CharUnderlineColor", XML_NAMESPACE_STYLE, u"text-underline-color");
1042 if (nIndexColor == -1 || nIndexColor > nEntryCount)
1043 break;
1045 sal_Int32 nIndexHasColor = xMapper->FindEntryIndex("CharUnderlineHasColor", XML_NAMESPACE_STYLE, u"text-underline-color");
1046 if (nIndexHasColor == -1 || nIndexHasColor > nEntryCount)
1047 break;
1049 const SvxUnderlineItem* pUL = static_cast<const SvxUnderlineItem*>(p);
1050 pUL->QueryValue(aAny, MID_TL_STYLE);
1051 rPropStates.emplace_back(nIndexStyle, aAny);
1052 rPropStates.emplace_back(nIndexType, aAny);
1053 rPropStates.emplace_back(nIndexWidth, aAny);
1055 pUL->QueryValue(aAny, MID_TL_COLOR);
1056 rPropStates.emplace_back(nIndexColor, aAny);
1058 pUL->QueryValue(aAny, MID_TL_HASCOLOR);
1059 rPropStates.emplace_back(nIndexHasColor, aAny);
1061 break;
1062 case EE_CHAR_OVERLINE:
1064 // Same with overline. Do just as we do with underline attributes.
1065 sal_Int32 nIndexStyle = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-style", 0);
1066 if (nIndexStyle == -1 || nIndexStyle > nEntryCount)
1067 break;
1069 sal_Int32 nIndexWidth = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-width", 0);
1070 if (nIndexWidth == -1 || nIndexWidth > nEntryCount)
1071 break;
1073 sal_Int32 nIndexType = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-type", 0);
1074 if (nIndexType == -1 || nIndexType > nEntryCount)
1075 break;
1077 sal_Int32 nIndexColor = xMapper->FindEntryIndex("CharOverlineColor", XML_NAMESPACE_STYLE, u"text-overline-color");
1078 if (nIndexColor == -1 || nIndexColor > nEntryCount)
1079 break;
1081 sal_Int32 nIndexHasColor = xMapper->FindEntryIndex("CharOverlineHasColor", XML_NAMESPACE_STYLE, u"text-overline-color");
1082 if (nIndexHasColor == -1 || nIndexHasColor > nEntryCount)
1083 break;
1085 const SvxOverlineItem* pOL = static_cast<const SvxOverlineItem*>(p);
1086 pOL->QueryValue(aAny, MID_TL_STYLE);
1087 rPropStates.emplace_back(nIndexStyle, aAny);
1088 rPropStates.emplace_back(nIndexType, aAny);
1089 rPropStates.emplace_back(nIndexWidth, aAny);
1091 pOL->QueryValue(aAny, MID_TL_COLOR);
1092 rPropStates.emplace_back(nIndexColor, aAny);
1094 pOL->QueryValue(aAny, MID_TL_HASCOLOR);
1095 rPropStates.emplace_back(nIndexHasColor, aAny);
1097 break;
1098 case EE_CHAR_COLOR:
1100 if (!static_cast<const SvxColorItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1101 continue;
1103 ::Color nColor;
1104 if ( aAny >>= nColor )
1106 sal_Int32 nIndexColor = ( nColor == COL_AUTO ) ? xMapper->GetEntryIndex(
1107 XML_NAMESPACE_STYLE, GetXMLToken( XML_USE_WINDOW_FONT_COLOR ), 0 ) : nIndex;
1108 rPropStates.emplace_back( nIndexColor, aAny );
1111 break;
1112 case EE_CHAR_WLM:
1114 if (!static_cast<const SvxWordLineModeItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1115 continue;
1117 rPropStates.emplace_back(nIndex, aAny);
1119 break;
1120 case EE_CHAR_STRIKEOUT:
1122 if (!static_cast<const SvxCrossedOutItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1123 continue;
1125 rPropStates.emplace_back(nIndex, aAny);
1127 break;
1128 case EE_CHAR_RELIEF:
1130 if (!static_cast<const SvxCharReliefItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1131 continue;
1133 rPropStates.emplace_back(nIndex, aAny);
1135 break;
1136 case EE_CHAR_OUTLINE:
1138 if (!static_cast<const SvxContourItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1139 continue;
1141 rPropStates.emplace_back(nIndex, aAny);
1143 break;
1144 case EE_CHAR_SHADOW:
1146 if (!static_cast<const SvxShadowedItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1147 continue;
1149 rPropStates.emplace_back(nIndex, aAny);
1151 break;
1152 case EE_CHAR_KERNING:
1154 if (!static_cast<const SvxKerningItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1155 continue;
1157 rPropStates.emplace_back(nIndex, aAny);
1159 break;
1160 case EE_CHAR_PAIRKERNING:
1162 if (!static_cast<const SvxAutoKernItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1163 continue;
1165 rPropStates.emplace_back(nIndex, aAny);
1167 break;
1168 case EE_CHAR_FONTWIDTH:
1170 if (!static_cast<const SvxCharScaleWidthItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1171 continue;
1173 rPropStates.emplace_back(nIndex, aAny);
1175 break;
1176 case EE_CHAR_ESCAPEMENT:
1178 sal_Int32 nIndexEsc = xMapper->FindEntryIndex("CharEscapement", XML_NAMESPACE_STYLE, u"text-position");
1179 if (nIndexEsc == -1 || nIndexEsc > nEntryCount)
1180 break;
1182 sal_Int32 nIndexEscHeight = xMapper->FindEntryIndex("CharEscapementHeight", XML_NAMESPACE_STYLE, u"text-position");
1183 if (nIndexEscHeight == -1 || nIndexEscHeight > nEntryCount)
1184 break;
1186 const SvxEscapementItem* pEsc = static_cast<const SvxEscapementItem*>(p);
1188 pEsc->QueryValue(aAny);
1189 rPropStates.emplace_back(nIndexEsc, aAny);
1191 pEsc->QueryValue(aAny, MID_ESC_HEIGHT);
1192 rPropStates.emplace_back(nIndexEscHeight, aAny);
1195 break;
1196 case EE_CHAR_EMPHASISMARK:
1198 if (!static_cast<const SvxEmphasisMarkItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1199 continue;
1201 rPropStates.emplace_back(nIndex, aAny);
1203 break;
1204 case EE_CHAR_LANGUAGE:
1205 case EE_CHAR_LANGUAGE_CJK:
1206 case EE_CHAR_LANGUAGE_CTL:
1208 if (!static_cast<const SvxLanguageItem*>(p)->QueryValue(aAny, pEntry->mnFlag))
1209 continue;
1211 // Export multiple entries.
1212 sal_Int32 nIndexLanguage, nIndexCountry, nIndexScript, nIndexTag;
1213 switch (p->Which())
1215 case EE_CHAR_LANGUAGE:
1216 nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"language", 0);
1217 nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"country", 0);
1218 nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"script", 0);
1219 nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag", 0);
1220 break;
1221 case EE_CHAR_LANGUAGE_CJK:
1222 nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"language-asian", 0);
1223 nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"country-asian", 0);
1224 nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"script-asian", 0);
1225 nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag-asian", 0);
1226 break;
1227 case EE_CHAR_LANGUAGE_CTL:
1228 nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"language-complex", 0);
1229 nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"country-complex", 0);
1230 nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"script-complex", 0);
1231 nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag-complex", 0);
1232 break;
1233 default:
1234 nIndexLanguage = nIndexCountry = nIndexScript = nIndexTag = -1;
1236 assert( nIndexLanguage >= 0 && nIndexCountry >= 0 && nIndexScript >= 0 && nIndexTag >= 0);
1237 rPropStates.emplace_back( nIndexLanguage, aAny);
1238 rPropStates.emplace_back( nIndexCountry, aAny);
1239 rPropStates.emplace_back( nIndexScript, aAny);
1240 rPropStates.emplace_back( nIndexTag, aAny);
1242 break;
1243 default:
1244 continue;
1248 return pField;
1253 void ScXMLExport::ExportCellTextAutoStyles(sal_Int32 nTable)
1255 if (!ValidTab(nTable))
1256 return;
1258 rtl::Reference<XMLPropertySetMapper> xMapper = GetTextParagraphExport()->GetTextPropMapper()->getPropertySetMapper();
1259 rtl::Reference<SvXMLAutoStylePoolP> xStylePool = GetAutoStylePool();
1260 const ScXMLEditAttributeMap& rAttrMap = GetEditAttributeMap();
1262 sc::EditTextIterator aIter(*pDoc, nTable);
1263 sal_Int32 nCellCount = 0;
1264 for (const EditTextObject* pEdit = aIter.first(); pEdit; pEdit = aIter.next(), ++nCellCount)
1266 std::vector<editeng::Section> aAttrs;
1267 pEdit->GetAllSections(aAttrs);
1268 if (aAttrs.empty())
1269 continue;
1271 for (const auto& rSec : aAttrs)
1273 const std::vector<const SfxPoolItem*>& rSecAttrs = rSec.maAttributes;
1274 if (rSecAttrs.empty())
1275 // No formats applied to this section. Skip it.
1276 continue;
1278 std::vector<XMLPropertyState> aPropStates;
1279 toXMLPropertyStates(*this, aPropStates, rSecAttrs, xMapper, rAttrMap);
1280 if (!aPropStates.empty())
1281 xStylePool->Add(XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates));
1285 GetProgressBarHelper()->ChangeReference(GetProgressBarHelper()->GetReference() + nCellCount);
1288 void ScXMLExport::WriteRowContent()
1290 ScMyRowFormatRange aRange;
1291 sal_Int32 nIndex(-1);
1292 #if OSL_DEBUG_LEVEL > 0
1293 sal_Int32 nPrevCol(0);
1294 #endif
1295 sal_Int32 nCols(0);
1296 sal_Int32 nPrevValidationIndex(-1);
1297 bool bIsAutoStyle(true);
1298 bool bIsFirst(true);
1299 while (pRowFormatRanges->GetNext(aRange))
1301 #if OSL_DEBUG_LEVEL > 0
1302 OSL_ENSURE(bIsFirst || (!bIsFirst && (nPrevCol + nCols == aRange.nStartColumn)), "here are some columns missing");
1303 #endif
1304 if (bIsFirst)
1306 nIndex = aRange.nIndex;
1307 nPrevValidationIndex = aRange.nValidationIndex;
1308 bIsAutoStyle = aRange.bIsAutoStyle;
1309 nCols = aRange.nRepeatColumns;
1310 bIsFirst = false;
1311 #if OSL_DEBUG_LEVEL > 0
1312 nPrevCol = aRange.nStartColumn;
1313 #endif
1315 else
1317 if (((aRange.nIndex == nIndex && aRange.bIsAutoStyle == bIsAutoStyle) ||
1318 (aRange.nIndex == nIndex && nIndex == -1)) &&
1319 nPrevValidationIndex == aRange.nValidationIndex)
1320 nCols += aRange.nRepeatColumns;
1321 else
1323 if (nIndex != -1)
1324 AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle));
1325 if (nPrevValidationIndex > -1)
1326 AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(nPrevValidationIndex));
1327 if (nCols > 1)
1329 AddAttribute(sAttrColumnsRepeated, OUString::number(nCols));
1331 SvXMLElementExport aElemC(*this, sElemCell, true, true);
1332 nIndex = aRange.nIndex;
1333 bIsAutoStyle = aRange.bIsAutoStyle;
1334 nCols = aRange.nRepeatColumns;
1335 nPrevValidationIndex = aRange.nValidationIndex;
1336 #if OSL_DEBUG_LEVEL > 0
1337 nPrevCol = aRange.nStartColumn;
1338 #endif
1342 if (!bIsFirst)
1344 if (nIndex != -1)
1345 AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle));
1346 if (nPrevValidationIndex > -1)
1347 AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(nPrevValidationIndex));
1348 if (nCols > 1)
1350 AddAttribute(sAttrColumnsRepeated, OUString::number(nCols));
1352 SvXMLElementExport aElemC(*this, sElemCell, true, true);
1356 void ScXMLExport::WriteRowStartTag(
1357 const sal_Int32 nIndex, const sal_Int32 nEqualRows,
1358 bool bHidden, bool bFiltered)
1360 // tdf#143940
1361 if (nIndex != -1)
1362 AddAttribute(sAttrStyleName, pRowStyles->GetStyleNameByIndex(nIndex));
1363 if (bHidden)
1365 if (bFiltered)
1366 AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_FILTER);
1367 else
1368 AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_COLLAPSE);
1370 if (nEqualRows > 1)
1372 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, OUString::number(nEqualRows));
1375 StartElement( sElemRow, true);
1378 void ScXMLExport::OpenHeaderRows()
1380 StartElement( XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true);
1381 bRowHeaderOpen = true;
1384 void ScXMLExport::CloseHeaderRows()
1386 EndElement(XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true);
1389 void ScXMLExport::OpenNewRow(
1390 const sal_Int32 nIndex, const sal_Int32 nStartRow, const sal_Int32 nEqualRows,
1391 bool bHidden, bool bFiltered)
1393 nOpenRow = nStartRow;
1394 if (pGroupRows->IsGroupStart(nStartRow))
1396 if (bHasRowHeader && bRowHeaderOpen)
1397 CloseHeaderRows();
1398 pGroupRows->OpenGroups(nStartRow);
1399 if (bHasRowHeader && bRowHeaderOpen)
1400 OpenHeaderRows();
1402 if (bHasRowHeader && !bRowHeaderOpen && nStartRow >= aRowHeaderRange.aStart.Row() && nStartRow <= aRowHeaderRange.aEnd.Row())
1404 if (nStartRow == aRowHeaderRange.aStart.Row())
1405 OpenHeaderRows();
1406 sal_Int32 nEquals;
1407 if (aRowHeaderRange.aEnd.Row() < nStartRow + nEqualRows - 1)
1408 nEquals = aRowHeaderRange.aEnd.Row() - nStartRow + 1;
1409 else
1410 nEquals = nEqualRows;
1411 WriteRowStartTag(nIndex, nEquals, bHidden, bFiltered);
1412 nOpenRow = nStartRow + nEquals - 1;
1413 if (nEquals < nEqualRows)
1415 CloseRow(nStartRow + nEquals - 1);
1416 WriteRowStartTag(nIndex, nEqualRows - nEquals, bHidden, bFiltered);
1417 nOpenRow = nStartRow + nEqualRows - 1;
1420 else
1421 WriteRowStartTag(nIndex, nEqualRows, bHidden, bFiltered);
1424 void ScXMLExport::OpenAndCloseRow(
1425 const sal_Int32 nIndex, const sal_Int32 nStartRow, const sal_Int32 nEqualRows,
1426 bool bHidden, bool bFiltered)
1428 OpenNewRow(nIndex, nStartRow, nEqualRows, bHidden, bFiltered);
1429 WriteRowContent();
1430 CloseRow(nStartRow + nEqualRows - 1);
1431 pRowFormatRanges->Clear();
1434 void ScXMLExport::OpenRow(const sal_Int32 nTable, const sal_Int32 nStartRow, const sal_Int32 nRepeatRow, ScXMLCachedRowAttrAccess& rRowAttr)
1436 if (nRepeatRow > 1)
1438 sal_Int32 nPrevIndex(0), nIndex;
1439 bool bPrevHidden = false;
1440 bool bPrevFiltered = false;
1441 bool bHidden = false;
1442 bool bFiltered = false;
1443 sal_Int32 nEqualRows(1);
1444 sal_Int32 nEndRow(nStartRow + nRepeatRow);
1445 sal_Int32 nEndRowHidden = nStartRow - 1;
1446 sal_Int32 nEndRowFiltered = nStartRow - 1;
1447 sal_Int32 nRow;
1448 for (nRow = nStartRow; nRow < nEndRow; ++nRow)
1450 if (nRow == nStartRow)
1452 nPrevIndex = pRowStyles->GetStyleNameIndex(nTable, nRow);
1453 if (pDoc)
1455 if (nRow > nEndRowHidden)
1457 bPrevHidden = rRowAttr.rowHidden(nTable, nRow, nEndRowHidden);
1458 bHidden = bPrevHidden;
1460 if (nRow > nEndRowFiltered)
1462 bPrevFiltered = rRowAttr.rowFiltered(nTable, nRow, nEndRowFiltered);
1463 bFiltered = bPrevFiltered;
1468 else
1470 nIndex = pRowStyles->GetStyleNameIndex(nTable, nRow);
1471 if (pDoc)
1473 if (nRow > nEndRowHidden)
1474 bHidden = rRowAttr.rowHidden(nTable, nRow, nEndRowHidden);
1475 if (nRow > nEndRowFiltered)
1476 bFiltered = rRowAttr.rowFiltered(nTable, nRow, nEndRowFiltered);
1478 if (nIndex == nPrevIndex && bHidden == bPrevHidden && bFiltered == bPrevFiltered &&
1479 !(bHasRowHeader && ((nRow == aRowHeaderRange.aStart.Row()) || (nRow - 1 == aRowHeaderRange.aEnd.Row()))) &&
1480 !(pGroupRows->IsGroupStart(nRow)) &&
1481 !(pGroupRows->IsGroupEnd(nRow - 1)))
1482 ++nEqualRows;
1483 else
1485 assert(nPrevIndex >= 0 && "coverity#1438402");
1486 ScRowFormatRanges* pTempRowFormatRanges = new ScRowFormatRanges(pRowFormatRanges.get());
1487 OpenAndCloseRow(nPrevIndex, nRow - nEqualRows, nEqualRows, bPrevHidden, bPrevFiltered);
1488 pRowFormatRanges.reset(pTempRowFormatRanges);
1489 nEqualRows = 1;
1490 nPrevIndex = nIndex;
1491 bPrevHidden = bHidden;
1492 bPrevFiltered = bFiltered;
1496 assert(nPrevIndex >= 0 && "coverity#1438402");
1497 OpenNewRow(nPrevIndex, nRow - nEqualRows, nEqualRows, bPrevHidden, bPrevFiltered);
1499 else
1501 sal_Int32 nIndex = pRowStyles->GetStyleNameIndex(nTable, nStartRow);
1502 bool bHidden = false;
1503 bool bFiltered = false;
1504 if (pDoc)
1506 sal_Int32 nEndRowHidden;
1507 sal_Int32 nEndRowFiltered;
1508 bHidden = rRowAttr.rowHidden(nTable, nStartRow, nEndRowHidden);
1509 bFiltered = rRowAttr.rowFiltered(nTable, nStartRow, nEndRowFiltered);
1511 assert(nIndex >= 0 && "coverity#1438402");
1512 OpenNewRow(nIndex, nStartRow, 1, bHidden, bFiltered);
1514 nOpenRow = nStartRow + nRepeatRow - 1;
1517 void ScXMLExport::CloseRow(const sal_Int32 nRow)
1519 if (nOpenRow > -1)
1521 EndElement(sElemRow, true);
1522 if (bHasRowHeader && nRow == aRowHeaderRange.aEnd.Row())
1524 CloseHeaderRows();
1525 bRowHeaderOpen = false;
1527 if (pGroupRows->IsGroupEnd(nRow))
1529 if (bHasRowHeader && bRowHeaderOpen)
1530 CloseHeaderRows();
1531 pGroupRows->CloseGroups(nRow);
1532 if (bHasRowHeader && bRowHeaderOpen)
1533 OpenHeaderRows();
1536 nOpenRow = -1;
1539 void ScXMLExport::ExportFormatRanges(const sal_Int32 nStartCol, const sal_Int32 nStartRow,
1540 const sal_Int32 nEndCol, const sal_Int32 nEndRow, const sal_Int32 nSheet)
1542 pRowFormatRanges->Clear();
1543 ScXMLCachedRowAttrAccess aRowAttr(pDoc);
1544 if (nStartRow == nEndRow)
1546 pCellStyles->GetFormatRanges(nStartCol, nEndCol, nStartRow, nSheet, pRowFormatRanges.get());
1547 if (nOpenRow == - 1)
1548 OpenRow(nSheet, nStartRow, 1, aRowAttr);
1549 WriteRowContent();
1550 pRowFormatRanges->Clear();
1552 else
1554 if (nOpenRow > -1)
1556 pCellStyles->GetFormatRanges(nStartCol, pSharedData->GetLastColumn(nSheet), nStartRow, nSheet, pRowFormatRanges.get());
1557 WriteRowContent();
1558 CloseRow(nStartRow);
1559 sal_Int32 nRows(1);
1560 sal_Int32 nTotalRows(nEndRow - nStartRow + 1 - 1);
1561 while (nRows < nTotalRows)
1563 pRowFormatRanges->Clear();
1564 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1565 sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows();
1566 OSL_ENSURE(nMaxRows, "something went wrong");
1567 if (nMaxRows >= nTotalRows - nRows)
1569 OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, aRowAttr);
1570 nRows += nTotalRows - nRows;
1572 else
1574 OpenRow(nSheet, nStartRow + nRows, nMaxRows, aRowAttr);
1575 nRows += nMaxRows;
1577 if (!pRowFormatRanges->GetSize())
1578 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1579 WriteRowContent();
1580 CloseRow(nStartRow + nRows - 1);
1582 if (nTotalRows == 1)
1583 CloseRow(nStartRow);
1584 OpenRow(nSheet, nEndRow, 1, aRowAttr);
1585 pRowFormatRanges->Clear();
1586 pCellStyles->GetFormatRanges(0, nEndCol, nEndRow, nSheet, pRowFormatRanges.get());
1587 WriteRowContent();
1589 else
1591 sal_Int32 nRows(0);
1592 sal_Int32 nTotalRows(nEndRow - nStartRow + 1 - 1);
1593 while (nRows < nTotalRows)
1595 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1596 sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows();
1597 OSL_ENSURE(nMaxRows, "something went wrong");
1598 if (nMaxRows >= nTotalRows - nRows)
1600 OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, aRowAttr);
1601 nRows += nTotalRows - nRows;
1603 else
1605 OpenRow(nSheet, nStartRow + nRows, nMaxRows, aRowAttr);
1606 nRows += nMaxRows;
1608 if (!pRowFormatRanges->GetSize())
1609 pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get());
1610 WriteRowContent();
1611 CloseRow(nStartRow + nRows - 1);
1613 OpenRow(nSheet, nEndRow, 1, aRowAttr);
1614 pRowFormatRanges->Clear();
1615 pCellStyles->GetFormatRanges(0, nEndCol, nEndRow, nSheet, pRowFormatRanges.get());
1616 WriteRowContent();
1621 void ScXMLExport::GetColumnRowHeader(bool& rHasColumnHeader, ScRange& rColumnHeaderRange,
1622 bool& rHasRowHeader, ScRange& rRowHeaderRange,
1623 OUString& rPrintRanges) const
1625 uno::Reference <sheet::XPrintAreas> xPrintAreas (xCurrentTable, uno::UNO_QUERY);
1626 if (!xPrintAreas.is())
1627 return;
1629 rHasRowHeader = xPrintAreas->getPrintTitleRows();
1630 rHasColumnHeader = xPrintAreas->getPrintTitleColumns();
1631 table::CellRangeAddress rTempRowHeaderRange = xPrintAreas->getTitleRows();
1632 rRowHeaderRange = ScRange(rTempRowHeaderRange.StartColumn,
1633 rTempRowHeaderRange.StartRow,
1634 rTempRowHeaderRange.Sheet,
1635 rTempRowHeaderRange.EndColumn,
1636 rTempRowHeaderRange.EndRow,
1637 rTempRowHeaderRange.Sheet);
1638 table::CellRangeAddress rTempColumnHeaderRange = xPrintAreas->getTitleColumns();
1639 rColumnHeaderRange = ScRange(rTempColumnHeaderRange.StartColumn,
1640 rTempColumnHeaderRange.StartRow,
1641 rTempColumnHeaderRange.Sheet,
1642 rTempColumnHeaderRange.EndColumn,
1643 rTempColumnHeaderRange.EndRow,
1644 rTempColumnHeaderRange.Sheet);
1645 uno::Sequence< table::CellRangeAddress > aRangeList( xPrintAreas->getPrintAreas() );
1646 ScRangeStringConverter::GetStringFromRangeList( rPrintRanges, aRangeList, pDoc, FormulaGrammar::CONV_OOO );
1649 void ScXMLExport::FillFieldGroup(ScOutlineArray* pFields, ScMyOpenCloseColumnRowGroup* pGroups)
1651 size_t nDepth = pFields->GetDepth();
1652 for (size_t i = 0; i < nDepth; ++i)
1654 size_t nFields = pFields->GetCount(i);
1655 for (size_t j = 0; j < nFields; ++j)
1657 ScMyColumnRowGroup aGroup;
1658 const ScOutlineEntry* pEntry = pFields->GetEntry(i, j);
1659 aGroup.nField = pEntry->GetStart();
1660 aGroup.nLevel = static_cast<sal_Int16>(i);
1661 aGroup.bDisplay = !(pEntry->IsHidden());
1662 pGroups->AddGroup(aGroup, pEntry->GetEnd());
1665 if (nDepth)
1666 pGroups->Sort();
1669 void ScXMLExport::FillColumnRowGroups()
1671 if (!pDoc)
1672 return;
1674 ScOutlineTable* pOutlineTable = pDoc->GetOutlineTable( static_cast<SCTAB>(nCurrentTable) );
1675 if(pOutlineTable)
1677 ScOutlineArray& rCols(pOutlineTable->GetColArray());
1678 ScOutlineArray& rRows(pOutlineTable->GetRowArray());
1679 FillFieldGroup(&rCols, pGroupColumns.get());
1680 FillFieldGroup(&rRows, pGroupRows.get());
1681 pSharedData->SetLastColumn(nCurrentTable, pGroupColumns->GetLast());
1682 pSharedData->SetLastRow(nCurrentTable, pGroupRows->GetLast());
1686 void ScXMLExport::SetBodyAttributes()
1688 if (!(pDoc && pDoc->IsDocProtected()))
1689 return;
1691 AddAttribute(XML_NAMESPACE_TABLE, XML_STRUCTURE_PROTECTED, XML_TRUE);
1692 OUStringBuffer aBuffer;
1693 uno::Sequence<sal_Int8> aPassHash;
1694 ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED;
1695 const ScDocProtection* p = pDoc->GetDocProtection();
1696 if (p)
1698 if (p->hasPasswordHash(PASSHASH_SHA1))
1700 aPassHash = p->getPasswordHash(PASSHASH_SHA1);
1701 eHashUsed = PASSHASH_SHA1;
1703 else if (p->hasPasswordHash(PASSHASH_SHA256))
1705 aPassHash = p->getPasswordHash(PASSHASH_SHA256);
1706 eHashUsed = PASSHASH_SHA256;
1708 else if (p->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
1710 aPassHash = p->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
1711 eHashUsed = PASSHASH_XL;
1714 ::comphelper::Base64::encode(aBuffer, aPassHash);
1715 if (aBuffer.isEmpty())
1716 return;
1718 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
1719 if (getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012)
1720 return;
1722 if (eHashUsed == PASSHASH_XL)
1724 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
1725 ScPassHashHelper::getHashURI(PASSHASH_XL));
1726 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
1727 AddAttribute(XML_NAMESPACE_LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2,
1728 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
1730 else if (eHashUsed == PASSHASH_SHA1)
1732 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
1733 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
1735 else if (eHashUsed == PASSHASH_SHA256)
1737 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
1738 ScPassHashHelper::getHashURI(PASSHASH_SHA256));
1742 static bool lcl_CopyStreamElement( const uno::Reference< io::XInputStream >& xInput,
1743 const uno::Reference< io::XOutputStream >& xOutput,
1744 sal_Int32 nCount )
1746 const sal_Int32 nBufSize = 16*1024;
1747 uno::Sequence<sal_Int8> aSequence(nBufSize);
1749 sal_Int32 nRemaining = nCount;
1750 bool bFirst = true;
1752 while ( nRemaining > 0 )
1754 sal_Int32 nRead = xInput->readBytes( aSequence, std::min( nRemaining, nBufSize ) );
1755 if (bFirst)
1757 // safety check: Make sure the copied part actually points to the start of an element
1758 if ( nRead < 1 || aSequence[0] != static_cast<sal_Int8>('<') )
1760 return false; // abort and set an error
1762 bFirst = false;
1764 if (nRead == nRemaining)
1766 // safety check: Make sure the copied part also ends at the end of an element
1767 if ( aSequence[nRead-1] != static_cast<sal_Int8>('>') )
1769 return false; // abort and set an error
1773 if ( nRead == nBufSize )
1775 xOutput->writeBytes( aSequence );
1776 nRemaining -= nRead;
1778 else
1780 if ( nRead > 0 )
1782 uno::Sequence<sal_Int8> aTempBuf( aSequence.getConstArray(), nRead );
1783 xOutput->writeBytes( aTempBuf );
1785 nRemaining = 0;
1788 return true; // successful
1791 static void lcl_SkipBytesInBlocks( const uno::Reference< io::XInputStream >& xInput, sal_Int32 nBytesToSkip )
1793 // skipBytes in zip stream is implemented as reading.
1794 // For now, split into several calls to avoid allocating a large buffer.
1795 // Later, skipBytes should be changed.
1797 const sal_Int32 nMaxSize = 32*1024;
1799 if ( nBytesToSkip > 0 )
1801 sal_Int32 nRemaining = nBytesToSkip;
1802 while ( nRemaining > 0 )
1804 sal_Int32 nSkip = std::min( nRemaining, nMaxSize );
1805 xInput->skipBytes( nSkip );
1806 nRemaining -= nSkip;
1811 void ScXMLExport::CopySourceStream( sal_Int32 nStartOffset, sal_Int32 nEndOffset, sal_Int32& rNewStart, sal_Int32& rNewEnd )
1813 uno::Reference<xml::sax::XDocumentHandler> xHandler = GetDocHandler();
1814 uno::Reference<io::XActiveDataSource> xDestSource( xHandler, uno::UNO_QUERY );
1815 if ( !xDestSource.is() )
1816 return;
1818 uno::Reference<io::XOutputStream> xDestStream = xDestSource->getOutputStream();
1819 uno::Reference<io::XSeekable> xDestSeek( xDestStream, uno::UNO_QUERY );
1820 if ( !xDestSeek.is() )
1821 return;
1823 // temporary: set same stream again to clear buffer
1824 xDestSource->setOutputStream( xDestStream );
1826 if ( getExportFlags() & SvXMLExportFlags::PRETTY )
1828 const OString aOutStr("\n ");
1829 uno::Sequence<sal_Int8> aOutSeq( reinterpret_cast<sal_Int8 const *>(aOutStr.getStr()), aOutStr.getLength() );
1830 xDestStream->writeBytes( aOutSeq );
1833 rNewStart = static_cast<sal_Int32>(xDestSeek->getPosition());
1835 if ( nStartOffset > nSourceStreamPos )
1836 lcl_SkipBytesInBlocks( xSourceStream, nStartOffset - nSourceStreamPos );
1838 if ( !lcl_CopyStreamElement( xSourceStream, xDestStream, nEndOffset - nStartOffset ) )
1840 // If copying went wrong, set an error.
1841 // ScXMLImportWrapper then resets all stream flags, so the next save attempt will use normal saving.
1843 uno::Sequence<OUString> aEmptySeq;
1844 SetError(XMLERROR_CANCEL|XMLERROR_FLAG_SEVERE, aEmptySeq);
1846 nSourceStreamPos = nEndOffset;
1848 rNewEnd = static_cast<sal_Int32>(xDestSeek->getPosition());
1851 const ScXMLEditAttributeMap& ScXMLExport::GetEditAttributeMap() const
1853 if (!mpEditAttrMap)
1854 mpEditAttrMap.reset(new ScXMLEditAttributeMap);
1855 return *mpEditAttrMap;
1858 void ScXMLExport::RegisterDefinedStyleNames( const uno::Reference< css::sheet::XSpreadsheetDocument > & xSpreadDoc )
1860 ScFormatSaveData* pFormatData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetFormatSaveData();
1861 auto xAutoStylePool = GetAutoStylePool();
1862 for (const auto& rFormatInfo : pFormatData->maIDToName)
1864 xAutoStylePool->RegisterDefinedName(XmlStyleFamily::TABLE_CELL, rFormatInfo.second);
1868 void ScXMLExport::ExportContent_()
1870 nCurrentTable = 0;
1871 if (!pSharedData)
1873 SCTAB nTableCount(0);
1874 sal_Int32 nShapesCount(0);
1875 CollectSharedData(nTableCount, nShapesCount);
1876 OSL_FAIL("no shared data set");
1877 if (!pSharedData)
1878 return;
1880 ScXMLExportDatabaseRanges aExportDatabaseRanges(*this);
1881 if (!GetModel().is())
1882 return;
1884 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
1885 if ( !xSpreadDoc.is() )
1886 return;
1888 ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetSheetSaveData();
1889 if (pSheetData)
1890 pSheetData->ResetSaveEntries();
1892 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
1893 if ( xIndex.is() )
1895 //_GetNamespaceMap().ClearQNamesCache();
1896 pChangeTrackingExportHelper->CollectAndWriteChanges();
1897 WriteCalculationSettings(xSpreadDoc);
1898 sal_Int32 nTableCount(xIndex->getCount());
1899 ScMyAreaLinksContainer aAreaLinks;
1900 GetAreaLinks( aAreaLinks );
1901 ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges());
1902 ScMyDetectiveOpContainer aDetectiveOpContainer;
1903 GetDetectiveOpList( aDetectiveOpContainer );
1905 pCellStyles->Sort();
1906 pMergedRangesContainer->Sort();
1907 pSharedData->GetDetectiveObjContainer()->Sort();
1909 mpCellsItr->Clear();
1910 mpCellsItr->SetShapes( pSharedData->GetShapesContainer() );
1911 mpCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() );
1912 mpCellsItr->SetMergedRanges( pMergedRangesContainer.get() );
1913 mpCellsItr->SetAreaLinks( &aAreaLinks );
1914 mpCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges );
1915 mpCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() );
1916 mpCellsItr->SetDetectiveOp( &aDetectiveOpContainer );
1918 if (nTableCount > 0)
1919 pValidationsContainer->WriteValidations(*this);
1920 WriteTheLabelRanges( xSpreadDoc );
1921 for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable)
1923 sal_Int32 nStartOffset = -1;
1924 sal_Int32 nEndOffset = -1;
1925 if (pSheetData && pDoc && pDoc->IsStreamValid(static_cast<SCTAB>(nTable)) && !pDoc->GetChangeTrack())
1926 pSheetData->GetStreamPos( nTable, nStartOffset, nEndOffset );
1928 if ( nStartOffset >= 0 && nEndOffset >= 0 && xSourceStream.is() )
1930 sal_Int32 nNewStart = -1;
1931 sal_Int32 nNewEnd = -1;
1932 CopySourceStream( nStartOffset, nEndOffset, nNewStart, nNewEnd );
1934 // store position of copied sheet in output
1935 pSheetData->AddSavePos( nTable, nNewStart, nNewEnd );
1937 // skip iterator entries for this sheet
1938 mpCellsItr->SkipTable(static_cast<SCTAB>(nTable));
1940 else
1942 uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
1943 WriteTable(nTable, xTable);
1945 IncrementProgressBar(false);
1948 WriteExternalRefCaches();
1949 WriteNamedExpressions();
1950 WriteDataStream();
1951 aExportDatabaseRanges.WriteDatabaseRanges();
1952 WriteExternalDataMapping();
1953 ScXMLExportDataPilot aExportDataPilot(*this);
1954 aExportDataPilot.WriteDataPilots();
1955 WriteConsolidation();
1956 ScXMLExportDDELinks aExportDDELinks(*this);
1957 aExportDDELinks.WriteDDELinks(xSpreadDoc);
1958 IncrementProgressBar(true, 0);
1959 GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference());
1962 void ScXMLExport::ExportStyles_( bool bUsed )
1964 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
1965 if (xSpreadDoc.is())
1966 RegisterDefinedStyleNames( xSpreadDoc);
1968 if (!pSharedData)
1970 SCTAB nTableCount(0);
1971 sal_Int32 nShapesCount(0);
1972 CollectSharedData(nTableCount, nShapesCount);
1974 rtl::Reference<XMLCellStyleExport> aStylesExp(new XMLCellStyleExport(*this, GetAutoStylePool().get()));
1975 if (GetModel().is())
1977 uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetModel(), uno::UNO_QUERY);
1978 if (xMultiServiceFactory.is())
1980 uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance("com.sun.star.sheet.Defaults"), uno::UNO_QUERY);
1981 if (xProperties.is())
1982 aStylesExp->exportDefaultStyle(xProperties, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, xCellStylesExportPropertySetMapper);
1983 if (pSharedData->HasShapes())
1985 GetShapeExport()->ExportGraphicDefaults();
1988 collectDataStyles(false);
1990 exportDataStyles();
1992 aStylesExp->exportStyleFamily(OUString("CellStyles"),
1993 OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME), xCellStylesExportPropertySetMapper, false, XmlStyleFamily::TABLE_CELL);
1995 SvXMLExport::ExportStyles_(bUsed);
1998 void ScXMLExport::AddStyleFromCells(const uno::Reference<beans::XPropertySet>& xProperties,
1999 const uno::Reference<sheet::XSpreadsheet>& xTable,
2000 sal_Int32 nTable, const OUString* pOldName)
2002 css::uno::Any aAny = xProperties->getPropertyValue("FormatID");
2003 sal_uInt64 nKey = 0;
2004 aAny >>= nKey;
2006 //! pass xCellRanges instead
2007 uno::Reference<sheet::XSheetCellRanges> xCellRanges( xProperties, uno::UNO_QUERY );
2009 OUString sStyleName;
2010 sal_Int32 nNumberFormat(-1);
2011 sal_Int32 nValidationIndex(-1);
2012 std::vector<XMLPropertyState> aPropStates(xCellStylesExportPropertySetMapper->Filter(*this, xProperties));
2013 std::vector< XMLPropertyState >::iterator aItr(aPropStates.begin());
2014 std::vector< XMLPropertyState >::iterator aEndItr(aPropStates.end());
2015 sal_Int32 nCount(0);
2016 while (aItr != aEndItr)
2018 if (aItr->mnIndex != -1)
2020 switch (xCellStylesPropertySetMapper->GetEntryContextId(aItr->mnIndex))
2022 case CTF_SC_VALIDATION :
2024 pValidationsContainer->AddValidation(aItr->maValue, nValidationIndex);
2025 // this is not very slow, because it is most the last property or
2026 // if it is not the last property it is the property before the last property,
2027 // so in the worst case only one property has to be copied, but in the best case no
2028 // property has to be copied
2029 aItr = aPropStates.erase(aItr);
2030 aEndItr = aPropStates.end(); // old aEndItr is invalidated!
2032 break;
2033 case CTF_SC_CELLSTYLE :
2035 aItr->maValue >>= sStyleName;
2036 aItr->mnIndex = -1;
2037 ++aItr;
2038 ++nCount;
2040 break;
2041 case CTF_SC_NUMBERFORMAT :
2043 if (aItr->maValue >>= nNumberFormat)
2044 addDataStyle(nNumberFormat);
2045 ++aItr;
2046 ++nCount;
2048 break;
2049 default:
2051 ++aItr;
2052 ++nCount;
2054 break;
2057 else
2059 ++aItr;
2060 ++nCount;
2063 if (nCount == 1) // this is the CellStyle and should be removed if alone
2064 aPropStates.clear();
2065 if (nNumberFormat == -1)
2066 xProperties->getPropertyValue(SC_UNONAME_NUMFMT) >>= nNumberFormat;
2067 if (sStyleName.isEmpty())
2068 return;
2070 if (!aPropStates.empty())
2072 sal_Int32 nIndex;
2073 if (pOldName)
2075 if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates)))
2077 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_CELL, *pOldName);
2078 // add to pCellStyles, so the name is found for normal sheets
2079 pCellStyles->AddStyleName(*pOldName, nIndex);
2082 else
2084 OUString sName;
2085 bool bAdded = false;
2086 if (nKey)
2088 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
2089 ScFormatSaveData* pFormatData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetFormatSaveData();
2090 auto itr = pFormatData->maIDToName.find(nKey);
2091 if (itr != pFormatData->maIDToName.end())
2093 sName = itr->second;
2094 bAdded = GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TABLE_CELL, sStyleName, aPropStates);
2095 if (bAdded)
2096 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_CELL, sName);
2099 bool bIsAutoStyle(true);
2100 if (bAdded || GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates)))
2102 pCellStyles->AddStyleName(sName, nIndex);
2104 else
2105 nIndex = pCellStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX, bIsAutoStyle);
2107 const uno::Sequence<table::CellRangeAddress> aAddresses(xCellRanges->getRangeAddresses());
2108 bool bGetMerge(true);
2109 for (table::CellRangeAddress const & address : aAddresses)
2111 pSharedData->SetLastColumn(nTable, address.EndColumn);
2112 pSharedData->SetLastRow(nTable, address.EndRow);
2113 pCellStyles->AddRangeStyleName(address, nIndex, bIsAutoStyle, nValidationIndex, nNumberFormat);
2114 if (bGetMerge)
2115 bGetMerge = GetMerged(&address, xTable);
2119 else
2121 OUString sEncodedStyleName(EncodeStyleName(sStyleName));
2122 sal_Int32 nIndex(0);
2123 pCellStyles->AddStyleName(sEncodedStyleName, nIndex, false);
2124 if ( !pOldName )
2126 const uno::Sequence<table::CellRangeAddress> aAddresses(xCellRanges->getRangeAddresses());
2127 bool bGetMerge(true);
2128 for (table::CellRangeAddress const & address : aAddresses)
2130 if (bGetMerge)
2131 bGetMerge = GetMerged(&address, xTable);
2132 pCellStyles->AddRangeStyleName(address, nIndex, false, nValidationIndex, nNumberFormat);
2133 if( sStyleName != "Default" || nValidationIndex != -1 )
2135 pSharedData->SetLastColumn(nTable, address.EndColumn);
2136 pSharedData->SetLastRow(nTable, address.EndRow);
2143 void ScXMLExport::AddStyleFromColumn(const uno::Reference<beans::XPropertySet>& xColumnProperties,
2144 const OUString* pOldName, sal_Int32& rIndex, bool& rIsVisible)
2146 std::vector<XMLPropertyState> aPropStates(xColumnStylesExportPropertySetMapper->Filter(*this, xColumnProperties));
2147 if(aPropStates.empty())
2148 return;
2150 auto aItr = std::find_if(aPropStates.begin(), aPropStates.end(),
2151 [this](const XMLPropertyState& rPropState) {
2152 return xColumnStylesPropertySetMapper->GetEntryContextId(rPropState.mnIndex) == CTF_SC_ISVISIBLE; });
2153 if (aItr != aPropStates.end())
2155 aItr->maValue >>= rIsVisible;
2158 const OUString sParent;
2159 if (pOldName)
2161 if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_COLUMN, sParent, std::move(aPropStates)))
2163 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_COLUMN, *pOldName);
2164 // add to pColumnStyles, so the name is found for normal sheets
2165 rIndex = pColumnStyles->AddStyleName(*pOldName);
2168 else
2170 OUString sName;
2171 if (GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_COLUMN, sParent, std::move(aPropStates)))
2173 rIndex = pColumnStyles->AddStyleName(sName);
2175 else
2176 rIndex = pColumnStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX);
2180 void ScXMLExport::AddStyleFromRow(const uno::Reference<beans::XPropertySet>& xRowProperties,
2181 const OUString* pOldName, sal_Int32& rIndex)
2183 std::vector<XMLPropertyState> aPropStates(xRowStylesExportPropertySetMapper->Filter(*this, xRowProperties));
2184 if(aPropStates.empty())
2185 return;
2187 const OUString sParent;
2188 if (pOldName)
2190 if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_ROW, sParent, std::move(aPropStates)))
2192 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_ROW, *pOldName);
2193 // add to pRowStyles, so the name is found for normal sheets
2194 rIndex = pRowStyles->AddStyleName(*pOldName);
2197 else
2199 OUString sName;
2200 if (GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_ROW, sParent, std::move(aPropStates)))
2202 rIndex = pRowStyles->AddStyleName(sName);
2204 else
2205 rIndex = pRowStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX);
2209 static uno::Any lcl_GetEnumerated( uno::Reference<container::XEnumerationAccess> const & xEnumAccess, sal_Int32 nIndex )
2211 uno::Any aRet;
2212 uno::Reference<container::XEnumeration> xEnum( xEnumAccess->createEnumeration() );
2215 sal_Int32 nSkip = nIndex;
2216 while ( nSkip > 0 )
2218 (void) xEnum->nextElement();
2219 --nSkip;
2221 aRet = xEnum->nextElement();
2223 catch (container::NoSuchElementException&)
2225 // leave aRet empty
2227 return aRet;
2230 void ScXMLExport::collectAutoStyles()
2232 SvXMLExport::collectAutoStyles();
2234 if (mbAutoStylesCollected)
2235 return;
2237 if (!GetModel().is())
2238 return;
2240 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
2241 if (!xSpreadDoc.is())
2242 return;
2244 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
2245 if (!xIndex.is())
2246 return;
2248 if (getExportFlags() & SvXMLExportFlags::CONTENT)
2250 // Reserve the loaded cell style names.
2251 RegisterDefinedStyleNames( xSpreadDoc);
2253 // re-create automatic styles with old names from stored data
2254 ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetSheetSaveData();
2255 if (pSheetData && pDoc)
2257 // formulas have to be calculated now, to detect changed results
2258 // (during normal save, they will be calculated anyway)
2259 SCTAB nTabCount = pDoc->GetTableCount();
2260 for (SCTAB nTab=0; nTab<nTabCount; ++nTab)
2261 if (pDoc->IsStreamValid(nTab))
2262 pDoc->InterpretDirtyCells(ScRange(0, 0, nTab, pDoc->MaxCol(), pDoc->MaxRow(), nTab));
2264 // stored cell styles
2265 const std::vector<ScCellStyleEntry>& rCellEntries = pSheetData->GetCellStyles();
2266 for (const auto& rCellEntry : rCellEntries)
2268 ScAddress aPos = rCellEntry.maCellPos;
2269 sal_Int32 nTable = aPos.Tab();
2270 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2271 if (bCopySheet)
2273 uno::Reference <sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2274 uno::Reference <beans::XPropertySet> xProperties(
2275 xTable->getCellByPosition( aPos.Col(), aPos.Row() ), uno::UNO_QUERY );
2277 AddStyleFromCells(xProperties, xTable, nTable, &rCellEntry.maName);
2281 // stored column styles
2282 const std::vector<ScCellStyleEntry>& rColumnEntries = pSheetData->GetColumnStyles();
2283 for (const auto& rColumnEntry : rColumnEntries)
2285 ScAddress aPos = rColumnEntry.maCellPos;
2286 sal_Int32 nTable = aPos.Tab();
2287 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2288 if (bCopySheet)
2290 uno::Reference<table::XColumnRowRange> xColumnRowRange(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2291 uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns());
2292 uno::Reference<beans::XPropertySet> xColumnProperties(xTableColumns->getByIndex( aPos.Col() ), uno::UNO_QUERY);
2294 sal_Int32 nIndex(-1);
2295 bool bIsVisible(true);
2296 AddStyleFromColumn( xColumnProperties, &rColumnEntry.maName, nIndex, bIsVisible );
2300 // stored row styles
2301 const std::vector<ScCellStyleEntry>& rRowEntries = pSheetData->GetRowStyles();
2302 for (const auto& rRowEntry : rRowEntries)
2304 ScAddress aPos = rRowEntry.maCellPos;
2305 sal_Int32 nTable = aPos.Tab();
2306 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2307 if (bCopySheet)
2309 uno::Reference<table::XColumnRowRange> xColumnRowRange(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2310 uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows());
2311 uno::Reference<beans::XPropertySet> xRowProperties(xTableRows->getByIndex( aPos.Row() ), uno::UNO_QUERY);
2313 sal_Int32 nIndex(-1);
2314 AddStyleFromRow( xRowProperties, &rRowEntry.maName, nIndex );
2318 // stored table styles
2319 const std::vector<ScCellStyleEntry>& rTableEntries = pSheetData->GetTableStyles();
2320 for (const auto& rTableEntry : rTableEntries)
2322 ScAddress aPos = rTableEntry.maCellPos;
2323 sal_Int32 nTable = aPos.Tab();
2324 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2325 if (bCopySheet)
2327 //! separate method AddStyleFromTable needed?
2328 uno::Reference<beans::XPropertySet> xTableProperties(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2329 if (xTableProperties.is())
2331 std::vector<XMLPropertyState> aPropStates(xTableStylesExportPropertySetMapper->Filter(*this, xTableProperties));
2332 OUString sName( rTableEntry.maName );
2333 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TABLE_TABLE, OUString(), std::move(aPropStates));
2334 GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_TABLE, sName);
2339 // stored styles for notes
2341 rtl::Reference<SvXMLExportPropertyMapper> xShapeMapper = XMLShapeExport::CreateShapePropMapper( *this );
2342 GetShapeExport(); // make sure the graphics styles family is added
2344 const std::vector<ScNoteStyleEntry>& rNoteEntries = pSheetData->GetNoteStyles();
2345 for (const auto& rNoteEntry : rNoteEntries)
2347 ScAddress aPos = rNoteEntry.maCellPos;
2348 SCTAB nTable = aPos.Tab();
2349 bool bCopySheet = pDoc->IsStreamValid( nTable );
2350 if (bCopySheet)
2352 //! separate method AddStyleFromNote needed?
2354 ScPostIt* pNote = pDoc->GetNote(aPos);
2355 OSL_ENSURE( pNote, "note not found" );
2356 if (pNote)
2358 SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
2359 // all uno shapes are created anyway in CollectSharedData
2360 uno::Reference<beans::XPropertySet> xShapeProperties( pDrawObj->getUnoShape(), uno::UNO_QUERY );
2361 if (xShapeProperties.is())
2363 if ( !rNoteEntry.maStyleName.isEmpty() )
2365 std::vector<XMLPropertyState> aPropStates(xShapeMapper->Filter(*this, xShapeProperties));
2366 OUString sName( rNoteEntry.maStyleName );
2367 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::SD_GRAPHICS_ID, OUString(), std::move(aPropStates));
2368 GetAutoStylePool()->RegisterName(XmlStyleFamily::SD_GRAPHICS_ID, sName);
2370 if ( !rNoteEntry.maTextStyle.isEmpty() )
2372 std::vector<XMLPropertyState> aPropStates(
2373 GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(*this, xShapeProperties));
2374 OUString sName( rNoteEntry.maTextStyle );
2375 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_PARAGRAPH, OUString(), std::move(aPropStates));
2376 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_PARAGRAPH, sName);
2383 // note paragraph styles
2385 rtl::Reference<SvXMLExportPropertyMapper> xParaPropMapper = GetTextParagraphExport()->GetParagraphPropertyMapper();
2387 const std::vector<ScTextStyleEntry>& rNoteParaEntries = pSheetData->GetNoteParaStyles();
2388 for (const auto& rNoteParaEntry : rNoteParaEntries)
2390 ScAddress aPos = rNoteParaEntry.maCellPos;
2391 SCTAB nTable = aPos.Tab();
2392 bool bCopySheet = pDoc->IsStreamValid( nTable );
2393 if (bCopySheet)
2395 ScPostIt* pNote = pDoc->GetNote( aPos );
2396 OSL_ENSURE( pNote, "note not found" );
2397 if (pNote)
2399 SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
2400 uno::Reference<container::XEnumerationAccess> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY);
2401 uno::Reference<beans::XPropertySet> xParaProp(
2402 lcl_GetEnumerated( xCellText, rNoteParaEntry.maSelection.nStartPara ), uno::UNO_QUERY );
2403 if ( xParaProp.is() )
2405 std::vector<XMLPropertyState> aPropStates(xParaPropMapper->Filter(*this, xParaProp));
2406 OUString sName( rNoteParaEntry.maName );
2407 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_PARAGRAPH, OUString(), std::move(aPropStates));
2408 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_PARAGRAPH, sName);
2414 // note text styles
2416 rtl::Reference<SvXMLExportPropertyMapper> xTextPropMapper = XMLTextParagraphExport::CreateCharExtPropMapper( *this );
2418 const std::vector<ScTextStyleEntry>& rNoteTextEntries = pSheetData->GetNoteTextStyles();
2419 for (const auto& rNoteTextEntry : rNoteTextEntries)
2421 ScAddress aPos = rNoteTextEntry.maCellPos;
2422 SCTAB nTable = aPos.Tab();
2423 bool bCopySheet = pDoc->IsStreamValid( nTable );
2424 if (bCopySheet)
2426 ScPostIt* pNote = pDoc->GetNote( aPos );
2427 OSL_ENSURE( pNote, "note not found" );
2428 if (pNote)
2430 SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos );
2431 uno::Reference<text::XSimpleText> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY);
2432 uno::Reference<beans::XPropertySet> xCursorProp(xCellText->createTextCursor(), uno::UNO_QUERY);
2433 ScDrawTextCursor* pCursor = comphelper::getFromUnoTunnel<ScDrawTextCursor>( xCursorProp );
2434 if (pCursor)
2436 pCursor->SetSelection( rNoteTextEntry.maSelection );
2438 std::vector<XMLPropertyState> aPropStates(xTextPropMapper->Filter(*this, xCursorProp));
2439 OUString sName( rNoteTextEntry.maName );
2440 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates));
2441 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_TEXT, sName);
2447 // stored text styles
2449 // Calling createTextCursor fires up editeng, which is very slow, and often subsequent style entries
2450 // refer to the same cell, so cache it.
2451 ScAddress aPrevPos;
2452 uno::Reference<beans::XPropertySet> xPrevCursorProp;
2453 const std::vector<ScTextStyleEntry>& rTextEntries = pSheetData->GetTextStyles();
2454 for (const auto& rTextEntry : rTextEntries)
2456 ScAddress aPos = rTextEntry.maCellPos;
2457 sal_Int32 nTable = aPos.Tab();
2458 bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) );
2459 if (!bCopySheet)
2460 continue;
2462 //! separate method AddStyleFromText needed?
2463 //! cache sheet object
2465 uno::Reference<beans::XPropertySet> xCursorProp;
2466 if (xPrevCursorProp && aPrevPos == aPos)
2467 xCursorProp = xPrevCursorProp;
2468 else
2470 uno::Reference<table::XCellRange> xCellRange(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2471 uno::Reference<text::XSimpleText> xCellText(xCellRange->getCellByPosition(aPos.Col(), aPos.Row()), uno::UNO_QUERY);
2472 xCursorProp.set(xCellText->createTextCursor(), uno::UNO_QUERY);
2474 ScCellTextCursor* pCursor = comphelper::getFromUnoTunnel<ScCellTextCursor>( xCursorProp );
2475 if (!pCursor)
2476 continue;
2477 pCursor->SetSelection( rTextEntry.maSelection );
2479 std::vector<XMLPropertyState> aPropStates(xTextPropMapper->Filter(*this, xCursorProp));
2480 OUString sName( rTextEntry.maName );
2481 GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates));
2482 GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_TEXT, sName);
2483 xPrevCursorProp = xCursorProp;
2484 aPrevPos = aPos;
2488 ExportExternalRefCacheStyles();
2490 if (!pSharedData)
2492 SCTAB nTableCount(0);
2493 sal_Int32 nShapesCount(0);
2494 CollectSharedData(nTableCount, nShapesCount);
2496 sal_Int32 nTableCount(xIndex->getCount());
2497 pCellStyles->AddNewTable(nTableCount - 1);
2498 CollectShapesAutoStyles(nTableCount);
2499 for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable, IncrementProgressBar(false))
2501 uno::Reference <sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
2502 if (!xTable.is())
2503 continue;
2505 // table styles array must be complete, including copied tables - Add should find the stored style
2506 uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
2507 if (xTableProperties.is())
2509 std::vector<XMLPropertyState> aPropStates(xTableStylesExportPropertySetMapper->Filter(*this, xTableProperties));
2510 if(!aPropStates.empty())
2512 OUString sName;
2513 GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_TABLE, OUString(), std::move(aPropStates));
2514 aTableStyles.push_back(sName);
2518 // collect other auto-styles only for non-copied sheets
2519 uno::Reference<sheet::XUniqueCellFormatRangesSupplier> xCellFormatRanges ( xTable, uno::UNO_QUERY );
2520 if ( xCellFormatRanges.is() )
2522 uno::Reference<container::XIndexAccess> xFormatRangesIndex(xCellFormatRanges->getUniqueCellFormatRanges());
2523 if (xFormatRangesIndex.is())
2525 sal_Int32 nFormatRangesCount(xFormatRangesIndex->getCount());
2526 GetProgressBarHelper()->ChangeReference(GetProgressBarHelper()->GetReference() + nFormatRangesCount);
2527 for (sal_Int32 nFormatRange = 0; nFormatRange < nFormatRangesCount; ++nFormatRange)
2529 uno::Reference< sheet::XSheetCellRanges> xCellRanges(xFormatRangesIndex->getByIndex(nFormatRange), uno::UNO_QUERY);
2530 if (xCellRanges.is())
2532 uno::Reference <beans::XPropertySet> xProperties (xCellRanges, uno::UNO_QUERY);
2533 if (xProperties.is())
2535 AddStyleFromCells(xProperties, xTable, nTable, nullptr);
2536 IncrementProgressBar(false);
2542 uno::Reference<table::XColumnRowRange> xColumnRowRange (xTable, uno::UNO_QUERY);
2543 if (xColumnRowRange.is() && pDoc)
2545 pDoc->SyncColRowFlags();
2546 uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns());
2547 if (xTableColumns.is())
2549 sal_Int32 nColumns(pDoc->GetLastChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable)));
2550 pSharedData->SetLastColumn(nTable, nColumns);
2551 table::CellRangeAddress aCellAddress(GetEndAddress(xTable));
2552 if (aCellAddress.EndColumn > nColumns)
2554 ++nColumns;
2555 pColumnStyles->AddNewTable(nTable, aCellAddress.EndColumn);
2557 else
2558 pColumnStyles->AddNewTable(nTable, nColumns);
2559 sal_Int32 nColumn = 0;
2560 while (nColumn <= pDoc->MaxCol())
2562 sal_Int32 nIndex(-1);
2563 bool bIsVisible(true);
2564 uno::Reference <beans::XPropertySet> xColumnProperties(xTableColumns->getByIndex(nColumn), uno::UNO_QUERY);
2565 if (xColumnProperties.is())
2567 AddStyleFromColumn( xColumnProperties, nullptr, nIndex, bIsVisible );
2568 pColumnStyles->AddFieldStyleName(nTable, nColumn, nIndex, bIsVisible);
2570 sal_Int32 nOld(nColumn);
2571 nColumn = pDoc->GetNextDifferentChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCCOL>(nColumn));
2572 for (sal_Int32 i = nOld + 1; i < nColumn; ++i)
2573 pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible);
2575 if (aCellAddress.EndColumn > nColumns)
2577 bool bIsVisible(true);
2578 sal_Int32 nIndex(pColumnStyles->GetStyleNameIndex(nTable, nColumns, bIsVisible));
2579 for (sal_Int32 i = nColumns + 1; i <= aCellAddress.EndColumn; ++i)
2580 pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible);
2583 uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows());
2584 if (xTableRows.is())
2586 sal_Int32 nRows(pDoc->GetLastChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable)));
2587 pSharedData->SetLastRow(nTable, nRows);
2589 pRowStyles->AddNewTable(nTable, pDoc->MaxRow());
2590 sal_Int32 nRow = 0;
2591 while (nRow <= pDoc->MaxRow())
2593 sal_Int32 nIndex = 0;
2594 uno::Reference <beans::XPropertySet> xRowProperties(xTableRows->getByIndex(nRow), uno::UNO_QUERY);
2595 if(xRowProperties.is())
2597 AddStyleFromRow( xRowProperties, nullptr, nIndex );
2598 pRowStyles->AddFieldStyleName(nTable, nRow, nIndex);
2600 sal_Int32 nOld(nRow);
2601 nRow = pDoc->GetNextDifferentChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCROW>(nRow));
2602 if (nRow > nOld + 1)
2603 pRowStyles->AddFieldStyleName(nTable, nOld + 1, nIndex, nRow - 1);
2607 ExportCellTextAutoStyles(nTable);
2610 pChangeTrackingExportHelper->CollectAutoStyles();
2613 if (getExportFlags() & SvXMLExportFlags::MASTERSTYLES)
2614 GetPageExport()->collectAutoStyles(true);
2616 mbAutoStylesCollected = true;
2619 void ScXMLExport::ExportAutoStyles_()
2621 if (!GetModel().is())
2622 return;
2624 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
2625 if (!xSpreadDoc.is())
2626 return;
2628 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
2629 if (!xIndex.is())
2630 return;
2632 collectAutoStyles();
2634 if (getExportFlags() & SvXMLExportFlags::CONTENT)
2636 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_COLUMN);
2637 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_ROW);
2638 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_TABLE);
2639 exportAutoDataStyles();
2640 GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_CELL);
2642 GetShapeExport()->exportAutoStyles();
2643 GetFormExport()->exportAutoStyles( );
2645 if (pDoc)
2647 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
2648 // #i100879# write the table style for cached tables only if there are cached tables
2649 // (same logic as in ExportExternalRefCacheStyles)
2650 if (pRefMgr->hasExternalData())
2652 // Special table style for the external ref cache tables.
2653 AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sExternalRefTabStyleName);
2654 AddAttribute(XML_NAMESPACE_STYLE, XML_FAMILY, XML_TABLE);
2655 SvXMLElementExport aElemStyle(*this, XML_NAMESPACE_STYLE, XML_STYLE, true, true);
2656 AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, XML_FALSE);
2657 SvXMLElementExport aElemStyleTabProps(*this, XML_NAMESPACE_STYLE, XML_TABLE_PROPERTIES, true, true);
2662 if (getExportFlags() & SvXMLExportFlags::MASTERSTYLES)
2664 exportAutoDataStyles();
2665 GetPageExport()->exportAutoStyles();
2668 // #i30251#; only write Text Styles once
2670 if ((getExportFlags() & SvXMLExportFlags::CONTENT) || (getExportFlags() & SvXMLExportFlags::MASTERSTYLES))
2671 GetTextParagraphExport()->exportTextAutoStyles();
2674 void ScXMLExport::ExportMasterStyles_()
2676 GetPageExport()->exportMasterStyles( true );
2679 void ScXMLExport::CollectInternalShape( uno::Reference< drawing::XShape > const & xShape )
2681 // detective objects and notes
2682 SdrObject* pObject = SdrObject::getSdrObjectFromXShape( xShape );
2683 if( !pObject )
2684 return;
2686 // collect note caption objects from all layers (internal or hidden)
2687 if( ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObject, static_cast< SCTAB >( nCurrentTable ) ) )
2689 if(pDoc->GetNote(pCaptData->maStart))
2691 pSharedData->AddNoteObj( xShape, pCaptData->maStart );
2693 // #i60851# When the file is saved while editing a new note,
2694 // the cell is still empty -> last column/row must be updated
2695 OSL_ENSURE( pCaptData->maStart.Tab() == nCurrentTable, "invalid table in object data" );
2696 pSharedData->SetLastColumn( nCurrentTable, pCaptData->maStart.Col() );
2697 pSharedData->SetLastRow( nCurrentTable, pCaptData->maStart.Row() );
2700 // other objects from internal layer only (detective)
2701 else if( pObject->GetLayer() == SC_LAYER_INTERN )
2703 ScDetectiveFunc aDetFunc( *pDoc, static_cast<SCTAB>(nCurrentTable) );
2704 ScAddress aPosition;
2705 ScRange aSourceRange;
2706 bool bRedLine;
2707 ScDetectiveObjType eObjType = aDetFunc.GetDetectiveObjectType(
2708 pObject, nCurrentTable, aPosition, aSourceRange, bRedLine );
2709 pSharedData->GetDetectiveObjContainer()->AddObject( eObjType, static_cast<SCTAB>(nCurrentTable), aPosition, aSourceRange, bRedLine );
2713 bool ScXMLExport::GetMerged (const table::CellRangeAddress* pCellAddress,
2714 const uno::Reference <sheet::XSpreadsheet>& xTable)
2716 bool bReady(false);
2717 sal_Int32 nRow(pCellAddress->StartRow);
2718 sal_Int32 nCol(pCellAddress->StartColumn);
2719 sal_Int32 nEndRow(pCellAddress->EndRow);
2720 sal_Int32 nEndCol(pCellAddress->EndColumn);
2721 bool bRowInc(nEndRow > nRow);
2722 while(!bReady && nRow <= nEndRow && nCol <= nEndCol)
2724 uno::Reference<sheet::XSheetCellRange> xSheetCellRange(xTable->getCellRangeByPosition(nCol, nRow, nCol, nRow), uno::UNO_QUERY);
2725 if (xSheetCellRange.is())
2727 uno::Reference<sheet::XSheetCellCursor> xCursor(xTable->createCursorByRange(xSheetCellRange));
2728 if(xCursor.is())
2730 uno::Reference<sheet::XCellRangeAddressable> xCellAddress (xCursor, uno::UNO_QUERY);
2731 xCursor->collapseToMergedArea();
2732 table::CellRangeAddress aCellAddress2(xCellAddress->getRangeAddress());
2733 ScRange aScRange( aCellAddress2.StartColumn, aCellAddress2.StartRow, aCellAddress2.Sheet,
2734 aCellAddress2.EndColumn, aCellAddress2.EndRow, aCellAddress2.Sheet );
2736 if ((aScRange.aEnd.Row() > nRow ||
2737 aScRange.aEnd.Col() > nCol) &&
2738 aScRange.aStart.Row() == nRow &&
2739 aScRange.aStart.Col() == nCol)
2741 pMergedRangesContainer->AddRange(aScRange);
2742 pSharedData->SetLastColumn(aScRange.aEnd.Tab(), aScRange.aEnd.Col());
2743 pSharedData->SetLastRow(aScRange.aEnd.Tab(), aScRange.aEnd.Row());
2745 else
2746 bReady = true;
2749 if (!bReady)
2751 if (bRowInc)
2752 ++nRow;
2753 else
2754 ++nCol;
2757 OSL_ENSURE(!(!bReady && nEndRow > nRow && nEndCol > nCol), "should not be possible");
2758 return !bReady;
2761 bool ScXMLExport::IsMatrix (const ScAddress& aCell,
2762 ScRange& aCellAddress, bool& bIsFirst) const
2764 bIsFirst = false;
2766 ScRange aMatrixRange;
2768 if (pDoc && pDoc->GetMatrixFormulaRange(aCell, aMatrixRange))
2770 aCellAddress = aMatrixRange;
2771 if ((aCellAddress.aStart.Col() == aCell.Col() && aCellAddress.aStart.Row() == aCell.Row()) &&
2772 (aCellAddress.aEnd.Col() > aCell.Col() || aCellAddress.aEnd.Row() > aCell.Row()))
2774 bIsFirst = true;
2775 return true;
2777 else if (aCellAddress.aStart.Col() != aCell.Col() || aCellAddress.aStart.Row() != aCell.Row() ||
2778 aCellAddress.aEnd.Col() != aCell.Col() || aCellAddress.aEnd.Row()!= aCell.Row())
2779 return true;
2780 else
2782 bIsFirst = true;
2783 return true;
2787 return false;
2790 void ScXMLExport::WriteTable(sal_Int32 nTable, const uno::Reference<sheet::XSpreadsheet>& xTable)
2792 if (!xTable.is())
2793 return;
2795 xCurrentTable.set(xTable);
2796 uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY );
2797 if (!xName.is())
2798 return;
2800 nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable );
2801 OUString sOUTableName(xName->getName());
2802 AddAttribute(sAttrName, sOUTableName);
2803 AddAttribute(sAttrStyleName, aTableStyles[nTable]);
2805 uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY);
2806 const ScTableProtection* pProtect = nullptr;
2807 if (xProtectable.is() && xProtectable->isProtected())
2809 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
2810 if (pDoc)
2812 pProtect = pDoc->GetTabProtection(nTable);
2813 if (pProtect)
2815 OUStringBuffer aBuffer;
2816 ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED;
2817 if (pProtect->hasPasswordHash(PASSHASH_SHA1))
2819 ::comphelper::Base64::encode(aBuffer,
2820 pProtect->getPasswordHash(PASSHASH_SHA1));
2821 eHashUsed = PASSHASH_SHA1;
2823 else if (pProtect->hasPasswordHash(PASSHASH_SHA256))
2825 ::comphelper::Base64::encode(aBuffer,
2826 pProtect->getPasswordHash(PASSHASH_SHA256));
2827 eHashUsed = PASSHASH_SHA256;
2829 else if (pProtect->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
2831 // Double-hash this by SHA1 on top of the legacy xls hash.
2832 uno::Sequence<sal_Int8> aHash = pProtect->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
2833 ::comphelper::Base64::encode(aBuffer, aHash);
2834 eHashUsed = PASSHASH_XL;
2836 if (!aBuffer.isEmpty())
2838 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
2839 if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
2841 if (eHashUsed == PASSHASH_XL)
2843 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
2844 ScPassHashHelper::getHashURI(PASSHASH_XL));
2845 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2846 AddAttribute(XML_NAMESPACE_LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2,
2847 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
2849 else if (eHashUsed == PASSHASH_SHA1)
2851 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
2852 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
2854 else if (eHashUsed == PASSHASH_SHA256)
2856 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM,
2857 ScPassHashHelper::getHashURI(PASSHASH_SHA256));
2864 OUString sPrintRanges;
2865 ScRange aColumnHeaderRange;
2866 bool bHasColumnHeader;
2867 GetColumnRowHeader(bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges);
2868 if( !sPrintRanges.isEmpty() )
2869 AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges );
2870 else if (pDoc && !pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable)))
2871 AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE);
2872 SvXMLElementExport aElemT(*this, sElemTab, true, true);
2874 if (pProtect && pProtect->isProtected() && getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2876 if (pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS))
2877 AddAttribute(XML_NAMESPACE_LO_EXT, XML_SELECT_PROTECTED_CELLS, XML_TRUE);
2878 if (pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS))
2879 AddAttribute(XML_NAMESPACE_LO_EXT, XML_SELECT_UNPROTECTED_CELLS, XML_TRUE);
2881 if (pProtect->isOptionEnabled(ScTableProtection::INSERT_COLUMNS))
2882 AddAttribute(XML_NAMESPACE_LO_EXT, XML_INSERT_COLUMNS, XML_TRUE);
2883 if (pProtect->isOptionEnabled(ScTableProtection::INSERT_ROWS))
2884 AddAttribute(XML_NAMESPACE_LO_EXT, XML_INSERT_ROWS, XML_TRUE);
2886 if (pProtect->isOptionEnabled(ScTableProtection::DELETE_COLUMNS))
2887 AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_COLUMNS, XML_TRUE);
2888 if (pProtect->isOptionEnabled(ScTableProtection::DELETE_ROWS))
2889 AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_ROWS, XML_TRUE);
2891 OUString aElemName = GetNamespaceMap().GetQNameByKey(
2892 XML_NAMESPACE_LO_EXT, GetXMLToken(XML_TABLE_PROTECTION));
2894 SvXMLElementExport aElemProtected(*this, aElemName, true, true);
2897 CheckAttrList();
2899 if ( pDoc && pDoc->GetSheetEvents( static_cast<SCTAB>(nTable) ) &&
2900 getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
2902 // store sheet events
2903 uno::Reference<document::XEventsSupplier> xSupplier(xTable, uno::UNO_QUERY);
2904 uno::Reference<container::XNameAccess> xEvents = xSupplier->getEvents();
2905 GetEventExport().ExportExt( xEvents );
2908 WriteTableSource();
2909 WriteScenario();
2910 uno::Reference<drawing::XDrawPage> xDrawPage;
2911 if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is())
2913 ::xmloff::OOfficeFormsExport aForms(*this);
2914 GetFormExport()->exportForms( xDrawPage );
2915 bool bRet(GetFormExport()->seekPage( xDrawPage ));
2916 OSL_ENSURE( bRet, "OFormLayerXMLExport::seekPage failed!" );
2918 if (pSharedData->HasDrawPage())
2920 GetShapeExport()->seekShapes(pSharedData->GetDrawPage(nTable));
2921 WriteTableShapes();
2923 table::CellRangeAddress aRange(GetEndAddress(xTable));
2924 pSharedData->SetLastColumn(nTable, aRange.EndColumn);
2925 pSharedData->SetLastRow(nTable, aRange.EndRow);
2926 mpCellsItr->SetCurrentTable(static_cast<SCTAB>(nTable), xCurrentTable);
2927 pGroupColumns->NewTable();
2928 pGroupRows->NewTable();
2929 FillColumnRowGroups();
2930 if (bHasColumnHeader)
2931 pSharedData->SetLastColumn(nTable, aColumnHeaderRange.aEnd.Col());
2932 bRowHeaderOpen = false;
2933 if (bHasRowHeader)
2934 pSharedData->SetLastRow(nTable, aRowHeaderRange.aEnd.Row());
2935 pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable),
2936 pSharedData->GetLastColumn(nTable), pCellStyles.get(), pDoc);
2937 pRowFormatRanges->SetColDefaults(&pDefaults->GetColDefaults());
2938 pCellStyles->SetColDefaults(&pDefaults->GetColDefaults());
2939 ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader);
2940 bool bIsFirst(true);
2941 sal_Int32 nEqualCells(0);
2942 ScMyCell aCell;
2943 ScMyCell aPrevCell;
2944 while (mpCellsItr->GetNext(aCell, pCellStyles.get()))
2946 if (bIsFirst)
2948 ExportFormatRanges(0, 0, aCell.maCellAddress.Col()-1, aCell.maCellAddress.Row(), nTable);
2949 aPrevCell = aCell;
2950 bIsFirst = false;
2952 else
2954 if ((aPrevCell.maCellAddress.Row() == aCell.maCellAddress.Row()) &&
2955 (aPrevCell.maCellAddress.Col() + nEqualCells + 1 == aCell.maCellAddress.Col()))
2957 if(IsCellEqual(aPrevCell, aCell))
2958 ++nEqualCells;
2959 else
2961 WriteCell(aPrevCell, nEqualCells);
2962 nEqualCells = 0;
2963 aPrevCell = aCell;
2966 else
2968 WriteCell(aPrevCell, nEqualCells);
2969 ExportFormatRanges(aPrevCell.maCellAddress.Col() + nEqualCells + 1, aPrevCell.maCellAddress.Row(),
2970 aCell.maCellAddress.Col()-1, aCell.maCellAddress.Row(), nTable);
2971 nEqualCells = 0;
2972 aPrevCell = aCell;
2976 if (!bIsFirst)
2978 WriteCell(aPrevCell, nEqualCells);
2979 ExportFormatRanges(aPrevCell.maCellAddress.Col() + nEqualCells + 1, aPrevCell.maCellAddress.Row(),
2980 pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
2982 else
2983 ExportFormatRanges(0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
2985 CloseRow(pSharedData->GetLastRow(nTable));
2987 if (!pDoc)
2988 return;
2990 // Export sheet-local named ranges.
2991 ScRangeName* pRangeName = pDoc->GetRangeName(nTable);
2992 if (pRangeName && !pRangeName->empty())
2994 WriteNamedRange(pRangeName);
2997 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2999 //export new conditional format information
3000 ExportConditionalFormat(nTable);
3001 exportSparklineGroups(nTable);
3005 namespace {
3007 void writeContent(
3008 ScXMLExport& rExport, const OUString& rStyleName, const OUString& rContent, const SvxFieldData* pField )
3010 std::unique_ptr<SvXMLElementExport> pElem;
3011 if (!rStyleName.isEmpty())
3013 // Formatted section with automatic style.
3014 rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, rStyleName);
3015 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3016 XML_NAMESPACE_TEXT, GetXMLToken(XML_SPAN));
3017 pElem.reset(new SvXMLElementExport(rExport, aElemName, false, false));
3020 if (pField)
3022 // Write a field item.
3023 OUString aFieldVal = ScEditUtil::GetCellFieldValue(*pField, rExport.GetDocument(), nullptr);
3024 switch (pField->GetClassId())
3026 case text::textfield::Type::URL:
3028 // <text:a xlink:href="url" xlink:type="simple">value</text:a>
3030 const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
3031 const OUString& aURL = pURLField->GetURL();
3032 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(aURL));
3033 rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, "simple");
3034 const OUString& aTargetFrame = pURLField->GetTargetFrame();
3035 if (!aTargetFrame.isEmpty())
3036 rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, aTargetFrame);
3038 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3039 XML_NAMESPACE_TEXT, GetXMLToken(XML_A));
3040 SvXMLElementExport aElem(rExport, aElemName, false, false);
3041 rExport.Characters(aFieldVal);
3043 break;
3044 case text::textfield::Type::DATE:
3046 // <text:date style:data-style-name="N2" text:date-value="YYYY-MM-DD">value</text:date>
3048 Date aDate(Date::SYSTEM);
3049 OUStringBuffer aBuf;
3050 sal_Int32 nVal = aDate.GetYear();
3051 aBuf.append(nVal);
3052 aBuf.append('-');
3053 nVal = aDate.GetMonth();
3054 if (nVal < 10)
3055 aBuf.append('0');
3056 aBuf.append(nVal);
3057 aBuf.append('-');
3058 nVal = aDate.GetDay();
3059 if (nVal < 10)
3060 aBuf.append('0');
3061 aBuf.append(nVal);
3062 rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, "N2");
3063 rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_DATE_VALUE, aBuf.makeStringAndClear());
3065 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3066 XML_NAMESPACE_TEXT, GetXMLToken(XML_DATE));
3067 SvXMLElementExport aElem(rExport, aElemName, false, false);
3068 rExport.Characters(aFieldVal);
3070 break;
3071 case text::textfield::Type::DOCINFO_TITLE:
3073 // <text:title>value</text:title>
3075 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3076 XML_NAMESPACE_TEXT, GetXMLToken(XML_TITLE));
3077 SvXMLElementExport aElem(rExport, aElemName, false, false);
3078 rExport.Characters(aFieldVal);
3080 break;
3081 case text::textfield::Type::TABLE:
3083 // <text:sheet-name>value</text:sheet-name>
3085 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3086 XML_NAMESPACE_TEXT, GetXMLToken(XML_SHEET_NAME));
3087 SvXMLElementExport aElem(rExport, aElemName, false, false);
3088 rExport.Characters(aFieldVal);
3090 break;
3091 default:
3092 rExport.Characters(aFieldVal);
3095 else
3096 rExport.Characters(rContent);
3099 void flushParagraph(
3100 ScXMLExport& rExport, std::u16string_view rParaText,
3101 rtl::Reference<XMLPropertySetMapper> const & xMapper, rtl::Reference<SvXMLAutoStylePoolP> const & xStylePool,
3102 const ScXMLEditAttributeMap& rAttrMap,
3103 std::vector<editeng::Section>::const_iterator it, std::vector<editeng::Section>::const_iterator const & itEnd )
3105 OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey(
3106 XML_NAMESPACE_TEXT, GetXMLToken(XML_P));
3107 SvXMLElementExport aElemP(rExport, aElemName, false, false);
3109 for (; it != itEnd; ++it)
3111 const editeng::Section& rSec = *it;
3113 OUString aContent(rParaText.substr(rSec.mnStart, rSec.mnEnd - rSec.mnStart));
3115 std::vector<XMLPropertyState> aPropStates;
3116 const SvxFieldData* pField = toXMLPropertyStates(rExport, aPropStates, rSec.maAttributes, xMapper, rAttrMap);
3117 OUString aStyleName = xStylePool->Find(XmlStyleFamily::TEXT_TEXT, OUString(), aPropStates);
3118 if (aContent == "\x001" && !pField)
3120 for (const SfxPoolItem* p : rSec.maAttributes)
3122 if (p->Which() == EE_FEATURE_TAB)
3124 SvXMLElementExport Tab(rExport, XML_NAMESPACE_TEXT, XML_TAB, false, false);
3125 break;
3129 else
3130 writeContent(rExport, aStyleName, aContent, pField);
3136 void ScXMLExport::WriteCell(ScMyCell& aCell, sal_Int32 nEqualCellCount)
3138 // nEqualCellCount is the number of additional cells
3139 SetRepeatAttribute(nEqualCellCount, (aCell.nType != table::CellContentType_EMPTY));
3141 if (aCell.nStyleIndex != -1)
3142 AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(aCell.nStyleIndex, aCell.bIsAutoStyle));
3143 if (aCell.nValidationIndex > -1)
3144 AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(aCell.nValidationIndex));
3145 const bool bIsFirstMatrixCell(aCell.bIsMatrixBase);
3146 if (bIsFirstMatrixCell)
3148 SCCOL nColumns( aCell.aMatrixRange.aEnd.Col() - aCell.aMatrixRange.aStart.Col() + 1 );
3149 SCROW nRows( aCell.aMatrixRange.aEnd.Row() - aCell.aMatrixRange.aStart.Row() + 1 );
3150 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED, OUString::number(nColumns));
3151 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED, OUString::number(nRows));
3153 bool bIsEmpty(false);
3154 switch (aCell.nType)
3156 case table::CellContentType_EMPTY :
3158 bIsEmpty = true;
3160 break;
3161 case table::CellContentType_VALUE :
3163 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3164 aCell.nNumberFormat, aCell.maBaseCell.getDouble());
3165 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3166 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3167 aCell.nNumberFormat, aCell.maBaseCell.getDouble(), false, XML_NAMESPACE_CALC_EXT, false);
3169 break;
3170 case table::CellContentType_TEXT :
3172 OUString sFormattedString(lcl_GetFormattedString(pDoc, aCell.maBaseCell, aCell.maCellAddress));
3173 OUString sCellString = aCell.maBaseCell.getString(pDoc);
3174 bool bExportValue = sCellString.indexOf('\x001') == -1;
3175 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3176 sCellString, sFormattedString, bExportValue);
3177 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3178 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3179 sCellString, sFormattedString, false, XML_NAMESPACE_CALC_EXT);
3181 break;
3182 case table::CellContentType_FORMULA :
3184 if (aCell.maBaseCell.getType() == CELLTYPE_FORMULA)
3186 const bool bIsMatrix(bIsFirstMatrixCell || aCell.bIsMatrixCovered);
3187 ScFormulaCell* pFormulaCell = aCell.maBaseCell.getFormula();
3188 if (!bIsMatrix || bIsFirstMatrixCell)
3190 if (!mpCompileFormulaCxt)
3192 const formula::FormulaGrammar::Grammar eGrammar = pDoc->GetStorageGrammar();
3193 mpCompileFormulaCxt.reset(new sc::CompileFormulaContext(*pDoc, eGrammar));
3196 OUString aFormula = pFormulaCell->GetFormula(*mpCompileFormulaCxt);
3197 sal_uInt16 nNamespacePrefix =
3198 (mpCompileFormulaCxt->getGrammar() == formula::FormulaGrammar::GRAM_ODFF ? XML_NAMESPACE_OF : XML_NAMESPACE_OOOC);
3200 if (!bIsMatrix)
3202 AddAttribute(sAttrFormula, GetNamespaceMap().GetQNameByKey(nNamespacePrefix, aFormula, false));
3204 else
3206 AddAttribute(sAttrFormula, GetNamespaceMap().GetQNameByKey(nNamespacePrefix, aFormula.copy(1, aFormula.getLength()-2), false));
3209 if (pFormulaCell->GetErrCode() != FormulaError::NONE)
3211 AddAttribute(sAttrValueType, XML_STRING);
3212 AddAttribute(sAttrStringValue, aCell.maBaseCell.getString(pDoc));
3213 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3215 //export calcext:value-type="error"
3216 AddAttribute(XML_NAMESPACE_CALC_EXT,XML_VALUE_TYPE, OUString("error"));
3219 else if (pFormulaCell->IsValue())
3221 bool bIsStandard;
3222 OUString sCurrency;
3223 GetNumberFormatAttributesExportHelper()->GetCellType(aCell.nNumberFormat, sCurrency, bIsStandard);
3224 if (pDoc)
3226 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3227 aCell.nNumberFormat, pDoc->GetValue(aCell.maCellAddress));
3228 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3230 GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes(
3231 aCell.nNumberFormat, pDoc->GetValue(aCell.maCellAddress), false, XML_NAMESPACE_CALC_EXT, false );
3235 else
3237 if (!aCell.maBaseCell.getString(pDoc).isEmpty())
3239 AddAttribute(sAttrValueType, XML_STRING);
3240 AddAttribute(sAttrStringValue, aCell.maBaseCell.getString(pDoc));
3241 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
3243 AddAttribute(XML_NAMESPACE_CALC_EXT,XML_VALUE_TYPE, XML_STRING);
3249 break;
3250 default:
3251 break;
3253 OUString* pCellString(&sElemCell);
3254 if (aCell.bIsCovered)
3256 pCellString = &sElemCoveredCell;
3258 else
3260 if (aCell.bIsMergedBase)
3262 SCCOL nColumns( aCell.aMergeRange.aEnd.Col() - aCell.aMergeRange.aStart.Col() + 1 );
3263 SCROW nRows( aCell.aMergeRange.aEnd.Row() - aCell.aMergeRange.aStart.Row() + 1 );
3264 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, OUString::number(nColumns));
3265 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, OUString::number(nRows));
3268 SvXMLElementExport aElemC(*this, *pCellString, true, true);
3269 CheckAttrList();
3270 WriteAreaLink(aCell);
3271 WriteAnnotation(aCell);
3272 WriteDetective(aCell);
3274 if (!bIsEmpty)
3276 if (aCell.maBaseCell.getType() == CELLTYPE_EDIT)
3278 WriteEditCell(aCell.maBaseCell.getEditText());
3280 else if (aCell.maBaseCell.getType() == CELLTYPE_FORMULA && aCell.maBaseCell.getFormula()->IsMultilineResult())
3282 WriteMultiLineFormulaResult(aCell.maBaseCell.getFormula());
3284 else
3286 SvXMLElementExport aElemP(*this, sElemP, true, false);
3288 OUString aParaStr =
3289 ScCellFormat::GetOutputString(*pDoc, aCell.maCellAddress, aCell.maBaseCell);
3291 bool bPrevCharWasSpace = true;
3292 GetTextParagraphExport()->exportCharacterData(aParaStr, bPrevCharWasSpace);
3295 WriteShapes(aCell);
3296 if (!bIsEmpty)
3297 IncrementProgressBar(false);
3300 void ScXMLExport::WriteEditCell(const EditTextObject* pText)
3302 rtl::Reference<XMLPropertySetMapper> xMapper = GetTextParagraphExport()->GetTextPropMapper()->getPropertySetMapper();
3303 rtl::Reference<SvXMLAutoStylePoolP> xStylePool = GetAutoStylePool();
3304 const ScXMLEditAttributeMap& rAttrMap = GetEditAttributeMap();
3306 // Get raw paragraph texts first.
3307 std::vector<OUString> aParaTexts;
3308 sal_Int32 nParaCount = pText->GetParagraphCount();
3309 aParaTexts.reserve(nParaCount);
3310 for (sal_Int32 i = 0; i < nParaCount; ++i)
3311 aParaTexts.push_back(pText->GetText(i));
3313 // Get all section data and iterate through them.
3314 std::vector<editeng::Section> aAttrs;
3315 pText->GetAllSections(aAttrs);
3316 std::vector<editeng::Section>::const_iterator itSec = aAttrs.begin(), itSecEnd = aAttrs.end();
3317 std::vector<editeng::Section>::const_iterator itPara = itSec;
3318 sal_Int32 nCurPara = 0; // current paragraph
3319 for (; itSec != itSecEnd; ++itSec)
3321 const editeng::Section& rSec = *itSec;
3322 if (nCurPara == rSec.mnParagraph)
3323 // Still in the same paragraph.
3324 continue;
3326 // Start of a new paragraph. Flush the old paragraph.
3327 flushParagraph(*this, aParaTexts[nCurPara], xMapper, xStylePool, rAttrMap, itPara, itSec);
3328 nCurPara = rSec.mnParagraph;
3329 itPara = itSec;
3332 flushParagraph(*this, aParaTexts[nCurPara], xMapper, xStylePool, rAttrMap, itPara, itSecEnd);
3335 void ScXMLExport::WriteMultiLineFormulaResult(const ScFormulaCell* pCell)
3337 OUString aElemName = GetNamespaceMap().GetQNameByKey(XML_NAMESPACE_TEXT, GetXMLToken(XML_P));
3339 OUString aResStr = pCell->GetResultString().getString();
3340 const sal_Unicode* p = aResStr.getStr();
3341 const sal_Unicode* pEnd = p + static_cast<size_t>(aResStr.getLength());
3342 const sal_Unicode* pPara = p; // paragraph head.
3343 for (; p != pEnd; ++p)
3345 if (*p != '\n')
3346 continue;
3348 // flush the paragraph.
3349 OUString aContent;
3350 if (*pPara == '\n')
3351 ++pPara;
3352 if (p > pPara)
3353 aContent = OUString(pPara, p-pPara);
3355 SvXMLElementExport aElem(*this, aElemName, false, false);
3356 Characters(aContent);
3358 pPara = p;
3361 OUString aContent;
3362 if (*pPara == '\n')
3363 ++pPara;
3364 if (pEnd > pPara)
3365 aContent = OUString(pPara, pEnd-pPara);
3367 SvXMLElementExport aElem(*this, aElemName, false, false);
3368 Characters(aContent);
3371 void ScXMLExport::ExportShape(const uno::Reference < drawing::XShape >& xShape, awt::Point* pPoint)
3373 uno::Reference < beans::XPropertySet > xShapeProps ( xShape, uno::UNO_QUERY );
3374 bool bIsChart( false );
3375 if (xShapeProps.is())
3377 sal_Int32 nZOrder = 0;
3378 if (xShapeProps->getPropertyValue("ZOrder") >>= nZOrder)
3380 AddAttribute(XML_NAMESPACE_DRAW, XML_ZINDEX, OUString::number(nZOrder));
3382 uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xShapeProps->getPropertySetInfo();
3383 OUString sPropCLSID ("CLSID");
3384 if( xPropSetInfo->hasPropertyByName( sPropCLSID ) )
3386 OUString sCLSID;
3387 if (xShapeProps->getPropertyValue( sPropCLSID ) >>= sCLSID)
3389 if ( sCLSID.equalsIgnoreAsciiCase(GetChartExport()->getChartCLSID()) )
3391 // we have a chart
3392 OUString sRanges;
3393 if ( pDoc )
3395 OUString aChartName;
3396 xShapeProps->getPropertyValue( "PersistName" ) >>= aChartName;
3397 ScChartListenerCollection* pCollection = pDoc->GetChartListenerCollection();
3398 if (pCollection)
3400 ScChartListener* pListener = pCollection->findByName(aChartName);
3401 if (pListener)
3403 const ScRangeListRef& rRangeList = pListener->GetRangeList();
3404 if ( rRangeList.is() )
3406 ScRangeStringConverter::GetStringFromRangeList( sRanges, rRangeList.get(), pDoc, FormulaGrammar::CONV_OOO );
3407 if ( !sRanges.isEmpty() )
3409 bIsChart = true;
3410 rtl::Reference<SvXMLAttributeList> pAttrList = new SvXMLAttributeList();
3411 pAttrList->AddAttribute(
3412 GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, GetXMLToken( XML_NOTIFY_ON_UPDATE_OF_RANGES ) ), sRanges );
3413 GetShapeExport()->exportShape( xShape, SEF_DEFAULT, pPoint, pAttrList.get() );
3420 if ( sRanges.isEmpty() )
3422 uno::Reference< frame::XModel > xChartModel;
3423 if( ( xShapeProps->getPropertyValue( "Model" ) >>= xChartModel ) &&
3424 xChartModel.is())
3426 uno::Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY );
3427 uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartModel, uno::UNO_QUERY );
3428 if( xChartDoc.is() && xReceiver.is() &&
3429 ! xChartDoc->hasInternalDataProvider())
3431 // we have a chart that gets its data from Calc
3432 bIsChart = true;
3433 uno::Sequence< OUString > aRepresentations(
3434 xReceiver->getUsedRangeRepresentations());
3435 rtl::Reference<SvXMLAttributeList> pAttrList;
3438 if (aRepresentations.hasElements())
3440 // add the ranges used by the chart to the shape
3441 // element to be able to start listening after
3442 // load (when the chart is not yet loaded)
3443 uno::Reference< chart2::data::XRangeXMLConversion > xRangeConverter( xChartDoc->getDataProvider(), uno::UNO_QUERY );
3444 sRanges = lcl_RangeSequenceToString( aRepresentations, xRangeConverter );
3445 pAttrList = new SvXMLAttributeList();
3446 pAttrList->AddAttribute(
3447 GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, GetXMLToken(XML_NOTIFY_ON_UPDATE_OF_RANGES) ), sRanges );
3450 catch (const lang::IllegalArgumentException&)
3452 TOOLS_WARN_EXCEPTION("sc", "Exception in lcl_RangeSequenceToString - invalid range?");
3454 GetShapeExport()->exportShape(xShape, SEF_DEFAULT, pPoint, pAttrList.get());
3462 if (!bIsChart)
3463 GetShapeExport()->exportShape(xShape, SEF_DEFAULT, pPoint);
3465 IncrementProgressBar(false);
3468 void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
3470 if( !(rMyCell.bHasShape && !rMyCell.aShapeList.empty() && pDoc) )
3471 return;
3473 // Reference point to turn absolute coordinates in reference point + offset. That happens in most
3474 // cases in XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint, which gets the absolute
3475 // coordinates as translation from matrix in property "Transformation". For cell anchored shapes
3476 // the reference point is left-top (in LTR mode) of that cell, which contains the shape.
3477 tools::Rectangle aCellRectFull = pDoc->GetMMRect(
3478 rMyCell.maCellAddress.Col(), rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Col(),
3479 rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Tab(), false /*bHiddenAsZero*/);
3480 awt::Point aPoint;
3481 bool bNegativePage = pDoc->IsNegativePage(rMyCell.maCellAddress.Tab());
3482 if (bNegativePage)
3483 aPoint.X = aCellRectFull.Right();
3484 else
3485 aPoint.X = aCellRectFull.Left();
3486 aPoint.Y = aCellRectFull.Top();
3488 for (const auto& rShape : rMyCell.aShapeList)
3490 if (rShape.xShape.is())
3492 // The current object geometry is based on bHiddenAsZero=true, but ODF file format
3493 // needs it as if there were no hidden rows or columns. We manipulate the geometry
3494 // accordingly for writing xml markup and restore geometry later.
3495 bool bNeedsRestore = false;
3496 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rShape.xShape);
3497 // Remember original geometry
3498 std::unique_ptr<SdrObjGeoData> pGeoData;
3499 if (pObj)
3500 pGeoData = pObj->GetGeoData();
3502 // Hiding row or column affects the shape based on its snap rect. So we need start and
3503 // end cell address of snap rect. In case of a transformed shape, it is not in rMyCell.
3504 ScAddress aSnapStartAddress = rMyCell.maCellAddress;
3505 ScDrawObjData* pObjData = nullptr;
3506 if (pObj)
3508 pObjData = ScDrawLayer::GetObjData(pObj);
3509 if (pObjData)
3510 aSnapStartAddress = pObjData->maStart;
3513 // In case rows or columns are hidden above or before the snap rect, move the shape to the
3514 // position it would have, if these rows and columns are visible.
3515 tools::Rectangle aRectFull = pDoc->GetMMRect(
3516 aSnapStartAddress.Col(), aSnapStartAddress.Row(), aSnapStartAddress.Col(),
3517 aSnapStartAddress.Row(), aSnapStartAddress.Tab(), false /*bHiddenAsZero*/);
3518 tools::Rectangle aRectReduced = pDoc->GetMMRect(
3519 aSnapStartAddress.Col(), aSnapStartAddress.Row(), aSnapStartAddress.Col(),
3520 aSnapStartAddress.Row(), aSnapStartAddress.Tab(), true /*bHiddenAsZero*/);
3521 const tools::Long nLeftDiff(aRectFull.Left() - aRectReduced.Left());
3522 const tools::Long nTopDiff(aRectFull.Top() - aRectReduced.Top());
3523 if (pObj && (abs(nLeftDiff) > 1 || abs(nTopDiff) > 1))
3525 bNeedsRestore = true;
3526 pObj->NbcMove(Size(nLeftDiff, nTopDiff));
3529 // tdf#137033 In case the shape is anchored "To Cell (resize with cell)" hiding rows or
3530 // columns inside the snap rect has not only changed size of the shape but rotate and shear
3531 // angle too. We resize the shape to full size. That will recover the original angles too.
3532 if (rShape.bResizeWithCell && pObjData) // implies pObj & aSnapStartAddress = pObjData->maStart
3534 // Get original size from anchor
3535 const Point aSnapStartOffset = pObjData->maStartOffset;
3536 // In case of 'resize with cell' maEnd and maEndOffset should be valid.
3537 const ScAddress aSnapEndAddress(pObjData->maEnd);
3538 const Point aSnapEndOffset = pObjData->maEndOffset;
3539 const tools::Rectangle aStartCellRect = pDoc->GetMMRect(
3540 aSnapStartAddress.Col(), aSnapStartAddress.Row(), aSnapStartAddress.Col(),
3541 aSnapStartAddress.Row(), aSnapStartAddress.Tab(), false /*bHiddenAsZero*/);
3542 const tools::Rectangle aEndCellRect = pDoc->GetMMRect(
3543 aSnapEndAddress.Col(), aSnapEndAddress.Row(), aSnapEndAddress.Col(),
3544 aSnapEndAddress.Row(), aSnapEndAddress.Tab(), false /*bHiddenAsZero*/);
3545 if (bNegativePage)
3547 aRectFull.SetLeft(aEndCellRect.Right() - aSnapEndOffset.X());
3548 aRectFull.SetRight(aStartCellRect.Right() - aSnapStartOffset.X());
3550 else
3552 aRectFull.SetLeft(aStartCellRect.Left() + aSnapStartOffset.X());
3553 aRectFull.SetRight(aEndCellRect.Left() + aSnapEndOffset.X());
3555 aRectFull.SetTop(aStartCellRect.Top() + aSnapStartOffset.Y());
3556 aRectFull.SetBottom(aEndCellRect.Top() + aSnapEndOffset.Y());
3557 aRectReduced = pObjData->getShapeRect();
3558 if(abs(aRectFull.getOpenWidth() - aRectReduced.getOpenWidth()) > 1
3559 || abs(aRectFull.getOpenHeight() - aRectReduced.getOpenHeight()) > 1)
3561 bNeedsRestore = true;
3562 Fraction aScaleWidth(aRectFull.getOpenWidth(), aRectReduced.getOpenWidth());
3563 if (!aScaleWidth.IsValid())
3564 aScaleWidth = Fraction(1.0);
3565 Fraction aScaleHeight(aRectFull.getOpenHeight(), aRectReduced.getOpenHeight());
3566 if (!aScaleHeight.IsValid())
3567 aScaleHeight = Fraction(1.0);
3568 pObj->NbcResize(pObj->GetRelativePos(), aScaleWidth, aScaleHeight);
3572 // We only write the end address if we want the shape to resize with the cell
3573 if ( rShape.bResizeWithCell &&
3574 rShape.xShape->getShapeType() != "com.sun.star.drawing.CaptionShape" )
3576 OUString sEndAddress;
3577 ScRangeStringConverter::GetStringFromAddress(sEndAddress, rShape.aEndAddress, pDoc, FormulaGrammar::CONV_OOO);
3578 AddAttribute(XML_NAMESPACE_TABLE, XML_END_CELL_ADDRESS, sEndAddress);
3579 OUStringBuffer sBuffer;
3580 GetMM100UnitConverter().convertMeasureToXML(
3581 sBuffer, rShape.nEndX);
3582 AddAttribute(XML_NAMESPACE_TABLE, XML_END_X, sBuffer.makeStringAndClear());
3583 GetMM100UnitConverter().convertMeasureToXML(
3584 sBuffer, rShape.nEndY);
3585 AddAttribute(XML_NAMESPACE_TABLE, XML_END_Y, sBuffer.makeStringAndClear());
3588 // Correct above calculated reference point for some cases:
3589 // a) For a RTL-sheet translate from matrix is not suitable, because the shape
3590 // from xml (which is always LTR) is not mirrored to negative page but shifted.
3591 // b) In case of horizontal mirrored, 'resize with cell' anchored custom shape, translate
3592 // has wrong values. FixMe: Why is translate wrong?
3593 // c) Measure lines do not use transformation matrix but use start and end point directly.
3594 ScDrawObjData* pNRObjData = nullptr;
3595 if (pObj && bNegativePage
3596 && rShape.xShape->getShapeType() == "com.sun.star.drawing.MeasureShape")
3598 // inverse of shift when import
3599 tools::Rectangle aSnapRect = pObj->GetSnapRect();
3600 aPoint.X = aSnapRect.Left() + aSnapRect.Right() - aPoint.X;
3602 else if (pObj && (pNRObjData = ScDrawLayer::GetNonRotatedObjData(pObj))
3603 && ((rShape.bResizeWithCell && pObj->GetObjIdentifier() == SdrObjKind::CustomShape
3604 && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX())
3605 || bNegativePage))
3607 //In these cases we set reference Point = matrix translate - startOffset.
3608 awt::Point aMatrixTranslate = rShape.xShape->getPosition();
3609 aPoint.X = aMatrixTranslate.X - pNRObjData->maStartOffset.X();
3610 aPoint.Y = aMatrixTranslate.Y - pNRObjData->maStartOffset.Y();
3613 ExportShape(rShape.xShape, &aPoint);
3615 // Restore object geometry
3616 if (bNeedsRestore && pObj && pGeoData)
3617 pObj->SetGeoData(*pGeoData);
3622 void ScXMLExport::WriteTableShapes()
3624 ScMyTableShapes* pTableShapes(pSharedData->GetTableShapes());
3625 if (!pTableShapes || (*pTableShapes)[nCurrentTable].empty())
3626 return;
3628 OSL_ENSURE(pTableShapes->size() > static_cast<size_t>(nCurrentTable), "wrong Table");
3629 SvXMLElementExport aShapesElem(*this, XML_NAMESPACE_TABLE, XML_SHAPES, true, false);
3630 for (const auto& rxShape : (*pTableShapes)[nCurrentTable])
3632 if (rxShape.is())
3634 if (pDoc->IsNegativePage(static_cast<SCTAB>(nCurrentTable)))
3636 // RTL-mirroring refers to snap rectangle, not to logic rectangle, therefore cannot use
3637 // getPosition() and getSize(), but need property "FrameRect" from rxShape or
3638 // GetSnapRect() from associated SdrObject.
3639 uno::Reference<beans::XPropertySet> xShapeProp(rxShape, uno::UNO_QUERY);
3640 awt::Rectangle aFrameRect;
3641 if (xShapeProp.is() && (xShapeProp->getPropertyValue("FrameRect") >>= aFrameRect))
3643 // file format uses shape in LTR mode. newLeft = - oldRight = - (oldLeft + width).
3644 // newTranslate = oldTranslate - refPoint, oldTranslate from transformation matrix,
3645 // calculated in XMLShapeExport::exportShape common for all modules.
3646 // oldTranslate.X = oldLeft ==> refPoint.X = 2 * oldLeft + width
3647 awt::Point aRefPoint;
3648 aRefPoint.X = 2 * aFrameRect.X + aFrameRect.Width - 1;
3649 aRefPoint.Y = 0;
3650 ExportShape(rxShape, &aRefPoint);
3652 // else should not happen
3654 else
3655 ExportShape(rxShape, nullptr);
3658 (*pTableShapes)[nCurrentTable].clear();
3661 void ScXMLExport::WriteAreaLink( const ScMyCell& rMyCell )
3663 if( !rMyCell.bHasAreaLink )
3664 return;
3666 const ScMyAreaLink& rAreaLink = rMyCell.aAreaLink;
3667 AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, rAreaLink.sSourceStr );
3668 AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3669 AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(rAreaLink.sURL) );
3670 AddAttribute( XML_NAMESPACE_TABLE, XML_FILTER_NAME, rAreaLink.sFilter );
3671 if( !rAreaLink.sFilterOptions.isEmpty() )
3672 AddAttribute( XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, rAreaLink.sFilterOptions );
3673 AddAttribute( XML_NAMESPACE_TABLE, XML_LAST_COLUMN_SPANNED, OUString::number(rAreaLink.GetColCount()) );
3674 AddAttribute( XML_NAMESPACE_TABLE, XML_LAST_ROW_SPANNED, OUString::number(rAreaLink.GetRowCount()) );
3675 if( rAreaLink.nRefreshDelaySeconds )
3677 OUStringBuffer sValue;
3678 ::sax::Converter::convertDuration( sValue,
3679 static_cast<double>(rAreaLink.nRefreshDelaySeconds) / 86400 );
3680 AddAttribute( XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, sValue.makeStringAndClear() );
3682 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_CELL_RANGE_SOURCE, true, true );
3685 void ScXMLExport::exportAnnotationMeta( const uno::Reference < drawing::XShape >& xShape)
3687 ScPostIt* pNote = pCurrentCell->pNote;
3689 if (!pNote)
3690 return;
3692 // TODO : notes
3693 //is it still useful, as this call back is only called from ScXMLExport::WriteAnnotation
3694 // and should be in sync with pCurrentCell
3695 SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(pCurrentCell->maCellAddress);
3696 uno::Reference<drawing::XShape> xCurrentShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY );
3697 if (xCurrentShape.get()!=xShape.get())
3698 return;
3700 const OUString& sAuthor(pNote->GetAuthor());
3701 if (!sAuthor.isEmpty())
3703 SvXMLElementExport aCreatorElem( *this, XML_NAMESPACE_DC,
3704 XML_CREATOR, true,
3705 false );
3706 Characters(sAuthor);
3709 const OUString& aDate(pNote->GetDate());
3710 if (pDoc)
3712 SvNumberFormatter* pNumForm = pDoc->GetFormatTable();
3713 double fDate;
3714 sal_uInt32 nfIndex = pNumForm->GetFormatIndex(NF_DATE_SYS_DDMMYYYY, LANGUAGE_SYSTEM);
3715 if (pNumForm->IsNumberFormat(aDate, nfIndex, fDate))
3717 OUStringBuffer sBuf;
3718 GetMM100UnitConverter().convertDateTime(sBuf, fDate,true);
3719 SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC,
3720 XML_DATE, true,
3721 false );
3722 Characters(sBuf.makeStringAndClear());
3724 else
3726 SvXMLElementExport aDateElem( *this, XML_NAMESPACE_META,
3727 XML_DATE_STRING, true,
3728 false );
3729 Characters(aDate);
3732 else
3734 SvXMLElementExport aDateElem( *this, XML_NAMESPACE_META,
3735 XML_DATE_STRING, true,
3736 false );
3737 Characters(aDate);
3741 void ScXMLExport::WriteAnnotation(const ScMyCell& rMyCell)
3743 ScPostIt* pNote = pDoc->GetNote(rMyCell.maCellAddress);
3744 if (!pNote)
3745 return;
3747 if (pNote->IsCaptionShown())
3748 AddAttribute(XML_NAMESPACE_OFFICE, XML_DISPLAY, XML_TRUE);
3750 pCurrentCell = &rMyCell;
3752 SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(rMyCell.maCellAddress);
3753 if (pNoteCaption)
3755 uno::Reference<drawing::XShape> xShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY );
3756 if (xShape.is())
3757 GetShapeExport()->exportShape(xShape, SEF_DEFAULT|XMLShapeExportFlags::ANNOTATION);
3760 pCurrentCell = nullptr;
3763 void ScXMLExport::WriteDetective( const ScMyCell& rMyCell )
3765 if( !(rMyCell.bHasDetectiveObj || rMyCell.bHasDetectiveOp) )
3766 return;
3768 const ScMyDetectiveObjVec& rObjVec = rMyCell.aDetectiveObjVec;
3769 const ScMyDetectiveOpVec& rOpVec = rMyCell.aDetectiveOpVec;
3770 sal_Int32 nObjCount(rObjVec.size());
3771 sal_Int32 nOpCount(rOpVec.size());
3772 if( !(nObjCount || nOpCount) )
3773 return;
3775 SvXMLElementExport aDetElem( *this, XML_NAMESPACE_TABLE, XML_DETECTIVE, true, true );
3776 OUString sString;
3777 for(const auto& rObj : rObjVec)
3779 if (rObj.eObjType != SC_DETOBJ_CIRCLE)
3781 if( (rObj.eObjType == SC_DETOBJ_ARROW) || (rObj.eObjType == SC_DETOBJ_TOOTHERTAB))
3783 ScRangeStringConverter::GetStringFromRange( sString, rObj.aSourceRange, pDoc, FormulaGrammar::CONV_OOO );
3784 AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sString );
3786 sString = ScXMLConverter::GetStringFromDetObjType( rObj.eObjType );
3787 AddAttribute( XML_NAMESPACE_TABLE, XML_DIRECTION, sString );
3788 if( rObj.bHasError )
3789 AddAttribute( XML_NAMESPACE_TABLE, XML_CONTAINS_ERROR, XML_TRUE );
3791 else
3792 AddAttribute( XML_NAMESPACE_TABLE, XML_MARKED_INVALID, XML_TRUE );
3793 SvXMLElementExport aRangeElem( *this, XML_NAMESPACE_TABLE, XML_HIGHLIGHTED_RANGE, true, true );
3795 for(const auto& rOp : rOpVec)
3797 OUString sOpString = ScXMLConverter::GetStringFromDetOpType( rOp.eOpType );
3798 AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, sOpString );
3799 AddAttribute( XML_NAMESPACE_TABLE, XML_INDEX, OUString::number(rOp.nIndex) );
3800 SvXMLElementExport aRangeElem( *this, XML_NAMESPACE_TABLE, XML_OPERATION, true, true );
3804 void ScXMLExport::SetRepeatAttribute(sal_Int32 nEqualCellCount, bool bIncProgress)
3806 // nEqualCellCount is additional cells, so the attribute value is nEqualCellCount+1
3807 if (nEqualCellCount > 0)
3809 sal_Int32 nTemp(nEqualCellCount + 1);
3810 OUString sOUEqualCellCount(OUString::number(nTemp));
3811 AddAttribute(sAttrColumnsRepeated, sOUEqualCellCount);
3812 if (bIncProgress)
3813 IncrementProgressBar(false, nEqualCellCount);
3817 bool ScXMLExport::IsEditCell(const ScMyCell& rCell)
3819 return rCell.maBaseCell.getType() == CELLTYPE_EDIT;
3822 bool ScXMLExport::IsCellEqual (const ScMyCell& aCell1, const ScMyCell& aCell2)
3824 bool bIsEqual = false;
3825 if( !aCell1.bIsMergedBase && !aCell2.bIsMergedBase &&
3826 aCell1.bIsCovered == aCell2.bIsCovered &&
3827 !aCell1.bIsMatrixBase && !aCell2.bIsMatrixBase &&
3828 aCell1.bIsMatrixCovered == aCell2.bIsMatrixCovered &&
3829 aCell1.bHasAnnotation == aCell2.bHasAnnotation &&
3830 !aCell1.bHasShape && !aCell2.bHasShape &&
3831 aCell1.bHasAreaLink == aCell2.bHasAreaLink &&
3832 !aCell1.bHasDetectiveObj && !aCell2.bHasDetectiveObj)
3834 if( (aCell1.bHasAreaLink &&
3835 (aCell1.aAreaLink.GetColCount() == 1) &&
3836 (aCell2.aAreaLink.GetColCount() == 1) &&
3837 aCell1.aAreaLink.Compare( aCell2.aAreaLink ) ) ||
3838 !aCell1.bHasAreaLink )
3840 if (!aCell1.bHasAnnotation)
3842 if ((((aCell1.nStyleIndex == aCell2.nStyleIndex) && (aCell1.bIsAutoStyle == aCell2.bIsAutoStyle)) ||
3843 ((aCell1.nStyleIndex == aCell2.nStyleIndex) && (aCell1.nStyleIndex == -1))) &&
3844 aCell1.nValidationIndex == aCell2.nValidationIndex &&
3845 aCell1.nType == aCell2.nType)
3847 switch ( aCell1.nType )
3849 case table::CellContentType_EMPTY :
3851 bIsEqual = true;
3853 break;
3854 case table::CellContentType_VALUE :
3856 // #i29101# number format may be different from column default styles,
3857 // but can lead to different value types, so it must also be compared
3858 bIsEqual = (aCell1.nNumberFormat == aCell2.nNumberFormat) &&
3859 (aCell1.maBaseCell.getDouble() == aCell2.maBaseCell.getDouble());
3861 break;
3862 case table::CellContentType_TEXT :
3864 if (IsEditCell(aCell1) || IsEditCell(aCell2))
3865 bIsEqual = false;
3866 else
3868 bIsEqual = (aCell1.maBaseCell.getString(pDoc) == aCell2.maBaseCell.getString(pDoc));
3871 break;
3872 case table::CellContentType_FORMULA :
3874 bIsEqual = false;
3876 break;
3877 default :
3879 bIsEqual = false;
3881 break;
3887 return bIsEqual;
3890 void ScXMLExport::WriteCalculationSettings(const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc)
3892 uno::Reference<beans::XPropertySet> xPropertySet(xSpreadDoc, uno::UNO_QUERY);
3893 if (!xPropertySet.is())
3894 return;
3896 bool bCalcAsShown (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_CALCASSHOWN) ));
3897 bool bIgnoreCase (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_IGNORECASE) ));
3898 bool bLookUpLabels (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_LOOKUPLABELS) ));
3899 bool bMatchWholeCell (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_MATCHWHOLE) ));
3900 bool bUseRegularExpressions (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_REGEXENABLED) ));
3901 bool bUseWildcards (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_WILDCARDSENABLED) ));
3902 if (bUseWildcards && bUseRegularExpressions)
3903 bUseRegularExpressions = false; // mutually exclusive, wildcards take precedence
3904 bool bIsIterationEnabled (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_ITERENABLED) ));
3905 sal_uInt16 nYear2000 (pDoc ? pDoc->GetDocOptions().GetYear2000() : 0);
3906 sal_Int32 nIterationCount(100);
3907 xPropertySet->getPropertyValue( SC_UNO_ITERCOUNT ) >>= nIterationCount;
3908 double fIterationEpsilon = 0;
3909 xPropertySet->getPropertyValue( SC_UNO_ITEREPSILON ) >>= fIterationEpsilon;
3910 util::Date aNullDate;
3911 xPropertySet->getPropertyValue( SC_UNO_NULLDATE ) >>= aNullDate;
3912 if (!(bCalcAsShown || bIgnoreCase || !bLookUpLabels || !bMatchWholeCell || !bUseRegularExpressions ||
3913 bUseWildcards ||
3914 bIsIterationEnabled || nIterationCount != 100 || !::rtl::math::approxEqual(fIterationEpsilon, 0.001) ||
3915 aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 || nYear2000 != 1930))
3916 return;
3918 if (bIgnoreCase)
3919 AddAttribute(XML_NAMESPACE_TABLE, XML_CASE_SENSITIVE, XML_FALSE);
3920 if (bCalcAsShown)
3921 AddAttribute(XML_NAMESPACE_TABLE, XML_PRECISION_AS_SHOWN, XML_TRUE);
3922 if (!bMatchWholeCell)
3923 AddAttribute(XML_NAMESPACE_TABLE, XML_SEARCH_CRITERIA_MUST_APPLY_TO_WHOLE_CELL, XML_FALSE);
3924 if (!bLookUpLabels)
3925 AddAttribute(XML_NAMESPACE_TABLE, XML_AUTOMATIC_FIND_LABELS, XML_FALSE);
3926 if (!bUseRegularExpressions)
3927 AddAttribute(XML_NAMESPACE_TABLE, XML_USE_REGULAR_EXPRESSIONS, XML_FALSE);
3928 if (bUseWildcards)
3929 AddAttribute(XML_NAMESPACE_TABLE, XML_USE_WILDCARDS, XML_TRUE);
3930 if (nYear2000 != 1930)
3932 AddAttribute(XML_NAMESPACE_TABLE, XML_NULL_YEAR, OUString::number(nYear2000));
3934 SvXMLElementExport aCalcSettings(*this, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true);
3936 if (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899)
3938 OUStringBuffer sDate;
3939 SvXMLUnitConverter::convertDateTime(sDate, 0.0, aNullDate);
3940 AddAttribute(XML_NAMESPACE_TABLE, XML_DATE_VALUE, sDate.makeStringAndClear());
3941 SvXMLElementExport aElemNullDate(*this, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true);
3943 if (bIsIterationEnabled || nIterationCount != 100 || !::rtl::math::approxEqual(fIterationEpsilon, 0.001))
3945 if (bIsIterationEnabled)
3946 AddAttribute(XML_NAMESPACE_TABLE, XML_STATUS, XML_ENABLE);
3947 if (nIterationCount != 100)
3949 AddAttribute(XML_NAMESPACE_TABLE, XML_STEPS, OUString::number(nIterationCount));
3951 if (!::rtl::math::approxEqual(fIterationEpsilon, 0.001))
3953 OUStringBuffer sBuffer;
3954 ::sax::Converter::convertDouble(sBuffer,
3955 fIterationEpsilon);
3956 AddAttribute(XML_NAMESPACE_TABLE, XML_MAXIMUM_DIFFERENCE, sBuffer.makeStringAndClear());
3958 SvXMLElementExport aElemIteration(*this, XML_NAMESPACE_TABLE, XML_ITERATION, true, true);
3963 void ScXMLExport::WriteTableSource()
3965 uno::Reference <sheet::XSheetLinkable> xLinkable (xCurrentTable, uno::UNO_QUERY);
3966 if (!(xLinkable.is() && GetModel().is()))
3967 return;
3969 sheet::SheetLinkMode nMode (xLinkable->getLinkMode());
3970 if (nMode == sheet::SheetLinkMode_NONE)
3971 return;
3973 OUString sLink (xLinkable->getLinkUrl());
3974 uno::Reference <beans::XPropertySet> xProps (GetModel(), uno::UNO_QUERY);
3975 if (!xProps.is())
3976 return;
3978 uno::Reference <container::XIndexAccess> xIndex(xProps->getPropertyValue(SC_UNO_SHEETLINKS), uno::UNO_QUERY);
3979 if (!xIndex.is())
3980 return;
3982 sal_Int32 nCount(xIndex->getCount());
3983 if (!nCount)
3984 return;
3986 bool bFound(false);
3987 uno::Reference <beans::XPropertySet> xLinkProps;
3988 for (sal_Int32 i = 0; (i < nCount) && !bFound; ++i)
3990 xLinkProps.set(xIndex->getByIndex(i), uno::UNO_QUERY);
3991 if (xLinkProps.is())
3993 OUString sNewLink;
3994 if (xLinkProps->getPropertyValue(SC_UNONAME_LINKURL) >>= sNewLink)
3995 bFound = sLink == sNewLink;
3998 if (!(bFound && xLinkProps.is()))
3999 return;
4001 OUString sFilter;
4002 OUString sFilterOptions;
4003 OUString sTableName (xLinkable->getLinkSheetName());
4004 sal_Int32 nRefresh(0);
4005 xLinkProps->getPropertyValue(SC_UNONAME_FILTER) >>= sFilter;
4006 xLinkProps->getPropertyValue(SC_UNONAME_FILTOPT) >>= sFilterOptions;
4007 xLinkProps->getPropertyValue(SC_UNONAME_REFDELAY) >>= nRefresh;
4008 if (sLink.isEmpty())
4009 return;
4011 AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
4012 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(sLink));
4013 if (!sTableName.isEmpty())
4014 AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, sTableName);
4015 if (!sFilter.isEmpty())
4016 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, sFilter);
4017 if (!sFilterOptions.isEmpty())
4018 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, sFilterOptions);
4019 if (nMode != sheet::SheetLinkMode_NORMAL)
4020 AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY);
4021 if( nRefresh )
4023 OUStringBuffer sBuffer;
4024 ::sax::Converter::convertDuration( sBuffer,
4025 static_cast<double>(nRefresh) / 86400 );
4026 AddAttribute( XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, sBuffer.makeStringAndClear() );
4028 SvXMLElementExport aSourceElem(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, true, true);
4031 // core implementation
4032 void ScXMLExport::WriteScenario()
4034 if (!(pDoc && pDoc->IsScenario(static_cast<SCTAB>(nCurrentTable))))
4035 return;
4037 OUString sComment;
4038 Color aColor;
4039 ScScenarioFlags nFlags;
4040 pDoc->GetScenarioData(static_cast<SCTAB>(nCurrentTable), sComment, aColor, nFlags);
4041 if (!(nFlags & ScScenarioFlags::ShowFrame))
4042 AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY_BORDER, XML_FALSE);
4043 OUStringBuffer aBuffer;
4044 ::sax::Converter::convertColor(aBuffer, aColor);
4045 AddAttribute(XML_NAMESPACE_TABLE, XML_BORDER_COLOR, aBuffer.makeStringAndClear());
4046 if (!(nFlags & ScScenarioFlags::TwoWay))
4047 AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_BACK, XML_FALSE);
4048 if (!(nFlags & ScScenarioFlags::Attrib))
4049 AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_STYLES, XML_FALSE);
4050 if (nFlags & ScScenarioFlags::Value)
4051 AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_FORMULAS, XML_FALSE);
4052 if (nFlags & ScScenarioFlags::Protected)
4053 AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
4054 ::sax::Converter::convertBool(aBuffer,
4055 pDoc->IsActiveScenario(static_cast<SCTAB>(nCurrentTable)));
4056 AddAttribute(XML_NAMESPACE_TABLE, XML_IS_ACTIVE, aBuffer.makeStringAndClear());
4057 const ScRangeList* pRangeList = pDoc->GetScenarioRanges(static_cast<SCTAB>(nCurrentTable));
4058 OUString sRangeListStr;
4059 ScRangeStringConverter::GetStringFromRangeList( sRangeListStr, pRangeList, pDoc, FormulaGrammar::CONV_OOO );
4060 AddAttribute(XML_NAMESPACE_TABLE, XML_SCENARIO_RANGES, sRangeListStr);
4061 if (!sComment.isEmpty())
4062 AddAttribute(XML_NAMESPACE_TABLE, XML_COMMENT, sComment);
4063 SvXMLElementExport aElem(*this, XML_NAMESPACE_TABLE, XML_SCENARIO, true, true);
4066 void ScXMLExport::WriteTheLabelRanges( const uno::Reference< sheet::XSpreadsheetDocument >& xSpreadDoc )
4068 uno::Reference< beans::XPropertySet > xDocProp( xSpreadDoc, uno::UNO_QUERY );
4069 if( !xDocProp.is() ) return;
4071 sal_Int32 nCount(0);
4072 uno::Reference< container::XIndexAccess > xColRangesIAccess(xDocProp->getPropertyValue( SC_UNO_COLLABELRNG ), uno::UNO_QUERY);
4073 if( xColRangesIAccess.is() )
4074 nCount += xColRangesIAccess->getCount();
4076 uno::Reference< container::XIndexAccess > xRowRangesIAccess(xDocProp->getPropertyValue( SC_UNO_ROWLABELRNG ), uno::UNO_QUERY);
4077 if( xRowRangesIAccess.is() )
4078 nCount += xRowRangesIAccess->getCount();
4080 if( nCount )
4082 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGES, true, true );
4083 WriteLabelRanges( xColRangesIAccess, true );
4084 WriteLabelRanges( xRowRangesIAccess, false );
4088 void ScXMLExport::WriteLabelRanges( const uno::Reference< container::XIndexAccess >& xRangesIAccess, bool bColumn )
4090 if( !xRangesIAccess.is() ) return;
4092 sal_Int32 nCount(xRangesIAccess->getCount());
4093 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
4095 uno::Reference< sheet::XLabelRange > xRange(xRangesIAccess->getByIndex( nIndex ), uno::UNO_QUERY);
4096 if( xRange.is() )
4098 OUString sRangeStr;
4099 table::CellRangeAddress aCellRange( xRange->getLabelArea() );
4100 ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc, FormulaGrammar::CONV_OOO );
4101 AddAttribute( XML_NAMESPACE_TABLE, XML_LABEL_CELL_RANGE_ADDRESS, sRangeStr );
4102 aCellRange = xRange->getDataArea();
4103 ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc, FormulaGrammar::CONV_OOO );
4104 AddAttribute( XML_NAMESPACE_TABLE, XML_DATA_CELL_RANGE_ADDRESS, sRangeStr );
4105 AddAttribute( XML_NAMESPACE_TABLE, XML_ORIENTATION, bColumn ? XML_COLUMN : XML_ROW );
4106 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGE, true, true );
4111 void ScXMLExport::WriteNamedExpressions()
4113 if (!pDoc)
4114 return;
4115 ScRangeName* pNamedRanges = pDoc->GetRangeName();
4116 WriteNamedRange(pNamedRanges);
4119 void ScXMLExport::WriteExternalDataMapping()
4121 if (!pDoc)
4122 return;
4124 if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4125 // Export this only for 1.2 extended and above.
4126 return;
4128 sc::ExternalDataMapper& rDataMapper = pDoc->GetExternalDataMapper();
4129 auto& rDataSources = rDataMapper.getDataSources();
4131 if (rDataSources.empty())
4132 return;
4134 SvXMLElementExport aMappings(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPINGS, true, true);
4135 for (const auto& itr : rDataSources)
4137 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, itr.getURL());
4138 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PROVIDER, itr.getProvider());
4139 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATA_FREQUENCY, OUString::number(sc::ExternalDataSource::getUpdateFrequency()));
4140 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_ID, itr.getID());
4141 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATABASE_NAME, itr.getDBName());
4143 SvXMLElementExport aMapping(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPING, true, true);
4144 // Add the data transformations
4145 WriteExternalDataTransformations(itr.getDataTransformation());
4149 void ScXMLExport::WriteExternalDataTransformations(const std::vector<std::shared_ptr<sc::DataTransformation>>& aDataTransformations)
4151 SvXMLElementExport aTransformations(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_TRANSFORMATIONS, true, true);
4152 for (auto& itr : aDataTransformations)
4154 sc::TransformationType aTransformationType = itr->getTransformationType();
4156 switch(aTransformationType)
4158 case sc::TransformationType::DELETE_TRANSFORMATION:
4160 // Delete Columns Transformation
4161 std::shared_ptr<sc::ColumnRemoveTransformation> aDeleteTransformation = std::dynamic_pointer_cast<sc::ColumnRemoveTransformation>(itr);
4162 std::set<SCCOL> aColumns = aDeleteTransformation->getColumns();
4163 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_REMOVE_TRANSFORMATION, true, true);
4164 for(auto& col : aColumns)
4166 // Add Columns
4167 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4168 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4171 break;
4172 case sc::TransformationType::SPLIT_TRANSFORMATION:
4174 std::shared_ptr<sc::SplitColumnTransformation> aSplitTransformation = std::dynamic_pointer_cast<sc::SplitColumnTransformation>(itr);
4176 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(aSplitTransformation->getColumn()));
4177 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SEPARATOR, OUString::number(aSplitTransformation->getSeparator()));
4178 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_SPLIT_TRANSFORMATION, true, true);
4180 break;
4181 case sc::TransformationType::MERGE_TRANSFORMATION:
4183 // Merge Transformation
4184 std::shared_ptr<sc::MergeColumnTransformation> aMergeTransformation = std::dynamic_pointer_cast<sc::MergeColumnTransformation>(itr);
4185 std::set<SCCOL> aColumns = aMergeTransformation->getColumns();
4187 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MERGE_STRING, aMergeTransformation->getMergeString());
4188 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_MERGE_TRANSFORMATION, true, true);
4190 for(auto& col : aColumns)
4192 // Columns
4193 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4194 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4197 break;
4198 case sc::TransformationType::SORT_TRANSFORMATION:
4200 // Sort Transformation
4201 std::shared_ptr<sc::SortTransformation> aSortTransformation = std::dynamic_pointer_cast<sc::SortTransformation>(itr);
4202 ScSortParam aSortParam = aSortTransformation->getSortParam();
4203 const sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager();
4204 const sc::DataStream* pStrm = rMgr.getDataStream();
4205 if (!pStrm)
4206 // No data stream.
4207 return;
4209 // Streamed range
4210 ScRange aRange = pStrm->GetRange();
4212 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_SORT_TRANSFORMATION, true, true);
4214 writeSort(*this, aSortParam, aRange, pDoc);
4216 break;
4217 case sc::TransformationType::TEXT_TRANSFORMATION:
4219 // Text Transformation
4220 std::shared_ptr<sc::TextTransformation> aTextTransformation = std::dynamic_pointer_cast<sc::TextTransformation>(itr);
4222 sc::TEXT_TRANSFORM_TYPE aTextTransformType = aTextTransformation->getTextTransformationType();
4224 switch ( aTextTransformType )
4226 case sc::TEXT_TRANSFORM_TYPE::TO_LOWER:
4227 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_LOWERCASE);
4228 break;
4229 case sc::TEXT_TRANSFORM_TYPE::TO_UPPER:
4230 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_UPPERCASE);
4231 break;
4232 case sc::TEXT_TRANSFORM_TYPE::CAPITALIZE:
4233 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_CAPITALIZE);
4234 break;
4235 case sc::TEXT_TRANSFORM_TYPE::TRIM:
4236 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_TRIM);
4237 break;
4240 std::set<SCCOL> aColumns = aTextTransformation->getColumns();
4242 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_TEXT_TRANSFORMATION, true, true);
4244 for(auto& col : aColumns)
4246 // Columns
4247 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4248 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4251 break;
4252 case sc::TransformationType::AGGREGATE_FUNCTION:
4254 // Aggregate Transformation
4255 std::shared_ptr<sc::AggregateFunction> aAggregateFunction = std::dynamic_pointer_cast<sc::AggregateFunction>(itr);
4256 std::set<SCCOL> aColumns = aAggregateFunction->getColumns();
4258 sc::AGGREGATE_FUNCTION aAggregateType = aAggregateFunction->getAggregateType();
4260 switch (aAggregateType)
4262 case sc::AGGREGATE_FUNCTION::SUM:
4263 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SUM);
4264 break;
4265 case sc::AGGREGATE_FUNCTION::AVERAGE:
4266 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_AVERAGE);
4267 break;
4268 case sc::AGGREGATE_FUNCTION::MIN:
4269 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MIN);
4270 break;
4271 case sc::AGGREGATE_FUNCTION::MAX:
4272 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MAX);
4273 break;
4276 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT,XML_COLUMN_AGGREGATE_TRANSFORMATION, true, true);
4278 for(auto& col : aColumns)
4280 // Columns
4281 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4282 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4285 break;
4286 case sc::TransformationType::NUMBER_TRANSFORMATION:
4288 // Number Transformation
4289 std::shared_ptr<sc::NumberTransformation> aNumberTransformation = std::dynamic_pointer_cast<sc::NumberTransformation>(itr);
4291 sc::NUMBER_TRANSFORM_TYPE aNumberTransformType = aNumberTransformation->getNumberTransformationType();
4293 switch ( aNumberTransformType )
4295 case sc::NUMBER_TRANSFORM_TYPE::ROUND:
4296 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND);
4297 break;
4298 case sc::NUMBER_TRANSFORM_TYPE::ROUND_UP:
4299 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND_UP);
4300 break;
4301 case sc::NUMBER_TRANSFORM_TYPE::ROUND_DOWN:
4302 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND_DOWN);
4303 break;
4304 case sc::NUMBER_TRANSFORM_TYPE::ABSOLUTE:
4305 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ABS);
4306 break;
4307 case sc::NUMBER_TRANSFORM_TYPE::LOG_E:
4308 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_LOG);
4309 break;
4310 case sc::NUMBER_TRANSFORM_TYPE::LOG_10:
4311 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_LOG_10);
4312 break;
4313 case sc::NUMBER_TRANSFORM_TYPE::CUBE:
4314 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CUBE);
4315 break;
4316 case sc::NUMBER_TRANSFORM_TYPE::SQUARE:
4317 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SQUARE);
4318 break;
4319 case sc::NUMBER_TRANSFORM_TYPE::SQUARE_ROOT:
4320 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SQUARE_ROOT);
4321 break;
4322 case sc::NUMBER_TRANSFORM_TYPE::EXPONENT:
4323 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_EXPONENTIAL);
4324 break;
4325 case sc::NUMBER_TRANSFORM_TYPE::IS_EVEN:
4326 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_EVEN);
4327 break;
4328 case sc::NUMBER_TRANSFORM_TYPE::IS_ODD:
4329 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ODD);
4330 break;
4331 case sc::NUMBER_TRANSFORM_TYPE::SIGN:
4332 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SIGN);
4333 break;
4336 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PRECISION, OUString::number(aNumberTransformation->getPrecision()));
4337 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_NUMBER_TRANSFORMATION, true, true);
4339 std::set<SCCOL> aColumns = aNumberTransformation->getColumn();
4340 for(auto& col : aColumns)
4342 // Columns
4343 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4344 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4347 break;
4348 case sc::TransformationType::REMOVE_NULL_TRANSFORMATION:
4350 // Replace Null Transformation
4351 std::shared_ptr<sc::ReplaceNullTransformation> aReplaceNullTransformation = std::dynamic_pointer_cast<sc::ReplaceNullTransformation>(itr);
4352 std::set<SCCOL> aColumns = aReplaceNullTransformation->getColumn();
4354 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_REPLACE_STRING, aReplaceNullTransformation->getReplaceString());
4355 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_REPLACENULL_TRANSFORMATION, true, true);
4357 for(auto& col : aColumns)
4359 // Columns
4360 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4361 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4364 break;
4365 case sc::TransformationType::DATETIME_TRANSFORMATION:
4367 // Number Transformation
4368 std::shared_ptr<sc::DateTimeTransformation> aDateTimeTransformation = std::dynamic_pointer_cast<sc::DateTimeTransformation>(itr);
4370 sc::DATETIME_TRANSFORMATION_TYPE aDateTimeTransformationType = aDateTimeTransformation->getDateTimeTransformationType();
4372 switch ( aDateTimeTransformationType )
4374 case sc::DATETIME_TRANSFORMATION_TYPE::DATE_STRING:
4375 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DATE_STRING);
4376 break;
4377 case sc::DATETIME_TRANSFORMATION_TYPE::YEAR:
4378 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_YEAR);
4379 break;
4380 case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR:
4381 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_YEAR);
4382 break;
4383 case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR:
4384 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_YEAR);
4385 break;
4386 case sc::DATETIME_TRANSFORMATION_TYPE::MONTH:
4387 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MONTH);
4388 break;
4389 case sc::DATETIME_TRANSFORMATION_TYPE::MONTH_NAME:
4390 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MONTH_NAME);
4391 break;
4392 case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH:
4393 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_MONTH);
4394 break;
4395 case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH:
4396 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_MONTH);
4397 break;
4398 case sc::DATETIME_TRANSFORMATION_TYPE::DAY:
4399 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY);
4400 break;
4401 case sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK:
4402 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY_OF_WEEK);
4403 break;
4404 case sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR:
4405 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY_OF_YEAR);
4406 break;
4407 case sc::DATETIME_TRANSFORMATION_TYPE::QUARTER:
4408 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_QUARTER);
4409 break;
4410 case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER:
4411 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_QUARTER);
4412 break;
4413 case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER:
4414 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_QUARTER);
4415 break;
4416 case sc::DATETIME_TRANSFORMATION_TYPE::TIME:
4417 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_TIME);
4418 break;
4419 case sc::DATETIME_TRANSFORMATION_TYPE::HOUR:
4420 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_HOUR);
4421 break;
4422 case sc::DATETIME_TRANSFORMATION_TYPE::MINUTE:
4423 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MINUTE);
4424 break;
4425 case sc::DATETIME_TRANSFORMATION_TYPE::SECOND:
4426 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SECONDS);
4427 break;
4430 SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_DATETIME_TRANSFORMATION, true, true);
4432 std::set<SCCOL> aColumns = aDateTimeTransformation->getColumn();
4433 for(auto& col : aColumns)
4435 // Columns
4436 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col));
4437 SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true);
4440 break;
4441 default:
4442 break;
4447 void ScXMLExport::WriteDataStream()
4449 if (!pDoc)
4450 return;
4452 if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
4453 // Export this only in experimental mode.
4454 return;
4456 if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4457 // Export this only for 1.2 extended and above.
4458 return;
4460 const sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager();
4461 const sc::DataStream* pStrm = rMgr.getDataStream();
4462 if (!pStrm)
4463 // No data stream.
4464 return;
4466 // Source URL
4467 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(pStrm->GetURL()));
4469 // Streamed range
4470 ScRange aRange = pStrm->GetRange();
4471 OUString aRangeStr;
4472 ScRangeStringConverter::GetStringFromRange(
4473 aRangeStr, aRange, pDoc, formula::FormulaGrammar::CONV_OOO);
4474 AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aRangeStr);
4476 // Empty line refresh option.
4477 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_EMPTY_LINE_REFRESH, pStrm->IsRefreshOnEmptyLine() ? XML_TRUE : XML_FALSE);
4479 // New data insertion position. Either top of bottom. Default to bottom.
4480 xmloff::token::XMLTokenEnum eInsertPosition = XML_BOTTOM;
4481 if (pStrm->GetMove() == sc::DataStream::MOVE_DOWN)
4482 eInsertPosition = XML_TOP;
4484 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_INSERTION_POSITION, eInsertPosition);
4486 SvXMLElementExport aElem(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_STREAM_SOURCE, true, true);
4489 void ScXMLExport::WriteNamedRange(ScRangeName* pRangeName)
4491 //write a global or local ScRangeName
4492 SvXMLElementExport aElemNEs(*this, XML_NAMESPACE_TABLE, XML_NAMED_EXPRESSIONS, true, true);
4493 for (const auto& rxEntry : *pRangeName)
4495 AddAttribute(sAttrName, rxEntry.second->GetName());
4497 OUString sBaseCellAddress;
4498 rxEntry.second->ValidateTabRefs();
4499 ScRangeStringConverter::GetStringFromAddress( sBaseCellAddress, rxEntry.second->GetPos(), pDoc,
4500 FormulaGrammar::CONV_OOO, ' ', false, ScRefFlags::ADDR_ABS_3D);
4501 assert(!sBaseCellAddress.isEmpty());
4502 AddAttribute(XML_NAMESPACE_TABLE, XML_BASE_CELL_ADDRESS, sBaseCellAddress);
4504 OUString sSymbol = rxEntry.second->GetSymbol(pDoc->GetStorageGrammar());
4505 OUString sTempSymbol(sSymbol);
4506 ScRange aRange;
4507 if (rxEntry.second->IsReference(aRange))
4510 OUString sContent(sTempSymbol.copy(1, sTempSymbol.getLength() -2 ));
4511 AddAttribute(XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sContent);
4513 sal_Int32 nRangeType = rxEntry.second->GetUnoType();
4514 OUStringBuffer sBufferRangeType;
4515 if ((nRangeType & sheet::NamedRangeFlag::COLUMN_HEADER) == sheet::NamedRangeFlag::COLUMN_HEADER)
4516 sBufferRangeType.append(GetXMLToken(XML_REPEAT_COLUMN));
4517 if ((nRangeType & sheet::NamedRangeFlag::ROW_HEADER) == sheet::NamedRangeFlag::ROW_HEADER)
4519 if (!sBufferRangeType.isEmpty())
4520 sBufferRangeType.append(" ");
4521 sBufferRangeType.append(GetXMLToken(XML_REPEAT_ROW));
4523 if ((nRangeType & sheet::NamedRangeFlag::FILTER_CRITERIA) == sheet::NamedRangeFlag::FILTER_CRITERIA)
4525 if (!sBufferRangeType.isEmpty())
4526 sBufferRangeType.append(" ");
4527 sBufferRangeType.append(GetXMLToken(XML_FILTER));
4529 if ((nRangeType & sheet::NamedRangeFlag::PRINT_AREA) == sheet::NamedRangeFlag::PRINT_AREA)
4531 if (!sBufferRangeType.isEmpty())
4532 sBufferRangeType.append(" ");
4533 sBufferRangeType.append(GetXMLToken(XML_PRINT_RANGE));
4535 OUString sRangeType = sBufferRangeType.makeStringAndClear();
4536 if (!sRangeType.isEmpty())
4537 AddAttribute(XML_NAMESPACE_TABLE, XML_RANGE_USABLE_AS, sRangeType);
4538 SvXMLElementExport aElemNR(*this, XML_NAMESPACE_TABLE, XML_NAMED_RANGE, true, true);
4541 else
4543 AddAttribute(XML_NAMESPACE_TABLE, XML_EXPRESSION, sTempSymbol);
4544 SvXMLElementExport aElemNE(*this, XML_NAMESPACE_TABLE, XML_NAMED_EXPRESSION, true, true);
4549 void ScXMLExport::exportSparklineGroups(SCTAB nTable)
4551 sc::SparklineGroupsExport aSparklineGroupExport(*this, nTable);
4552 aSparklineGroupExport.write();
4555 namespace {
4557 OUString getCondFormatEntryType(const ScColorScaleEntry& rEntry, bool bFirst = true)
4559 switch(rEntry.GetType())
4561 case COLORSCALE_MIN:
4562 return "minimum";
4563 case COLORSCALE_MAX:
4564 return "maximum";
4565 case COLORSCALE_PERCENT:
4566 return "percent";
4567 case COLORSCALE_PERCENTILE:
4568 return "percentile";
4569 case COLORSCALE_FORMULA:
4570 return "formula";
4571 case COLORSCALE_VALUE:
4572 return "number";
4573 case COLORSCALE_AUTO:
4574 // only important for data bars
4575 if(bFirst)
4576 return "auto-minimum";
4577 else
4578 return "auto-maximum";
4580 return OUString();
4583 OUString getDateStringForType(condformat::ScCondFormatDateType eType)
4585 switch(eType)
4587 case condformat::TODAY:
4588 return "today";
4589 case condformat::YESTERDAY:
4590 return "yesterday";
4591 case condformat::TOMORROW:
4592 return "tomorrow";
4593 case condformat::LAST7DAYS:
4594 return "last-7-days";
4595 case condformat::THISWEEK:
4596 return "this-week";
4597 case condformat::LASTWEEK:
4598 return "last-week";
4599 case condformat::NEXTWEEK:
4600 return "next-week";
4601 case condformat::THISMONTH:
4602 return "this-month";
4603 case condformat::LASTMONTH:
4604 return "last-month";
4605 case condformat::NEXTMONTH:
4606 return "next-month";
4607 case condformat::THISYEAR:
4608 return "this-year";
4609 case condformat::LASTYEAR:
4610 return "last-year";
4611 case condformat::NEXTYEAR:
4612 return "next-year";
4615 return OUString();
4620 void ScXMLExport::ExportConditionalFormat(SCTAB nTab)
4622 ScConditionalFormatList* pCondFormatList = pDoc->GetCondFormList(nTab);
4623 if(!pCondFormatList)
4624 return;
4626 if (pCondFormatList->empty())
4627 return;
4629 SvXMLElementExport aElementCondFormats(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITIONAL_FORMATS, true, true);
4631 for(const auto& rxCondFormat : *pCondFormatList)
4633 OUString sRanges;
4634 const ScRangeList& rRangeList = rxCondFormat->GetRange();
4635 ScRangeStringConverter::GetStringFromRangeList( sRanges, &rRangeList, pDoc, formula::FormulaGrammar::CONV_OOO );
4636 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TARGET_RANGE_ADDRESS, sRanges);
4637 SvXMLElementExport aElementCondFormat(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITIONAL_FORMAT, true, true);
4638 size_t nEntries = rxCondFormat->size();
4639 for(size_t i = 0; i < nEntries; ++i)
4641 const ScFormatEntry* pFormatEntry = rxCondFormat->GetEntry(i);
4642 if(pFormatEntry->GetType()==ScFormatEntry::Type::Condition)
4644 const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry);
4645 OUStringBuffer aCond;
4646 ScAddress aPos = pEntry->GetSrcPos();
4647 switch(pEntry->GetOperation())
4649 case ScConditionMode::Equal:
4650 aCond.append('=');
4651 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4652 break;
4653 case ScConditionMode::Less:
4654 aCond.append('<');
4655 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4656 break;
4657 case ScConditionMode::Greater:
4658 aCond.append('>');
4659 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4660 break;
4661 case ScConditionMode::EqLess:
4662 aCond.append("<=");
4663 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4664 break;
4665 case ScConditionMode::EqGreater:
4666 aCond.append(">=");
4667 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4668 break;
4669 case ScConditionMode::NotEqual:
4670 aCond.append("!=");
4671 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4672 break;
4673 case ScConditionMode::Between:
4674 aCond.append("between(");
4675 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4676 aCond.append(',');
4677 aCond.append(pEntry->GetExpression(aPos, 1, 0, formula::FormulaGrammar::GRAM_ODFF));
4678 aCond.append(')');
4679 break;
4680 case ScConditionMode::NotBetween:
4681 aCond.append("not-between(");
4682 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4683 aCond.append(',');
4684 aCond.append(pEntry->GetExpression(aPos, 1, 0, formula::FormulaGrammar::GRAM_ODFF));
4685 aCond.append(')');
4686 break;
4687 case ScConditionMode::Duplicate:
4688 aCond.append("duplicate");
4689 break;
4690 case ScConditionMode::NotDuplicate:
4691 aCond.append("unique");
4692 break;
4693 case ScConditionMode::Direct:
4694 aCond.append("formula-is(");
4695 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4696 aCond.append(')');
4697 break;
4698 case ScConditionMode::Top10:
4699 aCond.append("top-elements(");
4700 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4701 aCond.append(")");
4702 break;
4703 case ScConditionMode::Bottom10:
4704 aCond.append("bottom-elements(");
4705 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4706 aCond.append(")");
4707 break;
4708 case ScConditionMode::TopPercent:
4709 aCond.append("top-percent(");
4710 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4711 aCond.append(")");
4712 break;
4713 case ScConditionMode::BottomPercent:
4714 aCond.append("bottom-percent(");
4715 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4716 aCond.append(")");
4717 break;
4718 case ScConditionMode::AboveAverage:
4719 aCond.append("above-average");
4720 break;
4721 case ScConditionMode::BelowAverage:
4722 aCond.append("below-average");
4723 break;
4724 case ScConditionMode::AboveEqualAverage:
4725 aCond.append("above-equal-average");
4726 break;
4727 case ScConditionMode::BelowEqualAverage:
4728 aCond.append("below-equal-average");
4729 break;
4730 case ScConditionMode::Error:
4731 aCond.append("is-error");
4732 break;
4733 case ScConditionMode::NoError:
4734 aCond.append("is-no-error");
4735 break;
4736 case ScConditionMode::BeginsWith:
4737 aCond.append("begins-with(");
4738 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4739 aCond.append(")");
4740 break;
4741 case ScConditionMode::EndsWith:
4742 aCond.append("ends-with(");
4743 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4744 aCond.append(")");
4745 break;
4746 case ScConditionMode::ContainsText:
4747 aCond.append("contains-text(");
4748 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4749 aCond.append(")");
4750 break;
4751 case ScConditionMode::NotContainsText:
4752 aCond.append("not-contains-text(");
4753 aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF));
4754 aCond.append(")");
4755 break;
4756 case ScConditionMode::NONE:
4757 continue;
4758 default:
4759 SAL_WARN("sc", "unimplemented conditional format export");
4761 OUString sStyle = ScStyleNameConversion::DisplayToProgrammaticName(pEntry->GetStyle(), SfxStyleFamily::Para);
4762 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_APPLY_STYLE_NAME, sStyle);
4763 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, aCond.makeStringAndClear());
4765 OUString sBaseAddress;
4766 ScRangeStringConverter::GetStringFromAddress( sBaseAddress, aPos, pDoc,formula::FormulaGrammar::CONV_ODF );
4767 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_BASE_CELL_ADDRESS, sBaseAddress);
4768 SvXMLElementExport aElementCondEntry(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITION, true, true);
4770 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Colorscale)
4772 SvXMLElementExport aElementColorScale(*this, XML_NAMESPACE_CALC_EXT, XML_COLOR_SCALE, true, true);
4773 const ScColorScaleFormat& rColorScale = static_cast<const ScColorScaleFormat&>(*pFormatEntry);
4774 for(const auto& rxItem : rColorScale)
4776 if(rxItem->GetType() == COLORSCALE_FORMULA)
4778 OUString sFormula = rxItem->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4779 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4781 else
4782 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(rxItem->GetValue()));
4784 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*rxItem));
4785 OUStringBuffer aBuffer;
4786 ::sax::Converter::convertColor(aBuffer, rxItem->GetColor());
4787 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLOR, aBuffer.makeStringAndClear());
4788 SvXMLElementExport aElementColorScaleEntry(*this, XML_NAMESPACE_CALC_EXT, XML_COLOR_SCALE_ENTRY, true, true);
4791 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Databar)
4793 const ScDataBarFormatData* pFormatData = static_cast<const ScDataBarFormat&>(*pFormatEntry).GetDataBarData();
4794 if(!pFormatData->mbGradient)
4795 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_GRADIENT, XML_FALSE);
4796 if(pFormatData->mbOnlyBar)
4797 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SHOW_VALUE, XML_FALSE);
4799 if (pFormatData->mnMinLength != 0.0)
4800 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MIN_LENGTH, OUString::number(pFormatData->mnMinLength));
4802 if (pFormatData->mnMaxLength != 0.0)
4803 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MAX_LENGTH, OUString::number(pFormatData->mnMaxLength));
4805 if(pFormatData->mbNeg)
4807 if(pFormatData->mxNegativeColor)
4809 OUStringBuffer aBuffer;
4810 ::sax::Converter::convertColor(aBuffer, *pFormatData->mxNegativeColor);
4811 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_NEGATIVE_COLOR, aBuffer.makeStringAndClear());
4813 else
4815 OUStringBuffer aBuffer;
4816 ::sax::Converter::convertColor(aBuffer, COL_LIGHTRED);
4817 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_NEGATIVE_COLOR, aBuffer.makeStringAndClear());
4821 if(pFormatData->meAxisPosition != databar::AUTOMATIC)
4823 if(pFormatData->meAxisPosition == databar::NONE)
4825 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_POSITION, OUString("none"));
4827 else
4829 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_POSITION, OUString("middle"));
4833 OUStringBuffer aBuffer;
4834 ::sax::Converter::convertColor(aBuffer, pFormatData->maPositiveColor);
4835 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_POSITIVE_COLOR, aBuffer.makeStringAndClear());
4837 aBuffer.truncate();
4838 ::sax::Converter::convertColor(aBuffer, pFormatData->maAxisColor);
4839 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_COLOR, aBuffer.makeStringAndClear());
4840 SvXMLElementExport aElementDataBar(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_BAR, true, true);
4843 if(pFormatData->mpLowerLimit->GetType() == COLORSCALE_FORMULA)
4845 OUString sFormula = pFormatData->mpLowerLimit->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4846 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4848 else
4849 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(pFormatData->mpLowerLimit->GetValue()));
4850 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*pFormatData->mpLowerLimit));
4851 SvXMLElementExport aElementDataBarEntryLower(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true);
4855 if(pFormatData->mpUpperLimit->GetType() == COLORSCALE_FORMULA)
4857 OUString sFormula = pFormatData->mpUpperLimit->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4858 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4860 else
4861 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(pFormatData->mpUpperLimit->GetValue()));
4862 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*pFormatData->mpUpperLimit, false));
4863 SvXMLElementExport aElementDataBarEntryUpper(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true);
4866 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Iconset)
4868 const ScIconSetFormat& rIconSet = static_cast<const ScIconSetFormat&>(*pFormatEntry);
4869 OUString aIconSetName = OUString::createFromAscii(ScIconSetFormat::getIconSetName(rIconSet.GetIconSetData()->eIconSetType));
4870 AddAttribute( XML_NAMESPACE_CALC_EXT, XML_ICON_SET_TYPE, aIconSetName );
4871 if (rIconSet.GetIconSetData()->mbCustom)
4872 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM, OUString::boolean(true));
4874 SvXMLElementExport aElementColorScale(*this, XML_NAMESPACE_CALC_EXT, XML_ICON_SET, true, true);
4876 if (rIconSet.GetIconSetData()->mbCustom)
4878 for (const auto& [rType, rIndex] : rIconSet.GetIconSetData()->maCustomVector)
4880 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET_NAME, OUString::createFromAscii(ScIconSetFormat::getIconSetName(rType)));
4881 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET_INDEX, OUString::number(rIndex));
4882 SvXMLElementExport aCustomIcon(*this, XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET, true, true);
4887 if(!rIconSet.GetIconSetData()->mbShowValue)
4888 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SHOW_VALUE, XML_FALSE);
4889 for (auto const& it : rIconSet)
4891 if(it->GetType() == COLORSCALE_FORMULA)
4893 OUString sFormula = it->GetFormula(formula::FormulaGrammar::GRAM_ODFF);
4894 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula);
4896 else
4897 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(it->GetValue()));
4899 AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*it));
4900 SvXMLElementExport aElementColorScaleEntry(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true);
4903 else if(pFormatEntry->GetType() == ScFormatEntry::Type::Date)
4905 const ScCondDateFormatEntry& rDateFormat = static_cast<const ScCondDateFormatEntry&>(*pFormatEntry);
4906 OUString aDateType = getDateStringForType(rDateFormat.GetDateType());
4907 OUString aStyleName = ScStyleNameConversion::DisplayToProgrammaticName(rDateFormat.GetStyleName(), SfxStyleFamily::Para );
4908 AddAttribute( XML_NAMESPACE_CALC_EXT, XML_STYLE, aStyleName);
4909 AddAttribute( XML_NAMESPACE_CALC_EXT, XML_DATE, aDateType);
4910 SvXMLElementExport aElementDateFormat(*this, XML_NAMESPACE_CALC_EXT, XML_DATE_IS, true, true);
4916 void ScXMLExport::WriteExternalRefCaches()
4918 if (!pDoc)
4919 return;
4921 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
4922 pRefMgr->resetSrcFileData(GetOrigFileName());
4923 sal_uInt16 nCount = pRefMgr->getExternalFileCount();
4924 for (sal_uInt16 nFileId = 0; nFileId < nCount; ++nFileId)
4926 const OUString* pUrl = pRefMgr->getExternalFileName(nFileId);
4927 if (!pUrl)
4928 continue;
4930 vector<OUString> aTabNames;
4931 pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
4932 if (aTabNames.empty())
4933 continue;
4935 for (const auto& rTabName : aTabNames)
4937 ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, rTabName, false);
4938 if (!pTable || !pTable->isReferenced())
4939 continue;
4941 AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, "'" + *pUrl + "'#" + rTabName);
4942 AddAttribute(XML_NAMESPACE_TABLE, XML_PRINT, GetXMLToken(XML_FALSE));
4943 AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sExternalRefTabStyleName);
4944 SvXMLElementExport aElemTable(*this, XML_NAMESPACE_TABLE, XML_TABLE, true, true);
4946 const ScExternalRefManager::SrcFileData* pExtFileData = pRefMgr->getExternalFileData(nFileId);
4947 if (pExtFileData)
4949 OUString aRelUrl;
4950 if (!pExtFileData->maRelativeName.isEmpty())
4951 aRelUrl = pExtFileData->maRelativeName;
4952 else
4953 aRelUrl = GetRelativeReference(pExtFileData->maRelativeName);
4954 AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
4955 AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aRelUrl);
4956 AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, rTabName);
4957 if (!pExtFileData->maFilterName.isEmpty())
4958 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, pExtFileData->maFilterName);
4959 if (!pExtFileData->maFilterOptions.isEmpty())
4960 AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, pExtFileData->maFilterOptions);
4961 AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY);
4963 SvXMLElementExport aElemTableSource(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, true, true);
4966 // Determine maximum column count of used area, for repeated cells.
4967 SCCOL nMaxColsUsed = 1; // assume that there is at least one cell somewhere...
4968 vector<SCROW> aRows;
4969 pTable->getAllRows(aRows);
4970 for (SCROW nRow : aRows)
4972 vector<SCCOL> aCols;
4973 pTable->getAllCols(nRow, aCols);
4974 if (!aCols.empty())
4976 SCCOL nCol = aCols.back();
4977 if (nMaxColsUsed <= nCol)
4978 nMaxColsUsed = nCol + 1;
4982 // Column definitions have to be present to make a valid file
4984 if (nMaxColsUsed > 1)
4985 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
4986 OUString::number(nMaxColsUsed));
4987 SvXMLElementExport aElemColumn(*this, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true);
4990 // Write cache content for this table.
4991 SCROW nLastRow = 0;
4992 bool bFirstRow = true;
4993 for (SCROW nRow : aRows)
4995 if (bFirstRow)
4997 if (nRow > 0)
4999 if (nRow > 1)
5001 OUString aVal = OUString::number(nRow);
5002 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal);
5004 SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true);
5005 OUString aVal = OUString::number(static_cast<sal_Int32>(nMaxColsUsed));
5006 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5007 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5010 else
5012 SCROW nRowGap = nRow - nLastRow;
5013 if (nRowGap > 1)
5015 if (nRowGap > 2)
5017 OUString aVal = OUString::number(static_cast<sal_Int32>(nRowGap-1));
5018 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal);
5020 SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true);
5021 OUString aVal = OUString::number(static_cast<sal_Int32>(nMaxColsUsed));
5022 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5023 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5026 SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true);
5028 vector<SCCOL> aCols;
5029 pTable->getAllCols(nRow, aCols);
5030 SCCOL nLastCol = 0;
5031 bool bFirstCol = true;
5032 for (SCCOL nCol : aCols)
5034 if (bFirstCol)
5036 if (nCol > 0)
5038 if (nCol > 1)
5040 OUString aVal = OUString::number(static_cast<sal_Int32>(nCol));
5041 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5043 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5046 else
5048 SCCOL nColGap = nCol - nLastCol;
5049 if (nColGap > 1)
5051 if (nColGap > 2)
5053 OUString aVal = OUString::number(static_cast<sal_Int32>(nColGap-1));
5054 AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal);
5056 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5060 // Write out this cell.
5061 sal_uInt32 nNumFmt = 0;
5062 ScExternalRefCache::TokenRef pToken = pTable->getCell(nCol, nRow, &nNumFmt);
5063 OUString aStrVal;
5064 if (pToken)
5066 sal_Int32 nIndex = GetNumberFormatStyleIndex(nNumFmt);
5067 if (nIndex >= 0)
5069 const OUString & aStyleName = pCellStyles->GetStyleNameByIndex(nIndex, true);
5070 AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, aStyleName);
5073 switch(pToken->GetType())
5075 case svDouble:
5077 AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT);
5078 OUStringBuffer aVal;
5079 aVal.append(pToken->GetDouble());
5080 aStrVal = aVal.makeStringAndClear();
5081 AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, aStrVal);
5083 break;
5084 case svString:
5086 AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING);
5087 aStrVal = pToken->GetString().getString();
5089 break;
5090 default:
5094 SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true);
5095 SvXMLElementExport aElemText(*this, XML_NAMESPACE_TEXT, XML_P, true, false);
5096 Characters(aStrVal);
5098 nLastCol = nCol;
5099 bFirstCol = false;
5101 nLastRow = nRow;
5102 bFirstRow = false;
5108 // core implementation
5109 void ScXMLExport::WriteConsolidation()
5111 if (!pDoc)
5112 return;
5114 const ScConsolidateParam* pCons(pDoc->GetConsolidateDlgData());
5115 if( !pCons )
5116 return;
5118 OUString sStrData = ScXMLConverter::GetStringFromFunction( pCons->eFunction );
5119 AddAttribute( XML_NAMESPACE_TABLE, XML_FUNCTION, sStrData );
5121 sStrData.clear();
5122 for( sal_Int32 nIndex = 0; nIndex < pCons->nDataAreaCount; ++nIndex )
5123 ScRangeStringConverter::GetStringFromArea( sStrData, pCons->pDataAreas[ nIndex ], pDoc, FormulaGrammar::CONV_OOO, ' ', true );
5124 AddAttribute( XML_NAMESPACE_TABLE, XML_SOURCE_CELL_RANGE_ADDRESSES, sStrData );
5126 ScRangeStringConverter::GetStringFromAddress( sStrData, ScAddress( pCons->nCol, pCons->nRow, pCons->nTab ), pDoc, FormulaGrammar::CONV_OOO );
5127 AddAttribute( XML_NAMESPACE_TABLE, XML_TARGET_CELL_ADDRESS, sStrData );
5129 if( pCons->bByCol && !pCons->bByRow )
5130 AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_COLUMN );
5131 else if( !pCons->bByCol && pCons->bByRow )
5132 AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_ROW );
5133 else if( pCons->bByCol && pCons->bByRow )
5134 AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_BOTH );
5136 if( pCons->bReferenceData )
5137 AddAttribute( XML_NAMESPACE_TABLE, XML_LINK_TO_SOURCE_DATA, XML_TRUE );
5139 SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_CONSOLIDATION, true, true );
5142 SvXMLAutoStylePoolP* ScXMLExport::CreateAutoStylePool()
5144 return new ScXMLAutoStylePoolP(*this);
5147 XMLPageExport* ScXMLExport::CreatePageExport()
5149 return new XMLTableMasterPageExport( *this );
5152 void ScXMLExport::GetChangeTrackViewSettings(uno::Sequence<beans::PropertyValue>& rProps)
5154 ScChangeViewSettings* pViewSettings(GetDocument() ? GetDocument()->GetChangeViewSettings() : nullptr);
5155 if (!pViewSettings)
5156 return;
5158 sal_Int32 nChangePos(rProps.getLength());
5159 rProps.realloc(nChangePos + 1);
5160 beans::PropertyValue* pProps(rProps.getArray());
5162 uno::Sequence<beans::PropertyValue> aChangeProps(SC_VIEWCHANGES_COUNT);
5163 beans::PropertyValue* pChangeProps(aChangeProps.getArray());
5164 pChangeProps[SC_SHOW_CHANGES].Name = "ShowChanges";
5165 pChangeProps[SC_SHOW_CHANGES].Value <<= pViewSettings->ShowChanges();
5166 pChangeProps[SC_SHOW_ACCEPTED_CHANGES].Name = "ShowAcceptedChanges";
5167 pChangeProps[SC_SHOW_ACCEPTED_CHANGES].Value <<= pViewSettings->IsShowAccepted();
5168 pChangeProps[SC_SHOW_REJECTED_CHANGES].Name = "ShowRejectedChanges";
5169 pChangeProps[SC_SHOW_REJECTED_CHANGES].Value <<= pViewSettings->IsShowRejected();
5170 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME].Name = "ShowChangesByDatetime";
5171 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME].Value <<= pViewSettings->HasDate();
5172 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_MODE].Name = "ShowChangesByDatetimeMode";
5173 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_MODE].Value <<= static_cast<sal_Int16>(pViewSettings->GetTheDateMode());
5174 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME].Name = "ShowChangesByDatetimeFirstDatetime";
5175 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME].Value <<= pViewSettings->GetTheFirstDateTime().GetUNODateTime();
5176 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME].Name = "ShowChangesByDatetimeSecondDatetime";
5177 pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME].Value <<= pViewSettings->GetTheLastDateTime().GetUNODateTime();
5178 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR].Name = "ShowChangesByAuthor";
5179 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR].Value <<= pViewSettings->HasAuthor();
5180 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR_NAME].Name = "ShowChangesByAuthorName";
5181 pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR_NAME].Value <<= pViewSettings->GetTheAuthorToShow();
5182 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT].Name = "ShowChangesByComment";
5183 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT].Value <<= pViewSettings->HasComment();
5184 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT_TEXT].Name = "ShowChangesByCommentText";
5185 pChangeProps[SC_SHOW_CHANGES_BY_COMMENT_TEXT].Value <<= pViewSettings->GetTheComment();
5186 pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Name = "ShowChangesByRanges";
5187 pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Value <<= pViewSettings->HasRange();
5188 OUString sRangeList;
5189 ScRangeStringConverter::GetStringFromRangeList(sRangeList, &(pViewSettings->GetTheRangeList()), GetDocument(), FormulaGrammar::CONV_OOO);
5190 pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Name = "ShowChangesByRangesList";
5191 pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Value <<= sRangeList;
5193 pProps[nChangePos].Name = "TrackedChangesViewSettings";
5194 pProps[nChangePos].Value <<= aChangeProps;
5197 void ScXMLExport::GetViewSettings(uno::Sequence<beans::PropertyValue>& rProps)
5199 if (GetModel().is())
5201 rProps.realloc(4);
5202 beans::PropertyValue* pProps(rProps.getArray());
5203 ScModelObj* pDocObj(comphelper::getFromUnoTunnel<ScModelObj>( GetModel() ));
5204 if (pDocObj)
5206 SfxObjectShell* pEmbeddedObj = pDocObj->GetEmbeddedObject();
5207 if (pEmbeddedObj)
5209 tools::Rectangle aRect(pEmbeddedObj->GetVisArea());
5210 sal_uInt16 i(0);
5211 pProps[i].Name = "VisibleAreaTop";
5212 pProps[i].Value <<= static_cast<sal_Int32>(aRect.Top());
5213 pProps[++i].Name = "VisibleAreaLeft";
5214 pProps[i].Value <<= static_cast<sal_Int32>(aRect.Left());
5215 pProps[++i].Name = "VisibleAreaWidth";
5216 pProps[i].Value <<= static_cast<sal_Int32>(aRect.getOpenWidth());
5217 pProps[++i].Name = "VisibleAreaHeight";
5218 pProps[i].Value <<= static_cast<sal_Int32>(aRect.getOpenHeight());
5222 GetChangeTrackViewSettings(rProps);
5225 void ScXMLExport::GetConfigurationSettings(uno::Sequence<beans::PropertyValue>& rProps)
5227 if (!GetModel().is())
5228 return;
5230 uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetModel(), uno::UNO_QUERY);
5231 if (!xMultiServiceFactory.is())
5232 return;
5234 uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance("com.sun.star.comp.SpreadsheetSettings"), uno::UNO_QUERY);
5235 if (xProperties.is())
5236 SvXMLUnitConverter::convertPropertySet(rProps, xProperties);
5238 sal_Int32 nPropsToAdd = 0;
5239 OUStringBuffer aTrackedChangesKey;
5240 if (GetDocument() && GetDocument()->GetChangeTrack() && GetDocument()->GetChangeTrack()->IsProtected())
5242 ::comphelper::Base64::encode(aTrackedChangesKey,
5243 GetDocument()->GetChangeTrack()->GetProtection());
5244 if (!aTrackedChangesKey.isEmpty())
5245 ++nPropsToAdd;
5248 bool bVBACompat = false;
5249 uno::Reference <container::XNameAccess> xCodeNameAccess;
5250 OSL_ENSURE( pDoc, "ScXMLExport::GetConfigurationSettings - no ScDocument!" );
5251 // tdf#71271 - add code names regardless of VBA compatibility mode
5252 if (pDoc)
5254 // VBA compatibility mode
5255 if (bVBACompat = pDoc->IsInVBAMode(); bVBACompat)
5256 ++nPropsToAdd;
5258 // code names
5259 xCodeNameAccess = new XMLCodeNameProvider( pDoc );
5260 if( xCodeNameAccess->hasElements() )
5261 ++nPropsToAdd;
5262 else
5263 xCodeNameAccess.clear();
5266 if( nPropsToAdd <= 0 )
5267 return;
5269 sal_Int32 nCount(rProps.getLength());
5270 rProps.realloc(nCount + nPropsToAdd);
5271 auto pProps = rProps.getArray();
5272 if (!aTrackedChangesKey.isEmpty())
5274 pProps[nCount].Name = "TrackedChangesProtectionKey";
5275 pProps[nCount].Value <<= aTrackedChangesKey.makeStringAndClear();
5276 ++nCount;
5278 if( bVBACompat )
5280 pProps[nCount].Name = "VBACompatibilityMode";
5281 pProps[nCount].Value <<= bVBACompat;
5282 ++nCount;
5284 if( xCodeNameAccess.is() )
5286 pProps[nCount].Name = "ScriptConfiguration";
5287 pProps[nCount].Value <<= xCodeNameAccess;
5288 ++nCount;
5292 XMLShapeExport* ScXMLExport::CreateShapeExport()
5294 return new ScXMLShapeExport(*this);
5297 XMLNumberFormatAttributesExportHelper* ScXMLExport::GetNumberFormatAttributesExportHelper()
5299 if (!pNumberFormatAttributesExportHelper)
5300 pNumberFormatAttributesExportHelper.reset(new XMLNumberFormatAttributesExportHelper(GetNumberFormatsSupplier(), *this ));
5301 return pNumberFormatAttributesExportHelper.get();
5304 void ScXMLExport::CollectUserDefinedNamespaces(const SfxItemPool* pPool, sal_uInt16 nAttrib)
5306 for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(nAttrib))
5308 const SvXMLAttrContainerItem *pUnknown(static_cast<const SvXMLAttrContainerItem *>(pItem));
5309 if( pUnknown->GetAttrCount() > 0 )
5311 sal_uInt16 nIdx(pUnknown->GetFirstNamespaceIndex());
5312 while( USHRT_MAX != nIdx )
5314 if( (XML_NAMESPACE_UNKNOWN_FLAG & nIdx) != 0 )
5316 const OUString& rPrefix = pUnknown->GetPrefix( nIdx );
5317 // Add namespace declaration for unknown attributes if
5318 // there aren't existing ones for the prefix used by the
5319 // attributes
5320 GetNamespaceMap_().Add( rPrefix,
5321 pUnknown->GetNamespace( nIdx ) );
5323 nIdx = pUnknown->GetNextNamespaceIndex( nIdx );
5328 // #i66550# needed for 'presentation:event-listener' element for URLs in shapes
5329 GetNamespaceMap_().Add(
5330 GetXMLToken( XML_NP_PRESENTATION ),
5331 GetXMLToken( XML_N_PRESENTATION ),
5332 XML_NAMESPACE_PRESENTATION );
5335 void ScXMLExport::IncrementProgressBar(bool bFlush, sal_Int32 nInc)
5337 nProgressCount += nInc;
5338 if (bFlush || nProgressCount > 100)
5340 GetProgressBarHelper()->Increment(nProgressCount);
5341 nProgressCount = 0;
5345 ErrCode ScXMLExport::exportDoc( enum XMLTokenEnum eClass )
5347 if( getExportFlags() & (SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::STYLES|
5348 SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) )
5350 if (GetDocument())
5352 // if source doc was Excel then
5353 uno::Reference< frame::XModel > xModel = GetModel();
5354 if ( xModel.is() )
5356 auto pFoundShell = comphelper::getFromUnoTunnel<SfxObjectShell>(xModel);
5357 if ( pFoundShell && ooo::vba::isAlienExcelDoc( *pFoundShell ) )
5359 xRowStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScFromXLSRowStylesProperties, xScPropHdlFactory, true);
5360 xRowStylesExportPropertySetMapper = new ScXMLRowExportPropertyMapper(xRowStylesPropertySetMapper);
5361 GetAutoStylePool()->SetFamilyPropSetMapper( XmlStyleFamily::TABLE_ROW,
5362 xRowStylesExportPropertySetMapper );
5365 CollectUserDefinedNamespaces(GetDocument()->GetPool(), ATTR_USERDEF);
5366 CollectUserDefinedNamespaces(GetDocument()->GetEditPool(), EE_PARA_XMLATTRIBS);
5367 CollectUserDefinedNamespaces(GetDocument()->GetEditPool(), EE_CHAR_XMLATTRIBS);
5368 ScDrawLayer* pDrawLayer = GetDocument()->GetDrawLayer();
5369 if (pDrawLayer)
5371 CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), EE_PARA_XMLATTRIBS);
5372 CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), EE_CHAR_XMLATTRIBS);
5373 CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), SDRATTR_XMLATTRIBUTES);
5376 // sheet events use officeooo namespace
5377 if( (getExportFlags() & SvXMLExportFlags::CONTENT) &&
5378 getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
5380 bool bAnySheetEvents = false;
5381 SCTAB nTabCount = pDoc->GetTableCount();
5382 for (SCTAB nTab=0; nTab<nTabCount; ++nTab)
5383 if (pDoc->GetSheetEvents(nTab))
5384 bAnySheetEvents = true;
5385 if (bAnySheetEvents)
5386 GetNamespaceMap_().Add(
5387 GetXMLToken( XML_NP_OFFICE_EXT ),
5388 GetXMLToken( XML_N_OFFICE_EXT ),
5389 XML_NAMESPACE_OFFICE_EXT );
5393 return SvXMLExport::exportDoc( eClass );
5396 // XExporter
5397 void SAL_CALL ScXMLExport::setSourceDocument( const uno::Reference<lang::XComponent>& xComponent )
5399 SolarMutexGuard aGuard;
5400 SvXMLExport::setSourceDocument( xComponent );
5402 pDoc = ScXMLConverter::GetScDocument( GetModel() );
5403 OSL_ENSURE( pDoc, "ScXMLExport::setSourceDocument - no ScDocument!" );
5404 if (!pDoc)
5405 throw lang::IllegalArgumentException();
5407 // create ScChangeTrackingExportHelper after document is known
5408 pChangeTrackingExportHelper.reset(new ScChangeTrackingExportHelper(*this));
5410 // Set the document's storage grammar corresponding to the ODF version that
5411 // is to be written.
5412 SvtSaveOptions::ODFSaneDefaultVersion meODFDefaultVersion = getSaneDefaultVersion();
5413 switch (meODFDefaultVersion)
5415 // ODF 1.0 and 1.1 use GRAM_PODF, everything later or unspecified GRAM_ODFF
5416 case SvtSaveOptions::ODFSVER_010:
5417 case SvtSaveOptions::ODFSVER_011:
5418 pDoc->SetStorageGrammar( formula::FormulaGrammar::GRAM_PODF);
5419 break;
5420 default:
5421 pDoc->SetStorageGrammar( formula::FormulaGrammar::GRAM_ODFF);
5425 // XFilter
5426 sal_Bool SAL_CALL ScXMLExport::filter( const css::uno::Sequence< css::beans::PropertyValue >& aDescriptor )
5428 SolarMutexGuard aGuard;
5429 if (pDoc)
5430 pDoc->EnableIdle(false);
5431 bool bReturn(SvXMLExport::filter(aDescriptor));
5432 if (pDoc)
5433 pDoc->EnableIdle(true);
5434 return bReturn;
5437 void SAL_CALL ScXMLExport::cancel()
5439 SolarMutexGuard aGuard;
5440 if (pDoc)
5441 pDoc->EnableIdle(true);
5442 SvXMLExport::cancel();
5445 // XInitialization
5446 void SAL_CALL ScXMLExport::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
5448 SolarMutexGuard aGuard;
5449 SvXMLExport::initialize(aArguments);
5452 // XUnoTunnel
5453 sal_Int64 SAL_CALL ScXMLExport::getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier )
5455 SolarMutexGuard aGuard;
5456 return SvXMLExport::getSomething(aIdentifier);
5459 void ScXMLExport::DisposingModel()
5461 SvXMLExport::DisposingModel();
5462 pDoc = nullptr;
5463 xCurrentTable = nullptr;
5466 void ScXMLExport::SetSharedData(std::unique_ptr<ScMySharedData> pTemp) { pSharedData = std::move(pTemp); }
5468 std::unique_ptr<ScMySharedData> ScXMLExport::ReleaseSharedData() { return std::move(pSharedData); }
5469 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */