summaryrefslogtreecommitdiffstats
path: root/xmloff/source/chart/SchXMLSeries2Context.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/chart/SchXMLSeries2Context.cxx')
-rw-r--r--xmloff/source/chart/SchXMLSeries2Context.cxx1308
1 files changed, 1308 insertions, 0 deletions
diff --git a/xmloff/source/chart/SchXMLSeries2Context.cxx b/xmloff/source/chart/SchXMLSeries2Context.cxx
new file mode 100644
index 0000000000..cf4e33e769
--- /dev/null
+++ b/xmloff/source/chart/SchXMLSeries2Context.cxx
@@ -0,0 +1,1308 @@
+/* -*- 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 "SchXMLSeries2Context.hxx"
+#include "SchXMLPlotAreaContext.hxx"
+#include "SchXMLRegressionCurveObjectContext.hxx"
+#include "SchXMLPropertyMappingContext.hxx"
+#include "SchXMLTools.hxx"
+
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/XRegressionCurve.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+#include <com/sun/star/chart2/data/XDataSink.hpp>
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+
+#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
+#include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
+#include <com/sun/star/chart2/DataPointCustomLabelField.hpp>
+
+#include <com/sun/star/chart/ChartAxisAssign.hpp>
+#include <com/sun/star/chart/ChartSymbolType.hpp>
+#include <com/sun/star/chart/ChartDataCaption.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/chart/ChartLegendPosition.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XVisualObject.hpp>
+
+#include <comphelper/processfactory.hxx>
+
+#include <sal/log.hxx>
+#include <utility>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <xmloff/SchXMLSeriesHelper.hxx>
+#include <SchXMLImport.hxx>
+#include <xmloff/prstylei.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <algorithm> // std::find_if
+
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+
+class SchXMLDomain2Context : public SvXMLImportContext
+{
+private:
+ ::std::vector< OUString > & mrAddresses;
+
+public:
+ SchXMLDomain2Context( SvXMLImport& rImport,
+ ::std::vector< OUString > & rAddresses );
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
+};
+
+SchXMLDomain2Context::SchXMLDomain2Context(
+ SvXMLImport& rImport,
+ ::std::vector< OUString > & rAddresses ) :
+ SvXMLImportContext( rImport ),
+ mrAddresses( rAddresses )
+{
+}
+
+void SchXMLDomain2Context::startFastElement(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
+{
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ if (aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) )
+ mrAddresses.push_back( aIter.toString() );
+ else
+ XMLOFF_WARN_UNKNOWN("xmloff", aIter);
+ }
+}
+
+void lcl_setAutomaticSymbolSize( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
+{
+ awt::Size aSymbolSize(140,140);//old default for standard sized charts 7cm height
+
+ uno::Reference< chart::XChartDocument > xChartDoc( rImport.GetModel(), uno::UNO_QUERY );
+ if( xChartDoc.is() )
+ {
+ double fScale = 1;
+ uno::Reference< beans::XPropertySet > xLegendProp( xChartDoc->getLegend(), uno::UNO_QUERY );
+ chart::ChartLegendPosition aLegendPosition = chart::ChartLegendPosition_NONE;
+ if( xLegendProp.is() && (xLegendProp->getPropertyValue("Alignment") >>= aLegendPosition)
+ && chart::ChartLegendPosition_NONE != aLegendPosition )
+ {
+
+ double fFontHeight = 6.0;
+ if( xLegendProp->getPropertyValue("CharHeight") >>= fFontHeight )
+ fScale = 0.75*fFontHeight/6.0;
+ }
+ else
+ {
+ uno::Reference< embed::XVisualObject > xVisualObject( rImport.GetModel(), uno::UNO_QUERY );
+ if( xVisualObject.is() )
+ {
+ awt::Size aPageSize( xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
+ fScale = aPageSize.Height/7000.0;
+ }
+ }
+ if( fScale>0 )
+ {
+ aSymbolSize.Height = static_cast<sal_Int32>( fScale * aSymbolSize.Height );
+ aSymbolSize.Width = aSymbolSize.Height;
+ }
+ }
+ xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::Any( aSymbolSize ));
+}
+
+void lcl_setSymbolSizeIfNeeded( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
+{
+ if( !xSeriesOrPointProp.is() )
+ return;
+
+ sal_Int32 nSymbolType = chart::ChartSymbolType::NONE;
+ if( !(xSeriesOrPointProp.is() && ( xSeriesOrPointProp->getPropertyValue("SymbolType") >>= nSymbolType)) )
+ return;
+
+ if(chart::ChartSymbolType::NONE!=nSymbolType)
+ {
+ if( chart::ChartSymbolType::BITMAPURL==nSymbolType )
+ {
+ //set special size for graphics to indicate to use the bitmap size itself
+ xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::Any( awt::Size(-1,-1) ));
+ }
+ else
+ {
+ lcl_setAutomaticSymbolSize( xSeriesOrPointProp, rImport );
+ }
+ }
+}
+
+void lcl_resetSymbolSizeForPointsIfNecessary( const uno::Reference< beans::XPropertySet >& xPointProp, const SvXMLImport& rImport
+ , const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
+{
+ uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize", pPropStyleContext, pStylesCtxt ) );
+ if( !aASymbolSize.hasValue() )
+ lcl_setSymbolSizeIfNeeded( xPointProp, rImport );
+}
+
+void lcl_setLinkNumberFormatToSourceIfNeeded( const uno::Reference< beans::XPropertySet >& xPointProp
+ , const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
+{
+ uno::Any aAny( SchXMLTools::getPropertyFromContext(u"LinkNumberFormatToSource", pPropStyleContext, pStylesCtxt) );
+ if( aAny.hasValue() )
+ return;
+
+ if( !xPointProp.is() )
+ return;
+
+ bool bLinkToSource = false;
+ if( xPointProp.is() && (xPointProp->getPropertyValue("LinkNumberFormatToSource") >>= bLinkToSource) )
+ {
+ if( bLinkToSource )
+ {
+ xPointProp->setPropertyValue("LinkNumberFormatToSource", uno::Any(false));
+ }
+ }
+}
+
+void lcl_insertErrorBarLSequencesToMap(
+ tSchXMLLSequencesPerIndex & rInOutMap,
+ const uno::Reference< beans::XPropertySet > & xSeriesProp )
+{
+ Reference< chart2::data::XDataSource > xErrorBarSource;
+ if( ( xSeriesProp->getPropertyValue( "ErrorBarY" ) >>= xErrorBarSource ) &&
+ xErrorBarSource.is() )
+ {
+ const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences(
+ xErrorBarSource->getDataSequences());
+ for( const auto& rLSequence : aLSequences )
+ {
+ // use "0" as data index. This is ok, as it is not used for error bars
+ rInOutMap.emplace(
+ tSchXMLIndexWithPart( 0, SCH_XML_PART_ERROR_BARS ), rLSequence );
+ }
+ }
+}
+
+Reference< chart2::data::XLabeledDataSequence2 > lcl_createAndAddSequenceToSeries( const OUString& rRole
+ , const OUString& rRange
+ , const Reference< chart2::XChartDocument >& xChartDoc
+ , const Reference< chart2::XDataSeries >& xSeries )
+{
+ Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq;
+
+ Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY );
+ Reference< chart2::data::XDataSink > xSeriesSink( xSeries, uno::UNO_QUERY );
+
+ if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is() && xSeriesSink.is()) )
+ return xLabeledSeq;
+
+ // create a new sequence
+ xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence();
+
+ // set values at the new sequence
+ Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc );
+ Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY );
+ if( xSeqProp.is())
+ xSeqProp->setPropertyValue("Role", uno::Any( rRole));
+ xLabeledSeq->setValues( xSeq );
+
+ // add new sequence to data series / push to front to have the correct sequence order if charttype is changed afterwards
+ const Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeq( xSeriesSource->getDataSequences());
+ sal_Int32 nOldCount = aOldSeq.getLength();
+ Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeq( nOldCount + 1 );
+ auto pNewSeq = aNewSeq.getArray();
+ pNewSeq[0].set(xLabeledSeq, uno::UNO_QUERY_THROW);
+ std::copy(aOldSeq.begin(), aOldSeq.end(), std::next(pNewSeq));
+ xSeriesSink->setData( aNewSeq );
+
+ return xLabeledSeq;
+}
+
+XMLPropStyleContext* lcl_GetStylePropContext(
+ const SvXMLStylesContext* pStylesCtxt,
+ const SvXMLStyleContext*& rpStyle,
+ OUString const & rStyleName )
+{
+ rpStyle = pStylesCtxt->FindStyleChildContext( SchXMLImportHelper::GetChartFamilyID(), rStyleName );
+ XMLPropStyleContext* pPropStyleContext =
+ const_cast< XMLPropStyleContext* >(dynamic_cast< const XMLPropStyleContext* >( rpStyle ));
+ return pPropStyleContext;
+}
+
+} // anonymous namespace
+
+SchXMLSeries2Context::SchXMLSeries2Context(
+ SchXMLImportHelper& rImpHelper,
+ SvXMLImport& rImport,
+ const Reference< chart2::XChartDocument > & xNewDoc,
+ std::vector< SchXMLAxis >& rAxes,
+ ::std::vector< DataRowPointStyle >& rStyleVector,
+ ::std::vector< RegressionStyle >& rRegressionStyleVector,
+ sal_Int32 nSeriesIndex,
+ bool bStockHasVolume,
+ GlobalSeriesImportInfo& rGlobalSeriesImportInfo,
+ const OUString & aGlobalChartTypeName,
+ tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
+ bool& rGlobalChartTypeUsedBySeries,
+ const awt::Size & rChartSize ) :
+ SvXMLImportContext( rImport ),
+ mrImportHelper( rImpHelper ),
+ mxNewDoc( xNewDoc ),
+ mrAxes( rAxes ),
+ mrStyleVector( rStyleVector ),
+ mrRegressionStyleVector( rRegressionStyleVector ),
+ mnSeriesIndex( nSeriesIndex ),
+ mnDataPointIndex( 0 ),
+ m_bStockHasVolume( bStockHasVolume ),
+ m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo),
+ mpAttachedAxis( nullptr ),
+ mnAttachedAxis( 0 ),
+ maGlobalChartTypeName( aGlobalChartTypeName ),
+ maSeriesChartTypeName( aGlobalChartTypeName ),
+ m_bHasDomainContext(false),
+ mrLSequencesPerIndex( rLSequencesPerIndex ),
+ mrGlobalChartTypeUsedBySeries( rGlobalChartTypeUsedBySeries ),
+ mbSymbolSizeIsMissingInFile(false),
+ maChartSize( rChartSize ),
+ // A series manages the DataRowPointStyle-struct of a data-label child element.
+ mDataLabel(DataRowPointStyle::DATA_LABEL_SERIES, OUString{})
+{
+ if( aGlobalChartTypeName == "com.sun.star.chart2.DonutChartType" )
+ {
+ maSeriesChartTypeName = "com.sun.star.chart2.PieChartType";
+ maGlobalChartTypeName = maSeriesChartTypeName;
+ }
+}
+
+SchXMLSeries2Context::~SchXMLSeries2Context()
+{
+ SAL_WARN_IF( !maPostponedSequences.empty(), "xmloff.chart", "maPostponedSequences is NULL");
+}
+
+void SchXMLSeries2Context::startFastElement (sal_Int32 /*Element*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
+{
+ // parse attributes
+ mnAttachedAxis = 1;
+
+ bool bHasRange = false;
+ OUString aSeriesLabelRange;
+ OUString aSeriesLabelString;
+ bool bHideLegend = false;
+
+ for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
+ {
+ OUString aValue = aIter.toString();
+ switch(aIter.getToken())
+ {
+ case XML_ELEMENT(CHART, XML_VALUES_CELL_RANGE_ADDRESS):
+ m_aSeriesRange = aValue;
+ bHasRange = true;
+ break;
+ case XML_ELEMENT(CHART, XML_LABEL_CELL_ADDRESS):
+ aSeriesLabelRange = aValue;
+ break;
+ case XML_ELEMENT(LO_EXT, XML_LABEL_STRING):
+ aSeriesLabelString = aValue;
+ break;
+ case XML_ELEMENT(CHART, XML_ATTACHED_AXIS):
+ {
+ sal_Int32 nNumOfAxes = mrAxes.size();
+ for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ )
+ {
+ if( aValue == mrAxes[ nCurrent ].aName &&
+ mrAxes[ nCurrent ].eDimension == SCH_XML_AXIS_Y )
+ {
+ mpAttachedAxis = &( mrAxes[ nCurrent ] );
+ }
+ }
+ }
+ break;
+ case XML_ELEMENT(CHART, XML_STYLE_NAME):
+ msAutoStyleName = aValue;
+ break;
+ case XML_ELEMENT(CHART, XML_CLASS):
+ {
+ OUString aClassName;
+ sal_uInt16 nClassPrefix =
+ GetImport().GetNamespaceMap().GetKeyByAttrValueQName(
+ aValue, &aClassName );
+ if( XML_NAMESPACE_CHART == nClassPrefix )
+ maSeriesChartTypeName = SchXMLTools::GetChartTypeByClassName( aClassName, false /* bUseOldNames */ );
+
+ if( maSeriesChartTypeName.isEmpty())
+ maSeriesChartTypeName = aClassName;
+ }
+ break;
+ case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND):
+ bHideLegend = aValue.toBoolean();
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN("xmloff", aIter);
+ }
+ }
+
+ if( mpAttachedAxis )
+ {
+ if( mpAttachedAxis->nAxisIndex > 0 )
+ {
+ // secondary axis => property has to be set (primary is default)
+ mnAttachedAxis = 2;
+ }
+ }
+
+ try
+ {
+ SAL_WARN_IF( !mxNewDoc.is(), "xmloff.chart", "mxNewDoc is NULL");
+ if( m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && ! bHasRange )
+ m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable = false;
+
+ bool bIsCandleStick = maGlobalChartTypeName == "com.sun.star.chart2.CandleStickChartType";
+ if( !maSeriesChartTypeName.isEmpty() )
+ {
+ bIsCandleStick = maSeriesChartTypeName == "com.sun.star.chart2.CandleStickChartType";
+ }
+ else
+ {
+ if( bIsCandleStick
+ && m_bStockHasVolume
+ && mnSeriesIndex == 0 )
+ {
+ maSeriesChartTypeName = "com.sun.star.chart2.ColumnChartType";
+ bIsCandleStick = false;
+ }
+ else
+ {
+ maSeriesChartTypeName = maGlobalChartTypeName;
+ }
+ }
+ if( ! mrGlobalChartTypeUsedBySeries )
+ mrGlobalChartTypeUsedBySeries = (maSeriesChartTypeName == maGlobalChartTypeName);
+ sal_Int32 const nCoordinateSystemIndex = 0;//so far we can only import one coordinate system
+ m_xSeries.set(
+ SchXMLImportHelper::GetNewDataSeries( mxNewDoc, nCoordinateSystemIndex, maSeriesChartTypeName, ! mrGlobalChartTypeUsedBySeries ));
+ Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( SchXMLTools::GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW );
+
+ Reference< beans::XPropertySet > xSeriesProp( m_xSeries, uno::UNO_QUERY );
+ if (xSeriesProp.is())
+ {
+ if (bHideLegend)
+ xSeriesProp->setPropertyValue("ShowLegendEntry", uno::Any(false));
+
+ if( bIsCandleStick )
+ {
+ // set default color for range-line to black (before applying styles)
+ xSeriesProp->setPropertyValue("Color",
+ uno::Any( sal_Int32( 0x000000 ))); // black
+ }
+ else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" )
+ {
+ //@todo: this property should be saved
+ xSeriesProp->setPropertyValue("VaryColorsByPoint",
+ uno::Any( true ));
+ }
+
+ }
+
+ Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider());
+ Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY);
+
+ Reference<chart2::data::XDataSequence> xSequenceValues;
+
+ // values
+ if (xPivotTableDataProvider.is()) // is pivot chart
+ {
+ xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex));
+ }
+ else
+ {
+ if (bHasRange && !m_aSeriesRange.isEmpty())
+ xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc);
+ }
+
+ Reference<beans::XPropertySet> xSeqProp(xSequenceValues, uno::UNO_QUERY);
+ if (xSeqProp.is())
+ {
+ OUString aMainRole("values-y");
+ if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType")
+ aMainRole = "values-size";
+ xSeqProp->setPropertyValue("Role", uno::Any(aMainRole));
+ }
+ xLabeledSeq->setValues(xSequenceValues);
+
+ // register for setting local data if external data provider is not present
+ maPostponedSequences.emplace(
+ tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq );
+
+ // label
+ Reference<chart2::data::XDataSequence> xSequenceLabel;
+
+ if (xPivotTableDataProvider.is())
+ {
+ xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex));
+ }
+ else
+ {
+ if (!aSeriesLabelRange.isEmpty())
+ {
+ xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc));
+ }
+ else if (!aSeriesLabelString.isEmpty())
+ {
+ xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc));
+ }
+ }
+
+ //Labels should always include hidden cells
+ Reference<beans::XPropertySet> xSeqLabelProp(xSequenceLabel, uno::UNO_QUERY);
+ if (xSeqLabelProp.is() && xSeqLabelProp->getPropertySetInfo()->hasPropertyByName("IncludeHiddenCells"))
+ {
+ xSeqLabelProp->setPropertyValue( "IncludeHiddenCells", uno::Any(true));
+ }
+
+ xLabeledSeq->setLabel(xSequenceLabel);
+
+ // Note: Even if we have no label, we have to register the label
+ // for creation, because internal data always has labels. If
+ // they don't exist in the original, auto-generated labels are
+ // used for the internal data.
+ maPostponedSequences.emplace(
+ tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_LABEL ), xLabeledSeq );
+
+ Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( &xLabeledSeq, 1 );
+ Reference< chart2::data::XDataSink > xSink( m_xSeries, uno::UNO_QUERY_THROW );
+ xSink->setData( aSeq );
+ }
+ catch( const uno::Exception &)
+ {
+ DBG_UNHANDLED_EXCEPTION("xmloff.chart");
+ }
+
+ //init mbSymbolSizeIsMissingInFile:
+ try
+ {
+ if( !msAutoStyleName.isEmpty() )
+ {
+ const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
+ if( pStylesCtxt )
+ {
+ const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName );
+
+ const XMLPropStyleContext* pPropStyleContext = dynamic_cast< const XMLPropStyleContext * >( pStyle );
+
+ uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize"
+ , pPropStyleContext, pStylesCtxt ) );
+ mbSymbolSizeIsMissingInFile = !aASymbolSize.hasValue();
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ }
+}
+
+namespace {
+
+struct DomainInfo
+{
+ DomainInfo( OUString _aRole, OUString _aRange, sal_Int32 nIndex )
+ : aRole(std::move(_aRole)), aRange(std::move(_aRange)), nIndexForLocalData(nIndex)
+ {}
+
+ OUString aRole;
+ OUString aRange;
+ sal_Int32 nIndexForLocalData;
+};
+
+}
+
+void SchXMLSeries2Context::endFastElement(sal_Int32 )
+{
+ // special handling for different chart types. This is necessary as the
+ // roles are not yet saved in the file format
+ sal_Int32 nDomainCount = maDomainAddresses.size();
+ bool bIsScatterChart = maSeriesChartTypeName == "com.sun.star.chart2.ScatterChartType";
+ bool bIsBubbleChart = maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType";
+ bool bDeleteSeries = false;
+ std::vector< DomainInfo > aDomainInfos;
+
+ //different handling for different chart types necessary
+ if( bIsScatterChart || ( nDomainCount==1 && !bIsBubbleChart ) )
+ {
+ DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
+ bool bCreateXValues = true;
+ if( !maDomainAddresses.empty() )
+ {
+ if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
+ {
+ m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
+ m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
+ }
+ aDomainInfo.aRange = maDomainAddresses.front();
+ aDomainInfo.nIndexForLocalData = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
+ m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
+ }
+ else if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() && !m_bHasDomainContext && mnSeriesIndex==0 )
+ {
+ if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) //wrong old chart files:
+ {
+ //for xy charts the first series needs to have a domain
+ //if this by error iss not the case the first series is taken s x values
+ //needed for wrong files created while having an addin (e.g. BoxPlot)
+ m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = m_aSeriesRange;
+ m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
+ bDeleteSeries = true;
+ bCreateXValues = false;//they will be created for the next series
+ }
+ }
+ if( bCreateXValues )
+ aDomainInfos.push_back( aDomainInfo );
+ }
+ else if( bIsBubbleChart )
+ {
+ if( nDomainCount>1 )
+ {
+ DomainInfo aDomainInfo( "values-x", maDomainAddresses[1], m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
+ if( m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
+ {
+ //for bubble chart the second domain contains the x values which should become an index smaller than y values for own data table
+ //->so second first
+ m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress = maDomainAddresses[1];
+ m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
+ }
+ aDomainInfos.push_back( aDomainInfo );
+ m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
+ }
+ else if( !m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
+ {
+ DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ;
+ aDomainInfos.push_back( aDomainInfo );
+ }
+ if( nDomainCount>0)
+ {
+ DomainInfo aDomainInfo( "values-y", maDomainAddresses.front(), m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
+ if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
+ {
+ m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
+ m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
+ }
+ aDomainInfos.push_back( aDomainInfo );
+ m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
+ }
+ else if( !m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
+ {
+ DomainInfo aDomainInfo( "values-y", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
+ aDomainInfos.push_back( aDomainInfo );
+ }
+ }
+
+ if( bDeleteSeries )
+ {
+ //delete created series
+ SchXMLImportHelper::DeleteDataSeries(
+ m_xSeries, Reference< chart2::XChartDocument >( GetImport().GetModel(), uno::UNO_QUERY ) );
+ }
+ else
+ {
+ //add style
+ if( !msAutoStyleName.isEmpty() || mnAttachedAxis != 1 )
+ {
+ DataRowPointStyle aStyle(
+ DataRowPointStyle::DATA_SERIES,
+ m_xSeries,
+ -1, 1,
+ msAutoStyleName, mnAttachedAxis );
+ aStyle.mbSymbolSizeForSeriesIsMissingInFile=mbSymbolSizeIsMissingInFile;
+ mrStyleVector.push_back( aStyle );
+ }
+ // And styles for a data-label child element too. In contrast to data-labels as child of data points,
+ // an information about absolute position is useless here. We need only style information.
+ if (!mDataLabel.msStyleName.isEmpty())
+ {
+ mDataLabel.msStyleNameOfParent = msAutoStyleName;
+ mDataLabel.m_xSeries = m_xSeries;
+ mDataLabel.mnAttachedAxis = mnAttachedAxis; // not needed, but be consistent with its parent
+ mrStyleVector.push_back(mDataLabel);
+ }
+ }
+
+ for( std::vector< DomainInfo >::reverse_iterator aIt( aDomainInfos.rbegin() ); aIt!= aDomainInfos.rend(); ++aIt )
+ {
+ DomainInfo aDomainInfo( *aIt );
+ Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq =
+ lcl_createAndAddSequenceToSeries( aDomainInfo.aRole, aDomainInfo.aRange, mxNewDoc, m_xSeries );
+ if( xLabeledSeq.is() )
+ {
+ // register for setting local data if external data provider is not present
+ mrLSequencesPerIndex.emplace(
+ tSchXMLIndexWithPart( aDomainInfo.nIndexForLocalData, SCH_XML_PART_VALUES ),
+ Reference< chart2::data::XLabeledDataSequence >(xLabeledSeq, uno::UNO_QUERY_THROW) );
+ }
+ }
+
+ if( !bDeleteSeries )
+ {
+ for (auto const& postponedSequence : maPostponedSequences)
+ {
+ sal_Int32 nNewIndex = postponedSequence.first.first + nDomainCount;
+ mrLSequencesPerIndex.emplace( tSchXMLIndexWithPart( nNewIndex, postponedSequence.first.second ), postponedSequence.second );
+ }
+ m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
+ }
+ maPostponedSequences.clear();
+}
+
+css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLSeries2Context::createFastChildContext(
+ sal_Int32 nElement,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
+{
+ SvXMLImportContext* pContext = nullptr;
+
+ switch(nElement)
+ {
+ case XML_ELEMENT(CHART, XML_DOMAIN):
+ if( m_xSeries.is())
+ {
+ m_bHasDomainContext = true;
+ pContext = new SchXMLDomain2Context(
+ GetImport(), maDomainAddresses );
+ }
+ break;
+
+ case XML_ELEMENT(CHART, XML_MEAN_VALUE):
+ pContext = new SchXMLStatisticsObjectContext(
+ mrImportHelper, GetImport(),
+ msAutoStyleName,
+ mrStyleVector, m_xSeries,
+ SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE,
+ mrLSequencesPerIndex );
+ break;
+ case XML_ELEMENT(CHART, XML_REGRESSION_CURVE):
+ pContext = new SchXMLRegressionCurveObjectContext(
+ mrImportHelper, GetImport(),
+ mrRegressionStyleVector,
+ m_xSeries, maChartSize );
+ break;
+ case XML_ELEMENT(CHART, XML_ERROR_INDICATOR):
+ pContext = new SchXMLStatisticsObjectContext(
+ mrImportHelper, GetImport(),
+ msAutoStyleName,
+ mrStyleVector, m_xSeries,
+ SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR,
+ mrLSequencesPerIndex );
+ break;
+
+ case XML_ELEMENT(CHART, XML_DATA_POINT):
+ pContext = new SchXMLDataPointContext( GetImport(),
+ mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile );
+ break;
+ case XML_ELEMENT(CHART, XML_DATA_LABEL):
+ // CustomLabels are useless for a data label element as child of a series, because it serves as default
+ // for all data labels. But the ctor expects it, so use that of the mDataLabel struct as ersatz.
+ pContext = new SchXMLDataLabelContext(GetImport(), mDataLabel.mCustomLabels,
+ mDataLabel);
+ break;
+
+ case XML_ELEMENT(LO_EXT, XML_PROPERTY_MAPPING):
+ pContext = new SchXMLPropertyMappingContext(
+ GetImport(),
+ mrLSequencesPerIndex, m_xSeries );
+ break;
+ default:
+ XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
+ }
+
+ return pContext;
+}
+
+//static
+void SchXMLSeries2Context::initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
+ , const uno::Reference< frame::XModel >& xChartModel )
+{
+ // iterate over series first and remind propertysets in map
+ // new api <-> old api wrapper
+ ::std::map< Reference< chart2::XDataSeries >, Reference< beans::XPropertySet > > aSeriesMap;
+ for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
+ {
+ if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
+ continue;
+
+ if( !seriesStyle.m_xOldAPISeries.is() )
+ seriesStyle.m_xOldAPISeries = SchXMLSeriesHelper::createOldAPISeriesPropertySet( seriesStyle.m_xSeries, xChartModel );
+
+ aSeriesMap[seriesStyle.m_xSeries] = seriesStyle.m_xOldAPISeries;
+
+ }
+
+ //initialize m_xOldAPISeries for all other styles also
+ for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
+ {
+ if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES )
+ continue;
+ seriesStyle.m_xOldAPISeries = aSeriesMap[seriesStyle.m_xSeries];
+ }
+}
+
+//static
+void SchXMLSeries2Context::setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles )
+{
+ // iterate over series
+ // call initSeriesPropertySets first
+
+ for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
+ {
+ if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
+ continue;
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
+ if( !xSeries.is() )
+ continue;
+
+ if( rSeriesDefaultsAndStyles.maSymbolTypeDefault.hasValue() )
+ xSeries->setPropertyValue("SymbolType",rSeriesDefaultsAndStyles.maSymbolTypeDefault);
+ if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() )
+ xSeries->setPropertyValue("DataCaption",rSeriesDefaultsAndStyles.maDataCaptionDefault);
+
+ if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() )
+ xSeries->setPropertyValue("ErrorIndicator",rSeriesDefaultsAndStyles.maErrorIndicatorDefault);
+ if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() )
+ xSeries->setPropertyValue("ErrorCategory",rSeriesDefaultsAndStyles.maErrorCategoryDefault);
+ if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() )
+ xSeries->setPropertyValue("ConstantErrorLow",rSeriesDefaultsAndStyles.maConstantErrorLowDefault);
+ if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() )
+ xSeries->setPropertyValue("ConstantErrorHigh",rSeriesDefaultsAndStyles.maConstantErrorHighDefault);
+ if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() )
+ xSeries->setPropertyValue("PercentageError",rSeriesDefaultsAndStyles.maPercentageErrorDefault);
+ if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() )
+ xSeries->setPropertyValue("ErrorMargin",rSeriesDefaultsAndStyles.maErrorMarginDefault);
+
+ if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() )
+ xSeries->setPropertyValue("MeanValue",rSeriesDefaultsAndStyles.maMeanValueDefault);
+ if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() )
+ xSeries->setPropertyValue("RegressionCurves",rSeriesDefaultsAndStyles.maRegressionCurvesDefault);
+ }
+ catch( uno::Exception & )
+ {
+ //end of series reached
+ }
+ }
+}
+
+// ODF has the line and fill properties in a <style:style> element, which is referenced by the
+// <chart:data-label> element. But LibreOffice has them as special label properties of the series
+// or point respectively. The following array maps the API name of the ODF property to the name of
+// the internal property. Those are of kind "LabelFoo".
+// The array is used in methods setStylesToSeries and setStylesToDataPoints.
+const std::pair<OUString, OUString> aApiToLabelFooPairs[]
+ = { { "LineStyle", "LabelBorderStyle" },
+ { "LineWidth", "LabelBorderWidth" },
+ { "LineColor", "LabelBorderColor" },
+ // The name "LabelBorderDash" is defined, but the associated API name "LineDash" belongs to
+ // the <draw:stroke-dash> element and is not used directly as line property.
+ //{"LineDash", "LabelBorderDash"},
+ { "LineDashName", "LabelBorderDashName" },
+ { "LineTransparence", "LabelBorderTransparency" },
+ { "FillStyle", "LabelFillStyle" },
+ { "FillBackground", "LabelFillBackground" },
+ { "FillHatchName", "LabelFillHatchName" },
+ { "FillColor", "LabelFillColor" } };
+
+
+//static
+void SchXMLSeries2Context::setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
+ , const SvXMLStylesContext* pStylesCtxt
+ , const SvXMLStyleContext*& rpStyle
+ , OUString& rCurrStyleName
+ , const SchXMLImportHelper& rImportHelper
+ , const SvXMLImport& rImport
+ , bool bIsStockChart
+ , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex )
+{
+ // iterate over series
+ for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
+ {
+ if (seriesStyle.meType != DataRowPointStyle::DATA_SERIES)
+ continue;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
+ if( !xSeriesProp.is() )
+ continue;
+
+ if( seriesStyle.mnAttachedAxis != 1 )
+ {
+ xSeriesProp->setPropertyValue("Axis"
+ , uno::Any(chart::ChartAxisAssign::SECONDARY_Y) );
+ }
+
+ if( seriesStyle.msStyleName.isEmpty())
+ continue;
+
+ if( rCurrStyleName != seriesStyle.msStyleName )
+ {
+ rCurrStyleName = seriesStyle.msStyleName;
+ rpStyle = pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
+ }
+
+ //set style to series
+ // note: SvXMLStyleContext::FillPropertySet is not const
+ XMLPropStyleContext * pPropStyleContext =
+ const_cast< XMLPropStyleContext * >(
+ dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
+
+ if (!pPropStyleContext)
+ continue;
+
+ // error bar style must be set before the other error
+ // bar properties (which may be alphabetically before
+ // this property)
+ bool bHasErrorBarRangesFromData = false;
+ {
+ static constexpr OUString aErrorBarStylePropName( u"ErrorBarStyle"_ustr);
+ uno::Any aErrorBarStyle(
+ SchXMLTools::getPropertyFromContext( aErrorBarStylePropName, pPropStyleContext, pStylesCtxt ));
+ if( aErrorBarStyle.hasValue())
+ {
+ xSeriesProp->setPropertyValue( aErrorBarStylePropName, aErrorBarStyle );
+ sal_Int32 eEBStyle = chart::ErrorBarStyle::NONE;
+ bHasErrorBarRangesFromData =
+ ( ( aErrorBarStyle >>= eEBStyle ) &&
+ eEBStyle == chart::ErrorBarStyle::FROM_DATA );
+ }
+ }
+
+ //don't set the style to the min max line series of a stock chart
+ //otherwise the min max line properties gets overwritten and the series becomes invisible typically
+ if (bIsStockChart)
+ {
+ if (SchXMLSeriesHelper::isCandleStickSeries(
+ seriesStyle.m_xSeries,
+ rImportHelper.GetChartDocument()))
+ continue;
+ }
+
+ // Has the series a data-label child element?
+ auto pItLabel
+ = std::find_if(rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
+ rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
+ [&seriesStyle](const DataRowPointStyle& rStyle) {
+ return rStyle.meType == DataRowPointStyle::DATA_LABEL_SERIES
+ && rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
+ });
+ if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
+ {
+ // Bring the information from the data-label to the series
+ const SvXMLStyleContext* pLabelStyleContext(pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
+ // note: SvXMLStyleContext::FillPropertySet is not const
+ XMLPropStyleContext* pLabelPropStyleContext = const_cast<XMLPropStyleContext*>(
+ dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
+ if (pLabelPropStyleContext)
+ {
+ // Test each to be mapped property whether the data-label has a value for it.
+ // If found, set it at series.
+ uno::Reference<beans::XPropertySetInfo> xSeriesPropInfo(
+ xSeriesProp->getPropertySetInfo());
+ for (const auto& rPropPair : aApiToLabelFooPairs)
+ {
+ uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
+ rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
+ if (aPropValue.hasValue()
+ && xSeriesPropInfo->hasPropertyByName(rPropPair.second))
+ xSeriesProp->setPropertyValue(rPropPair.second, aPropValue);
+ }
+ }
+ }
+
+ pPropStyleContext->FillPropertySet( xSeriesProp );
+ if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
+ lcl_setSymbolSizeIfNeeded( xSeriesProp, rImport );
+ if( bHasErrorBarRangesFromData )
+ lcl_insertErrorBarLSequencesToMap( rInOutLSequencesPerIndex, xSeriesProp );
+
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
+ }
+ }
+}
+
+// static
+void SchXMLSeries2Context::setStylesToRegressionCurves(
+ SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles,
+ const SvXMLStylesContext* pStylesCtxt,
+ const SvXMLStyleContext*& rpStyle,
+ OUString const & rCurrentStyleName )
+{
+ // iterate over regression etc
+ for (auto const& regressionStyle : rSeriesDefaultsAndStyles.maRegressionStyleVector)
+ {
+ try
+ {
+ OUString aServiceName;
+ XMLPropStyleContext* pPropStyleContext = nullptr;
+
+ if (!rCurrentStyleName.isEmpty())
+ {
+ XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, rCurrentStyleName);
+ if( pCurrent )
+ {
+ pPropStyleContext = pCurrent;
+ uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
+ if ( aAny.hasValue() )
+ {
+ aAny >>= aServiceName;
+ }
+ }
+ }
+
+ if (!regressionStyle.msStyleName.isEmpty())
+ {
+ XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, regressionStyle.msStyleName);
+ if( pCurrent )
+ {
+ pPropStyleContext = pCurrent;
+ uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
+ if ( aAny.hasValue() )
+ {
+ aAny >>= aServiceName;
+ }
+ }
+ }
+
+ if( !aServiceName.isEmpty() )
+ {
+ Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory();
+ Reference< chart2::XRegressionCurve > xRegCurve( xMSF->createInstance( aServiceName ), uno::UNO_QUERY_THROW );
+ Reference< chart2::XRegressionCurveContainer > xRegCurveCont( regressionStyle.m_xSeries, uno::UNO_QUERY_THROW );
+
+ Reference< beans::XPropertySet > xCurveProperties( xRegCurve, uno::UNO_QUERY );
+ if( pPropStyleContext != nullptr)
+ pPropStyleContext->FillPropertySet( xCurveProperties );
+
+ xRegCurve->setEquationProperties( regressionStyle.m_xEquationProperties );
+
+ xRegCurveCont->addRegressionCurve( xRegCurve );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
+ }
+
+ }
+}
+
+// static
+void SchXMLSeries2Context::setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
+ , const SvXMLStylesContext* pStylesCtxt
+ , const SvXMLStyleContext*& rpStyle
+ , OUString& rCurrStyleName )
+{
+ // iterate over regression etc
+ for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
+ {
+ if( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR ||
+ seriesStyle.meType == DataRowPointStyle::MEAN_VALUE )
+ {
+ if ( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR )
+ {
+ uno::Reference< beans::XPropertySet > xNewSeriesProp(seriesStyle.m_xSeries,uno::UNO_QUERY);
+
+ if (seriesStyle.m_xErrorXProperties.is())
+ xNewSeriesProp->setPropertyValue("ErrorBarX",uno::Any(seriesStyle.m_xErrorXProperties));
+
+ if (seriesStyle.m_xErrorYProperties.is())
+ xNewSeriesProp->setPropertyValue("ErrorBarY",uno::Any(seriesStyle.m_xErrorYProperties));
+ }
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
+ if( !xSeriesProp.is() )
+ continue;
+
+ if( !seriesStyle.msStyleName.isEmpty())
+ {
+ if( rCurrStyleName != seriesStyle.msStyleName )
+ {
+ rCurrStyleName = seriesStyle.msStyleName;
+ rpStyle = pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
+ }
+
+ // note: SvXMLStyleContext::FillPropertySet is not const
+ XMLPropStyleContext * pPropStyleContext =
+ const_cast< XMLPropStyleContext * >(
+ dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
+ if( pPropStyleContext )
+ {
+ Reference< beans::XPropertySet > xStatPropSet;
+ switch( seriesStyle.meType )
+ {
+ case DataRowPointStyle::MEAN_VALUE:
+ xSeriesProp->getPropertyValue("DataMeanValueProperties") >>= xStatPropSet;
+ break;
+ case DataRowPointStyle::ERROR_INDICATOR:
+ xSeriesProp->getPropertyValue("DataErrorProperties") >>= xStatPropSet;
+ break;
+ default:
+ break;
+ }
+ if( xStatPropSet.is())
+ pPropStyleContext->FillPropertySet( xStatPropSet );
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
+ }
+ }
+ }
+}
+
+//static
+void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
+ , const SvXMLStylesContext* pStylesCtxt
+ , const SvXMLStyleContext*& rpStyle
+ , OUString& rCurrStyleName
+ , const SchXMLImportHelper& rImportHelper
+ , const SvXMLImport& rImport
+ , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter )
+{
+ for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
+ {
+ if( seriesStyle.meType != DataRowPointStyle::DATA_POINT )
+ continue;
+
+ if( seriesStyle.m_nPointIndex == -1 )
+ continue;
+
+ uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
+ if(!xSeriesProp.is())
+ continue;
+
+ //ignore datapoint properties for stock charts
+ //... todo ...
+ if( bIsStockChart )
+ {
+ if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries, rImportHelper.GetChartDocument() ) )
+ continue;
+ }
+
+ // data point style
+ for( sal_Int32 i = 0; i < seriesStyle.m_nPointRepeat; i++ )
+ {
+ try
+ {
+ uno::Reference< beans::XPropertySet > xPointProp(
+ SchXMLSeriesHelper::createOldAPIDataPointPropertySet( seriesStyle.m_xSeries, seriesStyle.m_nPointIndex + i
+ , rImportHelper.GetChartDocument() ) );
+
+ if( !xPointProp.is() )
+ continue;
+
+ if( bIsDonutChart )
+ {
+ //set special series styles for donut charts first
+ if( rCurrStyleName != seriesStyle.msSeriesStyleNameForDonuts )
+ {
+ rCurrStyleName = seriesStyle.msSeriesStyleNameForDonuts;
+ rpStyle = pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
+ }
+
+ // note: SvXMLStyleContext::FillPropertySet is not const
+ XMLPropStyleContext * pPropStyleContext =
+ const_cast< XMLPropStyleContext * >(
+ dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
+ if( pPropStyleContext )
+ pPropStyleContext->FillPropertySet( xPointProp );
+ }
+
+ try
+ {
+ //need to set this explicitly here for old files as the new api does not support this property fully anymore
+ if( bSwitchOffLinesForScatter )
+ xPointProp->setPropertyValue("Lines",uno::Any(false));
+ }
+ catch( const uno::Exception & )
+ {
+ }
+
+ if( rCurrStyleName != seriesStyle.msStyleName )
+ {
+ rCurrStyleName = seriesStyle.msStyleName;
+ rpStyle = pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
+ }
+
+ // note: SvXMLStyleContext::FillPropertySet is not const
+ XMLPropStyleContext * pPropStyleContext =
+ const_cast< XMLPropStyleContext * >(
+ dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
+ if (pPropStyleContext)
+ {
+ // Has the point a data-label child element?
+ auto pItLabel = std::find_if(
+ rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
+ rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
+ [&seriesStyle](const DataRowPointStyle& rStyle) {
+ return rStyle.meType == DataRowPointStyle::DATA_LABEL_POINT
+ && rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
+ });
+ if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
+ {
+ // Bring the information from the data-label to the point
+ const SvXMLStyleContext* pLabelStyleContext(
+ pStylesCtxt->FindStyleChildContext(
+ SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
+ // note: SvXMLStyleContext::FillPropertySet is not const
+ XMLPropStyleContext* pLabelPropStyleContext
+ = const_cast<XMLPropStyleContext*>(
+ dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
+ if (pLabelPropStyleContext)
+ {
+ // Test each to be mapped property whether the data-label has a value for it.
+ // If found, set it at the point.
+ uno::Reference<beans::XPropertySetInfo> xPointPropInfo(
+ xPointProp->getPropertySetInfo());
+ for (const auto& rPropPair : aApiToLabelFooPairs)
+ {
+ uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
+ rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
+ if (aPropValue.hasValue()
+ && xPointPropInfo->hasPropertyByName(rPropPair.second))
+ xPointProp->setPropertyValue(rPropPair.second, aPropValue);
+ }
+ }
+ }
+
+ pPropStyleContext->FillPropertySet( xPointProp );
+ if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
+ lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt );
+ if( !pPropStyleContext->isEmptyDataStyleName() )
+ lcl_setLinkNumberFormatToSourceIfNeeded( xPointProp, pPropStyleContext, pStylesCtxt );
+ }
+
+ // Custom labels might be passed as property
+ if(const size_t nLabelCount = seriesStyle.mCustomLabels.mLabels.size(); nLabelCount > 0)
+ {
+ auto& rCustomLabels = seriesStyle.mCustomLabels;
+
+ Sequence< Reference<chart2::XDataPointCustomLabelField>> xLabels(nLabelCount);
+ auto pxLabels = xLabels.getArray();
+ Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
+ for( size_t j = 0; j < nLabelCount; ++j )
+ {
+ Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext);
+ pxLabels[j] = xCustomLabel;
+ xCustomLabel->setString(rCustomLabels.mLabels[j]);
+ if ( j == 0 && rCustomLabels.mbDataLabelsRange)
+ {
+ xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE);
+ xCustomLabel->setGuid(rCustomLabels.msLabelGuid);
+ xCustomLabel->setCellRange(rCustomLabels.msLabelsCellRange);
+ xCustomLabel->setDataLabelsRange(true);
+ }
+ else
+ {
+ xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT);
+ }
+
+ // Restore character properties on the text span manually, till
+ // SchXMLExportHelper_Impl::exportCustomLabel() does not write the style.
+ uno::Reference<beans::XPropertySetInfo> xPointPropInfo
+ = xPointProp->getPropertySetInfo();
+ if (xPointPropInfo.is())
+ {
+ uno::Sequence<beans::Property> aProperties = xPointPropInfo->getProperties();
+ for (const auto& rProperty : std::as_const(aProperties))
+ {
+ if (!rProperty.Name.startsWith("Char")
+ || rProperty.Name.startsWith("Chart"))
+ {
+ continue;
+ }
+
+ xCustomLabel->setPropertyValue(
+ rProperty.Name, xPointProp->getPropertyValue(rProperty.Name));
+ }
+ }
+ }
+
+ xPointProp->setPropertyValue("CustomLabelFields", uno::Any(xLabels));
+ xPointProp->setPropertyValue("DataCaption", uno::Any(chart::ChartDataCaption::CUSTOM));
+ }
+
+ if( seriesStyle.mCustomLabelPos[0] != 0.0 || seriesStyle.mCustomLabelPos[1] != 0.0 )
+ {
+ chart2::RelativePosition aCustomlabelPosition;
+ aCustomlabelPosition.Primary = seriesStyle.mCustomLabelPos[0];
+ aCustomlabelPosition.Secondary = seriesStyle.mCustomLabelPos[1];
+ xPointProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomlabelPosition));
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to data points" );
+ }
+ }
+ } // styles iterator
+}
+
+//static
+void SchXMLSeries2Context::switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector )
+{
+ // iterate over series
+ for (auto const& seriesStyle : rSeriesStyleVector)
+ {
+ if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
+ continue;
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
+ if( !xSeries.is() )
+ continue;
+
+ xSeries->setPropertyValue("Lines",uno::Any(false));
+ }
+ catch( uno::Exception & )
+ {
+ //end of series reached
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */