Teach symstore more duplicated DLLs
[LibreOffice.git] / xmloff / source / chart / SchXMLExport.cxx
blobefa8a6873973c5d3b2e2ac0349712bb2c4ed760b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <sal/config.h>
22 #include <sal/log.hxx>
24 #include <sax/tools/converter.hxx>
26 #include <xmloff/xmlprmap.hxx>
28 #include <SchXMLExport.hxx>
29 #include <XMLChartPropertySetMapper.hxx>
30 #include "ColorPropertySet.hxx"
31 #include "SchXMLTools.hxx"
32 #include "SchXMLEnumConverter.hxx"
33 #include <facreg.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <tools/globname.hxx>
37 #include <comphelper/classids.hxx>
38 #include <comphelper/sequence.hxx>
40 #include <xmloff/nmspmap.hxx>
41 #include <xmloff/xmlnmspe.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>
49 #include <vector>
50 #include <algorithm>
51 #include <queue>
52 #include <iterator>
53 #include <numeric>
55 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
56 #include <com/sun/star/lang/XServiceInfo.hpp>
57 #include <com/sun/star/lang/XServiceName.hpp>
58 #include <com/sun/star/beans/XPropertySet.hpp>
59 #include <com/sun/star/uno/XComponentContext.hpp>
60 #include <com/sun/star/util/XRefreshable.hpp>
62 #include <com/sun/star/chart/XAxis.hpp>
63 #include <com/sun/star/chart/XAxisSupplier.hpp>
64 #include <com/sun/star/chart/XChartDocument.hpp>
65 #include <com/sun/star/chart/ChartLegendExpansion.hpp>
66 #include <com/sun/star/chart/ChartDataRowSource.hpp>
67 #include <com/sun/star/chart/ChartAxisAssign.hpp>
68 #include <com/sun/star/chart/TimeIncrement.hpp>
69 #include <com/sun/star/chart/TimeInterval.hpp>
70 #include <com/sun/star/chart/TimeUnit.hpp>
71 #include <com/sun/star/chart/X3DDisplay.hpp>
72 #include <com/sun/star/chart/XStatisticDisplay.hpp>
73 #include <com/sun/star/chart/XDiagramPositioning.hpp>
75 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
76 #include <com/sun/star/chart2/AxisType.hpp>
77 #include <com/sun/star/chart2/XChartDocument.hpp>
78 #include <com/sun/star/chart2/XDiagram.hpp>
79 #include <com/sun/star/chart2/RelativePosition.hpp>
80 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
81 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
82 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
83 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
84 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
85 #include <com/sun/star/chart2/data/XDataSource.hpp>
86 #include <com/sun/star/chart2/data/XDataSink.hpp>
87 #include <com/sun/star/chart2/data/XDataProvider.hpp>
88 #include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
89 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
90 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
91 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
92 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
94 #include <com/sun/star/util/MeasureUnit.hpp>
95 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
96 #include <com/sun/star/drawing/XShapes.hpp>
97 #include <com/sun/star/embed/Aspects.hpp>
98 #include <com/sun/star/embed/XVisualObject.hpp>
99 #include <com/sun/star/container/XChild.hpp>
101 #include <tools/diagnose_ex.h>
102 #include "MultiPropertySetHandler.hxx"
103 #include "PropertyMap.hxx"
105 using namespace com::sun::star;
106 using namespace ::xmloff::token;
108 using ::com::sun::star::uno::Sequence;
109 using ::com::sun::star::uno::Reference;
110 using ::com::sun::star::uno::Any;
111 using ::std::vector;
114 namespace
116 using CustomLabelSeq = Sequence<Reference<chart2::XDataPointCustomLabelField>>;
118 struct SchXMLDataPointStruct
120 OUString maStyleName;
121 sal_Int32 mnRepeat;
122 CustomLabelSeq mCustomLabelText;
124 SchXMLDataPointStruct() : mnRepeat( 1 ) {}
128 // class SchXMLExportHelper_Impl
130 class SchXMLExportHelper_Impl
132 public:
133 // first: data sequence for label, second: data sequence for values.
134 typedef ::std::pair< css::uno::Reference< css::chart2::data::XDataSequence >,
135 css::uno::Reference< css::chart2::data::XDataSequence > > tLabelValuesDataPair;
136 typedef ::std::vector< tLabelValuesDataPair > tDataSequenceCont;
138 public:
139 SchXMLExportHelper_Impl( SvXMLExport& rExport,
140 SvXMLAutoStylePoolP& rASPool );
142 SchXMLExportHelper_Impl(const SchXMLExportHelper_Impl&) = delete;
143 SchXMLExportHelper_Impl& operator=(const SchXMLExportHelper_Impl&) = delete;
145 // auto-styles
146 /// parse chart and collect all auto-styles used in current pool
147 void collectAutoStyles( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc );
149 /// write the styles collected into the current pool as <style:style> elements
150 void exportAutoStyles();
152 /** export the <chart:chart> element corresponding to rChartDoc
153 if bIncludeTable is true, the chart data is exported as <table:table>
154 element (inside the chart element).
156 Otherwise the external references stored in the chart document are used
157 for writing the corresponding attributes at series
159 All attributes contained in xAttrList are written at the chart element,
160 which is the outer element of a chart. So these attributes can easily
161 be parsed again by the container
163 void exportChart( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc,
164 bool bIncludeTable );
166 const rtl::Reference<XMLPropertySetMapper>& GetPropertySetMapper() const;
168 void SetChartRangeAddress( const OUString& rAddress )
169 { msChartAddress = rAddress; }
171 void InitRangeSegmentationProperties(
172 const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc );
174 static css::awt::Size getPageSize(
175 const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc );
177 /** first parseDocument: collect autostyles and store names in this queue
178 second parseDocument: export content and use names from this queue
180 ::std::queue< OUString > maAutoStyleNameQueue;
181 void CollectAutoStyle(
182 const std::vector< XMLPropertyState >& aStates );
183 void AddAutoStyleAttribute(
184 const std::vector< XMLPropertyState >& aStates );
186 SvXMLAutoStylePoolP& GetAutoStylePoolP()
187 { return mrAutoStylePool; }
189 /// if bExportContent is false the auto-styles are collected
190 void parseDocument( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc,
191 bool bExportContent,
192 bool bIncludeTable = false );
193 void exportTable();
194 void exportPlotArea(
195 const css::uno::Reference< css::chart::XDiagram >& xDiagram,
196 const css::uno::Reference< css::chart2::XDiagram >& xNewDiagram,
197 const css::awt::Size & rPageSize,
198 bool bExportContent,
199 bool bIncludeTable );
200 void exportCoordinateRegion( const css::uno::Reference< css::chart::XDiagram >& xDiagram );
201 void exportAxes( const css::uno::Reference< css::chart::XDiagram > & xDiagram,
202 const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram,
203 bool bExportContent );
204 void exportAxis( enum XMLTokenEnum eDimension, enum XMLTokenEnum eAxisName,
205 const Reference< beans::XPropertySet >& rAxisProps, const Reference< chart2::XAxis >& rChart2Axis,
206 const OUString& rCategoriesRanges,
207 bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, bool bExportContent );
208 void exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent );
209 void exportDateScale( const Reference< beans::XPropertySet >& rAxisProps );
210 void exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent );
212 void exportSeries(
213 const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram,
214 const css::awt::Size & rPageSize,
215 bool bExportContent,
216 bool bHasTwoYAxes );
218 void exportPropertyMapping(
219 const css::uno::Reference< css::chart2::data::XDataSource > & xSource,
220 const Sequence< OUString >& rSupportedMappings );
222 void exportCandleStickSeries(
223 const css::uno::Sequence<
224 css::uno::Reference< css::chart2::XDataSeries > > & aSeriesSeq,
225 const css::uno::Reference< css::chart2::XDiagram > & xDiagram,
226 bool bJapaneseCandleSticks,
227 bool bExportContent );
228 void exportDataPoints(
229 const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties,
230 sal_Int32 nSeriesLength,
231 const css::uno::Reference< css::chart2::XDiagram > & xDiagram,
232 bool bExportContent );
234 void exportCustomLabel(const CustomLabelSeq & xCustomLabel);
236 void exportRegressionCurve(
237 const css::uno::Reference<css::chart2::XDataSeries>& xSeries,
238 const css::awt::Size& rPageSize,
239 bool bExportContent );
241 void exportErrorBar (
242 const css::uno::Reference<beans::XPropertySet> &xSeriesProp, bool bYError,
243 bool bExportContent );
245 /// add svg position as attribute for current element
246 void addPosition( const css::awt::Point & rPosition );
247 void addPosition( const css::uno::Reference< css::drawing::XShape >& xShape );
248 /// add svg size as attribute for current element
249 void addSize( const css::awt::Size & rSize, bool bIsOOoNamespace = false );
250 void addSize( const css::uno::Reference< css::drawing::XShape >& xShape );
251 /// exports a string as a paragraph element
252 void exportText( const OUString& rText );
254 public:
255 SvXMLExport& mrExport;
256 SvXMLAutoStylePoolP& mrAutoStylePool;
257 rtl::Reference< XMLPropertySetMapper > mxPropertySetMapper;
258 rtl::Reference< XMLChartExportPropertyMapper > mxExpPropMapper;
260 static constexpr OUStringLiteral gsTableName = "local-table";
261 OUStringBuffer msStringBuffer;
262 OUString msString;
264 // members filled by InitRangeSegmentationProperties (retrieved from DataProvider)
265 bool mbHasCategoryLabels; //if the categories are only automatically generated this will be false
266 bool mbRowSourceColumns;
267 OUString msChartAddress;
268 css::uno::Sequence< sal_Int32 > maSequenceMapping;
270 OUString const msCLSID;
272 OUString maSrcShellID;
273 OUString maDestShellID;
275 css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes;
277 tDataSequenceCont m_aDataSequencesToExport;
278 OUString maCategoriesRange;
281 namespace
284 CustomLabelSeq lcl_getCustomLabelField(sal_Int32 nDataPointIndex,
285 const uno::Reference< chart2::XDataSeries >& rSeries)
287 if( !rSeries.is() )
288 return CustomLabelSeq();
290 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
291 if( nCurrentODFVersion <= SvtSaveOptions::ODFVER_012 )//do not export to ODF 1.2 or older
292 return CustomLabelSeq();
294 if(Reference<beans::XPropertySet> xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is())
296 if(Any aAny = xLabels->getPropertyValue("CustomLabelFields"); aAny.hasValue())
298 Sequence<uno::Reference<chart2::XDataPointCustomLabelField>> aCustomLabels;
299 aAny >>= aCustomLabels;
300 return aCustomLabels;
303 return CustomLabelSeq();
306 class lcl_MatchesRole
308 public:
309 explicit lcl_MatchesRole( const OUString & aRole ) :
310 m_aRole( aRole )
313 bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
315 if( !xSeq.is() )
316 return false;
317 Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
318 OUString aRole;
320 return ( xProp.is() &&
321 (xProp->getPropertyValue( "Role" ) >>= aRole ) &&
322 m_aRole == aRole );
325 private:
326 OUString const m_aRole;
329 template< typename T >
330 void lcl_SequenceToVectorAppend( const Sequence< T > & rSource, ::std::vector< T > & rDestination )
332 rDestination.reserve( rDestination.size() + rSource.getLength());
333 ::std::copy( rSource.begin(), rSource.end(),
334 ::std::back_inserter( rDestination ));
337 template< typename T >
338 void lcl_SequenceToVector( const Sequence< T > & rSource, ::std::vector< T > & rDestination )
340 rDestination.clear();
341 lcl_SequenceToVectorAppend( rSource, rDestination );
344 Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram )
346 Reference< chart2::data::XLabeledDataSequence > xResult;
349 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
350 xDiagram, uno::UNO_QUERY_THROW );
351 const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
352 xCooSysCnt->getCoordinateSystems());
353 for( const auto& rCooSys : aCooSysSeq )
355 Reference< chart2::XCoordinateSystem > xCooSys( rCooSys );
356 SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL" );
357 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
359 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
360 for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
362 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI );
363 SAL_WARN_IF( !xAxis.is(), "xmloff.chart", "xAxis is NULL");
364 if( xAxis.is())
366 chart2::ScaleData aScaleData = xAxis->getScaleData();
367 if( aScaleData.Categories.is())
369 xResult.set( aScaleData.Categories );
370 break;
377 catch( const uno::Exception & )
379 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
382 return xResult;
385 Reference< chart2::data::XDataSource > lcl_createDataSource(
386 const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData )
388 Reference< uno::XComponentContext > xContext(
389 comphelper::getProcessComponentContext() );
390 Reference< chart2::data::XDataSink > xSink(
391 xContext->getServiceManager()->createInstanceWithContext(
392 "com.sun.star.chart2.data.DataSource", xContext ),
393 uno::UNO_QUERY_THROW );
394 xSink->setData( aData );
396 return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY );
399 Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc )
401 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer;
402 if( xChartDoc.is() )
404 Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
405 ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram ));
406 for( const auto& rSeries : aSeriesVector )
408 Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY );
409 if( !xDataSource.is() )
410 continue;
411 uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() );
412 lcl_SequenceToVectorAppend( aDataSequences, aContainer );
416 return comphelper::containerToSequence( aContainer );
419 Reference< chart2::data::XLabeledDataSequence >
420 lcl_getDataSequenceByRole(
421 const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq,
422 const OUString & rRole )
424 Reference< chart2::data::XLabeledDataSequence > aNoResult;
426 const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
427 const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
428 const Reference< chart2::data::XLabeledDataSequence > * pMatch =
429 ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole ));
431 if( pMatch != pEnd )
432 return *pMatch;
434 return aNoResult;
437 Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, bool& rOutSourceHasCategoryLabels )
439 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector;
441 //categories are always the first sequence
442 Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
443 Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) );
444 if( xCategories.is() )
445 aLabeledSeqVector.push_back( xCategories );
446 rOutSourceHasCategoryLabels = xCategories.is();
448 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector(
449 lcl_getAllSeriesSequences( xChartDoc ) );
451 //the first x-values is always the next sequence //todo ... other x-values get lost for old format
452 Reference< chart2::data::XLabeledDataSequence > xXValues(
453 lcl_getDataSequenceByRole( aSeriesSeqVector, "values-x" ) );
454 if( xXValues.is() )
455 aLabeledSeqVector.push_back( xXValues );
457 //add all other sequences now without x-values
458 lcl_MatchesRole aHasXValues( "values-x" );
459 std::copy_if(aSeriesSeqVector.begin(), aSeriesSeqVector.end(), std::back_inserter(aLabeledSeqVector),
460 [&aHasXValues](const auto& rSeriesSeq) { return !aHasXValues( rSeriesSeq ); });
462 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( comphelper::containerToSequence(aLabeledSeqVector) );
464 return lcl_createDataSource( aSeq );
467 bool lcl_isSeriesAttachedToFirstAxis(
468 const Reference< chart2::XDataSeries > & xDataSeries )
470 bool bResult=true;
474 sal_Int32 nAxisIndex = 0;
475 Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
476 xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex;
477 bResult = (0==nAxisIndex);
479 catch( const uno::Exception & )
481 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
484 return bResult;
487 OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::XChartDocument > & xDoc )
489 OUString aResult = rRange;
490 if( !xDoc.is() )
491 return aResult;
492 Reference< chart2::data::XRangeXMLConversion > xConversion(
493 xDoc->getDataProvider(), uno::UNO_QUERY );
494 if( xConversion.is())
495 aResult = xConversion->convertRangeToXML( rRange );
496 return aResult;
499 typedef ::std::pair< OUString, OUString > tLabelAndValueRange;
501 tLabelAndValueRange lcl_getLabelAndValueRangeByRole(
502 const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt,
503 const OUString & rRole,
504 const Reference< chart2::XChartDocument > & xDoc,
505 SchXMLExportHelper_Impl::tDataSequenceCont & rOutSequencesToExport )
507 tLabelAndValueRange aResult;
509 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
510 lcl_getDataSequenceByRole( aSeqCnt, rRole ));
511 if( xLabeledSeq.is())
513 Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
514 if( xLabelSeq.is())
515 aResult.first = lcl_ConvertRange( xLabelSeq->getSourceRangeRepresentation(), xDoc );
517 Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
518 if( xValueSeq.is())
519 aResult.second = lcl_ConvertRange( xValueSeq->getSourceRangeRepresentation(), xDoc );
521 if( xLabelSeq.is() || xValueSeq.is())
522 rOutSequencesToExport.emplace_back( xLabelSeq, xValueSeq );
525 return aResult;
528 sal_Int32 lcl_getSequenceLengthByRole(
529 const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt,
530 const OUString & rRole )
532 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
533 lcl_getDataSequenceByRole( aSeqCnt, rRole ));
534 if( xLabeledSeq.is())
536 Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getValues());
537 return xSeq->getData().getLength();
539 return 0;
542 OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
544 OUStringBuffer aResult;
545 bool bPrecedeWithSpace = false;
546 for( const auto& rString : rSequence )
548 if( !rString.isEmpty())
550 if( bPrecedeWithSpace )
551 aResult.append( ' ' );
552 aResult.append( rString );
553 bPrecedeWithSpace = true;
556 return aResult.makeStringAndClear();
559 void lcl_getLabelStringSequence( Sequence< OUString >& rOutLabels, const Reference< chart2::data::XDataSequence > & xLabelSeq )
561 uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY );
562 if( xTextualDataSequence.is())
564 rOutLabels = xTextualDataSequence->getTextualData();
566 else if( xLabelSeq.is())
568 Sequence< uno::Any > aAnies( xLabelSeq->getData());
569 rOutLabels.realloc( aAnies.getLength());
570 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
571 aAnies[i] >>= rOutLabels[i];
575 sal_Int32 lcl_getMaxSequenceLength(
576 const SchXMLExportHelper_Impl::tDataSequenceCont & rContainer )
578 sal_Int32 nResult = 0;
579 for( const auto& rDataSequence : rContainer )
581 if( rDataSequence.second.is())
583 sal_Int32 nSeqLength = rDataSequence.second->getData().getLength();
584 if( nSeqLength > nResult )
585 nResult = nSeqLength;
588 return nResult;
591 uno::Sequence< OUString > lcl_DataSequenceToStringSequence(
592 const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
594 uno::Sequence< OUString > aResult;
595 if(!xDataSequence.is())
596 return aResult;
598 uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY );
599 if( xTextualDataSequence.is() )
601 aResult = xTextualDataSequence->getTextualData();
603 else
605 uno::Sequence< uno::Any > aValues = xDataSequence->getData();
606 aResult.realloc(aValues.getLength());
608 for(sal_Int32 nN=aValues.getLength();nN--;)
609 aValues[nN] >>= aResult[nN];
612 return aResult;
614 ::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq )
616 double fNan = 0.0;
617 ::rtl::math::setNan( &fNan );
618 ::std::vector< double > aResult;
619 if(!xSeq.is())
620 return aResult;
622 uno::Sequence< double > aValuesSequence;
623 Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
624 if( xNumSeq.is() )
626 aValuesSequence = xNumSeq->getNumericalData();
628 else
630 Sequence< uno::Any > aAnies( xSeq->getData() );
631 aValuesSequence.realloc( aAnies.getLength() );
632 for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
633 aAnies[i] >>= aValuesSequence[i];
636 //special handling for x-values (if x-values do point to categories, indices are used instead )
637 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY );
638 if( xProp.is() )
640 OUString aRole;
641 xProp->getPropertyValue("Role") >>= aRole;
642 if( aRole.match("values-x") )
644 //lcl_clearIfNoValuesButTextIsContained - replace by indices if the values are not appropriate
645 bool bHasValue = std::any_of(aValuesSequence.begin(), aValuesSequence.end(),
646 [](double fValue) { return !::rtl::math::isNan( fValue ); });
647 if(!bHasValue)
649 //no double value is contained
650 //is there any text?
651 uno::Sequence< OUString > aStrings( lcl_DataSequenceToStringSequence( xSeq ) );
652 bool bHasText = std::any_of(aStrings.begin(), aStrings.end(),
653 [](const OUString& rString) { return !rString.isEmpty(); });
654 if( bHasText )
656 std::iota(aValuesSequence.begin(), aValuesSequence.end(), 1);
662 ::std::copy( aValuesSequence.begin(), aValuesSequence.end(),
663 ::std::back_inserter( aResult ));
664 return aResult;
667 bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
669 if( !xDataSequence.is() )
670 return false;
671 uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY );
672 if( xProp.is() )
674 uno::Sequence< sal_Int32 > aHiddenValues;
677 xProp->getPropertyValue("HiddenValues") >>= aHiddenValues;
678 if( !aHiddenValues.hasElements() )
679 return true;
681 catch( const uno::Exception& )
683 return true;
686 return xDataSequence->getData().hasElements();
689 typedef vector< OUString > tStringVector;
690 typedef vector< vector< double > > t2DNumberContainer;
692 struct lcl_TableData
694 t2DNumberContainer aDataInRows;
695 tStringVector aDataRangeRepresentations;
697 tStringVector aColumnDescriptions;
698 tStringVector aColumnDescriptions_Ranges;
700 tStringVector aRowDescriptions;
701 tStringVector aRowDescriptions_Ranges;
703 Sequence< Sequence< uno::Any > > aComplexColumnDescriptions;//outer index is columns - inner index is level
704 Sequence< Sequence< uno::Any > > aComplexRowDescriptions;//outer index is rows - inner index is level
706 ::std::vector< sal_Int32 > aHiddenColumns;
709 typedef ::std::map< sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair >
710 lcl_DataSequenceMap;
712 struct lcl_SequenceToMapElement
714 std::pair<const sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair>
715 operator() (const SchXMLExportHelper_Impl::tLabelValuesDataPair& rContent)
717 sal_Int32 nIndex = -1;
718 if( rContent.second.is()) //has values
720 OUString aRangeRep( rContent.second->getSourceRangeRepresentation());
721 nIndex = aRangeRep.toInt32();
723 else if( rContent.first.is()) //has labels
724 nIndex = rContent.first->getSourceRangeRepresentation().copy( sizeof("label ")).toInt32();
725 return std::make_pair(nIndex, rContent);
729 void lcl_ReorderInternalSequencesAccordingToTheirRangeName(
730 SchXMLExportHelper_Impl::tDataSequenceCont & rInOutSequences )
732 lcl_DataSequenceMap aIndexSequenceMap;
733 ::std::transform( rInOutSequences.begin(), rInOutSequences.end(),
734 ::std::inserter( aIndexSequenceMap, aIndexSequenceMap.begin()),
735 lcl_SequenceToMapElement());
737 rInOutSequences.clear();
738 sal_Int32 nIndex = 0;
739 for( const auto& rEntry : aIndexSequenceMap )
741 if( rEntry.first >= 0 )
743 // fill empty columns
744 rInOutSequences.insert(
745 rInOutSequences.end(),
746 rEntry.first - nIndex,
747 SchXMLExportHelper_Impl::tDataSequenceCont::value_type(
748 uno::Reference< chart2::data::XDataSequence >(),
749 uno::Reference< chart2::data::XDataSequence >() ));
750 nIndex = rEntry.first;
751 rInOutSequences.push_back( rEntry.second );
754 ++nIndex;
758 lcl_TableData lcl_getDataForLocalTable(
759 const SchXMLExportHelper_Impl::tDataSequenceCont & aSequencesToExport,
760 const Reference< chart2::XAnyDescriptionAccess >& xAnyDescriptionAccess,
761 const OUString& rCategoriesRange,
762 bool bSeriesFromColumns,
763 const Reference< chart2::data::XRangeXMLConversion > & xRangeConversion )
765 lcl_TableData aResult;
769 Sequence< OUString > aSimpleCategories;
770 if( xAnyDescriptionAccess.is() )
772 //categories
773 if( bSeriesFromColumns )
775 aSimpleCategories = xAnyDescriptionAccess->getRowDescriptions();
776 aResult.aComplexRowDescriptions = xAnyDescriptionAccess->getAnyRowDescriptions();
778 else
780 aSimpleCategories = xAnyDescriptionAccess->getColumnDescriptions();
781 aResult.aComplexColumnDescriptions = xAnyDescriptionAccess->getAnyColumnDescriptions();
785 //series values and series labels
786 SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences = aSequencesToExport.size();
788 auto nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport ));
789 if( aSimpleCategories.getLength() > nMaxSequenceLength )
791 aSimpleCategories.realloc(nMaxSequenceLength);//#i110617#
793 size_t nNumColumns( bSeriesFromColumns ? nNumSequences : nMaxSequenceLength );
794 size_t nNumRows( bSeriesFromColumns ? nMaxSequenceLength : nNumSequences );
796 // resize data
797 aResult.aDataInRows.resize( nNumRows );
798 double fNan = 0.0;
799 ::rtl::math::setNan( &fNan );
801 for (auto& aData: aResult.aDataInRows)
802 aData.resize(nNumColumns, fNan);
803 aResult.aColumnDescriptions.resize( nNumColumns );
804 aResult.aComplexColumnDescriptions.realloc( nNumColumns );
805 aResult.aRowDescriptions.resize( nNumRows );
806 aResult.aComplexRowDescriptions.realloc( nNumRows );
808 tStringVector& rCategories = bSeriesFromColumns ? aResult.aRowDescriptions : aResult.aColumnDescriptions;
809 tStringVector& rLabels = bSeriesFromColumns ? aResult.aColumnDescriptions : aResult.aRowDescriptions;
811 //categories
812 lcl_SequenceToVector( aSimpleCategories, rCategories );
813 if( !rCategoriesRange.isEmpty() )
815 OUString aRange(rCategoriesRange);
816 if( xRangeConversion.is())
817 aRange = xRangeConversion->convertRangeToXML( aRange );
818 if( bSeriesFromColumns )
819 aResult.aRowDescriptions_Ranges.push_back( aRange );
820 else
821 aResult.aColumnDescriptions_Ranges.push_back( aRange );
824 // iterate over all sequences
825 size_t nSeqIdx = 0;
826 Sequence< Sequence< OUString > > aComplexLabels(nNumSequences);
827 for( const auto& rDataSequence : aSequencesToExport )
829 OUString aRange;
830 Sequence< OUString >& rCurrentComplexLabel = aComplexLabels[nSeqIdx];
831 if( rDataSequence.first.is())
833 lcl_getLabelStringSequence( rCurrentComplexLabel, rDataSequence.first );
834 rLabels[nSeqIdx] = lcl_flattenStringSequence( rCurrentComplexLabel );
835 aRange = rDataSequence.first->getSourceRangeRepresentation();
836 if( xRangeConversion.is())
837 aRange = xRangeConversion->convertRangeToXML( aRange );
839 else if( rDataSequence.second.is())
841 rCurrentComplexLabel.realloc(1);
842 rLabels[nSeqIdx] = rCurrentComplexLabel[0] = lcl_flattenStringSequence(
843 rDataSequence.second->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE ));
845 if( bSeriesFromColumns )
846 aResult.aColumnDescriptions_Ranges.push_back( aRange );
847 else
848 aResult.aRowDescriptions_Ranges.push_back( aRange );
850 ::std::vector< double > aNumbers( lcl_getAllValuesFromSequence( rDataSequence.second ));
851 if( bSeriesFromColumns )
853 const sal_Int32 nSize( static_cast< sal_Int32 >( aNumbers.size()));
854 for( sal_Int32 nIdx=0; nIdx<nSize; ++nIdx )
855 aResult.aDataInRows[nIdx][nSeqIdx] = aNumbers[nIdx];
857 else
858 aResult.aDataInRows[nSeqIdx] = aNumbers;
860 if( rDataSequence.second.is())
862 aRange = rDataSequence.second->getSourceRangeRepresentation();
863 if( xRangeConversion.is())
864 aRange = xRangeConversion->convertRangeToXML( aRange );
866 aResult.aDataRangeRepresentations.push_back( aRange );
868 //is column hidden?
869 if( !lcl_SequenceHasUnhiddenData(rDataSequence.first) && !lcl_SequenceHasUnhiddenData(rDataSequence.second) )
870 aResult.aHiddenColumns.push_back(nSeqIdx);
872 ++nSeqIdx;
874 Sequence< Sequence< Any > >& rComplexAnyLabels = bSeriesFromColumns ? aResult.aComplexColumnDescriptions : aResult.aComplexRowDescriptions;//#i116544#
875 rComplexAnyLabels.realloc(aComplexLabels.getLength());
876 for( sal_Int32 nN=0; nN<aComplexLabels.getLength();nN++ )
878 Sequence< OUString >& rSource = aComplexLabels[nN];
879 Sequence< Any >& rTarget = rComplexAnyLabels[nN];
880 rTarget.realloc( rSource.getLength() );
881 for( sal_Int32 i=0; i<rSource.getLength(); i++ )
882 rTarget[i] <<= rSource[i];
885 catch( const uno::Exception & )
887 TOOLS_INFO_EXCEPTION("xmloff.chart", "something went wrong during table data collection");
890 return aResult;
893 void lcl_exportNumberFormat( const OUString& rPropertyName, const Reference< beans::XPropertySet >& xPropSet,
894 SvXMLExport& rExport )
896 if( xPropSet.is())
898 sal_Int32 nNumberFormat = 0;
899 Any aNumAny = xPropSet->getPropertyValue( rPropertyName );
900 if( (aNumAny >>= nNumberFormat) && (nNumberFormat != -1) )
901 rExport.addDataStyle( nNumberFormat );
905 ::std::vector< Reference< chart2::data::XDataSequence > >
906 lcl_getErrorBarSequences( const Reference< beans::XPropertySet > & xErrorBarProp )
908 ::std::vector< Reference< chart2::data::XDataSequence > > aResult;
909 Reference< chart2::data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY );
910 if( !xErrorBarDataSource.is())
911 return aResult;
913 const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences(
914 xErrorBarDataSource->getDataSequences());
915 for( const auto& rSequence : aSequences )
919 if( rSequence.is())
921 Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues());
922 Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
923 OUString aRole;
924 if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) &&
925 aRole.match( "error-bars-" ))
927 aResult.push_back( xSequence );
931 catch( const uno::Exception & )
933 TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exporting error bar ranges" );
937 return aResult;
940 bool lcl_exportDomainForThisSequence( const Reference< chart2::data::XDataSequence >& rValues, OUString& rFirstRangeForThisDomainIndex, SvXMLExport& rExport )
942 bool bDomainExported = false;
943 if( rValues.is())
945 Reference< chart2::XChartDocument > xNewDoc( rExport.GetModel(), uno::UNO_QUERY );
946 OUString aRange( lcl_ConvertRange( rValues->getSourceRangeRepresentation(), xNewDoc ) );
948 //work around error in OOo 2.0 (problems with multiple series having a domain element)
949 if( rFirstRangeForThisDomainIndex.isEmpty() || aRange != rFirstRangeForThisDomainIndex )
951 rExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, aRange);
952 SvXMLElementExport aDomain( rExport, XML_NAMESPACE_CHART, XML_DOMAIN, true, true );
953 bDomainExported = true;
956 if( rFirstRangeForThisDomainIndex.isEmpty() )
957 rFirstRangeForThisDomainIndex = aRange;
959 return bDomainExported;
962 } // anonymous namespace
964 // class SchXMLExportHelper
966 SchXMLExportHelper::SchXMLExportHelper( SvXMLExport& rExport, SvXMLAutoStylePoolP& rASPool )
967 : m_pImpl( new SchXMLExportHelper_Impl( rExport, rASPool ) )
971 SchXMLExportHelper::~SchXMLExportHelper()
975 const OUString& SchXMLExportHelper::getChartCLSID() const
977 return m_pImpl->msCLSID;
980 void SchXMLExportHelper::SetSourceShellID( const OUString& rShellID )
982 m_pImpl->maSrcShellID = rShellID;
985 void SchXMLExportHelper::SetDestinationShellID( const OUString& rShellID )
987 m_pImpl->maDestShellID = rShellID;
990 const rtl::Reference< XMLPropertySetMapper >& SchXMLExportHelper_Impl::GetPropertySetMapper() const
992 return mxPropertySetMapper;
995 void SchXMLExportHelper_Impl::exportAutoStyles()
997 if( mxExpPropMapper.is())
999 //ToDo: when embedded in calc/writer this is not necessary because the
1000 // numberformatter is shared between both documents
1001 mrExport.exportAutoDataStyles();
1003 // export chart auto styles
1004 mrAutoStylePool.exportXML( XML_STYLE_FAMILY_SCH_CHART_ID );
1006 // export auto styles for additional shapes
1007 mrExport.GetShapeExport()->exportAutoStyles();
1008 // and for text in additional shapes
1009 mrExport.GetTextParagraphExport()->exportTextAutoStyles();
1013 // private methods
1015 SchXMLExportHelper_Impl::SchXMLExportHelper_Impl(
1016 SvXMLExport& rExport,
1017 SvXMLAutoStylePoolP& rASPool ) :
1018 mrExport( rExport ),
1019 mrAutoStylePool( rASPool ),
1020 mxPropertySetMapper( new XMLChartPropertySetMapper( true ) ),
1021 mxExpPropMapper( new XMLChartExportPropertyMapper( mxPropertySetMapper, rExport ) ),
1022 mbHasCategoryLabels( false ),
1023 mbRowSourceColumns( true ),
1024 msCLSID( SvGlobalName( SO3_SCH_CLASSID ).GetHexName() )
1026 // register chart auto-style family
1027 mrAutoStylePool.AddFamily(
1028 XML_STYLE_FAMILY_SCH_CHART_ID,
1029 OUString( XML_STYLE_FAMILY_SCH_CHART_NAME ),
1030 mxExpPropMapper.get(),
1031 OUString( XML_STYLE_FAMILY_SCH_CHART_PREFIX ));
1033 // register shape family
1034 mrAutoStylePool.AddFamily(
1035 XML_STYLE_FAMILY_SD_GRAPHICS_ID,
1036 OUString( XML_STYLE_FAMILY_SD_GRAPHICS_NAME ),
1037 mxExpPropMapper.get(),
1038 OUString( XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX ));
1039 // register paragraph family also for shapes
1040 mrAutoStylePool.AddFamily(
1041 XML_STYLE_FAMILY_TEXT_PARAGRAPH,
1042 GetXMLToken( XML_PARAGRAPH ),
1043 mxExpPropMapper.get(),
1044 OUString( 'P' ));
1045 // register text family also for shapes
1046 mrAutoStylePool.AddFamily(
1047 XML_STYLE_FAMILY_TEXT_TEXT,
1048 GetXMLToken( XML_TEXT ),
1049 mxExpPropMapper.get(),
1050 OUString( 'T' ));
1053 void SchXMLExportHelper_Impl::collectAutoStyles( Reference< chart::XChartDocument > const & rChartDoc )
1055 parseDocument( rChartDoc, false );
1058 void SchXMLExportHelper_Impl::exportChart( Reference< chart::XChartDocument > const & rChartDoc,
1059 bool bIncludeTable )
1061 parseDocument( rChartDoc, true, bIncludeTable );
1062 SAL_WARN_IF( !maAutoStyleNameQueue.empty(), "xmloff.chart", "There are still remaining autostyle names in the queue" );
1065 static OUString lcl_GetStringFromNumberSequence( const css::uno::Sequence< sal_Int32 >& rSequenceMapping, bool bRemoveOneFromEachIndex /*should be true if having categories*/ )
1067 OUStringBuffer aBuf;
1068 bool bHasPredecessor = false;
1069 for( sal_Int32 nIndex : rSequenceMapping )
1071 if( bRemoveOneFromEachIndex )
1072 --nIndex;
1073 if(nIndex>=0)
1075 if(bHasPredecessor)
1076 aBuf.append( ' ' );
1077 aBuf.append( nIndex );
1078 bHasPredecessor = true;
1081 return aBuf.makeStringAndClear();
1084 /// if bExportContent is false the auto-styles are collected
1085 void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > const & rChartDoc,
1086 bool bExportContent,
1087 bool bIncludeTable )
1089 Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY );
1090 if( !rChartDoc.is() || !xNewDoc.is() )
1092 SAL_WARN("xmloff.chart", "No XChartDocument was given for export." );
1093 return;
1096 mxExpPropMapper->setChartDoc(xNewDoc);
1098 awt::Size aPageSize( getPageSize( xNewDoc ));
1099 if( bExportContent )
1100 addSize( aPageSize );
1101 Reference< chart::XDiagram > xDiagram = rChartDoc->getDiagram();
1102 Reference< chart2::XDiagram > xNewDiagram;
1103 if( xNewDoc.is())
1104 xNewDiagram.set( xNewDoc->getFirstDiagram());
1106 //todo remove if model changes are notified and view is updated automatically
1107 if( bExportContent )
1109 Reference< util::XRefreshable > xRefreshable( xNewDoc, uno::UNO_QUERY );
1110 if( xRefreshable.is() )
1111 xRefreshable->refresh();
1114 // get Properties of ChartDocument
1115 bool bHasMainTitle = false;
1116 bool bHasSubTitle = false;
1117 bool bHasLegend = false;
1118 util::DateTime aNullDate(0,0,0,0,30,12,1899, false);
1120 std::vector< XMLPropertyState > aPropertyStates;
1122 Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY );
1123 if( xDocPropSet.is())
1127 Any aAny = xDocPropSet->getPropertyValue("HasMainTitle");
1128 aAny >>= bHasMainTitle;
1129 aAny = xDocPropSet->getPropertyValue("HasSubTitle");
1130 aAny >>= bHasSubTitle;
1131 aAny = xDocPropSet->getPropertyValue("HasLegend");
1132 aAny >>= bHasLegend;
1133 if ( bIncludeTable )
1135 aAny = xDocPropSet->getPropertyValue("NullDate");
1136 if ( !aAny.hasValue() )
1138 Reference<container::XChild> xChild(rChartDoc, uno::UNO_QUERY );
1139 if ( xChild.is() )
1141 Reference< beans::XPropertySet > xParentDoc( xChild->getParent(),uno::UNO_QUERY);
1142 if ( xParentDoc.is() && xParentDoc->getPropertySetInfo()->hasPropertyByName("NullDate") )
1143 aAny = xParentDoc->getPropertyValue("NullDate");
1147 aAny >>= aNullDate;
1150 catch( const beans::UnknownPropertyException & )
1152 SAL_WARN("xmloff.chart", "Required property not found in ChartDocument" );
1156 if ( bIncludeTable && (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 ) )
1158 SvXMLElementExport aSet( mrExport, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true );
1160 OUStringBuffer sBuffer;
1161 ::sax::Converter::convertDateTime(sBuffer, aNullDate, nullptr);
1162 mrExport.AddAttribute( XML_NAMESPACE_TABLE,XML_DATE_VALUE,sBuffer.makeStringAndClear());
1163 SvXMLElementExport aNull( mrExport, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true );
1167 // chart element
1168 std::unique_ptr<SvXMLElementExport> xElChart;
1170 // get property states for autostyles
1171 if( mxExpPropMapper.is())
1173 Reference< beans::XPropertySet > xPropSet = rChartDoc->getArea();
1174 if( xPropSet.is())
1175 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1178 if( bExportContent )
1180 //export data provider in xlink:href attribute
1181 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
1182 if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 )
1184 OUString aDataProviderURL( ".." );
1185 if( xNewDoc->hasInternalDataProvider() )
1186 aDataProviderURL = ".";
1187 else //special handling for data base data provider necessary
1189 Reference< chart2::data::XDatabaseDataProvider > xDBDataProvider( xNewDoc->getDataProvider(), uno::UNO_QUERY );
1190 if( xDBDataProvider.is() )
1191 aDataProviderURL = ".";
1193 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aDataProviderURL );
1194 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1197 Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xNewDoc->getDataProvider(), uno::UNO_QUERY);
1198 if (xPivotTableDataProvider.is() && nCurrentODFVersion > SvtSaveOptions::ODFVER_012)
1200 OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName();
1201 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, sPivotTableName);
1204 OUString sChartType( xDiagram->getDiagramType() );
1206 // attributes
1207 // determine class
1208 if( !sChartType.isEmpty())
1210 enum XMLTokenEnum eXMLChartType = SchXMLTools::getTokenByChartType( sChartType, true /* bUseOldNames */ );
1212 SAL_WARN_IF( eXMLChartType == XML_TOKEN_INVALID, "xmloff.chart", "invalid chart class" );
1213 if( eXMLChartType == XML_TOKEN_INVALID )
1214 eXMLChartType = XML_BAR;
1216 if( eXMLChartType == XML_ADD_IN )
1218 // sChartType is the service-name of the add-in
1219 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS,
1220 mrExport.GetNamespaceMap().GetQNameByKey(
1221 XML_NAMESPACE_OOO, sChartType) );
1223 else if( eXMLChartType != XML_TOKEN_INVALID )
1225 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS,
1226 mrExport.GetNamespaceMap().GetQNameByKey(
1227 XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) );
1230 //column-mapping or row-mapping
1231 if( maSequenceMapping.hasElements() )
1233 enum XMLTokenEnum eTransToken = ::xmloff::token::XML_ROW_MAPPING;
1234 if( mbRowSourceColumns )
1235 eTransToken = ::xmloff::token::XML_COLUMN_MAPPING;
1236 OUString aSequenceMappingStr( lcl_GetStringFromNumberSequence(
1237 maSequenceMapping, mbHasCategoryLabels && !xNewDoc->hasInternalDataProvider() ) );
1239 mrExport.AddAttribute( XML_NAMESPACE_CHART,
1240 ::xmloff::token::GetXMLToken( eTransToken ),
1241 aSequenceMappingStr );
1244 // write style name
1245 AddAutoStyleAttribute( aPropertyStates );
1247 //element
1248 xElChart.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_CHART, true, true ));
1250 else // autostyles
1252 CollectAutoStyle( aPropertyStates );
1254 // remove property states for autostyles
1255 aPropertyStates.clear();
1257 // title element
1258 if( bHasMainTitle )
1260 // get property states for autostyles
1261 if( mxExpPropMapper.is())
1263 Reference< beans::XPropertySet > xPropSet( rChartDoc->getTitle(), uno::UNO_QUERY );
1264 if( xPropSet.is())
1265 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1267 if( bExportContent )
1269 Reference< drawing::XShape > xShape = rChartDoc->getTitle();
1270 if( xShape.is()) // && "hasTitleBeenMoved"
1271 addPosition( xShape );
1273 // write style name
1274 AddAutoStyleAttribute( aPropertyStates );
1276 // element
1277 SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true );
1279 // content (text:p)
1280 Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1281 if( xPropSet.is())
1283 Any aAny( xPropSet->getPropertyValue( "String" ));
1284 OUString aText;
1285 aAny >>= aText;
1286 exportText( aText );
1289 else // autostyles
1291 CollectAutoStyle( aPropertyStates );
1293 // remove property states for autostyles
1294 aPropertyStates.clear();
1297 // subtitle element
1298 if( bHasSubTitle )
1300 // get property states for autostyles
1301 if( mxExpPropMapper.is())
1303 Reference< beans::XPropertySet > xPropSet( rChartDoc->getSubTitle(), uno::UNO_QUERY );
1304 if( xPropSet.is())
1305 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1308 if( bExportContent )
1310 Reference< drawing::XShape > xShape = rChartDoc->getSubTitle();
1311 if( xShape.is())
1312 addPosition( xShape );
1314 // write style name
1315 AddAutoStyleAttribute( aPropertyStates );
1317 // element (has no subelements)
1318 SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, true, true );
1320 // content (text:p)
1321 Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1322 if( xPropSet.is())
1324 Any aAny( xPropSet->getPropertyValue( "String" ));
1325 OUString aText;
1326 aAny >>= aText;
1327 exportText( aText );
1330 else // autostyles
1332 CollectAutoStyle( aPropertyStates );
1334 // remove property states for autostyles
1335 aPropertyStates.clear();
1338 // legend element
1339 if( bHasLegend )
1341 // get property states for autostyles
1342 if( mxExpPropMapper.is())
1344 Reference< beans::XPropertySet > xPropSet( rChartDoc->getLegend(), uno::UNO_QUERY );
1345 if( xPropSet.is())
1346 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1349 if( bExportContent )
1351 Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY );
1352 if( xProp.is())
1354 // export legend anchor position
1357 Any aAny( xProp->getPropertyValue("Alignment"));
1358 if( SchXMLEnumConverter::getLegendPositionConverter().exportXML( msString, aAny, mrExport.GetMM100UnitConverter() ) )
1359 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LEGEND_POSITION, msString );
1361 catch( const beans::UnknownPropertyException & )
1363 SAL_WARN("xmloff.chart", "Property Align not found in ChartLegend" );
1366 // export absolute legend position
1367 Reference< drawing::XShape > xLegendShape( xProp, uno::UNO_QUERY );
1368 addPosition( xLegendShape );
1370 // export legend size
1371 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
1372 if( xLegendShape.is() && nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 )
1376 chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH;
1377 OUString aExpansionString;
1378 Any aAny( xProp->getPropertyValue("Expansion"));
1379 bool bHasExpansion = (aAny >>= nLegendExpansion);
1380 if( bHasExpansion && SchXMLEnumConverter::getLegendExpansionConverter().exportXML( aExpansionString, aAny, mrExport.GetMM100UnitConverter() ) )
1382 mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION, aExpansionString );
1383 if( nLegendExpansion == chart::ChartLegendExpansion_CUSTOM)
1385 awt::Size aSize( xLegendShape->getSize() );
1386 // tdf#131966: chart legend attributes width and height shouldn't be exported to ODF 1.2 (strict)
1387 if (nCurrentODFVersion > SvtSaveOptions::ODFVER_012)
1388 addSize( aSize, true );
1389 OUStringBuffer aAspectRatioString;
1390 ::sax::Converter::convertDouble(
1391 aAspectRatioString,
1392 (aSize.Height == 0
1393 ? 1.0
1394 : double(aSize.Width)/double(aSize.Height)));
1395 mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO, aAspectRatioString.makeStringAndClear() );
1399 catch( const beans::UnknownPropertyException & )
1401 SAL_WARN("xmloff.chart", "Property Expansion not found in ChartLegend" );
1406 // write style name
1407 AddAutoStyleAttribute( aPropertyStates );
1409 // element
1410 SvXMLElementExport aLegend( mrExport, XML_NAMESPACE_CHART, XML_LEGEND, true, true );
1412 else // autostyles
1414 CollectAutoStyle( aPropertyStates );
1416 // remove property states for autostyles
1417 aPropertyStates.clear();
1420 // plot-area element
1421 if( xDiagram.is())
1422 exportPlotArea( xDiagram, xNewDiagram, aPageSize, bExportContent, bIncludeTable );
1424 // export additional shapes
1425 if( xDocPropSet.is() )
1427 if( bExportContent )
1429 if( mxAdditionalShapes.is())
1431 // can't call exportShapes with all shapes because the
1432 // initialisation happened with the complete draw page and not
1433 // the XShapes object used here. Thus the shapes have to be
1434 // exported one by one
1435 rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport();
1436 Reference< drawing::XShape > xShape;
1437 const sal_Int32 nShapeCount( mxAdditionalShapes->getCount());
1438 for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ )
1440 mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape;
1441 SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" );
1442 if( ! xShape.is())
1443 continue;
1445 rShapeExport->exportShape( xShape );
1447 // this would be the easier way if it worked:
1448 //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes );
1451 else
1453 // get a sequence of non-chart shapes (inserted via clipboard)
1456 Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes");
1457 aShapesAny >>= mxAdditionalShapes;
1459 catch( const uno::Exception & )
1461 TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found" );
1464 if( mxAdditionalShapes.is())
1466 // seek shapes has to be called for the whole page because in
1467 // the shape export the vector of shapes is accessed via the
1468 // ZOrder which might be (actually is) larger than the number of
1469 // shapes in mxAdditionalShapes
1470 Reference< drawing::XDrawPageSupplier > xSupplier( rChartDoc, uno::UNO_QUERY );
1471 SAL_WARN_IF( !xSupplier.is(), "xmloff.chart", "Cannot retrieve draw page to initialize shape export" );
1472 if( xSupplier.is() )
1474 Reference< drawing::XShapes > xDrawPage = xSupplier->getDrawPage();
1475 SAL_WARN_IF( !xDrawPage.is(), "xmloff.chart", "Invalid draw page for initializing shape export" );
1476 if( xDrawPage.is())
1477 mrExport.GetShapeExport()->seekShapes( xDrawPage );
1480 // can't call collectShapesAutoStyles with all shapes because
1481 // the initialisation happened with the complete draw page and
1482 // not the XShapes object used here. Thus the shapes have to be
1483 // exported one by one
1484 rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport();
1485 Reference< drawing::XShape > xShape;
1486 const sal_Int32 nShapeCount( mxAdditionalShapes->getCount());
1487 for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ )
1489 mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape;
1490 SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" );
1491 if( ! xShape.is())
1492 continue;
1494 rShapeExport->collectShapeAutoStyles( xShape );
1500 // table element
1501 // (is included as subelement of chart)
1502 if( bExportContent )
1504 // #85929# always export table, otherwise clipboard may lose data
1505 exportTable();
1509 static void lcl_exportComplexLabel( const Sequence< uno::Any >& rComplexLabel, SvXMLExport& rExport )
1511 sal_Int32 nLength = rComplexLabel.getLength();
1512 if( nLength<=1 )
1513 return;
1514 SvXMLElementExport aTextList( rExport, XML_NAMESPACE_TEXT, XML_LIST, true, true );
1515 for(const auto& rElem : rComplexLabel)
1517 SvXMLElementExport aListItem( rExport, XML_NAMESPACE_TEXT, XML_LIST_ITEM, true, true );
1518 OUString aString;
1519 if( !(rElem >>= aString) )
1521 //todo?
1523 SchXMLTools::exportText( rExport, aString, false /*bConvertTabsLFs*/ );
1527 void SchXMLExportHelper_Impl::exportTable()
1529 // table element
1530 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, gsTableName );
1534 bool bProtected = false;
1535 Reference< beans::XPropertySet > xProps( mrExport.GetModel(), uno::UNO_QUERY_THROW );
1536 if ( ( xProps->getPropertyValue("DisableDataTableDialog") >>= bProtected ) &&
1537 bProtected )
1539 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE );
1542 catch ( const uno::Exception& )
1546 SvXMLElementExport aTable( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true );
1548 bool bHasOwnData = false;
1549 Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
1550 Reference< chart2::data::XRangeXMLConversion > xRangeConversion;
1551 if( xNewDoc.is())
1553 bHasOwnData = xNewDoc->hasInternalDataProvider();
1554 xRangeConversion.set( xNewDoc->getDataProvider(), uno::UNO_QUERY );
1557 Reference< chart2::XAnyDescriptionAccess > xAnyDescriptionAccess;
1559 Reference< chart::XChartDocument > xChartDoc( mrExport.GetModel(), uno::UNO_QUERY );
1560 if( xChartDoc.is() )
1561 xAnyDescriptionAccess.set( xChartDoc->getData(), uno::UNO_QUERY );
1564 if( bHasOwnData )
1565 lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport );
1566 lcl_TableData aData( lcl_getDataForLocalTable( m_aDataSequencesToExport
1567 , xAnyDescriptionAccess, maCategoriesRange
1568 , mbRowSourceColumns, xRangeConversion ));
1570 tStringVector::const_iterator aDataRangeIter( aData.aDataRangeRepresentations.begin());
1571 const tStringVector::const_iterator aDataRangeEndIter( aData.aDataRangeRepresentations.end());
1573 tStringVector::const_iterator aRowDescriptions_RangeIter( aData.aRowDescriptions_Ranges.begin());
1574 const tStringVector::const_iterator aRowDescriptions_RangeEnd( aData.aRowDescriptions_Ranges.end());
1576 // declare columns
1578 SvXMLElementExport aHeaderColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true, true );
1579 SvXMLElementExport aHeaderColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1582 SvXMLElementExport aColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, true, true );
1584 sal_Int32 nNextIndex = 0;
1585 for(sal_Int32 nHiddenIndex : aData.aHiddenColumns)
1587 //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste )
1588 if( nHiddenIndex > nNextIndex )
1590 sal_Int64 nRepeat = static_cast< sal_Int64 >( nHiddenIndex - nNextIndex );
1591 if(nRepeat>1)
1592 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
1593 OUString::number( nRepeat ));
1594 SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1596 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_VISIBILITY, GetXMLToken( XML_COLLAPSE ) );
1597 SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1598 nNextIndex = nHiddenIndex+1;
1601 sal_Int32 nEndIndex = aData.aColumnDescriptions.size()-1;
1602 if( nEndIndex >= nNextIndex )
1604 sal_Int64 nRepeat = static_cast< sal_Int64 >( nEndIndex - nNextIndex + 1 );
1605 if(nRepeat>1)
1606 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
1607 OUString::number( nRepeat ));
1608 SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1612 // export rows with content
1613 //export header row
1615 SvXMLElementExport aHeaderRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true, true );
1616 SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true );
1618 //first one empty cell for the row descriptions
1620 SvXMLElementExport aEmptyCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1621 SvXMLElementExport aEmptyParagraph( mrExport, XML_NAMESPACE_TEXT, XML_P, true, true );
1624 //export column descriptions
1625 tStringVector::const_iterator aColumnDescriptions_RangeIter( aData.aColumnDescriptions_Ranges.begin());
1626 const tStringVector::const_iterator aColumnDescriptions_RangeEnd( aData.aColumnDescriptions_Ranges.end());
1627 const Sequence< Sequence< uno::Any > >& rComplexColumnDescriptions = aData.aComplexColumnDescriptions;
1628 sal_Int32 nComplexCount = rComplexColumnDescriptions.getLength();
1629 sal_Int32 nC = 0;
1630 for( const auto& rDesc : aData.aColumnDescriptions )
1632 bool bExportString = true;
1633 if( nC < nComplexCount )
1635 const Sequence< uno::Any >& rComplexLabel = rComplexColumnDescriptions[nC];
1636 if( rComplexLabel.hasElements() )
1638 double fValue=0.0;
1639 if( rComplexLabel[0] >>=fValue )
1641 bExportString = false;
1643 ::sax::Converter::convertDouble(
1644 msStringBuffer, fValue);
1645 msString = msStringBuffer.makeStringAndClear();
1646 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT );
1647 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString );
1651 if( bExportString )
1653 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING );
1656 SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1657 exportText( rDesc );
1658 if( nC < nComplexCount )
1659 lcl_exportComplexLabel( rComplexColumnDescriptions[nC], mrExport );
1660 if( !bHasOwnData && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd )
1662 // remind the original range to allow a correct re-association when copying via clipboard
1663 if (!(*aColumnDescriptions_RangeIter).isEmpty())
1664 SchXMLTools::exportRangeToSomewhere( mrExport, *aColumnDescriptions_RangeIter );
1665 ++aColumnDescriptions_RangeIter;
1668 nC++;
1670 SAL_WARN_IF( !bHasOwnData && (aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" );
1671 } // closing row and header-rows elements
1673 // export value rows
1675 SvXMLElementExport aRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROWS, true, true );
1676 tStringVector::const_iterator aRowDescriptionsIter( aData.aRowDescriptions.begin());
1677 const Sequence< Sequence< uno::Any > >& rComplexRowDescriptions = aData.aComplexRowDescriptions;
1678 sal_Int32 nComplexCount = rComplexRowDescriptions.getLength();
1679 sal_Int32 nC = 0;
1681 for( const auto& rRow : aData.aDataInRows )
1683 SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true );
1685 //export row descriptions
1687 bool bExportString = true;
1688 if( nC < nComplexCount )
1690 const Sequence< uno::Any >& rComplexLabel = rComplexRowDescriptions[nC];
1691 if( rComplexLabel.hasElements() )
1693 double fValue=0.0;
1694 if( rComplexLabel[0] >>=fValue )
1696 bExportString = false;
1698 ::sax::Converter::convertDouble(msStringBuffer, fValue);
1699 msString = msStringBuffer.makeStringAndClear();
1700 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT );
1701 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString );
1705 if( bExportString )
1707 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING );
1710 SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1711 if( aRowDescriptionsIter != aData.aRowDescriptions.end())
1713 exportText( *aRowDescriptionsIter );
1714 if( nC < nComplexCount )
1715 lcl_exportComplexLabel( rComplexRowDescriptions[nC], mrExport );
1716 if( !bHasOwnData && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd )
1718 // remind the original range to allow a correct re-association when copying via clipboard
1719 SchXMLTools::exportRangeToSomewhere( mrExport, *aRowDescriptions_RangeIter );
1720 ++aRowDescriptions_RangeIter;
1722 ++aRowDescriptionsIter;
1726 //export row values
1727 for( t2DNumberContainer::value_type::const_iterator aColIt( rRow.begin());
1728 aColIt != rRow.end(); ++aColIt )
1730 ::sax::Converter::convertDouble( msStringBuffer, *aColIt );
1731 msString = msStringBuffer.makeStringAndClear();
1732 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT );
1733 mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString );
1734 SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1735 exportText( msString ); // do not convert tabs and lfs
1736 if( ( !bHasOwnData && aDataRangeIter != aDataRangeEndIter ) &&
1737 ( mbRowSourceColumns || (aColIt == rRow.begin()) ) )
1739 // remind the original range to allow a correct re-association when copying via clipboard
1740 if (!(*aDataRangeIter).isEmpty())
1741 SchXMLTools::exportRangeToSomewhere( mrExport, *aDataRangeIter );
1742 ++aDataRangeIter;
1746 ++nC;
1750 // if range iterator was used it should have reached its end
1751 SAL_WARN_IF( !bHasOwnData && (aDataRangeIter != aDataRangeEndIter), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" );
1752 SAL_WARN_IF( !bHasOwnData && (aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" );
1755 namespace
1758 Reference< chart2::XCoordinateSystem > lcl_getCooSys( const Reference< chart2::XDiagram > & xNewDiagram )
1760 Reference< chart2::XCoordinateSystem > xCooSys;
1761 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDiagram, uno::UNO_QUERY );
1762 if(xCooSysCnt.is())
1764 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
1765 if(aCooSysSeq.hasElements())
1766 xCooSys = aCooSysSeq[0];
1768 return xCooSys;
1771 Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& xCooSys,
1772 enum XMLTokenEnum eDimension, bool bPrimary=true )
1774 Reference< chart2::XAxis > xNewAxis;
1777 if( xCooSys.is() )
1779 sal_Int32 nDimensionIndex=0;
1780 switch( eDimension )
1782 case XML_X:
1783 nDimensionIndex=0;
1784 break;
1785 case XML_Y:
1786 nDimensionIndex=1;
1787 break;
1788 case XML_Z:
1789 nDimensionIndex=2;
1790 break;
1791 default:
1792 break;
1795 xNewAxis = xCooSys->getAxisByDimension( nDimensionIndex, bPrimary ? 0 : 1 );
1798 catch( const uno::Exception & )
1801 return xNewAxis;
1806 void SchXMLExportHelper_Impl::exportPlotArea(
1807 const Reference< chart::XDiagram >& xDiagram,
1808 const Reference< chart2::XDiagram >& xNewDiagram,
1809 const awt::Size & rPageSize,
1810 bool bExportContent,
1811 bool bIncludeTable )
1813 SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
1814 if( ! xDiagram.is())
1815 return;
1817 // variables for autostyles
1818 Reference< beans::XPropertySet > xPropSet;
1819 std::vector< XMLPropertyState > aPropertyStates;
1821 msStringBuffer.setLength( 0 );
1823 // plot-area element
1825 std::unique_ptr<SvXMLElementExport> xElPlotArea;
1826 // get property states for autostyles
1827 xPropSet.set( xDiagram, uno::UNO_QUERY );
1828 if( xPropSet.is())
1830 if( mxExpPropMapper.is())
1831 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1833 if( bExportContent )
1835 rtl::Reference< XMLShapeExport > rShapeExport;
1837 // write style name
1838 AddAutoStyleAttribute( aPropertyStates );
1840 if( !msChartAddress.isEmpty() )
1842 if( !bIncludeTable )
1843 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, msChartAddress );
1845 Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY );
1846 if( xDoc.is() )
1848 Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY );
1849 if( xDocProp.is())
1851 Any aAny;
1855 bool bFirstCol = false, bFirstRow = false;
1857 aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstColumn" );
1858 aAny >>= bFirstCol;
1859 aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstRow" );
1860 aAny >>= bFirstRow;
1862 if( bFirstCol || bFirstRow )
1864 mrExport.AddAttribute( XML_NAMESPACE_CHART,
1865 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS ),
1866 ( bFirstCol
1867 ? ( bFirstRow
1868 ? ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH )
1869 : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN ))
1870 : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW )));
1873 catch( const beans::UnknownPropertyException & )
1875 SAL_WARN("xmloff.chart", "Properties missing" );
1881 // attributes
1882 if( xDiagram.is())
1884 addPosition( xDiagram );
1885 addSize( xDiagram );
1888 bool bIs3DChart = false;
1890 if( xPropSet.is())
1892 Any aAny;
1894 // 3d attributes
1897 aAny = xPropSet->getPropertyValue("Dim3D");
1898 aAny >>= bIs3DChart;
1900 if( bIs3DChart )
1902 rShapeExport = mrExport.GetShapeExport();
1903 if( rShapeExport.is())
1904 rShapeExport->export3DSceneAttributes( xPropSet );
1907 catch( const uno::Exception & )
1909 TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught");
1913 // plot-area element
1914 xElPlotArea.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_PLOT_AREA, true, true ));
1916 //inner position rectangle element
1917 exportCoordinateRegion( xDiagram );
1919 // light sources (inside plot area element)
1920 if( bIs3DChart &&
1921 rShapeExport.is())
1922 rShapeExport->export3DLamps( xPropSet );
1924 else // autostyles
1926 CollectAutoStyle( aPropertyStates );
1928 // remove property states for autostyles
1929 aPropertyStates.clear();
1931 // axis elements
1932 exportAxes( xDiagram, xNewDiagram, bExportContent );
1934 // series elements
1935 Reference< chart2::XAxis > xSecondYAxis = lcl_getAxis( lcl_getCooSys( xNewDiagram ), XML_Y, false );
1936 exportSeries( xNewDiagram, rPageSize, bExportContent, xSecondYAxis.is() );
1938 // stock-chart elements
1939 OUString sChartType ( xDiagram->getDiagramType());
1940 if( sChartType == "com.sun.star.chart.StockDiagram" )
1942 Reference< chart::XStatisticDisplay > xStockPropProvider( xDiagram, uno::UNO_QUERY );
1943 if( xStockPropProvider.is())
1945 // stock-gain-marker
1946 Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getUpBar();
1947 if( xStockPropSet.is())
1949 aPropertyStates.clear();
1950 aPropertyStates = mxExpPropMapper->Filter( xStockPropSet );
1952 if( !aPropertyStates.empty() )
1954 if( bExportContent )
1956 AddAutoStyleAttribute( aPropertyStates );
1958 SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_GAIN_MARKER, true, true );
1960 else
1962 CollectAutoStyle( aPropertyStates );
1967 // stock-loss-marker
1968 xStockPropSet = xStockPropProvider->getDownBar();
1969 if( xStockPropSet.is())
1971 aPropertyStates.clear();
1972 aPropertyStates = mxExpPropMapper->Filter( xStockPropSet );
1974 if( !aPropertyStates.empty() )
1976 if( bExportContent )
1978 AddAutoStyleAttribute( aPropertyStates );
1980 SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_LOSS_MARKER, true, true );
1982 else
1984 CollectAutoStyle( aPropertyStates );
1989 // stock-range-line
1990 xStockPropSet = xStockPropProvider->getMinMaxLine();
1991 if( xStockPropSet.is())
1993 aPropertyStates.clear();
1994 aPropertyStates = mxExpPropMapper->Filter( xStockPropSet );
1996 if( !aPropertyStates.empty() )
1998 if( bExportContent )
2000 AddAutoStyleAttribute( aPropertyStates );
2002 SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_RANGE_LINE, true, true );
2004 else
2006 CollectAutoStyle( aPropertyStates );
2013 // wall and floor element
2014 Reference< chart::X3DDisplay > xWallFloorSupplier( xDiagram, uno::UNO_QUERY );
2015 if( mxExpPropMapper.is() &&
2016 xWallFloorSupplier.is())
2018 // remove property states for autostyles
2019 aPropertyStates.clear();
2021 Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall();
2022 if( xWallPropSet.is())
2024 aPropertyStates = mxExpPropMapper->Filter( xWallPropSet );
2026 if( !aPropertyStates.empty() )
2028 // write element
2029 if( bExportContent )
2031 // add style name attribute
2032 AddAutoStyleAttribute( aPropertyStates );
2034 SvXMLElementExport aWall( mrExport, XML_NAMESPACE_CHART, XML_WALL, true, true );
2036 else // autostyles
2038 CollectAutoStyle( aPropertyStates );
2043 // floor element
2044 // remove property states for autostyles
2045 aPropertyStates.clear();
2047 Reference< beans::XPropertySet > xFloorPropSet = xWallFloorSupplier->getFloor();
2048 if( xFloorPropSet.is())
2050 aPropertyStates = mxExpPropMapper->Filter( xFloorPropSet );
2052 if( !aPropertyStates.empty() )
2054 // write element
2055 if( bExportContent )
2057 // add style name attribute
2058 AddAutoStyleAttribute( aPropertyStates );
2060 SvXMLElementExport aFloor( mrExport, XML_NAMESPACE_CHART, XML_FLOOR, true, true );
2062 else // autostyles
2064 CollectAutoStyle( aPropertyStates );
2071 void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference< chart::XDiagram >& xDiagram )
2073 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
2074 if( nCurrentODFVersion <= SvtSaveOptions::ODFVER_012 )//do not export to ODF 1.2 or older
2075 return;
2077 Reference< chart::XDiagramPositioning > xDiaPos( xDiagram, uno::UNO_QUERY );
2078 SAL_WARN_IF( !xDiaPos.is(), "xmloff.chart", "Invalid xDiaPos as parameter" );
2079 if( !xDiaPos.is() )
2080 return;
2082 awt::Rectangle aRect( xDiaPos->calculateDiagramPositionExcludingAxes() );
2083 addPosition( awt::Point(aRect.X,aRect.Y) );
2084 addSize( awt::Size(aRect.Width,aRect.Height) );
2086 SvXMLElementExport aCoordinateRegion( mrExport, XML_NAMESPACE_CHART_EXT, XML_COORDINATE_REGION, true, true );//#i100778# todo: change to chart namespace in future - dependent on fileformat
2089 namespace
2091 XMLTokenEnum lcl_getTimeUnitToken( sal_Int32 nTimeUnit )
2093 XMLTokenEnum eToken = XML_DAYS;
2094 switch( nTimeUnit )
2096 case css::chart::TimeUnit::YEAR:
2097 eToken = XML_YEARS;
2098 break;
2099 case css::chart::TimeUnit::MONTH:
2100 eToken = XML_MONTHS;
2101 break;
2102 default://days
2103 break;
2105 return eToken;
2109 void SchXMLExportHelper_Impl::exportDateScale( const Reference< beans::XPropertySet >& rAxisProps )
2111 if( !rAxisProps.is() )
2112 return;
2114 chart::TimeIncrement aIncrement;
2115 if( rAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement )
2117 sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY;
2118 if( aIncrement.TimeResolution >>= nTimeResolution )
2119 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, lcl_getTimeUnitToken( nTimeResolution ) );
2121 chart::TimeInterval aInterval;
2122 if( aIncrement.MajorTimeInterval >>= aInterval )
2124 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, OUString::number(aInterval.Number) );
2125 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) );
2127 if( aIncrement.MinorTimeInterval >>= aInterval )
2129 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, OUString::number(aInterval.Number) );
2130 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) );
2133 SvXMLElementExport aDateScale( mrExport, XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, true, true );//#i25706#todo: change namespace for next ODF version
2137 void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent )
2139 if( !rTitleProps.is() )
2140 return;
2141 std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( rTitleProps );
2142 if( bExportContent )
2144 OUString aText;
2145 Any aAny( rTitleProps->getPropertyValue( "String" ));
2146 aAny >>= aText;
2148 Reference< drawing::XShape > xShape( rTitleProps, uno::UNO_QUERY );
2149 if( xShape.is())
2150 addPosition( xShape );
2152 AddAutoStyleAttribute( aPropertyStates );
2153 SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true );
2155 // paragraph containing title
2156 exportText( aText );
2158 else
2160 CollectAutoStyle( aPropertyStates );
2162 aPropertyStates.clear();
2165 void SchXMLExportHelper_Impl::exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent )
2167 if( !rGridProperties.is() )
2168 return;
2169 std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( rGridProperties );
2170 if( bExportContent )
2172 AddAutoStyleAttribute( aPropertyStates );
2173 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, bMajor ? XML_MAJOR : XML_MINOR );
2174 SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, true, true );
2176 else
2178 CollectAutoStyle( aPropertyStates );
2180 aPropertyStates.clear();
2183 namespace
2186 //returns true if a date scale needs to be exported
2187 bool lcl_exportAxisType( const Reference< chart2::XAxis >& rChart2Axis, SvXMLExport& rExport)
2189 bool bExportDateScale = false;
2190 if( !rChart2Axis.is() )
2191 return bExportDateScale;
2193 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
2194 if( nCurrentODFVersion <= SvtSaveOptions::ODFVER_012 )//do not export to ODF 1.2 or older
2195 return bExportDateScale;
2197 chart2::ScaleData aScale( rChart2Axis->getScaleData() );
2198 //#i25706#todo: change namespace for next ODF version
2199 sal_uInt16 nNameSpace = XML_NAMESPACE_CHART_EXT;
2201 switch(aScale.AxisType)
2203 case chart2::AxisType::CATEGORY:
2204 if( aScale.AutoDateAxis )
2206 rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO );
2207 bExportDateScale = true;
2209 else
2210 rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_TEXT );
2211 break;
2212 case chart2::AxisType::DATE:
2213 rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_DATE );
2214 bExportDateScale = true;
2215 break;
2216 default: //AUTOMATIC
2217 rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO );
2218 break;
2221 return bExportDateScale;
2224 void disableLinkedNumberFormat(
2225 std::vector<XMLPropertyState>& rPropStates, const rtl::Reference<XMLPropertySetMapper>& rMapper )
2227 for (XMLPropertyState & rState : rPropStates)
2229 if (rState.mnIndex < 0 || rMapper->GetEntryCount() <= rState.mnIndex)
2230 continue;
2232 OUString aXMLName = rMapper->GetEntryXMLName(rState.mnIndex);
2234 if (aXMLName != "link-data-style-to-source")
2235 continue;
2237 // Entry found. Set the value to false and bail out.
2238 rState.maValue <<= false;
2239 return;
2242 // Entry not found. Insert a new entry for this.
2243 sal_Int32 nIndex = rMapper->GetEntryIndex(XML_NAMESPACE_CHART, "link-data-style-to-source", 0);
2244 XMLPropertyState aState(nIndex);
2245 aState.maValue <<= false;
2246 rPropStates.push_back(aState);
2251 void SchXMLExportHelper_Impl::exportAxis(
2252 enum XMLTokenEnum eDimension,
2253 enum XMLTokenEnum eAxisName,
2254 const Reference< beans::XPropertySet >& rAxisProps,
2255 const Reference< chart2::XAxis >& rChart2Axis,
2256 const OUString& rCategoriesRange,
2257 bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid,
2258 bool bExportContent )
2260 std::vector< XMLPropertyState > aPropertyStates;
2261 std::unique_ptr<SvXMLElementExport> pAxis;
2263 // get property states for autostyles
2264 if( rAxisProps.is() && mxExpPropMapper.is() )
2266 lcl_exportNumberFormat( "NumberFormat", rAxisProps, mrExport );
2267 aPropertyStates = mxExpPropMapper->Filter( rAxisProps );
2269 if (!maSrcShellID.isEmpty() && !maDestShellID.isEmpty() && maSrcShellID != maDestShellID)
2271 // Disable link to source number format property when pasting to
2272 // a different doc shell. These shell ID's should be both empty
2273 // during real ODF export.
2274 disableLinkedNumberFormat(aPropertyStates, mxExpPropMapper->getPropertySetMapper());
2278 bool bExportDateScale = false;
2279 if( bExportContent )
2281 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, eDimension );
2282 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, eAxisName );
2283 AddAutoStyleAttribute( aPropertyStates ); // write style name
2284 if( !rCategoriesRange.isEmpty() )
2285 bExportDateScale = lcl_exportAxisType( rChart2Axis, mrExport );
2287 // open axis element
2288 pAxis.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, true, true ));
2290 else
2292 CollectAutoStyle( aPropertyStates );
2294 aPropertyStates.clear();
2296 //date scale
2297 if( bExportDateScale )
2298 exportDateScale( rAxisProps );
2300 Reference< beans::XPropertySet > xTitleProps;
2301 Reference< beans::XPropertySet > xMajorGridProps;
2302 Reference< beans::XPropertySet > xMinorGridProps;
2303 Reference< chart::XAxis > xAxis( rAxisProps, uno::UNO_QUERY );
2304 if( xAxis.is() )
2306 xTitleProps = bHasTitle ? xAxis->getAxisTitle() : nullptr;
2307 xMajorGridProps = bHasMajorGrid ? xAxis->getMajorGrid() : nullptr;
2308 xMinorGridProps = bHasMinorGrid ? xAxis->getMinorGrid() : nullptr;
2311 // axis-title
2312 exportAxisTitle( xTitleProps , bExportContent );
2314 // categories if we have a categories chart
2315 if( bExportContent && !rCategoriesRange.isEmpty() )
2317 mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, rCategoriesRange );
2318 SvXMLElementExport aCategories( mrExport, XML_NAMESPACE_CHART, XML_CATEGORIES, true, true );
2321 // grid
2322 exportGrid( xMajorGridProps, true, bExportContent );
2323 exportGrid( xMinorGridProps, false, bExportContent );
2326 void SchXMLExportHelper_Impl::exportAxes(
2327 const Reference< chart::XDiagram > & xDiagram,
2328 const Reference< chart2::XDiagram > & xNewDiagram,
2329 bool bExportContent )
2331 SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
2332 if( ! xDiagram.is())
2333 return;
2335 // get some properties from document first
2336 bool bHasXAxis = false,
2337 bHasYAxis = false,
2338 bHasZAxis = false,
2339 bHasSecondaryXAxis = false,
2340 bHasSecondaryYAxis = false;
2341 bool bHasXAxisTitle = false,
2342 bHasYAxisTitle = false,
2343 bHasZAxisTitle = false,
2344 bHasSecondaryXAxisTitle = false,
2345 bHasSecondaryYAxisTitle = false;
2346 bool bHasXAxisMajorGrid = false,
2347 bHasXAxisMinorGrid = false,
2348 bHasYAxisMajorGrid = false,
2349 bHasYAxisMinorGrid = false,
2350 bHasZAxisMajorGrid = false,
2351 bHasZAxisMinorGrid = false;
2353 // get multiple properties using XMultiPropertySet
2354 MultiPropertySetHandler aDiagramProperties (xDiagram);
2356 aDiagramProperties.Add ("HasXAxis", bHasXAxis);
2357 aDiagramProperties.Add ("HasYAxis", bHasYAxis);
2358 aDiagramProperties.Add ("HasZAxis", bHasZAxis);
2359 aDiagramProperties.Add ("HasSecondaryXAxis", bHasSecondaryXAxis);
2360 aDiagramProperties.Add ("HasSecondaryYAxis", bHasSecondaryYAxis);
2362 aDiagramProperties.Add ("HasXAxisTitle", bHasXAxisTitle);
2363 aDiagramProperties.Add ("HasYAxisTitle", bHasYAxisTitle);
2364 aDiagramProperties.Add ("HasZAxisTitle", bHasZAxisTitle);
2365 aDiagramProperties.Add ("HasSecondaryXAxisTitle", bHasSecondaryXAxisTitle);
2366 aDiagramProperties.Add ("HasSecondaryYAxisTitle", bHasSecondaryYAxisTitle);
2368 aDiagramProperties.Add ("HasXAxisGrid", bHasXAxisMajorGrid);
2369 aDiagramProperties.Add ("HasYAxisGrid", bHasYAxisMajorGrid);
2370 aDiagramProperties.Add ("HasZAxisGrid", bHasZAxisMajorGrid);
2372 aDiagramProperties.Add ("HasXAxisHelpGrid", bHasXAxisMinorGrid);
2373 aDiagramProperties.Add ("HasYAxisHelpGrid", bHasYAxisMinorGrid);
2374 aDiagramProperties.Add ("HasZAxisHelpGrid", bHasZAxisMinorGrid);
2376 if ( ! aDiagramProperties.GetProperties ())
2378 SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram");
2381 Reference< chart2::XCoordinateSystem > xCooSys( lcl_getCooSys(xNewDiagram) );
2383 // write an axis element also if the axis itself is not visible, but a grid or a title
2385 OUString aCategoriesRange;
2386 Reference< chart::XAxisSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY );
2388 // x axis
2390 Reference< css::chart2::XAxis > xNewAxis = lcl_getAxis( xCooSys, XML_X );
2391 if( xNewAxis.is() )
2393 Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(0) : nullptr, uno::UNO_QUERY );
2394 if( mbHasCategoryLabels && bExportContent )
2396 Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) );
2397 if( xCategories.is() )
2399 Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() );
2400 if( xValues.is() )
2402 Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2403 maCategoriesRange = xValues->getSourceRangeRepresentation();
2404 aCategoriesRange = lcl_ConvertRange( maCategoriesRange, xNewDoc );
2408 exportAxis( XML_X, XML_PRIMARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasXAxisTitle, bHasXAxisMajorGrid, bHasXAxisMinorGrid, bExportContent );
2409 aCategoriesRange.clear();
2412 // secondary x axis
2414 xNewAxis = lcl_getAxis( xCooSys, XML_X, false );
2415 if( xNewAxis.is() )
2417 Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY );
2418 exportAxis( XML_X, XML_SECONDARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryXAxisTitle, false, false, bExportContent );
2421 // y axis
2423 xNewAxis = lcl_getAxis( xCooSys, XML_Y );
2424 if( xNewAxis.is() )
2426 Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(1) : nullptr, uno::UNO_QUERY );
2427 exportAxis( XML_Y, XML_PRIMARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasYAxisTitle, bHasYAxisMajorGrid, bHasYAxisMinorGrid, bExportContent );
2430 // secondary y axis
2432 xNewAxis = lcl_getAxis( xCooSys, XML_Y, false );
2433 if( xNewAxis.is() )
2435 Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY );
2436 exportAxis( XML_Y, XML_SECONDARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryYAxisTitle, false, false, bExportContent );
2439 // z axis
2441 xNewAxis = lcl_getAxis( xCooSys, XML_Z );
2442 if( xNewAxis.is() )
2444 Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(2) : nullptr, uno::UNO_QUERY );
2445 exportAxis( XML_Z, XML_PRIMARY_Z, xAxisProps, xNewAxis, aCategoriesRange, bHasZAxisTitle, bHasZAxisMajorGrid, bHasZAxisMinorGrid, bExportContent );
2449 namespace
2451 bool lcl_hasNoValuesButText( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
2453 if( !xDataSequence.is() )
2454 return false;//have no data
2456 Sequence< uno::Any > aData;
2457 Reference< chart2::data::XNumericalDataSequence > xNumericalDataSequence( xDataSequence, uno::UNO_QUERY );
2458 if( xNumericalDataSequence.is() )
2460 Sequence< double > aDoubles( xNumericalDataSequence->getNumericalData() );
2461 if (std::any_of(aDoubles.begin(), aDoubles.end(), [](double fDouble) { return !::rtl::math::isNan( fDouble ); }))
2462 return false;//have double value
2464 else
2466 aData = xDataSequence->getData();
2467 double fDouble = 0.0;
2468 bool bHaveDouble = std::any_of(aData.begin(), aData.end(),
2469 [&fDouble](const uno::Any& rData) { return (rData >>= fDouble) && !::rtl::math::isNan( fDouble ); });
2470 if (bHaveDouble)
2471 return false;//have double value
2473 //no values found
2475 Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY );
2476 if( xTextualDataSequence.is() )
2478 uno::Sequence< OUString > aStrings( xTextualDataSequence->getTextualData() );
2479 if (std::any_of(aStrings.begin(), aStrings.end(), [](const OUString& rString) { return !rString.isEmpty(); }))
2480 return true;//have text
2482 else
2484 if( !aData.hasElements() )
2485 aData = xDataSequence->getData();
2486 OUString aString;
2487 bool bHaveText = std::any_of(aData.begin(), aData.end(),
2488 [&aString](const uno::Any& rData) { return (rData >>= aString) && !aString.isEmpty(); });
2489 if (bHaveText)
2490 return true;//have text
2492 //no doubles and no texts
2493 return false;
2497 void SchXMLExportHelper_Impl::exportSeries(
2498 const Reference< chart2::XDiagram > & xNewDiagram,
2499 const awt::Size & rPageSize,
2500 bool bExportContent,
2501 bool bHasTwoYAxes )
2503 Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY );
2504 if( ! xBCooSysCnt.is())
2505 return;
2506 Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2508 OUString aFirstXDomainRange;
2509 OUString aFirstYDomainRange;
2511 std::vector< XMLPropertyState > aPropertyStates;
2513 const Sequence< Reference< chart2::XCoordinateSystem > >
2514 aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
2515 for( const auto& rCooSys : aCooSysSeq )
2517 Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY );
2518 if( ! xCTCnt.is())
2519 continue;
2520 const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
2521 for( const auto& rChartType : aCTSeq )
2523 Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY );
2524 if( ! xDSCnt.is())
2525 continue;
2526 // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
2527 OUString aChartType( rChartType->getChartType());
2528 OUString aLabelRole = rChartType->getRoleOfSequenceForSeriesLabel();
2530 // special export for stock charts
2531 if ( aChartType == "com.sun.star.chart2.CandleStickChartType" )
2533 bool bJapaneseCandleSticks = false;
2534 Reference< beans::XPropertySet > xCTProp( rChartType, uno::UNO_QUERY );
2535 if( xCTProp.is())
2536 xCTProp->getPropertyValue("Japanese") >>= bJapaneseCandleSticks;
2537 exportCandleStickSeries(
2538 xDSCnt->getDataSeries(), xNewDiagram, bJapaneseCandleSticks, bExportContent );
2539 continue;
2542 // export dataseries for current chart-type
2543 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
2544 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx )
2546 // export series
2547 Reference< chart2::data::XDataSource > xSource( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY );
2548 if( xSource.is())
2550 std::unique_ptr<SvXMLElementExport> pSeries;
2551 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
2552 xSource->getDataSequences());
2553 sal_Int32 nMainSequenceIndex = -1;
2554 sal_Int32 nSeriesLength = 0;
2555 sal_Int32 nAttachedAxis = chart::ChartAxisAssign::PRIMARY_Y;
2556 bool bHasMeanValueLine = false;
2557 Reference< beans::XPropertySet > xPropSet;
2558 tLabelValuesDataPair aSeriesLabelValuesPair;
2560 // search for main sequence and create a series element
2562 Reference< chart2::data::XDataSequence > xValuesSeq;
2563 Reference< chart2::data::XDataSequence > xLabelSeq;
2564 sal_Int32 nSeqIdx=0;
2565 for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2567 OUString aRole;
2568 Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2569 if( nMainSequenceIndex==-1 )
2571 Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2572 if( xSeqProp.is())
2573 xSeqProp->getPropertyValue("Role") >>= aRole;
2574 // "main" sequence
2575 if( aRole == aLabelRole )
2577 xValuesSeq.set( xTempValueSeq );
2578 xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2579 nMainSequenceIndex = nSeqIdx;
2582 sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2583 if( nSeriesLength < nSequenceLength )
2584 nSeriesLength = nSequenceLength;
2587 // have found the main sequence, then xValuesSeq and
2588 // xLabelSeq contain those. Otherwise both are empty
2590 // get property states for autostyles
2593 xPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet(
2594 aSeriesSeq[nSeriesIdx], mrExport.GetModel() );
2596 catch( const uno::Exception & )
2598 TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" );
2599 continue;
2601 if( xPropSet.is())
2603 // determine attached axis
2606 Any aAny( xPropSet->getPropertyValue( "Axis" ));
2607 aAny >>= nAttachedAxis;
2609 aAny = xPropSet->getPropertyValue( "MeanValue" );
2610 aAny >>= bHasMeanValueLine;
2612 catch( const beans::UnknownPropertyException & )
2614 TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
2617 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
2618 if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 )
2620 lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport );
2621 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport );
2624 if( mxExpPropMapper.is())
2625 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
2628 if( bExportContent )
2630 if( bHasTwoYAxes )
2632 if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
2633 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
2634 else
2635 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
2638 // write style name
2639 AddAutoStyleAttribute( aPropertyStates );
2641 if( xValuesSeq.is())
2642 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS,
2643 lcl_ConvertRange(
2644 xValuesSeq->getSourceRangeRepresentation(),
2645 xNewDoc ));
2646 else
2647 // #i75297# allow empty series, export empty range to have all ranges on import
2648 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, OUString());
2650 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
2651 if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 )
2653 if (xPropSet.is())
2655 Any aAny = xPropSet->getPropertyValue("ShowLegendEntry");
2656 if (!aAny.get<bool>())
2658 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
2663 if (xLabelSeq.is())
2665 // Check if the label is direct string value rather than a reference.
2666 bool bHasString = false;
2667 uno::Reference<beans::XPropertySet> xLSProp(xLabelSeq, uno::UNO_QUERY);
2668 if (xLSProp.is())
2672 xLSProp->getPropertyValue("HasStringLabel") >>= bHasString;
2674 catch (const beans::UnknownPropertyException&) {}
2677 OUString aRange = xLabelSeq->getSourceRangeRepresentation();
2679 if (bHasString)
2681 mrExport.AddAttribute(
2682 XML_NAMESPACE_LO_EXT, XML_LABEL_STRING, aRange);
2684 else
2686 mrExport.AddAttribute(
2687 XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS,
2688 lcl_ConvertRange(
2689 xLabelSeq->getSourceRangeRepresentation(), xNewDoc));
2693 if( xLabelSeq.is() || xValuesSeq.is() )
2694 aSeriesLabelValuesPair = tLabelValuesDataPair( xLabelSeq, xValuesSeq );
2696 // chart-type for mixed types
2697 enum XMLTokenEnum eCTToken(
2698 SchXMLTools::getTokenByChartType( aChartType, false /* bUseOldNames */ ));
2699 //@todo: get token for current charttype
2700 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS,
2701 mrExport.GetNamespaceMap().GetQNameByKey(
2702 XML_NAMESPACE_CHART, GetXMLToken( eCTToken )));
2704 // open series element until end of for loop
2705 pSeries.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ));
2707 else // autostyles
2709 CollectAutoStyle( aPropertyStates );
2711 // remove property states for autostyles
2712 aPropertyStates.clear();
2716 // export domain elements if we have a series parent element
2717 if( pSeries )
2719 // domain elements
2720 if( bExportContent )
2722 bool bIsScatterChart = aChartType == "com.sun.star.chart2.ScatterChartType";
2723 bool bIsBubbleChart = aChartType == "com.sun.star.chart2.BubbleChartType";
2724 Reference< chart2::data::XDataSequence > xYValuesForBubbleChart;
2725 if( bIsBubbleChart )
2727 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-y" ) );
2728 if( xSequence.is() )
2730 xYValuesForBubbleChart = xSequence->getValues();
2731 if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart, aFirstYDomainRange, mrExport ) )
2732 xYValuesForBubbleChart = nullptr;
2735 if( bIsScatterChart || bIsBubbleChart )
2737 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-x" ) );
2738 if( xSequence.is() )
2740 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2741 if( lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ) )
2742 m_aDataSequencesToExport.emplace_back(
2743 uno::Reference< chart2::data::XDataSequence >(), xValues );
2745 else if( nSeriesIdx==0 )
2747 //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly
2748 Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) );
2749 if( xCategories.is() )
2751 Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() );
2752 if( !lcl_hasNoValuesButText( xValues ) )
2753 lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport );
2757 if( xYValuesForBubbleChart.is() )
2758 m_aDataSequencesToExport.emplace_back(
2759 uno::Reference< chart2::data::XDataSequence >(), xYValuesForBubbleChart );
2763 // add sequences for main sequence after domain sequences,
2764 // so that the export of the local table has the correct order
2765 if( bExportContent &&
2766 (aSeriesLabelValuesPair.first.is() || aSeriesLabelValuesPair.second.is()))
2767 m_aDataSequencesToExport.push_back( aSeriesLabelValuesPair );
2769 // statistical objects:
2770 // regression curves and mean value lines
2771 if( bHasMeanValueLine &&
2772 xPropSet.is() &&
2773 mxExpPropMapper.is() )
2775 Reference< beans::XPropertySet > xStatProp;
2778 Any aPropAny( xPropSet->getPropertyValue( "DataMeanValueProperties" ));
2779 aPropAny >>= xStatProp;
2781 catch( const uno::Exception & )
2783 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" );
2786 if( xStatProp.is() )
2788 aPropertyStates = mxExpPropMapper->Filter( xStatProp );
2790 if( !aPropertyStates.empty() )
2792 // write element
2793 if( bExportContent )
2795 // add style name attribute
2796 AddAutoStyleAttribute( aPropertyStates );
2798 SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_MEAN_VALUE, true, true );
2800 else // autostyles
2802 CollectAutoStyle( aPropertyStates );
2808 if( xPropSet.is() &&
2809 mxExpPropMapper.is() )
2811 exportRegressionCurve( aSeriesSeq[nSeriesIdx], rPageSize, bExportContent );
2814 exportErrorBar( xPropSet,false, bExportContent ); // X ErrorBar
2815 exportErrorBar( xPropSet,true, bExportContent ); // Y ErrorBar
2817 exportDataPoints(
2818 uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ),
2819 nSeriesLength, xNewDiagram, bExportContent );
2821 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
2822 if( bExportContent && nCurrentODFVersion > SvtSaveOptions::ODFVER_012 )//do not export to ODF 1.2 or older
2824 Sequence< OUString > aSupportedMappings = rChartType->getSupportedPropertyRoles();
2825 exportPropertyMapping( xSource, aSupportedMappings );
2828 // close series element
2829 pSeries.reset();
2832 aPropertyStates.clear();
2837 void SchXMLExportHelper_Impl::exportPropertyMapping(
2838 const Reference< chart2::data::XDataSource > & xSource, const Sequence< OUString >& rSupportedMappings )
2840 Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2841 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
2842 xSource->getDataSequences());
2844 for(const auto& rSupportedMapping : rSupportedMappings)
2846 Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, rSupportedMapping ) );
2847 if(xSequence.is())
2849 Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2850 if( xValues.is())
2852 mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_PROPERTY, rSupportedMapping);
2853 mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_CELL_RANGE_ADDRESS,
2854 lcl_ConvertRange(
2855 xValues->getSourceRangeRepresentation(),
2856 xNewDoc ));
2857 SvXMLElementExport( mrExport, XML_NAMESPACE_LO_EXT, XML_PROPERTY_MAPPING, true, true );
2859 // register range for data table export
2860 m_aDataSequencesToExport.emplace_back(
2861 uno::Reference< chart2::data::XDataSequence >(), xValues );
2867 void SchXMLExportHelper_Impl::exportRegressionCurve(
2868 const Reference< chart2::XDataSeries >& xSeries,
2869 const awt::Size& rPageSize,
2870 bool bExportContent )
2872 OSL_ASSERT( mxExpPropMapper.is());
2874 Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, uno::UNO_QUERY );
2875 if( xRegressionCurveContainer.is() )
2877 const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
2879 for( const auto& xRegCurve : aRegCurveSeq )
2881 std::vector< XMLPropertyState > aEquationPropertyStates;
2882 if (!xRegCurve.is())
2883 continue;
2885 Reference< beans::XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
2886 if( !xProperties.is() )
2887 continue;
2889 Reference< lang::XServiceName > xServiceName( xProperties, uno::UNO_QUERY );
2890 if( !xServiceName.is() )
2891 continue;
2893 bool bShowEquation = false;
2894 bool bShowRSquared = false;
2895 bool bExportEquation = false;
2897 OUString aService = xServiceName->getServiceName();
2899 std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( xProperties );
2901 // Add service name (which is regression type)
2902 sal_Int32 nIndex = GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE);
2903 XMLPropertyState property(nIndex, uno::makeAny(aService));
2904 aPropertyStates.push_back(property);
2906 Reference< beans::XPropertySet > xEquationProperties;
2907 xEquationProperties.set( xRegCurve->getEquationProperties() );
2908 if( xEquationProperties.is())
2910 xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation;
2911 xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowRSquared;
2913 bExportEquation = ( bShowEquation || bShowRSquared );
2914 const SvtSaveOptions::ODFDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFDefaultVersion() );
2915 if( nCurrentVersion < SvtSaveOptions::ODFVER_012 )
2917 bExportEquation=false;
2919 if( bExportEquation )
2921 // number format
2922 sal_Int32 nNumberFormat = 0;
2923 if( (xEquationProperties->getPropertyValue("NumberFormat") >>= nNumberFormat ) &&
2924 nNumberFormat != -1 )
2926 mrExport.addDataStyle( nNumberFormat );
2928 aEquationPropertyStates = mxExpPropMapper->Filter( xEquationProperties );
2932 if( !aPropertyStates.empty() || bExportEquation )
2934 // write element
2935 if( bExportContent )
2937 // add style name attribute
2938 if( !aPropertyStates.empty())
2940 AddAutoStyleAttribute( aPropertyStates );
2943 SvXMLElementExport aRegressionExport( mrExport, XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, true, true );
2944 if( bExportEquation )
2946 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_EQUATION, (bShowEquation ? XML_TRUE : XML_FALSE) );
2947 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, (bShowRSquared ? XML_TRUE : XML_FALSE) );
2949 // export position
2950 chart2::RelativePosition aRelativePosition;
2951 if( xEquationProperties->getPropertyValue( "RelativePosition" ) >>= aRelativePosition )
2953 double fX = aRelativePosition.Primary * rPageSize.Width;
2954 double fY = aRelativePosition.Secondary * rPageSize.Height;
2955 awt::Point aPos;
2956 aPos.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
2957 aPos.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
2958 addPosition( aPos );
2961 if( !aEquationPropertyStates.empty())
2963 AddAutoStyleAttribute( aEquationPropertyStates );
2966 SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_EQUATION, true, true );
2969 else // autostyles
2971 if( !aPropertyStates.empty())
2973 CollectAutoStyle( aPropertyStates );
2975 if( bExportEquation && !aEquationPropertyStates.empty())
2977 CollectAutoStyle( aEquationPropertyStates );
2985 void SchXMLExportHelper_Impl::exportErrorBar( const Reference<beans::XPropertySet> &xSeriesProp,
2986 bool bYError, bool bExportContent )
2988 assert(mxExpPropMapper.is());
2990 const SvtSaveOptions::ODFDefaultVersion nCurrentVersion( SvtSaveOptions().GetODFDefaultVersion() );
2992 /// Don't export X ErrorBars for older ODF versions.
2993 if ( !bYError && nCurrentVersion < SvtSaveOptions::ODFVER_012 )
2994 return;
2996 if (xSeriesProp.is())
2998 bool bNegative = false, bPositive = false;
2999 sal_Int32 nErrorBarStyle = chart::ErrorBarStyle::NONE;
3000 Reference< beans::XPropertySet > xErrorBarProp;
3004 Any aAny = xSeriesProp->getPropertyValue( bYError ? OUString("ErrorBarY") : OUString("ErrorBarX") );
3005 aAny >>= xErrorBarProp;
3007 if ( xErrorBarProp.is() )
3009 aAny = xErrorBarProp->getPropertyValue("ShowNegativeError" );
3010 aAny >>= bNegative;
3012 aAny = xErrorBarProp->getPropertyValue("ShowPositiveError" );
3013 aAny >>= bPositive;
3015 aAny = xErrorBarProp->getPropertyValue("ErrorBarStyle" );
3016 aAny >>= nErrorBarStyle;
3019 catch( const beans::UnknownPropertyException & )
3021 TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
3024 if( nErrorBarStyle != chart::ErrorBarStyle::NONE && (bNegative || bPositive))
3026 if( bExportContent && nErrorBarStyle == chart::ErrorBarStyle::FROM_DATA )
3028 // register data ranges for error bars for export in local table
3029 ::std::vector< Reference< chart2::data::XDataSequence > > aErrorBarSequences(
3030 lcl_getErrorBarSequences( xErrorBarProp ));
3031 for( const auto& rErrorBarSequence : aErrorBarSequences )
3033 m_aDataSequencesToExport.emplace_back(
3034 uno::Reference< chart2::data::XDataSequence >(), rErrorBarSequence );
3038 std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( xErrorBarProp );
3040 if( !aPropertyStates.empty() )
3042 // write element
3043 if( bExportContent )
3045 // add style name attribute
3046 AddAutoStyleAttribute( aPropertyStates );
3048 if( nCurrentVersion >= SvtSaveOptions::ODFVER_012 )
3049 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, bYError ? XML_Y : XML_X );//#i114149#
3050 SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, true, true );
3052 else // autostyles
3054 CollectAutoStyle( aPropertyStates );
3061 void SchXMLExportHelper_Impl::exportCandleStickSeries(
3062 const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
3063 const Reference< chart2::XDiagram > & xDiagram,
3064 bool bJapaneseCandleSticks,
3065 bool bExportContent )
3068 for( const auto& xSeries : aSeriesSeq )
3070 sal_Int32 nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries )
3071 ? chart::ChartAxisAssign::PRIMARY_Y
3072 : chart::ChartAxisAssign::SECONDARY_Y;
3074 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
3075 if( xSource.is())
3077 // export series in correct order (as we don't store roles)
3078 // with japanese candlesticks: open, low, high, close
3079 // otherwise: low, high, close
3080 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
3081 xSource->getDataSequences());
3083 sal_Int32 nSeriesLength =
3084 lcl_getSequenceLengthByRole( aSeqCnt, "values-last");
3086 if( bExportContent )
3088 Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
3089 //@todo: export data points
3091 //TODO: moggi: same code three times
3092 // open
3093 if( bJapaneseCandleSticks )
3095 tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3096 aSeqCnt, "values-first", xNewDoc, m_aDataSequencesToExport ));
3097 if( !aRanges.second.isEmpty())
3098 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3099 if( !aRanges.first.isEmpty())
3100 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3101 if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3102 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3103 else
3104 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3105 SvXMLElementExport aOpenSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3106 // export empty data points
3107 exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3110 // low
3112 tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3113 aSeqCnt, "values-min", xNewDoc, m_aDataSequencesToExport ));
3114 if( !aRanges.second.isEmpty())
3115 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3116 if( !aRanges.first.isEmpty())
3117 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3118 if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3119 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3120 else
3121 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3122 SvXMLElementExport aLowSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3123 // export empty data points
3124 exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3127 // high
3129 tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3130 aSeqCnt, "values-max", xNewDoc, m_aDataSequencesToExport ));
3131 if( !aRanges.second.isEmpty())
3132 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3133 if( !aRanges.first.isEmpty())
3134 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3135 if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3136 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3137 else
3138 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3139 SvXMLElementExport aHighSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3140 // export empty data points
3141 exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3144 // close
3146 tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3147 aSeqCnt, "values-last", xNewDoc, m_aDataSequencesToExport ));
3148 if( !aRanges.second.isEmpty())
3149 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second );
3150 if( !aRanges.first.isEmpty())
3151 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first );
3152 if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3153 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y );
3154 else
3155 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y );
3156 SvXMLElementExport aCloseSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3157 // export empty data points
3158 exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3161 else // autostyles
3163 // for close series
3165 // remove property states for autostyles
3170 void SchXMLExportHelper_Impl::exportDataPoints(
3171 const uno::Reference< beans::XPropertySet > & xSeriesProperties,
3172 sal_Int32 nSeriesLength,
3173 const uno::Reference< chart2::XDiagram > & xDiagram,
3174 bool bExportContent )
3176 // data-points
3178 // write data-points only if they contain autostyles
3179 // objects with equal autostyles are grouped using the attribute
3180 // repeat="number"
3182 // Note: if only the nth data-point has autostyles there is an element
3183 // without style and repeat="n-1" attribute written in advance.
3185 // the sequence aDataPointSeq contains indices of data-points that
3186 // do have own attributes. This increases the performance substantially.
3188 // more performant version for #93600#
3189 if (!mxExpPropMapper.is())
3190 return;
3192 uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
3194 std::vector< XMLPropertyState > aPropertyStates;
3196 bool bVaryColorsByPoint = false;
3197 Sequence< sal_Int32 > aDataPointSeq;
3198 if( xSeriesProperties.is())
3200 xSeriesProperties->getPropertyValue("AttributedDataPoints") >>= aDataPointSeq;
3201 xSeriesProperties->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint;
3204 sal_Int32 nSize = aDataPointSeq.getLength();
3205 SAL_WARN_IF( nSize > nSeriesLength, "xmloff.chart", "Too many point attributes" );
3207 const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
3208 sal_Int32 nElement;
3209 sal_Int32 nRepeat;
3210 Reference< chart2::XColorScheme > xColorScheme;
3211 if( xDiagram.is())
3212 xColorScheme.set( xDiagram->getDefaultColorScheme());
3214 ::std::vector< SchXMLDataPointStruct > aDataPointVector;
3216 sal_Int32 nLastIndex = -1;
3218 // collect elements
3219 if( bVaryColorsByPoint && xColorScheme.is() )
3221 ::std::set< sal_Int32 > aAttrPointSet;
3222 ::std::copy( pPoints, pPoints + aDataPointSeq.getLength(),
3223 ::std::inserter( aAttrPointSet, aAttrPointSet.begin()));
3224 const ::std::set< sal_Int32 >::const_iterator aEndIt( aAttrPointSet.end());
3225 for( nElement = 0; nElement < nSeriesLength; ++nElement )
3227 aPropertyStates.clear();
3228 uno::Reference< beans::XPropertySet > xPropSet;
3229 bool bExportNumFmt = false;
3230 if( aAttrPointSet.find( nElement ) != aEndIt )
3234 xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3235 xSeries, nElement, mrExport.GetModel() );
3236 bExportNumFmt = true;
3238 catch( const uno::Exception & )
3240 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3243 else
3245 // property set only containing the color
3246 xPropSet.set( new ::xmloff::chart::ColorPropertySet(
3247 xColorScheme->getColorByIndex( nElement )));
3249 SAL_WARN_IF( !xPropSet.is(), "xmloff.chart", "Pie Segments should have properties" );
3250 if( xPropSet.is())
3252 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
3253 if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 && bExportNumFmt )
3255 lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport );
3256 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport );
3259 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
3260 if( !aPropertyStates.empty() )
3262 if( bExportContent )
3264 // write data-point with style
3265 SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3267 SchXMLDataPointStruct aPoint;
3268 aPoint.maStyleName = maAutoStyleNameQueue.front();
3269 if(bExportNumFmt)
3270 aPoint.mCustomLabelText = lcl_getCustomLabelField(nElement, xSeries);
3271 maAutoStyleNameQueue.pop();
3272 aDataPointVector.push_back( aPoint );
3274 else
3276 CollectAutoStyle( aPropertyStates );
3281 SAL_WARN_IF( bExportContent && (static_cast<sal_Int32>(aDataPointVector.size()) != nSeriesLength), "xmloff.chart", "not enough data points on content export" );
3283 else
3285 for( sal_Int32 nCurrIndex : aDataPointSeq )
3287 aPropertyStates.clear();
3288 //assuming sorted indices in pPoints
3290 if( nCurrIndex<0 || nCurrIndex>=nSeriesLength )
3291 break;
3293 // write leading empty data points
3294 if( nCurrIndex - nLastIndex > 1 )
3296 SchXMLDataPointStruct aPoint;
3297 aPoint.mnRepeat = nCurrIndex - nLastIndex - 1;
3298 aDataPointVector.push_back( aPoint );
3301 uno::Reference< beans::XPropertySet > xPropSet;
3302 // get property states
3305 xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet(
3306 xSeries, nCurrIndex, mrExport.GetModel() );
3308 catch( const uno::Exception & )
3310 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3312 if( xPropSet.is())
3314 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
3315 if( nCurrentODFVersion >= SvtSaveOptions::ODFVER_012 )
3317 lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport );
3318 lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport );
3321 aPropertyStates = mxExpPropMapper->Filter( xPropSet );
3322 if( !aPropertyStates.empty() )
3324 if( bExportContent )
3326 // write data-point with style
3327 SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3328 SchXMLDataPointStruct aPoint;
3329 aPoint.maStyleName = maAutoStyleNameQueue.front();
3330 aPoint.mCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries);
3331 maAutoStyleNameQueue.pop();
3333 aDataPointVector.push_back( aPoint );
3334 nLastIndex = nCurrIndex;
3336 else
3338 CollectAutoStyle( aPropertyStates );
3340 continue;
3344 // if we get here the property states are empty
3345 SchXMLDataPointStruct aPoint;
3346 aDataPointVector.push_back( aPoint );
3348 nLastIndex = nCurrIndex;
3350 // final empty elements
3351 nRepeat = nSeriesLength - nLastIndex - 1;
3352 if( nRepeat > 0 )
3354 SchXMLDataPointStruct aPoint;
3355 aPoint.mnRepeat = nRepeat;
3356 aDataPointVector.push_back( aPoint );
3360 if (!bExportContent)
3361 return;
3363 // write elements (merge equal ones)
3364 SchXMLDataPointStruct aPoint;
3365 SchXMLDataPointStruct aLastPoint;
3367 // initialize so that it doesn't matter if
3368 // the element is counted in the first iteration
3369 aLastPoint.mnRepeat = 0;
3371 for( const auto& rPoint : aDataPointVector )
3373 aPoint = rPoint;
3375 if( aPoint.maStyleName == aLastPoint.maStyleName && aLastPoint.mCustomLabelText.getLength() < 1 )
3376 aPoint.mnRepeat += aLastPoint.mnRepeat;
3377 else if( aLastPoint.mnRepeat > 0 )
3379 // write last element
3380 if( !aLastPoint.maStyleName.isEmpty() )
3381 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName );
3383 if( aLastPoint.mnRepeat > 1 )
3384 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED,
3385 OUString::number( ( aLastPoint.mnRepeat ) ));
3387 SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true );
3388 exportCustomLabel(aLastPoint.mCustomLabelText);
3390 aLastPoint = aPoint;
3392 // write last element if it hasn't been written in last iteration
3393 if( aPoint.maStyleName == aLastPoint.maStyleName )
3395 if( !aLastPoint.maStyleName.isEmpty() )
3396 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName );
3398 if( aLastPoint.mnRepeat > 1 )
3399 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED,
3400 OUString::number( ( aLastPoint.mnRepeat ) ));
3402 SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true );
3403 exportCustomLabel(aLastPoint.mCustomLabelText);
3407 void SchXMLExportHelper_Impl::exportCustomLabel( const CustomLabelSeq & xCustomLabel )
3409 if( xCustomLabel.getLength() < 1 )
3410 return; // nothing to export
3412 SvXMLElementExport aLabelElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true, true);
3413 SvXMLElementExport aPara( mrExport, XML_NAMESPACE_TEXT, XML_P, true, false );
3414 for( const Reference<chart2::XDataPointCustomLabelField>& label : xCustomLabel )
3416 // TODO add style
3417 SvXMLElementExport aSpan( mrExport, XML_NAMESPACE_TEXT, XML_SPAN, true, false);
3418 mrExport.GetDocHandler()->characters(label->getString());
3422 void SchXMLExportHelper_Impl::addPosition( const awt::Point & rPosition )
3424 mrExport.GetMM100UnitConverter().convertMeasureToXML(
3425 msStringBuffer, rPosition.X );
3426 msString = msStringBuffer.makeStringAndClear();
3427 mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, msString );
3429 mrExport.GetMM100UnitConverter().convertMeasureToXML(
3430 msStringBuffer, rPosition.Y );
3431 msString = msStringBuffer.makeStringAndClear();
3432 mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, msString );
3435 void SchXMLExportHelper_Impl::addPosition( const Reference< drawing::XShape >& xShape )
3437 if( xShape.is())
3438 addPosition( xShape->getPosition());
3441 void SchXMLExportHelper_Impl::addSize( const awt::Size & rSize, bool bIsOOoNamespace)
3443 mrExport.GetMM100UnitConverter().convertMeasureToXML(
3444 msStringBuffer, rSize.Width );
3445 msString = msStringBuffer.makeStringAndClear();
3446 mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG , XML_WIDTH, msString );
3448 mrExport.GetMM100UnitConverter().convertMeasureToXML(
3449 msStringBuffer, rSize.Height);
3450 msString = msStringBuffer.makeStringAndClear();
3451 mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG, XML_HEIGHT, msString );
3454 void SchXMLExportHelper_Impl::addSize( const Reference< drawing::XShape >& xShape )
3456 if( xShape.is())
3457 addSize( xShape->getSize() );
3460 awt::Size SchXMLExportHelper_Impl::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc )
3462 awt::Size aSize( 8000, 7000 );
3463 uno::Reference< embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY );
3464 SAL_WARN_IF( !xVisualObject.is(), "xmloff.chart", "need XVisualObject for page size" );
3465 if( xVisualObject.is() )
3466 aSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
3468 return aSize;
3471 void SchXMLExportHelper_Impl::CollectAutoStyle( const std::vector< XMLPropertyState >& aStates )
3473 if( !aStates.empty() )
3474 maAutoStyleNameQueue.push( GetAutoStylePoolP().Add( XML_STYLE_FAMILY_SCH_CHART_ID, aStates ));
3477 void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates )
3479 if( !aStates.empty() )
3481 SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3483 mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, maAutoStyleNameQueue.front() );
3484 maAutoStyleNameQueue.pop();
3488 void SchXMLExportHelper_Impl::exportText( const OUString& rText )
3490 SchXMLTools::exportText( mrExport, rText, false/*bConvertTabsLFs*/ );
3493 // class SchXMLExport
3495 SchXMLExport::SchXMLExport(const Reference<uno::XComponentContext>& xContext,
3496 OUString const& implementationName, SvXMLExportFlags nExportFlags)
3497 : SvXMLExport(util::MeasureUnit::CM, xContext, implementationName, ::xmloff::token::XML_CHART,
3498 nExportFlags)
3499 , maAutoStylePool(new SchXMLAutoStylePoolP(*this))
3500 , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool))
3502 if( getDefaultVersion() > SvtSaveOptions::ODFVER_012 )
3503 GetNamespaceMap_().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT);
3506 SchXMLExport::~SchXMLExport()
3510 ErrCode SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass )
3512 maExportHelper->SetSourceShellID(GetSourceShellID());
3513 maExportHelper->SetDestinationShellID(GetDestinationShellID());
3515 Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3516 maExportHelper->m_pImpl->InitRangeSegmentationProperties( xChartDoc );
3517 return SvXMLExport::exportDoc( eClass );
3520 void SchXMLExport::ExportMasterStyles_()
3522 // not available in chart
3523 SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" );
3526 void SchXMLExport::collectAutoStyles()
3528 SvXMLExport::collectAutoStyles();
3530 if (mbAutoStylesCollected)
3531 return;
3533 // there are no styles that require their own autostyles
3534 if( getExportFlags() & SvXMLExportFlags::CONTENT )
3536 Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3537 if( xChartDoc.is())
3539 maExportHelper->m_pImpl->collectAutoStyles( xChartDoc );
3541 else
3543 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3546 mbAutoStylesCollected = true;
3549 void SchXMLExport::ExportAutoStyles_()
3551 collectAutoStyles();
3553 if( getExportFlags() & SvXMLExportFlags::CONTENT )
3555 Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3556 if( xChartDoc.is())
3558 maExportHelper->m_pImpl->exportAutoStyles();
3560 else
3562 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3567 void SchXMLExport::ExportContent_()
3569 Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3570 if( xChartDoc.is())
3572 // determine if data comes from the outside
3573 bool bIncludeTable = true;
3575 Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
3576 if( xNewDoc.is())
3578 // check if we have own data. If so we must not export the complete
3579 // range string, as this is our only indicator for having own or
3580 // external data. @todo: fix this in the file format!
3581 Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
3582 if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
3584 bIncludeTable = false;
3587 else
3589 Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY );
3590 if( xServ.is())
3592 if( xServ->supportsService( "com.sun.star.chart.ChartTableAddressSupplier" ))
3594 Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY );
3595 if( xProp.is())
3597 Any aAny;
3600 OUString sChartAddress;
3601 aAny = xProp->getPropertyValue( "ChartRangeAddress" );
3602 aAny >>= sChartAddress;
3603 maExportHelper->m_pImpl->SetChartRangeAddress( sChartAddress );
3605 // do not include own table if there are external addresses
3606 bIncludeTable = sChartAddress.isEmpty();
3608 catch( const beans::UnknownPropertyException & )
3610 SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" );
3616 maExportHelper->m_pImpl->exportChart( xChartDoc, bIncludeTable );
3618 else
3620 SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" );
3624 rtl::Reference< XMLPropertySetMapper > const & SchXMLExport::GetPropertySetMapper() const
3626 return maExportHelper->m_pImpl->GetPropertySetMapper();
3629 void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc )
3631 if( xChartDoc.is())
3634 Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
3635 SAL_WARN_IF( !xDataProvider.is(), "xmloff.chart", "No DataProvider" );
3636 if( xDataProvider.is())
3638 Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels ));
3639 const Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource ));
3640 OUString sCellRange, sBrokenRange;
3641 bool bBrokenRangeAvailable = false;
3642 for( const auto& rArg : aArgs )
3644 if ( rArg.Name == "CellRangeRepresentation" )
3645 rArg.Value >>= sCellRange;
3646 else if ( rArg.Name == "BrokenCellRangeForExport" )
3648 if( rArg.Value >>= sBrokenRange )
3649 bBrokenRangeAvailable = true;
3651 else if ( rArg.Name == "DataRowSource" )
3653 chart::ChartDataRowSource eRowSource;
3654 rArg.Value >>= eRowSource;
3655 mbRowSourceColumns = ( eRowSource == chart::ChartDataRowSource_COLUMNS );
3657 else if ( rArg.Name == "SequenceMapping" )
3658 rArg.Value >>= maSequenceMapping;
3661 // #i79009# For Writer we have to export a broken version of the
3662 // range, where every row number is not too large, so that older
3663 // version can correctly read those files.
3664 msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange);
3665 if( !msChartAddress.isEmpty() )
3667 // convert format to XML-conform one
3668 Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY );
3669 if( xConversion.is())
3670 msChartAddress = xConversion->convertRangeToXML( msChartAddress );
3674 catch( const uno::Exception & )
3676 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
3680 // first version: everything goes in one storage
3682 Sequence< OUString > SchXMLExport_getSupportedServiceNames() throw()
3684 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLExporter" };
3687 OUString SchXMLExport_getImplementationName() throw()
3689 return "SchXMLExport.Compact";
3692 Reference< uno::XInterface > SchXMLExport_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3694 // #103997# removed some flags from EXPORT_ALL
3695 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr), SchXMLExport_getImplementationName(), SvXMLExportFlags::ALL ^ ( SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::SCRIPTS )));
3698 // Oasis format
3699 Sequence< OUString > SchXMLExport_Oasis_getSupportedServiceNames() throw()
3701 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLOasisExporter" };
3704 OUString SchXMLExport_Oasis_getImplementationName() throw()
3706 return "SchXMLExport.Oasis.Compact";
3709 Reference< uno::XInterface > SchXMLExport_Oasis_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3711 // #103997# removed some flags from EXPORT_ALL
3712 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr),
3713 SchXMLExport_Oasis_getImplementationName(),
3714 (SvXMLExportFlags::ALL ^ ( SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::SCRIPTS )) | SvXMLExportFlags::OASIS ));
3717 // multiple storage version: one for content / styles / meta
3719 Sequence< OUString > SchXMLExport_Styles_getSupportedServiceNames() throw()
3721 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLStylesExporter" };
3724 OUString SchXMLExport_Styles_getImplementationName() throw()
3726 return "SchXMLExport.Styles";
3729 Reference< uno::XInterface > SchXMLExport_Styles_createInstance(const Reference< lang::XMultiServiceFactory >& rSMgr)
3731 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr), SchXMLExport_Styles_getImplementationName(), SvXMLExportFlags::STYLES ));
3734 // Oasis format
3735 Sequence< OUString > SchXMLExport_Oasis_Styles_getSupportedServiceNames() throw()
3737 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLOasisStylesExporter" };
3740 OUString SchXMLExport_Oasis_Styles_getImplementationName() throw()
3742 return "SchXMLExport.Oasis.Styles";
3745 Reference< uno::XInterface > SchXMLExport_Oasis_Styles_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3747 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr), SchXMLExport_Oasis_Styles_getImplementationName(), SvXMLExportFlags::STYLES | SvXMLExportFlags::OASIS ));
3750 Sequence< OUString > SchXMLExport_Content_getSupportedServiceNames() throw()
3752 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLContentExporter" };
3755 OUString SchXMLExport_Content_getImplementationName() throw()
3757 return "SchXMLExport.Content";
3760 Reference< uno::XInterface > SchXMLExport_Content_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3762 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr), SchXMLExport_Content_getImplementationName(), SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::FONTDECLS ));
3765 // Oasis format
3766 Sequence< OUString > SchXMLExport_Oasis_Content_getSupportedServiceNames() throw()
3768 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLOasisContentExporter" };
3771 OUString SchXMLExport_Oasis_Content_getImplementationName() throw()
3773 return "SchXMLExport.Oasis.Content";
3776 Reference< uno::XInterface > SchXMLExport_Oasis_Content_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3778 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr), SchXMLExport_Oasis_Content_getImplementationName(), SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::OASIS ));
3781 // Oasis format
3782 Sequence< OUString > SchXMLExport_Oasis_Meta_getSupportedServiceNames() throw()
3784 return Sequence< OUString > { "com.sun.star.comp.Chart.XMLOasisMetaExporter" };
3787 OUString SchXMLExport_Oasis_Meta_getImplementationName() throw()
3789 return "SchXMLExport.Oasis.Meta";
3792 Reference< uno::XInterface > SchXMLExport_Oasis_Meta_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3794 return static_cast<cppu::OWeakObject*>(new SchXMLExport( comphelper::getComponentContext(rSMgr), SchXMLExport_Oasis_Meta_getImplementationName(), SvXMLExportFlags::META | SvXMLExportFlags::OASIS ));
3797 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */