/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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(u"Alignment"_ustr) >>= aLegendPosition) && chart::ChartLegendPosition_NONE != aLegendPosition ) { double fFontHeight = 6.0; if( xLegendProp->getPropertyValue(u"CharHeight"_ustr) >>= 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( fScale * aSymbolSize.Height ); aSymbolSize.Width = aSymbolSize.Height; } } xSeriesOrPointProp->setPropertyValue(u"SymbolSize"_ustr,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(u"SymbolType"_ustr) >>= 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(u"SymbolSize"_ustr,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(u"LinkNumberFormatToSource"_ustr) >>= bLinkToSource) ) { if( bLinkToSource ) { xPointProp->setPropertyValue(u"LinkNumberFormatToSource"_ustr, uno::Any(false)); } } } void lcl_insertErrorBarLSequencesToMap( tSchXMLLSequencesPerIndex & rInOutMap, const uno::Reference< beans::XPropertySet > & xSeriesProp ) { Reference< chart2::data::XDataSource > xErrorBarSource; if( ( xSeriesProp->getPropertyValue( u"ErrorBarY"_ustr ) >>= 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(u"Role"_ustr, 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(u"ShowLegendEntry"_ustr, uno::Any(false)); if( bIsCandleStick ) { // set default color for range-line to black (before applying styles) xSeriesProp->setPropertyValue(u"Color"_ustr, uno::Any( sal_Int32( 0x000000 ))); // black } else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" ) { //@todo: this property should be saved xSeriesProp->setPropertyValue(u"VaryColorsByPoint"_ustr, uno::Any( true )); } } Reference xDataProvider(mxNewDoc->getDataProvider()); Reference xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); Reference 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 xSeqProp(xSequenceValues, uno::UNO_QUERY); if (xSeqProp.is()) { OUString aMainRole(u"values-y"_ustr); if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType") aMainRole = "values-size"; xSeqProp->setPropertyValue(u"Role"_ustr, 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 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 xSeqLabelProp(xSequenceLabel, uno::UNO_QUERY); if (xSeqLabelProp.is() && xSeqLabelProp->getPropertySetInfo()->hasPropertyByName(u"IncludeHiddenCells"_ustr)) { xSeqLabelProp->setPropertyValue( u"IncludeHiddenCells"_ustr, 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( u"values-x"_ustr, 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( u"values-x"_ustr, 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( u"values-x"_ustr, m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ; aDomainInfos.push_back( aDomainInfo ); } if( nDomainCount>0) { DomainInfo aDomainInfo( u"values-y"_ustr, 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( u"values-y"_ustr, 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(u"SymbolType"_ustr,rSeriesDefaultsAndStyles.maSymbolTypeDefault); if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() ) xSeries->setPropertyValue(u"DataCaption"_ustr,rSeriesDefaultsAndStyles.maDataCaptionDefault); if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() ) xSeries->setPropertyValue(u"ErrorIndicator"_ustr,rSeriesDefaultsAndStyles.maErrorIndicatorDefault); if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() ) xSeries->setPropertyValue(u"ErrorCategory"_ustr,rSeriesDefaultsAndStyles.maErrorCategoryDefault); if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() ) xSeries->setPropertyValue(u"ConstantErrorLow"_ustr,rSeriesDefaultsAndStyles.maConstantErrorLowDefault); if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() ) xSeries->setPropertyValue(u"ConstantErrorHigh"_ustr,rSeriesDefaultsAndStyles.maConstantErrorHighDefault); if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() ) xSeries->setPropertyValue(u"PercentageError"_ustr,rSeriesDefaultsAndStyles.maPercentageErrorDefault); if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() ) xSeries->setPropertyValue(u"ErrorMargin"_ustr,rSeriesDefaultsAndStyles.maErrorMarginDefault); if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() ) xSeries->setPropertyValue(u"MeanValue"_ustr,rSeriesDefaultsAndStyles.maMeanValueDefault); if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() ) xSeries->setPropertyValue(u"RegressionCurves"_ustr,rSeriesDefaultsAndStyles.maRegressionCurvesDefault); } catch( uno::Exception & ) { //end of series reached } } } // ODF has the line and fill properties in a element, which is referenced by the // 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 aApiToLabelFooPairs[] = { { "LineStyle", "LabelBorderStyle" }, { "LineWidth", "LabelBorderWidth" }, { "LineColor", "LabelBorderColor" }, // The name "LabelBorderDash" is defined, but the associated API name "LineDash" belongs to // the 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(u"Axis"_ustr , 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( dynamic_cast(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 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(u"ErrorBarX"_ustr,uno::Any(seriesStyle.m_xErrorXProperties)); if (seriesStyle.m_xErrorYProperties.is()) xNewSeriesProp->setPropertyValue(u"ErrorBarY"_ustr,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(u"DataMeanValueProperties"_ustr) >>= xStatPropSet; break; case DataRowPointStyle::ERROR_INDICATOR: xSeriesProp->getPropertyValue(u"DataErrorProperties"_ustr) >>= 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(u"Lines"_ustr,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( dynamic_cast(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 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> xLabels(nLabelCount); auto pxLabels = xLabels.getArray(); const 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 xPointPropInfo = xPointProp->getPropertySetInfo(); if (xPointPropInfo.is()) { uno::Sequence aProperties = xPointPropInfo->getProperties(); for (const auto& rProperty : aProperties) { if (!rProperty.Name.startsWith("Char") || rProperty.Name.startsWith("Chart")) { continue; } xCustomLabel->setPropertyValue( rProperty.Name, xPointProp->getPropertyValue(rProperty.Name)); } } } xPointProp->setPropertyValue(u"CustomLabelFields"_ustr, uno::Any(xLabels)); xPointProp->setPropertyValue(u"DataCaption"_ustr, 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(u"CustomLabelPosition"_ustr, 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(u"Lines"_ustr,uno::Any(false)); } catch( uno::Exception & ) { //end of series reached } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */