diff options
Diffstat (limited to 'sc/source/filter/xml/xmlexprt.cxx')
-rw-r--r-- | sc/source/filter/xml/xmlexprt.cxx | 5454 |
1 files changed, 5454 insertions, 0 deletions
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx new file mode 100644 index 000000000..37b155bf9 --- /dev/null +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -0,0 +1,5454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include "xmlexprt.hxx" +#include "XMLConverter.hxx" +#include "xmlstyle.hxx" +#include <unonames.hxx> +#include <document.hxx> +#include <olinetab.hxx> +#include <formulacell.hxx> +#include <rangenam.hxx> +#include "XMLTableMasterPageExport.hxx" +#include <drwlayer.hxx> +#include "XMLExportDataPilot.hxx" +#include "XMLExportDatabaseRanges.hxx" +#include "XMLExportDDELinks.hxx" +#include "XMLExportIterator.hxx" +#include "XMLColumnRowGroupExport.hxx" +#include "XMLStylesExportHelper.hxx" +#include "XMLChangeTrackingExportHelper.hxx" +#include <sheetdata.hxx> +#include <docoptio.hxx> +#include "XMLExportSharedData.hxx" +#include <chgviset.hxx> +#include <docuno.hxx> +#include <textuno.hxx> +#include <chartlis.hxx> +#include <scitems.hxx> +#include <docpool.hxx> +#include <userdat.hxx> +#include <chgtrack.hxx> +#include <rangeutl.hxx> +#include <postit.hxx> +#include <externalrefmgr.hxx> +#include <editutil.hxx> +#include <tabprotection.hxx> +#include "cachedattraccess.hxx" +#include <colorscale.hxx> +#include <conditio.hxx> +#include <cellvalue.hxx> +#include <stylehelper.hxx> +#include <edittextiterator.hxx> +#include "editattributemap.hxx" +#include <arealink.hxx> +#include <datastream.hxx> +#include <documentlinkmgr.hxx> +#include <tokenstringcontext.hxx> +#include <cellform.hxx> +#include <datamapper.hxx> +#include <datatransformation.hxx> +#include "SparklineGroupsExport.hxx" +#include <SparklineList.hxx> + +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnamespace.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/namespacemap.hxx> +#include <xmloff/families.hxx> +#include <xmloff/numehelp.hxx> +#include <xmloff/txtparae.hxx> +#include <editeng/autokernitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/emphasismarkitem.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/section.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <editeng/flditem.hxx> +#include <editeng/eeitem.hxx> +#include <formula/errorcodes.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/XMLEventExport.hxx> +#include <xmloff/xmlprmap.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include <xmloff/table/XMLTableExport.hxx> + +#include <sax/tools/converter.hxx> +#include <tools/fldunit.hxx> + +#include <rtl/ustring.hxx> + +#include <tools/color.hxx> +#include <tools/diagnose_ex.h> +#include <rtl/math.hxx> +#include <svl/numformat.hxx> +#include <svl/zforlist.hxx> +#include <comphelper/base64.hxx> +#include <comphelper/extract.hxx> +#include <svx/svdoashp.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdocapt.hxx> +#include <vcl/svapp.hxx> + +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/form/XFormsSupplier2.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/sheet/XUsedAreaCursor.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XPrintAreas.hpp> +#include <com/sun/star/sheet/XUniqueCellFormatRangesSupplier.hpp> +#include <com/sun/star/sheet/XLabelRange.hpp> +#include <com/sun/star/sheet/NamedRangeFlag.hpp> +#include <com/sun/star/sheet/XSheetCellCursor.hpp> +#include <com/sun/star/sheet/XSheetCellRanges.hpp> +#include <com/sun/star/sheet/XSheetLinkable.hpp> +#include <com/sun/star/sheet/GlobalSheetSettings.hpp> +#include <com/sun/star/table/XColumnRowRange.hpp> +#include <com/sun/star/util/XProtectable.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/data/XRangeXMLConversion.hpp> +#include <com/sun/star/chart2/data/XDataReceiver.hpp> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> + +#include "XMLCodeNameProvider.hxx" + +#include <sfx2/linkmgr.hxx> +#include <sfx2/objsh.hxx> + +#include <memory> +#include <vector> +#include <vbahelper/vbaaccesshelper.hxx> +#include <officecfg/Office/Common.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + + + +//! not found in unonames.hxx +constexpr OUStringLiteral SC_LAYERID = u"LayerID"; + +#define SC_VIEWCHANGES_COUNT 13 +#define SC_SHOW_CHANGES 0 +#define SC_SHOW_ACCEPTED_CHANGES 1 +#define SC_SHOW_REJECTED_CHANGES 2 +#define SC_SHOW_CHANGES_BY_DATETIME 3 +#define SC_SHOW_CHANGES_BY_DATETIME_MODE 4 +#define SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME 5 +#define SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME 6 +#define SC_SHOW_CHANGES_BY_AUTHOR 7 +#define SC_SHOW_CHANGES_BY_AUTHOR_NAME 8 +#define SC_SHOW_CHANGES_BY_COMMENT 9 +#define SC_SHOW_CHANGES_BY_COMMENT_TEXT 10 +#define SC_SHOW_CHANGES_BY_RANGES 11 +#define SC_SHOW_CHANGES_BY_RANGES_LIST 12 + +using namespace formula; +using namespace com::sun::star; +using namespace xmloff::token; +using ::std::vector; +using ::com::sun::star::uno::UNO_QUERY; + +namespace +{ +OUString lcl_RangeSequenceToString( + const uno::Sequence< OUString > & rRanges, + const uno::Reference< chart2::data::XRangeXMLConversion > & xFormatConverter ) +{ + OUStringBuffer aResult; + const sal_Int32 nMaxIndex( rRanges.getLength() - 1 ); + const sal_Unicode cSep(' '); + for( sal_Int32 i=0; i<=nMaxIndex; ++i ) + { + OUString aRange( rRanges[i] ); + if( xFormatConverter.is()) + aRange = xFormatConverter->convertRangeToXML( aRange ); + aResult.append( aRange ); + if( i < nMaxIndex ) + aResult.append( cSep ); + } + return aResult.makeStringAndClear(); +} + +OUString lcl_GetFormattedString(ScDocument* pDoc, const ScRefCellValue& rCell, const ScAddress& rAddr) +{ + // return text/edit cell string content, with line feeds in edit cells + + if (!pDoc) + return OUString(); + + switch (rCell.meType) + { + case CELLTYPE_STRING: + { + const Color* pColor; + SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); + + sal_uInt32 nFormat = pDoc->GetNumberFormat(rAddr); + return ScCellFormat::GetString(rCell, nFormat, &pColor, *pFormatter, *pDoc); + } + case CELLTYPE_EDIT: + { + const EditTextObject* pData = rCell.mpEditText; + if (!pData) + return OUString(); + + EditEngine& rEngine = pDoc->GetEditEngine(); + rEngine.SetText(*pData); + return rEngine.GetText(); + } + break; + default: + ; + } + + return OUString(); +} + +} // anonymous namespace + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLExporter", SvXMLExportFlags::ALL)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLMetaExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLMetaExporter", SvXMLExportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLStylesExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLStylesExporter", SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLContentExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLContentExporter", SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLSettingsExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLSettingsExporter", SvXMLExportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLOasisExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisExporter", SvXMLExportFlags::ALL|SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLOasisMetaExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisMetaExporter", SvXMLExportFlags::META|SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLOasisStylesExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisStylesExporter", SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLOasisContentExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisContentExporter", SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +Calc_XMLOasisSettingsExporter_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ScXMLExport(context, "com.sun.star.comp.Calc.XMLOasisSettingsExporter", SvXMLExportFlags::SETTINGS|SvXMLExportFlags::OASIS)); +} + +namespace { + +class ScXMLShapeExport : public XMLShapeExport +{ +public: + explicit ScXMLShapeExport(SvXMLExport& rExp) + : XMLShapeExport(rExp, + // chain text attributes + XMLTextParagraphExport::CreateParaExtPropMapper(rExp)) + { + } + + /** is called before a shape element for the given XShape is exported */ + virtual void onExport( const uno::Reference < drawing::XShape >& xShape ) override; +}; + +} + +void ScXMLShapeExport::onExport( const uno::Reference < drawing::XShape >& xShape ) +{ + uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + if( xShapeProp.is() ) + { + sal_Int16 nLayerID = 0; + if( (xShapeProp->getPropertyValue( SC_LAYERID ) >>= nLayerID) && (SdrLayerID(nLayerID) == SC_LAYER_BACK) ) + GetExport().AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_BACKGROUND, XML_TRUE); + } +} + +sal_Int16 ScXMLExport::GetMeasureUnit() +{ + css::uno::Reference<css::sheet::XGlobalSheetSettings> xProperties = + css::sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() ); + const FieldUnit eFieldUnit = static_cast<FieldUnit>(xProperties->getMetric()); + return SvXMLUnitConverter::GetMeasureUnit(eFieldUnit); +} + +ScXMLExport::ScXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& rContext, + OUString const & implementationName, SvXMLExportFlags nExportFlag) +: SvXMLExport( + rContext, implementationName, GetMeasureUnit(), XML_SPREADSHEET, nExportFlag ), + pDoc(nullptr), + nSourceStreamPos(0), + pCurrentCell(nullptr), + nOpenRow(-1), + nProgressCount(0), + nCurrentTable(0), + bHasRowHeader(false), + bRowHeaderOpen(false) +{ + if (getExportFlags() & SvXMLExportFlags::CONTENT) + { + pGroupColumns.reset( new ScMyOpenCloseColumnRowGroup(*this, XML_TABLE_COLUMN_GROUP) ); + pGroupRows.reset( new ScMyOpenCloseColumnRowGroup(*this, XML_TABLE_ROW_GROUP) ); + pColumnStyles.reset( new ScColumnStyles() ); + pRowStyles.reset( new ScRowStyles() ); + pRowFormatRanges.reset( new ScRowFormatRanges() ); + pMergedRangesContainer.reset( new ScMyMergedRangesContainer() ); + pValidationsContainer.reset( new ScMyValidationsContainer() ); + mpCellsItr.reset(new ScMyNotEmptyCellsIterator(*this)); + pDefaults.reset( new ScMyDefaultStyles ); + } + pCellStyles.reset( new ScFormatRangeStyles() ); + + // document is not set here - create ScChangeTrackingExportHelper later + + xScPropHdlFactory = new XMLScPropHdlFactory; + xCellStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScCellStylesProperties, xScPropHdlFactory, true); + xColumnStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScColumnStylesProperties, xScPropHdlFactory, true); + xRowStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScRowStylesProperties, xScPropHdlFactory, true); + xTableStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScTableStylesProperties, xScPropHdlFactory, true); + xCellStylesExportPropertySetMapper = new ScXMLCellExportPropertyMapper(xCellStylesPropertySetMapper); + xCellStylesExportPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(*this)); + xColumnStylesExportPropertySetMapper = new ScXMLColumnExportPropertyMapper(xColumnStylesPropertySetMapper); + xRowStylesExportPropertySetMapper = new ScXMLRowExportPropertyMapper(xRowStylesPropertySetMapper); + xTableStylesExportPropertySetMapper = new ScXMLTableExportPropertyMapper(xTableStylesPropertySetMapper); + + GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_CELL, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, + xCellStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX); + GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_COLUMN, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME, + xColumnStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX); + GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_ROW, XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME, + xRowStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX); + GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_TABLE, XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME, + xTableStylesExportPropertySetMapper, XML_STYLE_FAMILY_TABLE_TABLE_STYLES_PREFIX); + + if( !(getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT)) ) + return; + + // This name is reserved for the external ref cache tables. This + // should not conflict with user-defined styles since this name is + // used for a table style which is not available in the UI. + sExternalRefTabStyleName = "ta_extref"; + GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_TABLE, sExternalRefTabStyleName); + + sAttrName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NAME)); + sAttrStyleName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_STYLE_NAME)); + sAttrColumnsRepeated = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NUMBER_COLUMNS_REPEATED)); + sAttrFormula = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_FORMULA)); + sAttrStringValue = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_STRING_VALUE)); + sAttrValueType = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_VALUE_TYPE)); + sElemCell = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_CELL)); + sElemCoveredCell = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_COVERED_TABLE_CELL)); + sElemCol = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_COLUMN)); + sElemRow = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE_ROW)); + sElemTab = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_TABLE)); + sElemP = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TEXT, GetXMLToken(XML_P)); +} + +ScXMLExport::~ScXMLExport() +{ + pGroupColumns.reset(); + pGroupRows.reset(); + pColumnStyles.reset(); + pRowStyles.reset(); + pCellStyles.reset(); + pRowFormatRanges.reset(); + pMergedRangesContainer.reset(); + pValidationsContainer.reset(); + pChangeTrackingExportHelper.reset(); + pDefaults.reset(); + pNumberFormatAttributesExportHelper.reset(); +} + +void ScXMLExport::SetSourceStream( const uno::Reference<io::XInputStream>& xNewStream ) +{ + xSourceStream = xNewStream; + + if ( !xSourceStream.is() ) + return; + + // make sure it's a plain UTF-8 stream as written by OOo itself + + const char pXmlHeader[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + sal_Int32 nLen = strlen(pXmlHeader); + + uno::Sequence<sal_Int8> aFileStart(nLen); + sal_Int32 nRead = xSourceStream->readBytes( aFileStart, nLen ); + + if ( nRead != nLen || memcmp( aFileStart.getConstArray(), pXmlHeader, nLen ) != 0 ) + { + // invalid - ignore stream, save normally + xSourceStream.clear(); + } + else + { + // keep track of the bytes already read + nSourceStreamPos = nRead; + + const ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(GetModel())->GetSheetSaveData(); + if (pSheetData) + { + // add the loaded namespaces to the name space map + + if ( !pSheetData->AddLoadedNamespaces( GetNamespaceMap_() ) ) + { + // conflicts in the namespaces - ignore the stream, save normally + xSourceStream.clear(); + } + } + } +} + +sal_Int32 ScXMLExport::GetNumberFormatStyleIndex(sal_Int32 nNumFmt) const +{ + NumberFormatIndexMap::const_iterator itr = aNumFmtIndexMap.find(nNumFmt); + if (itr == aNumFmtIndexMap.end()) + return -1; + + return itr->second; +} + +void ScXMLExport::CollectSharedData(SCTAB& nTableCount, sal_Int32& nShapesCount) +{ + if (!GetModel().is()) + return; + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc(GetModel(), uno::UNO_QUERY); + if (!xSpreadDoc.is()) + return; + + uno::Reference<container::XIndexAccess> xIndex(xSpreadDoc->getSheets(), uno::UNO_QUERY); + if (!xIndex.is()) + return; + + nTableCount = xIndex->getCount(); + if (!pSharedData) + pSharedData.reset(new ScMySharedData(nTableCount)); + + pCellStyles->AddNewTable(nTableCount - 1); + + for (SCTAB nTable = 0; nTable < nTableCount; ++nTable) + { + nCurrentTable = sal::static_int_cast<sal_uInt16>(nTable); + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xIndex->getByIndex(nTable), uno::UNO_QUERY); + if (!xDrawPageSupplier.is()) + continue; + + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage()); + ScMyDrawPage aDrawPage; + aDrawPage.bHasForms = false; + aDrawPage.xDrawPage.set(xDrawPage); + pSharedData->AddDrawPage(aDrawPage, nTable); + if (!xDrawPage.is()) + continue; + + sal_Int32 nShapes = xDrawPage->getCount(); + for (sal_Int32 nShape = 0; nShape < nShapes; ++nShape) + { + uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShape), uno::UNO_QUERY); + if (!xShape.is()) + continue; + + uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY); + if (!xShapeProp.is()) + continue; + + sal_Int16 nLayerID = 0; + bool bExtracted = xShapeProp->getPropertyValue(SC_LAYERID) >>= nLayerID; + if (!bExtracted) + continue; + + if ((SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN)) + { + CollectInternalShape(xShape); + continue; + } + + ++nShapesCount; + + SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape); + if (!pSdrObj) + continue; + + if (ScDrawObjData *pAnchor = ScDrawLayer::GetNonRotatedObjData(pSdrObj)) + { + ScMyShape aMyShape; + aMyShape.aAddress = pAnchor->maStart; + SAL_WARN_IF(aMyShape.aAddress.Tab() != nTable, "sc", "not anchored to current sheet!"); + aMyShape.aAddress.SetTab(nTable); + aMyShape.aEndAddress = pAnchor->maEnd; + aMyShape.aEndAddress.SetTab( nTable ); + aMyShape.nEndX = pAnchor->maEndOffset.X(); + aMyShape.nEndY = pAnchor->maEndOffset.Y(); + aMyShape.xShape = xShape; + aMyShape.bResizeWithCell = ScDrawLayer::IsResizeWithCell(*pSdrObj); + pSharedData->AddNewShape(aMyShape); + pSharedData->SetLastColumn(nTable, pAnchor->maStart.Col()); + pSharedData->SetLastRow(nTable, pAnchor->maStart.Row()); + } + else + pSharedData->AddTableShape(nTable, xShape); + } + } +} + +void ScXMLExport::CollectShapesAutoStyles(SCTAB nTableCount) +{ + // #i84077# To avoid compiler warnings about uninitialized aShapeItr, + // it's initialized using this dummy list. The iterator contains shapes + // from all sheets, so it can't be declared inside the nTable loop where + // it is used. + ScMyShapeList aDummyInitList; + + pSharedData->SortShapesContainer(); + pSharedData->SortNoteShapes(); + const ScMyShapeList* pShapeList(nullptr); + ScMyShapeList::const_iterator aShapeItr = aDummyInitList.end(); + if (pSharedData->GetShapesContainer()) + { + pShapeList = &pSharedData->GetShapesContainer()->GetShapes(); + aShapeItr = pShapeList->begin(); + } + if (pSharedData->HasDrawPage()) + { + for (SCTAB nTable = 0; nTable < nTableCount; ++nTable) + { + uno::Reference<drawing::XDrawPage> xDrawPage(pSharedData->GetDrawPage(nTable)); + + if (xDrawPage.is()) + { + GetShapeExport()->seekShapes(xDrawPage); + uno::Reference< form::XFormsSupplier2 > xFormsSupplier( xDrawPage, uno::UNO_QUERY ); + if( xFormsSupplier.is() && xFormsSupplier->hasForms() ) + { + GetFormExport()->examineForms(xDrawPage); + pSharedData->SetDrawPageHasForms(nTable, true); + } + ScMyTableShapes* pTableShapes(pSharedData->GetTableShapes()); + if (pTableShapes) + { + for (const auto& rxShape : (*pTableShapes)[nTable]) + { + GetShapeExport()->collectShapeAutoStyles(rxShape); + IncrementProgressBar(false); + } + } + if (pShapeList) + { + ScMyShapeList::const_iterator aEndItr(pShapeList->end()); + while ( aShapeItr != aEndItr && ( aShapeItr->aAddress.Tab() == nTable ) ) + { + GetShapeExport()->collectShapeAutoStyles(aShapeItr->xShape); + IncrementProgressBar(false); + ++aShapeItr; + } + } + if (pSharedData->GetNoteShapes()) + { + const ScMyNoteShapeList& rNoteShapes = pSharedData->GetNoteShapes()->GetNotes(); + for (const auto& rNoteShape : rNoteShapes) + { + if ( rNoteShape.aPos.Tab() == nTable ) + GetShapeExport()->collectShapeAutoStyles(rNoteShape.xShape); + } + } + } + } + } + pSharedData->SortNoteShapes(); // sort twice, because some more shapes are added +} + +void ScXMLExport::ExportMeta_() +{ + sal_Int32 nCellCount(pDoc ? pDoc->GetCellCount() : 0); + SCTAB nTableCount(0); + sal_Int32 nShapesCount(0); + GetAutoStylePool()->ClearEntries(); + CollectSharedData(nTableCount, nShapesCount); + + uno::Sequence<beans::NamedValue> stats + { + { "TableCount", uno::Any(static_cast<sal_Int32>(nTableCount)) }, + { "CellCount", uno::Any(nCellCount) }, + { "ObjectCount", uno::Any(nShapesCount) } + }; + + // update document statistics at the model + uno::Reference<document::XDocumentPropertiesSupplier> xPropSup(GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xPropSup->getDocumentProperties()); + if (xDocProps.is()) { + xDocProps->setDocumentStatistics(stats); + } + + // export document properties + SvXMLExport::ExportMeta_(); +} + +void ScXMLExport::ExportFontDecls_() +{ + GetFontAutoStylePool(); // make sure the pool is created + SvXMLExport::ExportFontDecls_(); +} + +table::CellRangeAddress ScXMLExport::GetEndAddress(const uno::Reference<sheet::XSpreadsheet>& xTable) +{ + table::CellRangeAddress aCellAddress; + uno::Reference<sheet::XSheetCellCursor> xCursor(xTable->createCursor()); + uno::Reference<sheet::XUsedAreaCursor> xUsedArea (xCursor, uno::UNO_QUERY); + uno::Reference<sheet::XCellRangeAddressable> xCellAddress (xCursor, uno::UNO_QUERY); + if (xUsedArea.is() && xCellAddress.is()) + { + xUsedArea->gotoEndOfUsedArea(true); + aCellAddress = xCellAddress->getRangeAddress(); + } + return aCellAddress; +} + +void ScXMLExport::GetAreaLinks( ScMyAreaLinksContainer& rAreaLinks ) +{ + if (pDoc->GetLinkManager()) + { + const sfx2::SvBaseLinks& rLinks = pDoc->GetLinkManager()->GetLinks(); + for (const auto & rLink : rLinks) + { + ScAreaLink *pLink = dynamic_cast<ScAreaLink*>(rLink.get()); + if (pLink) + { + ScMyAreaLink aAreaLink; + aAreaLink.aDestRange = pLink->GetDestArea(); + aAreaLink.sSourceStr = pLink->GetSource(); + aAreaLink.sFilter = pLink->GetFilter(); + aAreaLink.sFilterOptions = pLink->GetOptions(); + aAreaLink.sURL = pLink->GetFile(); + aAreaLink.nRefreshDelaySeconds = pLink->GetRefreshDelaySeconds(); + rAreaLinks.AddNewAreaLink( aAreaLink ); + } + } + } + rAreaLinks.Sort(); +} + +// core implementation +void ScXMLExport::GetDetectiveOpList( ScMyDetectiveOpContainer& rDetOp ) +{ + if (!pDoc) + return; + + ScDetOpList* pOpList(pDoc->GetDetOpList()); + if( !pOpList ) + return; + + size_t nCount = pOpList->Count(); + for (size_t nIndex = 0; nIndex < nCount; ++nIndex ) + { + const ScDetOpData& rDetData = pOpList->GetObject( nIndex); + const ScAddress& rDetPos = rDetData.GetPos(); + SCTAB nTab = rDetPos.Tab(); + if ( nTab < pDoc->GetTableCount() ) + { + rDetOp.AddOperation( rDetData.GetOperation(), rDetPos, static_cast<sal_uInt32>( nIndex) ); + + // cells with detective operations are written even if empty + pSharedData->SetLastColumn( nTab, rDetPos.Col() ); + pSharedData->SetLastRow( nTab, rDetPos.Row() ); + } + } + rDetOp.Sort(); +} + +void ScXMLExport::WriteSingleColumn(const sal_Int32 nRepeatColumns, const sal_Int32 nStyleIndex, + const sal_Int32 nIndex, const bool bIsAutoStyle, const bool bIsVisible) +{ + CheckAttrList(); + // tdf#138466 + if (nStyleIndex != -1) + AddAttribute(sAttrStyleName, pColumnStyles->GetStyleNameByIndex(nStyleIndex)); + if (!bIsVisible) + AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_COLLAPSE); + if (nRepeatColumns > 1) + { + OUString sOUEndCol(OUString::number(nRepeatColumns)); + AddAttribute(sAttrColumnsRepeated, sOUEndCol); + } + if (nIndex != -1) + AddAttribute(XML_NAMESPACE_TABLE, XML_DEFAULT_CELL_STYLE_NAME, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle)); + SvXMLElementExport aElemC(*this, sElemCol, true, true); +} + +void ScXMLExport::WriteColumn(const sal_Int32 nColumn, const sal_Int32 nRepeatColumns, + const sal_Int32 nStyleIndex, const bool bIsVisible) +{ + sal_Int32 nRepeat(1); + sal_Int32 nPrevIndex(pDefaults->GetColDefaults()[nColumn].nIndex); + bool bPrevAutoStyle(pDefaults->GetColDefaults()[nColumn].bIsAutoStyle); + for (sal_Int32 i = nColumn + 1; i < nColumn + nRepeatColumns; ++i) + { + if ((pDefaults->GetColDefaults()[i].nIndex != nPrevIndex) || + (pDefaults->GetColDefaults()[i].bIsAutoStyle != bPrevAutoStyle)) + { + WriteSingleColumn(nRepeat, nStyleIndex, nPrevIndex, bPrevAutoStyle, bIsVisible); + nPrevIndex = pDefaults->GetColDefaults()[i].nIndex; + bPrevAutoStyle = pDefaults->GetColDefaults()[i].bIsAutoStyle; + nRepeat = 1; + } + else + ++nRepeat; + } + WriteSingleColumn(nRepeat, nStyleIndex, nPrevIndex, bPrevAutoStyle, bIsVisible); +} + +void ScXMLExport::OpenHeaderColumn() +{ + StartElement( XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true ); +} + +void ScXMLExport::CloseHeaderColumn() +{ + EndElement(XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true); +} + +void ScXMLExport::ExportColumns(const sal_Int32 nTable, const ScRange& aColumnHeaderRange, const bool bHasColumnHeader) +{ + sal_Int32 nColsRepeated (1); + sal_Int32 nIndex; + sal_Int32 nPrevColumn(0); + bool bPrevIsVisible (true); + bool bWasHeader (false); + bool bIsClosed (true); + sal_Int32 nPrevIndex (-1); + sal_Int32 nColumn; + for (nColumn = 0; nColumn <= pSharedData->GetLastColumn(nTable); ++nColumn) + { + CheckAttrList(); + bool bIsVisible(true); + nIndex = pColumnStyles->GetStyleNameIndex(nTable, nColumn, bIsVisible); + + const bool bIsHeader = bHasColumnHeader && (aColumnHeaderRange.aStart.Col() <= nColumn) && (nColumn <= aColumnHeaderRange.aEnd.Col()); + if (bIsHeader != bWasHeader) + { + if (bIsHeader) + { + if (nColumn > 0) + { + WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible); + if (pGroupColumns->IsGroupEnd(nColumn - 1)) + pGroupColumns->CloseGroups(nColumn - 1); + } + bPrevIsVisible = bIsVisible; + nPrevIndex = nIndex; + nPrevColumn = nColumn; + nColsRepeated = 1; + if(pGroupColumns->IsGroupStart(nColumn)) + pGroupColumns->OpenGroups(nColumn); + OpenHeaderColumn(); + bWasHeader = true; + bIsClosed = false; + } + else + { + WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible); + CloseHeaderColumn(); + if (pGroupColumns->IsGroupEnd(nColumn - 1)) + pGroupColumns->CloseGroups(nColumn - 1); + if(pGroupColumns->IsGroupStart(nColumn)) + pGroupColumns->OpenGroups(nColumn); + bPrevIsVisible = bIsVisible; + nPrevIndex = nIndex; + nPrevColumn = nColumn; + nColsRepeated = 1; + bWasHeader = false; + bIsClosed = true; + } + } + else if (nColumn == 0) + { + if (pGroupColumns->IsGroupStart(nColumn)) + pGroupColumns->OpenGroups(nColumn); + bPrevIsVisible = bIsVisible; + nPrevIndex = nIndex; + } + else if ((bIsVisible == bPrevIsVisible) && (nIndex == nPrevIndex) && + !pGroupColumns->IsGroupStart(nColumn) && !pGroupColumns->IsGroupEnd(nColumn - 1)) + ++nColsRepeated; + else + { + WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible); + if (pGroupColumns->IsGroupEnd(nColumn - 1)) + { + if (bIsHeader) + CloseHeaderColumn(); + pGroupColumns->CloseGroups(nColumn - 1); + if (bIsHeader) + OpenHeaderColumn(); + } + if (pGroupColumns->IsGroupStart(nColumn)) + { + if (bIsHeader) + CloseHeaderColumn(); + pGroupColumns->OpenGroups(nColumn); + if (bIsHeader) + OpenHeaderColumn(); + } + bPrevIsVisible = bIsVisible; + nPrevIndex = nIndex; + nPrevColumn = nColumn; + nColsRepeated = 1; + } + } + WriteColumn(nPrevColumn, nColsRepeated, nPrevIndex, bPrevIsVisible); + if (!bIsClosed) + CloseHeaderColumn(); + if (pGroupColumns->IsGroupEnd(nColumn - 1)) + pGroupColumns->CloseGroups(nColumn - 1); +} + +void ScXMLExport::ExportExternalRefCacheStyles() +{ + sal_Int32 nEntryIndex = GetCellStylesPropertySetMapper()->FindEntryIndex( + "NumberFormat", XML_NAMESPACE_STYLE, u"data-style-name"); + + if (nEntryIndex < 0) + // No entry index for the number format is found. + return; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + if (!pRefMgr->hasExternalData()) + // No external reference data cached. + return; + + // Export each unique number format used in the external ref cache. + vector<sal_uInt32> aNumFmts; + pRefMgr->getAllCachedNumberFormats(aNumFmts); + const OUString aDefaultStyle = OUString("Default").intern(); + for (const auto& rNumFmt : aNumFmts) + { + sal_Int32 nNumFmt = static_cast<sal_Int32>(rNumFmt); + + addDataStyle(nNumFmt); + + uno::Any aVal; + aVal <<= nNumFmt; + vector<XMLPropertyState> aProps; + aVal <<= aDefaultStyle; + aProps.emplace_back(nEntryIndex, aVal); + + OUString aName; + sal_Int32 nIndex; + if (GetAutoStylePool()->Add(aName, XmlStyleFamily::TABLE_CELL, aDefaultStyle, std::move(aProps))) + { + pCellStyles->AddStyleName(aName, nIndex); + } + else + { + bool bIsAuto; + nIndex = pCellStyles->GetIndexOfStyleName( + aName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX, bIsAuto); + } + + // store the number format to index mapping for later use. + aNumFmtIndexMap.emplace(nNumFmt, nIndex); + } +} + +namespace { + +void handleFont( + SvXMLExport & rExport, + std::vector<XMLPropertyState>& rPropStates, + const SfxPoolItem* p, const rtl::Reference<XMLPropertySetMapper>& xMapper, std::u16string_view rXMLName ) +{ + sal_Int32 nEntryCount = xMapper->GetEntryCount(); + + // Apparently font info needs special handling. + const SvxFontItem* pItem = static_cast<const SvxFontItem*>(p); + + sal_Int32 nIndexFontName = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, rXMLName, 0); + + if (nIndexFontName == -1 || nIndexFontName >= nEntryCount) + return; + + OUString const sFamilyName(pItem->GetFamilyName()); + OUString const sStyleName(pItem->GetStyleName()); + auto const nFamily(pItem->GetFamily()); + auto const nPitch(pItem->GetPitch()); + auto const eEnc(pItem->GetCharSet()); + OUString const sName(rExport.GetFontAutoStylePool()->Find( + sFamilyName, sStyleName, nFamily, nPitch, eEnc)); + if (sName.isEmpty()) + { + assert(false); // fallback to fo:font-family etc. probably not needed + } + + rPropStates.emplace_back(nIndexFontName, uno::Any(sName)); +} + +const SvxFieldData* toXMLPropertyStates( + SvXMLExport & rExport, + std::vector<XMLPropertyState>& rPropStates, const std::vector<const SfxPoolItem*>& rSecAttrs, + const rtl::Reference<XMLPropertySetMapper>& xMapper, const ScXMLEditAttributeMap& rAttrMap ) +{ + const SvxFieldData* pField = nullptr; + sal_Int32 nEntryCount = xMapper->GetEntryCount(); + rPropStates.reserve(rSecAttrs.size()); + for (const SfxPoolItem* p : rSecAttrs) + { + if (p->Which() == EE_FEATURE_FIELD) + { + pField = static_cast<const SvxFieldItem*>(p)->GetField(); + continue; + } + + const ScXMLEditAttributeMap::Entry* pEntry = rAttrMap.getEntryByItemID(p->Which()); + if (!pEntry) + continue; + + sal_Int32 nIndex = xMapper->GetEntryIndex( + pEntry->nmXMLNS, OUString::createFromAscii(pEntry->mpXMLName), 0); + + if (nIndex == -1 || nIndex >= nEntryCount) + continue; + + uno::Any aAny; + switch (p->Which()) + { + case EE_CHAR_FONTINFO: + handleFont(rExport, rPropStates, p, xMapper, u"font-name"); + break; + case EE_CHAR_FONTINFO_CJK: + handleFont(rExport, rPropStates, p, xMapper, u"font-name-asian"); + break; + case EE_CHAR_FONTINFO_CTL: + handleFont(rExport, rPropStates, p, xMapper, u"font-name-complex"); + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + if (!static_cast<const SvxWeightItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + if (!static_cast<const SvxFontHeightItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + if (!static_cast<const SvxPostureItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_UNDERLINE: + { + // Underline attribute needs to export multiple entries. + sal_Int32 nIndexStyle = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-style", 0); + if (nIndexStyle == -1 || nIndexStyle > nEntryCount) + break; + + sal_Int32 nIndexWidth = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-width", 0); + if (nIndexWidth == -1 || nIndexWidth > nEntryCount) + break; + + sal_Int32 nIndexType = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-underline-type", 0); + if (nIndexType == -1 || nIndexType > nEntryCount) + break; + + sal_Int32 nIndexColor = xMapper->FindEntryIndex("CharUnderlineColor", XML_NAMESPACE_STYLE, u"text-underline-color"); + if (nIndexColor == -1 || nIndexColor > nEntryCount) + break; + + sal_Int32 nIndexHasColor = xMapper->FindEntryIndex("CharUnderlineHasColor", XML_NAMESPACE_STYLE, u"text-underline-color"); + if (nIndexHasColor == -1 || nIndexHasColor > nEntryCount) + break; + + const SvxUnderlineItem* pUL = static_cast<const SvxUnderlineItem*>(p); + pUL->QueryValue(aAny, MID_TL_STYLE); + rPropStates.emplace_back(nIndexStyle, aAny); + rPropStates.emplace_back(nIndexType, aAny); + rPropStates.emplace_back(nIndexWidth, aAny); + + pUL->QueryValue(aAny, MID_TL_COLOR); + rPropStates.emplace_back(nIndexColor, aAny); + + pUL->QueryValue(aAny, MID_TL_HASCOLOR); + rPropStates.emplace_back(nIndexHasColor, aAny); + } + break; + case EE_CHAR_OVERLINE: + { + // Same with overline. Do just as we do with underline attributes. + sal_Int32 nIndexStyle = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-style", 0); + if (nIndexStyle == -1 || nIndexStyle > nEntryCount) + break; + + sal_Int32 nIndexWidth = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-width", 0); + if (nIndexWidth == -1 || nIndexWidth > nEntryCount) + break; + + sal_Int32 nIndexType = xMapper->GetEntryIndex(XML_NAMESPACE_STYLE, u"text-overline-type", 0); + if (nIndexType == -1 || nIndexType > nEntryCount) + break; + + sal_Int32 nIndexColor = xMapper->FindEntryIndex("CharOverlineColor", XML_NAMESPACE_STYLE, u"text-overline-color"); + if (nIndexColor == -1 || nIndexColor > nEntryCount) + break; + + sal_Int32 nIndexHasColor = xMapper->FindEntryIndex("CharOverlineHasColor", XML_NAMESPACE_STYLE, u"text-overline-color"); + if (nIndexHasColor == -1 || nIndexHasColor > nEntryCount) + break; + + const SvxOverlineItem* pOL = static_cast<const SvxOverlineItem*>(p); + pOL->QueryValue(aAny, MID_TL_STYLE); + rPropStates.emplace_back(nIndexStyle, aAny); + rPropStates.emplace_back(nIndexType, aAny); + rPropStates.emplace_back(nIndexWidth, aAny); + + pOL->QueryValue(aAny, MID_TL_COLOR); + rPropStates.emplace_back(nIndexColor, aAny); + + pOL->QueryValue(aAny, MID_TL_HASCOLOR); + rPropStates.emplace_back(nIndexHasColor, aAny); + } + break; + case EE_CHAR_COLOR: + { + if (!static_cast<const SvxColorItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + ::Color nColor; + if ( aAny >>= nColor ) + { + sal_Int32 nIndexColor = ( nColor == COL_AUTO ) ? xMapper->GetEntryIndex( + XML_NAMESPACE_STYLE, GetXMLToken( XML_USE_WINDOW_FONT_COLOR ), 0 ) : nIndex; + rPropStates.emplace_back( nIndexColor, aAny ); + } + } + break; + case EE_CHAR_WLM: + { + if (!static_cast<const SvxWordLineModeItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_STRIKEOUT: + { + if (!static_cast<const SvxCrossedOutItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_RELIEF: + { + if (!static_cast<const SvxCharReliefItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_OUTLINE: + { + if (!static_cast<const SvxContourItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_SHADOW: + { + if (!static_cast<const SvxShadowedItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_KERNING: + { + if (!static_cast<const SvxKerningItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_PAIRKERNING: + { + if (!static_cast<const SvxAutoKernItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_FONTWIDTH: + { + if (!static_cast<const SvxCharScaleWidthItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_ESCAPEMENT: + { + sal_Int32 nIndexEsc = xMapper->FindEntryIndex("CharEscapement", XML_NAMESPACE_STYLE, u"text-position"); + if (nIndexEsc == -1 || nIndexEsc > nEntryCount) + break; + + sal_Int32 nIndexEscHeight = xMapper->FindEntryIndex("CharEscapementHeight", XML_NAMESPACE_STYLE, u"text-position"); + if (nIndexEscHeight == -1 || nIndexEscHeight > nEntryCount) + break; + + const SvxEscapementItem* pEsc = static_cast<const SvxEscapementItem*>(p); + + pEsc->QueryValue(aAny); + rPropStates.emplace_back(nIndexEsc, aAny); + + pEsc->QueryValue(aAny, MID_ESC_HEIGHT); + rPropStates.emplace_back(nIndexEscHeight, aAny); + + } + break; + case EE_CHAR_EMPHASISMARK: + { + if (!static_cast<const SvxEmphasisMarkItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + rPropStates.emplace_back(nIndex, aAny); + } + break; + case EE_CHAR_LANGUAGE: + case EE_CHAR_LANGUAGE_CJK: + case EE_CHAR_LANGUAGE_CTL: + { + if (!static_cast<const SvxLanguageItem*>(p)->QueryValue(aAny, pEntry->mnFlag)) + continue; + + // Export multiple entries. + sal_Int32 nIndexLanguage, nIndexCountry, nIndexScript, nIndexTag; + switch (p->Which()) + { + case EE_CHAR_LANGUAGE: + nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"language", 0); + nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"country", 0); + nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_FO, u"script", 0); + nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag", 0); + break; + case EE_CHAR_LANGUAGE_CJK: + nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"language-asian", 0); + nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"country-asian", 0); + nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"script-asian", 0); + nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag-asian", 0); + break; + case EE_CHAR_LANGUAGE_CTL: + nIndexLanguage = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"language-complex", 0); + nIndexCountry = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"country-complex", 0); + nIndexScript = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"script-complex", 0); + nIndexTag = xMapper->GetEntryIndex( XML_NAMESPACE_STYLE, u"rfc-language-tag-complex", 0); + break; + default: + nIndexLanguage = nIndexCountry = nIndexScript = nIndexTag = -1; + } + assert( nIndexLanguage >= 0 && nIndexCountry >= 0 && nIndexScript >= 0 && nIndexTag >= 0); + rPropStates.emplace_back( nIndexLanguage, aAny); + rPropStates.emplace_back( nIndexCountry, aAny); + rPropStates.emplace_back( nIndexScript, aAny); + rPropStates.emplace_back( nIndexTag, aAny); + } + break; + default: + continue; + } + } + + return pField; +} + +} + +void ScXMLExport::ExportCellTextAutoStyles(sal_Int32 nTable) +{ + if (!ValidTab(nTable)) + return; + + rtl::Reference<XMLPropertySetMapper> xMapper = GetTextParagraphExport()->GetTextPropMapper()->getPropertySetMapper(); + rtl::Reference<SvXMLAutoStylePoolP> xStylePool = GetAutoStylePool(); + const ScXMLEditAttributeMap& rAttrMap = GetEditAttributeMap(); + + sc::EditTextIterator aIter(*pDoc, nTable); + sal_Int32 nCellCount = 0; + for (const EditTextObject* pEdit = aIter.first(); pEdit; pEdit = aIter.next(), ++nCellCount) + { + std::vector<editeng::Section> aAttrs; + pEdit->GetAllSections(aAttrs); + if (aAttrs.empty()) + continue; + + for (const auto& rSec : aAttrs) + { + const std::vector<const SfxPoolItem*>& rSecAttrs = rSec.maAttributes; + if (rSecAttrs.empty()) + // No formats applied to this section. Skip it. + continue; + + std::vector<XMLPropertyState> aPropStates; + toXMLPropertyStates(*this, aPropStates, rSecAttrs, xMapper, rAttrMap); + if (!aPropStates.empty()) + xStylePool->Add(XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates)); + } + } + + GetProgressBarHelper()->ChangeReference(GetProgressBarHelper()->GetReference() + nCellCount); +} + +void ScXMLExport::WriteRowContent() +{ + ScMyRowFormatRange aRange; + sal_Int32 nIndex(-1); +#if OSL_DEBUG_LEVEL > 0 + sal_Int32 nPrevCol(0); +#endif + sal_Int32 nCols(0); + sal_Int32 nPrevValidationIndex(-1); + bool bIsAutoStyle(true); + bool bIsFirst(true); + while (pRowFormatRanges->GetNext(aRange)) + { +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE(bIsFirst || (!bIsFirst && (nPrevCol + nCols == aRange.nStartColumn)), "here are some columns missing"); +#endif + if (bIsFirst) + { + nIndex = aRange.nIndex; + nPrevValidationIndex = aRange.nValidationIndex; + bIsAutoStyle = aRange.bIsAutoStyle; + nCols = aRange.nRepeatColumns; + bIsFirst = false; +#if OSL_DEBUG_LEVEL > 0 + nPrevCol = aRange.nStartColumn; +#endif + } + else + { + if (((aRange.nIndex == nIndex && aRange.bIsAutoStyle == bIsAutoStyle) || + (aRange.nIndex == nIndex && nIndex == -1)) && + nPrevValidationIndex == aRange.nValidationIndex) + nCols += aRange.nRepeatColumns; + else + { + if (nIndex != -1) + AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle)); + if (nPrevValidationIndex > -1) + AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(nPrevValidationIndex)); + if (nCols > 1) + { + AddAttribute(sAttrColumnsRepeated, OUString::number(nCols)); + } + SvXMLElementExport aElemC(*this, sElemCell, true, true); + nIndex = aRange.nIndex; + bIsAutoStyle = aRange.bIsAutoStyle; + nCols = aRange.nRepeatColumns; + nPrevValidationIndex = aRange.nValidationIndex; +#if OSL_DEBUG_LEVEL > 0 + nPrevCol = aRange.nStartColumn; +#endif + } + } + } + if (!bIsFirst) + { + if (nIndex != -1) + AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(nIndex, bIsAutoStyle)); + if (nPrevValidationIndex > -1) + AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(nPrevValidationIndex)); + if (nCols > 1) + { + AddAttribute(sAttrColumnsRepeated, OUString::number(nCols)); + } + SvXMLElementExport aElemC(*this, sElemCell, true, true); + } +} + +void ScXMLExport::WriteRowStartTag( + const sal_Int32 nIndex, const sal_Int32 nEqualRows, + bool bHidden, bool bFiltered) +{ + // tdf#143940 + if (nIndex != -1) + AddAttribute(sAttrStyleName, pRowStyles->GetStyleNameByIndex(nIndex)); + if (bHidden) + { + if (bFiltered) + AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_FILTER); + else + AddAttribute(XML_NAMESPACE_TABLE, XML_VISIBILITY, XML_COLLAPSE); + } + if (nEqualRows > 1) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, OUString::number(nEqualRows)); + } + + StartElement( sElemRow, true); +} + +void ScXMLExport::OpenHeaderRows() +{ + StartElement( XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true); + bRowHeaderOpen = true; +} + +void ScXMLExport::CloseHeaderRows() +{ + EndElement(XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true); +} + +void ScXMLExport::OpenNewRow( + const sal_Int32 nIndex, const sal_Int32 nStartRow, const sal_Int32 nEqualRows, + bool bHidden, bool bFiltered) +{ + nOpenRow = nStartRow; + if (pGroupRows->IsGroupStart(nStartRow)) + { + if (bHasRowHeader && bRowHeaderOpen) + CloseHeaderRows(); + pGroupRows->OpenGroups(nStartRow); + if (bHasRowHeader && bRowHeaderOpen) + OpenHeaderRows(); + } + if (bHasRowHeader && !bRowHeaderOpen && nStartRow >= aRowHeaderRange.aStart.Row() && nStartRow <= aRowHeaderRange.aEnd.Row()) + { + if (nStartRow == aRowHeaderRange.aStart.Row()) + OpenHeaderRows(); + sal_Int32 nEquals; + if (aRowHeaderRange.aEnd.Row() < nStartRow + nEqualRows - 1) + nEquals = aRowHeaderRange.aEnd.Row() - nStartRow + 1; + else + nEquals = nEqualRows; + WriteRowStartTag(nIndex, nEquals, bHidden, bFiltered); + nOpenRow = nStartRow + nEquals - 1; + if (nEquals < nEqualRows) + { + CloseRow(nStartRow + nEquals - 1); + WriteRowStartTag(nIndex, nEqualRows - nEquals, bHidden, bFiltered); + nOpenRow = nStartRow + nEqualRows - 1; + } + } + else + WriteRowStartTag(nIndex, nEqualRows, bHidden, bFiltered); +} + +void ScXMLExport::OpenAndCloseRow( + const sal_Int32 nIndex, const sal_Int32 nStartRow, const sal_Int32 nEqualRows, + bool bHidden, bool bFiltered) +{ + OpenNewRow(nIndex, nStartRow, nEqualRows, bHidden, bFiltered); + WriteRowContent(); + CloseRow(nStartRow + nEqualRows - 1); + pRowFormatRanges->Clear(); +} + +void ScXMLExport::OpenRow(const sal_Int32 nTable, const sal_Int32 nStartRow, const sal_Int32 nRepeatRow, ScXMLCachedRowAttrAccess& rRowAttr) +{ + if (nRepeatRow > 1) + { + sal_Int32 nPrevIndex(0), nIndex; + bool bPrevHidden = false; + bool bPrevFiltered = false; + bool bHidden = false; + bool bFiltered = false; + sal_Int32 nEqualRows(1); + sal_Int32 nEndRow(nStartRow + nRepeatRow); + sal_Int32 nEndRowHidden = nStartRow - 1; + sal_Int32 nEndRowFiltered = nStartRow - 1; + sal_Int32 nRow; + for (nRow = nStartRow; nRow < nEndRow; ++nRow) + { + if (nRow == nStartRow) + { + nPrevIndex = pRowStyles->GetStyleNameIndex(nTable, nRow); + if (pDoc) + { + if (nRow > nEndRowHidden) + { + bPrevHidden = rRowAttr.rowHidden(nTable, nRow, nEndRowHidden); + bHidden = bPrevHidden; + } + if (nRow > nEndRowFiltered) + { + bPrevFiltered = rRowAttr.rowFiltered(nTable, nRow, nEndRowFiltered); + bFiltered = bPrevFiltered; + } + } + + } + else + { + nIndex = pRowStyles->GetStyleNameIndex(nTable, nRow); + if (pDoc) + { + if (nRow > nEndRowHidden) + bHidden = rRowAttr.rowHidden(nTable, nRow, nEndRowHidden); + if (nRow > nEndRowFiltered) + bFiltered = rRowAttr.rowFiltered(nTable, nRow, nEndRowFiltered); + } + if (nIndex == nPrevIndex && bHidden == bPrevHidden && bFiltered == bPrevFiltered && + !(bHasRowHeader && ((nRow == aRowHeaderRange.aStart.Row()) || (nRow - 1 == aRowHeaderRange.aEnd.Row()))) && + !(pGroupRows->IsGroupStart(nRow)) && + !(pGroupRows->IsGroupEnd(nRow - 1))) + ++nEqualRows; + else + { + assert(nPrevIndex >= 0 && "coverity#1438402"); + ScRowFormatRanges* pTempRowFormatRanges = new ScRowFormatRanges(pRowFormatRanges.get()); + OpenAndCloseRow(nPrevIndex, nRow - nEqualRows, nEqualRows, bPrevHidden, bPrevFiltered); + pRowFormatRanges.reset(pTempRowFormatRanges); + nEqualRows = 1; + nPrevIndex = nIndex; + bPrevHidden = bHidden; + bPrevFiltered = bFiltered; + } + } + } + assert(nPrevIndex >= 0 && "coverity#1438402"); + OpenNewRow(nPrevIndex, nRow - nEqualRows, nEqualRows, bPrevHidden, bPrevFiltered); + } + else + { + sal_Int32 nIndex = pRowStyles->GetStyleNameIndex(nTable, nStartRow); + bool bHidden = false; + bool bFiltered = false; + if (pDoc) + { + sal_Int32 nEndRowHidden; + sal_Int32 nEndRowFiltered; + bHidden = rRowAttr.rowHidden(nTable, nStartRow, nEndRowHidden); + bFiltered = rRowAttr.rowFiltered(nTable, nStartRow, nEndRowFiltered); + } + assert(nIndex >= 0 && "coverity#1438402"); + OpenNewRow(nIndex, nStartRow, 1, bHidden, bFiltered); + } + nOpenRow = nStartRow + nRepeatRow - 1; +} + +void ScXMLExport::CloseRow(const sal_Int32 nRow) +{ + if (nOpenRow > -1) + { + EndElement(sElemRow, true); + if (bHasRowHeader && nRow == aRowHeaderRange.aEnd.Row()) + { + CloseHeaderRows(); + bRowHeaderOpen = false; + } + if (pGroupRows->IsGroupEnd(nRow)) + { + if (bHasRowHeader && bRowHeaderOpen) + CloseHeaderRows(); + pGroupRows->CloseGroups(nRow); + if (bHasRowHeader && bRowHeaderOpen) + OpenHeaderRows(); + } + } + nOpenRow = -1; +} + +void ScXMLExport::ExportFormatRanges(const sal_Int32 nStartCol, const sal_Int32 nStartRow, + const sal_Int32 nEndCol, const sal_Int32 nEndRow, const sal_Int32 nSheet) +{ + pRowFormatRanges->Clear(); + ScXMLCachedRowAttrAccess aRowAttr(pDoc); + if (nStartRow == nEndRow) + { + pCellStyles->GetFormatRanges(nStartCol, nEndCol, nStartRow, nSheet, pRowFormatRanges.get()); + if (nOpenRow == - 1) + OpenRow(nSheet, nStartRow, 1, aRowAttr); + WriteRowContent(); + pRowFormatRanges->Clear(); + } + else + { + if (nOpenRow > -1) + { + pCellStyles->GetFormatRanges(nStartCol, pSharedData->GetLastColumn(nSheet), nStartRow, nSheet, pRowFormatRanges.get()); + WriteRowContent(); + CloseRow(nStartRow); + sal_Int32 nRows(1); + sal_Int32 nTotalRows(nEndRow - nStartRow + 1 - 1); + while (nRows < nTotalRows) + { + pRowFormatRanges->Clear(); + pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get()); + sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows(); + OSL_ENSURE(nMaxRows, "something went wrong"); + if (nMaxRows >= nTotalRows - nRows) + { + OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, aRowAttr); + nRows += nTotalRows - nRows; + } + else + { + OpenRow(nSheet, nStartRow + nRows, nMaxRows, aRowAttr); + nRows += nMaxRows; + } + if (!pRowFormatRanges->GetSize()) + pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get()); + WriteRowContent(); + CloseRow(nStartRow + nRows - 1); + } + if (nTotalRows == 1) + CloseRow(nStartRow); + OpenRow(nSheet, nEndRow, 1, aRowAttr); + pRowFormatRanges->Clear(); + pCellStyles->GetFormatRanges(0, nEndCol, nEndRow, nSheet, pRowFormatRanges.get()); + WriteRowContent(); + } + else + { + sal_Int32 nRows(0); + sal_Int32 nTotalRows(nEndRow - nStartRow + 1 - 1); + while (nRows < nTotalRows) + { + pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get()); + sal_Int32 nMaxRows = pRowFormatRanges->GetMaxRows(); + OSL_ENSURE(nMaxRows, "something went wrong"); + if (nMaxRows >= nTotalRows - nRows) + { + OpenRow(nSheet, nStartRow + nRows, nTotalRows - nRows, aRowAttr); + nRows += nTotalRows - nRows; + } + else + { + OpenRow(nSheet, nStartRow + nRows, nMaxRows, aRowAttr); + nRows += nMaxRows; + } + if (!pRowFormatRanges->GetSize()) + pCellStyles->GetFormatRanges(0, pSharedData->GetLastColumn(nSheet), nStartRow + nRows, nSheet, pRowFormatRanges.get()); + WriteRowContent(); + CloseRow(nStartRow + nRows - 1); + } + OpenRow(nSheet, nEndRow, 1, aRowAttr); + pRowFormatRanges->Clear(); + pCellStyles->GetFormatRanges(0, nEndCol, nEndRow, nSheet, pRowFormatRanges.get()); + WriteRowContent(); + } + } +} + +void ScXMLExport::GetColumnRowHeader(bool& rHasColumnHeader, ScRange& rColumnHeaderRange, + bool& rHasRowHeader, ScRange& rRowHeaderRange, + OUString& rPrintRanges) const +{ + uno::Reference <sheet::XPrintAreas> xPrintAreas (xCurrentTable, uno::UNO_QUERY); + if (!xPrintAreas.is()) + return; + + rHasRowHeader = xPrintAreas->getPrintTitleRows(); + rHasColumnHeader = xPrintAreas->getPrintTitleColumns(); + table::CellRangeAddress rTempRowHeaderRange = xPrintAreas->getTitleRows(); + rRowHeaderRange = ScRange(rTempRowHeaderRange.StartColumn, + rTempRowHeaderRange.StartRow, + rTempRowHeaderRange.Sheet, + rTempRowHeaderRange.EndColumn, + rTempRowHeaderRange.EndRow, + rTempRowHeaderRange.Sheet); + table::CellRangeAddress rTempColumnHeaderRange = xPrintAreas->getTitleColumns(); + rColumnHeaderRange = ScRange(rTempColumnHeaderRange.StartColumn, + rTempColumnHeaderRange.StartRow, + rTempColumnHeaderRange.Sheet, + rTempColumnHeaderRange.EndColumn, + rTempColumnHeaderRange.EndRow, + rTempColumnHeaderRange.Sheet); + uno::Sequence< table::CellRangeAddress > aRangeList( xPrintAreas->getPrintAreas() ); + ScRangeStringConverter::GetStringFromRangeList( rPrintRanges, aRangeList, pDoc, FormulaGrammar::CONV_OOO ); +} + +void ScXMLExport::FillFieldGroup(ScOutlineArray* pFields, ScMyOpenCloseColumnRowGroup* pGroups) +{ + size_t nDepth = pFields->GetDepth(); + for (size_t i = 0; i < nDepth; ++i) + { + size_t nFields = pFields->GetCount(i); + for (size_t j = 0; j < nFields; ++j) + { + ScMyColumnRowGroup aGroup; + const ScOutlineEntry* pEntry = pFields->GetEntry(i, j); + aGroup.nField = pEntry->GetStart(); + aGroup.nLevel = static_cast<sal_Int16>(i); + aGroup.bDisplay = !(pEntry->IsHidden()); + pGroups->AddGroup(aGroup, pEntry->GetEnd()); + } + } + if (nDepth) + pGroups->Sort(); +} + +void ScXMLExport::FillColumnRowGroups() +{ + if (!pDoc) + return; + + ScOutlineTable* pOutlineTable = pDoc->GetOutlineTable( static_cast<SCTAB>(nCurrentTable) ); + if(pOutlineTable) + { + ScOutlineArray& rCols(pOutlineTable->GetColArray()); + ScOutlineArray& rRows(pOutlineTable->GetRowArray()); + FillFieldGroup(&rCols, pGroupColumns.get()); + FillFieldGroup(&rRows, pGroupRows.get()); + pSharedData->SetLastColumn(nCurrentTable, pGroupColumns->GetLast()); + pSharedData->SetLastRow(nCurrentTable, pGroupRows->GetLast()); + } +} + +void ScXMLExport::SetBodyAttributes() +{ + if (!(pDoc && pDoc->IsDocProtected())) + return; + + AddAttribute(XML_NAMESPACE_TABLE, XML_STRUCTURE_PROTECTED, XML_TRUE); + OUStringBuffer aBuffer; + uno::Sequence<sal_Int8> aPassHash; + ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED; + const ScDocProtection* p = pDoc->GetDocProtection(); + if (p) + { + if (p->hasPasswordHash(PASSHASH_SHA1)) + { + aPassHash = p->getPasswordHash(PASSHASH_SHA1); + eHashUsed = PASSHASH_SHA1; + } + else if (p->hasPasswordHash(PASSHASH_SHA256)) + { + aPassHash = p->getPasswordHash(PASSHASH_SHA256); + eHashUsed = PASSHASH_SHA256; + } + else if (p->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1)) + { + aPassHash = p->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1); + eHashUsed = PASSHASH_XL; + } + } + ::comphelper::Base64::encode(aBuffer, aPassHash); + if (aBuffer.isEmpty()) + return; + + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear()); + if (getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012) + return; + + if (eHashUsed == PASSHASH_XL) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + ScPassHashHelper::getHashURI(PASSHASH_XL)); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2, + ScPassHashHelper::getHashURI(PASSHASH_SHA1)); + } + else if (eHashUsed == PASSHASH_SHA1) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + ScPassHashHelper::getHashURI(PASSHASH_SHA1)); + } + else if (eHashUsed == PASSHASH_SHA256) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + ScPassHashHelper::getHashURI(PASSHASH_SHA256)); + } +} + +static bool lcl_CopyStreamElement( const uno::Reference< io::XInputStream >& xInput, + const uno::Reference< io::XOutputStream >& xOutput, + sal_Int32 nCount ) +{ + const sal_Int32 nBufSize = 16*1024; + uno::Sequence<sal_Int8> aSequence(nBufSize); + + sal_Int32 nRemaining = nCount; + bool bFirst = true; + + while ( nRemaining > 0 ) + { + sal_Int32 nRead = xInput->readBytes( aSequence, std::min( nRemaining, nBufSize ) ); + if (bFirst) + { + // safety check: Make sure the copied part actually points to the start of an element + if ( nRead < 1 || aSequence[0] != static_cast<sal_Int8>('<') ) + { + return false; // abort and set an error + } + bFirst = false; + } + if (nRead == nRemaining) + { + // safety check: Make sure the copied part also ends at the end of an element + if ( aSequence[nRead-1] != static_cast<sal_Int8>('>') ) + { + return false; // abort and set an error + } + } + + if ( nRead == nBufSize ) + { + xOutput->writeBytes( aSequence ); + nRemaining -= nRead; + } + else + { + if ( nRead > 0 ) + { + uno::Sequence<sal_Int8> aTempBuf( aSequence.getConstArray(), nRead ); + xOutput->writeBytes( aTempBuf ); + } + nRemaining = 0; + } + } + return true; // successful +} + +static void lcl_SkipBytesInBlocks( const uno::Reference< io::XInputStream >& xInput, sal_Int32 nBytesToSkip ) +{ + // skipBytes in zip stream is implemented as reading. + // For now, split into several calls to avoid allocating a large buffer. + // Later, skipBytes should be changed. + + const sal_Int32 nMaxSize = 32*1024; + + if ( nBytesToSkip > 0 ) + { + sal_Int32 nRemaining = nBytesToSkip; + while ( nRemaining > 0 ) + { + sal_Int32 nSkip = std::min( nRemaining, nMaxSize ); + xInput->skipBytes( nSkip ); + nRemaining -= nSkip; + } + } +} + +void ScXMLExport::CopySourceStream( sal_Int32 nStartOffset, sal_Int32 nEndOffset, sal_Int32& rNewStart, sal_Int32& rNewEnd ) +{ + uno::Reference<xml::sax::XDocumentHandler> xHandler = GetDocHandler(); + uno::Reference<io::XActiveDataSource> xDestSource( xHandler, uno::UNO_QUERY ); + if ( !xDestSource.is() ) + return; + + uno::Reference<io::XOutputStream> xDestStream = xDestSource->getOutputStream(); + uno::Reference<io::XSeekable> xDestSeek( xDestStream, uno::UNO_QUERY ); + if ( !xDestSeek.is() ) + return; + + // temporary: set same stream again to clear buffer + xDestSource->setOutputStream( xDestStream ); + + if ( getExportFlags() & SvXMLExportFlags::PRETTY ) + { + const OString aOutStr("\n "); + uno::Sequence<sal_Int8> aOutSeq( reinterpret_cast<sal_Int8 const *>(aOutStr.getStr()), aOutStr.getLength() ); + xDestStream->writeBytes( aOutSeq ); + } + + rNewStart = static_cast<sal_Int32>(xDestSeek->getPosition()); + + if ( nStartOffset > nSourceStreamPos ) + lcl_SkipBytesInBlocks( xSourceStream, nStartOffset - nSourceStreamPos ); + + if ( !lcl_CopyStreamElement( xSourceStream, xDestStream, nEndOffset - nStartOffset ) ) + { + // If copying went wrong, set an error. + // ScXMLImportWrapper then resets all stream flags, so the next save attempt will use normal saving. + + uno::Sequence<OUString> aEmptySeq; + SetError(XMLERROR_CANCEL|XMLERROR_FLAG_SEVERE, aEmptySeq); + } + nSourceStreamPos = nEndOffset; + + rNewEnd = static_cast<sal_Int32>(xDestSeek->getPosition()); +} + +const ScXMLEditAttributeMap& ScXMLExport::GetEditAttributeMap() const +{ + if (!mpEditAttrMap) + mpEditAttrMap.reset(new ScXMLEditAttributeMap); + return *mpEditAttrMap; +} + +void ScXMLExport::RegisterDefinedStyleNames( const uno::Reference< css::sheet::XSpreadsheetDocument > & xSpreadDoc ) +{ + ScFormatSaveData* pFormatData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetFormatSaveData(); + auto xAutoStylePool = GetAutoStylePool(); + for (const auto& rFormatInfo : pFormatData->maIDToName) + { + xAutoStylePool->RegisterDefinedName(XmlStyleFamily::TABLE_CELL, rFormatInfo.second); + } +} + +void ScXMLExport::ExportContent_() +{ + nCurrentTable = 0; + if (!pSharedData) + { + SCTAB nTableCount(0); + sal_Int32 nShapesCount(0); + CollectSharedData(nTableCount, nShapesCount); + OSL_FAIL("no shared data set"); + if (!pSharedData) + return; + } + ScXMLExportDatabaseRanges aExportDatabaseRanges(*this); + if (!GetModel().is()) + return; + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); + if ( !xSpreadDoc.is() ) + return; + + ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetSheetSaveData(); + if (pSheetData) + pSheetData->ResetSaveEntries(); + + uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); + if ( xIndex.is() ) + { + //_GetNamespaceMap().ClearQNamesCache(); + pChangeTrackingExportHelper->CollectAndWriteChanges(); + WriteCalculationSettings(xSpreadDoc); + sal_Int32 nTableCount(xIndex->getCount()); + ScMyAreaLinksContainer aAreaLinks; + GetAreaLinks( aAreaLinks ); + ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges()); + ScMyDetectiveOpContainer aDetectiveOpContainer; + GetDetectiveOpList( aDetectiveOpContainer ); + + pCellStyles->Sort(); + pMergedRangesContainer->Sort(); + pSharedData->GetDetectiveObjContainer()->Sort(); + + mpCellsItr->Clear(); + mpCellsItr->SetShapes( pSharedData->GetShapesContainer() ); + mpCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() ); + mpCellsItr->SetMergedRanges( pMergedRangesContainer.get() ); + mpCellsItr->SetAreaLinks( &aAreaLinks ); + mpCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges ); + mpCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() ); + mpCellsItr->SetDetectiveOp( &aDetectiveOpContainer ); + + if (nTableCount > 0) + pValidationsContainer->WriteValidations(*this); + WriteTheLabelRanges( xSpreadDoc ); + for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable) + { + sal_Int32 nStartOffset = -1; + sal_Int32 nEndOffset = -1; + if (pSheetData && pDoc && pDoc->IsStreamValid(static_cast<SCTAB>(nTable)) && !pDoc->GetChangeTrack()) + pSheetData->GetStreamPos( nTable, nStartOffset, nEndOffset ); + + if ( nStartOffset >= 0 && nEndOffset >= 0 && xSourceStream.is() ) + { + sal_Int32 nNewStart = -1; + sal_Int32 nNewEnd = -1; + CopySourceStream( nStartOffset, nEndOffset, nNewStart, nNewEnd ); + + // store position of copied sheet in output + pSheetData->AddSavePos( nTable, nNewStart, nNewEnd ); + + // skip iterator entries for this sheet + mpCellsItr->SkipTable(static_cast<SCTAB>(nTable)); + } + else + { + uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY); + WriteTable(nTable, xTable); + } + IncrementProgressBar(false); + } + } + WriteExternalRefCaches(); + WriteNamedExpressions(); + WriteDataStream(); + aExportDatabaseRanges.WriteDatabaseRanges(); + WriteExternalDataMapping(); + ScXMLExportDataPilot aExportDataPilot(*this); + aExportDataPilot.WriteDataPilots(); + WriteConsolidation(); + ScXMLExportDDELinks aExportDDELinks(*this); + aExportDDELinks.WriteDDELinks(xSpreadDoc); + IncrementProgressBar(true, 0); + GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference()); +} + +void ScXMLExport::ExportStyles_( bool bUsed ) +{ + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); + if (xSpreadDoc.is()) + RegisterDefinedStyleNames( xSpreadDoc); + + if (!pSharedData) + { + SCTAB nTableCount(0); + sal_Int32 nShapesCount(0); + CollectSharedData(nTableCount, nShapesCount); + } + rtl::Reference<XMLCellStyleExport> aStylesExp(new XMLCellStyleExport(*this, GetAutoStylePool().get())); + if (GetModel().is()) + { + uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetModel(), uno::UNO_QUERY); + if (xMultiServiceFactory.is()) + { + uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance("com.sun.star.sheet.Defaults"), uno::UNO_QUERY); + if (xProperties.is()) + aStylesExp->exportDefaultStyle(xProperties, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, xCellStylesExportPropertySetMapper); + if (pSharedData->HasShapes()) + { + GetShapeExport()->ExportGraphicDefaults(); + } + } + collectDataStyles(false); + } + exportDataStyles(); + + aStylesExp->exportStyleFamily(OUString("CellStyles"), + OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME), xCellStylesExportPropertySetMapper, false, XmlStyleFamily::TABLE_CELL); + + SvXMLExport::ExportStyles_(bUsed); +} + +void ScXMLExport::AddStyleFromCells(const uno::Reference<beans::XPropertySet>& xProperties, + const uno::Reference<sheet::XSpreadsheet>& xTable, + sal_Int32 nTable, const OUString* pOldName) +{ + css::uno::Any aAny = xProperties->getPropertyValue("FormatID"); + sal_uInt64 nKey = 0; + aAny >>= nKey; + + //! pass xCellRanges instead + uno::Reference<sheet::XSheetCellRanges> xCellRanges( xProperties, uno::UNO_QUERY ); + + OUString sStyleName; + sal_Int32 nNumberFormat(-1); + sal_Int32 nValidationIndex(-1); + std::vector<XMLPropertyState> aPropStates(xCellStylesExportPropertySetMapper->Filter(*this, xProperties)); + std::vector< XMLPropertyState >::iterator aItr(aPropStates.begin()); + std::vector< XMLPropertyState >::iterator aEndItr(aPropStates.end()); + sal_Int32 nCount(0); + while (aItr != aEndItr) + { + if (aItr->mnIndex != -1) + { + switch (xCellStylesPropertySetMapper->GetEntryContextId(aItr->mnIndex)) + { + case CTF_SC_VALIDATION : + { + pValidationsContainer->AddValidation(aItr->maValue, nValidationIndex); + // this is not very slow, because it is most the last property or + // if it is not the last property it is the property before the last property, + // so in the worst case only one property has to be copied, but in the best case no + // property has to be copied + aItr = aPropStates.erase(aItr); + aEndItr = aPropStates.end(); // old aEndItr is invalidated! + } + break; + case CTF_SC_CELLSTYLE : + { + aItr->maValue >>= sStyleName; + aItr->mnIndex = -1; + ++aItr; + ++nCount; + } + break; + case CTF_SC_NUMBERFORMAT : + { + if (aItr->maValue >>= nNumberFormat) + addDataStyle(nNumberFormat); + ++aItr; + ++nCount; + } + break; + default: + { + ++aItr; + ++nCount; + } + break; + } + } + else + { + ++aItr; + ++nCount; + } + } + if (nCount == 1) // this is the CellStyle and should be removed if alone + aPropStates.clear(); + if (nNumberFormat == -1) + xProperties->getPropertyValue(SC_UNONAME_NUMFMT) >>= nNumberFormat; + if (sStyleName.isEmpty()) + return; + + if (!aPropStates.empty()) + { + sal_Int32 nIndex; + if (pOldName) + { + if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates))) + { + GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_CELL, *pOldName); + // add to pCellStyles, so the name is found for normal sheets + pCellStyles->AddStyleName(*pOldName, nIndex); + } + } + else + { + OUString sName; + bool bAdded = false; + if (nKey) + { + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); + ScFormatSaveData* pFormatData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetFormatSaveData(); + auto itr = pFormatData->maIDToName.find(nKey); + if (itr != pFormatData->maIDToName.end()) + { + sName = itr->second; + bAdded = GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates)); + if (bAdded) + GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_CELL, sName); + } + } + bool bIsAutoStyle(true); + if (bAdded || GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_CELL, sStyleName, std::move(aPropStates))) + { + pCellStyles->AddStyleName(sName, nIndex); + } + else + nIndex = pCellStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX, bIsAutoStyle); + + const uno::Sequence<table::CellRangeAddress> aAddresses(xCellRanges->getRangeAddresses()); + bool bGetMerge(true); + for (table::CellRangeAddress const & address : aAddresses) + { + pSharedData->SetLastColumn(nTable, address.EndColumn); + pSharedData->SetLastRow(nTable, address.EndRow); + pCellStyles->AddRangeStyleName(address, nIndex, bIsAutoStyle, nValidationIndex, nNumberFormat); + if (bGetMerge) + bGetMerge = GetMerged(&address, xTable); + } + } + } + else + { + OUString sEncodedStyleName(EncodeStyleName(sStyleName)); + sal_Int32 nIndex(0); + pCellStyles->AddStyleName(sEncodedStyleName, nIndex, false); + if ( !pOldName ) + { + const uno::Sequence<table::CellRangeAddress> aAddresses(xCellRanges->getRangeAddresses()); + bool bGetMerge(true); + for (table::CellRangeAddress const & address : aAddresses) + { + if (bGetMerge) + bGetMerge = GetMerged(&address, xTable); + pCellStyles->AddRangeStyleName(address, nIndex, false, nValidationIndex, nNumberFormat); + if( sStyleName != "Default" || nValidationIndex != -1 ) + { + pSharedData->SetLastColumn(nTable, address.EndColumn); + pSharedData->SetLastRow(nTable, address.EndRow); + } + } + } + } +} + +void ScXMLExport::AddStyleFromColumn(const uno::Reference<beans::XPropertySet>& xColumnProperties, + const OUString* pOldName, sal_Int32& rIndex, bool& rIsVisible) +{ + std::vector<XMLPropertyState> aPropStates(xColumnStylesExportPropertySetMapper->Filter(*this, xColumnProperties)); + if(aPropStates.empty()) + return; + + auto aItr = std::find_if(aPropStates.begin(), aPropStates.end(), + [this](const XMLPropertyState& rPropState) { + return xColumnStylesPropertySetMapper->GetEntryContextId(rPropState.mnIndex) == CTF_SC_ISVISIBLE; }); + if (aItr != aPropStates.end()) + { + aItr->maValue >>= rIsVisible; + } + + const OUString sParent; + if (pOldName) + { + if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_COLUMN, sParent, std::move(aPropStates))) + { + GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_COLUMN, *pOldName); + // add to pColumnStyles, so the name is found for normal sheets + rIndex = pColumnStyles->AddStyleName(*pOldName); + } + } + else + { + OUString sName; + if (GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_COLUMN, sParent, std::move(aPropStates))) + { + rIndex = pColumnStyles->AddStyleName(sName); + } + else + rIndex = pColumnStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX); + } +} + +void ScXMLExport::AddStyleFromRow(const uno::Reference<beans::XPropertySet>& xRowProperties, + const OUString* pOldName, sal_Int32& rIndex) +{ + std::vector<XMLPropertyState> aPropStates(xRowStylesExportPropertySetMapper->Filter(*this, xRowProperties)); + if(aPropStates.empty()) + return; + + const OUString sParent; + if (pOldName) + { + if (GetAutoStylePool()->AddNamed(*pOldName, XmlStyleFamily::TABLE_ROW, sParent, std::move(aPropStates))) + { + GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_ROW, *pOldName); + // add to pRowStyles, so the name is found for normal sheets + rIndex = pRowStyles->AddStyleName(*pOldName); + } + } + else + { + OUString sName; + if (GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_ROW, sParent, std::move(aPropStates))) + { + rIndex = pRowStyles->AddStyleName(sName); + } + else + rIndex = pRowStyles->GetIndexOfStyleName(sName, XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX); + } +} + +static uno::Any lcl_GetEnumerated( uno::Reference<container::XEnumerationAccess> const & xEnumAccess, sal_Int32 nIndex ) +{ + uno::Any aRet; + uno::Reference<container::XEnumeration> xEnum( xEnumAccess->createEnumeration() ); + try + { + sal_Int32 nSkip = nIndex; + while ( nSkip > 0 ) + { + (void) xEnum->nextElement(); + --nSkip; + } + aRet = xEnum->nextElement(); + } + catch (container::NoSuchElementException&) + { + // leave aRet empty + } + return aRet; +} + +void ScXMLExport::collectAutoStyles() +{ + SvXMLExport::collectAutoStyles(); + + if (mbAutoStylesCollected) + return; + + if (!GetModel().is()) + return; + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); + if (!xSpreadDoc.is()) + return; + + uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); + if (!xIndex.is()) + return; + + if (getExportFlags() & SvXMLExportFlags::CONTENT) + { + // Reserve the loaded cell style names. + RegisterDefinedStyleNames( xSpreadDoc); + + // re-create automatic styles with old names from stored data + ScSheetSaveData* pSheetData = comphelper::getFromUnoTunnel<ScModelObj>(xSpreadDoc)->GetSheetSaveData(); + if (pSheetData && pDoc) + { + // formulas have to be calculated now, to detect changed results + // (during normal save, they will be calculated anyway) + SCTAB nTabCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; ++nTab) + if (pDoc->IsStreamValid(nTab)) + pDoc->InterpretDirtyCells(ScRange(0, 0, nTab, pDoc->MaxCol(), pDoc->MaxRow(), nTab)); + + // stored cell styles + const std::vector<ScCellStyleEntry>& rCellEntries = pSheetData->GetCellStyles(); + for (const auto& rCellEntry : rCellEntries) + { + ScAddress aPos = rCellEntry.maCellPos; + sal_Int32 nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) ); + if (bCopySheet) + { + uno::Reference <sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY); + uno::Reference <beans::XPropertySet> xProperties( + xTable->getCellByPosition( aPos.Col(), aPos.Row() ), uno::UNO_QUERY ); + + AddStyleFromCells(xProperties, xTable, nTable, &rCellEntry.maName); + } + } + + // stored column styles + const std::vector<ScCellStyleEntry>& rColumnEntries = pSheetData->GetColumnStyles(); + for (const auto& rColumnEntry : rColumnEntries) + { + ScAddress aPos = rColumnEntry.maCellPos; + sal_Int32 nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) ); + if (bCopySheet) + { + uno::Reference<table::XColumnRowRange> xColumnRowRange(xIndex->getByIndex(nTable), uno::UNO_QUERY); + uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns()); + uno::Reference<beans::XPropertySet> xColumnProperties(xTableColumns->getByIndex( aPos.Col() ), uno::UNO_QUERY); + + sal_Int32 nIndex(-1); + bool bIsVisible(true); + AddStyleFromColumn( xColumnProperties, &rColumnEntry.maName, nIndex, bIsVisible ); + } + } + + // stored row styles + const std::vector<ScCellStyleEntry>& rRowEntries = pSheetData->GetRowStyles(); + for (const auto& rRowEntry : rRowEntries) + { + ScAddress aPos = rRowEntry.maCellPos; + sal_Int32 nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) ); + if (bCopySheet) + { + uno::Reference<table::XColumnRowRange> xColumnRowRange(xIndex->getByIndex(nTable), uno::UNO_QUERY); + uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows()); + uno::Reference<beans::XPropertySet> xRowProperties(xTableRows->getByIndex( aPos.Row() ), uno::UNO_QUERY); + + sal_Int32 nIndex(-1); + AddStyleFromRow( xRowProperties, &rRowEntry.maName, nIndex ); + } + } + + // stored table styles + const std::vector<ScCellStyleEntry>& rTableEntries = pSheetData->GetTableStyles(); + for (const auto& rTableEntry : rTableEntries) + { + ScAddress aPos = rTableEntry.maCellPos; + sal_Int32 nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) ); + if (bCopySheet) + { + //! separate method AddStyleFromTable needed? + uno::Reference<beans::XPropertySet> xTableProperties(xIndex->getByIndex(nTable), uno::UNO_QUERY); + if (xTableProperties.is()) + { + std::vector<XMLPropertyState> aPropStates(xTableStylesExportPropertySetMapper->Filter(*this, xTableProperties)); + OUString sName( rTableEntry.maName ); + GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TABLE_TABLE, OUString(), std::move(aPropStates)); + GetAutoStylePool()->RegisterName(XmlStyleFamily::TABLE_TABLE, sName); + } + } + } + + // stored styles for notes + + rtl::Reference<SvXMLExportPropertyMapper> xShapeMapper = XMLShapeExport::CreateShapePropMapper( *this ); + GetShapeExport(); // make sure the graphics styles family is added + + const std::vector<ScNoteStyleEntry>& rNoteEntries = pSheetData->GetNoteStyles(); + for (const auto& rNoteEntry : rNoteEntries) + { + ScAddress aPos = rNoteEntry.maCellPos; + SCTAB nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( nTable ); + if (bCopySheet) + { + //! separate method AddStyleFromNote needed? + + ScPostIt* pNote = pDoc->GetNote(aPos); + OSL_ENSURE( pNote, "note not found" ); + if (pNote) + { + SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos ); + // all uno shapes are created anyway in CollectSharedData + uno::Reference<beans::XPropertySet> xShapeProperties( pDrawObj->getUnoShape(), uno::UNO_QUERY ); + if (xShapeProperties.is()) + { + if ( !rNoteEntry.maStyleName.isEmpty() ) + { + std::vector<XMLPropertyState> aPropStates(xShapeMapper->Filter(*this, xShapeProperties)); + OUString sName( rNoteEntry.maStyleName ); + GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::SD_GRAPHICS_ID, OUString(), std::move(aPropStates)); + GetAutoStylePool()->RegisterName(XmlStyleFamily::SD_GRAPHICS_ID, sName); + } + if ( !rNoteEntry.maTextStyle.isEmpty() ) + { + std::vector<XMLPropertyState> aPropStates( + GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(*this, xShapeProperties)); + OUString sName( rNoteEntry.maTextStyle ); + GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_PARAGRAPH, OUString(), std::move(aPropStates)); + GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_PARAGRAPH, sName); + } + } + } + } + } + + // note paragraph styles + + rtl::Reference<SvXMLExportPropertyMapper> xParaPropMapper = GetTextParagraphExport()->GetParagraphPropertyMapper(); + + const std::vector<ScTextStyleEntry>& rNoteParaEntries = pSheetData->GetNoteParaStyles(); + for (const auto& rNoteParaEntry : rNoteParaEntries) + { + ScAddress aPos = rNoteParaEntry.maCellPos; + SCTAB nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( nTable ); + if (bCopySheet) + { + ScPostIt* pNote = pDoc->GetNote( aPos ); + OSL_ENSURE( pNote, "note not found" ); + if (pNote) + { + SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos ); + uno::Reference<container::XEnumerationAccess> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xParaProp( + lcl_GetEnumerated( xCellText, rNoteParaEntry.maSelection.nStartPara ), uno::UNO_QUERY ); + if ( xParaProp.is() ) + { + std::vector<XMLPropertyState> aPropStates(xParaPropMapper->Filter(*this, xParaProp)); + OUString sName( rNoteParaEntry.maName ); + GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_PARAGRAPH, OUString(), std::move(aPropStates)); + GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_PARAGRAPH, sName); + } + } + } + } + + // note text styles + + rtl::Reference<SvXMLExportPropertyMapper> xTextPropMapper = XMLTextParagraphExport::CreateCharExtPropMapper( *this ); + + const std::vector<ScTextStyleEntry>& rNoteTextEntries = pSheetData->GetNoteTextStyles(); + for (const auto& rNoteTextEntry : rNoteTextEntries) + { + ScAddress aPos = rNoteTextEntry.maCellPos; + SCTAB nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( nTable ); + if (bCopySheet) + { + ScPostIt* pNote = pDoc->GetNote( aPos ); + OSL_ENSURE( pNote, "note not found" ); + if (pNote) + { + SdrCaptionObj* pDrawObj = pNote->GetOrCreateCaption( aPos ); + uno::Reference<text::XSimpleText> xCellText(pDrawObj->getUnoShape(), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xCursorProp(xCellText->createTextCursor(), uno::UNO_QUERY); + ScDrawTextCursor* pCursor = comphelper::getFromUnoTunnel<ScDrawTextCursor>( xCursorProp ); + if (pCursor) + { + pCursor->SetSelection( rNoteTextEntry.maSelection ); + + std::vector<XMLPropertyState> aPropStates(xTextPropMapper->Filter(*this, xCursorProp)); + OUString sName( rNoteTextEntry.maName ); + GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates)); + GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_TEXT, sName); + } + } + } + } + + // stored text styles + + // Calling createTextCursor fires up editeng, which is very slow, and often subsequent style entries + // refer to the same cell, so cache it. + ScAddress aPrevPos; + uno::Reference<beans::XPropertySet> xPrevCursorProp; + const std::vector<ScTextStyleEntry>& rTextEntries = pSheetData->GetTextStyles(); + for (const auto& rTextEntry : rTextEntries) + { + ScAddress aPos = rTextEntry.maCellPos; + sal_Int32 nTable = aPos.Tab(); + bool bCopySheet = pDoc->IsStreamValid( static_cast<SCTAB>(nTable) ); + if (!bCopySheet) + continue; + + //! separate method AddStyleFromText needed? + //! cache sheet object + + uno::Reference<beans::XPropertySet> xCursorProp; + if (xPrevCursorProp && aPrevPos == aPos) + xCursorProp = xPrevCursorProp; + else + { + uno::Reference<table::XCellRange> xCellRange(xIndex->getByIndex(nTable), uno::UNO_QUERY); + uno::Reference<text::XSimpleText> xCellText(xCellRange->getCellByPosition(aPos.Col(), aPos.Row()), uno::UNO_QUERY); + xCursorProp.set(xCellText->createTextCursor(), uno::UNO_QUERY); + } + ScCellTextCursor* pCursor = comphelper::getFromUnoTunnel<ScCellTextCursor>( xCursorProp ); + if (!pCursor) + continue; + pCursor->SetSelection( rTextEntry.maSelection ); + + std::vector<XMLPropertyState> aPropStates(xTextPropMapper->Filter(*this, xCursorProp)); + OUString sName( rTextEntry.maName ); + GetAutoStylePool()->AddNamed(sName, XmlStyleFamily::TEXT_TEXT, OUString(), std::move(aPropStates)); + GetAutoStylePool()->RegisterName(XmlStyleFamily::TEXT_TEXT, sName); + xPrevCursorProp = xCursorProp; + aPrevPos = aPos; + } + } + + ExportExternalRefCacheStyles(); + + if (!pSharedData) + { + SCTAB nTableCount(0); + sal_Int32 nShapesCount(0); + CollectSharedData(nTableCount, nShapesCount); + } + sal_Int32 nTableCount(xIndex->getCount()); + pCellStyles->AddNewTable(nTableCount - 1); + CollectShapesAutoStyles(nTableCount); + for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable, IncrementProgressBar(false)) + { + uno::Reference <sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY); + if (!xTable.is()) + continue; + + // table styles array must be complete, including copied tables - Add should find the stored style + uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY); + if (xTableProperties.is()) + { + std::vector<XMLPropertyState> aPropStates(xTableStylesExportPropertySetMapper->Filter(*this, xTableProperties)); + if(!aPropStates.empty()) + { + OUString sName; + GetAutoStylePool()->Add(sName, XmlStyleFamily::TABLE_TABLE, OUString(), std::move(aPropStates)); + aTableStyles.push_back(sName); + } + } + + // collect other auto-styles only for non-copied sheets + uno::Reference<sheet::XUniqueCellFormatRangesSupplier> xCellFormatRanges ( xTable, uno::UNO_QUERY ); + if ( xCellFormatRanges.is() ) + { + uno::Reference<container::XIndexAccess> xFormatRangesIndex(xCellFormatRanges->getUniqueCellFormatRanges()); + if (xFormatRangesIndex.is()) + { + sal_Int32 nFormatRangesCount(xFormatRangesIndex->getCount()); + GetProgressBarHelper()->ChangeReference(GetProgressBarHelper()->GetReference() + nFormatRangesCount); + for (sal_Int32 nFormatRange = 0; nFormatRange < nFormatRangesCount; ++nFormatRange) + { + uno::Reference< sheet::XSheetCellRanges> xCellRanges(xFormatRangesIndex->getByIndex(nFormatRange), uno::UNO_QUERY); + if (xCellRanges.is()) + { + uno::Reference <beans::XPropertySet> xProperties (xCellRanges, uno::UNO_QUERY); + if (xProperties.is()) + { + AddStyleFromCells(xProperties, xTable, nTable, nullptr); + IncrementProgressBar(false); + } + } + } + } + } + uno::Reference<table::XColumnRowRange> xColumnRowRange (xTable, uno::UNO_QUERY); + if (xColumnRowRange.is() && pDoc) + { + pDoc->SyncColRowFlags(); + uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns()); + if (xTableColumns.is()) + { + sal_Int32 nColumns(pDoc->GetLastChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable))); + pSharedData->SetLastColumn(nTable, nColumns); + table::CellRangeAddress aCellAddress(GetEndAddress(xTable)); + if (aCellAddress.EndColumn > nColumns) + { + ++nColumns; + pColumnStyles->AddNewTable(nTable, aCellAddress.EndColumn); + } + else + pColumnStyles->AddNewTable(nTable, nColumns); + sal_Int32 nColumn = 0; + while (nColumn <= pDoc->MaxCol()) + { + sal_Int32 nIndex(-1); + bool bIsVisible(true); + uno::Reference <beans::XPropertySet> xColumnProperties(xTableColumns->getByIndex(nColumn), uno::UNO_QUERY); + if (xColumnProperties.is()) + { + AddStyleFromColumn( xColumnProperties, nullptr, nIndex, bIsVisible ); + pColumnStyles->AddFieldStyleName(nTable, nColumn, nIndex, bIsVisible); + } + sal_Int32 nOld(nColumn); + nColumn = pDoc->GetNextDifferentChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCCOL>(nColumn)); + for (sal_Int32 i = nOld + 1; i < nColumn; ++i) + pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible); + } + if (aCellAddress.EndColumn > nColumns) + { + bool bIsVisible(true); + sal_Int32 nIndex(pColumnStyles->GetStyleNameIndex(nTable, nColumns, bIsVisible)); + for (sal_Int32 i = nColumns + 1; i <= aCellAddress.EndColumn; ++i) + pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible); + } + } + uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows()); + if (xTableRows.is()) + { + sal_Int32 nRows(pDoc->GetLastChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable))); + pSharedData->SetLastRow(nTable, nRows); + + pRowStyles->AddNewTable(nTable, pDoc->MaxRow()); + sal_Int32 nRow = 0; + while (nRow <= pDoc->MaxRow()) + { + sal_Int32 nIndex = 0; + uno::Reference <beans::XPropertySet> xRowProperties(xTableRows->getByIndex(nRow), uno::UNO_QUERY); + if(xRowProperties.is()) + { + AddStyleFromRow( xRowProperties, nullptr, nIndex ); + pRowStyles->AddFieldStyleName(nTable, nRow, nIndex); + } + sal_Int32 nOld(nRow); + nRow = pDoc->GetNextDifferentChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCROW>(nRow)); + if (nRow > nOld + 1) + pRowStyles->AddFieldStyleName(nTable, nOld + 1, nIndex, nRow - 1); + } + } + } + ExportCellTextAutoStyles(nTable); + } + + pChangeTrackingExportHelper->CollectAutoStyles(); + } + + if (getExportFlags() & SvXMLExportFlags::MASTERSTYLES) + GetPageExport()->collectAutoStyles(true); + + mbAutoStylesCollected = true; +} + +void ScXMLExport::ExportAutoStyles_() +{ + if (!GetModel().is()) + return; + + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY ); + if (!xSpreadDoc.is()) + return; + + uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); + if (!xIndex.is()) + return; + + collectAutoStyles(); + + if (getExportFlags() & SvXMLExportFlags::CONTENT) + { + GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_COLUMN); + GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_ROW); + GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_TABLE); + exportAutoDataStyles(); + GetAutoStylePool()->exportXML(XmlStyleFamily::TABLE_CELL); + + GetShapeExport()->exportAutoStyles(); + GetFormExport()->exportAutoStyles( ); + + if (pDoc) + { + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + // #i100879# write the table style for cached tables only if there are cached tables + // (same logic as in ExportExternalRefCacheStyles) + if (pRefMgr->hasExternalData()) + { + // Special table style for the external ref cache tables. + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sExternalRefTabStyleName); + AddAttribute(XML_NAMESPACE_STYLE, XML_FAMILY, XML_TABLE); + SvXMLElementExport aElemStyle(*this, XML_NAMESPACE_STYLE, XML_STYLE, true, true); + AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, XML_FALSE); + SvXMLElementExport aElemStyleTabProps(*this, XML_NAMESPACE_STYLE, XML_TABLE_PROPERTIES, true, true); + } + } + } + + if (getExportFlags() & SvXMLExportFlags::MASTERSTYLES) + { + exportAutoDataStyles(); + GetPageExport()->exportAutoStyles(); + } + + // #i30251#; only write Text Styles once + + if ((getExportFlags() & SvXMLExportFlags::CONTENT) || (getExportFlags() & SvXMLExportFlags::MASTERSTYLES)) + GetTextParagraphExport()->exportTextAutoStyles(); +} + +void ScXMLExport::ExportMasterStyles_() +{ + GetPageExport()->exportMasterStyles( true ); +} + +void ScXMLExport::CollectInternalShape( uno::Reference< drawing::XShape > const & xShape ) +{ + // detective objects and notes + SdrObject* pObject = SdrObject::getSdrObjectFromXShape( xShape ); + if( !pObject ) + return; + + // collect note caption objects from all layers (internal or hidden) + if( ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObject, static_cast< SCTAB >( nCurrentTable ) ) ) + { + if(pDoc->GetNote(pCaptData->maStart)) + { + pSharedData->AddNoteObj( xShape, pCaptData->maStart ); + + // #i60851# When the file is saved while editing a new note, + // the cell is still empty -> last column/row must be updated + OSL_ENSURE( pCaptData->maStart.Tab() == nCurrentTable, "invalid table in object data" ); + pSharedData->SetLastColumn( nCurrentTable, pCaptData->maStart.Col() ); + pSharedData->SetLastRow( nCurrentTable, pCaptData->maStart.Row() ); + } + } + // other objects from internal layer only (detective) + else if( pObject->GetLayer() == SC_LAYER_INTERN ) + { + ScDetectiveFunc aDetFunc( *pDoc, static_cast<SCTAB>(nCurrentTable) ); + ScAddress aPosition; + ScRange aSourceRange; + bool bRedLine; + ScDetectiveObjType eObjType = aDetFunc.GetDetectiveObjectType( + pObject, nCurrentTable, aPosition, aSourceRange, bRedLine ); + pSharedData->GetDetectiveObjContainer()->AddObject( eObjType, static_cast<SCTAB>(nCurrentTable), aPosition, aSourceRange, bRedLine ); + } +} + +bool ScXMLExport::GetMerged (const table::CellRangeAddress* pCellAddress, + const uno::Reference <sheet::XSpreadsheet>& xTable) +{ + bool bReady(false); + sal_Int32 nRow(pCellAddress->StartRow); + sal_Int32 nCol(pCellAddress->StartColumn); + sal_Int32 nEndRow(pCellAddress->EndRow); + sal_Int32 nEndCol(pCellAddress->EndColumn); + bool bRowInc(nEndRow > nRow); + while(!bReady && nRow <= nEndRow && nCol <= nEndCol) + { + uno::Reference<sheet::XSheetCellRange> xSheetCellRange(xTable->getCellRangeByPosition(nCol, nRow, nCol, nRow), uno::UNO_QUERY); + if (xSheetCellRange.is()) + { + uno::Reference<sheet::XSheetCellCursor> xCursor(xTable->createCursorByRange(xSheetCellRange)); + if(xCursor.is()) + { + uno::Reference<sheet::XCellRangeAddressable> xCellAddress (xCursor, uno::UNO_QUERY); + xCursor->collapseToMergedArea(); + table::CellRangeAddress aCellAddress2(xCellAddress->getRangeAddress()); + ScRange aScRange( aCellAddress2.StartColumn, aCellAddress2.StartRow, aCellAddress2.Sheet, + aCellAddress2.EndColumn, aCellAddress2.EndRow, aCellAddress2.Sheet ); + + if ((aScRange.aEnd.Row() > nRow || + aScRange.aEnd.Col() > nCol) && + aScRange.aStart.Row() == nRow && + aScRange.aStart.Col() == nCol) + { + pMergedRangesContainer->AddRange(aScRange); + pSharedData->SetLastColumn(aScRange.aEnd.Tab(), aScRange.aEnd.Col()); + pSharedData->SetLastRow(aScRange.aEnd.Tab(), aScRange.aEnd.Row()); + } + else + bReady = true; + } + } + if (!bReady) + { + if (bRowInc) + ++nRow; + else + ++nCol; + } + } + OSL_ENSURE(!(!bReady && nEndRow > nRow && nEndCol > nCol), "should not be possible"); + return !bReady; +} + +bool ScXMLExport::IsMatrix (const ScAddress& aCell, + ScRange& aCellAddress, bool& bIsFirst) const +{ + bIsFirst = false; + + ScRange aMatrixRange; + + if (pDoc && pDoc->GetMatrixFormulaRange(aCell, aMatrixRange)) + { + aCellAddress = aMatrixRange; + if ((aCellAddress.aStart.Col() == aCell.Col() && aCellAddress.aStart.Row() == aCell.Row()) && + (aCellAddress.aEnd.Col() > aCell.Col() || aCellAddress.aEnd.Row() > aCell.Row())) + { + bIsFirst = true; + return true; + } + else if (aCellAddress.aStart.Col() != aCell.Col() || aCellAddress.aStart.Row() != aCell.Row() || + aCellAddress.aEnd.Col() != aCell.Col() || aCellAddress.aEnd.Row()!= aCell.Row()) + return true; + else + { + bIsFirst = true; + return true; + } + } + + return false; +} + +void ScXMLExport::WriteTable(sal_Int32 nTable, const uno::Reference<sheet::XSpreadsheet>& xTable) +{ + if (!xTable.is()) + return; + + xCurrentTable.set(xTable); + uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY ); + if (!xName.is()) + return; + + nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable ); + OUString sOUTableName(xName->getName()); + AddAttribute(sAttrName, sOUTableName); + AddAttribute(sAttrStyleName, aTableStyles[nTable]); + + uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY); + const ScTableProtection* pProtect = nullptr; + if (xProtectable.is() && xProtectable->isProtected()) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE); + if (pDoc) + { + pProtect = pDoc->GetTabProtection(nTable); + if (pProtect) + { + OUStringBuffer aBuffer; + ScPasswordHash eHashUsed = PASSHASH_UNSPECIFIED; + if (pProtect->hasPasswordHash(PASSHASH_SHA1)) + { + ::comphelper::Base64::encode(aBuffer, + pProtect->getPasswordHash(PASSHASH_SHA1)); + eHashUsed = PASSHASH_SHA1; + } + else if (pProtect->hasPasswordHash(PASSHASH_SHA256)) + { + ::comphelper::Base64::encode(aBuffer, + pProtect->getPasswordHash(PASSHASH_SHA256)); + eHashUsed = PASSHASH_SHA256; + } + else if (pProtect->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1)) + { + // Double-hash this by SHA1 on top of the legacy xls hash. + uno::Sequence<sal_Int8> aHash = pProtect->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1); + ::comphelper::Base64::encode(aBuffer, aHash); + eHashUsed = PASSHASH_XL; + } + if (!aBuffer.isEmpty()) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear()); + if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + if (eHashUsed == PASSHASH_XL) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + ScPassHashHelper::getHashURI(PASSHASH_XL)); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2, + ScPassHashHelper::getHashURI(PASSHASH_SHA1)); + } + else if (eHashUsed == PASSHASH_SHA1) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + ScPassHashHelper::getHashURI(PASSHASH_SHA1)); + } + else if (eHashUsed == PASSHASH_SHA256) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + ScPassHashHelper::getHashURI(PASSHASH_SHA256)); + } + } + } + } + } + } + OUString sPrintRanges; + ScRange aColumnHeaderRange; + bool bHasColumnHeader; + GetColumnRowHeader(bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges); + if( !sPrintRanges.isEmpty() ) + AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges ); + else if (pDoc && !pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable))) + AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE); + SvXMLElementExport aElemT(*this, sElemTab, true, true); + + if (pProtect && pProtect->isProtected() && getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + if (pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_SELECT_PROTECTED_CELLS, XML_TRUE); + if (pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_SELECT_UNPROTECTED_CELLS, XML_TRUE); + + if (pProtect->isOptionEnabled(ScTableProtection::INSERT_COLUMNS)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_INSERT_COLUMNS, XML_TRUE); + if (pProtect->isOptionEnabled(ScTableProtection::INSERT_ROWS)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_INSERT_ROWS, XML_TRUE); + + if (pProtect->isOptionEnabled(ScTableProtection::DELETE_COLUMNS)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_COLUMNS, XML_TRUE); + if (pProtect->isOptionEnabled(ScTableProtection::DELETE_ROWS)) + AddAttribute(XML_NAMESPACE_LO_EXT, XML_DELETE_ROWS, XML_TRUE); + + OUString aElemName = GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_LO_EXT, GetXMLToken(XML_TABLE_PROTECTION)); + + SvXMLElementExport aElemProtected(*this, aElemName, true, true); + } + + CheckAttrList(); + + if ( pDoc && pDoc->GetSheetEvents( static_cast<SCTAB>(nTable) ) && + getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + // store sheet events + uno::Reference<document::XEventsSupplier> xSupplier(xTable, uno::UNO_QUERY); + uno::Reference<container::XNameAccess> xEvents = xSupplier->getEvents(); + GetEventExport().ExportExt( xEvents ); + } + + WriteTableSource(); + WriteScenario(); + uno::Reference<drawing::XDrawPage> xDrawPage; + if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is()) + { + ::xmloff::OOfficeFormsExport aForms(*this); + GetFormExport()->exportForms( xDrawPage ); + bool bRet(GetFormExport()->seekPage( xDrawPage )); + OSL_ENSURE( bRet, "OFormLayerXMLExport::seekPage failed!" ); + } + if (pSharedData->HasDrawPage()) + { + GetShapeExport()->seekShapes(pSharedData->GetDrawPage(nTable)); + WriteTableShapes(); + } + table::CellRangeAddress aRange(GetEndAddress(xTable)); + pSharedData->SetLastColumn(nTable, aRange.EndColumn); + pSharedData->SetLastRow(nTable, aRange.EndRow); + mpCellsItr->SetCurrentTable(static_cast<SCTAB>(nTable), xCurrentTable); + pGroupColumns->NewTable(); + pGroupRows->NewTable(); + FillColumnRowGroups(); + if (bHasColumnHeader) + pSharedData->SetLastColumn(nTable, aColumnHeaderRange.aEnd.Col()); + bRowHeaderOpen = false; + if (bHasRowHeader) + pSharedData->SetLastRow(nTable, aRowHeaderRange.aEnd.Row()); + pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable), + pSharedData->GetLastColumn(nTable), pCellStyles.get(), pDoc); + pRowFormatRanges->SetColDefaults(&pDefaults->GetColDefaults()); + pCellStyles->SetColDefaults(&pDefaults->GetColDefaults()); + ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader); + bool bIsFirst(true); + sal_Int32 nEqualCells(0); + ScMyCell aCell; + ScMyCell aPrevCell; + while (mpCellsItr->GetNext(aCell, pCellStyles.get())) + { + if (bIsFirst) + { + ExportFormatRanges(0, 0, aCell.maCellAddress.Col()-1, aCell.maCellAddress.Row(), nTable); + aPrevCell = aCell; + bIsFirst = false; + } + else + { + if ((aPrevCell.maCellAddress.Row() == aCell.maCellAddress.Row()) && + (aPrevCell.maCellAddress.Col() + nEqualCells + 1 == aCell.maCellAddress.Col())) + { + if(IsCellEqual(aPrevCell, aCell)) + ++nEqualCells; + else + { + WriteCell(aPrevCell, nEqualCells); + nEqualCells = 0; + aPrevCell = aCell; + } + } + else + { + WriteCell(aPrevCell, nEqualCells); + ExportFormatRanges(aPrevCell.maCellAddress.Col() + nEqualCells + 1, aPrevCell.maCellAddress.Row(), + aCell.maCellAddress.Col()-1, aCell.maCellAddress.Row(), nTable); + nEqualCells = 0; + aPrevCell = aCell; + } + } + } + if (!bIsFirst) + { + WriteCell(aPrevCell, nEqualCells); + ExportFormatRanges(aPrevCell.maCellAddress.Col() + nEqualCells + 1, aPrevCell.maCellAddress.Row(), + pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable); + } + else + ExportFormatRanges(0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable); + + CloseRow(pSharedData->GetLastRow(nTable)); + + if (!pDoc) + return; + + // Export sheet-local named ranges. + ScRangeName* pRangeName = pDoc->GetRangeName(nTable); + if (pRangeName && !pRangeName->empty()) + { + WriteNamedRange(pRangeName); + } + + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + //export new conditional format information + ExportConditionalFormat(nTable); + exportSparklineGroups(nTable); + } +} + +namespace { + +void writeContent( + ScXMLExport& rExport, const OUString& rStyleName, const OUString& rContent, const SvxFieldData* pField ) +{ + std::unique_ptr<SvXMLElementExport> pElem; + if (!rStyleName.isEmpty()) + { + // Formatted section with automatic style. + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, rStyleName); + OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_SPAN)); + pElem.reset(new SvXMLElementExport(rExport, aElemName, false, false)); + } + + if (pField) + { + // Write a field item. + OUString aFieldVal = ScEditUtil::GetCellFieldValue(*pField, rExport.GetDocument(), nullptr); + switch (pField->GetClassId()) + { + case text::textfield::Type::URL: + { + // <text:a xlink:href="url" xlink:type="simple">value</text:a> + + const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField); + const OUString& aURL = pURLField->GetURL(); + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(aURL)); + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, "simple"); + const OUString& aTargetFrame = pURLField->GetTargetFrame(); + if (!aTargetFrame.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, aTargetFrame); + + OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_A)); + SvXMLElementExport aElem(rExport, aElemName, false, false); + rExport.Characters(aFieldVal); + } + break; + case text::textfield::Type::DATE: + { + // <text:date style:data-style-name="N2" text:date-value="YYYY-MM-DD">value</text:date> + + Date aDate(Date::SYSTEM); + OUStringBuffer aBuf; + sal_Int32 nVal = aDate.GetYear(); + aBuf.append(nVal); + aBuf.append('-'); + nVal = aDate.GetMonth(); + if (nVal < 10) + aBuf.append('0'); + aBuf.append(nVal); + aBuf.append('-'); + nVal = aDate.GetDay(); + if (nVal < 10) + aBuf.append('0'); + aBuf.append(nVal); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, "N2"); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_DATE_VALUE, aBuf.makeStringAndClear()); + + OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_DATE)); + SvXMLElementExport aElem(rExport, aElemName, false, false); + rExport.Characters(aFieldVal); + } + break; + case text::textfield::Type::DOCINFO_TITLE: + { + // <text:title>value</text:title> + + OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_TITLE)); + SvXMLElementExport aElem(rExport, aElemName, false, false); + rExport.Characters(aFieldVal); + } + break; + case text::textfield::Type::TABLE: + { + // <text:sheet-name>value</text:sheet-name> + + OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_SHEET_NAME)); + SvXMLElementExport aElem(rExport, aElemName, false, false); + rExport.Characters(aFieldVal); + } + break; + default: + rExport.Characters(aFieldVal); + } + } + else + rExport.Characters(rContent); +} + +void flushParagraph( + ScXMLExport& rExport, std::u16string_view rParaText, + rtl::Reference<XMLPropertySetMapper> const & xMapper, rtl::Reference<SvXMLAutoStylePoolP> const & xStylePool, + const ScXMLEditAttributeMap& rAttrMap, + std::vector<editeng::Section>::const_iterator it, std::vector<editeng::Section>::const_iterator const & itEnd ) +{ + OUString aElemName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_P)); + SvXMLElementExport aElemP(rExport, aElemName, false, false); + + for (; it != itEnd; ++it) + { + const editeng::Section& rSec = *it; + + OUString aContent(rParaText.substr(rSec.mnStart, rSec.mnEnd - rSec.mnStart)); + + std::vector<XMLPropertyState> aPropStates; + const SvxFieldData* pField = toXMLPropertyStates(rExport, aPropStates, rSec.maAttributes, xMapper, rAttrMap); + OUString aStyleName = xStylePool->Find(XmlStyleFamily::TEXT_TEXT, OUString(), aPropStates); + writeContent(rExport, aStyleName, aContent, pField); + } +} + +} + +void ScXMLExport::WriteCell(ScMyCell& aCell, sal_Int32 nEqualCellCount) +{ + // nEqualCellCount is the number of additional cells + SetRepeatAttribute(nEqualCellCount, (aCell.nType != table::CellContentType_EMPTY)); + + if (aCell.nStyleIndex != -1) + AddAttribute(sAttrStyleName, pCellStyles->GetStyleNameByIndex(aCell.nStyleIndex, aCell.bIsAutoStyle)); + if (aCell.nValidationIndex > -1) + AddAttribute(XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, pValidationsContainer->GetValidationName(aCell.nValidationIndex)); + const bool bIsFirstMatrixCell(aCell.bIsMatrixBase); + if (bIsFirstMatrixCell) + { + SCCOL nColumns( aCell.aMatrixRange.aEnd.Col() - aCell.aMatrixRange.aStart.Col() + 1 ); + SCROW nRows( aCell.aMatrixRange.aEnd.Row() - aCell.aMatrixRange.aStart.Row() + 1 ); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED, OUString::number(nColumns)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED, OUString::number(nRows)); + } + bool bIsEmpty(false); + switch (aCell.nType) + { + case table::CellContentType_EMPTY : + { + bIsEmpty = true; + } + break; + case table::CellContentType_VALUE : + { + GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes( + aCell.nNumberFormat, aCell.maBaseCell.mfValue); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes( + aCell.nNumberFormat, aCell.maBaseCell.mfValue, false, XML_NAMESPACE_CALC_EXT, false); + } + break; + case table::CellContentType_TEXT : + { + OUString sFormattedString(lcl_GetFormattedString(pDoc, aCell.maBaseCell, aCell.maCellAddress)); + OUString sCellString = aCell.maBaseCell.getString(pDoc); + GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes( + sCellString, sFormattedString); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes( + sCellString, sFormattedString, false, XML_NAMESPACE_CALC_EXT); + } + break; + case table::CellContentType_FORMULA : + { + if (aCell.maBaseCell.meType == CELLTYPE_FORMULA) + { + const bool bIsMatrix(bIsFirstMatrixCell || aCell.bIsMatrixCovered); + ScFormulaCell* pFormulaCell = aCell.maBaseCell.mpFormula; + if (!bIsMatrix || bIsFirstMatrixCell) + { + if (!mpCompileFormulaCxt) + { + const formula::FormulaGrammar::Grammar eGrammar = pDoc->GetStorageGrammar(); + mpCompileFormulaCxt.reset(new sc::CompileFormulaContext(*pDoc, eGrammar)); + } + + OUString aFormula = pFormulaCell->GetFormula(*mpCompileFormulaCxt); + sal_uInt16 nNamespacePrefix = + (mpCompileFormulaCxt->getGrammar() == formula::FormulaGrammar::GRAM_ODFF ? XML_NAMESPACE_OF : XML_NAMESPACE_OOOC); + + if (!bIsMatrix) + { + AddAttribute(sAttrFormula, GetNamespaceMap().GetQNameByKey(nNamespacePrefix, aFormula, false)); + } + else + { + AddAttribute(sAttrFormula, GetNamespaceMap().GetQNameByKey(nNamespacePrefix, aFormula.copy(1, aFormula.getLength()-2), false)); + } + } + if (pFormulaCell->GetErrCode() != FormulaError::NONE) + { + AddAttribute(sAttrValueType, XML_STRING); + AddAttribute(sAttrStringValue, aCell.maBaseCell.getString(pDoc)); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + //export calcext:value-type="error" + AddAttribute(XML_NAMESPACE_CALC_EXT,XML_VALUE_TYPE, OUString("error")); + } + } + else if (pFormulaCell->IsValue()) + { + bool bIsStandard; + OUString sCurrency; + GetNumberFormatAttributesExportHelper()->GetCellType(aCell.nNumberFormat, sCurrency, bIsStandard); + if (pDoc) + { + GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes( + aCell.nNumberFormat, pDoc->GetValue(aCell.maCellAddress)); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetNumberFormatAttributesExportHelper()->SetNumberFormatAttributes( + aCell.nNumberFormat, pDoc->GetValue(aCell.maCellAddress), false, XML_NAMESPACE_CALC_EXT, false ); + } + } + } + else + { + if (!aCell.maBaseCell.getString(pDoc).isEmpty()) + { + AddAttribute(sAttrValueType, XML_STRING); + AddAttribute(sAttrStringValue, aCell.maBaseCell.getString(pDoc)); + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + AddAttribute(XML_NAMESPACE_CALC_EXT,XML_VALUE_TYPE, XML_STRING); + } + } + } + } + } + break; + default: + break; + } + OUString* pCellString(&sElemCell); + if (aCell.bIsCovered) + { + pCellString = &sElemCoveredCell; + } + else + { + if (aCell.bIsMergedBase) + { + SCCOL nColumns( aCell.aMergeRange.aEnd.Col() - aCell.aMergeRange.aStart.Col() + 1 ); + SCROW nRows( aCell.aMergeRange.aEnd.Row() - aCell.aMergeRange.aStart.Row() + 1 ); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, OUString::number(nColumns)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, OUString::number(nRows)); + } + } + SvXMLElementExport aElemC(*this, *pCellString, true, true); + CheckAttrList(); + WriteAreaLink(aCell); + WriteAnnotation(aCell); + WriteDetective(aCell); + + if (!bIsEmpty) + { + if (aCell.maBaseCell.meType == CELLTYPE_EDIT) + { + WriteEditCell(aCell.maBaseCell.mpEditText); + } + else if (aCell.maBaseCell.meType == CELLTYPE_FORMULA && aCell.maBaseCell.mpFormula->IsMultilineResult()) + { + WriteMultiLineFormulaResult(aCell.maBaseCell.mpFormula); + } + else + { + SvXMLElementExport aElemP(*this, sElemP, true, false); + + OUString aParaStr = + ScCellFormat::GetOutputString(*pDoc, aCell.maCellAddress, aCell.maBaseCell); + + bool bPrevCharWasSpace = true; + GetTextParagraphExport()->exportCharacterData(aParaStr, bPrevCharWasSpace); + } + } + WriteShapes(aCell); + if (!bIsEmpty) + IncrementProgressBar(false); +} + +void ScXMLExport::WriteEditCell(const EditTextObject* pText) +{ + rtl::Reference<XMLPropertySetMapper> xMapper = GetTextParagraphExport()->GetTextPropMapper()->getPropertySetMapper(); + rtl::Reference<SvXMLAutoStylePoolP> xStylePool = GetAutoStylePool(); + const ScXMLEditAttributeMap& rAttrMap = GetEditAttributeMap(); + + // Get raw paragraph texts first. + std::vector<OUString> aParaTexts; + sal_Int32 nParaCount = pText->GetParagraphCount(); + aParaTexts.reserve(nParaCount); + for (sal_Int32 i = 0; i < nParaCount; ++i) + aParaTexts.push_back(pText->GetText(i)); + + // Get all section data and iterate through them. + std::vector<editeng::Section> aAttrs; + pText->GetAllSections(aAttrs); + std::vector<editeng::Section>::const_iterator itSec = aAttrs.begin(), itSecEnd = aAttrs.end(); + std::vector<editeng::Section>::const_iterator itPara = itSec; + sal_Int32 nCurPara = 0; // current paragraph + for (; itSec != itSecEnd; ++itSec) + { + const editeng::Section& rSec = *itSec; + if (nCurPara == rSec.mnParagraph) + // Still in the same paragraph. + continue; + + // Start of a new paragraph. Flush the old paragraph. + flushParagraph(*this, aParaTexts[nCurPara], xMapper, xStylePool, rAttrMap, itPara, itSec); + nCurPara = rSec.mnParagraph; + itPara = itSec; + } + + flushParagraph(*this, aParaTexts[nCurPara], xMapper, xStylePool, rAttrMap, itPara, itSecEnd); +} + +void ScXMLExport::WriteMultiLineFormulaResult(const ScFormulaCell* pCell) +{ + OUString aElemName = GetNamespaceMap().GetQNameByKey(XML_NAMESPACE_TEXT, GetXMLToken(XML_P)); + + OUString aResStr = pCell->GetResultString().getString(); + const sal_Unicode* p = aResStr.getStr(); + const sal_Unicode* pEnd = p + static_cast<size_t>(aResStr.getLength()); + const sal_Unicode* pPara = p; // paragraph head. + for (; p != pEnd; ++p) + { + if (*p != '\n') + continue; + + // flush the paragraph. + OUString aContent; + if (*pPara == '\n') + ++pPara; + if (p > pPara) + aContent = OUString(pPara, p-pPara); + + SvXMLElementExport aElem(*this, aElemName, false, false); + Characters(aContent); + + pPara = p; + } + + OUString aContent; + if (*pPara == '\n') + ++pPara; + if (pEnd > pPara) + aContent = OUString(pPara, pEnd-pPara); + + SvXMLElementExport aElem(*this, aElemName, false, false); + Characters(aContent); +} + +void ScXMLExport::ExportShape(const uno::Reference < drawing::XShape >& xShape, awt::Point* pPoint) +{ + uno::Reference < beans::XPropertySet > xShapeProps ( xShape, uno::UNO_QUERY ); + bool bIsChart( false ); + if (xShapeProps.is()) + { + sal_Int32 nZOrder = 0; + if (xShapeProps->getPropertyValue("ZOrder") >>= nZOrder) + { + AddAttribute(XML_NAMESPACE_DRAW, XML_ZINDEX, OUString::number(nZOrder)); + } + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xShapeProps->getPropertySetInfo(); + OUString sPropCLSID ("CLSID"); + if( xPropSetInfo->hasPropertyByName( sPropCLSID ) ) + { + OUString sCLSID; + if (xShapeProps->getPropertyValue( sPropCLSID ) >>= sCLSID) + { + if ( sCLSID.equalsIgnoreAsciiCase(GetChartExport()->getChartCLSID()) ) + { + // we have a chart + OUString sRanges; + if ( pDoc ) + { + OUString aChartName; + xShapeProps->getPropertyValue( "PersistName" ) >>= aChartName; + ScChartListenerCollection* pCollection = pDoc->GetChartListenerCollection(); + if (pCollection) + { + ScChartListener* pListener = pCollection->findByName(aChartName); + if (pListener) + { + const ScRangeListRef& rRangeList = pListener->GetRangeList(); + if ( rRangeList.is() ) + { + ScRangeStringConverter::GetStringFromRangeList( sRanges, rRangeList.get(), pDoc, FormulaGrammar::CONV_OOO ); + if ( !sRanges.isEmpty() ) + { + bIsChart = true; + rtl::Reference<SvXMLAttributeList> pAttrList = new SvXMLAttributeList(); + pAttrList->AddAttribute( + GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, GetXMLToken( XML_NOTIFY_ON_UPDATE_OF_RANGES ) ), sRanges ); + GetShapeExport()->exportShape( xShape, SEF_DEFAULT, pPoint, pAttrList.get() ); + } + } + } + } + } + + if ( sRanges.isEmpty() ) + { + uno::Reference< frame::XModel > xChartModel; + if( ( xShapeProps->getPropertyValue( "Model" ) >>= xChartModel ) && + xChartModel.is()) + { + uno::Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY ); + uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartModel, uno::UNO_QUERY ); + if( xChartDoc.is() && xReceiver.is() && + ! xChartDoc->hasInternalDataProvider()) + { + // we have a chart that gets its data from Calc + bIsChart = true; + uno::Sequence< OUString > aRepresentations( + xReceiver->getUsedRangeRepresentations()); + rtl::Reference<SvXMLAttributeList> pAttrList; + try + { + if (aRepresentations.hasElements()) + { + // add the ranges used by the chart to the shape + // element to be able to start listening after + // load (when the chart is not yet loaded) + uno::Reference< chart2::data::XRangeXMLConversion > xRangeConverter( xChartDoc->getDataProvider(), uno::UNO_QUERY ); + sRanges = lcl_RangeSequenceToString( aRepresentations, xRangeConverter ); + pAttrList = new SvXMLAttributeList(); + pAttrList->AddAttribute( + GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, GetXMLToken(XML_NOTIFY_ON_UPDATE_OF_RANGES) ), sRanges ); + } + } + catch (const lang::IllegalArgumentException&) + { + TOOLS_WARN_EXCEPTION("sc", "Exception in lcl_RangeSequenceToString - invalid range?"); + } + GetShapeExport()->exportShape(xShape, SEF_DEFAULT, pPoint, pAttrList.get()); + } + } + } + } + } + } + } + if (!bIsChart) + GetShapeExport()->exportShape(xShape, SEF_DEFAULT, pPoint); + + IncrementProgressBar(false); +} + +void ScXMLExport::WriteShapes(const ScMyCell& rMyCell) +{ + if( !(rMyCell.bHasShape && !rMyCell.aShapeList.empty() && pDoc) ) + return; + + // Reference point to turn absolute coordinates in reference point + offset. That happens in most + // cases in XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint, which gets the absolute + // coordinates as translation from matrix in property "Transformation". For cell anchored shapes + // the reference point is left-top (in LTR mode) of that cell, which contains the shape. + tools::Rectangle aCellRectFull = pDoc->GetMMRect( + rMyCell.maCellAddress.Col(), rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Col(), + rMyCell.maCellAddress.Row(), rMyCell.maCellAddress.Tab(), false /*bHiddenAsZero*/); + awt::Point aPoint; + bool bNegativePage = pDoc->IsNegativePage(rMyCell.maCellAddress.Tab()); + if (bNegativePage) + aPoint.X = aCellRectFull.Right(); + else + aPoint.X = aCellRectFull.Left(); + aPoint.Y = aCellRectFull.Top(); + + for (const auto& rShape : rMyCell.aShapeList) + { + if (rShape.xShape.is()) + { + // The current object geometry is based on bHiddenAsZero=true, but ODF file format + // needs it as if there were no hidden rows or columns. We manipulate the geometry + // accordingly for writing xml markup and restore geometry later. + bool bNeedsRestore = false; + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rShape.xShape); + // Remember original geometry + std::unique_ptr<SdrObjGeoData> pGeoData; + if (pObj) + pGeoData = pObj->GetGeoData(); + + // Hiding row or column affects the shape based on its snap rect. So we need start and + // end cell address of snap rect. In case of a transformed shape, it is not in rMyCell. + ScAddress aSnapStartAddress = rMyCell.maCellAddress; + ScDrawObjData* pObjData = nullptr; + if (pObj) + { + pObjData = ScDrawLayer::GetObjData(pObj); + if (pObjData) + aSnapStartAddress = pObjData->maStart; + } + + // In case rows or columns are hidden above or before the snap rect, move the shape to the + // position it would have, if these rows and columns are visible. + tools::Rectangle aRectFull = pDoc->GetMMRect( + aSnapStartAddress.Col(), aSnapStartAddress.Row(), aSnapStartAddress.Col(), + aSnapStartAddress.Row(), aSnapStartAddress.Tab(), false /*bHiddenAsZero*/); + tools::Rectangle aRectReduced = pDoc->GetMMRect( + aSnapStartAddress.Col(), aSnapStartAddress.Row(), aSnapStartAddress.Col(), + aSnapStartAddress.Row(), aSnapStartAddress.Tab(), true /*bHiddenAsZero*/); + const tools::Long nLeftDiff(aRectFull.Left() - aRectReduced.Left()); + const tools::Long nTopDiff(aRectFull.Top() - aRectReduced.Top()); + if (pObj && (abs(nLeftDiff) > 1 || abs(nTopDiff) > 1)) + { + bNeedsRestore = true; + pObj->NbcMove(Size(nLeftDiff, nTopDiff)); + } + + // tdf#137033 In case the shape is anchored "To Cell (resize with cell)" hiding rows or + // columns inside the snap rect has not only changed size of the shape but rotate and shear + // angle too. We resize the shape to full size. That will recover the original angles too. + if (rShape.bResizeWithCell && pObjData) // implies pObj & aSnapStartAddress = pObjData->maStart + { + // Get original size from anchor + const Point aSnapStartOffset = pObjData->maStartOffset; + // In case of 'resize with cell' maEnd and maEndOffset should be valid. + const ScAddress aSnapEndAddress(pObjData->maEnd); + const Point aSnapEndOffset = pObjData->maEndOffset; + const tools::Rectangle aStartCellRect = pDoc->GetMMRect( + aSnapStartAddress.Col(), aSnapStartAddress.Row(), aSnapStartAddress.Col(), + aSnapStartAddress.Row(), aSnapStartAddress.Tab(), false /*bHiddenAsZero*/); + const tools::Rectangle aEndCellRect = pDoc->GetMMRect( + aSnapEndAddress.Col(), aSnapEndAddress.Row(), aSnapEndAddress.Col(), + aSnapEndAddress.Row(), aSnapEndAddress.Tab(), false /*bHiddenAsZero*/); + if (bNegativePage) + { + aRectFull.SetLeft(aEndCellRect.Right() - aSnapEndOffset.X()); + aRectFull.SetRight(aStartCellRect.Right() - aSnapStartOffset.X()); + } + else + { + aRectFull.SetLeft(aStartCellRect.Left() + aSnapStartOffset.X()); + aRectFull.SetRight(aEndCellRect.Left() + aSnapEndOffset.X()); + } + aRectFull.SetTop(aStartCellRect.Top() + aSnapStartOffset.Y()); + aRectFull.SetBottom(aEndCellRect.Top() + aSnapEndOffset.Y()); + aRectReduced = pObjData->getShapeRect(); + if(abs(aRectFull.getWidth() - aRectReduced.getWidth()) > 1 + || abs(aRectFull.getHeight() - aRectReduced.getHeight()) > 1) + { + bNeedsRestore = true; + Fraction aScaleWidth(aRectFull.getWidth(), aRectReduced.getWidth()); + if (!aScaleWidth.IsValid()) + aScaleWidth = Fraction(1.0); + Fraction aScaleHeight(aRectFull.getHeight(), aRectReduced.getHeight()); + if (!aScaleHeight.IsValid()) + aScaleHeight = Fraction(1.0); + pObj->NbcResize(pObj->GetRelativePos(), aScaleWidth, aScaleHeight); + } + } + + // We only write the end address if we want the shape to resize with the cell + if ( rShape.bResizeWithCell && + rShape.xShape->getShapeType() != "com.sun.star.drawing.CaptionShape" ) + { + OUString sEndAddress; + ScRangeStringConverter::GetStringFromAddress(sEndAddress, rShape.aEndAddress, pDoc, FormulaGrammar::CONV_OOO); + AddAttribute(XML_NAMESPACE_TABLE, XML_END_CELL_ADDRESS, sEndAddress); + OUStringBuffer sBuffer; + GetMM100UnitConverter().convertMeasureToXML( + sBuffer, rShape.nEndX); + AddAttribute(XML_NAMESPACE_TABLE, XML_END_X, sBuffer.makeStringAndClear()); + GetMM100UnitConverter().convertMeasureToXML( + sBuffer, rShape.nEndY); + AddAttribute(XML_NAMESPACE_TABLE, XML_END_Y, sBuffer.makeStringAndClear()); + } + + // Correct above calculated reference point for some cases: + // a) For a RTL-sheet translate from matrix is not suitable, because the shape + // from xml (which is always LTR) is not mirrored to negative page but shifted. + // b) In case of horizontal mirrored, 'resize with cell' anchored custom shape, translate + // has wrong values. FixMe: Why is translate wrong? + // c) Measure lines do not use transformation matrix but use start and end point directly. + ScDrawObjData* pNRObjData = nullptr; + if (pObj && bNegativePage + && rShape.xShape->getShapeType() == "com.sun.star.drawing.MeasureShape") + { + // inverse of shift when import + tools::Rectangle aSnapRect = pObj->GetSnapRect(); + aPoint.X = aSnapRect.Left() + aSnapRect.Right() - aPoint.X; + } + else if (pObj && (pNRObjData = ScDrawLayer::GetNonRotatedObjData(pObj)) + && ((rShape.bResizeWithCell && pObj->GetObjIdentifier() == SdrObjKind::CustomShape + && static_cast<SdrObjCustomShape*>(pObj)->IsMirroredX()) + || bNegativePage)) + { + //In these cases we set reference Point = matrix translate - startOffset. + awt::Point aMatrixTranslate = rShape.xShape->getPosition(); + aPoint.X = aMatrixTranslate.X - pNRObjData->maStartOffset.X(); + aPoint.Y = aMatrixTranslate.Y - pNRObjData->maStartOffset.Y(); + } + + ExportShape(rShape.xShape, &aPoint); + + // Restore object geometry + if (bNeedsRestore && pObj && pGeoData) + pObj->SetGeoData(*pGeoData); + } + } +} + +void ScXMLExport::WriteTableShapes() +{ + ScMyTableShapes* pTableShapes(pSharedData->GetTableShapes()); + if (!pTableShapes || (*pTableShapes)[nCurrentTable].empty()) + return; + + OSL_ENSURE(pTableShapes->size() > static_cast<size_t>(nCurrentTable), "wrong Table"); + SvXMLElementExport aShapesElem(*this, XML_NAMESPACE_TABLE, XML_SHAPES, true, false); + for (const auto& rxShape : (*pTableShapes)[nCurrentTable]) + { + if (rxShape.is()) + { + if (pDoc->IsNegativePage(static_cast<SCTAB>(nCurrentTable))) + { + // RTL-mirroring refers to snap rectangle, not to logic rectangle, therefore cannot use + // getPosition() and getSize(), but need property "FrameRect" from rxShape or + // GetSnapRect() from associated SdrObject. + uno::Reference<beans::XPropertySet> xShapeProp(rxShape, uno::UNO_QUERY); + awt::Rectangle aFrameRect; + if (xShapeProp.is() && (xShapeProp->getPropertyValue("FrameRect") >>= aFrameRect)) + { + // file format uses shape in LTR mode. newLeft = - oldRight = - (oldLeft + width). + // newTranslate = oldTranslate - refPoint, oldTranslate from transformation matrix, + // calculated in XMLShapeExport::exportShape common for all modules. + // oldTranslate.X = oldLeft ==> refPoint.X = 2 * oldLeft + width + awt::Point aRefPoint; + aRefPoint.X = 2 * aFrameRect.X + aFrameRect.Width - 1; + aRefPoint.Y = 0; + ExportShape(rxShape, &aRefPoint); + } + // else should not happen + } + else + ExportShape(rxShape, nullptr); + } + } + (*pTableShapes)[nCurrentTable].clear(); +} + +void ScXMLExport::WriteAreaLink( const ScMyCell& rMyCell ) +{ + if( !rMyCell.bHasAreaLink ) + return; + + const ScMyAreaLink& rAreaLink = rMyCell.aAreaLink; + AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, rAreaLink.sSourceStr ); + AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(rAreaLink.sURL) ); + AddAttribute( XML_NAMESPACE_TABLE, XML_FILTER_NAME, rAreaLink.sFilter ); + if( !rAreaLink.sFilterOptions.isEmpty() ) + AddAttribute( XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, rAreaLink.sFilterOptions ); + AddAttribute( XML_NAMESPACE_TABLE, XML_LAST_COLUMN_SPANNED, OUString::number(rAreaLink.GetColCount()) ); + AddAttribute( XML_NAMESPACE_TABLE, XML_LAST_ROW_SPANNED, OUString::number(rAreaLink.GetRowCount()) ); + if( rAreaLink.nRefreshDelaySeconds ) + { + OUStringBuffer sValue; + ::sax::Converter::convertDuration( sValue, + static_cast<double>(rAreaLink.nRefreshDelaySeconds) / 86400 ); + AddAttribute( XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, sValue.makeStringAndClear() ); + } + SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_CELL_RANGE_SOURCE, true, true ); +} + +void ScXMLExport::exportAnnotationMeta( const uno::Reference < drawing::XShape >& xShape) +{ + ScPostIt* pNote = pCurrentCell->pNote; + + if (!pNote) + return; + + // TODO : notes + //is it still useful, as this call back is only called from ScXMLExport::WriteAnnotation + // and should be in sync with pCurrentCell + SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(pCurrentCell->maCellAddress); + uno::Reference<drawing::XShape> xCurrentShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY ); + if (xCurrentShape.get()!=xShape.get()) + return; + + const OUString& sAuthor(pNote->GetAuthor()); + if (!sAuthor.isEmpty()) + { + SvXMLElementExport aCreatorElem( *this, XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + Characters(sAuthor); + } + + const OUString& aDate(pNote->GetDate()); + if (pDoc) + { + SvNumberFormatter* pNumForm = pDoc->GetFormatTable(); + double fDate; + sal_uInt32 nfIndex = pNumForm->GetFormatIndex(NF_DATE_SYS_DDMMYYYY, LANGUAGE_SYSTEM); + if (pNumForm->IsNumberFormat(aDate, nfIndex, fDate)) + { + OUStringBuffer sBuf; + GetMM100UnitConverter().convertDateTime(sBuf, fDate,true); + SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC, + XML_DATE, true, + false ); + Characters(sBuf.makeStringAndClear()); + } + else + { + SvXMLElementExport aDateElem( *this, XML_NAMESPACE_META, + XML_DATE_STRING, true, + false ); + Characters(aDate); + } + } + else + { + SvXMLElementExport aDateElem( *this, XML_NAMESPACE_META, + XML_DATE_STRING, true, + false ); + Characters(aDate); + } +} + +void ScXMLExport::WriteAnnotation(const ScMyCell& rMyCell) +{ + ScPostIt* pNote = pDoc->GetNote(rMyCell.maCellAddress); + if (!pNote) + return; + + if (pNote->IsCaptionShown()) + AddAttribute(XML_NAMESPACE_OFFICE, XML_DISPLAY, XML_TRUE); + + pCurrentCell = &rMyCell; + + SdrCaptionObj* pNoteCaption = pNote->GetOrCreateCaption(rMyCell.maCellAddress); + if (pNoteCaption) + { + uno::Reference<drawing::XShape> xShape( pNoteCaption->getUnoShape(), uno::UNO_QUERY ); + if (xShape.is()) + GetShapeExport()->exportShape(xShape, SEF_DEFAULT|XMLShapeExportFlags::ANNOTATION); + } + + pCurrentCell = nullptr; +} + +void ScXMLExport::WriteDetective( const ScMyCell& rMyCell ) +{ + if( !(rMyCell.bHasDetectiveObj || rMyCell.bHasDetectiveOp) ) + return; + + const ScMyDetectiveObjVec& rObjVec = rMyCell.aDetectiveObjVec; + const ScMyDetectiveOpVec& rOpVec = rMyCell.aDetectiveOpVec; + sal_Int32 nObjCount(rObjVec.size()); + sal_Int32 nOpCount(rOpVec.size()); + if( !(nObjCount || nOpCount) ) + return; + + SvXMLElementExport aDetElem( *this, XML_NAMESPACE_TABLE, XML_DETECTIVE, true, true ); + OUString sString; + for(const auto& rObj : rObjVec) + { + if (rObj.eObjType != SC_DETOBJ_CIRCLE) + { + if( (rObj.eObjType == SC_DETOBJ_ARROW) || (rObj.eObjType == SC_DETOBJ_TOOTHERTAB)) + { + ScRangeStringConverter::GetStringFromRange( sString, rObj.aSourceRange, pDoc, FormulaGrammar::CONV_OOO ); + AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sString ); + } + sString = ScXMLConverter::GetStringFromDetObjType( rObj.eObjType ); + AddAttribute( XML_NAMESPACE_TABLE, XML_DIRECTION, sString ); + if( rObj.bHasError ) + AddAttribute( XML_NAMESPACE_TABLE, XML_CONTAINS_ERROR, XML_TRUE ); + } + else + AddAttribute( XML_NAMESPACE_TABLE, XML_MARKED_INVALID, XML_TRUE ); + SvXMLElementExport aRangeElem( *this, XML_NAMESPACE_TABLE, XML_HIGHLIGHTED_RANGE, true, true ); + } + for(const auto& rOp : rOpVec) + { + OUString sOpString = ScXMLConverter::GetStringFromDetOpType( rOp.eOpType ); + AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, sOpString ); + AddAttribute( XML_NAMESPACE_TABLE, XML_INDEX, OUString::number(rOp.nIndex) ); + SvXMLElementExport aRangeElem( *this, XML_NAMESPACE_TABLE, XML_OPERATION, true, true ); + } +} + +void ScXMLExport::SetRepeatAttribute(sal_Int32 nEqualCellCount, bool bIncProgress) +{ + // nEqualCellCount is additional cells, so the attribute value is nEqualCellCount+1 + if (nEqualCellCount > 0) + { + sal_Int32 nTemp(nEqualCellCount + 1); + OUString sOUEqualCellCount(OUString::number(nTemp)); + AddAttribute(sAttrColumnsRepeated, sOUEqualCellCount); + if (bIncProgress) + IncrementProgressBar(false, nEqualCellCount); + } +} + +bool ScXMLExport::IsEditCell(const ScMyCell& rCell) +{ + return rCell.maBaseCell.meType == CELLTYPE_EDIT; +} + +bool ScXMLExport::IsCellEqual (const ScMyCell& aCell1, const ScMyCell& aCell2) +{ + bool bIsEqual = false; + if( !aCell1.bIsMergedBase && !aCell2.bIsMergedBase && + aCell1.bIsCovered == aCell2.bIsCovered && + !aCell1.bIsMatrixBase && !aCell2.bIsMatrixBase && + aCell1.bIsMatrixCovered == aCell2.bIsMatrixCovered && + aCell1.bHasAnnotation == aCell2.bHasAnnotation && + !aCell1.bHasShape && !aCell2.bHasShape && + aCell1.bHasAreaLink == aCell2.bHasAreaLink && + !aCell1.bHasDetectiveObj && !aCell2.bHasDetectiveObj) + { + if( (aCell1.bHasAreaLink && + (aCell1.aAreaLink.GetColCount() == 1) && + (aCell2.aAreaLink.GetColCount() == 1) && + aCell1.aAreaLink.Compare( aCell2.aAreaLink ) ) || + !aCell1.bHasAreaLink ) + { + if (!aCell1.bHasAnnotation) + { + if ((((aCell1.nStyleIndex == aCell2.nStyleIndex) && (aCell1.bIsAutoStyle == aCell2.bIsAutoStyle)) || + ((aCell1.nStyleIndex == aCell2.nStyleIndex) && (aCell1.nStyleIndex == -1))) && + aCell1.nValidationIndex == aCell2.nValidationIndex && + aCell1.nType == aCell2.nType) + { + switch ( aCell1.nType ) + { + case table::CellContentType_EMPTY : + { + bIsEqual = true; + } + break; + case table::CellContentType_VALUE : + { + // #i29101# number format may be different from column default styles, + // but can lead to different value types, so it must also be compared + bIsEqual = (aCell1.nNumberFormat == aCell2.nNumberFormat) && + (aCell1.maBaseCell.mfValue == aCell2.maBaseCell.mfValue); + } + break; + case table::CellContentType_TEXT : + { + if (IsEditCell(aCell1) || IsEditCell(aCell2)) + bIsEqual = false; + else + { + bIsEqual = (aCell1.maBaseCell.getString(pDoc) == aCell2.maBaseCell.getString(pDoc)); + } + } + break; + case table::CellContentType_FORMULA : + { + bIsEqual = false; + } + break; + default : + { + bIsEqual = false; + } + break; + } + } + } + } + } + return bIsEqual; +} + +void ScXMLExport::WriteCalculationSettings(const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc) +{ + uno::Reference<beans::XPropertySet> xPropertySet(xSpreadDoc, uno::UNO_QUERY); + if (!xPropertySet.is()) + return; + + bool bCalcAsShown (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_CALCASSHOWN) )); + bool bIgnoreCase (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_IGNORECASE) )); + bool bLookUpLabels (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_LOOKUPLABELS) )); + bool bMatchWholeCell (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_MATCHWHOLE) )); + bool bUseRegularExpressions (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_REGEXENABLED) )); + bool bUseWildcards (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_WILDCARDSENABLED) )); + if (bUseWildcards && bUseRegularExpressions) + bUseRegularExpressions = false; // mutually exclusive, wildcards take precedence + bool bIsIterationEnabled (::cppu::any2bool( xPropertySet->getPropertyValue(SC_UNO_ITERENABLED) )); + sal_uInt16 nYear2000 (pDoc ? pDoc->GetDocOptions().GetYear2000() : 0); + sal_Int32 nIterationCount(100); + xPropertySet->getPropertyValue( SC_UNO_ITERCOUNT ) >>= nIterationCount; + double fIterationEpsilon = 0; + xPropertySet->getPropertyValue( SC_UNO_ITEREPSILON ) >>= fIterationEpsilon; + util::Date aNullDate; + xPropertySet->getPropertyValue( SC_UNO_NULLDATE ) >>= aNullDate; + if (!(bCalcAsShown || bIgnoreCase || !bLookUpLabels || !bMatchWholeCell || !bUseRegularExpressions || + bUseWildcards || + bIsIterationEnabled || nIterationCount != 100 || !::rtl::math::approxEqual(fIterationEpsilon, 0.001) || + aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 || nYear2000 != 1930)) + return; + + if (bIgnoreCase) + AddAttribute(XML_NAMESPACE_TABLE, XML_CASE_SENSITIVE, XML_FALSE); + if (bCalcAsShown) + AddAttribute(XML_NAMESPACE_TABLE, XML_PRECISION_AS_SHOWN, XML_TRUE); + if (!bMatchWholeCell) + AddAttribute(XML_NAMESPACE_TABLE, XML_SEARCH_CRITERIA_MUST_APPLY_TO_WHOLE_CELL, XML_FALSE); + if (!bLookUpLabels) + AddAttribute(XML_NAMESPACE_TABLE, XML_AUTOMATIC_FIND_LABELS, XML_FALSE); + if (!bUseRegularExpressions) + AddAttribute(XML_NAMESPACE_TABLE, XML_USE_REGULAR_EXPRESSIONS, XML_FALSE); + if (bUseWildcards) + AddAttribute(XML_NAMESPACE_TABLE, XML_USE_WILDCARDS, XML_TRUE); + if (nYear2000 != 1930) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_NULL_YEAR, OUString::number(nYear2000)); + } + SvXMLElementExport aCalcSettings(*this, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true); + { + if (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899) + { + OUStringBuffer sDate; + SvXMLUnitConverter::convertDateTime(sDate, 0.0, aNullDate); + AddAttribute(XML_NAMESPACE_TABLE, XML_DATE_VALUE, sDate.makeStringAndClear()); + SvXMLElementExport aElemNullDate(*this, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true); + } + if (bIsIterationEnabled || nIterationCount != 100 || !::rtl::math::approxEqual(fIterationEpsilon, 0.001)) + { + if (bIsIterationEnabled) + AddAttribute(XML_NAMESPACE_TABLE, XML_STATUS, XML_ENABLE); + if (nIterationCount != 100) + { + AddAttribute(XML_NAMESPACE_TABLE, XML_STEPS, OUString::number(nIterationCount)); + } + if (!::rtl::math::approxEqual(fIterationEpsilon, 0.001)) + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDouble(sBuffer, + fIterationEpsilon); + AddAttribute(XML_NAMESPACE_TABLE, XML_MAXIMUM_DIFFERENCE, sBuffer.makeStringAndClear()); + } + SvXMLElementExport aElemIteration(*this, XML_NAMESPACE_TABLE, XML_ITERATION, true, true); + } + } +} + +void ScXMLExport::WriteTableSource() +{ + uno::Reference <sheet::XSheetLinkable> xLinkable (xCurrentTable, uno::UNO_QUERY); + if (!(xLinkable.is() && GetModel().is())) + return; + + sheet::SheetLinkMode nMode (xLinkable->getLinkMode()); + if (nMode == sheet::SheetLinkMode_NONE) + return; + + OUString sLink (xLinkable->getLinkUrl()); + uno::Reference <beans::XPropertySet> xProps (GetModel(), uno::UNO_QUERY); + if (!xProps.is()) + return; + + uno::Reference <container::XIndexAccess> xIndex(xProps->getPropertyValue(SC_UNO_SHEETLINKS), uno::UNO_QUERY); + if (!xIndex.is()) + return; + + sal_Int32 nCount(xIndex->getCount()); + if (!nCount) + return; + + bool bFound(false); + uno::Reference <beans::XPropertySet> xLinkProps; + for (sal_Int32 i = 0; (i < nCount) && !bFound; ++i) + { + xLinkProps.set(xIndex->getByIndex(i), uno::UNO_QUERY); + if (xLinkProps.is()) + { + OUString sNewLink; + if (xLinkProps->getPropertyValue(SC_UNONAME_LINKURL) >>= sNewLink) + bFound = sLink == sNewLink; + } + } + if (!(bFound && xLinkProps.is())) + return; + + OUString sFilter; + OUString sFilterOptions; + OUString sTableName (xLinkable->getLinkSheetName()); + sal_Int32 nRefresh(0); + xLinkProps->getPropertyValue(SC_UNONAME_FILTER) >>= sFilter; + xLinkProps->getPropertyValue(SC_UNONAME_FILTOPT) >>= sFilterOptions; + xLinkProps->getPropertyValue(SC_UNONAME_REFDELAY) >>= nRefresh; + if (sLink.isEmpty()) + return; + + AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(sLink)); + if (!sTableName.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, sTableName); + if (!sFilter.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, sFilter); + if (!sFilterOptions.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, sFilterOptions); + if (nMode != sheet::SheetLinkMode_NORMAL) + AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY); + if( nRefresh ) + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDuration( sBuffer, + static_cast<double>(nRefresh) / 86400 ); + AddAttribute( XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, sBuffer.makeStringAndClear() ); + } + SvXMLElementExport aSourceElem(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, true, true); +} + +// core implementation +void ScXMLExport::WriteScenario() +{ + if (!(pDoc && pDoc->IsScenario(static_cast<SCTAB>(nCurrentTable)))) + return; + + OUString sComment; + Color aColor; + ScScenarioFlags nFlags; + pDoc->GetScenarioData(static_cast<SCTAB>(nCurrentTable), sComment, aColor, nFlags); + if (!(nFlags & ScScenarioFlags::ShowFrame)) + AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY_BORDER, XML_FALSE); + OUStringBuffer aBuffer; + ::sax::Converter::convertColor(aBuffer, aColor); + AddAttribute(XML_NAMESPACE_TABLE, XML_BORDER_COLOR, aBuffer.makeStringAndClear()); + if (!(nFlags & ScScenarioFlags::TwoWay)) + AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_BACK, XML_FALSE); + if (!(nFlags & ScScenarioFlags::Attrib)) + AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_STYLES, XML_FALSE); + if (nFlags & ScScenarioFlags::Value) + AddAttribute(XML_NAMESPACE_TABLE, XML_COPY_FORMULAS, XML_FALSE); + if (nFlags & ScScenarioFlags::Protected) + AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE); + ::sax::Converter::convertBool(aBuffer, + pDoc->IsActiveScenario(static_cast<SCTAB>(nCurrentTable))); + AddAttribute(XML_NAMESPACE_TABLE, XML_IS_ACTIVE, aBuffer.makeStringAndClear()); + const ScRangeList* pRangeList = pDoc->GetScenarioRanges(static_cast<SCTAB>(nCurrentTable)); + OUString sRangeListStr; + ScRangeStringConverter::GetStringFromRangeList( sRangeListStr, pRangeList, pDoc, FormulaGrammar::CONV_OOO ); + AddAttribute(XML_NAMESPACE_TABLE, XML_SCENARIO_RANGES, sRangeListStr); + if (!sComment.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_COMMENT, sComment); + SvXMLElementExport aElem(*this, XML_NAMESPACE_TABLE, XML_SCENARIO, true, true); +} + +void ScXMLExport::WriteTheLabelRanges( const uno::Reference< sheet::XSpreadsheetDocument >& xSpreadDoc ) +{ + uno::Reference< beans::XPropertySet > xDocProp( xSpreadDoc, uno::UNO_QUERY ); + if( !xDocProp.is() ) return; + + sal_Int32 nCount(0); + uno::Reference< container::XIndexAccess > xColRangesIAccess(xDocProp->getPropertyValue( SC_UNO_COLLABELRNG ), uno::UNO_QUERY); + if( xColRangesIAccess.is() ) + nCount += xColRangesIAccess->getCount(); + + uno::Reference< container::XIndexAccess > xRowRangesIAccess(xDocProp->getPropertyValue( SC_UNO_ROWLABELRNG ), uno::UNO_QUERY); + if( xRowRangesIAccess.is() ) + nCount += xRowRangesIAccess->getCount(); + + if( nCount ) + { + SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGES, true, true ); + WriteLabelRanges( xColRangesIAccess, true ); + WriteLabelRanges( xRowRangesIAccess, false ); + } +} + +void ScXMLExport::WriteLabelRanges( const uno::Reference< container::XIndexAccess >& xRangesIAccess, bool bColumn ) +{ + if( !xRangesIAccess.is() ) return; + + sal_Int32 nCount(xRangesIAccess->getCount()); + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + { + uno::Reference< sheet::XLabelRange > xRange(xRangesIAccess->getByIndex( nIndex ), uno::UNO_QUERY); + if( xRange.is() ) + { + OUString sRangeStr; + table::CellRangeAddress aCellRange( xRange->getLabelArea() ); + ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc, FormulaGrammar::CONV_OOO ); + AddAttribute( XML_NAMESPACE_TABLE, XML_LABEL_CELL_RANGE_ADDRESS, sRangeStr ); + aCellRange = xRange->getDataArea(); + ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc, FormulaGrammar::CONV_OOO ); + AddAttribute( XML_NAMESPACE_TABLE, XML_DATA_CELL_RANGE_ADDRESS, sRangeStr ); + AddAttribute( XML_NAMESPACE_TABLE, XML_ORIENTATION, bColumn ? XML_COLUMN : XML_ROW ); + SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGE, true, true ); + } + } +} + +void ScXMLExport::WriteNamedExpressions() +{ + if (!pDoc) + return; + ScRangeName* pNamedRanges = pDoc->GetRangeName(); + WriteNamedRange(pNamedRanges); +} + +void ScXMLExport::WriteExternalDataMapping() +{ + if (!pDoc) + return; + + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + // Export this only for 1.2 extended and above. + return; + + sc::ExternalDataMapper& rDataMapper = pDoc->GetExternalDataMapper(); + auto& rDataSources = rDataMapper.getDataSources(); + + if (rDataSources.empty()) + return; + + SvXMLElementExport aMappings(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPINGS, true, true); + for (const auto& itr : rDataSources) + { + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, itr.getURL()); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PROVIDER, itr.getProvider()); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATA_FREQUENCY, OUString::number(sc::ExternalDataSource::getUpdateFrequency())); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_ID, itr.getID()); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_DATABASE_NAME, itr.getDBName()); + + SvXMLElementExport aMapping(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_MAPPING, true, true); + // Add the data transformations + WriteExternalDataTransformations(itr.getDataTransformation()); + } +} + +void ScXMLExport::WriteExternalDataTransformations(const std::vector<std::shared_ptr<sc::DataTransformation>>& aDataTransformations) +{ + SvXMLElementExport aTransformations(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_TRANSFORMATIONS, true, true); + for (auto& itr : aDataTransformations) + { + sc::TransformationType aTransformationType = itr->getTransformationType(); + + switch(aTransformationType) + { + case sc::TransformationType::DELETE_TRANSFORMATION: + { + // Delete Columns Transformation + std::shared_ptr<sc::ColumnRemoveTransformation> aDeleteTransformation = std::dynamic_pointer_cast<sc::ColumnRemoveTransformation>(itr); + std::set<SCCOL> aColumns = aDeleteTransformation->getColumns(); + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_REMOVE_TRANSFORMATION, true, true); + for(auto& col : aColumns) + { + // Add Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + case sc::TransformationType::SPLIT_TRANSFORMATION: + { + std::shared_ptr<sc::SplitColumnTransformation> aSplitTransformation = std::dynamic_pointer_cast<sc::SplitColumnTransformation>(itr); + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(aSplitTransformation->getColumn())); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SEPARATOR, OUString::number(aSplitTransformation->getSeparator())); + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_SPLIT_TRANSFORMATION, true, true); + } + break; + case sc::TransformationType::MERGE_TRANSFORMATION: + { + // Merge Transformation + std::shared_ptr<sc::MergeColumnTransformation> aMergeTransformation = std::dynamic_pointer_cast<sc::MergeColumnTransformation>(itr); + std::set<SCCOL> aColumns = aMergeTransformation->getColumns(); + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MERGE_STRING, aMergeTransformation->getMergeString()); + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_MERGE_TRANSFORMATION, true, true); + + for(auto& col : aColumns) + { + // Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + case sc::TransformationType::SORT_TRANSFORMATION: + { + // Sort Transformation + std::shared_ptr<sc::SortTransformation> aSortTransformation = std::dynamic_pointer_cast<sc::SortTransformation>(itr); + ScSortParam aSortParam = aSortTransformation->getSortParam(); + const sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager(); + const sc::DataStream* pStrm = rMgr.getDataStream(); + if (!pStrm) + // No data stream. + return; + + // Streamed range + ScRange aRange = pStrm->GetRange(); + + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_SORT_TRANSFORMATION, true, true); + + writeSort(*this, aSortParam, aRange, pDoc); + } + break; + case sc::TransformationType::TEXT_TRANSFORMATION: + { + // Text Transformation + std::shared_ptr<sc::TextTransformation> aTextTransformation = std::dynamic_pointer_cast<sc::TextTransformation>(itr); + + sc::TEXT_TRANSFORM_TYPE aTextTransformType = aTextTransformation->getTextTransformationType(); + + switch ( aTextTransformType ) + { + case sc::TEXT_TRANSFORM_TYPE::TO_LOWER: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_LOWERCASE); + break; + case sc::TEXT_TRANSFORM_TYPE::TO_UPPER: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_UPPERCASE); + break; + case sc::TEXT_TRANSFORM_TYPE::CAPITALIZE: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CASEMAP_CAPITALIZE); + break; + case sc::TEXT_TRANSFORM_TYPE::TRIM: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_TRIM); + break; + } + + std::set<SCCOL> aColumns = aTextTransformation->getColumns(); + + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_TEXT_TRANSFORMATION, true, true); + + for(auto& col : aColumns) + { + // Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + case sc::TransformationType::AGGREGATE_FUNCTION: + { + // Aggregate Transformation + std::shared_ptr<sc::AggregateFunction> aAggregateFunction = std::dynamic_pointer_cast<sc::AggregateFunction>(itr); + std::set<SCCOL> aColumns = aAggregateFunction->getColumns(); + + sc::AGGREGATE_FUNCTION aAggregateType = aAggregateFunction->getAggregateType(); + + switch (aAggregateType) + { + case sc::AGGREGATE_FUNCTION::SUM: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SUM); + break; + case sc::AGGREGATE_FUNCTION::AVERAGE: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_AVERAGE); + break; + case sc::AGGREGATE_FUNCTION::MIN: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MIN); + break; + case sc::AGGREGATE_FUNCTION::MAX: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MAX); + break; + } + + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT,XML_COLUMN_AGGREGATE_TRANSFORMATION, true, true); + + for(auto& col : aColumns) + { + // Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + case sc::TransformationType::NUMBER_TRANSFORMATION: + { + // Number Transformation + std::shared_ptr<sc::NumberTransformation> aNumberTransformation = std::dynamic_pointer_cast<sc::NumberTransformation>(itr); + + sc::NUMBER_TRANSFORM_TYPE aNumberTransformType = aNumberTransformation->getNumberTransformationType(); + + switch ( aNumberTransformType ) + { + case sc::NUMBER_TRANSFORM_TYPE::ROUND: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND); + break; + case sc::NUMBER_TRANSFORM_TYPE::ROUND_UP: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND_UP); + break; + case sc::NUMBER_TRANSFORM_TYPE::ROUND_DOWN: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ROUND_DOWN); + break; + case sc::NUMBER_TRANSFORM_TYPE::ABSOLUTE: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ABS); + break; + case sc::NUMBER_TRANSFORM_TYPE::LOG_E: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_LOG); + break; + case sc::NUMBER_TRANSFORM_TYPE::LOG_10: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_LOG_10); + break; + case sc::NUMBER_TRANSFORM_TYPE::CUBE: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_CUBE); + break; + case sc::NUMBER_TRANSFORM_TYPE::SQUARE: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SQUARE); + break; + case sc::NUMBER_TRANSFORM_TYPE::SQUARE_ROOT: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SQUARE_ROOT); + break; + case sc::NUMBER_TRANSFORM_TYPE::EXPONENT: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_EXPONENTIAL); + break; + case sc::NUMBER_TRANSFORM_TYPE::IS_EVEN: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_EVEN); + break; + case sc::NUMBER_TRANSFORM_TYPE::IS_ODD: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_ODD); + break; + case sc::NUMBER_TRANSFORM_TYPE::SIGN: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SIGN); + break; + } + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_PRECISION, OUString::number(aNumberTransformation->getPrecision())); + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_NUMBER_TRANSFORMATION, true, true); + + std::set<SCCOL> aColumns = aNumberTransformation->getColumn(); + for(auto& col : aColumns) + { + // Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + case sc::TransformationType::REMOVE_NULL_TRANSFORMATION: + { + // Replace Null Transformation + std::shared_ptr<sc::ReplaceNullTransformation> aReplaceNullTransformation = std::dynamic_pointer_cast<sc::ReplaceNullTransformation>(itr); + std::set<SCCOL> aColumns = aReplaceNullTransformation->getColumn(); + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_REPLACE_STRING, aReplaceNullTransformation->getReplaceString()); + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_REPLACENULL_TRANSFORMATION, true, true); + + for(auto& col : aColumns) + { + // Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + case sc::TransformationType::DATETIME_TRANSFORMATION: + { + // Number Transformation + std::shared_ptr<sc::DateTimeTransformation> aDateTimeTransformation = std::dynamic_pointer_cast<sc::DateTimeTransformation>(itr); + + sc::DATETIME_TRANSFORMATION_TYPE aDateTimeTransformationType = aDateTimeTransformation->getDateTimeTransformationType(); + + switch ( aDateTimeTransformationType ) + { + case sc::DATETIME_TRANSFORMATION_TYPE::DATE_STRING: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DATE_STRING); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::YEAR: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_YEAR); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_YEAR); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_YEAR); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::MONTH: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MONTH); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::MONTH_NAME: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MONTH_NAME); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_MONTH); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_MONTH); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::DAY: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY_OF_WEEK); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_DAY_OF_YEAR); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::QUARTER: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_QUARTER); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_START_OF_QUARTER); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_END_OF_QUARTER); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::TIME: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_TIME); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::HOUR: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_HOUR); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::MINUTE: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_MINUTE); + break; + case sc::DATETIME_TRANSFORMATION_TYPE::SECOND: + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, XML_SECONDS); + break; + } + + SvXMLElementExport aTransformation(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN_DATETIME_TRANSFORMATION, true, true); + + std::set<SCCOL> aColumns = aDateTimeTransformation->getColumn(); + for(auto& col : aColumns) + { + // Columns + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLUMN, OUString::number(col)); + SvXMLElementExport aCol(*this, XML_NAMESPACE_CALC_EXT, XML_COLUMN, true, true); + } + } + break; + default: + break; + } + } +} + +void ScXMLExport::WriteDataStream() +{ + if (!pDoc) + return; + + if (!officecfg::Office::Common::Misc::ExperimentalMode::get()) + // Export this only in experimental mode. + return; + + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + // Export this only for 1.2 extended and above. + return; + + const sc::DocumentLinkManager& rMgr = pDoc->GetDocLinkManager(); + const sc::DataStream* pStrm = rMgr.getDataStream(); + if (!pStrm) + // No data stream. + return; + + // Source URL + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetRelativeReference(pStrm->GetURL())); + + // Streamed range + ScRange aRange = pStrm->GetRange(); + OUString aRangeStr; + ScRangeStringConverter::GetStringFromRange( + aRangeStr, aRange, pDoc, formula::FormulaGrammar::CONV_OOO); + AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aRangeStr); + + // Empty line refresh option. + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_EMPTY_LINE_REFRESH, pStrm->IsRefreshOnEmptyLine() ? XML_TRUE : XML_FALSE); + + // New data insertion position. Either top of bottom. Default to bottom. + xmloff::token::XMLTokenEnum eInsertPosition = XML_BOTTOM; + if (pStrm->GetMove() == sc::DataStream::MOVE_DOWN) + eInsertPosition = XML_TOP; + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_INSERTION_POSITION, eInsertPosition); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_STREAM_SOURCE, true, true); +} + +void ScXMLExport::WriteNamedRange(ScRangeName* pRangeName) +{ + //write a global or local ScRangeName + SvXMLElementExport aElemNEs(*this, XML_NAMESPACE_TABLE, XML_NAMED_EXPRESSIONS, true, true); + for (const auto& rxEntry : *pRangeName) + { + AddAttribute(sAttrName, rxEntry.second->GetName()); + + OUString sBaseCellAddress; + rxEntry.second->ValidateTabRefs(); + ScRangeStringConverter::GetStringFromAddress( sBaseCellAddress, rxEntry.second->GetPos(), pDoc, + FormulaGrammar::CONV_OOO, ' ', false, ScRefFlags::ADDR_ABS_3D); + AddAttribute(XML_NAMESPACE_TABLE, XML_BASE_CELL_ADDRESS, sBaseCellAddress); + + OUString sSymbol = rxEntry.second->GetSymbol(pDoc->GetStorageGrammar()); + OUString sTempSymbol(sSymbol); + ScRange aRange; + if (rxEntry.second->IsReference(aRange)) + { + + OUString sContent(sTempSymbol.copy(1, sTempSymbol.getLength() -2 )); + AddAttribute(XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sContent); + + sal_Int32 nRangeType = rxEntry.second->GetUnoType(); + OUStringBuffer sBufferRangeType; + if ((nRangeType & sheet::NamedRangeFlag::COLUMN_HEADER) == sheet::NamedRangeFlag::COLUMN_HEADER) + sBufferRangeType.append(GetXMLToken(XML_REPEAT_COLUMN)); + if ((nRangeType & sheet::NamedRangeFlag::ROW_HEADER) == sheet::NamedRangeFlag::ROW_HEADER) + { + if (!sBufferRangeType.isEmpty()) + sBufferRangeType.append(" "); + sBufferRangeType.append(GetXMLToken(XML_REPEAT_ROW)); + } + if ((nRangeType & sheet::NamedRangeFlag::FILTER_CRITERIA) == sheet::NamedRangeFlag::FILTER_CRITERIA) + { + if (!sBufferRangeType.isEmpty()) + sBufferRangeType.append(" "); + sBufferRangeType.append(GetXMLToken(XML_FILTER)); + } + if ((nRangeType & sheet::NamedRangeFlag::PRINT_AREA) == sheet::NamedRangeFlag::PRINT_AREA) + { + if (!sBufferRangeType.isEmpty()) + sBufferRangeType.append(" "); + sBufferRangeType.append(GetXMLToken(XML_PRINT_RANGE)); + } + OUString sRangeType = sBufferRangeType.makeStringAndClear(); + if (!sRangeType.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_RANGE_USABLE_AS, sRangeType); + SvXMLElementExport aElemNR(*this, XML_NAMESPACE_TABLE, XML_NAMED_RANGE, true, true); + + } + else + { + AddAttribute(XML_NAMESPACE_TABLE, XML_EXPRESSION, sTempSymbol); + SvXMLElementExport aElemNE(*this, XML_NAMESPACE_TABLE, XML_NAMED_EXPRESSION, true, true); + } + } +} + +void ScXMLExport::exportSparklineGroups(SCTAB nTable) +{ + sc::SparklineGroupsExport aSparklineGroupExport(*this, nTable); + aSparklineGroupExport.write(); +} + +namespace { + +OUString getCondFormatEntryType(const ScColorScaleEntry& rEntry, bool bFirst = true) +{ + switch(rEntry.GetType()) + { + case COLORSCALE_MIN: + return "minimum"; + case COLORSCALE_MAX: + return "maximum"; + case COLORSCALE_PERCENT: + return "percent"; + case COLORSCALE_PERCENTILE: + return "percentile"; + case COLORSCALE_FORMULA: + return "formula"; + case COLORSCALE_VALUE: + return "number"; + case COLORSCALE_AUTO: + // only important for data bars + if(bFirst) + return "auto-minimum"; + else + return "auto-maximum"; + } + return OUString(); +} + +OUString getDateStringForType(condformat::ScCondFormatDateType eType) +{ + switch(eType) + { + case condformat::TODAY: + return "today"; + case condformat::YESTERDAY: + return "yesterday"; + case condformat::TOMORROW: + return "tomorrow"; + case condformat::LAST7DAYS: + return "last-7-days"; + case condformat::THISWEEK: + return "this-week"; + case condformat::LASTWEEK: + return "last-week"; + case condformat::NEXTWEEK: + return "next-week"; + case condformat::THISMONTH: + return "this-month"; + case condformat::LASTMONTH: + return "last-month"; + case condformat::NEXTMONTH: + return "next-month"; + case condformat::THISYEAR: + return "this-year"; + case condformat::LASTYEAR: + return "last-year"; + case condformat::NEXTYEAR: + return "next-year"; + } + + return OUString(); +} + +} + +void ScXMLExport::ExportConditionalFormat(SCTAB nTab) +{ + ScConditionalFormatList* pCondFormatList = pDoc->GetCondFormList(nTab); + if(!pCondFormatList) + return; + + if (pCondFormatList->empty()) + return; + + SvXMLElementExport aElementCondFormats(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITIONAL_FORMATS, true, true); + + for(const auto& rxCondFormat : *pCondFormatList) + { + OUString sRanges; + const ScRangeList& rRangeList = rxCondFormat->GetRange(); + ScRangeStringConverter::GetStringFromRangeList( sRanges, &rRangeList, pDoc, formula::FormulaGrammar::CONV_OOO ); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TARGET_RANGE_ADDRESS, sRanges); + SvXMLElementExport aElementCondFormat(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITIONAL_FORMAT, true, true); + size_t nEntries = rxCondFormat->size(); + for(size_t i = 0; i < nEntries; ++i) + { + const ScFormatEntry* pFormatEntry = rxCondFormat->GetEntry(i); + if(pFormatEntry->GetType()==ScFormatEntry::Type::Condition) + { + const ScCondFormatEntry* pEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry); + OUStringBuffer aCond; + ScAddress aPos = pEntry->GetSrcPos(); + switch(pEntry->GetOperation()) + { + case ScConditionMode::Equal: + aCond.append('='); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + break; + case ScConditionMode::Less: + aCond.append('<'); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + break; + case ScConditionMode::Greater: + aCond.append('>'); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + break; + case ScConditionMode::EqLess: + aCond.append("<="); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + break; + case ScConditionMode::EqGreater: + aCond.append(">="); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + break; + case ScConditionMode::NotEqual: + aCond.append("!="); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + break; + case ScConditionMode::Between: + aCond.append("between("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(','); + aCond.append(pEntry->GetExpression(aPos, 1, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(')'); + break; + case ScConditionMode::NotBetween: + aCond.append("not-between("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(','); + aCond.append(pEntry->GetExpression(aPos, 1, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(')'); + break; + case ScConditionMode::Duplicate: + aCond.append("duplicate"); + break; + case ScConditionMode::NotDuplicate: + aCond.append("unique"); + break; + case ScConditionMode::Direct: + aCond.append("formula-is("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(')'); + break; + case ScConditionMode::Top10: + aCond.append("top-elements("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::Bottom10: + aCond.append("bottom-elements("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::TopPercent: + aCond.append("top-percent("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::BottomPercent: + aCond.append("bottom-percent("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::AboveAverage: + aCond.append("above-average"); + break; + case ScConditionMode::BelowAverage: + aCond.append("below-average"); + break; + case ScConditionMode::AboveEqualAverage: + aCond.append("above-equal-average"); + break; + case ScConditionMode::BelowEqualAverage: + aCond.append("below-equal-average"); + break; + case ScConditionMode::Error: + aCond.append("is-error"); + break; + case ScConditionMode::NoError: + aCond.append("is-no-error"); + break; + case ScConditionMode::BeginsWith: + aCond.append("begins-with("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::EndsWith: + aCond.append("ends-with("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::ContainsText: + aCond.append("contains-text("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::NotContainsText: + aCond.append("not-contains-text("); + aCond.append(pEntry->GetExpression(aPos, 0, 0, formula::FormulaGrammar::GRAM_ODFF)); + aCond.append(")"); + break; + case ScConditionMode::NONE: + continue; + default: + SAL_WARN("sc", "unimplemented conditional format export"); + } + OUString sStyle = ScStyleNameConversion::DisplayToProgrammaticName(pEntry->GetStyle(), SfxStyleFamily::Para); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_APPLY_STYLE_NAME, sStyle); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, aCond.makeStringAndClear()); + + OUString sBaseAddress; + ScRangeStringConverter::GetStringFromAddress( sBaseAddress, aPos, pDoc,formula::FormulaGrammar::CONV_ODF ); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_BASE_CELL_ADDRESS, sBaseAddress); + SvXMLElementExport aElementCondEntry(*this, XML_NAMESPACE_CALC_EXT, XML_CONDITION, true, true); + } + else if(pFormatEntry->GetType() == ScFormatEntry::Type::Colorscale) + { + SvXMLElementExport aElementColorScale(*this, XML_NAMESPACE_CALC_EXT, XML_COLOR_SCALE, true, true); + const ScColorScaleFormat& rColorScale = static_cast<const ScColorScaleFormat&>(*pFormatEntry); + for(const auto& rxItem : rColorScale) + { + if(rxItem->GetType() == COLORSCALE_FORMULA) + { + OUString sFormula = rxItem->GetFormula(formula::FormulaGrammar::GRAM_ODFF); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula); + } + else + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(rxItem->GetValue())); + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*rxItem)); + OUStringBuffer aBuffer; + ::sax::Converter::convertColor(aBuffer, rxItem->GetColor()); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_COLOR, aBuffer.makeStringAndClear()); + SvXMLElementExport aElementColorScaleEntry(*this, XML_NAMESPACE_CALC_EXT, XML_COLOR_SCALE_ENTRY, true, true); + } + } + else if(pFormatEntry->GetType() == ScFormatEntry::Type::Databar) + { + const ScDataBarFormatData* pFormatData = static_cast<const ScDataBarFormat&>(*pFormatEntry).GetDataBarData(); + if(!pFormatData->mbGradient) + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_GRADIENT, XML_FALSE); + if(pFormatData->mbOnlyBar) + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SHOW_VALUE, XML_FALSE); + + if (pFormatData->mnMinLength != 0.0) + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MIN_LENGTH, OUString::number(pFormatData->mnMinLength)); + + if (pFormatData->mnMaxLength != 0.0) + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_MAX_LENGTH, OUString::number(pFormatData->mnMaxLength)); + + if(pFormatData->mbNeg) + { + if(pFormatData->mxNegativeColor) + { + OUStringBuffer aBuffer; + ::sax::Converter::convertColor(aBuffer, *pFormatData->mxNegativeColor); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_NEGATIVE_COLOR, aBuffer.makeStringAndClear()); + } + else + { + OUStringBuffer aBuffer; + ::sax::Converter::convertColor(aBuffer, COL_LIGHTRED); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_NEGATIVE_COLOR, aBuffer.makeStringAndClear()); + } + } + + if(pFormatData->meAxisPosition != databar::AUTOMATIC) + { + if(pFormatData->meAxisPosition == databar::NONE) + { + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_POSITION, OUString("none")); + } + else + { + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_POSITION, OUString("middle")); + } + } + + OUStringBuffer aBuffer; + ::sax::Converter::convertColor(aBuffer, pFormatData->maPositiveColor); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_POSITIVE_COLOR, aBuffer.makeStringAndClear()); + + aBuffer.truncate(); + ::sax::Converter::convertColor(aBuffer, pFormatData->maAxisColor); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_AXIS_COLOR, aBuffer.makeStringAndClear()); + SvXMLElementExport aElementDataBar(*this, XML_NAMESPACE_CALC_EXT, XML_DATA_BAR, true, true); + + { + if(pFormatData->mpLowerLimit->GetType() == COLORSCALE_FORMULA) + { + OUString sFormula = pFormatData->mpLowerLimit->GetFormula(formula::FormulaGrammar::GRAM_ODFF); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula); + } + else + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(pFormatData->mpLowerLimit->GetValue())); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*pFormatData->mpLowerLimit)); + SvXMLElementExport aElementDataBarEntryLower(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true); + } + + { + if(pFormatData->mpUpperLimit->GetType() == COLORSCALE_FORMULA) + { + OUString sFormula = pFormatData->mpUpperLimit->GetFormula(formula::FormulaGrammar::GRAM_ODFF); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula); + } + else + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(pFormatData->mpUpperLimit->GetValue())); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*pFormatData->mpUpperLimit, false)); + SvXMLElementExport aElementDataBarEntryUpper(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true); + } + } + else if(pFormatEntry->GetType() == ScFormatEntry::Type::Iconset) + { + const ScIconSetFormat& rIconSet = static_cast<const ScIconSetFormat&>(*pFormatEntry); + OUString aIconSetName = OUString::createFromAscii(ScIconSetFormat::getIconSetName(rIconSet.GetIconSetData()->eIconSetType)); + AddAttribute( XML_NAMESPACE_CALC_EXT, XML_ICON_SET_TYPE, aIconSetName ); + if (rIconSet.GetIconSetData()->mbCustom) + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM, OUString::boolean(true)); + + SvXMLElementExport aElementColorScale(*this, XML_NAMESPACE_CALC_EXT, XML_ICON_SET, true, true); + + if (rIconSet.GetIconSetData()->mbCustom) + { + for (const auto& [rType, rIndex] : rIconSet.GetIconSetData()->maCustomVector) + { + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET_NAME, OUString::createFromAscii(ScIconSetFormat::getIconSetName(rType))); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET_INDEX, OUString::number(rIndex)); + SvXMLElementExport aCustomIcon(*this, XML_NAMESPACE_CALC_EXT, XML_CUSTOM_ICONSET, true, true); + } + + } + + if(!rIconSet.GetIconSetData()->mbShowValue) + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_SHOW_VALUE, XML_FALSE); + for (auto const& it : rIconSet) + { + if(it->GetType() == COLORSCALE_FORMULA) + { + OUString sFormula = it->GetFormula(formula::FormulaGrammar::GRAM_ODFF); + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, sFormula); + } + else + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_VALUE, OUString::number(it->GetValue())); + + AddAttribute(XML_NAMESPACE_CALC_EXT, XML_TYPE, getCondFormatEntryType(*it)); + SvXMLElementExport aElementColorScaleEntry(*this, XML_NAMESPACE_CALC_EXT, XML_FORMATTING_ENTRY, true, true); + } + } + else if(pFormatEntry->GetType() == ScFormatEntry::Type::Date) + { + const ScCondDateFormatEntry& rDateFormat = static_cast<const ScCondDateFormatEntry&>(*pFormatEntry); + OUString aDateType = getDateStringForType(rDateFormat.GetDateType()); + OUString aStyleName = ScStyleNameConversion::DisplayToProgrammaticName(rDateFormat.GetStyleName(), SfxStyleFamily::Para ); + AddAttribute( XML_NAMESPACE_CALC_EXT, XML_STYLE, aStyleName); + AddAttribute( XML_NAMESPACE_CALC_EXT, XML_DATE, aDateType); + SvXMLElementExport aElementDateFormat(*this, XML_NAMESPACE_CALC_EXT, XML_DATE_IS, true, true); + } + } + } +} + +void ScXMLExport::WriteExternalRefCaches() +{ + if (!pDoc) + return; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pRefMgr->resetSrcFileData(GetOrigFileName()); + sal_uInt16 nCount = pRefMgr->getExternalFileCount(); + for (sal_uInt16 nFileId = 0; nFileId < nCount; ++nFileId) + { + const OUString* pUrl = pRefMgr->getExternalFileName(nFileId); + if (!pUrl) + continue; + + vector<OUString> aTabNames; + pRefMgr->getAllCachedTableNames(nFileId, aTabNames); + if (aTabNames.empty()) + continue; + + for (const auto& rTabName : aTabNames) + { + ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, rTabName, false); + if (!pTable || !pTable->isReferenced()) + continue; + + AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, "'" + *pUrl + "'#" + rTabName); + AddAttribute(XML_NAMESPACE_TABLE, XML_PRINT, GetXMLToken(XML_FALSE)); + AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sExternalRefTabStyleName); + SvXMLElementExport aElemTable(*this, XML_NAMESPACE_TABLE, XML_TABLE, true, true); + { + const ScExternalRefManager::SrcFileData* pExtFileData = pRefMgr->getExternalFileData(nFileId); + if (pExtFileData) + { + OUString aRelUrl; + if (!pExtFileData->maRelativeName.isEmpty()) + aRelUrl = pExtFileData->maRelativeName; + else + aRelUrl = GetRelativeReference(pExtFileData->maRelativeName); + AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aRelUrl); + AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, rTabName); + if (!pExtFileData->maFilterName.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, pExtFileData->maFilterName); + if (!pExtFileData->maFilterOptions.isEmpty()) + AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, pExtFileData->maFilterOptions); + AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY); + } + SvXMLElementExport aElemTableSource(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, true, true); + } + + // Determine maximum column count of used area, for repeated cells. + SCCOL nMaxColsUsed = 1; // assume that there is at least one cell somewhere... + vector<SCROW> aRows; + pTable->getAllRows(aRows); + for (SCROW nRow : aRows) + { + vector<SCCOL> aCols; + pTable->getAllCols(nRow, aCols); + if (!aCols.empty()) + { + SCCOL nCol = aCols.back(); + if (nMaxColsUsed <= nCol) + nMaxColsUsed = nCol + 1; + } + } + + // Column definitions have to be present to make a valid file + { + if (nMaxColsUsed > 1) + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::number(nMaxColsUsed)); + SvXMLElementExport aElemColumn(*this, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true); + } + + // Write cache content for this table. + SCROW nLastRow = 0; + bool bFirstRow = true; + for (SCROW nRow : aRows) + { + if (bFirstRow) + { + if (nRow > 0) + { + if (nRow > 1) + { + OUString aVal = OUString::number(nRow); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal); + } + SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true); + OUString aVal = OUString::number(static_cast<sal_Int32>(nMaxColsUsed)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal); + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true); + } + } + else + { + SCROW nRowGap = nRow - nLastRow; + if (nRowGap > 1) + { + if (nRowGap > 2) + { + OUString aVal = OUString::number(static_cast<sal_Int32>(nRowGap-1)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal); + } + SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true); + OUString aVal = OUString::number(static_cast<sal_Int32>(nMaxColsUsed)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal); + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true); + } + } + SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true); + + vector<SCCOL> aCols; + pTable->getAllCols(nRow, aCols); + SCCOL nLastCol = 0; + bool bFirstCol = true; + for (SCCOL nCol : aCols) + { + if (bFirstCol) + { + if (nCol > 0) + { + if (nCol > 1) + { + OUString aVal = OUString::number(static_cast<sal_Int32>(nCol)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal); + } + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true); + } + } + else + { + SCCOL nColGap = nCol - nLastCol; + if (nColGap > 1) + { + if (nColGap > 2) + { + OUString aVal = OUString::number(static_cast<sal_Int32>(nColGap-1)); + AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal); + } + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true); + } + } + + // Write out this cell. + sal_uInt32 nNumFmt = 0; + ScExternalRefCache::TokenRef pToken = pTable->getCell(nCol, nRow, &nNumFmt); + OUString aStrVal; + if (pToken) + { + sal_Int32 nIndex = GetNumberFormatStyleIndex(nNumFmt); + if (nIndex >= 0) + { + const OUString & aStyleName = pCellStyles->GetStyleNameByIndex(nIndex, true); + AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, aStyleName); + } + + switch(pToken->GetType()) + { + case svDouble: + { + AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT); + OUStringBuffer aVal; + aVal.append(pToken->GetDouble()); + aStrVal = aVal.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, aStrVal); + } + break; + case svString: + { + AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING); + aStrVal = pToken->GetString().getString(); + } + break; + default: + ; + } + } + SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true); + SvXMLElementExport aElemText(*this, XML_NAMESPACE_TEXT, XML_P, true, false); + Characters(aStrVal); + + nLastCol = nCol; + bFirstCol = false; + } + nLastRow = nRow; + bFirstRow = false; + } + } + } +} + +// core implementation +void ScXMLExport::WriteConsolidation() +{ + if (!pDoc) + return; + + const ScConsolidateParam* pCons(pDoc->GetConsolidateDlgData()); + if( !pCons ) + return; + + OUString sStrData = ScXMLConverter::GetStringFromFunction( pCons->eFunction ); + AddAttribute( XML_NAMESPACE_TABLE, XML_FUNCTION, sStrData ); + + sStrData.clear(); + for( sal_Int32 nIndex = 0; nIndex < pCons->nDataAreaCount; ++nIndex ) + ScRangeStringConverter::GetStringFromArea( sStrData, pCons->pDataAreas[ nIndex ], pDoc, FormulaGrammar::CONV_OOO, ' ', true ); + AddAttribute( XML_NAMESPACE_TABLE, XML_SOURCE_CELL_RANGE_ADDRESSES, sStrData ); + + ScRangeStringConverter::GetStringFromAddress( sStrData, ScAddress( pCons->nCol, pCons->nRow, pCons->nTab ), pDoc, FormulaGrammar::CONV_OOO ); + AddAttribute( XML_NAMESPACE_TABLE, XML_TARGET_CELL_ADDRESS, sStrData ); + + if( pCons->bByCol && !pCons->bByRow ) + AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_COLUMN ); + else if( !pCons->bByCol && pCons->bByRow ) + AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_ROW ); + else if( pCons->bByCol && pCons->bByRow ) + AddAttribute( XML_NAMESPACE_TABLE, XML_USE_LABEL, XML_BOTH ); + + if( pCons->bReferenceData ) + AddAttribute( XML_NAMESPACE_TABLE, XML_LINK_TO_SOURCE_DATA, XML_TRUE ); + + SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_CONSOLIDATION, true, true ); +} + +SvXMLAutoStylePoolP* ScXMLExport::CreateAutoStylePool() +{ + return new ScXMLAutoStylePoolP(*this); +} + +XMLPageExport* ScXMLExport::CreatePageExport() +{ + return new XMLTableMasterPageExport( *this ); +} + +void ScXMLExport::GetChangeTrackViewSettings(uno::Sequence<beans::PropertyValue>& rProps) +{ + ScChangeViewSettings* pViewSettings(GetDocument() ? GetDocument()->GetChangeViewSettings() : nullptr); + if (!pViewSettings) + return; + + sal_Int32 nChangePos(rProps.getLength()); + rProps.realloc(nChangePos + 1); + beans::PropertyValue* pProps(rProps.getArray()); + + uno::Sequence<beans::PropertyValue> aChangeProps(SC_VIEWCHANGES_COUNT); + beans::PropertyValue* pChangeProps(aChangeProps.getArray()); + pChangeProps[SC_SHOW_CHANGES].Name = "ShowChanges"; + pChangeProps[SC_SHOW_CHANGES].Value <<= pViewSettings->ShowChanges(); + pChangeProps[SC_SHOW_ACCEPTED_CHANGES].Name = "ShowAcceptedChanges"; + pChangeProps[SC_SHOW_ACCEPTED_CHANGES].Value <<= pViewSettings->IsShowAccepted(); + pChangeProps[SC_SHOW_REJECTED_CHANGES].Name = "ShowRejectedChanges"; + pChangeProps[SC_SHOW_REJECTED_CHANGES].Value <<= pViewSettings->IsShowRejected(); + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME].Name = "ShowChangesByDatetime"; + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME].Value <<= pViewSettings->HasDate(); + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_MODE].Name = "ShowChangesByDatetimeMode"; + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_MODE].Value <<= static_cast<sal_Int16>(pViewSettings->GetTheDateMode()); + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME].Name = "ShowChangesByDatetimeFirstDatetime"; + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME].Value <<= pViewSettings->GetTheFirstDateTime().GetUNODateTime(); + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME].Name = "ShowChangesByDatetimeSecondDatetime"; + pChangeProps[SC_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME].Value <<= pViewSettings->GetTheLastDateTime().GetUNODateTime(); + pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR].Name = "ShowChangesByAuthor"; + pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR].Value <<= pViewSettings->HasAuthor(); + pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR_NAME].Name = "ShowChangesByAuthorName"; + pChangeProps[SC_SHOW_CHANGES_BY_AUTHOR_NAME].Value <<= pViewSettings->GetTheAuthorToShow(); + pChangeProps[SC_SHOW_CHANGES_BY_COMMENT].Name = "ShowChangesByComment"; + pChangeProps[SC_SHOW_CHANGES_BY_COMMENT].Value <<= pViewSettings->HasComment(); + pChangeProps[SC_SHOW_CHANGES_BY_COMMENT_TEXT].Name = "ShowChangesByCommentText"; + pChangeProps[SC_SHOW_CHANGES_BY_COMMENT_TEXT].Value <<= pViewSettings->GetTheComment(); + pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Name = "ShowChangesByRanges"; + pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Value <<= pViewSettings->HasRange(); + OUString sRangeList; + ScRangeStringConverter::GetStringFromRangeList(sRangeList, &(pViewSettings->GetTheRangeList()), GetDocument(), FormulaGrammar::CONV_OOO); + pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Name = "ShowChangesByRangesList"; + pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Value <<= sRangeList; + + pProps[nChangePos].Name = "TrackedChangesViewSettings"; + pProps[nChangePos].Value <<= aChangeProps; +} + +void ScXMLExport::GetViewSettings(uno::Sequence<beans::PropertyValue>& rProps) +{ + if (GetModel().is()) + { + rProps.realloc(4); + beans::PropertyValue* pProps(rProps.getArray()); + ScModelObj* pDocObj(comphelper::getFromUnoTunnel<ScModelObj>( GetModel() )); + if (pDocObj) + { + SfxObjectShell* pEmbeddedObj = pDocObj->GetEmbeddedObject(); + if (pEmbeddedObj) + { + tools::Rectangle aRect(pEmbeddedObj->GetVisArea()); + sal_uInt16 i(0); + pProps[i].Name = "VisibleAreaTop"; + pProps[i].Value <<= static_cast<sal_Int32>(aRect.Top()); + pProps[++i].Name = "VisibleAreaLeft"; + pProps[i].Value <<= static_cast<sal_Int32>(aRect.Left()); + pProps[++i].Name = "VisibleAreaWidth"; + pProps[i].Value <<= static_cast<sal_Int32>(aRect.getWidth()); + pProps[++i].Name = "VisibleAreaHeight"; + pProps[i].Value <<= static_cast<sal_Int32>(aRect.getHeight()); + } + } + } + GetChangeTrackViewSettings(rProps); +} + +void ScXMLExport::GetConfigurationSettings(uno::Sequence<beans::PropertyValue>& rProps) +{ + if (!GetModel().is()) + return; + + uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetModel(), uno::UNO_QUERY); + if (!xMultiServiceFactory.is()) + return; + + uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance("com.sun.star.comp.SpreadsheetSettings"), uno::UNO_QUERY); + if (xProperties.is()) + SvXMLUnitConverter::convertPropertySet(rProps, xProperties); + + sal_Int32 nPropsToAdd = 0; + OUStringBuffer aTrackedChangesKey; + if (GetDocument() && GetDocument()->GetChangeTrack() && GetDocument()->GetChangeTrack()->IsProtected()) + { + ::comphelper::Base64::encode(aTrackedChangesKey, + GetDocument()->GetChangeTrack()->GetProtection()); + if (!aTrackedChangesKey.isEmpty()) + ++nPropsToAdd; + } + + bool bVBACompat = false; + uno::Reference <container::XNameAccess> xCodeNameAccess; + OSL_ENSURE( pDoc, "ScXMLExport::GetConfigurationSettings - no ScDocument!" ); + // tdf#71271 - add code names regardless of VBA compatibility mode + if (pDoc) + { + // VBA compatibility mode + if (bVBACompat = pDoc->IsInVBAMode(); bVBACompat) + ++nPropsToAdd; + + // code names + xCodeNameAccess = new XMLCodeNameProvider( pDoc ); + if( xCodeNameAccess->hasElements() ) + ++nPropsToAdd; + else + xCodeNameAccess.clear(); + } + + if( nPropsToAdd <= 0 ) + return; + + sal_Int32 nCount(rProps.getLength()); + rProps.realloc(nCount + nPropsToAdd); + auto pProps = rProps.getArray(); + if (!aTrackedChangesKey.isEmpty()) + { + pProps[nCount].Name = "TrackedChangesProtectionKey"; + pProps[nCount].Value <<= aTrackedChangesKey.makeStringAndClear(); + ++nCount; + } + if( bVBACompat ) + { + pProps[nCount].Name = "VBACompatibilityMode"; + pProps[nCount].Value <<= bVBACompat; + ++nCount; + } + if( xCodeNameAccess.is() ) + { + pProps[nCount].Name = "ScriptConfiguration"; + pProps[nCount].Value <<= xCodeNameAccess; + ++nCount; + } +} + +XMLShapeExport* ScXMLExport::CreateShapeExport() +{ + return new ScXMLShapeExport(*this); +} + +XMLNumberFormatAttributesExportHelper* ScXMLExport::GetNumberFormatAttributesExportHelper() +{ + if (!pNumberFormatAttributesExportHelper) + pNumberFormatAttributesExportHelper.reset(new XMLNumberFormatAttributesExportHelper(GetNumberFormatsSupplier(), *this )); + return pNumberFormatAttributesExportHelper.get(); +} + +void ScXMLExport::CollectUserDefinedNamespaces(const SfxItemPool* pPool, sal_uInt16 nAttrib) +{ + for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(nAttrib)) + { + const SvXMLAttrContainerItem *pUnknown(static_cast<const SvXMLAttrContainerItem *>(pItem)); + if( pUnknown->GetAttrCount() > 0 ) + { + sal_uInt16 nIdx(pUnknown->GetFirstNamespaceIndex()); + while( USHRT_MAX != nIdx ) + { + if( (XML_NAMESPACE_UNKNOWN_FLAG & nIdx) != 0 ) + { + const OUString& rPrefix = pUnknown->GetPrefix( nIdx ); + // Add namespace declaration for unknown attributes if + // there aren't existing ones for the prefix used by the + // attributes + GetNamespaceMap_().Add( rPrefix, + pUnknown->GetNamespace( nIdx ) ); + } + nIdx = pUnknown->GetNextNamespaceIndex( nIdx ); + } + } + } + + // #i66550# needed for 'presentation:event-listener' element for URLs in shapes + GetNamespaceMap_().Add( + GetXMLToken( XML_NP_PRESENTATION ), + GetXMLToken( XML_N_PRESENTATION ), + XML_NAMESPACE_PRESENTATION ); +} + +void ScXMLExport::IncrementProgressBar(bool bFlush, sal_Int32 nInc) +{ + nProgressCount += nInc; + if (bFlush || nProgressCount > 100) + { + GetProgressBarHelper()->Increment(nProgressCount); + nProgressCount = 0; + } +} + +ErrCode ScXMLExport::exportDoc( enum XMLTokenEnum eClass ) +{ + if( getExportFlags() & (SvXMLExportFlags::FONTDECLS|SvXMLExportFlags::STYLES| + SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + if (GetDocument()) + { + // if source doc was Excel then + uno::Reference< frame::XModel > xModel = GetModel(); + if ( xModel.is() ) + { + auto pFoundShell = comphelper::getFromUnoTunnel<SfxObjectShell>(xModel); + if ( pFoundShell && ooo::vba::isAlienExcelDoc( *pFoundShell ) ) + { + xRowStylesPropertySetMapper = new XMLPropertySetMapper(aXMLScFromXLSRowStylesProperties, xScPropHdlFactory, true); + xRowStylesExportPropertySetMapper = new ScXMLRowExportPropertyMapper(xRowStylesPropertySetMapper); + GetAutoStylePool()->SetFamilyPropSetMapper( XmlStyleFamily::TABLE_ROW, + xRowStylesExportPropertySetMapper ); + } + } + CollectUserDefinedNamespaces(GetDocument()->GetPool(), ATTR_USERDEF); + CollectUserDefinedNamespaces(GetDocument()->GetEditPool(), EE_PARA_XMLATTRIBS); + CollectUserDefinedNamespaces(GetDocument()->GetEditPool(), EE_CHAR_XMLATTRIBS); + ScDrawLayer* pDrawLayer = GetDocument()->GetDrawLayer(); + if (pDrawLayer) + { + CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), EE_PARA_XMLATTRIBS); + CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), EE_CHAR_XMLATTRIBS); + CollectUserDefinedNamespaces(&pDrawLayer->GetItemPool(), SDRATTR_XMLATTRIBUTES); + } + + // sheet events use officeooo namespace + if( (getExportFlags() & SvXMLExportFlags::CONTENT) && + getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + bool bAnySheetEvents = false; + SCTAB nTabCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; ++nTab) + if (pDoc->GetSheetEvents(nTab)) + bAnySheetEvents = true; + if (bAnySheetEvents) + GetNamespaceMap_().Add( + GetXMLToken( XML_NP_OFFICE_EXT ), + GetXMLToken( XML_N_OFFICE_EXT ), + XML_NAMESPACE_OFFICE_EXT ); + } + } + } + return SvXMLExport::exportDoc( eClass ); +} + +// XExporter +void SAL_CALL ScXMLExport::setSourceDocument( const uno::Reference<lang::XComponent>& xComponent ) +{ + SolarMutexGuard aGuard; + SvXMLExport::setSourceDocument( xComponent ); + + pDoc = ScXMLConverter::GetScDocument( GetModel() ); + OSL_ENSURE( pDoc, "ScXMLExport::setSourceDocument - no ScDocument!" ); + if (!pDoc) + throw lang::IllegalArgumentException(); + + // create ScChangeTrackingExportHelper after document is known + pChangeTrackingExportHelper.reset(new ScChangeTrackingExportHelper(*this)); + + // Set the document's storage grammar corresponding to the ODF version that + // is to be written. + SvtSaveOptions::ODFSaneDefaultVersion meODFDefaultVersion = getSaneDefaultVersion(); + switch (meODFDefaultVersion) + { + // ODF 1.0 and 1.1 use GRAM_PODF, everything later or unspecified GRAM_ODFF + case SvtSaveOptions::ODFSVER_010: + case SvtSaveOptions::ODFSVER_011: + pDoc->SetStorageGrammar( formula::FormulaGrammar::GRAM_PODF); + break; + default: + pDoc->SetStorageGrammar( formula::FormulaGrammar::GRAM_ODFF); + } +} + +// XFilter +sal_Bool SAL_CALL ScXMLExport::filter( const css::uno::Sequence< css::beans::PropertyValue >& aDescriptor ) +{ + SolarMutexGuard aGuard; + if (pDoc) + pDoc->EnableIdle(false); + bool bReturn(SvXMLExport::filter(aDescriptor)); + if (pDoc) + pDoc->EnableIdle(true); + return bReturn; +} + +void SAL_CALL ScXMLExport::cancel() +{ + SolarMutexGuard aGuard; + if (pDoc) + pDoc->EnableIdle(true); + SvXMLExport::cancel(); +} + +// XInitialization +void SAL_CALL ScXMLExport::initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) +{ + SolarMutexGuard aGuard; + SvXMLExport::initialize(aArguments); +} + +// XUnoTunnel +sal_Int64 SAL_CALL ScXMLExport::getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) +{ + SolarMutexGuard aGuard; + return SvXMLExport::getSomething(aIdentifier); +} + +void ScXMLExport::DisposingModel() +{ + SvXMLExport::DisposingModel(); + pDoc = nullptr; + xCurrentTable = nullptr; +} + +void ScXMLExport::SetSharedData(std::unique_ptr<ScMySharedData> pTemp) { pSharedData = std::move(pTemp); } + +std::unique_ptr<ScMySharedData> ScXMLExport::ReleaseSharedData() { return std::move(pSharedData); } +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |