Avoid potential negative array index access to cached text.
[LibreOffice.git] / xmloff / source / chart / SchXMLSeries2Context.cxx
blobcf4e33e769cfb09d1627b881ae71ed0f34619ff7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "SchXMLSeries2Context.hxx"
21 #include "SchXMLPlotAreaContext.hxx"
22 #include "SchXMLRegressionCurveObjectContext.hxx"
23 #include "SchXMLPropertyMappingContext.hxx"
24 #include "SchXMLTools.hxx"
26 #include <com/sun/star/chart2/XChartDocument.hpp>
27 #include <com/sun/star/chart2/XRegressionCurve.hpp>
28 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
29 #include <com/sun/star/chart2/data/XDataSink.hpp>
30 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
31 #include <com/sun/star/chart2/RelativePosition.hpp>
33 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
34 #include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
35 #include <com/sun/star/chart2/DataPointCustomLabelField.hpp>
37 #include <com/sun/star/chart/ChartAxisAssign.hpp>
38 #include <com/sun/star/chart/ChartSymbolType.hpp>
39 #include <com/sun/star/chart/ChartDataCaption.hpp>
40 #include <com/sun/star/chart/ErrorBarStyle.hpp>
41 #include <com/sun/star/chart/XChartDocument.hpp>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/chart/ChartLegendPosition.hpp>
44 #include <com/sun/star/embed/Aspects.hpp>
45 #include <com/sun/star/embed/XVisualObject.hpp>
47 #include <comphelper/processfactory.hxx>
49 #include <sal/log.hxx>
50 #include <utility>
51 #include <xmloff/xmlnamespace.hxx>
52 #include <xmloff/xmlimp.hxx>
53 #include <xmloff/namespacemap.hxx>
54 #include <xmloff/SchXMLSeriesHelper.hxx>
55 #include <SchXMLImport.hxx>
56 #include <xmloff/prstylei.hxx>
57 #include <comphelper/diagnose_ex.hxx>
59 #include <algorithm> // std::find_if
61 using namespace ::com::sun::star;
62 using namespace ::xmloff::token;
64 using ::com::sun::star::uno::Reference;
65 using ::com::sun::star::uno::Sequence;
67 namespace
70 class SchXMLDomain2Context : public SvXMLImportContext
72 private:
73 ::std::vector< OUString > & mrAddresses;
75 public:
76 SchXMLDomain2Context( SvXMLImport& rImport,
77 ::std::vector< OUString > & rAddresses );
78 virtual void SAL_CALL startFastElement(
79 sal_Int32 nElement,
80 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
83 SchXMLDomain2Context::SchXMLDomain2Context(
84 SvXMLImport& rImport,
85 ::std::vector< OUString > & rAddresses ) :
86 SvXMLImportContext( rImport ),
87 mrAddresses( rAddresses )
91 void SchXMLDomain2Context::startFastElement(
92 sal_Int32 /*nElement*/,
93 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
95 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
97 if (aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) )
98 mrAddresses.push_back( aIter.toString() );
99 else
100 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
104 void lcl_setAutomaticSymbolSize( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
106 awt::Size aSymbolSize(140,140);//old default for standard sized charts 7cm height
108 uno::Reference< chart::XChartDocument > xChartDoc( rImport.GetModel(), uno::UNO_QUERY );
109 if( xChartDoc.is() )
111 double fScale = 1;
112 uno::Reference< beans::XPropertySet > xLegendProp( xChartDoc->getLegend(), uno::UNO_QUERY );
113 chart::ChartLegendPosition aLegendPosition = chart::ChartLegendPosition_NONE;
114 if( xLegendProp.is() && (xLegendProp->getPropertyValue("Alignment") >>= aLegendPosition)
115 && chart::ChartLegendPosition_NONE != aLegendPosition )
118 double fFontHeight = 6.0;
119 if( xLegendProp->getPropertyValue("CharHeight") >>= fFontHeight )
120 fScale = 0.75*fFontHeight/6.0;
122 else
124 uno::Reference< embed::XVisualObject > xVisualObject( rImport.GetModel(), uno::UNO_QUERY );
125 if( xVisualObject.is() )
127 awt::Size aPageSize( xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
128 fScale = aPageSize.Height/7000.0;
131 if( fScale>0 )
133 aSymbolSize.Height = static_cast<sal_Int32>( fScale * aSymbolSize.Height );
134 aSymbolSize.Width = aSymbolSize.Height;
137 xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::Any( aSymbolSize ));
140 void lcl_setSymbolSizeIfNeeded( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
142 if( !xSeriesOrPointProp.is() )
143 return;
145 sal_Int32 nSymbolType = chart::ChartSymbolType::NONE;
146 if( !(xSeriesOrPointProp.is() && ( xSeriesOrPointProp->getPropertyValue("SymbolType") >>= nSymbolType)) )
147 return;
149 if(chart::ChartSymbolType::NONE!=nSymbolType)
151 if( chart::ChartSymbolType::BITMAPURL==nSymbolType )
153 //set special size for graphics to indicate to use the bitmap size itself
154 xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::Any( awt::Size(-1,-1) ));
156 else
158 lcl_setAutomaticSymbolSize( xSeriesOrPointProp, rImport );
163 void lcl_resetSymbolSizeForPointsIfNecessary( const uno::Reference< beans::XPropertySet >& xPointProp, const SvXMLImport& rImport
164 , const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
166 uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize", pPropStyleContext, pStylesCtxt ) );
167 if( !aASymbolSize.hasValue() )
168 lcl_setSymbolSizeIfNeeded( xPointProp, rImport );
171 void lcl_setLinkNumberFormatToSourceIfNeeded( const uno::Reference< beans::XPropertySet >& xPointProp
172 , const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
174 uno::Any aAny( SchXMLTools::getPropertyFromContext(u"LinkNumberFormatToSource", pPropStyleContext, pStylesCtxt) );
175 if( aAny.hasValue() )
176 return;
178 if( !xPointProp.is() )
179 return;
181 bool bLinkToSource = false;
182 if( xPointProp.is() && (xPointProp->getPropertyValue("LinkNumberFormatToSource") >>= bLinkToSource) )
184 if( bLinkToSource )
186 xPointProp->setPropertyValue("LinkNumberFormatToSource", uno::Any(false));
191 void lcl_insertErrorBarLSequencesToMap(
192 tSchXMLLSequencesPerIndex & rInOutMap,
193 const uno::Reference< beans::XPropertySet > & xSeriesProp )
195 Reference< chart2::data::XDataSource > xErrorBarSource;
196 if( ( xSeriesProp->getPropertyValue( "ErrorBarY" ) >>= xErrorBarSource ) &&
197 xErrorBarSource.is() )
199 const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences(
200 xErrorBarSource->getDataSequences());
201 for( const auto& rLSequence : aLSequences )
203 // use "0" as data index. This is ok, as it is not used for error bars
204 rInOutMap.emplace(
205 tSchXMLIndexWithPart( 0, SCH_XML_PART_ERROR_BARS ), rLSequence );
210 Reference< chart2::data::XLabeledDataSequence2 > lcl_createAndAddSequenceToSeries( const OUString& rRole
211 , const OUString& rRange
212 , const Reference< chart2::XChartDocument >& xChartDoc
213 , const Reference< chart2::XDataSeries >& xSeries )
215 Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq;
217 Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY );
218 Reference< chart2::data::XDataSink > xSeriesSink( xSeries, uno::UNO_QUERY );
220 if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is() && xSeriesSink.is()) )
221 return xLabeledSeq;
223 // create a new sequence
224 xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence();
226 // set values at the new sequence
227 Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc );
228 Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY );
229 if( xSeqProp.is())
230 xSeqProp->setPropertyValue("Role", uno::Any( rRole));
231 xLabeledSeq->setValues( xSeq );
233 // add new sequence to data series / push to front to have the correct sequence order if charttype is changed afterwards
234 const Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeq( xSeriesSource->getDataSequences());
235 sal_Int32 nOldCount = aOldSeq.getLength();
236 Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeq( nOldCount + 1 );
237 auto pNewSeq = aNewSeq.getArray();
238 pNewSeq[0].set(xLabeledSeq, uno::UNO_QUERY_THROW);
239 std::copy(aOldSeq.begin(), aOldSeq.end(), std::next(pNewSeq));
240 xSeriesSink->setData( aNewSeq );
242 return xLabeledSeq;
245 XMLPropStyleContext* lcl_GetStylePropContext(
246 const SvXMLStylesContext* pStylesCtxt,
247 const SvXMLStyleContext*& rpStyle,
248 OUString const & rStyleName )
250 rpStyle = pStylesCtxt->FindStyleChildContext( SchXMLImportHelper::GetChartFamilyID(), rStyleName );
251 XMLPropStyleContext* pPropStyleContext =
252 const_cast< XMLPropStyleContext* >(dynamic_cast< const XMLPropStyleContext* >( rpStyle ));
253 return pPropStyleContext;
256 } // anonymous namespace
258 SchXMLSeries2Context::SchXMLSeries2Context(
259 SchXMLImportHelper& rImpHelper,
260 SvXMLImport& rImport,
261 const Reference< chart2::XChartDocument > & xNewDoc,
262 std::vector< SchXMLAxis >& rAxes,
263 ::std::vector< DataRowPointStyle >& rStyleVector,
264 ::std::vector< RegressionStyle >& rRegressionStyleVector,
265 sal_Int32 nSeriesIndex,
266 bool bStockHasVolume,
267 GlobalSeriesImportInfo& rGlobalSeriesImportInfo,
268 const OUString & aGlobalChartTypeName,
269 tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
270 bool& rGlobalChartTypeUsedBySeries,
271 const awt::Size & rChartSize ) :
272 SvXMLImportContext( rImport ),
273 mrImportHelper( rImpHelper ),
274 mxNewDoc( xNewDoc ),
275 mrAxes( rAxes ),
276 mrStyleVector( rStyleVector ),
277 mrRegressionStyleVector( rRegressionStyleVector ),
278 mnSeriesIndex( nSeriesIndex ),
279 mnDataPointIndex( 0 ),
280 m_bStockHasVolume( bStockHasVolume ),
281 m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo),
282 mpAttachedAxis( nullptr ),
283 mnAttachedAxis( 0 ),
284 maGlobalChartTypeName( aGlobalChartTypeName ),
285 maSeriesChartTypeName( aGlobalChartTypeName ),
286 m_bHasDomainContext(false),
287 mrLSequencesPerIndex( rLSequencesPerIndex ),
288 mrGlobalChartTypeUsedBySeries( rGlobalChartTypeUsedBySeries ),
289 mbSymbolSizeIsMissingInFile(false),
290 maChartSize( rChartSize ),
291 // A series manages the DataRowPointStyle-struct of a data-label child element.
292 mDataLabel(DataRowPointStyle::DATA_LABEL_SERIES, OUString{})
294 if( aGlobalChartTypeName == "com.sun.star.chart2.DonutChartType" )
296 maSeriesChartTypeName = "com.sun.star.chart2.PieChartType";
297 maGlobalChartTypeName = maSeriesChartTypeName;
301 SchXMLSeries2Context::~SchXMLSeries2Context()
303 SAL_WARN_IF( !maPostponedSequences.empty(), "xmloff.chart", "maPostponedSequences is NULL");
306 void SchXMLSeries2Context::startFastElement (sal_Int32 /*Element*/,
307 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
309 // parse attributes
310 mnAttachedAxis = 1;
312 bool bHasRange = false;
313 OUString aSeriesLabelRange;
314 OUString aSeriesLabelString;
315 bool bHideLegend = false;
317 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
319 OUString aValue = aIter.toString();
320 switch(aIter.getToken())
322 case XML_ELEMENT(CHART, XML_VALUES_CELL_RANGE_ADDRESS):
323 m_aSeriesRange = aValue;
324 bHasRange = true;
325 break;
326 case XML_ELEMENT(CHART, XML_LABEL_CELL_ADDRESS):
327 aSeriesLabelRange = aValue;
328 break;
329 case XML_ELEMENT(LO_EXT, XML_LABEL_STRING):
330 aSeriesLabelString = aValue;
331 break;
332 case XML_ELEMENT(CHART, XML_ATTACHED_AXIS):
334 sal_Int32 nNumOfAxes = mrAxes.size();
335 for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ )
337 if( aValue == mrAxes[ nCurrent ].aName &&
338 mrAxes[ nCurrent ].eDimension == SCH_XML_AXIS_Y )
340 mpAttachedAxis = &( mrAxes[ nCurrent ] );
344 break;
345 case XML_ELEMENT(CHART, XML_STYLE_NAME):
346 msAutoStyleName = aValue;
347 break;
348 case XML_ELEMENT(CHART, XML_CLASS):
350 OUString aClassName;
351 sal_uInt16 nClassPrefix =
352 GetImport().GetNamespaceMap().GetKeyByAttrValueQName(
353 aValue, &aClassName );
354 if( XML_NAMESPACE_CHART == nClassPrefix )
355 maSeriesChartTypeName = SchXMLTools::GetChartTypeByClassName( aClassName, false /* bUseOldNames */ );
357 if( maSeriesChartTypeName.isEmpty())
358 maSeriesChartTypeName = aClassName;
360 break;
361 case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND):
362 bHideLegend = aValue.toBoolean();
363 break;
364 default:
365 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
369 if( mpAttachedAxis )
371 if( mpAttachedAxis->nAxisIndex > 0 )
373 // secondary axis => property has to be set (primary is default)
374 mnAttachedAxis = 2;
380 SAL_WARN_IF( !mxNewDoc.is(), "xmloff.chart", "mxNewDoc is NULL");
381 if( m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && ! bHasRange )
382 m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable = false;
384 bool bIsCandleStick = maGlobalChartTypeName == "com.sun.star.chart2.CandleStickChartType";
385 if( !maSeriesChartTypeName.isEmpty() )
387 bIsCandleStick = maSeriesChartTypeName == "com.sun.star.chart2.CandleStickChartType";
389 else
391 if( bIsCandleStick
392 && m_bStockHasVolume
393 && mnSeriesIndex == 0 )
395 maSeriesChartTypeName = "com.sun.star.chart2.ColumnChartType";
396 bIsCandleStick = false;
398 else
400 maSeriesChartTypeName = maGlobalChartTypeName;
403 if( ! mrGlobalChartTypeUsedBySeries )
404 mrGlobalChartTypeUsedBySeries = (maSeriesChartTypeName == maGlobalChartTypeName);
405 sal_Int32 const nCoordinateSystemIndex = 0;//so far we can only import one coordinate system
406 m_xSeries.set(
407 SchXMLImportHelper::GetNewDataSeries( mxNewDoc, nCoordinateSystemIndex, maSeriesChartTypeName, ! mrGlobalChartTypeUsedBySeries ));
408 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( SchXMLTools::GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW );
410 Reference< beans::XPropertySet > xSeriesProp( m_xSeries, uno::UNO_QUERY );
411 if (xSeriesProp.is())
413 if (bHideLegend)
414 xSeriesProp->setPropertyValue("ShowLegendEntry", uno::Any(false));
416 if( bIsCandleStick )
418 // set default color for range-line to black (before applying styles)
419 xSeriesProp->setPropertyValue("Color",
420 uno::Any( sal_Int32( 0x000000 ))); // black
422 else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" )
424 //@todo: this property should be saved
425 xSeriesProp->setPropertyValue("VaryColorsByPoint",
426 uno::Any( true ));
431 Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider());
432 Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY);
434 Reference<chart2::data::XDataSequence> xSequenceValues;
436 // values
437 if (xPivotTableDataProvider.is()) // is pivot chart
439 xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex));
441 else
443 if (bHasRange && !m_aSeriesRange.isEmpty())
444 xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc);
447 Reference<beans::XPropertySet> xSeqProp(xSequenceValues, uno::UNO_QUERY);
448 if (xSeqProp.is())
450 OUString aMainRole("values-y");
451 if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType")
452 aMainRole = "values-size";
453 xSeqProp->setPropertyValue("Role", uno::Any(aMainRole));
455 xLabeledSeq->setValues(xSequenceValues);
457 // register for setting local data if external data provider is not present
458 maPostponedSequences.emplace(
459 tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq );
461 // label
462 Reference<chart2::data::XDataSequence> xSequenceLabel;
464 if (xPivotTableDataProvider.is())
466 xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex));
468 else
470 if (!aSeriesLabelRange.isEmpty())
472 xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc));
474 else if (!aSeriesLabelString.isEmpty())
476 xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc));
480 //Labels should always include hidden cells
481 Reference<beans::XPropertySet> xSeqLabelProp(xSequenceLabel, uno::UNO_QUERY);
482 if (xSeqLabelProp.is() && xSeqLabelProp->getPropertySetInfo()->hasPropertyByName("IncludeHiddenCells"))
484 xSeqLabelProp->setPropertyValue( "IncludeHiddenCells", uno::Any(true));
487 xLabeledSeq->setLabel(xSequenceLabel);
489 // Note: Even if we have no label, we have to register the label
490 // for creation, because internal data always has labels. If
491 // they don't exist in the original, auto-generated labels are
492 // used for the internal data.
493 maPostponedSequences.emplace(
494 tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_LABEL ), xLabeledSeq );
496 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( &xLabeledSeq, 1 );
497 Reference< chart2::data::XDataSink > xSink( m_xSeries, uno::UNO_QUERY_THROW );
498 xSink->setData( aSeq );
500 catch( const uno::Exception &)
502 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
505 //init mbSymbolSizeIsMissingInFile:
508 if( !msAutoStyleName.isEmpty() )
510 const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
511 if( pStylesCtxt )
513 const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
514 SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName );
516 const XMLPropStyleContext* pPropStyleContext = dynamic_cast< const XMLPropStyleContext * >( pStyle );
518 uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize"
519 , pPropStyleContext, pStylesCtxt ) );
520 mbSymbolSizeIsMissingInFile = !aASymbolSize.hasValue();
524 catch( const uno::Exception & )
529 namespace {
531 struct DomainInfo
533 DomainInfo( OUString _aRole, OUString _aRange, sal_Int32 nIndex )
534 : aRole(std::move(_aRole)), aRange(std::move(_aRange)), nIndexForLocalData(nIndex)
537 OUString aRole;
538 OUString aRange;
539 sal_Int32 nIndexForLocalData;
544 void SchXMLSeries2Context::endFastElement(sal_Int32 )
546 // special handling for different chart types. This is necessary as the
547 // roles are not yet saved in the file format
548 sal_Int32 nDomainCount = maDomainAddresses.size();
549 bool bIsScatterChart = maSeriesChartTypeName == "com.sun.star.chart2.ScatterChartType";
550 bool bIsBubbleChart = maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType";
551 bool bDeleteSeries = false;
552 std::vector< DomainInfo > aDomainInfos;
554 //different handling for different chart types necessary
555 if( bIsScatterChart || ( nDomainCount==1 && !bIsBubbleChart ) )
557 DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
558 bool bCreateXValues = true;
559 if( !maDomainAddresses.empty() )
561 if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
563 m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
564 m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
566 aDomainInfo.aRange = maDomainAddresses.front();
567 aDomainInfo.nIndexForLocalData = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
568 m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
570 else if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() && !m_bHasDomainContext && mnSeriesIndex==0 )
572 if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) //wrong old chart files:
574 //for xy charts the first series needs to have a domain
575 //if this by error iss not the case the first series is taken s x values
576 //needed for wrong files created while having an addin (e.g. BoxPlot)
577 m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = m_aSeriesRange;
578 m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
579 bDeleteSeries = true;
580 bCreateXValues = false;//they will be created for the next series
583 if( bCreateXValues )
584 aDomainInfos.push_back( aDomainInfo );
586 else if( bIsBubbleChart )
588 if( nDomainCount>1 )
590 DomainInfo aDomainInfo( "values-x", maDomainAddresses[1], m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
591 if( m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
593 //for bubble chart the second domain contains the x values which should become an index smaller than y values for own data table
594 //->so second first
595 m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress = maDomainAddresses[1];
596 m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
598 aDomainInfos.push_back( aDomainInfo );
599 m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
601 else if( !m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
603 DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ;
604 aDomainInfos.push_back( aDomainInfo );
606 if( nDomainCount>0)
608 DomainInfo aDomainInfo( "values-y", maDomainAddresses.front(), m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
609 if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
611 m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
612 m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
614 aDomainInfos.push_back( aDomainInfo );
615 m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
617 else if( !m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
619 DomainInfo aDomainInfo( "values-y", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
620 aDomainInfos.push_back( aDomainInfo );
624 if( bDeleteSeries )
626 //delete created series
627 SchXMLImportHelper::DeleteDataSeries(
628 m_xSeries, Reference< chart2::XChartDocument >( GetImport().GetModel(), uno::UNO_QUERY ) );
630 else
632 //add style
633 if( !msAutoStyleName.isEmpty() || mnAttachedAxis != 1 )
635 DataRowPointStyle aStyle(
636 DataRowPointStyle::DATA_SERIES,
637 m_xSeries,
638 -1, 1,
639 msAutoStyleName, mnAttachedAxis );
640 aStyle.mbSymbolSizeForSeriesIsMissingInFile=mbSymbolSizeIsMissingInFile;
641 mrStyleVector.push_back( aStyle );
643 // And styles for a data-label child element too. In contrast to data-labels as child of data points,
644 // an information about absolute position is useless here. We need only style information.
645 if (!mDataLabel.msStyleName.isEmpty())
647 mDataLabel.msStyleNameOfParent = msAutoStyleName;
648 mDataLabel.m_xSeries = m_xSeries;
649 mDataLabel.mnAttachedAxis = mnAttachedAxis; // not needed, but be consistent with its parent
650 mrStyleVector.push_back(mDataLabel);
654 for( std::vector< DomainInfo >::reverse_iterator aIt( aDomainInfos.rbegin() ); aIt!= aDomainInfos.rend(); ++aIt )
656 DomainInfo aDomainInfo( *aIt );
657 Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq =
658 lcl_createAndAddSequenceToSeries( aDomainInfo.aRole, aDomainInfo.aRange, mxNewDoc, m_xSeries );
659 if( xLabeledSeq.is() )
661 // register for setting local data if external data provider is not present
662 mrLSequencesPerIndex.emplace(
663 tSchXMLIndexWithPart( aDomainInfo.nIndexForLocalData, SCH_XML_PART_VALUES ),
664 Reference< chart2::data::XLabeledDataSequence >(xLabeledSeq, uno::UNO_QUERY_THROW) );
668 if( !bDeleteSeries )
670 for (auto const& postponedSequence : maPostponedSequences)
672 sal_Int32 nNewIndex = postponedSequence.first.first + nDomainCount;
673 mrLSequencesPerIndex.emplace( tSchXMLIndexWithPart( nNewIndex, postponedSequence.first.second ), postponedSequence.second );
675 m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
677 maPostponedSequences.clear();
680 css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLSeries2Context::createFastChildContext(
681 sal_Int32 nElement,
682 const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
684 SvXMLImportContext* pContext = nullptr;
686 switch(nElement)
688 case XML_ELEMENT(CHART, XML_DOMAIN):
689 if( m_xSeries.is())
691 m_bHasDomainContext = true;
692 pContext = new SchXMLDomain2Context(
693 GetImport(), maDomainAddresses );
695 break;
697 case XML_ELEMENT(CHART, XML_MEAN_VALUE):
698 pContext = new SchXMLStatisticsObjectContext(
699 mrImportHelper, GetImport(),
700 msAutoStyleName,
701 mrStyleVector, m_xSeries,
702 SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE,
703 mrLSequencesPerIndex );
704 break;
705 case XML_ELEMENT(CHART, XML_REGRESSION_CURVE):
706 pContext = new SchXMLRegressionCurveObjectContext(
707 mrImportHelper, GetImport(),
708 mrRegressionStyleVector,
709 m_xSeries, maChartSize );
710 break;
711 case XML_ELEMENT(CHART, XML_ERROR_INDICATOR):
712 pContext = new SchXMLStatisticsObjectContext(
713 mrImportHelper, GetImport(),
714 msAutoStyleName,
715 mrStyleVector, m_xSeries,
716 SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR,
717 mrLSequencesPerIndex );
718 break;
720 case XML_ELEMENT(CHART, XML_DATA_POINT):
721 pContext = new SchXMLDataPointContext( GetImport(),
722 mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile );
723 break;
724 case XML_ELEMENT(CHART, XML_DATA_LABEL):
725 // CustomLabels are useless for a data label element as child of a series, because it serves as default
726 // for all data labels. But the ctor expects it, so use that of the mDataLabel struct as ersatz.
727 pContext = new SchXMLDataLabelContext(GetImport(), mDataLabel.mCustomLabels,
728 mDataLabel);
729 break;
731 case XML_ELEMENT(LO_EXT, XML_PROPERTY_MAPPING):
732 pContext = new SchXMLPropertyMappingContext(
733 GetImport(),
734 mrLSequencesPerIndex, m_xSeries );
735 break;
736 default:
737 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
740 return pContext;
743 //static
744 void SchXMLSeries2Context::initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
745 , const uno::Reference< frame::XModel >& xChartModel )
747 // iterate over series first and remind propertysets in map
748 // new api <-> old api wrapper
749 ::std::map< Reference< chart2::XDataSeries >, Reference< beans::XPropertySet > > aSeriesMap;
750 for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
752 if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
753 continue;
755 if( !seriesStyle.m_xOldAPISeries.is() )
756 seriesStyle.m_xOldAPISeries = SchXMLSeriesHelper::createOldAPISeriesPropertySet( seriesStyle.m_xSeries, xChartModel );
758 aSeriesMap[seriesStyle.m_xSeries] = seriesStyle.m_xOldAPISeries;
762 //initialize m_xOldAPISeries for all other styles also
763 for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
765 if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES )
766 continue;
767 seriesStyle.m_xOldAPISeries = aSeriesMap[seriesStyle.m_xSeries];
771 //static
772 void SchXMLSeries2Context::setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles )
774 // iterate over series
775 // call initSeriesPropertySets first
777 for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
779 if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
780 continue;
784 uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
785 if( !xSeries.is() )
786 continue;
788 if( rSeriesDefaultsAndStyles.maSymbolTypeDefault.hasValue() )
789 xSeries->setPropertyValue("SymbolType",rSeriesDefaultsAndStyles.maSymbolTypeDefault);
790 if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() )
791 xSeries->setPropertyValue("DataCaption",rSeriesDefaultsAndStyles.maDataCaptionDefault);
793 if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() )
794 xSeries->setPropertyValue("ErrorIndicator",rSeriesDefaultsAndStyles.maErrorIndicatorDefault);
795 if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() )
796 xSeries->setPropertyValue("ErrorCategory",rSeriesDefaultsAndStyles.maErrorCategoryDefault);
797 if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() )
798 xSeries->setPropertyValue("ConstantErrorLow",rSeriesDefaultsAndStyles.maConstantErrorLowDefault);
799 if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() )
800 xSeries->setPropertyValue("ConstantErrorHigh",rSeriesDefaultsAndStyles.maConstantErrorHighDefault);
801 if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() )
802 xSeries->setPropertyValue("PercentageError",rSeriesDefaultsAndStyles.maPercentageErrorDefault);
803 if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() )
804 xSeries->setPropertyValue("ErrorMargin",rSeriesDefaultsAndStyles.maErrorMarginDefault);
806 if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() )
807 xSeries->setPropertyValue("MeanValue",rSeriesDefaultsAndStyles.maMeanValueDefault);
808 if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() )
809 xSeries->setPropertyValue("RegressionCurves",rSeriesDefaultsAndStyles.maRegressionCurvesDefault);
811 catch( uno::Exception & )
813 //end of series reached
818 // ODF has the line and fill properties in a <style:style> element, which is referenced by the
819 // <chart:data-label> element. But LibreOffice has them as special label properties of the series
820 // or point respectively. The following array maps the API name of the ODF property to the name of
821 // the internal property. Those are of kind "LabelFoo".
822 // The array is used in methods setStylesToSeries and setStylesToDataPoints.
823 const std::pair<OUString, OUString> aApiToLabelFooPairs[]
824 = { { "LineStyle", "LabelBorderStyle" },
825 { "LineWidth", "LabelBorderWidth" },
826 { "LineColor", "LabelBorderColor" },
827 // The name "LabelBorderDash" is defined, but the associated API name "LineDash" belongs to
828 // the <draw:stroke-dash> element and is not used directly as line property.
829 //{"LineDash", "LabelBorderDash"},
830 { "LineDashName", "LabelBorderDashName" },
831 { "LineTransparence", "LabelBorderTransparency" },
832 { "FillStyle", "LabelFillStyle" },
833 { "FillBackground", "LabelFillBackground" },
834 { "FillHatchName", "LabelFillHatchName" },
835 { "FillColor", "LabelFillColor" } };
838 //static
839 void SchXMLSeries2Context::setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
840 , const SvXMLStylesContext* pStylesCtxt
841 , const SvXMLStyleContext*& rpStyle
842 , OUString& rCurrStyleName
843 , const SchXMLImportHelper& rImportHelper
844 , const SvXMLImport& rImport
845 , bool bIsStockChart
846 , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex )
848 // iterate over series
849 for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
851 if (seriesStyle.meType != DataRowPointStyle::DATA_SERIES)
852 continue;
855 uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
856 if( !xSeriesProp.is() )
857 continue;
859 if( seriesStyle.mnAttachedAxis != 1 )
861 xSeriesProp->setPropertyValue("Axis"
862 , uno::Any(chart::ChartAxisAssign::SECONDARY_Y) );
865 if( seriesStyle.msStyleName.isEmpty())
866 continue;
868 if( rCurrStyleName != seriesStyle.msStyleName )
870 rCurrStyleName = seriesStyle.msStyleName;
871 rpStyle = pStylesCtxt->FindStyleChildContext(
872 SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
875 //set style to series
876 // note: SvXMLStyleContext::FillPropertySet is not const
877 XMLPropStyleContext * pPropStyleContext =
878 const_cast< XMLPropStyleContext * >(
879 dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
881 if (!pPropStyleContext)
882 continue;
884 // error bar style must be set before the other error
885 // bar properties (which may be alphabetically before
886 // this property)
887 bool bHasErrorBarRangesFromData = false;
889 static constexpr OUString aErrorBarStylePropName( u"ErrorBarStyle"_ustr);
890 uno::Any aErrorBarStyle(
891 SchXMLTools::getPropertyFromContext( aErrorBarStylePropName, pPropStyleContext, pStylesCtxt ));
892 if( aErrorBarStyle.hasValue())
894 xSeriesProp->setPropertyValue( aErrorBarStylePropName, aErrorBarStyle );
895 sal_Int32 eEBStyle = chart::ErrorBarStyle::NONE;
896 bHasErrorBarRangesFromData =
897 ( ( aErrorBarStyle >>= eEBStyle ) &&
898 eEBStyle == chart::ErrorBarStyle::FROM_DATA );
902 //don't set the style to the min max line series of a stock chart
903 //otherwise the min max line properties gets overwritten and the series becomes invisible typically
904 if (bIsStockChart)
906 if (SchXMLSeriesHelper::isCandleStickSeries(
907 seriesStyle.m_xSeries,
908 rImportHelper.GetChartDocument()))
909 continue;
912 // Has the series a data-label child element?
913 auto pItLabel
914 = std::find_if(rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
915 rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
916 [&seriesStyle](const DataRowPointStyle& rStyle) {
917 return rStyle.meType == DataRowPointStyle::DATA_LABEL_SERIES
918 && rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
920 if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
922 // Bring the information from the data-label to the series
923 const SvXMLStyleContext* pLabelStyleContext(pStylesCtxt->FindStyleChildContext(
924 SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
925 // note: SvXMLStyleContext::FillPropertySet is not const
926 XMLPropStyleContext* pLabelPropStyleContext = const_cast<XMLPropStyleContext*>(
927 dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
928 if (pLabelPropStyleContext)
930 // Test each to be mapped property whether the data-label has a value for it.
931 // If found, set it at series.
932 uno::Reference<beans::XPropertySetInfo> xSeriesPropInfo(
933 xSeriesProp->getPropertySetInfo());
934 for (const auto& rPropPair : aApiToLabelFooPairs)
936 uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
937 rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
938 if (aPropValue.hasValue()
939 && xSeriesPropInfo->hasPropertyByName(rPropPair.second))
940 xSeriesProp->setPropertyValue(rPropPair.second, aPropValue);
945 pPropStyleContext->FillPropertySet( xSeriesProp );
946 if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
947 lcl_setSymbolSizeIfNeeded( xSeriesProp, rImport );
948 if( bHasErrorBarRangesFromData )
949 lcl_insertErrorBarLSequencesToMap( rInOutLSequencesPerIndex, xSeriesProp );
952 catch( const uno::Exception & )
954 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
959 // static
960 void SchXMLSeries2Context::setStylesToRegressionCurves(
961 SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles,
962 const SvXMLStylesContext* pStylesCtxt,
963 const SvXMLStyleContext*& rpStyle,
964 OUString const & rCurrentStyleName )
966 // iterate over regression etc
967 for (auto const& regressionStyle : rSeriesDefaultsAndStyles.maRegressionStyleVector)
971 OUString aServiceName;
972 XMLPropStyleContext* pPropStyleContext = nullptr;
974 if (!rCurrentStyleName.isEmpty())
976 XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, rCurrentStyleName);
977 if( pCurrent )
979 pPropStyleContext = pCurrent;
980 uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
981 if ( aAny.hasValue() )
983 aAny >>= aServiceName;
988 if (!regressionStyle.msStyleName.isEmpty())
990 XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, regressionStyle.msStyleName);
991 if( pCurrent )
993 pPropStyleContext = pCurrent;
994 uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
995 if ( aAny.hasValue() )
997 aAny >>= aServiceName;
1002 if( !aServiceName.isEmpty() )
1004 Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory();
1005 Reference< chart2::XRegressionCurve > xRegCurve( xMSF->createInstance( aServiceName ), uno::UNO_QUERY_THROW );
1006 Reference< chart2::XRegressionCurveContainer > xRegCurveCont( regressionStyle.m_xSeries, uno::UNO_QUERY_THROW );
1008 Reference< beans::XPropertySet > xCurveProperties( xRegCurve, uno::UNO_QUERY );
1009 if( pPropStyleContext != nullptr)
1010 pPropStyleContext->FillPropertySet( xCurveProperties );
1012 xRegCurve->setEquationProperties( regressionStyle.m_xEquationProperties );
1014 xRegCurveCont->addRegressionCurve( xRegCurve );
1017 catch( const uno::Exception& )
1019 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
1025 // static
1026 void SchXMLSeries2Context::setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
1027 , const SvXMLStylesContext* pStylesCtxt
1028 , const SvXMLStyleContext*& rpStyle
1029 , OUString& rCurrStyleName )
1031 // iterate over regression etc
1032 for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
1034 if( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR ||
1035 seriesStyle.meType == DataRowPointStyle::MEAN_VALUE )
1037 if ( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR )
1039 uno::Reference< beans::XPropertySet > xNewSeriesProp(seriesStyle.m_xSeries,uno::UNO_QUERY);
1041 if (seriesStyle.m_xErrorXProperties.is())
1042 xNewSeriesProp->setPropertyValue("ErrorBarX",uno::Any(seriesStyle.m_xErrorXProperties));
1044 if (seriesStyle.m_xErrorYProperties.is())
1045 xNewSeriesProp->setPropertyValue("ErrorBarY",uno::Any(seriesStyle.m_xErrorYProperties));
1050 uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
1051 if( !xSeriesProp.is() )
1052 continue;
1054 if( !seriesStyle.msStyleName.isEmpty())
1056 if( rCurrStyleName != seriesStyle.msStyleName )
1058 rCurrStyleName = seriesStyle.msStyleName;
1059 rpStyle = pStylesCtxt->FindStyleChildContext(
1060 SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
1063 // note: SvXMLStyleContext::FillPropertySet is not const
1064 XMLPropStyleContext * pPropStyleContext =
1065 const_cast< XMLPropStyleContext * >(
1066 dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
1067 if( pPropStyleContext )
1069 Reference< beans::XPropertySet > xStatPropSet;
1070 switch( seriesStyle.meType )
1072 case DataRowPointStyle::MEAN_VALUE:
1073 xSeriesProp->getPropertyValue("DataMeanValueProperties") >>= xStatPropSet;
1074 break;
1075 case DataRowPointStyle::ERROR_INDICATOR:
1076 xSeriesProp->getPropertyValue("DataErrorProperties") >>= xStatPropSet;
1077 break;
1078 default:
1079 break;
1081 if( xStatPropSet.is())
1082 pPropStyleContext->FillPropertySet( xStatPropSet );
1086 catch( const uno::Exception & )
1088 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
1094 //static
1095 void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
1096 , const SvXMLStylesContext* pStylesCtxt
1097 , const SvXMLStyleContext*& rpStyle
1098 , OUString& rCurrStyleName
1099 , const SchXMLImportHelper& rImportHelper
1100 , const SvXMLImport& rImport
1101 , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter )
1103 for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
1105 if( seriesStyle.meType != DataRowPointStyle::DATA_POINT )
1106 continue;
1108 if( seriesStyle.m_nPointIndex == -1 )
1109 continue;
1111 uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
1112 if(!xSeriesProp.is())
1113 continue;
1115 //ignore datapoint properties for stock charts
1116 //... todo ...
1117 if( bIsStockChart )
1119 if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries, rImportHelper.GetChartDocument() ) )
1120 continue;
1123 // data point style
1124 for( sal_Int32 i = 0; i < seriesStyle.m_nPointRepeat; i++ )
1128 uno::Reference< beans::XPropertySet > xPointProp(
1129 SchXMLSeriesHelper::createOldAPIDataPointPropertySet( seriesStyle.m_xSeries, seriesStyle.m_nPointIndex + i
1130 , rImportHelper.GetChartDocument() ) );
1132 if( !xPointProp.is() )
1133 continue;
1135 if( bIsDonutChart )
1137 //set special series styles for donut charts first
1138 if( rCurrStyleName != seriesStyle.msSeriesStyleNameForDonuts )
1140 rCurrStyleName = seriesStyle.msSeriesStyleNameForDonuts;
1141 rpStyle = pStylesCtxt->FindStyleChildContext(
1142 SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
1145 // note: SvXMLStyleContext::FillPropertySet is not const
1146 XMLPropStyleContext * pPropStyleContext =
1147 const_cast< XMLPropStyleContext * >(
1148 dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
1149 if( pPropStyleContext )
1150 pPropStyleContext->FillPropertySet( xPointProp );
1155 //need to set this explicitly here for old files as the new api does not support this property fully anymore
1156 if( bSwitchOffLinesForScatter )
1157 xPointProp->setPropertyValue("Lines",uno::Any(false));
1159 catch( const uno::Exception & )
1163 if( rCurrStyleName != seriesStyle.msStyleName )
1165 rCurrStyleName = seriesStyle.msStyleName;
1166 rpStyle = pStylesCtxt->FindStyleChildContext(
1167 SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
1170 // note: SvXMLStyleContext::FillPropertySet is not const
1171 XMLPropStyleContext * pPropStyleContext =
1172 const_cast< XMLPropStyleContext * >(
1173 dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
1174 if (pPropStyleContext)
1176 // Has the point a data-label child element?
1177 auto pItLabel = std::find_if(
1178 rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
1179 rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
1180 [&seriesStyle](const DataRowPointStyle& rStyle) {
1181 return rStyle.meType == DataRowPointStyle::DATA_LABEL_POINT
1182 && rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
1184 if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
1186 // Bring the information from the data-label to the point
1187 const SvXMLStyleContext* pLabelStyleContext(
1188 pStylesCtxt->FindStyleChildContext(
1189 SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
1190 // note: SvXMLStyleContext::FillPropertySet is not const
1191 XMLPropStyleContext* pLabelPropStyleContext
1192 = const_cast<XMLPropStyleContext*>(
1193 dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
1194 if (pLabelPropStyleContext)
1196 // Test each to be mapped property whether the data-label has a value for it.
1197 // If found, set it at the point.
1198 uno::Reference<beans::XPropertySetInfo> xPointPropInfo(
1199 xPointProp->getPropertySetInfo());
1200 for (const auto& rPropPair : aApiToLabelFooPairs)
1202 uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
1203 rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
1204 if (aPropValue.hasValue()
1205 && xPointPropInfo->hasPropertyByName(rPropPair.second))
1206 xPointProp->setPropertyValue(rPropPair.second, aPropValue);
1211 pPropStyleContext->FillPropertySet( xPointProp );
1212 if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
1213 lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt );
1214 if( !pPropStyleContext->isEmptyDataStyleName() )
1215 lcl_setLinkNumberFormatToSourceIfNeeded( xPointProp, pPropStyleContext, pStylesCtxt );
1218 // Custom labels might be passed as property
1219 if(const size_t nLabelCount = seriesStyle.mCustomLabels.mLabels.size(); nLabelCount > 0)
1221 auto& rCustomLabels = seriesStyle.mCustomLabels;
1223 Sequence< Reference<chart2::XDataPointCustomLabelField>> xLabels(nLabelCount);
1224 auto pxLabels = xLabels.getArray();
1225 Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
1226 for( size_t j = 0; j < nLabelCount; ++j )
1228 Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext);
1229 pxLabels[j] = xCustomLabel;
1230 xCustomLabel->setString(rCustomLabels.mLabels[j]);
1231 if ( j == 0 && rCustomLabels.mbDataLabelsRange)
1233 xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE);
1234 xCustomLabel->setGuid(rCustomLabels.msLabelGuid);
1235 xCustomLabel->setCellRange(rCustomLabels.msLabelsCellRange);
1236 xCustomLabel->setDataLabelsRange(true);
1238 else
1240 xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT);
1243 // Restore character properties on the text span manually, till
1244 // SchXMLExportHelper_Impl::exportCustomLabel() does not write the style.
1245 uno::Reference<beans::XPropertySetInfo> xPointPropInfo
1246 = xPointProp->getPropertySetInfo();
1247 if (xPointPropInfo.is())
1249 uno::Sequence<beans::Property> aProperties = xPointPropInfo->getProperties();
1250 for (const auto& rProperty : std::as_const(aProperties))
1252 if (!rProperty.Name.startsWith("Char")
1253 || rProperty.Name.startsWith("Chart"))
1255 continue;
1258 xCustomLabel->setPropertyValue(
1259 rProperty.Name, xPointProp->getPropertyValue(rProperty.Name));
1264 xPointProp->setPropertyValue("CustomLabelFields", uno::Any(xLabels));
1265 xPointProp->setPropertyValue("DataCaption", uno::Any(chart::ChartDataCaption::CUSTOM));
1268 if( seriesStyle.mCustomLabelPos[0] != 0.0 || seriesStyle.mCustomLabelPos[1] != 0.0 )
1270 chart2::RelativePosition aCustomlabelPosition;
1271 aCustomlabelPosition.Primary = seriesStyle.mCustomLabelPos[0];
1272 aCustomlabelPosition.Secondary = seriesStyle.mCustomLabelPos[1];
1273 xPointProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomlabelPosition));
1276 catch( const uno::Exception & )
1278 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to data points" );
1281 } // styles iterator
1284 //static
1285 void SchXMLSeries2Context::switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector )
1287 // iterate over series
1288 for (auto const& seriesStyle : rSeriesStyleVector)
1290 if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
1291 continue;
1295 uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
1296 if( !xSeries.is() )
1297 continue;
1299 xSeries->setPropertyValue("Lines",uno::Any(false));
1301 catch( uno::Exception & )
1303 //end of series reached
1308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */