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 OUStringLiteral gsTableName
= u
"local-table";
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 OUString( XML_STYLE_FAMILY_SCH_CHART_NAME
),
1084 mxExpPropMapper
.get(),
1085 OUString( XML_STYLE_FAMILY_SCH_CHART_PREFIX
));
1087 // register shape family
1088 mrAutoStylePool
.AddFamily(
1089 XmlStyleFamily::SD_GRAPHICS_ID
,
1090 OUString( XML_STYLE_FAMILY_SD_GRAPHICS_NAME
),
1091 mxExpPropMapper
.get(),
1092 OUString( 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 css::uno::Sequence
<OUString
> aAutoStylePropNames
= mrAutoStylePool
.GetPropertyNames();
1593 Reference
< drawing::XShape
> xShape
;
1594 const sal_Int32
nShapeCount( mxAdditionalShapes
->getCount());
1595 for( sal_Int32 nShapeId
= 0; nShapeId
< nShapeCount
; nShapeId
++ )
1597 mxAdditionalShapes
->getByIndex( nShapeId
) >>= xShape
;
1598 SAL_WARN_IF( !xShape
.is(), "xmloff.chart", "Shape without an XShape?" );
1602 rShapeExport
->collectShapeAutoStyles( xShape
, aAutoStylePropNames
);
1609 // (is included as subelement of chart)
1610 if( bExportContent
)
1612 // #85929# always export table, otherwise clipboard may lose data
1617 static void lcl_exportComplexLabel( const Sequence
< uno::Any
>& rComplexLabel
, SvXMLExport
& rExport
)
1619 sal_Int32 nLength
= rComplexLabel
.getLength();
1622 SvXMLElementExport
aTextList( rExport
, XML_NAMESPACE_TEXT
, XML_LIST
, true, true );
1623 for(const auto& rElem
: rComplexLabel
)
1625 SvXMLElementExport
aListItem( rExport
, XML_NAMESPACE_TEXT
, XML_LIST_ITEM
, true, true );
1627 if( !(rElem
>>= aString
) )
1632 aString
= OUString::number(aNum
);
1635 SchXMLTools::exportText( rExport
, aString
, false /*bConvertTabsLFs*/ );
1639 void SchXMLExportHelper_Impl::exportTable()
1642 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_NAME
, gsTableName
);
1646 bool bProtected
= false;
1647 Reference
< beans::XPropertySet
> xProps( mrExport
.GetModel(), uno::UNO_QUERY_THROW
);
1648 if ( ( xProps
->getPropertyValue("DisableDataTableDialog") >>= bProtected
) &&
1651 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_PROTECTED
, XML_TRUE
);
1654 catch ( const uno::Exception
& )
1658 SvXMLElementExport
aTable( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE
, true, true );
1660 bool bHasOwnData
= false;
1661 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
1662 Reference
< chart2::data::XRangeXMLConversion
> xRangeConversion
;
1665 bHasOwnData
= xNewDoc
->hasInternalDataProvider();
1666 xRangeConversion
.set( xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
1669 Reference
< chart2::XAnyDescriptionAccess
> xAnyDescriptionAccess
;
1671 Reference
< chart::XChartDocument
> xChartDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
1672 if( xChartDoc
.is() )
1673 xAnyDescriptionAccess
.set( xChartDoc
->getData(), uno::UNO_QUERY
);
1677 lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport
);
1678 lcl_TableData
aData( lcl_getDataForLocalTable( m_aDataSequencesToExport
1679 , xAnyDescriptionAccess
, maCategoriesRange
1680 , mbRowSourceColumns
, xRangeConversion
));
1682 tStringVector::const_iterator
aDataRangeIter( aData
.aDataRangeRepresentations
.begin());
1683 const tStringVector::const_iterator
aDataRangeEndIter( aData
.aDataRangeRepresentations
.end());
1685 tStringVector::const_iterator
aRowDescriptions_RangeIter( aData
.aRowDescriptions_Ranges
.begin());
1686 const tStringVector::const_iterator
aRowDescriptions_RangeEnd( aData
.aRowDescriptions_Ranges
.end());
1690 SvXMLElementExport
aHeaderColumns( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_HEADER_COLUMNS
, true, true );
1691 SvXMLElementExport
aHeaderColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1694 SvXMLElementExport
aColumns( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMNS
, true, true );
1696 sal_Int32 nNextIndex
= 0;
1697 for(sal_Int32 nHiddenIndex
: aData
.aHiddenColumns
)
1699 //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste )
1700 if( nHiddenIndex
> nNextIndex
)
1702 sal_Int64 nRepeat
= static_cast< sal_Int64
>( nHiddenIndex
- nNextIndex
);
1704 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_REPEATED
,
1705 OUString::number( nRepeat
));
1706 SvXMLElementExport
aColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1708 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_VISIBILITY
, GetXMLToken( XML_COLLAPSE
) );
1709 SvXMLElementExport
aColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1710 nNextIndex
= nHiddenIndex
+1;
1713 sal_Int32 nEndIndex
= aData
.aColumnDescriptions
.size()-1;
1714 if( nEndIndex
>= nNextIndex
)
1716 sal_Int64 nRepeat
= static_cast< sal_Int64
>( nEndIndex
- nNextIndex
+ 1 );
1718 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_REPEATED
,
1719 OUString::number( nRepeat
));
1720 SvXMLElementExport
aColumn( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_COLUMN
, true, true );
1724 // export rows with content
1727 SvXMLElementExport
aHeaderRows( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_HEADER_ROWS
, true, true );
1728 SvXMLElementExport
aRow( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_ROW
, true, true );
1730 //first one empty cell for the row descriptions
1732 SvXMLElementExport
aEmptyCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1733 SvXMLElementExport
aEmptyParagraph( mrExport
, XML_NAMESPACE_TEXT
, XML_P
, true, true );
1736 //export column descriptions
1737 tStringVector::const_iterator
aColumnDescriptions_RangeIter( aData
.aColumnDescriptions_Ranges
.begin());
1738 const tStringVector::const_iterator
aColumnDescriptions_RangeEnd( aData
.aColumnDescriptions_Ranges
.end());
1739 const Sequence
< Sequence
< uno::Any
> >& rComplexColumnDescriptions
= aData
.aComplexColumnDescriptions
;
1740 sal_Int32 nComplexCount
= rComplexColumnDescriptions
.getLength();
1742 for( const auto& rDesc
: aData
.aColumnDescriptions
)
1744 bool bExportString
= true;
1745 if( nC
< nComplexCount
)
1747 const Sequence
< uno::Any
>& rComplexLabel
= rComplexColumnDescriptions
[nC
];
1748 if( rComplexLabel
.hasElements() )
1751 if( rComplexLabel
[0] >>=fValue
)
1753 bExportString
= false;
1755 ::sax::Converter::convertDouble(
1756 msStringBuffer
, fValue
);
1757 msString
= msStringBuffer
.makeStringAndClear();
1758 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_FLOAT
);
1759 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE
, msString
);
1765 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_STRING
);
1768 SvXMLElementExport
aCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1769 exportText( rDesc
);
1770 if( nC
< nComplexCount
)
1771 lcl_exportComplexLabel( rComplexColumnDescriptions
[nC
], mrExport
);
1772 if( !bHasOwnData
&& aColumnDescriptions_RangeIter
!= aColumnDescriptions_RangeEnd
)
1774 // remind the original range to allow a correct re-association when copying via clipboard
1775 if (!(*aColumnDescriptions_RangeIter
).isEmpty())
1776 SchXMLTools::exportRangeToSomewhere( mrExport
, *aColumnDescriptions_RangeIter
);
1777 ++aColumnDescriptions_RangeIter
;
1782 SAL_WARN_IF( !bHasOwnData
&& (aColumnDescriptions_RangeIter
!= aColumnDescriptions_RangeEnd
), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" );
1783 } // closing row and header-rows elements
1785 // export value rows
1787 SvXMLElementExport
aRows( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_ROWS
, true, true );
1788 tStringVector::const_iterator
aRowDescriptionsIter( aData
.aRowDescriptions
.begin());
1789 const Sequence
< Sequence
< uno::Any
> >& rComplexRowDescriptions
= aData
.aComplexRowDescriptions
;
1790 sal_Int32 nComplexCount
= rComplexRowDescriptions
.getLength();
1793 for( const auto& rRow
: aData
.aDataInRows
)
1795 SvXMLElementExport
aRow( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_ROW
, true, true );
1797 //export row descriptions
1799 bool bExportString
= true;
1800 if( nC
< nComplexCount
)
1802 const Sequence
< uno::Any
>& rComplexLabel
= rComplexRowDescriptions
[nC
];
1803 if( rComplexLabel
.hasElements() )
1806 if( rComplexLabel
[0] >>=fValue
)
1808 bExportString
= false;
1810 ::sax::Converter::convertDouble(msStringBuffer
, fValue
);
1811 msString
= msStringBuffer
.makeStringAndClear();
1812 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_FLOAT
);
1813 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE
, msString
);
1819 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_STRING
);
1822 SvXMLElementExport
aCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1823 if( aRowDescriptionsIter
!= aData
.aRowDescriptions
.end())
1825 exportText( *aRowDescriptionsIter
);
1826 if( nC
< nComplexCount
)
1827 lcl_exportComplexLabel( rComplexRowDescriptions
[nC
], mrExport
);
1828 if( !bHasOwnData
&& aRowDescriptions_RangeIter
!= aRowDescriptions_RangeEnd
)
1830 // remind the original range to allow a correct re-association when copying via clipboard
1831 SchXMLTools::exportRangeToSomewhere( mrExport
, *aRowDescriptions_RangeIter
);
1832 ++aRowDescriptions_RangeIter
;
1834 ++aRowDescriptionsIter
;
1839 for( t2DNumberContainer::value_type::const_iterator
aColIt( rRow
.begin());
1840 aColIt
!= rRow
.end(); ++aColIt
)
1842 ::sax::Converter::convertDouble( msStringBuffer
, *aColIt
);
1843 msString
= msStringBuffer
.makeStringAndClear();
1844 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE_TYPE
, XML_FLOAT
);
1845 mrExport
.AddAttribute( XML_NAMESPACE_OFFICE
, XML_VALUE
, msString
);
1846 SvXMLElementExport
aCell( mrExport
, XML_NAMESPACE_TABLE
, XML_TABLE_CELL
, true, true );
1847 exportText( msString
); // do not convert tabs and lfs
1848 if( ( !bHasOwnData
&& aDataRangeIter
!= aDataRangeEndIter
) &&
1849 ( mbRowSourceColumns
|| (aColIt
== rRow
.begin()) ) )
1851 // remind the original range to allow a correct re-association when copying via clipboard
1852 if (!(*aDataRangeIter
).isEmpty())
1853 SchXMLTools::exportRangeToSomewhere( mrExport
, *aDataRangeIter
);
1862 // if range iterator was used it should have reached its end
1863 SAL_WARN_IF( !bHasOwnData
&& (aDataRangeIter
!= aDataRangeEndIter
), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" );
1864 SAL_WARN_IF( !bHasOwnData
&& (aRowDescriptions_RangeIter
!= aRowDescriptions_RangeEnd
), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" );
1870 Reference
< chart2::XCoordinateSystem
> lcl_getCooSys( const Reference
< chart2::XDiagram
> & xNewDiagram
)
1872 Reference
< chart2::XCoordinateSystem
> xCooSys
;
1873 Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xNewDiagram
, uno::UNO_QUERY
);
1876 Sequence
< Reference
< chart2::XCoordinateSystem
> > aCooSysSeq( xCooSysCnt
->getCoordinateSystems() );
1877 if(aCooSysSeq
.hasElements())
1878 xCooSys
= aCooSysSeq
[0];
1883 Reference
< chart2::XAxis
> lcl_getAxis( const Reference
< chart2::XCoordinateSystem
>& xCooSys
,
1884 enum XMLTokenEnum eDimension
, bool bPrimary
=true )
1886 Reference
< chart2::XAxis
> xNewAxis
;
1891 sal_Int32 nDimensionIndex
=0;
1892 switch( eDimension
)
1907 xNewAxis
= xCooSys
->getAxisByDimension( nDimensionIndex
, bPrimary
? 0 : 1 );
1910 catch( const uno::Exception
& )
1918 void SchXMLExportHelper_Impl::exportPlotArea(
1919 const Reference
< chart::XDiagram
>& xDiagram
,
1920 const Reference
< chart2::XDiagram
>& xNewDiagram
,
1921 const awt::Size
& rPageSize
,
1922 bool bExportContent
,
1923 bool bIncludeTable
)
1925 SAL_WARN_IF( !xDiagram
.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
1926 if( ! xDiagram
.is())
1929 // variables for autostyles
1930 Reference
< beans::XPropertySet
> xPropSet
;
1931 std::vector
< XMLPropertyState
> aPropertyStates
;
1933 msStringBuffer
.setLength( 0 );
1935 // plot-area element
1937 std::unique_ptr
<SvXMLElementExport
> xElPlotArea
;
1938 // get property states for autostyles
1939 xPropSet
.set( xDiagram
, uno::UNO_QUERY
);
1942 if( mxExpPropMapper
.is())
1943 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
1945 if( bExportContent
)
1947 rtl::Reference
< XMLShapeExport
> rShapeExport
;
1950 AddAutoStyleAttribute( aPropertyStates
);
1952 if( !msChartAddress
.isEmpty() )
1954 if( !bIncludeTable
)
1955 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_CELL_RANGE_ADDRESS
, msChartAddress
);
1957 Reference
< chart::XChartDocument
> xDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
1960 Reference
< beans::XPropertySet
> xDocProp( xDoc
, uno::UNO_QUERY
);
1967 bool bFirstCol
= false, bFirstRow
= false;
1969 aAny
= xDocProp
->getPropertyValue( "DataSourceLabelsInFirstColumn" );
1971 aAny
= xDocProp
->getPropertyValue( "DataSourceLabelsInFirstRow" );
1974 if( bFirstCol
|| bFirstRow
)
1976 mrExport
.AddAttribute( XML_NAMESPACE_CHART
,
1977 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS
),
1980 ? ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH
)
1981 : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN
))
1982 : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW
)));
1985 catch( const beans::UnknownPropertyException
& )
1987 SAL_WARN("xmloff.chart", "Properties missing" );
1996 addPosition( xDiagram
);
1997 addSize( xDiagram
);
2000 bool bIs3DChart
= false;
2009 aAny
= xPropSet
->getPropertyValue("Dim3D");
2010 aAny
>>= bIs3DChart
;
2014 rShapeExport
= mrExport
.GetShapeExport();
2015 if( rShapeExport
.is())
2016 rShapeExport
->export3DSceneAttributes( xPropSet
);
2019 catch( const uno::Exception
& )
2021 TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught");
2025 // plot-area element
2026 xElPlotArea
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_PLOT_AREA
, true, true ));
2028 //inner position rectangle element
2029 exportCoordinateRegion( xDiagram
);
2031 // light sources (inside plot area element)
2034 rShapeExport
->export3DLamps( xPropSet
);
2038 CollectAutoStyle( std::move(aPropertyStates
) );
2040 // remove property states for autostyles
2041 aPropertyStates
.clear();
2044 exportAxes( xDiagram
, xNewDiagram
, bExportContent
);
2047 Reference
< chart2::XAxis
> xSecondYAxis
= lcl_getAxis( lcl_getCooSys( xNewDiagram
), XML_Y
, false );
2048 exportSeries( xNewDiagram
, rPageSize
, bExportContent
, xSecondYAxis
.is() );
2050 // stock-chart elements
2051 OUString
sChartType ( xDiagram
->getDiagramType());
2052 if( sChartType
== "com.sun.star.chart.StockDiagram" )
2054 Reference
< chart::XStatisticDisplay
> xStockPropProvider( xDiagram
, uno::UNO_QUERY
);
2055 if( xStockPropProvider
.is())
2057 // stock-gain-marker
2058 Reference
< beans::XPropertySet
> xStockPropSet
= xStockPropProvider
->getUpBar();
2059 if( xStockPropSet
.is())
2061 aPropertyStates
.clear();
2062 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStockPropSet
);
2064 if( !aPropertyStates
.empty() )
2066 if( bExportContent
)
2068 AddAutoStyleAttribute( aPropertyStates
);
2070 SvXMLElementExport
aGain( mrExport
, XML_NAMESPACE_CHART
, XML_STOCK_GAIN_MARKER
, true, true );
2074 CollectAutoStyle( std::move(aPropertyStates
) );
2079 // stock-loss-marker
2080 xStockPropSet
= xStockPropProvider
->getDownBar();
2081 if( xStockPropSet
.is())
2083 aPropertyStates
.clear();
2084 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStockPropSet
);
2086 if( !aPropertyStates
.empty() )
2088 if( bExportContent
)
2090 AddAutoStyleAttribute( aPropertyStates
);
2092 SvXMLElementExport
aGain( mrExport
, XML_NAMESPACE_CHART
, XML_STOCK_LOSS_MARKER
, true, true );
2096 CollectAutoStyle( std::move(aPropertyStates
) );
2102 xStockPropSet
= xStockPropProvider
->getMinMaxLine();
2103 if( xStockPropSet
.is())
2105 aPropertyStates
.clear();
2106 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStockPropSet
);
2108 if( !aPropertyStates
.empty() )
2110 if( bExportContent
)
2112 AddAutoStyleAttribute( aPropertyStates
);
2114 SvXMLElementExport
aGain( mrExport
, XML_NAMESPACE_CHART
, XML_STOCK_RANGE_LINE
, true, true );
2118 CollectAutoStyle( std::move(aPropertyStates
) );
2125 // wall and floor element
2126 Reference
< chart::X3DDisplay
> xWallFloorSupplier( xDiagram
, uno::UNO_QUERY
);
2127 if( !(mxExpPropMapper
.is() &&
2128 xWallFloorSupplier
.is()))
2131 // remove property states for autostyles
2132 aPropertyStates
.clear();
2134 Reference
< beans::XPropertySet
> xWallPropSet
= xWallFloorSupplier
->getWall();
2135 if( xWallPropSet
.is())
2137 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xWallPropSet
);
2139 if( !aPropertyStates
.empty() )
2142 if( bExportContent
)
2144 // add style name attribute
2145 AddAutoStyleAttribute( aPropertyStates
);
2147 SvXMLElementExport
aWall( mrExport
, XML_NAMESPACE_CHART
, XML_WALL
, true, true );
2151 CollectAutoStyle( std::move(aPropertyStates
) );
2157 // remove property states for autostyles
2158 aPropertyStates
.clear();
2160 Reference
< beans::XPropertySet
> xFloorPropSet
= xWallFloorSupplier
->getFloor();
2161 if( !xFloorPropSet
.is())
2164 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xFloorPropSet
);
2166 if( aPropertyStates
.empty() )
2170 if( bExportContent
)
2172 // add style name attribute
2173 AddAutoStyleAttribute( aPropertyStates
);
2175 SvXMLElementExport
aFloor( mrExport
, XML_NAMESPACE_CHART
, XML_FLOOR
, true, true );
2179 CollectAutoStyle( std::move(aPropertyStates
) );
2183 void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference
< chart::XDiagram
>& xDiagram
)
2185 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2186 mrExport
.getSaneDefaultVersion());
2187 if (nCurrentODFVersion
<= SvtSaveOptions::ODFSVER_012
) //do not export to ODF 1.2 or older
2190 Reference
< chart::XDiagramPositioning
> xDiaPos( xDiagram
, uno::UNO_QUERY
);
2191 SAL_WARN_IF( !xDiaPos
.is(), "xmloff.chart", "Invalid xDiaPos as parameter" );
2195 awt::Rectangle
aRect( xDiaPos
->calculateDiagramPositionExcludingAxes() );
2196 addPosition( awt::Point(aRect
.X
,aRect
.Y
) );
2197 addSize( awt::Size(aRect
.Width
,aRect
.Height
) );
2199 // ODF 1.3 OFFICE-3928
2200 SvXMLElementExport
aCoordinateRegion( mrExport
,
2201 (SvtSaveOptions::ODFSVER_013
<= nCurrentODFVersion
) ? XML_NAMESPACE_CHART
: XML_NAMESPACE_CHART_EXT
,
2202 XML_COORDINATE_REGION
, true, true );
2207 XMLTokenEnum
lcl_getTimeUnitToken( sal_Int32 nTimeUnit
)
2209 XMLTokenEnum eToken
= XML_DAYS
;
2212 case css::chart::TimeUnit::YEAR
:
2215 case css::chart::TimeUnit::MONTH
:
2216 eToken
= XML_MONTHS
;
2225 void SchXMLExportHelper_Impl::exportDateScale( const Reference
< beans::XPropertySet
>& rAxisProps
)
2227 if( !rAxisProps
.is() )
2230 chart::TimeIncrement aIncrement
;
2231 if( !(rAxisProps
->getPropertyValue("TimeIncrement") >>= aIncrement
) )
2234 sal_Int32 nTimeResolution
= css::chart::TimeUnit::DAY
;
2235 if( aIncrement
.TimeResolution
>>= nTimeResolution
)
2236 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_BASE_TIME_UNIT
, lcl_getTimeUnitToken( nTimeResolution
) );
2238 chart::TimeInterval aInterval
;
2239 if( aIncrement
.MajorTimeInterval
>>= aInterval
)
2241 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MAJOR_INTERVAL_VALUE
, OUString::number(aInterval
.Number
) );
2242 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MAJOR_INTERVAL_UNIT
, lcl_getTimeUnitToken( aInterval
.TimeUnit
) );
2244 if( aIncrement
.MinorTimeInterval
>>= aInterval
)
2246 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MINOR_INTERVAL_VALUE
, OUString::number(aInterval
.Number
) );
2247 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_MINOR_INTERVAL_UNIT
, lcl_getTimeUnitToken( aInterval
.TimeUnit
) );
2250 SvXMLElementExport
aDateScale( mrExport
, XML_NAMESPACE_CHART_EXT
, XML_DATE_SCALE
, true, true );//#i25706#todo: change namespace for next ODF version
2253 void SchXMLExportHelper_Impl::exportAxisTitle( const Reference
< beans::XPropertySet
>& rTitleProps
, bool bExportContent
)
2255 if( !rTitleProps
.is() )
2257 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, rTitleProps
);
2258 if( bExportContent
)
2261 Any
aAny( rTitleProps
->getPropertyValue( "String" ));
2264 Reference
< drawing::XShape
> xShape( rTitleProps
, uno::UNO_QUERY
);
2266 addPosition( xShape
);
2268 AddAutoStyleAttribute( aPropertyStates
);
2269 SvXMLElementExport
aTitle( mrExport
, XML_NAMESPACE_CHART
, XML_TITLE
, true, true );
2271 // paragraph containing title
2272 exportText( aText
);
2276 CollectAutoStyle( std::move(aPropertyStates
) );
2278 aPropertyStates
.clear();
2281 void SchXMLExportHelper_Impl::exportGrid( const Reference
< beans::XPropertySet
>& rGridProperties
, bool bMajor
, bool bExportContent
)
2283 if( !rGridProperties
.is() )
2285 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, rGridProperties
);
2286 if( bExportContent
)
2288 AddAutoStyleAttribute( aPropertyStates
);
2289 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_CLASS
, bMajor
? XML_MAJOR
: XML_MINOR
);
2290 SvXMLElementExport
aGrid( mrExport
, XML_NAMESPACE_CHART
, XML_GRID
, true, true );
2294 CollectAutoStyle( std::move(aPropertyStates
) );
2296 aPropertyStates
.clear();
2302 //returns true if a date scale needs to be exported
2303 bool lcl_exportAxisType( const Reference
< chart2::XAxis
>& rChart2Axis
, SvXMLExport
& rExport
)
2305 bool bExportDateScale
= false;
2306 if( !rChart2Axis
.is() )
2307 return bExportDateScale
;
2309 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2310 rExport
.getSaneDefaultVersion());
2311 if ((nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) == 0) //do not export to ODF 1.3 or older
2312 return bExportDateScale
;
2314 chart2::ScaleData
aScale( rChart2Axis
->getScaleData() );
2315 //#i25706#todo: change namespace for next ODF version
2316 sal_uInt16 nNameSpace
= XML_NAMESPACE_CHART_EXT
;
2318 switch(aScale
.AxisType
)
2320 case chart2::AxisType::CATEGORY
:
2321 if( aScale
.AutoDateAxis
)
2323 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_AUTO
);
2324 bExportDateScale
= true;
2327 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_TEXT
);
2329 case chart2::AxisType::DATE
:
2330 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_DATE
);
2331 bExportDateScale
= true;
2333 default: //AUTOMATIC
2334 rExport
.AddAttribute( nNameSpace
, XML_AXIS_TYPE
, XML_AUTO
);
2338 return bExportDateScale
;
2341 void disableLinkedNumberFormat(
2342 std::vector
<XMLPropertyState
>& rPropStates
, const rtl::Reference
<XMLPropertySetMapper
>& rMapper
)
2344 for (XMLPropertyState
& rState
: rPropStates
)
2346 if (rState
.mnIndex
< 0 || rMapper
->GetEntryCount() <= rState
.mnIndex
)
2349 OUString aXMLName
= rMapper
->GetEntryXMLName(rState
.mnIndex
);
2351 if (aXMLName
!= "link-data-style-to-source")
2354 // Entry found. Set the value to false and bail out.
2355 rState
.maValue
<<= false;
2359 // Entry not found. Insert a new entry for this.
2360 sal_Int32 nIndex
= rMapper
->GetEntryIndex(XML_NAMESPACE_CHART
, u
"link-data-style-to-source", 0);
2361 XMLPropertyState
aState(nIndex
);
2362 aState
.maValue
<<= false;
2363 rPropStates
.push_back(aState
);
2368 void SchXMLExportHelper_Impl::exportAxis(
2369 enum XMLTokenEnum eDimension
,
2370 enum XMLTokenEnum eAxisName
,
2371 const Reference
< beans::XPropertySet
>& rAxisProps
,
2372 const Reference
< chart2::XAxis
>& rChart2Axis
,
2373 const OUString
& rCategoriesRange
,
2374 bool bHasTitle
, bool bHasMajorGrid
, bool bHasMinorGrid
,
2375 bool bExportContent
, std::u16string_view sChartType
)
2377 std::vector
< XMLPropertyState
> aPropertyStates
;
2378 std::unique_ptr
<SvXMLElementExport
> pAxis
;
2380 // get property states for autostyles
2381 if( rAxisProps
.is() && mxExpPropMapper
.is() )
2383 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2384 mrExport
.getSaneDefaultVersion());
2385 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
2386 && eDimension
== XML_X
)
2388 chart2::ScaleData
aScaleData(rChart2Axis
->getScaleData());
2389 bool bShiftedCatPos
= aScaleData
.ShiftedCategoryPosition
;
2390 if (sChartType
== u
"com.sun.star.chart.BarDiagram" || sChartType
== u
"com.sun.star.chart.StockDiagram")
2392 if (!bShiftedCatPos
)
2393 rAxisProps
->setPropertyValue("MajorOrigin", uno::Any(0.0));
2395 else if (bShiftedCatPos
)
2396 rAxisProps
->setPropertyValue("MajorOrigin", uno::Any(0.5));
2399 lcl_exportNumberFormat( "NumberFormat", rAxisProps
, mrExport
);
2400 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, rAxisProps
);
2402 if (!maSrcShellID
.isEmpty() && !maDestShellID
.isEmpty() && maSrcShellID
!= maDestShellID
)
2404 // Disable link to source number format property when pasting to
2405 // a different doc shell. These shell ID's should be both empty
2406 // during real ODF export.
2407 disableLinkedNumberFormat(aPropertyStates
, mxExpPropMapper
->getPropertySetMapper());
2411 bool bExportDateScale
= false;
2412 if( bExportContent
)
2414 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DIMENSION
, eDimension
);
2415 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_NAME
, eAxisName
);
2416 AddAutoStyleAttribute( aPropertyStates
); // write style name
2417 if( !rCategoriesRange
.isEmpty() )
2418 bExportDateScale
= lcl_exportAxisType( rChart2Axis
, mrExport
);
2420 // open axis element
2421 pAxis
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_AXIS
, true, true ));
2425 CollectAutoStyle( std::move(aPropertyStates
) );
2427 aPropertyStates
.clear();
2430 if( bExportDateScale
)
2431 exportDateScale( rAxisProps
);
2433 Reference
< beans::XPropertySet
> xTitleProps
;
2434 Reference
< beans::XPropertySet
> xMajorGridProps
;
2435 Reference
< beans::XPropertySet
> xMinorGridProps
;
2436 Reference
< chart::XAxis
> xAxis( rAxisProps
, uno::UNO_QUERY
);
2439 xTitleProps
= bHasTitle
? xAxis
->getAxisTitle() : nullptr;
2440 xMajorGridProps
= bHasMajorGrid
? xAxis
->getMajorGrid() : nullptr;
2441 xMinorGridProps
= bHasMinorGrid
? xAxis
->getMinorGrid() : nullptr;
2445 exportAxisTitle( xTitleProps
, bExportContent
);
2447 // categories if we have a categories chart
2448 if( bExportContent
&& !rCategoriesRange
.isEmpty() )
2450 mrExport
.AddAttribute( XML_NAMESPACE_TABLE
, XML_CELL_RANGE_ADDRESS
, rCategoriesRange
);
2451 SvXMLElementExport
aCategories( mrExport
, XML_NAMESPACE_CHART
, XML_CATEGORIES
, true, true );
2455 exportGrid( xMajorGridProps
, true, bExportContent
);
2456 exportGrid( xMinorGridProps
, false, bExportContent
);
2459 void SchXMLExportHelper_Impl::exportAxes(
2460 const Reference
< chart::XDiagram
> & xDiagram
,
2461 const Reference
< chart2::XDiagram
> & xNewDiagram
,
2462 bool bExportContent
)
2464 SAL_WARN_IF( !xDiagram
.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
2465 if( ! xDiagram
.is())
2468 // get some properties from document first
2469 bool bHasXAxis
= false,
2472 bHasSecondaryXAxis
= false,
2473 bHasSecondaryYAxis
= false;
2474 bool bHasXAxisTitle
= false,
2475 bHasYAxisTitle
= false,
2476 bHasZAxisTitle
= false,
2477 bHasSecondaryXAxisTitle
= false,
2478 bHasSecondaryYAxisTitle
= false;
2479 bool bHasXAxisMajorGrid
= false,
2480 bHasXAxisMinorGrid
= false,
2481 bHasYAxisMajorGrid
= false,
2482 bHasYAxisMinorGrid
= false,
2483 bHasZAxisMajorGrid
= false,
2484 bHasZAxisMinorGrid
= false;
2486 // get multiple properties using XMultiPropertySet
2487 MultiPropertySetHandler
aDiagramProperties (xDiagram
);
2489 aDiagramProperties
.Add ("HasXAxis", bHasXAxis
);
2490 aDiagramProperties
.Add ("HasYAxis", bHasYAxis
);
2491 aDiagramProperties
.Add ("HasZAxis", bHasZAxis
);
2492 aDiagramProperties
.Add ("HasSecondaryXAxis", bHasSecondaryXAxis
);
2493 aDiagramProperties
.Add ("HasSecondaryYAxis", bHasSecondaryYAxis
);
2495 aDiagramProperties
.Add ("HasXAxisTitle", bHasXAxisTitle
);
2496 aDiagramProperties
.Add ("HasYAxisTitle", bHasYAxisTitle
);
2497 aDiagramProperties
.Add ("HasZAxisTitle", bHasZAxisTitle
);
2498 aDiagramProperties
.Add ("HasSecondaryXAxisTitle", bHasSecondaryXAxisTitle
);
2499 aDiagramProperties
.Add ("HasSecondaryYAxisTitle", bHasSecondaryYAxisTitle
);
2501 aDiagramProperties
.Add ("HasXAxisGrid", bHasXAxisMajorGrid
);
2502 aDiagramProperties
.Add ("HasYAxisGrid", bHasYAxisMajorGrid
);
2503 aDiagramProperties
.Add ("HasZAxisGrid", bHasZAxisMajorGrid
);
2505 aDiagramProperties
.Add ("HasXAxisHelpGrid", bHasXAxisMinorGrid
);
2506 aDiagramProperties
.Add ("HasYAxisHelpGrid", bHasYAxisMinorGrid
);
2507 aDiagramProperties
.Add ("HasZAxisHelpGrid", bHasZAxisMinorGrid
);
2509 if ( ! aDiagramProperties
.GetProperties ())
2511 SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram");
2514 Reference
< chart2::XCoordinateSystem
> xCooSys( lcl_getCooSys(xNewDiagram
) );
2516 // write an axis element also if the axis itself is not visible, but a grid or a title
2518 OUString aCategoriesRange
;
2519 Reference
< chart::XAxisSupplier
> xAxisSupp( xDiagram
, uno::UNO_QUERY
);
2520 OUString sChartType
= xDiagram
->getDiagramType();
2524 Reference
< css::chart2::XAxis
> xNewAxis
= lcl_getAxis( xCooSys
, XML_X
);
2527 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getAxis(0) : nullptr, uno::UNO_QUERY
);
2528 if( mbHasCategoryLabels
&& bExportContent
)
2530 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( xNewDiagram
) );
2531 if( xCategories
.is() )
2533 Reference
< chart2::data::XDataSequence
> xValues( xCategories
->getValues() );
2536 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
2537 maCategoriesRange
= xValues
->getSourceRangeRepresentation();
2538 aCategoriesRange
= lcl_ConvertRange( maCategoriesRange
, xNewDoc
);
2542 exportAxis( XML_X
, XML_PRIMARY_X
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasXAxisTitle
, bHasXAxisMajorGrid
, bHasXAxisMinorGrid
, bExportContent
, sChartType
);
2543 aCategoriesRange
.clear();
2548 xNewAxis
= lcl_getAxis( xCooSys
, XML_X
, false );
2551 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY
);
2552 exportAxis( XML_X
, XML_SECONDARY_X
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasSecondaryXAxisTitle
, false, false, bExportContent
, sChartType
);
2557 xNewAxis
= lcl_getAxis( xCooSys
, XML_Y
);
2560 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getAxis(1) : nullptr, uno::UNO_QUERY
);
2561 exportAxis( XML_Y
, XML_PRIMARY_Y
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasYAxisTitle
, bHasYAxisMajorGrid
, bHasYAxisMinorGrid
, bExportContent
, sChartType
);
2566 xNewAxis
= lcl_getAxis( xCooSys
, XML_Y
, false );
2569 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY
);
2570 exportAxis( XML_Y
, XML_SECONDARY_Y
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasSecondaryYAxisTitle
, false, false, bExportContent
, sChartType
);
2575 xNewAxis
= lcl_getAxis( xCooSys
, XML_Z
);
2578 Reference
< beans::XPropertySet
> xAxisProps( xAxisSupp
.is() ? xAxisSupp
->getAxis(2) : nullptr, uno::UNO_QUERY
);
2579 exportAxis( XML_Z
, XML_PRIMARY_Z
, xAxisProps
, xNewAxis
, aCategoriesRange
, bHasZAxisTitle
, bHasZAxisMajorGrid
, bHasZAxisMinorGrid
, bExportContent
, sChartType
);
2585 bool lcl_hasNoValuesButText( const uno::Reference
< chart2::data::XDataSequence
>& xDataSequence
)
2587 if( !xDataSequence
.is() )
2588 return false;//have no data
2590 Sequence
< uno::Any
> aData
;
2591 Reference
< chart2::data::XNumericalDataSequence
> xNumericalDataSequence( xDataSequence
, uno::UNO_QUERY
);
2592 if( xNumericalDataSequence
.is() )
2594 const Sequence
< double > aDoubles( xNumericalDataSequence
->getNumericalData() );
2595 if (std::any_of(aDoubles
.begin(), aDoubles
.end(), [](double fDouble
) { return !std::isnan( fDouble
); }))
2596 return false;//have double value
2600 aData
= xDataSequence
->getData();
2601 double fDouble
= 0.0;
2602 bool bHaveDouble
= std::any_of(std::cbegin(aData
), std::cend(aData
),
2603 [&fDouble
](const uno::Any
& rData
) { return (rData
>>= fDouble
) && !std::isnan( fDouble
); });
2605 return false;//have double value
2609 Reference
< chart2::data::XTextualDataSequence
> xTextualDataSequence( xDataSequence
, uno::UNO_QUERY
);
2610 if( xTextualDataSequence
.is() )
2612 const uno::Sequence
< OUString
> aStrings( xTextualDataSequence
->getTextualData() );
2613 if (std::any_of(aStrings
.begin(), aStrings
.end(), [](const OUString
& rString
) { return !rString
.isEmpty(); }))
2614 return true;//have text
2618 if( !aData
.hasElements() )
2619 aData
= xDataSequence
->getData();
2621 bool bHaveText
= std::any_of(std::cbegin(aData
), std::cend(aData
),
2622 [&aString
](const uno::Any
& rData
) { return (rData
>>= aString
) && !aString
.isEmpty(); });
2624 return true;//have text
2626 //no doubles and no texts
2630 // ODF has the line and fill properties in a <style:style> element, which is referenced by the
2631 // <chart:data-label> element. But LibreOffice has them as special label properties of the series
2632 // or point respectively. The following method generates ODF from internal API name.
2633 void lcl_createDataLabelProperties(
2634 std::vector
<XMLPropertyState
>& rDataLabelPropertyStates
,
2635 const Reference
<beans::XPropertySet
>& xPropSet
,
2636 const rtl::Reference
<XMLChartExportPropertyMapper
>& xExpPropMapper
)
2638 if (!xExpPropMapper
.is() || !xPropSet
.is())
2641 const uno::Reference
<beans::XPropertySetInfo
> xInfo(xPropSet
->getPropertySetInfo());
2642 const uno::Reference
<beans::XPropertyState
> xPropState(xPropSet
, uno::UNO_QUERY
);
2643 const rtl::Reference
<XMLPropertySetMapper
>& rPropertySetMapper(
2644 xExpPropMapper
->getPropertySetMapper());
2645 if (!xInfo
.is() || !xPropState
.is() || !rPropertySetMapper
.is())
2648 struct API2ODFMapItem
2651 sal_uInt16 nNameSpace
; // from include/xmloff/xmlnamespace.hxx
2652 OUString sLocalName
;
2653 API2ODFMapItem(OUString sAPI
, const sal_uInt16 nNS
, OUString sLocal
)
2654 : sAPIName(std::move(sAPI
))
2656 , sLocalName(std::move(sLocal
))
2661 const API2ODFMapItem aLabelFoo2ODFArray
[]
2662 = { API2ODFMapItem("LabelBorderStyle", XML_NAMESPACE_DRAW
, "stroke"),
2663 API2ODFMapItem("LabelBorderWidth", XML_NAMESPACE_SVG
, "stroke-width"),
2664 API2ODFMapItem("LabelBorderColor", XML_NAMESPACE_SVG
, "stroke-color"),
2665 API2ODFMapItem("LabelBorderDashName", XML_NAMESPACE_DRAW
, "stroke-dash"),
2666 API2ODFMapItem("LabelBorderTransparency", XML_NAMESPACE_SVG
, "stroke-opacity"),
2667 API2ODFMapItem("LabelFillStyle", XML_NAMESPACE_DRAW
, "fill"),
2668 API2ODFMapItem("LabelFillBackground", XML_NAMESPACE_DRAW
, "fill-hatch-solid"),
2669 API2ODFMapItem("LabelFillHatchName", XML_NAMESPACE_DRAW
, "fill-hatch-name"),
2670 API2ODFMapItem("LabelFillColor", XML_NAMESPACE_DRAW
, "fill-color") };
2672 for (const auto& rIt
: aLabelFoo2ODFArray
)
2674 if (!xInfo
->hasPropertyByName(rIt
.sAPIName
)
2675 || xPropState
->getPropertyState(rIt
.sAPIName
) != beans::PropertyState_DIRECT_VALUE
)
2677 sal_Int32 nTargetIndex
2678 = rPropertySetMapper
->GetEntryIndex(rIt
.nNameSpace
, rIt
.sLocalName
, 0);
2679 if (nTargetIndex
< 0)
2681 XMLPropertyState
aDataLabelStateItem(nTargetIndex
,
2682 xPropSet
->getPropertyValue(rIt
.sAPIName
));
2683 rDataLabelPropertyStates
.emplace_back(aDataLabelStateItem
);
2686 } // anonymous namespace
2688 void SchXMLExportHelper_Impl::exportSeries(
2689 const Reference
< chart2::XDiagram
> & xNewDiagram
,
2690 const awt::Size
& rPageSize
,
2691 bool bExportContent
,
2694 Reference
< chart2::XCoordinateSystemContainer
> xBCooSysCnt( xNewDiagram
, uno::UNO_QUERY
);
2695 if( ! xBCooSysCnt
.is())
2697 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
2699 OUString aFirstXDomainRange
;
2700 OUString aFirstYDomainRange
;
2702 std::vector
< XMLPropertyState
> aPropertyStates
;
2703 std::vector
< XMLPropertyState
> aDataLabelPropertyStates
;
2705 const Sequence
< Reference
< chart2::XCoordinateSystem
> >
2706 aCooSysSeq( xBCooSysCnt
->getCoordinateSystems());
2707 for( const auto& rCooSys
: aCooSysSeq
)
2709 Reference
< chart2::XChartTypeContainer
> xCTCnt( rCooSys
, uno::UNO_QUERY
);
2712 const Sequence
< Reference
< chart2::XChartType
> > aCTSeq( xCTCnt
->getChartTypes());
2713 for( const auto& rChartType
: aCTSeq
)
2715 Reference
< chart2::XDataSeriesContainer
> xDSCnt( rChartType
, uno::UNO_QUERY
);
2718 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
2719 OUString
aChartType( rChartType
->getChartType());
2720 OUString aLabelRole
= rChartType
->getRoleOfSequenceForSeriesLabel();
2722 // special export for stock charts
2723 if ( aChartType
== "com.sun.star.chart2.CandleStickChartType" )
2725 bool bJapaneseCandleSticks
= false;
2726 Reference
< beans::XPropertySet
> xCTProp( rChartType
, uno::UNO_QUERY
);
2728 xCTProp
->getPropertyValue("Japanese") >>= bJapaneseCandleSticks
;
2729 exportCandleStickSeries(
2730 xDSCnt
->getDataSeries(), xNewDiagram
, bJapaneseCandleSticks
, bExportContent
);
2734 // export dataseries for current chart-type
2735 Sequence
< Reference
< chart2::XDataSeries
> > aSeriesSeq( xDSCnt
->getDataSeries());
2736 for( sal_Int32 nSeriesIdx
=0; nSeriesIdx
<aSeriesSeq
.getLength(); ++nSeriesIdx
)
2739 Reference
< chart2::data::XDataSource
> xSource( aSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
);
2742 std::unique_ptr
<SvXMLElementExport
> pSeries
;
2743 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
2744 xSource
->getDataSequences());
2745 sal_Int32 nMainSequenceIndex
= -1;
2746 sal_Int32 nSeriesLength
= 0;
2747 bool bHasMeanValueLine
= false;
2748 Reference
< beans::XPropertySet
> xPropSet
;
2749 tLabelValuesDataPair aSeriesLabelValuesPair
;
2751 // search for main sequence and create a series element
2753 Reference
< chart2::data::XDataSequence
> xValuesSeq
;
2754 Reference
< chart2::data::XDataSequence
> xLabelSeq
;
2755 sal_Int32 nSeqIdx
=0;
2756 for( ; nSeqIdx
<aSeqCnt
.getLength(); ++nSeqIdx
)
2758 Reference
< chart2::data::XDataSequence
> xTempValueSeq( aSeqCnt
[nSeqIdx
]->getValues() );
2759 if( nMainSequenceIndex
==-1 )
2762 Reference
< beans::XPropertySet
> xSeqProp( xTempValueSeq
, uno::UNO_QUERY
);
2764 xSeqProp
->getPropertyValue("Role") >>= aRole
;
2766 if( aRole
== aLabelRole
)
2768 xValuesSeq
.set( xTempValueSeq
);
2769 xLabelSeq
.set( aSeqCnt
[nSeqIdx
]->getLabel());
2770 nMainSequenceIndex
= nSeqIdx
;
2773 sal_Int32 nSequenceLength
= (xTempValueSeq
.is()? xTempValueSeq
->getData().getLength() : sal_Int32(0));
2774 if( nSeriesLength
< nSequenceLength
)
2775 nSeriesLength
= nSequenceLength
;
2778 // have found the main sequence, then xValuesSeq and
2779 // xLabelSeq contain those. Otherwise both are empty
2781 sal_Int32 nAttachedAxis
= chart::ChartAxisAssign::PRIMARY_Y
;
2782 // get property states for autostyles
2785 xPropSet
= SchXMLSeriesHelper::createOldAPISeriesPropertySet(
2786 aSeriesSeq
[nSeriesIdx
], mrExport
.GetModel() );
2788 catch( const uno::Exception
& )
2790 TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" );
2795 // determine attached axis
2798 Any
aAny( xPropSet
->getPropertyValue( "Axis" ));
2799 aAny
>>= nAttachedAxis
;
2801 aAny
= xPropSet
->getPropertyValue( "MeanValue" );
2802 aAny
>>= bHasMeanValueLine
;
2804 catch( const beans::UnknownPropertyException
& )
2806 TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
2809 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2810 mrExport
.getSaneDefaultVersion());
2811 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
2813 lcl_exportNumberFormat( "NumberFormat", xPropSet
, mrExport
);
2814 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet
, mrExport
);
2817 if( mxExpPropMapper
.is())
2818 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
2821 if( bExportContent
)
2825 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
2826 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
2828 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
2832 AddAutoStyleAttribute( aPropertyStates
);
2834 if( xValuesSeq
.is())
2835 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
,
2837 xValuesSeq
->getSourceRangeRepresentation(),
2840 // #i75297# allow empty series, export empty range to have all ranges on import
2841 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, OUString());
2843 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
2844 mrExport
.getSaneDefaultVersion());
2845 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) // do not export to ODF 1.3 or older
2849 Any aAny
= xPropSet
->getPropertyValue("ShowLegendEntry");
2850 if (!aAny
.get
<bool>())
2852 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_HIDE_LEGEND
, OUString::boolean(true));
2859 // Check if the label is direct string value rather than a reference.
2860 bool bHasString
= false;
2861 uno::Reference
<beans::XPropertySet
> xLSProp(xLabelSeq
, uno::UNO_QUERY
);
2866 xLSProp
->getPropertyValue("HasStringLabel") >>= bHasString
;
2868 catch (const beans::UnknownPropertyException
&) {}
2871 OUString aRange
= xLabelSeq
->getSourceRangeRepresentation();
2875 mrExport
.AddAttribute(
2876 XML_NAMESPACE_LO_EXT
, XML_LABEL_STRING
, aRange
);
2880 mrExport
.AddAttribute(
2881 XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
,
2883 xLabelSeq
->getSourceRangeRepresentation(), xNewDoc
));
2887 if( xLabelSeq
.is() || xValuesSeq
.is() )
2888 aSeriesLabelValuesPair
= tLabelValuesDataPair( xLabelSeq
, xValuesSeq
);
2890 // chart-type for mixed types
2891 enum XMLTokenEnum
eCTToken(
2892 SchXMLTools::getTokenByChartType( aChartType
, false /* bUseOldNames */ ));
2893 //@todo: get token for current charttype
2894 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_CLASS
,
2895 mrExport
.GetNamespaceMap().GetQNameByKey(
2896 XML_NAMESPACE_CHART
, GetXMLToken( eCTToken
)));
2898 // open series element until end of for loop
2899 pSeries
.reset(new SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true ));
2903 CollectAutoStyle( std::move(aPropertyStates
) );
2905 // remove property states for autostyles
2906 aPropertyStates
.clear();
2910 // export domain elements if we have a series parent element
2914 if( bExportContent
)
2916 bool bIsScatterChart
= aChartType
== "com.sun.star.chart2.ScatterChartType";
2917 bool bIsBubbleChart
= aChartType
== "com.sun.star.chart2.BubbleChartType";
2918 Reference
< chart2::data::XDataSequence
> xYValuesForBubbleChart
;
2919 if( bIsBubbleChart
)
2921 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, "values-y" ) );
2922 if( xSequence
.is() )
2924 xYValuesForBubbleChart
= xSequence
->getValues();
2925 if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart
, aFirstYDomainRange
, mrExport
) )
2926 xYValuesForBubbleChart
= nullptr;
2929 if( bIsScatterChart
|| bIsBubbleChart
)
2931 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, "values-x" ) );
2932 if( xSequence
.is() )
2934 Reference
< chart2::data::XDataSequence
> xValues( xSequence
->getValues() );
2935 if( lcl_exportDomainForThisSequence( xValues
, aFirstXDomainRange
, mrExport
) )
2936 m_aDataSequencesToExport
.emplace_back(
2937 uno::Reference
< chart2::data::XDataSequence
>(), xValues
);
2939 else if( nSeriesIdx
==0 )
2941 //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly
2942 Reference
< chart2::data::XLabeledDataSequence
> xCategories( lcl_getCategories( xNewDiagram
) );
2943 if( xCategories
.is() )
2945 Reference
< chart2::data::XDataSequence
> xValues( xCategories
->getValues() );
2946 if( !lcl_hasNoValuesButText( xValues
) )
2947 lcl_exportDomainForThisSequence( xValues
, aFirstXDomainRange
, mrExport
);
2951 if( xYValuesForBubbleChart
.is() )
2952 m_aDataSequencesToExport
.emplace_back(
2953 uno::Reference
< chart2::data::XDataSequence
>(), xYValuesForBubbleChart
);
2957 // add sequences for main sequence after domain sequences,
2958 // so that the export of the local table has the correct order
2959 if( bExportContent
&&
2960 (aSeriesLabelValuesPair
.first
.is() || aSeriesLabelValuesPair
.second
.is()))
2961 m_aDataSequencesToExport
.push_back( aSeriesLabelValuesPair
);
2963 // statistical objects:
2964 // regression curves and mean value lines
2965 if( bHasMeanValueLine
&&
2967 mxExpPropMapper
.is() )
2969 Reference
< beans::XPropertySet
> xStatProp
;
2972 Any
aPropAny( xPropSet
->getPropertyValue( "DataMeanValueProperties" ));
2973 aPropAny
>>= xStatProp
;
2975 catch( const uno::Exception
& )
2977 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" );
2980 if( xStatProp
.is() )
2982 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xStatProp
);
2984 if( !aPropertyStates
.empty() )
2987 if( bExportContent
)
2989 // add style name attribute
2990 AddAutoStyleAttribute( aPropertyStates
);
2992 SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_MEAN_VALUE
, true, true );
2996 CollectAutoStyle( std::move(aPropertyStates
) );
3002 if( xPropSet
.is() &&
3003 mxExpPropMapper
.is() )
3005 exportRegressionCurve( aSeriesSeq
[nSeriesIdx
], rPageSize
, bExportContent
);
3008 exportErrorBar( xPropSet
,false, bExportContent
); // X ErrorBar
3009 exportErrorBar( xPropSet
,true, bExportContent
); // Y ErrorBar
3012 uno::Reference
< beans::XPropertySet
>( aSeriesSeq
[nSeriesIdx
], uno::UNO_QUERY
),
3013 nSeriesLength
, xNewDiagram
, bExportContent
);
3015 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3016 mrExport
.getSaneDefaultVersion());
3018 // create <chart:data-label> child element if needed.
3019 if (xPropSet
.is() && mxExpPropMapper
.is())
3021 // Generate style for <chart:data-label> child element
3022 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3024 lcl_createDataLabelProperties(aDataLabelPropertyStates
, xPropSet
,
3030 if (!aDataLabelPropertyStates
.empty())
3033 AddAutoStyleAttribute(aDataLabelPropertyStates
);
3034 // Further content does currently not exist for a <chart:data-label>
3035 // element as child of a <chart:series>.
3036 SvXMLElementExport(mrExport
, XML_NAMESPACE_CHART
, XML_DATA_LABEL
, true,
3042 // add the style for the to be <chart:data-label> too
3043 if (!aDataLabelPropertyStates
.empty())
3044 CollectAutoStyle(std::move(aDataLabelPropertyStates
));
3046 aDataLabelPropertyStates
.clear();
3048 if (bExportContent
&& nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) // do not export to ODF 1.3 or older
3050 Sequence
< OUString
> aSupportedMappings
= rChartType
->getSupportedPropertyRoles();
3051 exportPropertyMapping( xSource
, aSupportedMappings
);
3054 // close series element
3058 aPropertyStates
.clear();
3059 aDataLabelPropertyStates
.clear();
3064 void SchXMLExportHelper_Impl::exportPropertyMapping(
3065 const Reference
< chart2::data::XDataSource
> & xSource
, const Sequence
< OUString
>& rSupportedMappings
)
3067 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
3068 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
3069 xSource
->getDataSequences());
3071 for(const auto& rSupportedMapping
: rSupportedMappings
)
3073 Reference
< chart2::data::XLabeledDataSequence
> xSequence( lcl_getDataSequenceByRole( aSeqCnt
, rSupportedMapping
) );
3076 Reference
< chart2::data::XDataSequence
> xValues( xSequence
->getValues() );
3079 mrExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_PROPERTY
, rSupportedMapping
);
3080 mrExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_CELL_RANGE_ADDRESS
,
3082 xValues
->getSourceRangeRepresentation(),
3084 SvXMLElementExport( mrExport
, XML_NAMESPACE_LO_EXT
, XML_PROPERTY_MAPPING
, true, true );
3086 // register range for data table export
3087 m_aDataSequencesToExport
.emplace_back(
3088 uno::Reference
< chart2::data::XDataSequence
>(), xValues
);
3094 void SchXMLExportHelper_Impl::exportRegressionCurve(
3095 const Reference
< chart2::XDataSeries
>& xSeries
,
3096 const awt::Size
& rPageSize
,
3097 bool bExportContent
)
3099 OSL_ASSERT( mxExpPropMapper
.is());
3101 Reference
< chart2::XRegressionCurveContainer
> xRegressionCurveContainer( xSeries
, uno::UNO_QUERY
);
3102 if( !xRegressionCurveContainer
.is() )
3105 const Sequence
< Reference
< chart2::XRegressionCurve
> > aRegCurveSeq
= xRegressionCurveContainer
->getRegressionCurves();
3107 for( const auto& xRegCurve
: aRegCurveSeq
)
3109 std::vector
< XMLPropertyState
> aEquationPropertyStates
;
3110 if (!xRegCurve
.is())
3113 Reference
< beans::XPropertySet
> xProperties( xRegCurve
, uno::UNO_QUERY
);
3114 if( !xProperties
.is() )
3117 Reference
< lang::XServiceName
> xServiceName( xProperties
, uno::UNO_QUERY
);
3118 if( !xServiceName
.is() )
3121 bool bShowEquation
= false;
3122 bool bShowRSquared
= false;
3123 bool bExportEquation
= false;
3125 OUString aService
= xServiceName
->getServiceName();
3127 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xProperties
);
3129 // Add service name (which is regression type)
3130 sal_Int32 nIndex
= GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE
);
3131 XMLPropertyState
property(nIndex
, uno::Any(aService
));
3132 aPropertyStates
.push_back(property
);
3134 Reference
< beans::XPropertySet
> xEquationProperties
;
3135 xEquationProperties
.set( xRegCurve
->getEquationProperties() );
3136 if( xEquationProperties
.is())
3138 xEquationProperties
->getPropertyValue( "ShowEquation") >>= bShowEquation
;
3139 xEquationProperties
->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowRSquared
;
3141 bExportEquation
= ( bShowEquation
|| bShowRSquared
);
3142 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentVersion(
3143 mrExport
.getSaneDefaultVersion());
3144 if (nCurrentVersion
< SvtSaveOptions::ODFSVER_012
)
3146 bExportEquation
=false;
3148 if( bExportEquation
)
3151 sal_Int32 nNumberFormat
= 0;
3152 if( (xEquationProperties
->getPropertyValue("NumberFormat") >>= nNumberFormat
) &&
3153 nNumberFormat
!= -1 )
3155 mrExport
.addDataStyle( nNumberFormat
);
3157 aEquationPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xEquationProperties
);
3161 if( !aPropertyStates
.empty() || bExportEquation
)
3164 if( bExportContent
)
3166 // add style name attribute
3167 if( !aPropertyStates
.empty())
3169 AddAutoStyleAttribute( aPropertyStates
);
3172 SvXMLElementExport
aRegressionExport( mrExport
, XML_NAMESPACE_CHART
, XML_REGRESSION_CURVE
, true, true );
3173 if( bExportEquation
)
3175 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DISPLAY_EQUATION
, (bShowEquation
? XML_TRUE
: XML_FALSE
) );
3176 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DISPLAY_R_SQUARE
, (bShowRSquared
? XML_TRUE
: XML_FALSE
) );
3179 chart2::RelativePosition aRelativePosition
;
3180 if( xEquationProperties
->getPropertyValue( "RelativePosition" ) >>= aRelativePosition
)
3182 double fX
= aRelativePosition
.Primary
* rPageSize
.Width
;
3183 double fY
= aRelativePosition
.Secondary
* rPageSize
.Height
;
3185 aPos
.X
= static_cast< sal_Int32
>( ::rtl::math::round( fX
));
3186 aPos
.Y
= static_cast< sal_Int32
>( ::rtl::math::round( fY
));
3187 addPosition( aPos
);
3190 if( !aEquationPropertyStates
.empty())
3192 AddAutoStyleAttribute( aEquationPropertyStates
);
3195 SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_EQUATION
, true, true );
3200 if( !aPropertyStates
.empty())
3202 CollectAutoStyle( std::move(aPropertyStates
) );
3204 if( bExportEquation
&& !aEquationPropertyStates
.empty())
3206 CollectAutoStyle( std::move(aEquationPropertyStates
) );
3213 void SchXMLExportHelper_Impl::exportErrorBar( const Reference
<beans::XPropertySet
> &xSeriesProp
,
3214 bool bYError
, bool bExportContent
)
3216 assert(mxExpPropMapper
.is());
3218 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentVersion(
3219 mrExport
.getSaneDefaultVersion());
3221 /// Don't export X ErrorBars for older ODF versions.
3222 if (!bYError
&& nCurrentVersion
< SvtSaveOptions::ODFSVER_012
)
3225 if (!xSeriesProp
.is())
3228 bool bNegative
= false, bPositive
= false;
3229 sal_Int32 nErrorBarStyle
= chart::ErrorBarStyle::NONE
;
3230 Reference
< beans::XPropertySet
> xErrorBarProp
;
3234 Any aAny
= xSeriesProp
->getPropertyValue( bYError
? OUString("ErrorBarY") : OUString("ErrorBarX") );
3235 aAny
>>= xErrorBarProp
;
3237 if ( xErrorBarProp
.is() )
3239 aAny
= xErrorBarProp
->getPropertyValue("ShowNegativeError" );
3242 aAny
= xErrorBarProp
->getPropertyValue("ShowPositiveError" );
3245 aAny
= xErrorBarProp
->getPropertyValue("ErrorBarStyle" );
3246 aAny
>>= nErrorBarStyle
;
3249 catch( const beans::UnknownPropertyException
& )
3251 TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
3254 if( !(nErrorBarStyle
!= chart::ErrorBarStyle::NONE
&& (bNegative
|| bPositive
)))
3257 if( bExportContent
&& nErrorBarStyle
== chart::ErrorBarStyle::FROM_DATA
)
3259 // register data ranges for error bars for export in local table
3260 ::std::vector
< Reference
< chart2::data::XDataSequence
> > aErrorBarSequences(
3261 lcl_getErrorBarSequences( xErrorBarProp
));
3262 for( const auto& rErrorBarSequence
: aErrorBarSequences
)
3264 m_aDataSequencesToExport
.emplace_back(
3265 uno::Reference
< chart2::data::XDataSequence
>(), rErrorBarSequence
);
3269 std::vector
<XMLPropertyState
> aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xErrorBarProp
);
3271 if( aPropertyStates
.empty() )
3275 if( bExportContent
)
3277 // add style name attribute
3278 AddAutoStyleAttribute( aPropertyStates
);
3280 if (nCurrentVersion
>= SvtSaveOptions::ODFSVER_012
)
3281 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_DIMENSION
, bYError
? XML_Y
: XML_X
);//#i114149#
3282 SvXMLElementExport( mrExport
, XML_NAMESPACE_CHART
, XML_ERROR_INDICATOR
, true, true );
3286 CollectAutoStyle( std::move(aPropertyStates
) );
3290 void SchXMLExportHelper_Impl::exportCandleStickSeries(
3291 const Sequence
< Reference
< chart2::XDataSeries
> > & aSeriesSeq
,
3292 const Reference
< chart2::XDiagram
> & xDiagram
,
3293 bool bJapaneseCandleSticks
,
3294 bool bExportContent
)
3297 for( const auto& xSeries
: aSeriesSeq
)
3299 sal_Int32 nAttachedAxis
= lcl_isSeriesAttachedToFirstAxis( xSeries
)
3300 ? chart::ChartAxisAssign::PRIMARY_Y
3301 : chart::ChartAxisAssign::SECONDARY_Y
;
3303 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
3306 // export series in correct order (as we don't store roles)
3307 // with japanese candlesticks: open, low, high, close
3308 // otherwise: low, high, close
3309 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aSeqCnt(
3310 xSource
->getDataSequences());
3312 sal_Int32 nSeriesLength
=
3313 lcl_getSequenceLengthByRole( aSeqCnt
, "values-last");
3315 if( bExportContent
)
3317 Reference
< chart2::XChartDocument
> xNewDoc( mrExport
.GetModel(), uno::UNO_QUERY
);
3318 //@todo: export data points
3320 //TODO: moggi: same code three times
3322 if( bJapaneseCandleSticks
)
3324 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3325 aSeqCnt
, "values-first", xNewDoc
, m_aDataSequencesToExport
));
3326 if( !aRanges
.second
.isEmpty())
3327 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3328 if( !aRanges
.first
.isEmpty())
3329 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3330 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3331 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3333 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3334 SvXMLElementExport
aOpenSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3335 // export empty data points
3336 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3341 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3342 aSeqCnt
, "values-min", xNewDoc
, m_aDataSequencesToExport
));
3343 if( !aRanges
.second
.isEmpty())
3344 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3345 if( !aRanges
.first
.isEmpty())
3346 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3347 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3348 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3350 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3351 SvXMLElementExport
aLowSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3352 // export empty data points
3353 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3358 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3359 aSeqCnt
, "values-max", xNewDoc
, m_aDataSequencesToExport
));
3360 if( !aRanges
.second
.isEmpty())
3361 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3362 if( !aRanges
.first
.isEmpty())
3363 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3364 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3365 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3367 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3368 SvXMLElementExport
aHighSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3369 // export empty data points
3370 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3375 tLabelAndValueRange
aRanges( lcl_getLabelAndValueRangeByRole(
3376 aSeqCnt
, "values-last", xNewDoc
, m_aDataSequencesToExport
));
3377 if( !aRanges
.second
.isEmpty())
3378 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_VALUES_CELL_RANGE_ADDRESS
, aRanges
.second
);
3379 if( !aRanges
.first
.isEmpty())
3380 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_LABEL_CELL_ADDRESS
, aRanges
.first
);
3381 if( nAttachedAxis
== chart::ChartAxisAssign::SECONDARY_Y
)
3382 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_SECONDARY_Y
);
3384 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_ATTACHED_AXIS
, XML_PRIMARY_Y
);
3385 SvXMLElementExport
aCloseSeries( mrExport
, XML_NAMESPACE_CHART
, XML_SERIES
, true, true );
3386 // export empty data points
3387 exportDataPoints( nullptr, nSeriesLength
, xDiagram
, bExportContent
);
3394 // remove property states for autostyles
3399 void SchXMLExportHelper_Impl::exportDataPoints(
3400 const uno::Reference
< beans::XPropertySet
> & xSeriesProperties
,
3401 sal_Int32 nSeriesLength
,
3402 const uno::Reference
< chart2::XDiagram
> & xDiagram
,
3403 bool bExportContent
)
3407 // write data-points only if they contain autostyles
3408 // objects with equal autostyles are grouped using the attribute
3411 // Note: if only the nth data-point has autostyles there is an element
3412 // without style and repeat="n-1" attribute written in advance.
3414 // the sequence aDataPointSeq contains indices of data-points that
3415 // do have own attributes. This increases the performance substantially.
3417 // more performant version for #93600#
3418 if (!mxExpPropMapper
.is())
3421 uno::Reference
< chart2::XDataSeries
> xSeries( xSeriesProperties
, uno::UNO_QUERY
);
3423 std::vector
< XMLPropertyState
> aPropertyStates
;
3424 std::vector
<XMLPropertyState
> aDataLabelPropertyStates
;
3426 bool bVaryColorsByPoint
= false;
3427 Sequence
< sal_Int32
> aDataPointSeq
;
3428 Sequence
<sal_Int32
> deletedLegendEntriesSeq
;
3429 if( xSeriesProperties
.is())
3431 xSeriesProperties
->getPropertyValue("AttributedDataPoints") >>= aDataPointSeq
;
3432 xSeriesProperties
->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint
;
3434 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3435 mrExport
.getSaneDefaultVersion());
3436 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) // do not export to ODF 1.3 or older
3437 xSeriesProperties
->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq
;
3440 sal_Int32 nSize
= aDataPointSeq
.getLength();
3441 SAL_WARN_IF( nSize
> nSeriesLength
, "xmloff.chart", "Too many point attributes" );
3443 const sal_Int32
* pPoints
= aDataPointSeq
.getConstArray();
3445 Reference
< chart2::XColorScheme
> xColorScheme
;
3447 xColorScheme
.set( xDiagram
->getDefaultColorScheme());
3449 ::std::vector
< SchXMLDataPointStruct
> aDataPointVector
;
3451 sal_Int32 nLastIndex
= -1;
3454 if( bVaryColorsByPoint
&& xColorScheme
.is() )
3456 o3tl::sorted_vector
< sal_Int32
> aAttrPointSet
;
3457 aAttrPointSet
.reserve(aDataPointSeq
.getLength());
3458 for (auto p
= pPoints
; p
< pPoints
+ aDataPointSeq
.getLength(); ++p
)
3459 aAttrPointSet
.insert( *p
);
3460 const auto aEndIt
= aAttrPointSet
.end();
3461 for( nElement
= 0; nElement
< nSeriesLength
; ++nElement
)
3463 aPropertyStates
.clear();
3464 aDataLabelPropertyStates
.clear();
3465 uno::Reference
< beans::XPropertySet
> xPropSet
;
3466 bool bExportNumFmt
= false;
3467 if( aAttrPointSet
.find( nElement
) != aEndIt
)
3471 xPropSet
= SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3472 xSeries
, nElement
, mrExport
.GetModel() );
3473 bExportNumFmt
= true;
3475 catch( const uno::Exception
& )
3477 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3482 // property set only containing the color
3483 xPropSet
.set( new ::xmloff::chart::ColorPropertySet(
3484 ::Color(ColorTransparency
, xColorScheme
->getColorByIndex( nElement
))));
3486 SAL_WARN_IF( !xPropSet
.is(), "xmloff.chart", "Pie Segments should have properties" );
3489 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3490 mrExport
.getSaneDefaultVersion());
3491 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
&& bExportNumFmt
)
3493 lcl_exportNumberFormat( "NumberFormat", xPropSet
, mrExport
);
3494 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet
, mrExport
);
3497 // Generate style for <chart:data-label> child element
3498 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3500 lcl_createDataLabelProperties(aDataLabelPropertyStates
, xPropSet
,
3504 if (nCurrentODFVersion
& SvtSaveOptions::ODFSVER_EXTENDED
)
3506 sal_Int32 nPlacement
= 0;
3507 xPropSet
->getPropertyValue("LabelPlacement") >>= nPlacement
;
3508 if (nPlacement
== chart::DataLabelPlacement::CUSTOM
)
3510 xPropSet
->setPropertyValue("LabelPlacement",
3511 uno::Any(chart::DataLabelPlacement::OUTSIDE
));
3515 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
3516 if (!aPropertyStates
.empty() || !aDataLabelPropertyStates
.empty())
3520 // write data-point with style
3521 SchXMLDataPointStruct aPoint
;
3522 if (!aPropertyStates
.empty())
3524 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3525 "Autostyle queue empty!");
3526 aPoint
.maStyleName
= maAutoStyleNameQueue
.front();
3527 maAutoStyleNameQueue
.pop();
3529 if (!aDataLabelPropertyStates
.empty())
3531 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3532 "Autostyle queue empty!");
3533 aPoint
.msDataLabelStyleName
= maAutoStyleNameQueue
.front();
3534 maAutoStyleNameQueue
.pop();
3537 aPoint
.mCustomLabel
= lcl_getCustomLabelField(mrExport
, nElement
, xSeries
);
3538 aPoint
.mCustomLabelPos
= lcl_getCustomLabelPosition(mrExport
, nElement
, xSeries
);
3540 aDataPointVector
.push_back( aPoint
);
3544 if (!aPropertyStates
.empty())
3545 CollectAutoStyle(std::move(aPropertyStates
));
3546 if (!aDataLabelPropertyStates
.empty())
3547 CollectAutoStyle(std::move(aDataLabelPropertyStates
));
3552 SAL_WARN_IF( bExportContent
&& (static_cast<sal_Int32
>(aDataPointVector
.size()) != nSeriesLength
), "xmloff.chart", "not enough data points on content export" );
3556 for( sal_Int32 nCurrIndex
: std::as_const(aDataPointSeq
) )
3558 aPropertyStates
.clear();
3559 aDataLabelPropertyStates
.clear();
3560 //assuming sorted indices in pPoints
3562 if( nCurrIndex
<0 || nCurrIndex
>=nSeriesLength
)
3565 // write leading empty data points
3566 if( nCurrIndex
- nLastIndex
> 1 )
3568 SchXMLDataPointStruct aPoint
;
3569 aPoint
.mnRepeat
= nCurrIndex
- nLastIndex
- 1;
3570 aDataPointVector
.push_back( aPoint
);
3573 uno::Reference
< beans::XPropertySet
> xPropSet
;
3574 // get property states
3577 xPropSet
= SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3578 xSeries
, nCurrIndex
, mrExport
.GetModel() );
3580 catch( const uno::Exception
& )
3582 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3586 const SvtSaveOptions::ODFSaneDefaultVersion
nCurrentODFVersion(
3587 mrExport
.getSaneDefaultVersion());
3588 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3590 lcl_exportNumberFormat( "NumberFormat", xPropSet
, mrExport
);
3591 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet
, mrExport
);
3594 // Generate style for <chart:data-label> child element
3595 if (nCurrentODFVersion
>= SvtSaveOptions::ODFSVER_012
)
3597 lcl_createDataLabelProperties(aDataLabelPropertyStates
, xPropSet
,
3601 aPropertyStates
= mxExpPropMapper
->Filter(mrExport
, xPropSet
);
3603 if (!aPropertyStates
.empty() || !aDataLabelPropertyStates
.empty())
3605 if( bExportContent
)
3607 // write data-point with style
3608 SchXMLDataPointStruct aPoint
;
3609 if (!aPropertyStates
.empty())
3611 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3612 "Autostyle queue empty!");
3613 aPoint
.maStyleName
= maAutoStyleNameQueue
.front();
3614 maAutoStyleNameQueue
.pop();
3616 aPoint
.mCustomLabel
= lcl_getCustomLabelField(mrExport
, nCurrIndex
, xSeries
);
3617 aPoint
.mCustomLabelPos
= lcl_getCustomLabelPosition(mrExport
, nCurrIndex
, xSeries
);
3618 if (!aDataLabelPropertyStates
.empty())
3620 SAL_WARN_IF(maAutoStyleNameQueue
.empty(), "xmloff.chart",
3621 "Autostyle queue empty!");
3622 aPoint
.msDataLabelStyleName
= maAutoStyleNameQueue
.front();
3623 maAutoStyleNameQueue
.pop();
3626 aDataPointVector
.push_back( aPoint
);
3627 nLastIndex
= nCurrIndex
;
3631 if (!aPropertyStates
.empty())
3632 CollectAutoStyle(std::move(aPropertyStates
));
3633 if (!aDataLabelPropertyStates
.empty())
3634 CollectAutoStyle(std::move(aDataLabelPropertyStates
));
3640 // if we get here the property states are empty
3641 SchXMLDataPointStruct aPoint
;
3642 aDataPointVector
.push_back( aPoint
);
3644 nLastIndex
= nCurrIndex
;
3646 // final empty elements
3647 sal_Int32 nRepeat
= nSeriesLength
- nLastIndex
- 1;
3650 SchXMLDataPointStruct aPoint
;
3651 aPoint
.mnRepeat
= nRepeat
;
3652 aDataPointVector
.push_back( aPoint
);
3656 if (!bExportContent
)
3659 // write elements (merge equal ones)
3660 SchXMLDataPointStruct aPoint
;
3661 SchXMLDataPointStruct aLastPoint
;
3663 // initialize so that it doesn't matter if
3664 // the element is counted in the first iteration
3665 aLastPoint
.mnRepeat
= 0;
3666 sal_Int32 nIndex
= 0;
3667 for( const auto& rPoint
: aDataPointVector
)
3671 if (aPoint
.maStyleName
== aLastPoint
.maStyleName
3672 && aLastPoint
.mCustomLabel
.maFields
.getLength() < 1
3673 && aLastPoint
.mCustomLabelPos
.Primary
== 0.0
3674 && aLastPoint
.mCustomLabelPos
.Secondary
== 0.0
3675 && aPoint
.msDataLabelStyleName
== aLastPoint
.msDataLabelStyleName
)
3676 aPoint
.mnRepeat
+= aLastPoint
.mnRepeat
;
3677 else if( aLastPoint
.mnRepeat
> 0 )
3679 // write last element
3680 if( !aLastPoint
.maStyleName
.isEmpty() )
3681 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_STYLE_NAME
, aLastPoint
.maStyleName
);
3683 if( aLastPoint
.mnRepeat
> 1 )
3684 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_REPEATED
,
3685 OUString::number( aLastPoint
.mnRepeat
));
3687 for (const auto& deletedLegendEntry
: std::as_const(deletedLegendEntriesSeq
))
3689 if (nIndex
== deletedLegendEntry
)
3691 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_HIDE_LEGEND
, OUString::boolean(true));
3696 exportCustomLabelPosition(aLastPoint
.mCustomLabelPos
); // adds attributes
3697 SvXMLElementExport
aPointElem( mrExport
, XML_NAMESPACE_CHART
, XML_DATA_POINT
, true, true );
3698 exportCustomLabel(aLastPoint
);
3700 aLastPoint
= aPoint
;
3702 // write last element if it hasn't been written in last iteration
3703 if( aPoint
.maStyleName
!= aLastPoint
.maStyleName
)
3706 if( !aLastPoint
.maStyleName
.isEmpty() )
3707 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_STYLE_NAME
, aLastPoint
.maStyleName
);
3709 if( aLastPoint
.mnRepeat
> 1 )
3710 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_REPEATED
,
3711 OUString::number( aLastPoint
.mnRepeat
));
3713 for (const auto& deletedLegendEntry
: std::as_const(deletedLegendEntriesSeq
))
3715 if (nIndex
== deletedLegendEntry
)
3717 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_HIDE_LEGEND
, OUString::boolean(true));
3722 exportCustomLabelPosition(aLastPoint
.mCustomLabelPos
); // adds attributes
3723 SvXMLElementExport
aPointElem( mrExport
, XML_NAMESPACE_CHART
, XML_DATA_POINT
, true, true );
3724 exportCustomLabel(aLastPoint
);
3727 void SchXMLExportHelper_Impl::exportCustomLabel(const SchXMLDataPointStruct
& rPoint
)
3729 if (rPoint
.mCustomLabel
.maFields
.getLength() < 1 && rPoint
.msDataLabelStyleName
.isEmpty())
3730 return; // nothing to export
3732 if (!rPoint
.msDataLabelStyleName
.isEmpty())
3733 mrExport
.AddAttribute(XML_NAMESPACE_CHART
, XML_STYLE_NAME
, rPoint
.msDataLabelStyleName
);
3735 if (rPoint
.mCustomLabel
.mbDataLabelsRange
)
3737 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_DATA_LABELS_CELL_RANGE
, rPoint
.mCustomLabel
.maRange
);
3738 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_DATA_LABEL_GUID
, rPoint
.mCustomLabel
.maGuid
);
3740 // TODO svg:x and svg:y for <chart:data-label>
3741 SvXMLElementExport
aLabelElem( mrExport
, XML_NAMESPACE_CHART
, XML_DATA_LABEL
, true, true);
3742 SvXMLElementExport
aPara( mrExport
, XML_NAMESPACE_TEXT
, XML_P
, true, false );
3744 for (const Reference
<chart2::XDataPointCustomLabelField
>& label
: rPoint
.mCustomLabel
.maFields
)
3747 SvXMLElementExport
aSpan( mrExport
, XML_NAMESPACE_TEXT
, XML_SPAN
, true, false);
3748 mrExport
.GetDocHandler()->characters(label
->getString());
3752 void SchXMLExportHelper_Impl::exportCustomLabelPosition( const chart2::RelativePosition
& xCustomLabelPosition
)
3754 if( xCustomLabelPosition
.Primary
== 0.0 && xCustomLabelPosition
.Secondary
== 0.0 )
3755 return; // nothing to export
3757 OUStringBuffer aCustomLabelPosString
;
3758 ::sax::Converter::convertDouble(aCustomLabelPosString
, xCustomLabelPosition
.Primary
);
3759 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_CUSTOM_LABEL_POS_X
, aCustomLabelPosString
.makeStringAndClear());
3761 ::sax::Converter::convertDouble(aCustomLabelPosString
, xCustomLabelPosition
.Secondary
);
3762 mrExport
.AddAttribute(XML_NAMESPACE_LO_EXT
, XML_CUSTOM_LABEL_POS_Y
, aCustomLabelPosString
.makeStringAndClear());
3765 void SchXMLExportHelper_Impl::addPosition( const awt::Point
& rPosition
)
3767 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3768 msStringBuffer
, rPosition
.X
);
3769 msString
= msStringBuffer
.makeStringAndClear();
3770 mrExport
.AddAttribute( XML_NAMESPACE_SVG
, XML_X
, msString
);
3772 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3773 msStringBuffer
, rPosition
.Y
);
3774 msString
= msStringBuffer
.makeStringAndClear();
3775 mrExport
.AddAttribute( XML_NAMESPACE_SVG
, XML_Y
, msString
);
3778 void SchXMLExportHelper_Impl::addPosition( const Reference
< drawing::XShape
>& xShape
)
3781 addPosition( xShape
->getPosition());
3784 void SchXMLExportHelper_Impl::addSize( const awt::Size
& rSize
, bool bIsOOoNamespace
)
3786 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3787 msStringBuffer
, rSize
.Width
);
3788 msString
= msStringBuffer
.makeStringAndClear();
3789 mrExport
.AddAttribute( bIsOOoNamespace
? XML_NAMESPACE_CHART_EXT
: XML_NAMESPACE_SVG
, XML_WIDTH
, msString
);
3791 mrExport
.GetMM100UnitConverter().convertMeasureToXML(
3792 msStringBuffer
, rSize
.Height
);
3793 msString
= msStringBuffer
.makeStringAndClear();
3794 mrExport
.AddAttribute( bIsOOoNamespace
? XML_NAMESPACE_CHART_EXT
: XML_NAMESPACE_SVG
, XML_HEIGHT
, msString
);
3797 void SchXMLExportHelper_Impl::addSize( const Reference
< drawing::XShape
>& xShape
)
3800 addSize( xShape
->getSize() );
3803 awt::Size
SchXMLExportHelper_Impl::getPageSize( const Reference
< chart2::XChartDocument
> & xChartDoc
)
3805 awt::Size
aSize( 8000, 7000 );
3806 uno::Reference
< embed::XVisualObject
> xVisualObject( xChartDoc
, uno::UNO_QUERY
);
3807 SAL_WARN_IF( !xVisualObject
.is(), "xmloff.chart", "need XVisualObject for page size" );
3808 if( xVisualObject
.is() )
3809 aSize
= xVisualObject
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
);
3814 void SchXMLExportHelper_Impl::CollectAutoStyle( std::vector
< XMLPropertyState
>&& aStates
)
3816 if( !aStates
.empty() )
3817 maAutoStyleNameQueue
.push( mrAutoStylePool
.Add( XmlStyleFamily::SCH_CHART_ID
, std::move(aStates
) ));
3820 void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector
< XMLPropertyState
>& aStates
)
3822 if( !aStates
.empty() )
3824 SAL_WARN_IF( maAutoStyleNameQueue
.empty(), "xmloff.chart", "Autostyle queue empty!" );
3826 mrExport
.AddAttribute( XML_NAMESPACE_CHART
, XML_STYLE_NAME
, maAutoStyleNameQueue
.front() );
3827 maAutoStyleNameQueue
.pop();
3831 void SchXMLExportHelper_Impl::exportText( const OUString
& rText
)
3833 SchXMLTools::exportText( mrExport
, rText
, false/*bConvertTabsLFs*/ );
3837 SchXMLExport::SchXMLExport(const Reference
<uno::XComponentContext
>& xContext
,
3838 OUString
const& implementationName
, SvXMLExportFlags nExportFlags
)
3839 : SvXMLExport(xContext
, implementationName
, util::MeasureUnit::CM
, ::xmloff::token::XML_CHART
,
3841 , maAutoStylePool(new SchXMLAutoStylePoolP(*this))
3842 , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool
))
3844 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED
)
3845 GetNamespaceMap_().Add( GetXMLToken(XML_NP_CHART_EXT
), GetXMLToken(XML_N_CHART_EXT
), XML_NAMESPACE_CHART_EXT
);
3848 SchXMLExport::~SchXMLExport()
3852 ErrCode
SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass
)
3854 maExportHelper
->SetSourceShellID(GetSourceShellID());
3855 maExportHelper
->SetDestinationShellID(GetDestinationShellID());
3857 Reference
< chart2::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3858 maExportHelper
->m_pImpl
->InitRangeSegmentationProperties( xChartDoc
);
3859 return SvXMLExport::exportDoc( eClass
);
3862 void SchXMLExport::ExportMasterStyles_()
3864 // not available in chart
3865 SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" );
3868 void SchXMLExport::collectAutoStyles()
3870 SvXMLExport::collectAutoStyles();
3872 if (mbAutoStylesCollected
)
3875 // there are no styles that require their own autostyles
3876 if( getExportFlags() & SvXMLExportFlags::CONTENT
)
3878 Reference
< chart::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3881 maExportHelper
->m_pImpl
->collectAutoStyles( xChartDoc
);
3885 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3888 mbAutoStylesCollected
= true;
3891 void SchXMLExport::ExportAutoStyles_()
3893 collectAutoStyles();
3895 if( getExportFlags() & SvXMLExportFlags::CONTENT
)
3897 Reference
< chart::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3900 maExportHelper
->m_pImpl
->exportAutoStyles();
3904 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3909 void SchXMLExport::ExportContent_()
3911 Reference
< chart::XChartDocument
> xChartDoc( GetModel(), uno::UNO_QUERY
);
3914 // determine if data comes from the outside
3915 bool bIncludeTable
= true;
3917 Reference
< chart2::XChartDocument
> xNewDoc( xChartDoc
, uno::UNO_QUERY
);
3920 // check if we have own data. If so we must not export the complete
3921 // range string, as this is our only indicator for having own or
3922 // external data. @todo: fix this in the file format!
3923 Reference
< lang::XServiceInfo
> xDPServiceInfo( xNewDoc
->getDataProvider(), uno::UNO_QUERY
);
3924 if( ! (xDPServiceInfo
.is() && xDPServiceInfo
->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
3926 bIncludeTable
= false;
3931 Reference
< lang::XServiceInfo
> xServ( xChartDoc
, uno::UNO_QUERY
);
3934 if( xServ
->supportsService( "com.sun.star.chart.ChartTableAddressSupplier" ))
3936 Reference
< beans::XPropertySet
> xProp( xServ
, uno::UNO_QUERY
);
3942 OUString sChartAddress
;
3943 aAny
= xProp
->getPropertyValue( "ChartRangeAddress" );
3944 aAny
>>= sChartAddress
;
3945 maExportHelper
->m_pImpl
->SetChartRangeAddress( sChartAddress
);
3947 // do not include own table if there are external addresses
3948 bIncludeTable
= sChartAddress
.isEmpty();
3950 catch( const beans::UnknownPropertyException
& )
3952 SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" );
3958 maExportHelper
->m_pImpl
->exportChart( xChartDoc
, bIncludeTable
);
3962 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" );
3966 rtl::Reference
< XMLPropertySetMapper
> const & SchXMLExport::GetPropertySetMapper() const
3968 return maExportHelper
->m_pImpl
->GetPropertySetMapper();
3971 void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference
< chart2::XChartDocument
> & xChartDoc
)
3973 if( !xChartDoc
.is())
3978 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
3979 SAL_WARN_IF( !xDataProvider
.is(), "xmloff.chart", "No DataProvider" );
3980 if( xDataProvider
.is())
3982 Reference
< chart2::data::XDataSource
> xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc
, mbHasCategoryLabels
));
3983 const Sequence
< beans::PropertyValue
> aArgs( xDataProvider
->detectArguments( xDataSource
));
3984 OUString sCellRange
, sBrokenRange
;
3985 bool bBrokenRangeAvailable
= false;
3986 for( const auto& rArg
: aArgs
)
3988 if ( rArg
.Name
== "CellRangeRepresentation" )
3989 rArg
.Value
>>= sCellRange
;
3990 else if ( rArg
.Name
== "BrokenCellRangeForExport" )
3992 if( rArg
.Value
>>= sBrokenRange
)
3993 bBrokenRangeAvailable
= true;
3995 else if ( rArg
.Name
== "DataRowSource" )
3997 chart::ChartDataRowSource eRowSource
;
3998 rArg
.Value
>>= eRowSource
;
3999 mbRowSourceColumns
= ( eRowSource
== chart::ChartDataRowSource_COLUMNS
);
4001 else if ( rArg
.Name
== "SequenceMapping" )
4002 rArg
.Value
>>= maSequenceMapping
;
4005 // #i79009# For Writer we have to export a broken version of the
4006 // range, where every row number is not too large, so that older
4007 // version can correctly read those files.
4008 msChartAddress
= (bBrokenRangeAvailable
? sBrokenRange
: sCellRange
);
4009 if( !msChartAddress
.isEmpty() )
4011 // convert format to XML-conform one
4012 Reference
< chart2::data::XRangeXMLConversion
> xConversion( xDataProvider
, uno::UNO_QUERY
);
4013 if( xConversion
.is())
4014 msChartAddress
= xConversion
->convertRangeToXML( msChartAddress
);
4018 catch( const uno::Exception
& )
4020 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
4024 // first version: everything goes in one storage
4026 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4027 com_sun_star_comp_Chart_XMLExporter_get_implementation(uno::XComponentContext
* pCtx
,
4028 uno::Sequence
<uno::Any
> const& /*rSeq*/)
4030 return cppu::acquire(
4031 new SchXMLExport(pCtx
, "SchXMLExport.Compact",
4032 SvXMLExportFlags::ALL
4033 ^ (SvXMLExportFlags::SETTINGS
| SvXMLExportFlags::MASTERSTYLES
4034 | SvXMLExportFlags::SCRIPTS
)));
4038 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4039 com_sun_star_comp_Chart_XMLOasisExporter_get_implementation(uno::XComponentContext
* pCtx
,
4040 uno::Sequence
<uno::Any
> const& /*rSeq*/)
4042 return cppu::acquire(
4043 new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Compact",
4044 (SvXMLExportFlags::ALL
4045 ^ (SvXMLExportFlags::SETTINGS
| SvXMLExportFlags::MASTERSTYLES
4046 | SvXMLExportFlags::SCRIPTS
))
4047 | SvXMLExportFlags::OASIS
));
4050 // multiple storage version: one for content / styles / meta
4052 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4053 com_sun_star_comp_Chart_XMLStylesExporter_get_implementation(
4054 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4056 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Styles", SvXMLExportFlags::STYLES
));
4060 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4061 com_sun_star_comp_Chart_XMLOasisStylesExporter_get_implementation(
4062 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4064 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Styles",
4065 SvXMLExportFlags::STYLES
| SvXMLExportFlags::OASIS
));
4068 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4069 com_sun_star_comp_Chart_XMLContentExporter_get_implementation(
4070 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4072 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Content",
4073 SvXMLExportFlags::AUTOSTYLES
| SvXMLExportFlags::CONTENT
4074 | SvXMLExportFlags::FONTDECLS
));
4077 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4078 com_sun_star_comp_Chart_XMLOasisContentExporter_get_implementation(
4079 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4081 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Content",
4082 SvXMLExportFlags::AUTOSTYLES
| SvXMLExportFlags::CONTENT
4083 | SvXMLExportFlags::FONTDECLS
4084 | SvXMLExportFlags::OASIS
));
4089 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
4090 com_sun_star_comp_Chart_XMLOasisMetaExporter_get_implementation(
4091 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
4093 return cppu::acquire(new SchXMLExport(pCtx
, "SchXMLExport.Oasis.Meta",
4094 SvXMLExportFlags::META
| SvXMLExportFlags::OASIS
));
4097 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */