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 .
21 #include <sal/config.h>
22 #include <sal/log.hxx>
24 #include <sax/tools/converter.hxx>
27 #include <xmloff/xmlprmap.hxx>
29 #include <SchXMLExport.hxx>
30 #include <XMLChartPropertySetMapper.hxx>
31 #include "ColorPropertySet.hxx"
32 #include "SchXMLTools.hxx"
33 #include "SchXMLEnumConverter.hxx"
35 #include <comphelper/processfactory.hxx>
36 #include <tools/globname.hxx>
37 #include <comphelper/classids.hxx>
38 #include <comphelper/sequence.hxx>
40 #include <xmloff/namespacemap.hxx>
41 #include <xmloff/xmlnamespace.hxx>
42 #include <xmloff/xmltoken.hxx>
43 #include <xmloff/families.hxx>
44 #include <xmloff/xmlaustp.hxx>
45 #include <xmloff/xmluconv.hxx>
46 #include <xmloff/SchXMLSeriesHelper.hxx>
47 #include <rtl/math.hxx>
48 #include <o3tl/sorted_vector.hxx>
49 #include <o3tl/string_view.hxx>
58 #include <com/sun/star/lang/XServiceInfo.hpp>
59 #include <com/sun/star/lang/XServiceName.hpp>
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <com/sun/star/uno/XComponentContext.hpp>
62 #include <com/sun/star/util/XRefreshable.hpp>
64 #include <com/sun/star/chart/XAxis.hpp>
65 #include <com/sun/star/chart/XAxisSupplier.hpp>
66 #include <com/sun/star/chart/XChartDocument.hpp>
67 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
68 #include <com/sun/star/chart/ChartDataRowSource.hpp>
69 #include <com/sun/star/chart/ChartAxisAssign.hpp>
70 #include <com/sun/star/chart/DataLabelPlacement.hpp>
71 #include <com/sun/star/chart/TimeIncrement.hpp>
72 #include <com/sun/star/chart/TimeInterval.hpp>
73 #include <com/sun/star/chart/TimeUnit.hpp>
74 #include <com/sun/star/chart/X3DDisplay.hpp>
75 #include <com/sun/star/chart/XStatisticDisplay.hpp>
76 #include <com/sun/star/chart/XDiagramPositioning.hpp>
78 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
79 #include <com/sun/star/chart2/AxisType.hpp>
80 #include <com/sun/star/chart2/XChartDocument.hpp>
81 #include <com/sun/star/chart2/XDiagram.hpp>
82 #include <com/sun/star/chart2/RelativePosition.hpp>
83 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
84 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
85 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
86 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
87 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
88 #include <com/sun/star/chart2/data/XDataSource.hpp>
89 #include <com/sun/star/chart2/data/XDataSink.hpp>
90 #include <com/sun/star/chart2/data/XDataProvider.hpp>
91 #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
92 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
93 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
94 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
95 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
97 #include <com/sun/star/util/MeasureUnit.hpp>
98 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
99 #include <com/sun/star/drawing/XShapes.hpp>
100 #include <com/sun/star/embed/Aspects.hpp>
101 #include <com/sun/star/embed/XVisualObject.hpp>
102 #include <com/sun/star/container/XChild.hpp>
104 #include <comphelper/diagnose_ex.hxx>
105 #include "MultiPropertySetHandler.hxx"
106 #include "PropertyMap.hxx"
108 using namespace com::sun::star
;
109 using namespace ::xmloff::token
;
111 using ::com::sun::star::uno::Sequence
;
112 using ::com::sun::star::uno::Reference
;
113 using ::com::sun::star::uno::Any
;
120 * Used to store a data point custom-label's fields and also the helper members that
121 * indicates whether this label's contents are sourced from a cell[range] and
122 * the address of the cell[range] with guid of the CELLRANGE field.
124 struct CustomLabelData
127 mbDataLabelsRange( false )
132 Sequence
<Reference
<chart2::XDataPointCustomLabelField
>> maFields
;
133 /// Are label's contents sourced from a cell[range] ?
134 bool mbDataLabelsRange
;
135 /// cell[range] from which label's contents are sourced.
137 /// GUID of the CELLRANGE field.
141 struct SchXMLDataPointStruct
143 OUString maStyleName
;
145 chart2::RelativePosition mCustomLabelPos
; // loext:custom-label-pos-x and -y
147 // There is no internal equivalent for <chart:data-label>. It will be generated on the fly
148 // on export. All about data label is hold in the data point.
149 CustomLabelData mCustomLabel
; // <text:p> child element in <chart:data-label>
150 OUString msDataLabelStyleName
; // chart:style-name attribute in <chart:data-label>
152 SchXMLDataPointStruct() : mnRepeat( 1 ) {}
157 class SchXMLExportHelper_Impl
160 // first: data sequence for label, second: data sequence for values.
161 typedef ::std::pair
< css::uno::Reference
< css::chart2::data::XDataSequence
>,
162 css::uno::Reference
< css::chart2::data::XDataSequence
> > tLabelValuesDataPair
;
163 typedef ::std::vector
< tLabelValuesDataPair
> tDataSequenceCont
;
166 SchXMLExportHelper_Impl( SvXMLExport
& rExport
,
167 SvXMLAutoStylePoolP
& rASPool
);
169 SchXMLExportHelper_Impl(const SchXMLExportHelper_Impl
&) = delete;
170 SchXMLExportHelper_Impl
& operator=(const SchXMLExportHelper_Impl
&) = delete;
173 /// parse chart and collect all auto-styles used in current pool
174 void collectAutoStyles( css::uno::Reference
< css::chart::XChartDocument
> const & rChartDoc
);
176 /// write the styles collected into the current pool as <style:style> elements
177 void exportAutoStyles();
179 /** export the <chart:chart> element corresponding to rChartDoc
180 if bIncludeTable is true, the chart data is exported as <table:table>
181 element (inside the chart element).
183 Otherwise the external references stored in the chart document are used
184 for writing the corresponding attributes at series
186 All attributes contained in xAttrList are written at the chart element,
187 which is the outer element of a chart. So these attributes can easily
188 be parsed again by the container
190 void exportChart( css::uno::Reference
< css::chart::XChartDocument
> const & rChartDoc
,
191 bool bIncludeTable
);
193 const rtl::Reference
<XMLPropertySetMapper
>& GetPropertySetMapper() const;
195 void SetChartRangeAddress( const OUString
& rAddress
)
196 { msChartAddress
= rAddress
; }
198 void InitRangeSegmentationProperties(
199 const css::uno::Reference
< css::chart2::XChartDocument
> & xChartDoc
);
201 static css::awt::Size
getPageSize(
202 const css::uno::Reference
< css::chart2::XChartDocument
> & xChartDoc
);
204 /** first parseDocument: collect autostyles and store names in this queue
205 second parseDocument: export content and use names from this queue
207 ::std::queue
< OUString
> maAutoStyleNameQueue
;
208 void CollectAutoStyle(
209 std::vector
< XMLPropertyState
>&& aStates
);
210 void AddAutoStyleAttribute(
211 const std::vector
< XMLPropertyState
>& aStates
);
213 /// if bExportContent is false the auto-styles are collected
214 void parseDocument( css::uno::Reference
< css::chart::XChartDocument
> const & rChartDoc
,
216 bool bIncludeTable
= false );
219 const css::uno::Reference
< css::chart::XDiagram
>& xDiagram
,
220 const css::uno::Reference
< css::chart2::XDiagram
>& xNewDiagram
,
221 const css::awt::Size
& rPageSize
,
223 bool bIncludeTable
);
224 void exportCoordinateRegion( const css::uno::Reference
< css::chart::XDiagram
>& xDiagram
);
225 void exportAxes( const css::uno::Reference
< css::chart::XDiagram
> & xDiagram
,
226 const css::uno::Reference
< css::chart2::XDiagram
> & xNewDiagram
,
227 bool bExportContent
);
228 void exportAxis( enum XMLTokenEnum eDimension
, enum XMLTokenEnum eAxisName
,
229 const Reference
< beans::XPropertySet
>& rAxisProps
, const Reference
< chart2::XAxis
>& rChart2Axis
,
230 const OUString
& rCategoriesRanges
,
231 bool bHasTitle
, bool bHasMajorGrid
, bool bHasMinorGrid
, bool bExportContent
, std::u16string_view sChartType
);
232 void exportGrid( const Reference
< beans::XPropertySet
>& rGridProperties
, bool bMajor
, bool bExportContent
);
233 void exportDateScale( const Reference
< beans::XPropertySet
>& rAxisProps
);
234 void exportAxisTitle( const Reference
< beans::XPropertySet
>& rTitleProps
, bool bExportContent
);
237 const css::uno::Reference
< css::chart2::XDiagram
> & xNewDiagram
,
238 const css::awt::Size
& rPageSize
,
242 void exportPropertyMapping(
243 const css::uno::Reference
< css::chart2::data::XDataSource
> & xSource
,
244 const Sequence
< OUString
>& rSupportedMappings
);
246 void exportCandleStickSeries(
247 const css::uno::Sequence
<
248 css::uno::Reference
< css::chart2::XDataSeries
> > & aSeriesSeq
,
249 const css::uno::Reference
< css::chart2::XDiagram
> & xDiagram
,
250 bool bJapaneseCandleSticks
,
251 bool bExportContent
);
252 void exportDataPoints(
253 const css::uno::Reference
< css::beans::XPropertySet
> & xSeriesProperties
,
254 sal_Int32 nSeriesLength
,
255 const css::uno::Reference
< css::chart2::XDiagram
> & xDiagram
,
256 bool bExportContent
);
258 void exportCustomLabel(const SchXMLDataPointStruct
& rPoint
);
259 void exportCustomLabelPosition(const chart2::RelativePosition
& xCustomLabelPosition
);
261 void exportRegressionCurve(
262 const css::uno::Reference
<css::chart2::XDataSeries
>& xSeries
,
263 const css::awt::Size
& rPageSize
,
264 bool bExportContent
);
266 void exportErrorBar (
267 const css::uno::Reference
<beans::XPropertySet
> &xSeriesProp
, bool bYError
,
268 bool bExportContent
);
270 /// add svg position as attribute for current element
271 void addPosition( const css::awt::Point
& rPosition
);
272 void addPosition( const css::uno::Reference
< css::drawing::XShape
>& xShape
);
273 /// add svg size as attribute for current element
274 void addSize( const css::awt::Size
& rSize
, bool bIsOOoNamespace
= false );
275 void addSize( const css::uno::Reference
< css::drawing::XShape
>& xShape
);
276 /// exports a string as a paragraph element
277 void exportText( const OUString
& rText
);
280 SvXMLExport
& mrExport
;
281 SvXMLAutoStylePoolP
& mrAutoStylePool
;
282 rtl::Reference
< XMLPropertySetMapper
> mxPropertySetMapper
;
283 rtl::Reference
< XMLChartExportPropertyMapper
> mxExpPropMapper
;
285 static constexpr OUString gsTableName
= u
"local-table"_ustr
;
286 OUStringBuffer msStringBuffer
;
289 // members filled by InitRangeSegmentationProperties (retrieved from DataProvider)
290 bool mbHasCategoryLabels
; //if the categories are only automatically generated this will be false
291 bool mbRowSourceColumns
;
292 OUString msChartAddress
;
293 css::uno::Sequence
< sal_Int32
> maSequenceMapping
;
297 OUString maSrcShellID
;
298 OUString maDestShellID
;
300 css::uno::Reference
< css::drawing::XShapes
> mxAdditionalShapes
;
302 tDataSequenceCont m_aDataSequencesToExport
;
303 OUString maCategoriesRange
;
308 CustomLabelData
lcl_getCustomLabelField(SvXMLExport
const& rExport
,
309 sal_Int32 nDataPointIndex
,
310 const uno::Reference
< chart2::XDataSeries
>& rSeries
)
313 return CustomLabelData();
315 // Custom data label text will be written to the <text:p> child element of a
316 // <chart:data-label> element. That exists only since ODF 1.2.
317 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
318 rExport
.getSaneDefaultVersion());
319 if (nCurrentODFVersion
< SvtSaveOptions::ODFSVER_012
)
320 return CustomLabelData();
322 if(Reference
<beans::XPropertySet
> xLabels
= rSeries
->getDataPointByIndex(nDataPointIndex
); xLabels
.is())
324 if(Any aAny
= xLabels
->getPropertyValue("CustomLabelFields"); aAny
.hasValue())
326 CustomLabelData aData
;
327 Sequence
<uno::Reference
<chart2::XDataPointCustomLabelField
>> aCustomLabels
;
328 aAny
>>= aCustomLabels
;
329 for (const auto& rField
: std::as_const(aCustomLabels
))
331 if (rField
->getFieldType() == chart2::DataPointCustomLabelFieldType_CELLRANGE
)
333 if (rField
->getDataLabelsRange())
334 aData
.mbDataLabelsRange
= true;
335 aData
.maRange
= rField
->getCellRange();
336 aData
.maGuid
= rField
->getGuid();
340 aData
.maFields
= aCustomLabels
;
344 return CustomLabelData();
347 css::chart2::RelativePosition
lcl_getCustomLabelPosition(
348 SvXMLExport
const& rExport
,
349 sal_Int32
const nDataPointIndex
,
350 const uno::Reference
< chart2::XDataSeries
>& rSeries
)
353 return chart2::RelativePosition();
355 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
356 rExport
.getSaneDefaultVersion());
358 if ((nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) == 0) // do not export to ODF 1.3 or older
359 return chart2::RelativePosition();
361 if (Reference
<beans::XPropertySet
> xLabels
= rSeries
->getDataPointByIndex(nDataPointIndex
); xLabels
.is())
363 if (Any aAny
= xLabels
->getPropertyValue("CustomLabelPosition"); aAny
.hasValue())
365 chart2::RelativePosition aCustomLabelPos
;
366 aAny
>>= aCustomLabelPos
;
367 return aCustomLabelPos
;
370 return chart2::RelativePosition();
373 class lcl_MatchesRole
376 explicit lcl_MatchesRole( OUString aRole
) :
377 m_aRole(std::move( aRole
))
380 bool operator () ( const Reference
< chart2::data::XLabeledDataSequence
> & xSeq
) const
384 Reference
< beans::XPropertySet
> xProp( xSeq
->getValues(), uno::UNO_QUERY
);
387 return ( xProp
.is() &&
388 (xProp
->getPropertyValue( "Role" ) >>= aRole
) &&
396 Reference
< chart2::data::XLabeledDataSequence
> lcl_getCategories( const Reference
< chart2::XDiagram
> & xDiagram
)
398 Reference
< chart2::data::XLabeledDataSequence
> xResult
;
401 Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt(
402 xDiagram
, uno::UNO_QUERY_THROW
);
403 const Sequence
< Reference
< chart2::XCoordinateSystem
> > aCooSysSeq(
404 xCooSysCnt
->getCoordinateSystems());
405 for( const auto& rCooSys
: aCooSysSeq
)
407 Reference
< chart2::XCoordinateSystem
> xCooSys( rCooSys
);
408 SAL_WARN_IF( !xCooSys
.is(), "xmloff.chart", "xCooSys is NULL" );
409 for( sal_Int32 nN
= xCooSys
->getDimension(); nN
--; )
411 const sal_Int32 nMaxAxisIndex
= xCooSys
->getMaximumAxisIndexByDimension(nN
);
412 for(sal_Int32 nI
=0; nI
<=nMaxAxisIndex
; ++nI
)
414 Reference
< chart2::XAxis
> xAxis
= xCooSys
->getAxisByDimension( nN
, nI
);
415 SAL_WARN_IF( !xAxis
.is(), "xmloff.chart", "xAxis is NULL");
418 chart2::ScaleData aScaleData
= xAxis
->getScaleData();
419 if( aScaleData
.Categories
.is())
421 xResult
.set( aScaleData
.Categories
);
429 catch( const uno::Exception
& )
431 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
437 Reference
< chart2::data::XDataSource
> lcl_createDataSource(
438 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > & aData
)
440 Reference
< uno::XComponentContext
> xContext(
441 comphelper::getProcessComponentContext() );
442 Reference
< chart2::data::XDataSink
> xSink(
443 xContext
->getServiceManager()->createInstanceWithContext(
444 "com.sun.star.chart2.data.DataSource", xContext
),
445 uno::UNO_QUERY_THROW
);
446 xSink
->setData( aData
);
448 return Reference
< chart2::data::XDataSource
>( xSink
, uno::UNO_QUERY
);
451 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > lcl_getAllSeriesSequences( const Reference
< chart2::XChartDocument
>& xChartDoc
)
453 ::std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aContainer
;
456 Reference
< chart2::XDiagram
> xDiagram( xChartDoc
->getFirstDiagram());
457 ::std::vector
< Reference
< chart2::XDataSeries
> > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram
));
458 for( const auto& rSeries
: aSeriesVector
)
460 Reference
< chart2::data::XDataSource
> xDataSource( rSeries
, uno::UNO_QUERY
);
461 if( !xDataSource
.is() )
463 const uno::Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aDataSequences( xDataSource
->getDataSequences() );
464 aContainer
.insert( aContainer
.end(), aDataSequences
.begin(), aDataSequences
.end() );
468 return comphelper::containerToSequence( aContainer
);
471 Reference
< chart2::data::XLabeledDataSequence
>
472 lcl_getDataSequenceByRole(
473 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > & aLabeledSeq
,
474 const OUString
& rRole
)
476 Reference
< chart2::data::XLabeledDataSequence
> aNoResult
;
478 const Reference
< chart2::data::XLabeledDataSequence
> * pBegin
= aLabeledSeq
.getConstArray();
479 const Reference
< chart2::data::XLabeledDataSequence
> * pEnd
= pBegin
+ aLabeledSeq
.getLength();
480 const Reference
< chart2::data::XLabeledDataSequence
> * pMatch
=
481 ::std::find_if( pBegin
, pEnd
, lcl_MatchesRole( rRole
));
489 Reference
< chart2::data::XDataSource
> lcl_pressUsedDataIntoRectangularFormat( const Reference
< chart2::XChartDocument
>& xChartDoc
, bool& rOutSourceHasCategoryLabels
)
491 ::std::vector
< Reference
< chart2::data::XLabeledDataSequence
> > aLabeledSeqVector
;
493 //categories are always the first sequence
494 Reference
< chart2::XDiagram
> xDiagram( xChartDoc
->getFirstDiagram());
495 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( xDiagram
) );
496 if( xCategories
.is() )
497 aLabeledSeqVector
.push_back( xCategories
);
498 rOutSourceHasCategoryLabels
= xCategories
.is();
500 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeriesSeqVector(
501 lcl_getAllSeriesSequences( xChartDoc
) );
503 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
504 Reference
< chart2::data::XLabeledDataSequence
> xXValues(
505 lcl_getDataSequenceByRole( aSeriesSeqVector
, "values-x" ) );
507 aLabeledSeqVector
.push_back( xXValues
);
509 //add all other sequences now without x-values
510 lcl_MatchesRole
aHasXValues( "values-x" );
511 std::copy_if(aSeriesSeqVector
.begin(), aSeriesSeqVector
.end(), std::back_inserter(aLabeledSeqVector
),
512 [&aHasXValues
](const auto& rSeriesSeq
) { return !aHasXValues( rSeriesSeq
); });
514 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeq( comphelper::containerToSequence(aLabeledSeqVector
) );
516 return lcl_createDataSource( aSeq
);
519 bool lcl_isSeriesAttachedToFirstAxis(
520 const Reference
< chart2::XDataSeries
> & xDataSeries
)
526 sal_Int32 nAxisIndex
= 0;
527 Reference
< beans::XPropertySet
> xProp( xDataSeries
, uno::UNO_QUERY_THROW
);
528 xProp
->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex
;
529 bResult
= (0==nAxisIndex
);
531 catch( const uno::Exception
& )
533 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
539 OUString
lcl_ConvertRange( const OUString
& rRange
, const Reference
< chart2::XChartDocument
> & xDoc
)
541 OUString aResult
= rRange
;
544 Reference
< chart2::data::XRangeXMLConversion
> xConversion(
545 xDoc
->getDataProvider(), uno::UNO_QUERY
);
546 if( xConversion
.is())
547 aResult
= xConversion
->convertRangeToXML( rRange
);
551 typedef ::std::pair
< OUString
, OUString
> tLabelAndValueRange
;
553 tLabelAndValueRange
lcl_getLabelAndValueRangeByRole(
554 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > & aSeqCnt
,
555 const OUString
& rRole
,
556 const Reference
< chart2::XChartDocument
> & xDoc
,
557 SchXMLExportHelper_Impl::tDataSequenceCont
& rOutSequencesToExport
)
559 tLabelAndValueRange aResult
;
561 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq(
562 lcl_getDataSequenceByRole( aSeqCnt
, rRole
));
563 if( xLabeledSeq
.is())
565 Reference
< chart2::data::XDataSequence
> xLabelSeq( xLabeledSeq
->getLabel());
567 aResult
.first
= lcl_ConvertRange( xLabelSeq
->getSourceRangeRepresentation(), xDoc
);
569 Reference
< chart2::data::XDataSequence
> xValueSeq( xLabeledSeq
->getValues());
571 aResult
.second
= lcl_ConvertRange( xValueSeq
->getSourceRangeRepresentation(), xDoc
);
573 if( xLabelSeq
.is() || xValueSeq
.is())
574 rOutSequencesToExport
.emplace_back( xLabelSeq
, xValueSeq
);
580 sal_Int32
lcl_getSequenceLengthByRole(
581 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > & aSeqCnt
,
582 const OUString
& rRole
)
584 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq(
585 lcl_getDataSequenceByRole( aSeqCnt
, rRole
));
586 if( xLabeledSeq
.is())
588 Reference
< chart2::data::XDataSequence
> xSeq( xLabeledSeq
->getValues());
589 return xSeq
->getData().getLength();
594 OUString
lcl_flattenStringSequence( const Sequence
< OUString
> & rSequence
)
596 OUStringBuffer aResult
;
597 bool bPrecedeWithSpace
= false;
598 for( const auto& rString
: rSequence
)
600 if( !rString
.isEmpty())
602 if( bPrecedeWithSpace
)
603 aResult
.append( ' ' );
604 aResult
.append( rString
);
605 bPrecedeWithSpace
= true;
608 return aResult
.makeStringAndClear();
611 void lcl_getLabelStringSequence( Sequence
< OUString
>& rOutLabels
, const Reference
< chart2::data::XDataSequence
> & xLabelSeq
)
613 uno::Reference
< chart2::data::XTextualDataSequence
> xTextualDataSequence( xLabelSeq
, uno::UNO_QUERY
);
614 if( xTextualDataSequence
.is())
616 rOutLabels
= xTextualDataSequence
->getTextualData();
618 else if( xLabelSeq
.is())
620 Sequence
< uno::Any
> aAnies( xLabelSeq
->getData());
621 rOutLabels
.realloc( aAnies
.getLength());
622 auto pOutLabels
= rOutLabels
.getArray();
623 for( sal_Int32 i
=0; i
<aAnies
.getLength(); ++i
)
624 aAnies
[i
] >>= pOutLabels
[i
];
628 sal_Int32
lcl_getMaxSequenceLength(
629 const SchXMLExportHelper_Impl::tDataSequenceCont
& rContainer
)
631 sal_Int32 nResult
= 0;
632 for( const auto& rDataSequence
: rContainer
)
634 if( rDataSequence
.second
.is())
636 sal_Int32 nSeqLength
= rDataSequence
.second
->getData().getLength();
637 if( nSeqLength
> nResult
)
638 nResult
= nSeqLength
;
644 uno::Sequence
< OUString
> lcl_DataSequenceToStringSequence(
645 const uno::Reference
< chart2::data::XDataSequence
>& xDataSequence
)
647 uno::Sequence
< OUString
> aResult
;
648 if(!xDataSequence
.is())
651 uno::Reference
< chart2::data::XTextualDataSequence
> xTextualDataSequence( xDataSequence
, uno::UNO_QUERY
);
652 if( xTextualDataSequence
.is() )
654 aResult
= xTextualDataSequence
->getTextualData();
658 uno::Sequence
< uno::Any
> aValues
= xDataSequence
->getData();
659 aResult
.realloc(aValues
.getLength());
660 auto pResult
= aResult
.getArray();
662 for(sal_Int32 nN
=aValues
.getLength();nN
--;)
663 aValues
[nN
] >>= pResult
[nN
];
668 ::std::vector
< double > lcl_getAllValuesFromSequence( const Reference
< chart2::data::XDataSequence
> & xSeq
)
670 ::std::vector
< double > aResult
;
674 uno::Sequence
< double > aValuesSequence
;
675 Reference
< chart2::data::XNumericalDataSequence
> xNumSeq( xSeq
, uno::UNO_QUERY
);
678 aValuesSequence
= xNumSeq
->getNumericalData();
682 Sequence
< uno::Any
> aAnies( xSeq
->getData() );
683 aValuesSequence
.realloc( aAnies
.getLength() );
684 auto pValuesSequence
= aValuesSequence
.getArray();
685 for( sal_Int32 i
=0; i
<aAnies
.getLength(); ++i
)
686 aAnies
[i
] >>= pValuesSequence
[i
];
689 //special handling for x-values (if x-values do point to categories, indices are used instead )
690 Reference
< beans::XPropertySet
> xProp( xSeq
, uno::UNO_QUERY
);
694 xProp
->getPropertyValue("Role") >>= aRole
;
695 if( aRole
.match("values-x") )
697 //lcl_clearIfNoValuesButTextIsContained - replace by indices if the values are not appropriate
698 bool bHasValue
= std::any_of(std::cbegin(aValuesSequence
), std::cend(aValuesSequence
),
699 [](double fValue
) { return !std::isnan( fValue
); });
702 //no double value is contained
704 const uno::Sequence
< OUString
> aStrings( lcl_DataSequenceToStringSequence( xSeq
) );
705 bool bHasText
= std::any_of(aStrings
.begin(), aStrings
.end(),
706 [](const OUString
& rString
) { return !rString
.isEmpty(); });
709 auto [begin
, end
] = asNonConstRange(aValuesSequence
);
710 std::iota(begin
, end
, 1);
716 aResult
.insert( aResult
.end(), std::cbegin(aValuesSequence
), std::cend(aValuesSequence
) );
720 bool lcl_SequenceHasUnhiddenData( const uno::Reference
< chart2::data::XDataSequence
>& xDataSequence
)
722 if( !xDataSequence
.is() )
724 uno::Reference
< beans::XPropertySet
> xProp( xDataSequence
, uno::UNO_QUERY
);
727 uno::Sequence
< sal_Int32
> aHiddenValues
;
730 xProp
->getPropertyValue("HiddenValues") >>= aHiddenValues
;
731 if( !aHiddenValues
.hasElements() )
734 catch( const uno::Exception
& )
739 return xDataSequence
->getData().hasElements();
742 typedef vector
< OUString
> tStringVector
;
743 typedef vector
< vector
< double > > t2DNumberContainer
;
747 t2DNumberContainer aDataInRows
;
748 tStringVector aDataRangeRepresentations
;
750 tStringVector aColumnDescriptions
;
751 tStringVector aColumnDescriptions_Ranges
;
753 tStringVector aRowDescriptions
;
754 tStringVector aRowDescriptions_Ranges
;
756 Sequence
< Sequence
< uno::Any
> > aComplexColumnDescriptions
;//outer index is columns - inner index is level
757 Sequence
< Sequence
< uno::Any
> > aComplexRowDescriptions
;//outer index is rows - inner index is level
759 ::std::vector
< sal_Int32
> aHiddenColumns
;
762 typedef ::std::map
< sal_Int32
, SchXMLExportHelper_Impl::tLabelValuesDataPair
>
765 struct lcl_SequenceToMapElement
767 std::pair
<const sal_Int32
, SchXMLExportHelper_Impl::tLabelValuesDataPair
>
768 operator() (const SchXMLExportHelper_Impl::tLabelValuesDataPair
& rContent
)
770 sal_Int32 nIndex
= -1;
771 if( rContent
.second
.is()) //has values
773 OUString
aRangeRep( rContent
.second
->getSourceRangeRepresentation());
774 nIndex
= aRangeRep
.toInt32();
776 else if( rContent
.first
.is()) //has labels
777 nIndex
= o3tl::toInt32(rContent
.first
->getSourceRangeRepresentation().subView( sizeof("label ")));
778 return std::make_pair(nIndex
, rContent
);
782 void lcl_ReorderInternalSequencesAccordingToTheirRangeName(
783 SchXMLExportHelper_Impl::tDataSequenceCont
& rInOutSequences
)
785 lcl_DataSequenceMap aIndexSequenceMap
;
786 ::std::transform( rInOutSequences
.begin(), rInOutSequences
.end(),
787 ::std::inserter( aIndexSequenceMap
, aIndexSequenceMap
.begin()),
788 lcl_SequenceToMapElement());
790 rInOutSequences
.clear();
791 sal_Int32 nIndex
= 0;
792 for( const auto& rEntry
: aIndexSequenceMap
)
794 if( rEntry
.first
>= 0 )
796 // fill empty columns
797 rInOutSequences
.insert(
798 rInOutSequences
.end(),
799 rEntry
.first
- nIndex
,
800 SchXMLExportHelper_Impl::tDataSequenceCont::value_type(
801 uno::Reference
< chart2::data::XDataSequence
>(),
802 uno::Reference
< chart2::data::XDataSequence
>() ));
803 nIndex
= rEntry
.first
;
804 rInOutSequences
.push_back( rEntry
.second
);
811 lcl_TableData
lcl_getDataForLocalTable(
812 const SchXMLExportHelper_Impl::tDataSequenceCont
& aSequencesToExport
,
813 const Reference
< chart2::XAnyDescriptionAccess
>& xAnyDescriptionAccess
,
814 const OUString
& rCategoriesRange
,
815 bool bSeriesFromColumns
,
816 const Reference
< chart2::data::XRangeXMLConversion
> & xRangeConversion
)
818 lcl_TableData aResult
;
822 Sequence
< OUString
> aSimpleCategories
;
823 if( xAnyDescriptionAccess
.is() )
826 if( bSeriesFromColumns
)
828 aSimpleCategories
= xAnyDescriptionAccess
->getRowDescriptions();
829 aResult
.aComplexRowDescriptions
= xAnyDescriptionAccess
->getAnyRowDescriptions();
833 aSimpleCategories
= xAnyDescriptionAccess
->getColumnDescriptions();
834 aResult
.aComplexColumnDescriptions
= xAnyDescriptionAccess
->getAnyColumnDescriptions();
838 //series values and series labels
839 SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences
= aSequencesToExport
.size();
841 auto nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport
));
842 if( aSimpleCategories
.getLength() > nMaxSequenceLength
)
844 aSimpleCategories
.realloc(nMaxSequenceLength
);//#i110617#
846 size_t nNumColumns( bSeriesFromColumns
? nNumSequences
: nMaxSequenceLength
);
847 size_t nNumRows( bSeriesFromColumns
? nMaxSequenceLength
: nNumSequences
);
850 aResult
.aDataInRows
.resize( nNumRows
);
852 for (auto& aData
: aResult
.aDataInRows
)
853 aData
.resize(nNumColumns
, std::numeric_limits
<double>::quiet_NaN());
854 aResult
.aColumnDescriptions
.resize( nNumColumns
);
855 aResult
.aComplexColumnDescriptions
.realloc( nNumColumns
);
856 aResult
.aRowDescriptions
.resize( nNumRows
);
857 aResult
.aComplexRowDescriptions
.realloc( nNumRows
);
859 tStringVector
& rCategories
= bSeriesFromColumns
? aResult
.aRowDescriptions
: aResult
.aColumnDescriptions
;
860 tStringVector
& rLabels
= bSeriesFromColumns
? aResult
.aColumnDescriptions
: aResult
.aRowDescriptions
;
864 rCategories
.insert( rCategories
.begin(), std::cbegin(aSimpleCategories
), std::cend(aSimpleCategories
) );
865 if( !rCategoriesRange
.isEmpty() )
867 OUString
aRange(rCategoriesRange
);
868 if( xRangeConversion
.is())
869 aRange
= xRangeConversion
->convertRangeToXML( aRange
);
870 if( bSeriesFromColumns
)
871 aResult
.aRowDescriptions_Ranges
.push_back( aRange
);
873 aResult
.aColumnDescriptions_Ranges
.push_back( aRange
);
876 // iterate over all sequences
878 Sequence
< Sequence
< OUString
> > aComplexLabels(nNumSequences
);
879 auto aComplexLabelsRange
= asNonConstRange(aComplexLabels
);
880 for( const auto& rDataSequence
: aSequencesToExport
)
883 Sequence
< OUString
>& rCurrentComplexLabel
= aComplexLabelsRange
[nSeqIdx
];
884 if( rDataSequence
.first
.is())
886 lcl_getLabelStringSequence( rCurrentComplexLabel
, rDataSequence
.first
);
887 rLabels
[nSeqIdx
] = lcl_flattenStringSequence( rCurrentComplexLabel
);
888 aRange
= rDataSequence
.first
->getSourceRangeRepresentation();
889 if( xRangeConversion
.is())
890 aRange
= xRangeConversion
->convertRangeToXML( aRange
);
892 else if( rDataSequence
.second
.is())
894 rCurrentComplexLabel
.realloc(1);
895 rLabels
[nSeqIdx
] = rCurrentComplexLabel
.getArray()[0] = lcl_flattenStringSequence(
896 rDataSequence
.second
->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE
));
898 if( bSeriesFromColumns
)
899 aResult
.aColumnDescriptions_Ranges
.push_back( aRange
);
901 aResult
.aRowDescriptions_Ranges
.push_back( aRange
);
903 ::std::vector
< double > aNumbers( lcl_getAllValuesFromSequence( rDataSequence
.second
));
904 if( bSeriesFromColumns
)
906 const sal_Int32
nSize( static_cast< sal_Int32
>( aNumbers
.size()));
907 for( sal_Int32 nIdx
=0; nIdx
<nSize
; ++nIdx
)
908 aResult
.aDataInRows
[nIdx
][nSeqIdx
] = aNumbers
[nIdx
];
911 aResult
.aDataInRows
[nSeqIdx
] = aNumbers
;
913 if( rDataSequence
.second
.is())
915 aRange
= rDataSequence
.second
->getSourceRangeRepresentation();
916 if( xRangeConversion
.is())
917 aRange
= xRangeConversion
->convertRangeToXML( aRange
);
919 aResult
.aDataRangeRepresentations
.push_back( aRange
);
922 if( !lcl_SequenceHasUnhiddenData(rDataSequence
.first
) && !lcl_SequenceHasUnhiddenData(rDataSequence
.second
) )
923 aResult
.aHiddenColumns
.push_back(nSeqIdx
);
927 Sequence
< Sequence
< Any
> >& rComplexAnyLabels
= bSeriesFromColumns
? aResult
.aComplexColumnDescriptions
: aResult
.aComplexRowDescriptions
;//#i116544#
928 rComplexAnyLabels
.realloc(aComplexLabels
.getLength());
929 auto pComplexAnyLabels
= rComplexAnyLabels
.getArray();
930 for( sal_Int32 nN
=0; nN
<aComplexLabels
.getLength();nN
++ )
932 Sequence
< OUString
>& rSource
= aComplexLabelsRange
[nN
];
933 Sequence
< Any
>& rTarget
= pComplexAnyLabels
[nN
];
934 rTarget
.realloc( rSource
.getLength() );
935 auto pTarget
= rTarget
.getArray();
936 for( sal_Int32 i
=0; i
<rSource
.getLength(); i
++ )
937 pTarget
[i
] <<= rSource
[i
];
940 catch( const uno::Exception
& )
942 TOOLS_INFO_EXCEPTION("xmloff.chart", "something went wrong during table data collection");
948 void lcl_exportNumberFormat( const OUString
& rPropertyName
, const Reference
< beans::XPropertySet
>& xPropSet
,
949 SvXMLExport
& rExport
)
953 sal_Int32 nNumberFormat
= 0;
954 Any aNumAny
= xPropSet
->getPropertyValue( rPropertyName
);
955 if( (aNumAny
>>= nNumberFormat
) && (nNumberFormat
!= -1) )
956 rExport
.addDataStyle( nNumberFormat
);
960 ::std::vector
< Reference
< chart2::data::XDataSequence
> >
961 lcl_getErrorBarSequences( const Reference
< beans::XPropertySet
> & xErrorBarProp
)
963 ::std::vector
< Reference
< chart2::data::XDataSequence
> > aResult
;
964 Reference
< chart2::data::XDataSource
> xErrorBarDataSource( xErrorBarProp
, uno::UNO_QUERY
);
965 if( !xErrorBarDataSource
.is())
968 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSequences(
969 xErrorBarDataSource
->getDataSequences());
970 for( const auto& rSequence
: aSequences
)
976 Reference
< chart2::data::XDataSequence
> xSequence( rSequence
->getValues());
977 Reference
< beans::XPropertySet
> xSeqProp( xSequence
, uno::UNO_QUERY_THROW
);
979 if( ( xSeqProp
->getPropertyValue( "Role" ) >>= aRole
) &&
980 aRole
.match( "error-bars-" ))
982 aResult
.push_back( xSequence
);
986 catch( const uno::Exception
& )
988 TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exporting error bar ranges" );
995 bool lcl_exportDomainForThisSequence( const Reference
< chart2::data::XDataSequence
>& rValues
, OUString
& rFirstRangeForThisDomainIndex
, SvXMLExport
& rExport
)
997 bool bDomainExported
= false;
1000 Reference
< chart2::XChartDocument
> xNewDoc( rExport
.GetModel(), uno::UNO_QUERY
);
1001 OUString
aRange( lcl_ConvertRange( rValues
->getSourceRangeRepresentation(), xNewDoc
) );
1003 //work around error in OOo 2.0 (problems with multiple series having a domain element)
1004 if( rFirstRangeForThisDomainIndex
.isEmpty() || aRange
!= rFirstRangeForThisDomainIndex
)
1006 rExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_CELL_RANGE_ADDRESS
, aRange
);
1007 SvXMLElementExport
aDomain( rExport
, XML_NAMESPACE_CHART
, XML_DOMAIN
, true, true );
1008 bDomainExported
= true;
1011 if( rFirstRangeForThisDomainIndex
.isEmpty() )
1012 rFirstRangeForThisDomainIndex
= aRange
;
1014 return bDomainExported
;
1017 } // anonymous namespace
1020 SchXMLExportHelper::SchXMLExportHelper( SvXMLExport
& rExport
, SvXMLAutoStylePoolP
& rASPool
)
1021 : m_pImpl( new SchXMLExportHelper_Impl( rExport
, rASPool
) )
1025 SchXMLExportHelper::~SchXMLExportHelper()
1029 const OUString
& SchXMLExportHelper::getChartCLSID() const
1031 return m_pImpl
->msCLSID
;
1034 void SchXMLExportHelper::SetSourceShellID( const OUString
& rShellID
)
1036 m_pImpl
->maSrcShellID
= rShellID
;
1039 void SchXMLExportHelper::SetDestinationShellID( const OUString
& rShellID
)
1041 m_pImpl
->maDestShellID
= rShellID
;
1044 const rtl::Reference
< XMLPropertySetMapper
>& SchXMLExportHelper_Impl::GetPropertySetMapper() const
1046 return mxPropertySetMapper
;
1049 void SchXMLExportHelper_Impl::exportAutoStyles()
1051 if( !mxExpPropMapper
.is())
1054 //ToDo: when embedded in calc/writer this is not necessary because the
1055 // numberformatter is shared between both documents
1056 mrExport
.exportAutoDataStyles();
1058 // export chart auto styles
1059 mrAutoStylePool
.exportXML( XmlStyleFamily::SCH_CHART_ID
);
1061 // export auto styles for additional shapes
1062 mrExport
.GetShapeExport()->exportAutoStyles();
1063 // and for text in additional shapes
1064 mrExport
.GetTextParagraphExport()->exportTextAutoStyles();
1069 SchXMLExportHelper_Impl::SchXMLExportHelper_Impl(
1070 SvXMLExport
& rExport
,
1071 SvXMLAutoStylePoolP
& rASPool
) :
1072 mrExport( rExport
),
1073 mrAutoStylePool( rASPool
),
1074 mxPropertySetMapper( new XMLChartPropertySetMapper(&rExport
) ),
1075 mxExpPropMapper( new XMLChartExportPropertyMapper( mxPropertySetMapper
, rExport
) ),
1076 mbHasCategoryLabels( false ),
1077 mbRowSourceColumns( true ),
1078 msCLSID( SvGlobalName( SO3_SCH_CLASSID
).GetHexName() )
1080 // register chart auto-style family
1081 mrAutoStylePool
.AddFamily(
1082 XmlStyleFamily::SCH_CHART_ID
,
1083 XML_STYLE_FAMILY_SCH_CHART_NAME
,
1084 mxExpPropMapper
.get(),
1085 XML_STYLE_FAMILY_SCH_CHART_PREFIX
);
1087 // register shape family
1088 mrAutoStylePool
.AddFamily(
1089 XmlStyleFamily::SD_GRAPHICS_ID
,
1090 XML_STYLE_FAMILY_SD_GRAPHICS_NAME
,
1091 mxExpPropMapper
.get(),
1092 XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX
);
1093 // register paragraph family also for shapes
1094 mrAutoStylePool
.AddFamily(
1095 XmlStyleFamily::TEXT_PARAGRAPH
,
1096 GetXMLToken( XML_PARAGRAPH
),
1097 mxExpPropMapper
.get(),
1099 // register text family also for shapes
1100 mrAutoStylePool
.AddFamily(
1101 XmlStyleFamily::TEXT_TEXT
,
1102 GetXMLToken( XML_TEXT
),
1103 mxExpPropMapper
.get(),
1107 void SchXMLExportHelper_Impl::collectAutoStyles( Reference
< chart::XChartDocument
> const & rChartDoc
)
1109 parseDocument( rChartDoc
, false );
1112 void SchXMLExportHelper_Impl::exportChart( Reference
< chart::XChartDocument
> const & rChartDoc
,
1113 bool bIncludeTable
)
1115 parseDocument( rChartDoc
, true, bIncludeTable
);
1116 SAL_WARN_IF( !maAutoStyleNameQueue
.empty(), "xmloff.chart", "There are still remaining autostyle names in the queue" );
1119 static OUString
lcl_GetStringFromNumberSequence( const css::uno::Sequence
< sal_Int32
>& rSequenceMapping
, bool bRemoveOneFromEachIndex
/*should be true if having categories*/ )
1121 OUStringBuffer aBuf
;
1122 bool bHasPredecessor
= false;
1123 for( sal_Int32 nIndex
: rSequenceMapping
)
1125 if( bRemoveOneFromEachIndex
)
1131 aBuf
.append( nIndex
);
1132 bHasPredecessor
= true;
1135 return aBuf
.makeStringAndClear();
1138 /// if bExportContent is false the auto-styles are collected
1139 void SchXMLExportHelper_Impl::parseDocument( Reference
< chart::XChartDocument
> const & rChartDoc
,
1140 bool bExportContent
,
1141 bool bIncludeTable
)
1143 Reference
< chart2::XChartDocument
> xNewDoc( rChartDoc
, uno::UNO_QUERY
);
1144 if( !rChartDoc
.is() || !xNewDoc
.is() )
1146 SAL_WARN("xmloff.chart", "No XChartDocument was given for export." );
1150 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(mrExport
.getSaneDefaultVersion());
1152 mxExpPropMapper
->setChartDoc(xNewDoc
);
1154 awt::Size
aPageSize( getPageSize( xNewDoc
));
1155 if( bExportContent
)
1156 addSize( aPageSize
);
1157 Reference
< chart::XDiagram
> xDiagram
= rChartDoc
->getDiagram();
1158 Reference
< chart2::XDiagram
> xNewDiagram
;
1160 xNewDiagram
.set( xNewDoc
->getFirstDiagram());
1162 //todo remove if model changes are notified and view is updated automatically
1163 if( bExportContent
)
1165 Reference
< util::XRefreshable
> xRefreshable( xNewDoc
, uno::UNO_QUERY
);
1166 if( xRefreshable
.is() )
1167 xRefreshable
->refresh();
1170 // get Properties of ChartDocument
1171 bool bHasMainTitle
= false;
1172 bool bHasSubTitle
= false;
1173 bool bHasLegend
= false;
1174 util::DateTime
aNullDate(0,0,0,0,30,12,1899, false);
1176 std::vector
< XMLPropertyState
> aPropertyStates
;
1178 Reference
< beans::XPropertySet
> xDocPropSet( rChartDoc
, uno::UNO_QUERY
);
1179 if( xDocPropSet
.is())
1183 Any aAny
= xDocPropSet
->getPropertyValue("HasMainTitle");
1184 aAny
>>= bHasMainTitle
;
1185 aAny
= xDocPropSet
->getPropertyValue("HasSubTitle");
1186 aAny
>>= bHasSubTitle
;
1187 aAny
= xDocPropSet
->getPropertyValue("HasLegend");
1188 aAny
>>= bHasLegend
;
1189 if ( bIncludeTable
)
1191 aAny
= xDocPropSet
->getPropertyValue("NullDate");
1192 if ( !aAny
.hasValue() )
1194 Reference
<container::XChild
> xChild(rChartDoc
, uno::UNO_QUERY
);
1197 Reference
< beans::XPropertySet
> xParentDoc( xChild
->getParent(),uno::UNO_QUERY
);
1198 if ( xParentDoc
.is() && xParentDoc
->getPropertySetInfo()->hasPropertyByName("NullDate") )
1199 aAny
= xParentDoc
->getPropertyValue("NullDate");
1206 catch( const beans::UnknownPropertyException
& )
1208 SAL_WARN("xmloff.chart", "Required property not found in ChartDocument" );
1212 if ( bIncludeTable
&& (aNullDate
.Day
!= 30 || aNullDate
.Month
!= 12 || aNullDate
.Year
!= 1899 ) )
1214 SvXMLElementExport
aSet( mrExport
, XML_NAMESPACE_TABLE
, XML_CALCULATION_SETTINGS
, true, true );
1216 OUStringBuffer sBuffer
;
1217 ::sax::Converter::convertDateTime(sBuffer
, aNullDate
, nullptr);
1218 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
,XML_DATE_VALUE
,sBuffer
.makeStringAndClear());
1219 SvXMLElementExport
aNull( mrExport
, XML_NAMESPACE_TABLE
, XML_NULL_DATE
, true, true );
1224 std::unique_ptr
<SvXMLElementExport
> xElChart
;
1226 // get property states for autostyles
1227 if( mxExpPropMapper
.is())
1229 Reference
< beans::XPropertySet
> xPropSet
= rChartDoc
->getArea();
1231 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1234 if( bExportContent
)
1236 //export data provider in xlink:href attribute
1238 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
1240 OUString
aDataProviderURL( ".." );
1241 if( xNewDoc
->hasInternalDataProvider() )
1242 aDataProviderURL
= ".";
1243 else //special handling for data base data provider necessary
1245 Reference
< chart2::data::XDatabaseDataProvider
> xDBDataProvider( xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
1246 if( xDBDataProvider
.is() )
1247 aDataProviderURL
= ".";
1249 mrExport
.AddAttribute( XML_NAMESPACE_XLINK
, XML_HREF
, aDataProviderURL
);
1250 mrExport
.AddAttribute( XML_NAMESPACE_XLINK
, XML_TYPE
, XML_SIMPLE
);
1253 Reference
<chart2::data::XPivotTableDataProvider
> xPivotTableDataProvider(xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
1254 if (xPivotTableDataProvider
.is() && nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
1256 OUString sPivotTableName
= xPivotTableDataProvider
->getPivotTableName();
1257 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_DATA_PILOT_SOURCE
, sPivotTableName
);
1260 OUString
sChartType( xDiagram
->getDiagramType() );
1264 if( !sChartType
.isEmpty())
1266 enum XMLTokenEnum eXMLChartType
= SchXMLTools::getTokenByChartType( sChartType
, true /* bUseOldNames */ );
1268 SAL_WARN_IF( eXMLChartType
== XML_TOKEN_INVALID
, "xmloff.chart", "invalid chart class" );
1269 if( eXMLChartType
== XML_TOKEN_INVALID
)
1270 eXMLChartType
= XML_BAR
;
1272 if( eXMLChartType
== XML_ADD_IN
)
1274 // sChartType is the service-name of the add-in
1275 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_CLASS
,
1276 mrExport
.GetNamespaceMap().GetQNameByKey(
1277 XML_NAMESPACE_OOO
, sChartType
) );
1279 else if( eXMLChartType
!= XML_TOKEN_INVALID
)
1281 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_CLASS
,
1282 mrExport
.GetNamespaceMap().GetQNameByKey(
1283 XML_NAMESPACE_CHART
, GetXMLToken(eXMLChartType
)) );
1286 //column-mapping or row-mapping
1287 if( maSequenceMapping
.hasElements() )
1289 enum XMLTokenEnum eTransToken
= ::xmloff::token::XML_ROW_MAPPING
;
1290 if( mbRowSourceColumns
)
1291 eTransToken
= ::xmloff::token::XML_COLUMN_MAPPING
;
1292 OUString
aSequenceMappingStr( lcl_GetStringFromNumberSequence(
1293 maSequenceMapping
, mbHasCategoryLabels
&& !xNewDoc
->hasInternalDataProvider() ) );
1295 mrExport
.AddAttribute( XML_NAMESPACE_CHART
,
1296 ::xmloff::token::GetXMLToken( eTransToken
),
1297 aSequenceMappingStr
);
1301 AddAutoStyleAttribute( aPropertyStates
);
1304 xElChart
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_CHART
, true, true ));
1308 CollectAutoStyle( std::move(aPropertyStates
) );
1310 // remove property states for autostyles
1311 aPropertyStates
.clear();
1316 // get property states for autostyles
1317 if( mxExpPropMapper
.is())
1319 Reference
< beans::XPropertySet
> xPropSet( rChartDoc
->getTitle(), uno::UNO_QUERY
);
1321 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1323 if( bExportContent
)
1325 Reference
< drawing::XShape
> xShape
= rChartDoc
->getTitle();
1326 if( xShape
.is()) // && "hasTitleBeenMoved"
1327 addPosition( xShape
);
1330 AddAutoStyleAttribute( aPropertyStates
);
1333 SvXMLElementExport
aElTitle( mrExport
, XML_NAMESPACE_CHART
, XML_TITLE
, true, true );
1336 Reference
< beans::XPropertySet
> xPropSet( xShape
, uno::UNO_QUERY
);
1339 Any
aAny( xPropSet
->getPropertyValue( "String" ));
1342 exportText( aText
);
1347 CollectAutoStyle( std::move(aPropertyStates
) );
1349 // remove property states for autostyles
1350 aPropertyStates
.clear();
1356 // get property states for autostyles
1357 if( mxExpPropMapper
.is())
1359 Reference
< beans::XPropertySet
> xPropSet( rChartDoc
->getSubTitle(), uno::UNO_QUERY
);
1361 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1364 if( bExportContent
)
1366 Reference
< drawing::XShape
> xShape
= rChartDoc
->getSubTitle();
1368 addPosition( xShape
);
1371 AddAutoStyleAttribute( aPropertyStates
);
1373 // element (has no subelements)
1374 SvXMLElementExport
aElSubTitle( mrExport
, XML_NAMESPACE_CHART
, XML_SUBTITLE
, true, true );
1377 Reference
< beans::XPropertySet
> xPropSet( xShape
, uno::UNO_QUERY
);
1380 Any
aAny( xPropSet
->getPropertyValue( "String" ));
1383 exportText( aText
);
1388 CollectAutoStyle( std::move(aPropertyStates
) );
1390 // remove property states for autostyles
1391 aPropertyStates
.clear();
1397 // get property states for autostyles
1398 if( mxExpPropMapper
.is())
1400 Reference
< beans::XPropertySet
> xPropSet( rChartDoc
->getLegend(), uno::UNO_QUERY
);
1402 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1405 if( bExportContent
)
1407 Reference
< beans::XPropertySet
> xProp( rChartDoc
->getLegend(), uno::UNO_QUERY
);
1410 // export legend anchor position
1413 Any
aAny( xProp
->getPropertyValue("Alignment"));
1414 if( SchXMLEnumConverter::getLegendPositionConverter().exportXML( msString
, aAny
, mrExport
.GetMM100UnitConverter() ) )
1415 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LEGEND_POSITION
, msString
);
1417 catch( const beans::UnknownPropertyException
& )
1419 SAL_WARN("xmloff.chart", "Property Align not found in ChartLegend" );
1422 // export legend overlay
1425 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
1427 Any
aAny( xProp
->getPropertyValue("Overlay"));
1428 if(aAny
.get
<bool>())
1429 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_OVERLAY
, OUString::boolean(true));
1432 catch( const beans::UnknownPropertyException
& )
1434 SAL_WARN("xmloff.chart", "Property Overlay not found in ChartLegend" );
1437 // export absolute legend position
1438 Reference
< drawing::XShape
> xLegendShape( xProp
, uno::UNO_QUERY
);
1439 addPosition( xLegendShape
);
1441 // export legend size
1442 if (xLegendShape
.is() && nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
1446 chart::ChartLegendExpansion nLegendExpansion
= chart::ChartLegendExpansion_HIGH
;
1447 OUString aExpansionString
;
1448 Any
aAny( xProp
->getPropertyValue("Expansion"));
1449 bool bHasExpansion
= (aAny
>>= nLegendExpansion
);
1450 if( bHasExpansion
&& SchXMLEnumConverter::getLegendExpansionConverter().exportXML( aExpansionString
, aAny
, mrExport
.GetMM100UnitConverter() ) )
1452 mrExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_LEGEND_EXPANSION
, aExpansionString
);
1453 if( nLegendExpansion
== chart::ChartLegendExpansion_CUSTOM
)
1455 awt::Size
aSize( xLegendShape
->getSize() );
1456 // tdf#131966: chart legend attributes width and height shouldn't be exported to ODF 1.2 (strict)
1457 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_013
)
1458 { // ODF 1.3 OFFICE-3883
1459 addSize( aSize
, false );
1461 else if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
1463 addSize( aSize
, true );
1465 OUStringBuffer aAspectRatioString
;
1466 ::sax::Converter::convertDouble(
1470 : double(aSize
.Width
)/double(aSize
.Height
)));
1471 mrExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_LEGEND_EXPANSION_ASPECT_RATIO
, aAspectRatioString
.makeStringAndClear() );
1475 catch( const beans::UnknownPropertyException
& )
1477 SAL_WARN("xmloff.chart", "Property Expansion not found in ChartLegend" );
1483 AddAutoStyleAttribute( aPropertyStates
);
1486 SvXMLElementExport
aLegend( mrExport
, XML_NAMESPACE_CHART
, XML_LEGEND
, true, true );
1490 CollectAutoStyle( std::move(aPropertyStates
) );
1492 // remove property states for autostyles
1493 aPropertyStates
.clear();
1496 // Export data table element and properties
1497 if (xNewDiagram
.is() && nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
1499 auto xDataTable
= xNewDiagram
->getDataTable();
1501 if (xDataTable
.is())
1503 // get property states for autostyles
1504 if (mxExpPropMapper
.is())
1506 uno::Reference
<beans::XPropertySet
> xPropSet(xDataTable
, uno::UNO_QUERY
);
1508 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1513 // add style name attribute
1514 AddAutoStyleAttribute(aPropertyStates
);
1515 SvXMLElementExport
aDataTableElement(mrExport
, XML_NAMESPACE_LO_EXT
, XML_DATA_TABLE
, true, true);
1519 CollectAutoStyle(std::move(aPropertyStates
));
1523 // remove property states for autostyles
1524 aPropertyStates
.clear();
1527 // plot-area element
1529 exportPlotArea( xDiagram
, xNewDiagram
, aPageSize
, bExportContent
, bIncludeTable
);
1531 // export additional shapes
1532 if( xDocPropSet
.is() )
1534 if( bExportContent
)
1536 if( mxAdditionalShapes
.is())
1538 // can't call exportShapes with all shapes because the
1539 // initialisation happened with the complete draw page and not
1540 // the XShapes object used here. Thus the shapes have to be
1541 // exported one by one
1542 rtl::Reference
< XMLShapeExport
> rShapeExport
= mrExport
.GetShapeExport();
1543 Reference
< drawing::XShape
> xShape
;
1544 const sal_Int32
nShapeCount( mxAdditionalShapes
->getCount());
1545 for( sal_Int32 nShapeId
= 0; nShapeId
< nShapeCount
; nShapeId
++ )
1547 mxAdditionalShapes
->getByIndex( nShapeId
) >>= xShape
;
1548 SAL_WARN_IF( !xShape
.is(), "xmloff.chart", "Shape without an XShape?" );
1552 rShapeExport
->exportShape( xShape
);
1554 // this would be the easier way if it worked:
1555 //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes );
1560 // get a sequence of non-chart shapes (inserted via clipboard)
1563 Any aShapesAny
= xDocPropSet
->getPropertyValue("AdditionalShapes");
1564 aShapesAny
>>= mxAdditionalShapes
;
1566 catch( const uno::Exception
& )
1568 TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found" );
1571 if( mxAdditionalShapes
.is())
1573 // seek shapes has to be called for the whole page because in
1574 // the shape export the vector of shapes is accessed via the
1575 // ZOrder which might be (actually is) larger than the number of
1576 // shapes in mxAdditionalShapes
1577 Reference
< drawing::XDrawPageSupplier
> xSupplier( rChartDoc
, uno::UNO_QUERY
);
1578 SAL_WARN_IF( !xSupplier
.is(), "xmloff.chart", "Cannot retrieve draw page to initialize shape export" );
1579 if( xSupplier
.is() )
1581 Reference
< drawing::XShapes
> xDrawPage
= xSupplier
->getDrawPage();
1582 SAL_WARN_IF( !xDrawPage
.is(), "xmloff.chart", "Invalid draw page for initializing shape export" );
1584 mrExport
.GetShapeExport()->seekShapes( xDrawPage
);
1587 // can't call collectShapesAutoStyles with all shapes because
1588 // the initialisation happened with the complete draw page and
1589 // not the XShapes object used here. Thus the shapes have to be
1590 // exported one by one
1591 rtl::Reference
< XMLShapeExport
> rShapeExport
= mrExport
.GetShapeExport();
1592 Reference
< drawing::XShape
> xShape
;
1593 const sal_Int32
nShapeCount( mxAdditionalShapes
->getCount());
1594 for( sal_Int32 nShapeId
= 0; nShapeId
< nShapeCount
; nShapeId
++ )
1596 mxAdditionalShapes
->getByIndex( nShapeId
) >>= xShape
;
1597 SAL_WARN_IF( !xShape
.is(), "xmloff.chart", "Shape without an XShape?" );
1601 rShapeExport
->collectShapeAutoStyles( xShape
);
1608 // (is included as subelement of chart)
1609 if( bExportContent
)
1611 // #85929# always export table, otherwise clipboard may lose data
1616 static void lcl_exportComplexLabel( const Sequence
< uno::Any
>& rComplexLabel
, SvXMLExport
& rExport
)
1618 sal_Int32 nLength
= rComplexLabel
.getLength();
1621 SvXMLElementExport
aTextList( rExport
, XML_NAMESPACE_TEXT
, XML_LIST
, true, true );
1622 for(const auto& rElem
: rComplexLabel
)
1624 SvXMLElementExport
aListItem( rExport
, XML_NAMESPACE_TEXT
, XML_LIST_ITEM
, true, true );
1626 if( !(rElem
>>= aString
) )
1631 aString
= OUString::number(aNum
);
1634 SchXMLTools::exportText( rExport
, aString
, false /*bConvertTabsLFs*/ );
1638 void SchXMLExportHelper_Impl::exportTable()
1641 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_NAME
, gsTableName
);
1645 bool bProtected
= false;
1646 Reference
< beans::XPropertySet
> xProps( mrExport
.GetModel(), uno::UNO_QUERY_THROW
);
1647 if ( ( xProps
->getPropertyValue("DisableDataTableDialog") >>= bProtected
) &&
1650 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_PROTECTED
, XML_TRUE
);
1653 catch ( const uno::Exception
& )
1657 SvXMLElementExport
aTable( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE
, true, true );
1659 bool bHasOwnData
= false;
1660 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
1661 Reference
< chart2::data::XRangeXMLConversion
> xRangeConversion
;
1664 bHasOwnData
= xNewDoc
->hasInternalDataProvider();
1665 xRangeConversion
.set( xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
1668 Reference
< chart2::XAnyDescriptionAccess
> xAnyDescriptionAccess
;
1670 Reference
< chart::XChartDocument
> xChartDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
1671 if( xChartDoc
.is() )
1672 xAnyDescriptionAccess
.set( xChartDoc
->getData(), uno::UNO_QUERY
);
1676 lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport
);
1677 lcl_TableData
aData( lcl_getDataForLocalTable( m_aDataSequencesToExport
1678 , xAnyDescriptionAccess
, maCategoriesRange
1679 , mbRowSourceColumns
, xRangeConversion
));
1681 tStringVector::const_iterator
aDataRangeIter( aData
.aDataRangeRepresentations
.begin());
1682 const tStringVector::const_iterator
aDataRangeEndIter( aData
.aDataRangeRepresentations
.end());
1684 tStringVector::const_iterator
aRowDescriptions_RangeIter( aData
.aRowDescriptions_Ranges
.begin());
1685 const tStringVector::const_iterator
aRowDescriptions_RangeEnd( aData
.aRowDescriptions_Ranges
.end());
1689 SvXMLElementExport
aHeaderColumns( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_HEADER_COLUMNS
, true, true );
1690 SvXMLElementExport
aHeaderColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1693 SvXMLElementExport
aColumns( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMNS
, true, true );
1695 sal_Int32 nNextIndex
= 0;
1696 for(sal_Int32 nHiddenIndex
: aData
.aHiddenColumns
)
1698 //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste )
1699 if( nHiddenIndex
> nNextIndex
)
1701 sal_Int64 nRepeat
= static_cast< sal_Int64
>( nHiddenIndex
- nNextIndex
);
1703 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_REPEATED
,
1704 OUString::number( nRepeat
));
1705 SvXMLElementExport
aColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1707 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_VISIBILITY
, GetXMLToken( XML_COLLAPSE
) );
1708 SvXMLElementExport
aColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1709 nNextIndex
= nHiddenIndex
+1;
1712 sal_Int32 nEndIndex
= aData
.aColumnDescriptions
.size()-1;
1713 if( nEndIndex
>= nNextIndex
)
1715 sal_Int64 nRepeat
= static_cast< sal_Int64
>( nEndIndex
- nNextIndex
+ 1 );
1717 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_REPEATED
,
1718 OUString::number( nRepeat
));
1719 SvXMLElementExport
aColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1723 // export rows with content
1726 SvXMLElementExport
aHeaderRows( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_HEADER_ROWS
, true, true );
1727 SvXMLElementExport
aRow( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_ROW
, true, true );
1729 //first one empty cell for the row descriptions
1731 SvXMLElementExport
aEmptyCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1732 SvXMLElementExport
aEmptyParagraph( mrExport
, XML_NAMESPACE_TEXT
, XML_P
, true, true );
1735 //export column descriptions
1736 tStringVector::const_iterator
aColumnDescriptions_RangeIter( aData
.aColumnDescriptions_Ranges
.begin());
1737 const tStringVector::const_iterator
aColumnDescriptions_RangeEnd( aData
.aColumnDescriptions_Ranges
.end());
1738 const Sequence
< Sequence
< uno::Any
> >& rComplexColumnDescriptions
= aData
.aComplexColumnDescriptions
;
1739 sal_Int32 nComplexCount
= rComplexColumnDescriptions
.getLength();
1741 for( const auto& rDesc
: aData
.aColumnDescriptions
)
1743 bool bExportString
= true;
1744 if( nC
< nComplexCount
)
1746 const Sequence
< uno::Any
>& rComplexLabel
= rComplexColumnDescriptions
[nC
];
1747 if( rComplexLabel
.hasElements() )
1750 if( rComplexLabel
[0] >>=fValue
)
1752 bExportString
= false;
1754 ::sax::Converter::convertDouble(
1755 msStringBuffer
, fValue
);
1756 msString
= msStringBuffer
.makeStringAndClear();
1757 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_FLOAT
);
1758 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE
, msString
);
1764 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_STRING
);
1767 SvXMLElementExport
aCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1768 exportText( rDesc
);
1769 if( nC
< nComplexCount
)
1770 lcl_exportComplexLabel( rComplexColumnDescriptions
[nC
], mrExport
);
1771 if( !bHasOwnData
&& aColumnDescriptions_RangeIter
!= aColumnDescriptions_RangeEnd
)
1773 // remind the original range to allow a correct re-association when copying via clipboard
1774 if (!(*aColumnDescriptions_RangeIter
).isEmpty())
1775 SchXMLTools::exportRangeToSomewhere( mrExport
, *aColumnDescriptions_RangeIter
);
1776 ++aColumnDescriptions_RangeIter
;
1781 SAL_WARN_IF( !bHasOwnData
&& (aColumnDescriptions_RangeIter
!= aColumnDescriptions_RangeEnd
), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" );
1782 } // closing row and header-rows elements
1784 // export value rows
1786 SvXMLElementExport
aRows( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_ROWS
, true, true );
1787 tStringVector::const_iterator
aRowDescriptionsIter( aData
.aRowDescriptions
.begin());
1788 const Sequence
< Sequence
< uno::Any
> >& rComplexRowDescriptions
= aData
.aComplexRowDescriptions
;
1789 sal_Int32 nComplexCount
= rComplexRowDescriptions
.getLength();
1792 for( const auto& rRow
: aData
.aDataInRows
)
1794 SvXMLElementExport
aRow( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_ROW
, true, true );
1796 //export row descriptions
1798 bool bExportString
= true;
1799 if( nC
< nComplexCount
)
1801 const Sequence
< uno::Any
>& rComplexLabel
= rComplexRowDescriptions
[nC
];
1802 if( rComplexLabel
.hasElements() )
1805 if( rComplexLabel
[0] >>=fValue
)
1807 bExportString
= false;
1809 ::sax::Converter::convertDouble(msStringBuffer
, fValue
);
1810 msString
= msStringBuffer
.makeStringAndClear();
1811 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_FLOAT
);
1812 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE
, msString
);
1818 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_STRING
);
1821 SvXMLElementExport
aCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1822 if( aRowDescriptionsIter
!= aData
.aRowDescriptions
.end())
1824 exportText( *aRowDescriptionsIter
);
1825 if( nC
< nComplexCount
)
1826 lcl_exportComplexLabel( rComplexRowDescriptions
[nC
], mrExport
);
1827 if( !bHasOwnData
&& aRowDescriptions_RangeIter
!= aRowDescriptions_RangeEnd
)
1829 // remind the original range to allow a correct re-association when copying via clipboard
1830 SchXMLTools::exportRangeToSomewhere( mrExport
, *aRowDescriptions_RangeIter
);
1831 ++aRowDescriptions_RangeIter
;
1833 ++aRowDescriptionsIter
;
1838 for( t2DNumberContainer::value_type::const_iterator
aColIt( rRow
.begin());
1839 aColIt
!= rRow
.end(); ++aColIt
)
1841 ::sax::Converter::convertDouble( msStringBuffer
, *aColIt
);
1842 msString
= msStringBuffer
.makeStringAndClear();
1843 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_FLOAT
);
1844 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE
, msString
);
1845 SvXMLElementExport
aCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1846 exportText( msString
); // do not convert tabs and lfs
1847 if( ( !bHasOwnData
&& aDataRangeIter
!= aDataRangeEndIter
) &&
1848 ( mbRowSourceColumns
|| (aColIt
== rRow
.begin()) ) )
1850 // remind the original range to allow a correct re-association when copying via clipboard
1851 if (!(*aDataRangeIter
).isEmpty())
1852 SchXMLTools::exportRangeToSomewhere( mrExport
, *aDataRangeIter
);
1861 // if range iterator was used it should have reached its end
1862 SAL_WARN_IF( !bHasOwnData
&& (aDataRangeIter
!= aDataRangeEndIter
), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" );
1863 SAL_WARN_IF( !bHasOwnData
&& (aRowDescriptions_RangeIter
!= aRowDescriptions_RangeEnd
), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" );
1869 Reference
< chart2::XCoordinateSystem
> lcl_getCooSys( const Reference
< chart2::XDiagram
> & xNewDiagram
)
1871 Reference
< chart2::XCoordinateSystem
> xCooSys
;
1872 Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xNewDiagram
, uno::UNO_QUERY
);
1875 Sequence
< Reference
< chart2::XCoordinateSystem
> > aCooSysSeq( xCooSysCnt
->getCoordinateSystems() );
1876 if(aCooSysSeq
.hasElements())
1877 xCooSys
= aCooSysSeq
[0];
1882 Reference
< chart2::XAxis
> lcl_getAxis( const Reference
< chart2::XCoordinateSystem
>& xCooSys
,
1883 enum XMLTokenEnum eDimension
, bool bPrimary
=true )
1885 Reference
< chart2::XAxis
> xNewAxis
;
1890 sal_Int32 nDimensionIndex
=0;
1891 switch( eDimension
)
1906 xNewAxis
= xCooSys
->getAxisByDimension( nDimensionIndex
, bPrimary
? 0 : 1 );
1909 catch( const uno::Exception
& )
1917 void SchXMLExportHelper_Impl::exportPlotArea(
1918 const Reference
< chart::XDiagram
>& xDiagram
,
1919 const Reference
< chart2::XDiagram
>& xNewDiagram
,
1920 const awt::Size
& rPageSize
,
1921 bool bExportContent
,
1922 bool bIncludeTable
)
1924 SAL_WARN_IF( !xDiagram
.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
1925 if( ! xDiagram
.is())
1928 // variables for autostyles
1929 Reference
< beans::XPropertySet
> xPropSet
;
1930 std::vector
< XMLPropertyState
> aPropertyStates
;
1932 msStringBuffer
.setLength( 0 );
1934 // plot-area element
1936 std::unique_ptr
<SvXMLElementExport
> xElPlotArea
;
1937 // get property states for autostyles
1938 xPropSet
.set( xDiagram
, uno::UNO_QUERY
);
1941 if( mxExpPropMapper
.is())
1942 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1944 if( bExportContent
)
1946 rtl::Reference
< XMLShapeExport
> rShapeExport
;
1949 AddAutoStyleAttribute( aPropertyStates
);
1951 if( !msChartAddress
.isEmpty() )
1953 if( !bIncludeTable
)
1954 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_CELL_RANGE_ADDRESS
, msChartAddress
);
1956 Reference
< chart::XChartDocument
> xDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
1959 Reference
< beans::XPropertySet
> xDocProp( xDoc
, uno::UNO_QUERY
);
1966 bool bFirstCol
= false, bFirstRow
= false;
1968 aAny
= xDocProp
->getPropertyValue( "DataSourceLabelsInFirstColumn" );
1970 aAny
= xDocProp
->getPropertyValue( "DataSourceLabelsInFirstRow" );
1973 if( bFirstCol
|| bFirstRow
)
1975 mrExport
.AddAttribute( XML_NAMESPACE_CHART
,
1976 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS
),
1979 ? ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH
)
1980 : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN
))
1981 : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW
)));
1984 catch( const beans::UnknownPropertyException
& )
1986 SAL_WARN("xmloff.chart", "Properties missing" );
1995 addPosition( xDiagram
);
1996 addSize( xDiagram
);
1999 bool bIs3DChart
= false;
2008 aAny
= xPropSet
->getPropertyValue("Dim3D");
2009 aAny
>>= bIs3DChart
;
2013 rShapeExport
= mrExport
.GetShapeExport();
2014 if( rShapeExport
.is())
2015 rShapeExport
->export3DSceneAttributes( xPropSet
);
2018 catch( const uno::Exception
& )
2020 TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught");
2024 // plot-area element
2025 xElPlotArea
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_PLOT_AREA
, true, true ));
2027 //inner position rectangle element
2028 exportCoordinateRegion( xDiagram
);
2030 // light sources (inside plot area element)
2033 rShapeExport
->export3DLamps( xPropSet
);
2037 CollectAutoStyle( std::move(aPropertyStates
) );
2039 // remove property states for autostyles
2040 aPropertyStates
.clear();
2043 exportAxes( xDiagram
, xNewDiagram
, bExportContent
);
2046 Reference
< chart2::XAxis
> xSecondYAxis
= lcl_getAxis( lcl_getCooSys( xNewDiagram
), XML_Y
, false );
2047 exportSeries( xNewDiagram
, rPageSize
, bExportContent
, xSecondYAxis
.is() );
2049 // stock-chart elements
2050 OUString
sChartType ( xDiagram
->getDiagramType());
2051 if( sChartType
== "com.sun.star.chart.StockDiagram" )
2053 Reference
< chart::XStatisticDisplay
> xStockPropProvider( xDiagram
, uno::UNO_QUERY
);
2054 if( xStockPropProvider
.is())
2056 // stock-gain-marker
2057 Reference
< beans::XPropertySet
> xStockPropSet
= xStockPropProvider
->getUpBar();
2058 if( xStockPropSet
.is())
2060 aPropertyStates
.clear();
2061 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStockPropSet
);
2063 if( !aPropertyStates
.empty() )
2065 if( bExportContent
)
2067 AddAutoStyleAttribute( aPropertyStates
);
2069 SvXMLElementExport
aGain( mrExport
, XML_NAMESPACE_CHART
, XML_STOCK_GAIN_MARKER
, true, true );
2073 CollectAutoStyle( std::move(aPropertyStates
) );
2078 // stock-loss-marker
2079 xStockPropSet
= xStockPropProvider
->getDownBar();
2080 if( xStockPropSet
.is())
2082 aPropertyStates
.clear();
2083 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStockPropSet
);
2085 if( !aPropertyStates
.empty() )
2087 if( bExportContent
)
2089 AddAutoStyleAttribute( aPropertyStates
);
2091 SvXMLElementExport
aGain( mrExport
, XML_NAMESPACE_CHART
, XML_STOCK_LOSS_MARKER
, true, true );
2095 CollectAutoStyle( std::move(aPropertyStates
) );
2101 xStockPropSet
= xStockPropProvider
->getMinMaxLine();
2102 if( xStockPropSet
.is())
2104 aPropertyStates
.clear();
2105 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStockPropSet
);
2107 if( !aPropertyStates
.empty() )
2109 if( bExportContent
)
2111 AddAutoStyleAttribute( aPropertyStates
);
2113 SvXMLElementExport
aGain( mrExport
, XML_NAMESPACE_CHART
, XML_STOCK_RANGE_LINE
, true, true );
2117 CollectAutoStyle( std::move(aPropertyStates
) );
2124 // wall and floor element
2125 Reference
< chart::X3DDisplay
> xWallFloorSupplier( xDiagram
, uno::UNO_QUERY
);
2126 if( !(mxExpPropMapper
.is() &&
2127 xWallFloorSupplier
.is()))
2130 // remove property states for autostyles
2131 aPropertyStates
.clear();
2133 Reference
< beans::XPropertySet
> xWallPropSet
= xWallFloorSupplier
->getWall();
2134 if( xWallPropSet
.is())
2136 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xWallPropSet
);
2138 if( !aPropertyStates
.empty() )
2141 if( bExportContent
)
2143 // add style name attribute
2144 AddAutoStyleAttribute( aPropertyStates
);
2146 SvXMLElementExport
aWall( mrExport
, XML_NAMESPACE_CHART
, XML_WALL
, true, true );
2150 CollectAutoStyle( std::move(aPropertyStates
) );
2156 // remove property states for autostyles
2157 aPropertyStates
.clear();
2159 Reference
< beans::XPropertySet
> xFloorPropSet
= xWallFloorSupplier
->getFloor();
2160 if( !xFloorPropSet
.is())
2163 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xFloorPropSet
);
2165 if( aPropertyStates
.empty() )
2169 if( bExportContent
)
2171 // add style name attribute
2172 AddAutoStyleAttribute( aPropertyStates
);
2174 SvXMLElementExport
aFloor( mrExport
, XML_NAMESPACE_CHART
, XML_FLOOR
, true, true );
2178 CollectAutoStyle( std::move(aPropertyStates
) );
2182 void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference
< chart::XDiagram
>& xDiagram
)
2184 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2185 mrExport
.getSaneDefaultVersion());
2186 if (nCurrentODFVersion
<= SvtSaveOptions::ODFSVER_012
) //do not export to ODF 1.2 or older
2189 Reference
< chart::XDiagramPositioning
> xDiaPos( xDiagram
, uno::UNO_QUERY
);
2190 SAL_WARN_IF( !xDiaPos
.is(), "xmloff.chart", "Invalid xDiaPos as parameter" );
2194 awt::Rectangle
aRect( xDiaPos
->calculateDiagramPositionExcludingAxes() );
2195 addPosition( awt::Point(aRect
.X
,aRect
.Y
) );
2196 addSize( awt::Size(aRect
.Width
,aRect
.Height
) );
2198 // ODF 1.3 OFFICE-3928
2199 SvXMLElementExport
aCoordinateRegion( mrExport
,
2200 (SvtSaveOptions::ODFSVER_013
<= nCurrentODFVersion
) ? XML_NAMESPACE_CHART
: XML_NAMESPACE_CHART_EXT
,
2201 XML_COORDINATE_REGION
, true, true );
2206 XMLTokenEnum
lcl_getTimeUnitToken( sal_Int32 nTimeUnit
)
2208 XMLTokenEnum eToken
= XML_DAYS
;
2211 case css::chart::TimeUnit::YEAR
:
2214 case css::chart::TimeUnit::MONTH
:
2215 eToken
= XML_MONTHS
;
2224 void SchXMLExportHelper_Impl::exportDateScale( const Reference
< beans::XPropertySet
>& rAxisProps
)
2226 if( !rAxisProps
.is() )
2229 chart::TimeIncrement aIncrement
;
2230 if( !(rAxisProps
->getPropertyValue("TimeIncrement") >>= aIncrement
) )
2233 sal_Int32 nTimeResolution
= css::chart::TimeUnit::DAY
;
2234 if( aIncrement
.TimeResolution
>>= nTimeResolution
)
2235 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_BASE_TIME_UNIT
, lcl_getTimeUnitToken( nTimeResolution
) );
2237 chart::TimeInterval aInterval
;
2238 if( aIncrement
.MajorTimeInterval
>>= aInterval
)
2240 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MAJOR_INTERVAL_VALUE
, OUString::number(aInterval
.Number
) );
2241 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MAJOR_INTERVAL_UNIT
, lcl_getTimeUnitToken( aInterval
.TimeUnit
) );
2243 if( aIncrement
.MinorTimeInterval
>>= aInterval
)
2245 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MINOR_INTERVAL_VALUE
, OUString::number(aInterval
.Number
) );
2246 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MINOR_INTERVAL_UNIT
, lcl_getTimeUnitToken( aInterval
.TimeUnit
) );
2249 SvXMLElementExport
aDateScale( mrExport
, XML_NAMESPACE_CHART_EXT
, XML_DATE_SCALE
, true, true );//#i25706#todo: change namespace for next ODF version
2252 void SchXMLExportHelper_Impl::exportAxisTitle( const Reference
< beans::XPropertySet
>& rTitleProps
, bool bExportContent
)
2254 if( !rTitleProps
.is() )
2256 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, rTitleProps
);
2257 if( bExportContent
)
2260 Any
aAny( rTitleProps
->getPropertyValue( "String" ));
2263 Reference
< drawing::XShape
> xShape( rTitleProps
, uno::UNO_QUERY
);
2265 addPosition( xShape
);
2267 AddAutoStyleAttribute( aPropertyStates
);
2268 SvXMLElementExport
aTitle( mrExport
, XML_NAMESPACE_CHART
, XML_TITLE
, true, true );
2270 // paragraph containing title
2271 exportText( aText
);
2275 CollectAutoStyle( std::move(aPropertyStates
) );
2277 aPropertyStates
.clear();
2280 void SchXMLExportHelper_Impl::exportGrid( const Reference
< beans::XPropertySet
>& rGridProperties
, bool bMajor
, bool bExportContent
)
2282 if( !rGridProperties
.is() )
2284 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, rGridProperties
);
2285 if( bExportContent
)
2287 AddAutoStyleAttribute( aPropertyStates
);
2288 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_CLASS
, bMajor
? XML_MAJOR
: XML_MINOR
);
2289 SvXMLElementExport
aGrid( mrExport
, XML_NAMESPACE_CHART
, XML_GRID
, true, true );
2293 CollectAutoStyle( std::move(aPropertyStates
) );
2295 aPropertyStates
.clear();
2301 //returns true if a date scale needs to be exported
2302 bool lcl_exportAxisType( const Reference
< chart2::XAxis
>& rChart2Axis
, SvXMLExport
& rExport
)
2304 bool bExportDateScale
= false;
2305 if( !rChart2Axis
.is() )
2306 return bExportDateScale
;
2308 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2309 rExport
.getSaneDefaultVersion());
2310 if ((nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) == 0) //do not export to ODF 1.3 or older
2311 return bExportDateScale
;
2313 chart2::ScaleData
aScale( rChart2Axis
->getScaleData() );
2314 //#i25706#todo: change namespace for next ODF version
2315 sal_uInt16 nNameSpace
= XML_NAMESPACE_CHART_EXT
;
2317 switch(aScale
.AxisType
)
2319 case chart2::AxisType::CATEGORY
:
2320 if( aScale
.AutoDateAxis
)
2322 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_AUTO
);
2323 bExportDateScale
= true;
2326 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_TEXT
);
2328 case chart2::AxisType::DATE
:
2329 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_DATE
);
2330 bExportDateScale
= true;
2332 default: //AUTOMATIC
2333 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_AUTO
);
2337 return bExportDateScale
;
2340 void disableLinkedNumberFormat(
2341 std::vector
<XMLPropertyState
>& rPropStates
, const rtl::Reference
<XMLPropertySetMapper
>& rMapper
)
2343 for (XMLPropertyState
& rState
: rPropStates
)
2345 if (rState
.mnIndex
< 0 || rMapper
->GetEntryCount() <= rState
.mnIndex
)
2348 OUString aXMLName
= rMapper
->GetEntryXMLName(rState
.mnIndex
);
2350 if (aXMLName
!= "link-data-style-to-source")
2353 // Entry found. Set the value to false and bail out.
2354 rState
.maValue
<<= false;
2358 // Entry not found. Insert a new entry for this.
2359 sal_Int32 nIndex
= rMapper
->GetEntryIndex(XML_NAMESPACE_CHART
, u
"link-data-style-to-source", 0);
2360 XMLPropertyState
aState(nIndex
);
2361 aState
.maValue
<<= false;
2362 rPropStates
.push_back(aState
);
2367 void SchXMLExportHelper_Impl::exportAxis(
2368 enum XMLTokenEnum eDimension
,
2369 enum XMLTokenEnum eAxisName
,
2370 const Reference
< beans::XPropertySet
>& rAxisProps
,
2371 const Reference
< chart2::XAxis
>& rChart2Axis
,
2372 const OUString
& rCategoriesRange
,
2373 bool bHasTitle
, bool bHasMajorGrid
, bool bHasMinorGrid
,
2374 bool bExportContent
, std::u16string_view sChartType
)
2376 std::vector
< XMLPropertyState
> aPropertyStates
;
2377 std::unique_ptr
<SvXMLElementExport
> pAxis
;
2379 // get property states for autostyles
2380 if( rAxisProps
.is() && mxExpPropMapper
.is() )
2382 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2383 mrExport
.getSaneDefaultVersion());
2384 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
2385 && eDimension
== XML_X
)
2387 chart2::ScaleData
aScaleData(rChart2Axis
->getScaleData());
2388 bool bShiftedCatPos
= aScaleData
.ShiftedCategoryPosition
;
2389 if (sChartType
== u
"com.sun.star.chart.BarDiagram" || sChartType
== u
"com.sun.star.chart.StockDiagram")
2391 if (!bShiftedCatPos
)
2392 rAxisProps
->setPropertyValue("MajorOrigin", uno::Any(0.0));
2394 else if (bShiftedCatPos
)
2395 rAxisProps
->setPropertyValue("MajorOrigin", uno::Any(0.5));
2398 lcl_exportNumberFormat( "NumberFormat", rAxisProps
, mrExport
);
2399 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, rAxisProps
);
2401 if (!maSrcShellID
.isEmpty() && !maDestShellID
.isEmpty() && maSrcShellID
!= maDestShellID
)
2403 // Disable link to source number format property when pasting to
2404 // a different doc shell. These shell ID's should be both empty
2405 // during real ODF export.
2406 disableLinkedNumberFormat(aPropertyStates
, mxExpPropMapper
->getPropertySetMapper());
2410 bool bExportDateScale
= false;
2411 if( bExportContent
)
2413 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DIMENSION
, eDimension
);
2414 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_NAME
, eAxisName
);
2415 AddAutoStyleAttribute( aPropertyStates
); // write style name
2416 if( !rCategoriesRange
.isEmpty() )
2417 bExportDateScale
= lcl_exportAxisType( rChart2Axis
, mrExport
);
2419 // open axis element
2420 pAxis
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_AXIS
, true, true ));
2424 CollectAutoStyle( std::move(aPropertyStates
) );
2426 aPropertyStates
.clear();
2429 if( bExportDateScale
)
2430 exportDateScale( rAxisProps
);
2432 Reference
< beans::XPropertySet
> xTitleProps
;
2433 Reference
< beans::XPropertySet
> xMajorGridProps
;
2434 Reference
< beans::XPropertySet
> xMinorGridProps
;
2435 Reference
< chart::XAxis
> xAxis( rAxisProps
, uno::UNO_QUERY
);
2438 xTitleProps
= bHasTitle
? xAxis
->getAxisTitle() : nullptr;
2439 xMajorGridProps
= bHasMajorGrid
? xAxis
->getMajorGrid() : nullptr;
2440 xMinorGridProps
= bHasMinorGrid
? xAxis
->getMinorGrid() : nullptr;
2444 exportAxisTitle( xTitleProps
, bExportContent
);
2446 // categories if we have a categories chart
2447 if( bExportContent
&& !rCategoriesRange
.isEmpty() )
2449 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_CELL_RANGE_ADDRESS
, rCategoriesRange
);
2450 SvXMLElementExport
aCategories( mrExport
, XML_NAMESPACE_CHART
, XML_CATEGORIES
, true, true );
2454 exportGrid( xMajorGridProps
, true, bExportContent
);
2455 exportGrid( xMinorGridProps
, false, bExportContent
);
2458 void SchXMLExportHelper_Impl::exportAxes(
2459 const Reference
< chart::XDiagram
> & xDiagram
,
2460 const Reference
< chart2::XDiagram
> & xNewDiagram
,
2461 bool bExportContent
)
2463 SAL_WARN_IF( !xDiagram
.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
2464 if( ! xDiagram
.is())
2467 // get some properties from document first
2468 bool bHasXAxis
= false,
2471 bHasSecondaryXAxis
= false,
2472 bHasSecondaryYAxis
= false;
2473 bool bHasXAxisTitle
= false,
2474 bHasYAxisTitle
= false,
2475 bHasZAxisTitle
= false,
2476 bHasSecondaryXAxisTitle
= false,
2477 bHasSecondaryYAxisTitle
= false;
2478 bool bHasXAxisMajorGrid
= false,
2479 bHasXAxisMinorGrid
= false,
2480 bHasYAxisMajorGrid
= false,
2481 bHasYAxisMinorGrid
= false,
2482 bHasZAxisMajorGrid
= false,
2483 bHasZAxisMinorGrid
= false;
2485 // get multiple properties using XMultiPropertySet
2486 MultiPropertySetHandler
aDiagramProperties (xDiagram
);
2488 aDiagramProperties
.Add ("HasXAxis", bHasXAxis
);
2489 aDiagramProperties
.Add ("HasYAxis", bHasYAxis
);
2490 aDiagramProperties
.Add ("HasZAxis", bHasZAxis
);
2491 aDiagramProperties
.Add ("HasSecondaryXAxis", bHasSecondaryXAxis
);
2492 aDiagramProperties
.Add ("HasSecondaryYAxis", bHasSecondaryYAxis
);
2494 aDiagramProperties
.Add ("HasXAxisTitle", bHasXAxisTitle
);
2495 aDiagramProperties
.Add ("HasYAxisTitle", bHasYAxisTitle
);
2496 aDiagramProperties
.Add ("HasZAxisTitle", bHasZAxisTitle
);
2497 aDiagramProperties
.Add ("HasSecondaryXAxisTitle", bHasSecondaryXAxisTitle
);
2498 aDiagramProperties
.Add ("HasSecondaryYAxisTitle", bHasSecondaryYAxisTitle
);
2500 aDiagramProperties
.Add ("HasXAxisGrid", bHasXAxisMajorGrid
);
2501 aDiagramProperties
.Add ("HasYAxisGrid", bHasYAxisMajorGrid
);
2502 aDiagramProperties
.Add ("HasZAxisGrid", bHasZAxisMajorGrid
);
2504 aDiagramProperties
.Add ("HasXAxisHelpGrid", bHasXAxisMinorGrid
);
2505 aDiagramProperties
.Add ("HasYAxisHelpGrid", bHasYAxisMinorGrid
);
2506 aDiagramProperties
.Add ("HasZAxisHelpGrid", bHasZAxisMinorGrid
);
2508 if ( ! aDiagramProperties
.GetProperties ())
2510 SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram");
2513 Reference
< chart2::XCoordinateSystem
> xCooSys( lcl_getCooSys(xNewDiagram
) );
2515 // write an axis element also if the axis itself is not visible, but a grid or a title
2517 OUString aCategoriesRange
;
2518 Reference
< chart::XAxisSupplier
> xAxisSupp( xDiagram
, uno::UNO_QUERY
);
2519 OUString sChartType
= xDiagram
->getDiagramType();
2523 Reference
< css::chart2::XAxis
> xNewAxis
= lcl_getAxis( xCooSys
, XML_X
);
2526 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getAxis(0) : nullptr, uno::UNO_QUERY
);
2527 if( mbHasCategoryLabels
&& bExportContent
)
2529 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( xNewDiagram
) );
2530 if( xCategories
.is() )
2532 Reference
< chart2::data::XDataSequence
> xValues( xCategories
->getValues() );
2535 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
2536 maCategoriesRange
= xValues
->getSourceRangeRepresentation();
2537 aCategoriesRange
= lcl_ConvertRange( maCategoriesRange
, xNewDoc
);
2541 exportAxis( XML_X
, XML_PRIMARY_X
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasXAxisTitle
, bHasXAxisMajorGrid
, bHasXAxisMinorGrid
, bExportContent
, sChartType
);
2542 aCategoriesRange
.clear();
2547 xNewAxis
= lcl_getAxis( xCooSys
, XML_X
, false );
2550 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY
);
2551 exportAxis( XML_X
, XML_SECONDARY_X
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasSecondaryXAxisTitle
, false, false, bExportContent
, sChartType
);
2556 xNewAxis
= lcl_getAxis( xCooSys
, XML_Y
);
2559 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getAxis(1) : nullptr, uno::UNO_QUERY
);
2560 exportAxis( XML_Y
, XML_PRIMARY_Y
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasYAxisTitle
, bHasYAxisMajorGrid
, bHasYAxisMinorGrid
, bExportContent
, sChartType
);
2565 xNewAxis
= lcl_getAxis( xCooSys
, XML_Y
, false );
2568 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY
);
2569 exportAxis( XML_Y
, XML_SECONDARY_Y
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasSecondaryYAxisTitle
, false, false, bExportContent
, sChartType
);
2574 xNewAxis
= lcl_getAxis( xCooSys
, XML_Z
);
2577 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getAxis(2) : nullptr, uno::UNO_QUERY
);
2578 exportAxis( XML_Z
, XML_PRIMARY_Z
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasZAxisTitle
, bHasZAxisMajorGrid
, bHasZAxisMinorGrid
, bExportContent
, sChartType
);
2584 bool lcl_hasNoValuesButText( const uno::Reference
< chart2::data::XDataSequence
>& xDataSequence
)
2586 if( !xDataSequence
.is() )
2587 return false;//have no data
2589 Sequence
< uno::Any
> aData
;
2590 Reference
< chart2::data::XNumericalDataSequence
> xNumericalDataSequence( xDataSequence
, uno::UNO_QUERY
);
2591 if( xNumericalDataSequence
.is() )
2593 const Sequence
< double > aDoubles( xNumericalDataSequence
->getNumericalData() );
2594 if (std::any_of(aDoubles
.begin(), aDoubles
.end(), [](double fDouble
) { return !std::isnan( fDouble
); }))
2595 return false;//have double value
2599 aData
= xDataSequence
->getData();
2600 double fDouble
= 0.0;
2601 bool bHaveDouble
= std::any_of(std::cbegin(aData
), std::cend(aData
),
2602 [&fDouble
](const uno::Any
& rData
) { return (rData
>>= fDouble
) && !std::isnan( fDouble
); });
2604 return false;//have double value
2608 Reference
< chart2::data::XTextualDataSequence
> xTextualDataSequence( xDataSequence
, uno::UNO_QUERY
);
2609 if( xTextualDataSequence
.is() )
2611 const uno::Sequence
< OUString
> aStrings( xTextualDataSequence
->getTextualData() );
2612 if (std::any_of(aStrings
.begin(), aStrings
.end(), [](const OUString
& rString
) { return !rString
.isEmpty(); }))
2613 return true;//have text
2617 if( !aData
.hasElements() )
2618 aData
= xDataSequence
->getData();
2620 bool bHaveText
= std::any_of(std::cbegin(aData
), std::cend(aData
),
2621 [&aString
](const uno::Any
& rData
) { return (rData
>>= aString
) && !aString
.isEmpty(); });
2623 return true;//have text
2625 //no doubles and no texts
2629 // ODF has the line and fill properties in a <style:style> element, which is referenced by the
2630 // <chart:data-label> element. But LibreOffice has them as special label properties of the series
2631 // or point respectively. The following method generates ODF from internal API name.
2632 void lcl_createDataLabelProperties(
2633 std::vector
<XMLPropertyState
>& rDataLabelPropertyStates
,
2634 const Reference
<beans::XPropertySet
>& xPropSet
,
2635 const rtl::Reference
<XMLChartExportPropertyMapper
>& xExpPropMapper
)
2637 if (!xExpPropMapper
.is() || !xPropSet
.is())
2640 const uno::Reference
<beans::XPropertySetInfo
> xInfo(xPropSet
->getPropertySetInfo());
2641 const uno::Reference
<beans::XPropertyState
> xPropState(xPropSet
, uno::UNO_QUERY
);
2642 const rtl::Reference
<XMLPropertySetMapper
>& rPropertySetMapper(
2643 xExpPropMapper
->getPropertySetMapper());
2644 if (!xInfo
.is() || !xPropState
.is() || !rPropertySetMapper
.is())
2647 struct API2ODFMapItem
2650 sal_uInt16 nNameSpace
; // from include/xmloff/xmlnamespace.hxx
2651 OUString sLocalName
;
2652 API2ODFMapItem(OUString sAPI
, const sal_uInt16 nNS
, OUString sLocal
)
2653 : sAPIName(std::move(sAPI
))
2655 , sLocalName(std::move(sLocal
))
2660 const API2ODFMapItem aLabelFoo2ODFArray
[]
2661 = { API2ODFMapItem("LabelBorderStyle", XML_NAMESPACE_DRAW
, "stroke"),
2662 API2ODFMapItem("LabelBorderWidth", XML_NAMESPACE_SVG
, "stroke-width"),
2663 API2ODFMapItem("LabelBorderColor", XML_NAMESPACE_SVG
, "stroke-color"),
2664 API2ODFMapItem("LabelBorderDashName", XML_NAMESPACE_DRAW
, "stroke-dash"),
2665 API2ODFMapItem("LabelBorderTransparency", XML_NAMESPACE_SVG
, "stroke-opacity"),
2666 API2ODFMapItem("LabelFillStyle", XML_NAMESPACE_DRAW
, "fill"),
2667 API2ODFMapItem("LabelFillBackground", XML_NAMESPACE_DRAW
, "fill-hatch-solid"),
2668 API2ODFMapItem("LabelFillHatchName", XML_NAMESPACE_DRAW
, "fill-hatch-name"),
2669 API2ODFMapItem("LabelFillColor", XML_NAMESPACE_DRAW
, "fill-color") };
2671 for (const auto& rIt
: aLabelFoo2ODFArray
)
2673 if (!xInfo
->hasPropertyByName(rIt
.sAPIName
)
2674 || xPropState
->getPropertyState(rIt
.sAPIName
) != beans::PropertyState_DIRECT_VALUE
)
2676 sal_Int32 nTargetIndex
2677 = rPropertySetMapper
->GetEntryIndex(rIt
.nNameSpace
, rIt
.sLocalName
, 0);
2678 if (nTargetIndex
< 0)
2680 XMLPropertyState
aDataLabelStateItem(nTargetIndex
,
2681 xPropSet
->getPropertyValue(rIt
.sAPIName
));
2682 rDataLabelPropertyStates
.emplace_back(aDataLabelStateItem
);
2685 } // anonymous namespace
2687 void SchXMLExportHelper_Impl::exportSeries(
2688 const Reference
< chart2::XDiagram
> & xNewDiagram
,
2689 const awt::Size
& rPageSize
,
2690 bool bExportContent
,
2693 Reference
< chart2::XCoordinateSystemContainer
> xBCooSysCnt( xNewDiagram
, uno::UNO_QUERY
);
2694 if( ! xBCooSysCnt
.is())
2696 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
2698 OUString aFirstXDomainRange
;
2699 OUString aFirstYDomainRange
;
2701 std::vector
< XMLPropertyState
> aPropertyStates
;
2702 std::vector
< XMLPropertyState
> aDataLabelPropertyStates
;
2704 const Sequence
< Reference
< chart2::XCoordinateSystem
> >
2705 aCooSysSeq( xBCooSysCnt
->getCoordinateSystems());
2706 for( const auto& rCooSys
: aCooSysSeq
)
2708 Reference
< chart2::XChartTypeContainer
> xCTCnt( rCooSys
, uno::UNO_QUERY
);
2711 const Sequence
< Reference
< chart2::XChartType
> > aCTSeq( xCTCnt
->getChartTypes());
2712 for( const auto& rChartType
: aCTSeq
)
2714 Reference
< chart2::XDataSeriesContainer
> xDSCnt( rChartType
, uno::UNO_QUERY
);
2717 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
2718 OUString
aChartType( rChartType
->getChartType());
2719 OUString aLabelRole
= rChartType
->getRoleOfSequenceForSeriesLabel();
2721 // special export for stock charts
2722 if ( aChartType
== "com.sun.star.chart2.CandleStickChartType" )
2724 bool bJapaneseCandleSticks
= false;
2725 Reference
< beans::XPropertySet
> xCTProp( rChartType
, uno::UNO_QUERY
);
2727 xCTProp
->getPropertyValue("Japanese") >>= bJapaneseCandleSticks
;
2728 exportCandleStickSeries(
2729 xDSCnt
->getDataSeries(), xNewDiagram
, bJapaneseCandleSticks
, bExportContent
);
2733 // export dataseries for current chart-type
2734 Sequence
< Reference
< chart2::XDataSeries
> > aSeriesSeq( xDSCnt
->getDataSeries());
2735 for( sal_Int32 nSeriesIdx
=0; nSeriesIdx
<aSeriesSeq
.getLength(); ++nSeriesIdx
)
2738 Reference
< chart2::data::XDataSource
> xSource( aSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
);
2741 std::unique_ptr
<SvXMLElementExport
> pSeries
;
2742 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
2743 xSource
->getDataSequences());
2744 sal_Int32 nMainSequenceIndex
= -1;
2745 sal_Int32 nSeriesLength
= 0;
2746 bool bHasMeanValueLine
= false;
2747 Reference
< beans::XPropertySet
> xPropSet
;
2748 tLabelValuesDataPair aSeriesLabelValuesPair
;
2750 // search for main sequence and create a series element
2752 Reference
< chart2::data::XDataSequence
> xValuesSeq
;
2753 Reference
< chart2::data::XDataSequence
> xLabelSeq
;
2754 sal_Int32 nSeqIdx
=0;
2755 for( ; nSeqIdx
<aSeqCnt
.getLength(); ++nSeqIdx
)
2757 Reference
< chart2::data::XDataSequence
> xTempValueSeq( aSeqCnt
[nSeqIdx
]->getValues() );
2758 if( nMainSequenceIndex
==-1 )
2761 Reference
< beans::XPropertySet
> xSeqProp( xTempValueSeq
, uno::UNO_QUERY
);
2763 xSeqProp
->getPropertyValue("Role") >>= aRole
;
2765 if( aRole
== aLabelRole
)
2767 xValuesSeq
.set( xTempValueSeq
);
2768 xLabelSeq
.set( aSeqCnt
[nSeqIdx
]->getLabel());
2769 nMainSequenceIndex
= nSeqIdx
;
2772 sal_Int32 nSequenceLength
= (xTempValueSeq
.is()? xTempValueSeq
->getData().getLength() : sal_Int32(0));
2773 if( nSeriesLength
< nSequenceLength
)
2774 nSeriesLength
= nSequenceLength
;
2777 // have found the main sequence, then xValuesSeq and
2778 // xLabelSeq contain those. Otherwise both are empty
2780 sal_Int32 nAttachedAxis
= chart::ChartAxisAssign::PRIMARY_Y
;
2781 // get property states for autostyles
2784 xPropSet
= SchXMLSeriesHelper::createOldAPISeriesPropertySet(
2785 aSeriesSeq
[nSeriesIdx
], mrExport
.GetModel() );
2787 catch( const uno::Exception
& )
2789 TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" );
2794 // determine attached axis
2797 Any
aAny( xPropSet
->getPropertyValue( "Axis" ));
2798 aAny
>>= nAttachedAxis
;
2800 aAny
= xPropSet
->getPropertyValue( "MeanValue" );
2801 aAny
>>= bHasMeanValueLine
;
2803 catch( const beans::UnknownPropertyException
& )
2805 TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
2808 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2809 mrExport
.getSaneDefaultVersion());
2810 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
2812 lcl_exportNumberFormat( "NumberFormat", xPropSet
, mrExport
);
2813 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet
, mrExport
);
2816 if( mxExpPropMapper
.is())
2817 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
2820 if( bExportContent
)
2824 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
2825 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
2827 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
2831 AddAutoStyleAttribute( aPropertyStates
);
2833 if( xValuesSeq
.is())
2834 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
,
2836 xValuesSeq
->getSourceRangeRepresentation(),
2839 // #i75297# allow empty series, export empty range to have all ranges on import
2840 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, OUString());
2842 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2843 mrExport
.getSaneDefaultVersion());
2844 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) // do not export to ODF 1.3 or older
2848 Any aAny
= xPropSet
->getPropertyValue("ShowLegendEntry");
2849 if (!aAny
.get
<bool>())
2851 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_HIDE_LEGEND
, OUString::boolean(true));
2858 // Check if the label is direct string value rather than a reference.
2859 bool bHasString
= false;
2860 uno::Reference
<beans::XPropertySet
> xLSProp(xLabelSeq
, uno::UNO_QUERY
);
2865 xLSProp
->getPropertyValue("HasStringLabel") >>= bHasString
;
2867 catch (const beans::UnknownPropertyException
&) {}
2870 OUString aRange
= xLabelSeq
->getSourceRangeRepresentation();
2874 mrExport
.AddAttribute(
2875 XML_NAMESPACE_LO_EXT
, XML_LABEL_STRING
, aRange
);
2879 mrExport
.AddAttribute(
2880 XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
,
2882 xLabelSeq
->getSourceRangeRepresentation(), xNewDoc
));
2886 if( xLabelSeq
.is() || xValuesSeq
.is() )
2887 aSeriesLabelValuesPair
= tLabelValuesDataPair( xLabelSeq
, xValuesSeq
);
2889 // chart-type for mixed types
2890 enum XMLTokenEnum
eCTToken(
2891 SchXMLTools::getTokenByChartType( aChartType
, false /* bUseOldNames */ ));
2892 //@todo: get token for current charttype
2893 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_CLASS
,
2894 mrExport
.GetNamespaceMap().GetQNameByKey(
2895 XML_NAMESPACE_CHART
, GetXMLToken( eCTToken
)));
2897 // open series element until end of for loop
2898 pSeries
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true ));
2902 CollectAutoStyle( std::move(aPropertyStates
) );
2904 // remove property states for autostyles
2905 aPropertyStates
.clear();
2909 // export domain elements if we have a series parent element
2913 if( bExportContent
)
2915 bool bIsScatterChart
= aChartType
== "com.sun.star.chart2.ScatterChartType";
2916 bool bIsBubbleChart
= aChartType
== "com.sun.star.chart2.BubbleChartType";
2917 Reference
< chart2::data::XDataSequence
> xYValuesForBubbleChart
;
2918 if( bIsBubbleChart
)
2920 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, "values-y" ) );
2921 if( xSequence
.is() )
2923 xYValuesForBubbleChart
= xSequence
->getValues();
2924 if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart
, aFirstYDomainRange
, mrExport
) )
2925 xYValuesForBubbleChart
= nullptr;
2928 if( bIsScatterChart
|| bIsBubbleChart
)
2930 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, "values-x" ) );
2931 if( xSequence
.is() )
2933 Reference
< chart2::data::XDataSequence
> xValues( xSequence
->getValues() );
2934 if( lcl_exportDomainForThisSequence( xValues
, aFirstXDomainRange
, mrExport
) )
2935 m_aDataSequencesToExport
.emplace_back(
2936 uno::Reference
< chart2::data::XDataSequence
>(), xValues
);
2938 else if( nSeriesIdx
==0 )
2940 //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly
2941 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( xNewDiagram
) );
2942 if( xCategories
.is() )
2944 Reference
< chart2::data::XDataSequence
> xValues( xCategories
->getValues() );
2945 if( !lcl_hasNoValuesButText( xValues
) )
2946 lcl_exportDomainForThisSequence( xValues
, aFirstXDomainRange
, mrExport
);
2950 if( xYValuesForBubbleChart
.is() )
2951 m_aDataSequencesToExport
.emplace_back(
2952 uno::Reference
< chart2::data::XDataSequence
>(), xYValuesForBubbleChart
);
2956 // add sequences for main sequence after domain sequences,
2957 // so that the export of the local table has the correct order
2958 if( bExportContent
&&
2959 (aSeriesLabelValuesPair
.first
.is() || aSeriesLabelValuesPair
.second
.is()))
2960 m_aDataSequencesToExport
.push_back( aSeriesLabelValuesPair
);
2962 // statistical objects:
2963 // regression curves and mean value lines
2964 if( bHasMeanValueLine
&&
2966 mxExpPropMapper
.is() )
2968 Reference
< beans::XPropertySet
> xStatProp
;
2971 Any
aPropAny( xPropSet
->getPropertyValue( "DataMeanValueProperties" ));
2972 aPropAny
>>= xStatProp
;
2974 catch( const uno::Exception
& )
2976 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" );
2979 if( xStatProp
.is() )
2981 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStatProp
);
2983 if( !aPropertyStates
.empty() )
2986 if( bExportContent
)
2988 // add style name attribute
2989 AddAutoStyleAttribute( aPropertyStates
);
2991 SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_MEAN_VALUE
, true, true );
2995 CollectAutoStyle( std::move(aPropertyStates
) );
3001 if( xPropSet
.is() &&
3002 mxExpPropMapper
.is() )
3004 exportRegressionCurve( aSeriesSeq
[nSeriesIdx
], rPageSize
, bExportContent
);
3007 exportErrorBar( xPropSet
,false, bExportContent
); // X ErrorBar
3008 exportErrorBar( xPropSet
,true, bExportContent
); // Y ErrorBar
3011 uno::Reference
< beans::XPropertySet
>( aSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
),
3012 nSeriesLength
, xNewDiagram
, bExportContent
);
3014 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3015 mrExport
.getSaneDefaultVersion());
3017 // create <chart:data-label> child element if needed.
3018 if (xPropSet
.is() && mxExpPropMapper
.is())
3020 // Generate style for <chart:data-label> child element
3021 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3023 lcl_createDataLabelProperties(aDataLabelPropertyStates
, xPropSet
,
3029 if (!aDataLabelPropertyStates
.empty())
3032 AddAutoStyleAttribute(aDataLabelPropertyStates
);
3033 // Further content does currently not exist for a <chart:data-label>
3034 // element as child of a <chart:series>.
3035 SvXMLElementExport(mrExport
, XML_NAMESPACE_CHART
, XML_DATA_LABEL
, true,
3041 // add the style for the to be <chart:data-label> too
3042 if (!aDataLabelPropertyStates
.empty())
3043 CollectAutoStyle(std::move(aDataLabelPropertyStates
));
3045 aDataLabelPropertyStates
.clear();
3047 if (bExportContent
&& nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) // do not export to ODF 1.3 or older
3049 Sequence
< OUString
> aSupportedMappings
= rChartType
->getSupportedPropertyRoles();
3050 exportPropertyMapping( xSource
, aSupportedMappings
);
3053 // close series element
3057 aPropertyStates
.clear();
3058 aDataLabelPropertyStates
.clear();
3063 void SchXMLExportHelper_Impl::exportPropertyMapping(
3064 const Reference
< chart2::data::XDataSource
> & xSource
, const Sequence
< OUString
>& rSupportedMappings
)
3066 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
3067 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
3068 xSource
->getDataSequences());
3070 for(const auto& rSupportedMapping
: rSupportedMappings
)
3072 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, rSupportedMapping
) );
3075 Reference
< chart2::data::XDataSequence
> xValues( xSequence
->getValues() );
3078 mrExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_PROPERTY
, rSupportedMapping
);
3079 mrExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_CELL_RANGE_ADDRESS
,
3081 xValues
->getSourceRangeRepresentation(),
3083 SvXMLElementExport( mrExport
, XML_NAMESPACE_LO_EXT
, XML_PROPERTY_MAPPING
, true, true );
3085 // register range for data table export
3086 m_aDataSequencesToExport
.emplace_back(
3087 uno::Reference
< chart2::data::XDataSequence
>(), xValues
);
3093 void SchXMLExportHelper_Impl::exportRegressionCurve(
3094 const Reference
< chart2::XDataSeries
>& xSeries
,
3095 const awt::Size
& rPageSize
,
3096 bool bExportContent
)
3098 OSL_ASSERT( mxExpPropMapper
.is());
3100 Reference
< chart2::XRegressionCurveContainer
> xRegressionCurveContainer( xSeries
, uno::UNO_QUERY
);
3101 if( !xRegressionCurveContainer
.is() )
3104 const Sequence
< Reference
< chart2::XRegressionCurve
> > aRegCurveSeq
= xRegressionCurveContainer
->getRegressionCurves();
3106 for( const auto& xRegCurve
: aRegCurveSeq
)
3108 std::vector
< XMLPropertyState
> aEquationPropertyStates
;
3109 if (!xRegCurve
.is())
3112 Reference
< beans::XPropertySet
> xProperties( xRegCurve
, uno::UNO_QUERY
);
3113 if( !xProperties
.is() )
3116 Reference
< lang::XServiceName
> xServiceName( xProperties
, uno::UNO_QUERY
);
3117 if( !xServiceName
.is() )
3120 bool bShowEquation
= false;
3121 bool bShowRSquared
= false;
3122 bool bExportEquation
= false;
3124 OUString aService
= xServiceName
->getServiceName();
3126 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xProperties
);
3128 // Add service name (which is regression type)
3129 sal_Int32 nIndex
= GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE
);
3130 XMLPropertyState
property(nIndex
, uno::Any(aService
));
3131 aPropertyStates
.push_back(property
);
3133 Reference
< beans::XPropertySet
> xEquationProperties
;
3134 xEquationProperties
.set( xRegCurve
->getEquationProperties() );
3135 if( xEquationProperties
.is())
3137 xEquationProperties
->getPropertyValue( "ShowEquation") >>= bShowEquation
;
3138 xEquationProperties
->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowRSquared
;
3140 bExportEquation
= ( bShowEquation
|| bShowRSquared
);
3141 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentVersion(
3142 mrExport
.getSaneDefaultVersion());
3143 if (nCurrentVersion
< SvtSaveOptions::ODFSVER_012
)
3145 bExportEquation
=false;
3147 if( bExportEquation
)
3150 sal_Int32 nNumberFormat
= 0;
3151 if( (xEquationProperties
->getPropertyValue("NumberFormat") >>= nNumberFormat
) &&
3152 nNumberFormat
!= -1 )
3154 mrExport
.addDataStyle( nNumberFormat
);
3156 aEquationPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xEquationProperties
);
3160 if( !aPropertyStates
.empty() || bExportEquation
)
3163 if( bExportContent
)
3165 // add style name attribute
3166 if( !aPropertyStates
.empty())
3168 AddAutoStyleAttribute( aPropertyStates
);
3171 SvXMLElementExport
aRegressionExport( mrExport
, XML_NAMESPACE_CHART
, XML_REGRESSION_CURVE
, true, true );
3172 if( bExportEquation
)
3174 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DISPLAY_EQUATION
, (bShowEquation
? XML_TRUE
: XML_FALSE
) );
3175 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DISPLAY_R_SQUARE
, (bShowRSquared
? XML_TRUE
: XML_FALSE
) );
3178 chart2::RelativePosition aRelativePosition
;
3179 if( xEquationProperties
->getPropertyValue( "RelativePosition" ) >>= aRelativePosition
)
3181 double fX
= aRelativePosition
.Primary
* rPageSize
.Width
;
3182 double fY
= aRelativePosition
.Secondary
* rPageSize
.Height
;
3184 aPos
.X
= static_cast< sal_Int32
>( ::rtl::math::round( fX
));
3185 aPos
.Y
= static_cast< sal_Int32
>( ::rtl::math::round( fY
));
3186 addPosition( aPos
);
3189 if( !aEquationPropertyStates
.empty())
3191 AddAutoStyleAttribute( aEquationPropertyStates
);
3194 SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_EQUATION
, true, true );
3199 if( !aPropertyStates
.empty())
3201 CollectAutoStyle( std::move(aPropertyStates
) );
3203 if( bExportEquation
&& !aEquationPropertyStates
.empty())
3205 CollectAutoStyle( std::move(aEquationPropertyStates
) );
3212 void SchXMLExportHelper_Impl::exportErrorBar( const Reference
<beans::XPropertySet
> &xSeriesProp
,
3213 bool bYError
, bool bExportContent
)
3215 assert(mxExpPropMapper
.is());
3217 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentVersion(
3218 mrExport
.getSaneDefaultVersion());
3220 /// Don't export X ErrorBars for older ODF versions.
3221 if (!bYError
&& nCurrentVersion
< SvtSaveOptions::ODFSVER_012
)
3224 if (!xSeriesProp
.is())
3227 bool bNegative
= false, bPositive
= false;
3228 sal_Int32 nErrorBarStyle
= chart::ErrorBarStyle::NONE
;
3229 Reference
< beans::XPropertySet
> xErrorBarProp
;
3233 Any aAny
= xSeriesProp
->getPropertyValue( bYError
? OUString("ErrorBarY") : OUString("ErrorBarX") );
3234 aAny
>>= xErrorBarProp
;
3236 if ( xErrorBarProp
.is() )
3238 aAny
= xErrorBarProp
->getPropertyValue("ShowNegativeError" );
3241 aAny
= xErrorBarProp
->getPropertyValue("ShowPositiveError" );
3244 aAny
= xErrorBarProp
->getPropertyValue("ErrorBarStyle" );
3245 aAny
>>= nErrorBarStyle
;
3248 catch( const beans::UnknownPropertyException
& )
3250 TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
3253 if( !(nErrorBarStyle
!= chart::ErrorBarStyle::NONE
&& (bNegative
|| bPositive
)))
3256 if( bExportContent
&& nErrorBarStyle
== chart::ErrorBarStyle::FROM_DATA
)
3258 // register data ranges for error bars for export in local table
3259 ::std::vector
< Reference
< chart2::data::XDataSequence
> > aErrorBarSequences(
3260 lcl_getErrorBarSequences( xErrorBarProp
));
3261 for( const auto& rErrorBarSequence
: aErrorBarSequences
)
3263 m_aDataSequencesToExport
.emplace_back(
3264 uno::Reference
< chart2::data::XDataSequence
>(), rErrorBarSequence
);
3268 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xErrorBarProp
);
3270 if( aPropertyStates
.empty() )
3274 if( bExportContent
)
3276 // add style name attribute
3277 AddAutoStyleAttribute( aPropertyStates
);
3279 if (nCurrentVersion
>= SvtSaveOptions::ODFSVER_012
)
3280 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DIMENSION
, bYError
? XML_Y
: XML_X
);//#i114149#
3281 SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_ERROR_INDICATOR
, true, true );
3285 CollectAutoStyle( std::move(aPropertyStates
) );
3289 void SchXMLExportHelper_Impl::exportCandleStickSeries(
3290 const Sequence
< Reference
< chart2::XDataSeries
> > & aSeriesSeq
,
3291 const Reference
< chart2::XDiagram
> & xDiagram
,
3292 bool bJapaneseCandleSticks
,
3293 bool bExportContent
)
3296 for( const auto& xSeries
: aSeriesSeq
)
3298 sal_Int32 nAttachedAxis
= lcl_isSeriesAttachedToFirstAxis( xSeries
)
3299 ? chart::ChartAxisAssign::PRIMARY_Y
3300 : chart::ChartAxisAssign::SECONDARY_Y
;
3302 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
3305 // export series in correct order (as we don't store roles)
3306 // with japanese candlesticks: open, low, high, close
3307 // otherwise: low, high, close
3308 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
3309 xSource
->getDataSequences());
3311 sal_Int32 nSeriesLength
=
3312 lcl_getSequenceLengthByRole( aSeqCnt
, "values-last");
3314 if( bExportContent
)
3316 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
3317 //@todo: export data points
3319 //TODO: moggi: same code three times
3321 if( bJapaneseCandleSticks
)
3323 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3324 aSeqCnt
, "values-first", xNewDoc
, m_aDataSequencesToExport
));
3325 if( !aRanges
.second
.isEmpty())
3326 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3327 if( !aRanges
.first
.isEmpty())
3328 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3329 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3330 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3332 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3333 SvXMLElementExport
aOpenSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3334 // export empty data points
3335 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3340 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3341 aSeqCnt
, "values-min", xNewDoc
, m_aDataSequencesToExport
));
3342 if( !aRanges
.second
.isEmpty())
3343 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3344 if( !aRanges
.first
.isEmpty())
3345 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3346 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3347 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3349 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3350 SvXMLElementExport
aLowSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3351 // export empty data points
3352 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3357 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3358 aSeqCnt
, "values-max", xNewDoc
, m_aDataSequencesToExport
));
3359 if( !aRanges
.second
.isEmpty())
3360 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3361 if( !aRanges
.first
.isEmpty())
3362 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3363 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3364 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3366 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3367 SvXMLElementExport
aHighSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3368 // export empty data points
3369 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3374 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3375 aSeqCnt
, "values-last", xNewDoc
, m_aDataSequencesToExport
));
3376 if( !aRanges
.second
.isEmpty())
3377 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3378 if( !aRanges
.first
.isEmpty())
3379 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3380 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3381 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3383 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3384 SvXMLElementExport
aCloseSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3385 // export empty data points
3386 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3393 // remove property states for autostyles
3398 void SchXMLExportHelper_Impl::exportDataPoints(
3399 const uno::Reference
< beans::XPropertySet
> & xSeriesProperties
,
3400 sal_Int32 nSeriesLength
,
3401 const uno::Reference
< chart2::XDiagram
> & xDiagram
,
3402 bool bExportContent
)
3406 // write data-points only if they contain autostyles
3407 // objects with equal autostyles are grouped using the attribute
3410 // Note: if only the nth data-point has autostyles there is an element
3411 // without style and repeat="n-1" attribute written in advance.
3413 // the sequence aDataPointSeq contains indices of data-points that
3414 // do have own attributes. This increases the performance substantially.
3416 // more performant version for #93600#
3417 if (!mxExpPropMapper
.is())
3420 uno::Reference
< chart2::XDataSeries
> xSeries( xSeriesProperties
, uno::UNO_QUERY
);
3422 std::vector
< XMLPropertyState
> aPropertyStates
;
3423 std::vector
<XMLPropertyState
> aDataLabelPropertyStates
;
3425 bool bVaryColorsByPoint
= false;
3426 Sequence
< sal_Int32
> aDataPointSeq
;
3427 Sequence
<sal_Int32
> deletedLegendEntriesSeq
;
3428 if( xSeriesProperties
.is())
3430 xSeriesProperties
->getPropertyValue("AttributedDataPoints") >>= aDataPointSeq
;
3431 xSeriesProperties
->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint
;
3433 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3434 mrExport
.getSaneDefaultVersion());
3435 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) // do not export to ODF 1.3 or older
3436 xSeriesProperties
->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq
;
3439 sal_Int32 nSize
= aDataPointSeq
.getLength();
3440 SAL_WARN_IF( nSize
> nSeriesLength
, "xmloff.chart", "Too many point attributes" );
3442 const sal_Int32
* pPoints
= aDataPointSeq
.getConstArray();
3444 Reference
< chart2::XColorScheme
> xColorScheme
;
3446 xColorScheme
.set( xDiagram
->getDefaultColorScheme());
3448 ::std::vector
< SchXMLDataPointStruct
> aDataPointVector
;
3450 sal_Int32 nLastIndex
= -1;
3453 if( bVaryColorsByPoint
&& xColorScheme
.is() )
3455 o3tl::sorted_vector
< sal_Int32
> aAttrPointSet
;
3456 aAttrPointSet
.reserve(aDataPointSeq
.getLength());
3457 for (auto p
= pPoints
; p
< pPoints
+ aDataPointSeq
.getLength(); ++p
)
3458 aAttrPointSet
.insert( *p
);
3459 const auto aEndIt
= aAttrPointSet
.end();
3460 for( nElement
= 0; nElement
< nSeriesLength
; ++nElement
)
3462 aPropertyStates
.clear();
3463 aDataLabelPropertyStates
.clear();
3464 uno::Reference
< beans::XPropertySet
> xPropSet
;
3465 bool bExportNumFmt
= false;
3466 if( aAttrPointSet
.find( nElement
) != aEndIt
)
3470 xPropSet
= SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3471 xSeries
, nElement
, mrExport
.GetModel() );
3472 bExportNumFmt
= true;
3474 catch( const uno::Exception
& )
3476 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3481 // property set only containing the color
3482 xPropSet
.set( new ::xmloff::chart::ColorPropertySet(
3483 ::Color(ColorTransparency
, xColorScheme
->getColorByIndex( nElement
))));
3485 SAL_WARN_IF( !xPropSet
.is(), "xmloff.chart", "Pie Segments should have properties" );
3488 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3489 mrExport
.getSaneDefaultVersion());
3490 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
&& bExportNumFmt
)
3492 lcl_exportNumberFormat( "NumberFormat", xPropSet
, mrExport
);
3493 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet
, mrExport
);
3496 // Generate style for <chart:data-label> child element
3497 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3499 lcl_createDataLabelProperties(aDataLabelPropertyStates
, xPropSet
,
3503 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
3505 sal_Int32 nPlacement
= 0;
3506 xPropSet
->getPropertyValue("LabelPlacement") >>= nPlacement
;
3507 if (nPlacement
== chart::DataLabelPlacement::CUSTOM
)
3509 xPropSet
->setPropertyValue("LabelPlacement",
3510 uno::Any(chart::DataLabelPlacement::OUTSIDE
));
3514 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
3515 if (!aPropertyStates
.empty() || !aDataLabelPropertyStates
.empty())
3519 // write data-point with style
3520 SchXMLDataPointStruct aPoint
;
3521 if (!aPropertyStates
.empty())
3523 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3524 "Autostyle queue empty!");
3525 aPoint
.maStyleName
= maAutoStyleNameQueue
.front();
3526 maAutoStyleNameQueue
.pop();
3528 if (!aDataLabelPropertyStates
.empty())
3530 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3531 "Autostyle queue empty!");
3532 aPoint
.msDataLabelStyleName
= maAutoStyleNameQueue
.front();
3533 maAutoStyleNameQueue
.pop();
3536 aPoint
.mCustomLabel
= lcl_getCustomLabelField(mrExport
, nElement
, xSeries
);
3537 aPoint
.mCustomLabelPos
= lcl_getCustomLabelPosition(mrExport
, nElement
, xSeries
);
3539 aDataPointVector
.push_back( aPoint
);
3543 if (!aPropertyStates
.empty())
3544 CollectAutoStyle(std::move(aPropertyStates
));
3545 if (!aDataLabelPropertyStates
.empty())
3546 CollectAutoStyle(std::move(aDataLabelPropertyStates
));
3551 SAL_WARN_IF( bExportContent
&& (static_cast<sal_Int32
>(aDataPointVector
.size()) != nSeriesLength
), "xmloff.chart", "not enough data points on content export" );
3555 for( sal_Int32 nCurrIndex
: std::as_const(aDataPointSeq
) )
3557 aPropertyStates
.clear();
3558 aDataLabelPropertyStates
.clear();
3559 //assuming sorted indices in pPoints
3561 if( nCurrIndex
<0 || nCurrIndex
>=nSeriesLength
)
3564 // write leading empty data points
3565 if( nCurrIndex
- nLastIndex
> 1 )
3567 SchXMLDataPointStruct aPoint
;
3568 aPoint
.mnRepeat
= nCurrIndex
- nLastIndex
- 1;
3569 aDataPointVector
.push_back( aPoint
);
3572 uno::Reference
< beans::XPropertySet
> xPropSet
;
3573 // get property states
3576 xPropSet
= SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3577 xSeries
, nCurrIndex
, mrExport
.GetModel() );
3579 catch( const uno::Exception
& )
3581 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3585 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3586 mrExport
.getSaneDefaultVersion());
3587 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3589 lcl_exportNumberFormat( "NumberFormat", xPropSet
, mrExport
);
3590 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet
, mrExport
);
3593 // Generate style for <chart:data-label> child element
3594 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3596 lcl_createDataLabelProperties(aDataLabelPropertyStates
, xPropSet
,
3600 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
3602 if (!aPropertyStates
.empty() || !aDataLabelPropertyStates
.empty())
3604 if( bExportContent
)
3606 // write data-point with style
3607 SchXMLDataPointStruct aPoint
;
3608 if (!aPropertyStates
.empty())
3610 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3611 "Autostyle queue empty!");
3612 aPoint
.maStyleName
= maAutoStyleNameQueue
.front();
3613 maAutoStyleNameQueue
.pop();
3615 aPoint
.mCustomLabel
= lcl_getCustomLabelField(mrExport
, nCurrIndex
, xSeries
);
3616 aPoint
.mCustomLabelPos
= lcl_getCustomLabelPosition(mrExport
, nCurrIndex
, xSeries
);
3617 if (!aDataLabelPropertyStates
.empty())
3619 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3620 "Autostyle queue empty!");
3621 aPoint
.msDataLabelStyleName
= maAutoStyleNameQueue
.front();
3622 maAutoStyleNameQueue
.pop();
3625 aDataPointVector
.push_back( aPoint
);
3626 nLastIndex
= nCurrIndex
;
3630 if (!aPropertyStates
.empty())
3631 CollectAutoStyle(std::move(aPropertyStates
));
3632 if (!aDataLabelPropertyStates
.empty())
3633 CollectAutoStyle(std::move(aDataLabelPropertyStates
));
3639 // if we get here the property states are empty
3640 SchXMLDataPointStruct aPoint
;
3641 aDataPointVector
.push_back( aPoint
);
3643 nLastIndex
= nCurrIndex
;
3645 // final empty elements
3646 sal_Int32 nRepeat
= nSeriesLength
- nLastIndex
- 1;
3649 SchXMLDataPointStruct aPoint
;
3650 aPoint
.mnRepeat
= nRepeat
;
3651 aDataPointVector
.push_back( aPoint
);
3655 if (!bExportContent
)
3658 // write elements (merge equal ones)
3659 SchXMLDataPointStruct aPoint
;
3660 SchXMLDataPointStruct aLastPoint
;
3662 // initialize so that it doesn't matter if
3663 // the element is counted in the first iteration
3664 aLastPoint
.mnRepeat
= 0;
3665 sal_Int32 nIndex
= 0;
3666 for( const auto& rPoint
: aDataPointVector
)
3670 if (aPoint
.maStyleName
== aLastPoint
.maStyleName
3671 && aLastPoint
.mCustomLabel
.maFields
.getLength() < 1
3672 && aLastPoint
.mCustomLabelPos
.Primary
== 0.0
3673 && aLastPoint
.mCustomLabelPos
.Secondary
== 0.0
3674 && aPoint
.msDataLabelStyleName
== aLastPoint
.msDataLabelStyleName
)
3675 aPoint
.mnRepeat
+= aLastPoint
.mnRepeat
;
3676 else if( aLastPoint
.mnRepeat
> 0 )
3678 // write last element
3679 if( !aLastPoint
.maStyleName
.isEmpty() )
3680 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_STYLE_NAME
, aLastPoint
.maStyleName
);
3682 if( aLastPoint
.mnRepeat
> 1 )
3683 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_REPEATED
,
3684 OUString::number( aLastPoint
.mnRepeat
));
3686 for (const auto& deletedLegendEntry
: std::as_const(deletedLegendEntriesSeq
))
3688 if (nIndex
== deletedLegendEntry
)
3690 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_HIDE_LEGEND
, OUString::boolean(true));
3695 exportCustomLabelPosition(aLastPoint
.mCustomLabelPos
); // adds attributes
3696 SvXMLElementExport
aPointElem( mrExport
, XML_NAMESPACE_CHART
, XML_DATA_POINT
, true, true );
3697 exportCustomLabel(aLastPoint
);
3699 aLastPoint
= aPoint
;
3701 // write last element if it hasn't been written in last iteration
3702 if( aPoint
.maStyleName
!= aLastPoint
.maStyleName
)
3705 if( !aLastPoint
.maStyleName
.isEmpty() )
3706 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_STYLE_NAME
, aLastPoint
.maStyleName
);
3708 if( aLastPoint
.mnRepeat
> 1 )
3709 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_REPEATED
,
3710 OUString::number( aLastPoint
.mnRepeat
));
3712 for (const auto& deletedLegendEntry
: std::as_const(deletedLegendEntriesSeq
))
3714 if (nIndex
== deletedLegendEntry
)
3716 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_HIDE_LEGEND
, OUString::boolean(true));
3721 exportCustomLabelPosition(aLastPoint
.mCustomLabelPos
); // adds attributes
3722 SvXMLElementExport
aPointElem( mrExport
, XML_NAMESPACE_CHART
, XML_DATA_POINT
, true, true );
3723 exportCustomLabel(aLastPoint
);
3726 void SchXMLExportHelper_Impl::exportCustomLabel(const SchXMLDataPointStruct
& rPoint
)
3728 if (rPoint
.mCustomLabel
.maFields
.getLength() < 1 && rPoint
.msDataLabelStyleName
.isEmpty())
3729 return; // nothing to export
3731 if (!rPoint
.msDataLabelStyleName
.isEmpty())
3732 mrExport
.AddAttribute(XML_NAMESPACE_CHART
, XML_STYLE_NAME
, rPoint
.msDataLabelStyleName
);
3734 if (rPoint
.mCustomLabel
.mbDataLabelsRange
)
3736 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_DATA_LABELS_CELL_RANGE
, rPoint
.mCustomLabel
.maRange
);
3737 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_DATA_LABEL_GUID
, rPoint
.mCustomLabel
.maGuid
);
3739 // TODO svg:x and svg:y for <chart:data-label>
3740 SvXMLElementExport
aLabelElem( mrExport
, XML_NAMESPACE_CHART
, XML_DATA_LABEL
, true, true);
3741 SvXMLElementExport
aPara( mrExport
, XML_NAMESPACE_TEXT
, XML_P
, true, false );
3743 for (const Reference
<chart2::XDataPointCustomLabelField
>& label
: rPoint
.mCustomLabel
.maFields
)
3746 SvXMLElementExport
aSpan( mrExport
, XML_NAMESPACE_TEXT
, XML_SPAN
, true, false);
3747 mrExport
.GetDocHandler()->characters(label
->getString());
3751 void SchXMLExportHelper_Impl::exportCustomLabelPosition( const chart2::RelativePosition
& xCustomLabelPosition
)
3753 if( xCustomLabelPosition
.Primary
== 0.0 && xCustomLabelPosition
.Secondary
== 0.0 )
3754 return; // nothing to export
3756 OUStringBuffer aCustomLabelPosString
;
3757 ::sax::Converter::convertDouble(aCustomLabelPosString
, xCustomLabelPosition
.Primary
);
3758 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_CUSTOM_LABEL_POS_X
, aCustomLabelPosString
.makeStringAndClear());
3760 ::sax::Converter::convertDouble(aCustomLabelPosString
, xCustomLabelPosition
.Secondary
);
3761 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_CUSTOM_LABEL_POS_Y
, aCustomLabelPosString
.makeStringAndClear());
3764 void SchXMLExportHelper_Impl::addPosition( const awt::Point
& rPosition
)
3766 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3767 msStringBuffer
, rPosition
.X
);
3768 msString
= msStringBuffer
.makeStringAndClear();
3769 mrExport
.AddAttribute( XML_NAMESPACE_SVG
, XML_X
, msString
);
3771 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3772 msStringBuffer
, rPosition
.Y
);
3773 msString
= msStringBuffer
.makeStringAndClear();
3774 mrExport
.AddAttribute( XML_NAMESPACE_SVG
, XML_Y
, msString
);
3777 void SchXMLExportHelper_Impl::addPosition( const Reference
< drawing::XShape
>& xShape
)
3780 addPosition( xShape
->getPosition());
3783 void SchXMLExportHelper_Impl::addSize( const awt::Size
& rSize
, bool bIsOOoNamespace
)
3785 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3786 msStringBuffer
, rSize
.Width
);
3787 msString
= msStringBuffer
.makeStringAndClear();
3788 mrExport
.AddAttribute( bIsOOoNamespace
? XML_NAMESPACE_CHART_EXT
: XML_NAMESPACE_SVG
, XML_WIDTH
, msString
);
3790 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3791 msStringBuffer
, rSize
.Height
);
3792 msString
= msStringBuffer
.makeStringAndClear();
3793 mrExport
.AddAttribute( bIsOOoNamespace
? XML_NAMESPACE_CHART_EXT
: XML_NAMESPACE_SVG
, XML_HEIGHT
, msString
);
3796 void SchXMLExportHelper_Impl::addSize( const Reference
< drawing::XShape
>& xShape
)
3799 addSize( xShape
->getSize() );
3802 awt::Size
SchXMLExportHelper_Impl::getPageSize( const Reference
< chart2::XChartDocument
> & xChartDoc
)
3804 awt::Size
aSize( 8000, 7000 );
3805 uno::Reference
< embed::XVisualObject
> xVisualObject( xChartDoc
, uno::UNO_QUERY
);
3806 SAL_WARN_IF( !xVisualObject
.is(), "xmloff.chart", "need XVisualObject for page size" );
3807 if( xVisualObject
.is() )
3808 aSize
= xVisualObject
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
3813 void SchXMLExportHelper_Impl::CollectAutoStyle( std::vector
< XMLPropertyState
>&& aStates
)
3815 if( !aStates
.empty() )
3816 maAutoStyleNameQueue
.push( mrAutoStylePool
.Add( XmlStyleFamily::SCH_CHART_ID
, std::move(aStates
) ));
3819 void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector
< XMLPropertyState
>& aStates
)
3821 if( !aStates
.empty() )
3823 SAL_WARN_IF( maAutoStyleNameQueue
.empty(), "xmloff.chart", "Autostyle queue empty!" );
3825 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_STYLE_NAME
, maAutoStyleNameQueue
.front() );
3826 maAutoStyleNameQueue
.pop();
3830 void SchXMLExportHelper_Impl::exportText( const OUString
& rText
)
3832 SchXMLTools::exportText( mrExport
, rText
, false/*bConvertTabsLFs*/ );
3836 SchXMLExport::SchXMLExport(const Reference
<uno::XComponentContext
>& xContext
,
3837 OUString
const& implementationName
, SvXMLExportFlags nExportFlags
)
3838 : SvXMLExport(xContext
, implementationName
, util::MeasureUnit::CM
, ::xmloff::token::XML_CHART
,
3840 , maAutoStylePool(new SchXMLAutoStylePoolP(*this))
3841 , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool
))
3843 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED
)
3844 GetNamespaceMap_().Add( GetXMLToken(XML_NP_CHART_EXT
), GetXMLToken(XML_N_CHART_EXT
), XML_NAMESPACE_CHART_EXT
);
3847 SchXMLExport::~SchXMLExport()
3851 ErrCode
SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass
)
3853 maExportHelper
->SetSourceShellID(GetSourceShellID());
3854 maExportHelper
->SetDestinationShellID(GetDestinationShellID());
3856 Reference
< chart2::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3857 maExportHelper
->m_pImpl
->InitRangeSegmentationProperties( xChartDoc
);
3858 return SvXMLExport::exportDoc( eClass
);
3861 void SchXMLExport::ExportMasterStyles_()
3863 // not available in chart
3864 SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" );
3867 void SchXMLExport::collectAutoStyles()
3869 SvXMLExport::collectAutoStyles();
3871 if (mbAutoStylesCollected
)
3874 // there are no styles that require their own autostyles
3875 if( getExportFlags() & SvXMLExportFlags::CONTENT
)
3877 Reference
< chart::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3880 maExportHelper
->m_pImpl
->collectAutoStyles( xChartDoc
);
3884 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3887 mbAutoStylesCollected
= true;
3890 void SchXMLExport::ExportAutoStyles_()
3892 collectAutoStyles();
3894 if( getExportFlags() & SvXMLExportFlags::CONTENT
)
3896 Reference
< chart::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3899 maExportHelper
->m_pImpl
->exportAutoStyles();
3903 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3908 void SchXMLExport::ExportContent_()
3910 Reference
< chart::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3913 // determine if data comes from the outside
3914 bool bIncludeTable
= true;
3916 Reference
< chart2::XChartDocument
> xNewDoc( xChartDoc
, uno::UNO_QUERY
);
3919 // check if we have own data. If so we must not export the complete
3920 // range string, as this is our only indicator for having own or
3921 // external data. @todo: fix this in the file format!
3922 Reference
< lang::XServiceInfo
> xDPServiceInfo( xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
3923 if( ! (xDPServiceInfo
.is() && xDPServiceInfo
->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
3925 bIncludeTable
= false;
3930 Reference
< lang::XServiceInfo
> xServ( xChartDoc
, uno::UNO_QUERY
);
3933 if( xServ
->supportsService( "com.sun.star.chart.ChartTableAddressSupplier" ))
3935 Reference
< beans::XPropertySet
> xProp( xServ
, uno::UNO_QUERY
);
3941 OUString sChartAddress
;
3942 aAny
= xProp
->getPropertyValue( "ChartRangeAddress" );
3943 aAny
>>= sChartAddress
;
3944 maExportHelper
->m_pImpl
->SetChartRangeAddress( sChartAddress
);
3946 // do not include own table if there are external addresses
3947 bIncludeTable
= sChartAddress
.isEmpty();
3949 catch( const beans::UnknownPropertyException
& )
3951 SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" );
3957 maExportHelper
->m_pImpl
->exportChart( xChartDoc
, bIncludeTable
);
3961 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" );
3965 rtl::Reference
< XMLPropertySetMapper
> const & SchXMLExport::GetPropertySetMapper() const
3967 return maExportHelper
->m_pImpl
->GetPropertySetMapper();
3970 void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference
< chart2::XChartDocument
> & xChartDoc
)
3972 if( !xChartDoc
.is())
3977 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
3978 SAL_WARN_IF( !xDataProvider
.is(), "xmloff.chart", "No DataProvider" );
3979 if( xDataProvider
.is())
3981 Reference
< chart2::data::XDataSource
> xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc
, mbHasCategoryLabels
));
3982 const Sequence
< beans::PropertyValue
> aArgs( xDataProvider
->detectArguments( xDataSource
));
3983 OUString sCellRange
, sBrokenRange
;
3984 bool bBrokenRangeAvailable
= false;
3985 for( const auto& rArg
: aArgs
)
3987 if ( rArg
.Name
== "CellRangeRepresentation" )
3988 rArg
.Value
>>= sCellRange
;
3989 else if ( rArg
.Name
== "BrokenCellRangeForExport" )
3991 if( rArg
.Value
>>= sBrokenRange
)
3992 bBrokenRangeAvailable
= true;
3994 else if ( rArg
.Name
== "DataRowSource" )
3996 chart::ChartDataRowSource eRowSource
;
3997 rArg
.Value
>>= eRowSource
;
3998 mbRowSourceColumns
= ( eRowSource
== chart::ChartDataRowSource_COLUMNS
);
4000 else if ( rArg
.Name
== "SequenceMapping" )
4001 rArg
.Value
>>= maSequenceMapping
;
4004 // #i79009# For Writer we have to export a broken version of the
4005 // range, where every row number is not too large, so that older
4006 // version can correctly read those files.
4007 msChartAddress
= (bBrokenRangeAvailable
? sBrokenRange
: sCellRange
);
4008 if( !msChartAddress
.isEmpty() )
4010 // convert format to XML-conform one
4011 Reference
< chart2::data::XRangeXMLConversion
> xConversion( xDataProvider
, uno::UNO_QUERY
);
4012 if( xConversion
.is())
4013 msChartAddress
= xConversion
->convertRangeToXML( msChartAddress
);
4017 catch( const uno::Exception
& )
4019 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
4023 // first version: everything goes in one storage
4025 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4026 com_sun_star_comp_Chart_XMLExporter_get_implementation(uno::XComponentContext
* pCtx
,
4027 uno::Sequence
<uno::Any
> const& /*rSeq*/)
4029 return cppu::acquire(
4030 new SchXMLExport(pCtx
, "SchXMLExport.Compact",
4031 SvXMLExportFlags::ALL
4032 ^ (SvXMLExportFlags::SETTINGS
| SvXMLExportFlags::MASTERSTYLES
4033 | SvXMLExportFlags::SCRIPTS
)));
4037 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4038 com_sun_star_comp_Chart_XMLOasisExporter_get_implementation(uno::XComponentContext
* pCtx
,
4039 uno::Sequence
<uno::Any
> const& /*rSeq*/)
4041 return cppu::acquire(
4042 new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Compact",
4043 (SvXMLExportFlags::ALL
4044 ^ (SvXMLExportFlags::SETTINGS
| SvXMLExportFlags::MASTERSTYLES
4045 | SvXMLExportFlags::SCRIPTS
))
4046 | SvXMLExportFlags::OASIS
));
4049 // multiple storage version: one for content / styles / meta
4051 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4052 com_sun_star_comp_Chart_XMLStylesExporter_get_implementation(
4053 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4055 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Styles", SvXMLExportFlags::STYLES
));
4059 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4060 com_sun_star_comp_Chart_XMLOasisStylesExporter_get_implementation(
4061 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4063 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Styles",
4064 SvXMLExportFlags::STYLES
| SvXMLExportFlags::OASIS
));
4067 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4068 com_sun_star_comp_Chart_XMLContentExporter_get_implementation(
4069 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4071 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Content",
4072 SvXMLExportFlags::AUTOSTYLES
| SvXMLExportFlags::CONTENT
4073 | SvXMLExportFlags::FONTDECLS
));
4076 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4077 com_sun_star_comp_Chart_XMLOasisContentExporter_get_implementation(
4078 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4080 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Content",
4081 SvXMLExportFlags::AUTOSTYLES
| SvXMLExportFlags::CONTENT
4082 | SvXMLExportFlags::FONTDECLS
4083 | SvXMLExportFlags::OASIS
));
4088 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4089 com_sun_star_comp_Chart_XMLOasisMetaExporter_get_implementation(
4090 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4092 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Meta",
4093 SvXMLExportFlags::META
| SvXMLExportFlags::OASIS
));
4096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */