1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
70 class SchXMLDomain2Context
: public SvXMLImportContext
73 ::std::vector
< OUString
> & mrAddresses
;
76 SchXMLDomain2Context( SvXMLImport
& rImport
,
77 ::std::vector
< OUString
> & rAddresses
);
78 virtual void SAL_CALL
startFastElement(
80 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
) override
;
83 SchXMLDomain2Context::SchXMLDomain2Context(
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() );
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
);
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;
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;
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() )
145 sal_Int32 nSymbolType
= chart::ChartSymbolType::NONE
;
146 if( !(xSeriesOrPointProp
.is() && ( xSeriesOrPointProp
->getPropertyValue("SymbolType") >>= nSymbolType
)) )
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) ));
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() )
178 if( !xPointProp
.is() )
181 bool bLinkToSource
= false;
182 if( xPointProp
.is() && (xPointProp
->getPropertyValue("LinkNumberFormatToSource") >>= 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
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()) )
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
);
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
);
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
),
276 mrStyleVector( rStyleVector
),
277 mrRegressionStyleVector( rRegressionStyleVector
),
278 mnSeriesIndex( nSeriesIndex
),
279 mnDataPointIndex( 0 ),
280 m_bStockHasVolume( bStockHasVolume
),
281 m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo
),
282 mpAttachedAxis( nullptr ),
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
)
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
;
326 case XML_ELEMENT(CHART
, XML_LABEL_CELL_ADDRESS
):
327 aSeriesLabelRange
= aValue
;
329 case XML_ELEMENT(LO_EXT
, XML_LABEL_STRING
):
330 aSeriesLabelString
= aValue
;
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
] );
345 case XML_ELEMENT(CHART
, XML_STYLE_NAME
):
346 msAutoStyleName
= aValue
;
348 case XML_ELEMENT(CHART
, XML_CLASS
):
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
;
361 case XML_ELEMENT(LO_EXT
, XML_HIDE_LEGEND
):
362 bHideLegend
= aValue
.toBoolean();
365 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
371 if( mpAttachedAxis
->nAxisIndex
> 0 )
373 // secondary axis => property has to be set (primary is default)
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";
393 && mnSeriesIndex
== 0 )
395 maSeriesChartTypeName
= "com.sun.star.chart2.ColumnChartType";
396 bIsCandleStick
= false;
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
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())
414 xSeriesProp
->setPropertyValue("ShowLegendEntry", uno::Any(false));
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",
431 Reference
<chart2::data::XDataProvider
> xDataProvider(mxNewDoc
->getDataProvider());
432 Reference
<chart2::data::XPivotTableDataProvider
> xPivotTableDataProvider(xDataProvider
, uno::UNO_QUERY
);
434 Reference
<chart2::data::XDataSequence
> xSequenceValues
;
437 if (xPivotTableDataProvider
.is()) // is pivot chart
439 xSequenceValues
.set(xPivotTableDataProvider
->createDataSequenceOfValuesByIndex(mnSeriesIndex
));
443 if (bHasRange
&& !m_aSeriesRange
.isEmpty())
444 xSequenceValues
= SchXMLTools::CreateDataSequence(m_aSeriesRange
, mxNewDoc
);
447 Reference
<beans::XPropertySet
> xSeqProp(xSequenceValues
, uno::UNO_QUERY
);
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
);
462 Reference
<chart2::data::XDataSequence
> xSequenceLabel
;
464 if (xPivotTableDataProvider
.is())
466 xSequenceLabel
.set(xPivotTableDataProvider
->createDataSequenceOfLabelsByIndex(mnSeriesIndex
));
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();
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
& )
533 DomainInfo( OUString _aRole
, OUString _aRange
, sal_Int32 nIndex
)
534 : aRole(std::move(_aRole
)), aRange(std::move(_aRange
)), nIndexForLocalData(nIndex
)
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
584 aDomainInfos
.push_back( aDomainInfo
);
586 else if( bIsBubbleChart
)
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
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
);
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
);
626 //delete created series
627 SchXMLImportHelper::DeleteDataSeries(
628 m_xSeries
, Reference
< chart2::XChartDocument
>( GetImport().GetModel(), uno::UNO_QUERY
) );
633 if( !msAutoStyleName
.isEmpty() || mnAttachedAxis
!= 1 )
635 DataRowPointStyle
aStyle(
636 DataRowPointStyle::DATA_SERIES
,
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
) );
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(
682 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& )
684 SvXMLImportContext
* pContext
= nullptr;
688 case XML_ELEMENT(CHART
, XML_DOMAIN
):
691 m_bHasDomainContext
= true;
692 pContext
= new SchXMLDomain2Context(
693 GetImport(), maDomainAddresses
);
697 case XML_ELEMENT(CHART
, XML_MEAN_VALUE
):
698 pContext
= new SchXMLStatisticsObjectContext(
699 mrImportHelper
, GetImport(),
701 mrStyleVector
, m_xSeries
,
702 SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE
,
703 mrLSequencesPerIndex
);
705 case XML_ELEMENT(CHART
, XML_REGRESSION_CURVE
):
706 pContext
= new SchXMLRegressionCurveObjectContext(
707 mrImportHelper
, GetImport(),
708 mrRegressionStyleVector
,
709 m_xSeries
, maChartSize
);
711 case XML_ELEMENT(CHART
, XML_ERROR_INDICATOR
):
712 pContext
= new SchXMLStatisticsObjectContext(
713 mrImportHelper
, GetImport(),
715 mrStyleVector
, m_xSeries
,
716 SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR
,
717 mrLSequencesPerIndex
);
720 case XML_ELEMENT(CHART
, XML_DATA_POINT
):
721 pContext
= new SchXMLDataPointContext( GetImport(),
722 mrStyleVector
, m_xSeries
, mnDataPointIndex
, mbSymbolSizeIsMissingInFile
);
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
,
731 case XML_ELEMENT(LO_EXT
, XML_PROPERTY_MAPPING
):
732 pContext
= new SchXMLPropertyMappingContext(
734 mrLSequencesPerIndex
, m_xSeries
);
737 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
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
)
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
)
767 seriesStyle
.m_xOldAPISeries
= aSeriesMap
[seriesStyle
.m_xSeries
];
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
)
784 uno::Reference
< beans::XPropertySet
> xSeries( seriesStyle
.m_xOldAPISeries
);
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" } };
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
846 , tSchXMLLSequencesPerIndex
& rInOutLSequencesPerIndex
)
848 // iterate over series
849 for (const auto & seriesStyle
: rSeriesDefaultsAndStyles
.maSeriesStyleVector
)
851 if (seriesStyle
.meType
!= DataRowPointStyle::DATA_SERIES
)
855 uno::Reference
< beans::XPropertySet
> xSeriesProp( seriesStyle
.m_xOldAPISeries
);
856 if( !xSeriesProp
.is() )
859 if( seriesStyle
.mnAttachedAxis
!= 1 )
861 xSeriesProp
->setPropertyValue("Axis"
862 , uno::Any(chart::ChartAxisAssign::SECONDARY_Y
) );
865 if( seriesStyle
.msStyleName
.isEmpty())
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
)
884 // error bar style must be set before the other error
885 // bar properties (which may be alphabetically before
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
906 if (SchXMLSeriesHelper::isCandleStickSeries(
907 seriesStyle
.m_xSeries
,
908 rImportHelper
.GetChartDocument()))
912 // Has the series a data-label child element?
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" );
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
);
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
);
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" );
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() )
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
;
1075 case DataRowPointStyle::ERROR_INDICATOR
:
1076 xSeriesProp
->getPropertyValue("DataErrorProperties") >>= xStatPropSet
;
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" );
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
)
1108 if( seriesStyle
.m_nPointIndex
== -1 )
1111 uno::Reference
< beans::XPropertySet
> xSeriesProp( seriesStyle
.m_xOldAPISeries
);
1112 if(!xSeriesProp
.is())
1115 //ignore datapoint properties for stock charts
1119 if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle
.m_xSeries
, rImportHelper
.GetChartDocument() ) )
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() )
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);
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"))
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
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
)
1295 uno::Reference
< beans::XPropertySet
> xSeries( seriesStyle
.m_xOldAPISeries
);
1299 xSeries
->setPropertyValue("Lines",uno::Any(false));
1301 catch( uno::Exception
& )
1303 //end of series reached
1308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */