LibreOffice Module xmloff (master)  1
SchXMLExport.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <memory>
21 #include <sal/config.h>
22 #include <sal/log.hxx>
23 
24 #include <sax/tools/converter.hxx>
25 
26 #include <xmloff/xmlprmap.hxx>
27 
28 #include <SchXMLExport.hxx>
30 #include "ColorPropertySet.hxx"
31 #include "SchXMLTools.hxx"
32 #include "SchXMLEnumConverter.hxx"
33 #include <facreg.hxx>
34 
36 #include <tools/globname.hxx>
37 #include <comphelper/classids.hxx>
38 #include <comphelper/sequence.hxx>
39 
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>
47 #include <rtl/math.hxx>
48 
49 #include <vector>
50 #include <algorithm>
51 #include <queue>
52 #include <iterator>
53 #include <numeric>
54 
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>
61 
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>
74 
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>
93 
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>
100 
101 #include <tools/diagnose_ex.h>
103 #include "PropertyMap.hxx"
104 
105 using namespace com::sun::star;
106 using namespace ::xmloff::token;
107 
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;
112 
113 
114 namespace
115 {
116  using CustomLabelSeq = Sequence<Reference<chart2::XDataPointCustomLabelField>>;
117 
118  struct SchXMLDataPointStruct
119  {
120  OUString maStyleName;
121  sal_Int32 mnRepeat;
122  CustomLabelSeq mCustomLabelText;
123  chart2::RelativePosition mCustomLabelPos;
124 
125  SchXMLDataPointStruct() : mnRepeat( 1 ) {}
126  };
127 }
128 
129 
131 {
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;
137 
138 public:
140  SvXMLAutoStylePoolP& rASPool );
141 
143  SchXMLExportHelper_Impl& operator=(const SchXMLExportHelper_Impl&) = delete;
144 
145  // auto-styles
147  void collectAutoStyles( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc );
148 
150  void exportAutoStyles();
151 
163  void exportChart( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc,
164  bool bIncludeTable );
165 
166  const rtl::Reference<XMLPropertySetMapper>& GetPropertySetMapper() const;
167 
168  void SetChartRangeAddress( const OUString& rAddress )
169  { msChartAddress = rAddress; }
170 
171  void InitRangeSegmentationProperties(
172  const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc );
173 
174  static css::awt::Size getPageSize(
175  const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc );
176 
180  ::std::queue< OUString > maAutoStyleNameQueue;
181  void CollectAutoStyle(
182  const std::vector< XMLPropertyState >& aStates );
183  void AddAutoStyleAttribute(
184  const std::vector< XMLPropertyState >& aStates );
185 
187  void parseDocument( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc,
188  bool bExportContent,
189  bool bIncludeTable = false );
190  void exportTable();
191  void exportPlotArea(
192  const css::uno::Reference< css::chart::XDiagram >& xDiagram,
193  const css::uno::Reference< css::chart2::XDiagram >& xNewDiagram,
194  const css::awt::Size & rPageSize,
195  bool bExportContent,
196  bool bIncludeTable );
197  void exportCoordinateRegion( const css::uno::Reference< css::chart::XDiagram >& xDiagram );
198  void exportAxes( const css::uno::Reference< css::chart::XDiagram > & xDiagram,
199  const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram,
200  bool bExportContent );
201  void exportAxis( enum XMLTokenEnum eDimension, enum XMLTokenEnum eAxisName,
202  const Reference< beans::XPropertySet >& rAxisProps, const Reference< chart2::XAxis >& rChart2Axis,
203  const OUString& rCategoriesRanges,
204  bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, bool bExportContent, OUString sChartType );
205  void exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent );
206  void exportDateScale( const Reference< beans::XPropertySet >& rAxisProps );
207  void exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent );
208 
209  void exportSeries(
210  const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram,
211  const css::awt::Size & rPageSize,
212  bool bExportContent,
213  bool bHasTwoYAxes );
214 
215  void exportPropertyMapping(
216  const css::uno::Reference< css::chart2::data::XDataSource > & xSource,
217  const Sequence< OUString >& rSupportedMappings );
218 
219  void exportCandleStickSeries(
220  const css::uno::Sequence<
221  css::uno::Reference< css::chart2::XDataSeries > > & aSeriesSeq,
222  const css::uno::Reference< css::chart2::XDiagram > & xDiagram,
223  bool bJapaneseCandleSticks,
224  bool bExportContent );
225  void exportDataPoints(
226  const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties,
227  sal_Int32 nSeriesLength,
228  const css::uno::Reference< css::chart2::XDiagram > & xDiagram,
229  bool bExportContent );
230 
231  void exportCustomLabel(const CustomLabelSeq & xCustomLabel);
232  void exportCustomLabelPosition(const chart2::RelativePosition & xCustomLabelPosition);
233 
234  void exportRegressionCurve(
235  const css::uno::Reference<css::chart2::XDataSeries>& xSeries,
236  const css::awt::Size& rPageSize,
237  bool bExportContent );
238 
239  void exportErrorBar (
240  const css::uno::Reference<beans::XPropertySet> &xSeriesProp, bool bYError,
241  bool bExportContent );
242 
244  void addPosition( const css::awt::Point & rPosition );
245  void addPosition( const css::uno::Reference< css::drawing::XShape >& xShape );
247  void addSize( const css::awt::Size & rSize, bool bIsOOoNamespace = false );
248  void addSize( const css::uno::Reference< css::drawing::XShape >& xShape );
250  void exportText( const OUString& rText );
251 
252 public:
257 
258  static constexpr OUStringLiteral gsTableName = "local-table";
259  OUStringBuffer msStringBuffer;
260  OUString msString;
261 
262  // members filled by InitRangeSegmentationProperties (retrieved from DataProvider)
263  bool mbHasCategoryLabels; //if the categories are only automatically generated this will be false
265  OUString msChartAddress;
266  css::uno::Sequence< sal_Int32 > maSequenceMapping;
267 
268  OUString msCLSID;
269 
270  OUString maSrcShellID;
271  OUString maDestShellID;
272 
273  css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes;
274 
275  tDataSequenceCont m_aDataSequencesToExport;
277 };
278 
279 namespace
280 {
281 
282 CustomLabelSeq lcl_getCustomLabelField(sal_Int32 nDataPointIndex,
283  const uno::Reference< chart2::XDataSeries >& rSeries)
284 {
285  if( !rSeries.is() )
286  return CustomLabelSeq();
287 
288  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
289  if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
290  return CustomLabelSeq();
291 
292  if(Reference<beans::XPropertySet> xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is())
293  {
294  if(Any aAny = xLabels->getPropertyValue("CustomLabelFields"); aAny.hasValue())
295  {
296  Sequence<uno::Reference<chart2::XDataPointCustomLabelField>> aCustomLabels;
297  aAny >>= aCustomLabels;
298  return aCustomLabels;
299  }
300  }
301  return CustomLabelSeq();
302 }
303 
304 css::chart2::RelativePosition lcl_getCustomLabelPosition(sal_Int32 nDataPointIndex,
305  const uno::Reference< chart2::XDataSeries >& rSeries)
306 {
307  if (!rSeries.is())
308  return chart2::RelativePosition();
309 
310  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
311  if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
312  return chart2::RelativePosition();
313 
314  if (Reference<beans::XPropertySet> xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is())
315  {
316  if (Any aAny = xLabels->getPropertyValue("CustomLabelPosition"); aAny.hasValue())
317  {
318  chart2::RelativePosition aCustomLabelPos;
319  aAny >>= aCustomLabelPos;
320  return aCustomLabelPos;
321  }
322  }
323  return chart2::RelativePosition();
324 }
325 
326 class lcl_MatchesRole
327 {
328 public:
329  explicit lcl_MatchesRole( const OUString & aRole ) :
330  m_aRole( aRole )
331  {}
332 
333  bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
334  {
335  if( !xSeq.is() )
336  return false;
337  Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
338  OUString aRole;
339 
340  return ( xProp.is() &&
341  (xProp->getPropertyValue( "Role" ) >>= aRole ) &&
342  m_aRole == aRole );
343  }
344 
345 private:
346  OUString m_aRole;
347 };
348 
349 template< typename T >
350  void lcl_SequenceToVectorAppend( const Sequence< T > & rSource, ::std::vector< T > & rDestination )
351 {
352  rDestination.reserve( rDestination.size() + rSource.getLength());
353  ::std::copy( rSource.begin(), rSource.end(),
354  ::std::back_inserter( rDestination ));
355 }
356 
357 template< typename T >
358  void lcl_SequenceToVector( const Sequence< T > & rSource, ::std::vector< T > & rDestination )
359 {
360  rDestination.clear();
361  lcl_SequenceToVectorAppend( rSource, rDestination );
362 }
363 
364 Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram )
365 {
367  try
368  {
369  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
370  xDiagram, uno::UNO_QUERY_THROW );
371  const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
372  xCooSysCnt->getCoordinateSystems());
373  for( const auto& rCooSys : aCooSysSeq )
374  {
375  Reference< chart2::XCoordinateSystem > xCooSys( rCooSys );
376  SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL" );
377  for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
378  {
379  const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
380  for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
381  {
382  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI );
383  SAL_WARN_IF( !xAxis.is(), "xmloff.chart", "xAxis is NULL");
384  if( xAxis.is())
385  {
386  chart2::ScaleData aScaleData = xAxis->getScaleData();
387  if( aScaleData.Categories.is())
388  {
389  xResult.set( aScaleData.Categories );
390  break;
391  }
392  }
393  }
394  }
395  }
396  }
397  catch( const uno::Exception & )
398  {
399  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
400  }
401 
402  return xResult;
403 }
404 
405 Reference< chart2::data::XDataSource > lcl_createDataSource(
406  const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData )
407 {
410  Reference< chart2::data::XDataSink > xSink(
411  xContext->getServiceManager()->createInstanceWithContext(
412  "com.sun.star.chart2.data.DataSource", xContext ),
413  uno::UNO_QUERY_THROW );
414  xSink->setData( aData );
415 
416  return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY );
417 }
418 
419 Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc )
420 {
421  ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer;
422  if( xChartDoc.is() )
423  {
424  Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
425  ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram ));
426  for( const auto& rSeries : aSeriesVector )
427  {
428  Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY );
429  if( !xDataSource.is() )
430  continue;
431  uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() );
432  lcl_SequenceToVectorAppend( aDataSequences, aContainer );
433  }
434  }
435 
436  return comphelper::containerToSequence( aContainer );
437 }
438 
440  lcl_getDataSequenceByRole(
441  const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq,
442  const OUString & rRole )
443 {
445 
446  const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
447  const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
449  ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole ));
450 
451  if( pMatch != pEnd )
452  return *pMatch;
453 
454  return aNoResult;
455 }
456 
457 Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, bool& rOutSourceHasCategoryLabels )
458 {
459  ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector;
460 
461  //categories are always the first sequence
462  Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
463  Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) );
464  if( xCategories.is() )
465  aLabeledSeqVector.push_back( xCategories );
466  rOutSourceHasCategoryLabels = xCategories.is();
467 
468  Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector(
469  lcl_getAllSeriesSequences( xChartDoc ) );
470 
471  //the first x-values is always the next sequence //todo ... other x-values get lost for old format
473  lcl_getDataSequenceByRole( aSeriesSeqVector, "values-x" ) );
474  if( xXValues.is() )
475  aLabeledSeqVector.push_back( xXValues );
476 
477  //add all other sequences now without x-values
478  lcl_MatchesRole aHasXValues( "values-x" );
479  std::copy_if(aSeriesSeqVector.begin(), aSeriesSeqVector.end(), std::back_inserter(aLabeledSeqVector),
480  [&aHasXValues](const auto& rSeriesSeq) { return !aHasXValues( rSeriesSeq ); });
481 
482  Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( comphelper::containerToSequence(aLabeledSeqVector) );
483 
484  return lcl_createDataSource( aSeq );
485 }
486 
487 bool lcl_isSeriesAttachedToFirstAxis(
488  const Reference< chart2::XDataSeries > & xDataSeries )
489 {
490  bool bResult=true;
491 
492  try
493  {
494  sal_Int32 nAxisIndex = 0;
495  Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
496  xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex;
497  bResult = (0==nAxisIndex);
498  }
499  catch( const uno::Exception & )
500  {
501  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
502  }
503 
504  return bResult;
505 }
506 
507 OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::XChartDocument > & xDoc )
508 {
509  OUString aResult = rRange;
510  if( !xDoc.is() )
511  return aResult;
512  Reference< chart2::data::XRangeXMLConversion > xConversion(
513  xDoc->getDataProvider(), uno::UNO_QUERY );
514  if( xConversion.is())
515  aResult = xConversion->convertRangeToXML( rRange );
516  return aResult;
517 }
518 
519 typedef ::std::pair< OUString, OUString > tLabelAndValueRange;
520 
521 tLabelAndValueRange lcl_getLabelAndValueRangeByRole(
522  const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt,
523  const OUString & rRole,
524  const Reference< chart2::XChartDocument > & xDoc,
525  SchXMLExportHelper_Impl::tDataSequenceCont & rOutSequencesToExport )
526 {
527  tLabelAndValueRange aResult;
528 
530  lcl_getDataSequenceByRole( aSeqCnt, rRole ));
531  if( xLabeledSeq.is())
532  {
533  Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
534  if( xLabelSeq.is())
535  aResult.first = lcl_ConvertRange( xLabelSeq->getSourceRangeRepresentation(), xDoc );
536 
537  Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
538  if( xValueSeq.is())
539  aResult.second = lcl_ConvertRange( xValueSeq->getSourceRangeRepresentation(), xDoc );
540 
541  if( xLabelSeq.is() || xValueSeq.is())
542  rOutSequencesToExport.emplace_back( xLabelSeq, xValueSeq );
543  }
544 
545  return aResult;
546 }
547 
548 sal_Int32 lcl_getSequenceLengthByRole(
549  const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt,
550  const OUString & rRole )
551 {
553  lcl_getDataSequenceByRole( aSeqCnt, rRole ));
554  if( xLabeledSeq.is())
555  {
556  Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getValues());
557  return xSeq->getData().getLength();
558  }
559  return 0;
560 }
561 
562 OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
563 {
564  OUStringBuffer aResult;
565  bool bPrecedeWithSpace = false;
566  for( const auto& rString : rSequence )
567  {
568  if( !rString.isEmpty())
569  {
570  if( bPrecedeWithSpace )
571  aResult.append( ' ' );
572  aResult.append( rString );
573  bPrecedeWithSpace = true;
574  }
575  }
576  return aResult.makeStringAndClear();
577 }
578 
579 void lcl_getLabelStringSequence( Sequence< OUString >& rOutLabels, const Reference< chart2::data::XDataSequence > & xLabelSeq )
580 {
581  uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY );
582  if( xTextualDataSequence.is())
583  {
584  rOutLabels = xTextualDataSequence->getTextualData();
585  }
586  else if( xLabelSeq.is())
587  {
588  Sequence< uno::Any > aAnies( xLabelSeq->getData());
589  rOutLabels.realloc( aAnies.getLength());
590  for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
591  aAnies[i] >>= rOutLabels[i];
592  }
593 }
594 
595 sal_Int32 lcl_getMaxSequenceLength(
596  const SchXMLExportHelper_Impl::tDataSequenceCont & rContainer )
597 {
598  sal_Int32 nResult = 0;
599  for( const auto& rDataSequence : rContainer )
600  {
601  if( rDataSequence.second.is())
602  {
603  sal_Int32 nSeqLength = rDataSequence.second->getData().getLength();
604  if( nSeqLength > nResult )
605  nResult = nSeqLength;
606  }
607  }
608  return nResult;
609 }
610 
611 uno::Sequence< OUString > lcl_DataSequenceToStringSequence(
612  const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
613 {
614  uno::Sequence< OUString > aResult;
615  if(!xDataSequence.is())
616  return aResult;
617 
618  uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY );
619  if( xTextualDataSequence.is() )
620  {
621  aResult = xTextualDataSequence->getTextualData();
622  }
623  else
624  {
625  uno::Sequence< uno::Any > aValues = xDataSequence->getData();
626  aResult.realloc(aValues.getLength());
627 
628  for(sal_Int32 nN=aValues.getLength();nN--;)
629  aValues[nN] >>= aResult[nN];
630  }
631 
632  return aResult;
633 }
634 ::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq )
635 {
636  double fNan = 0.0;
637  ::rtl::math::setNan( &fNan );
638  ::std::vector< double > aResult;
639  if(!xSeq.is())
640  return aResult;
641 
642  uno::Sequence< double > aValuesSequence;
643  Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
644  if( xNumSeq.is() )
645  {
646  aValuesSequence = xNumSeq->getNumericalData();
647  }
648  else
649  {
650  Sequence< uno::Any > aAnies( xSeq->getData() );
651  aValuesSequence.realloc( aAnies.getLength() );
652  for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
653  aAnies[i] >>= aValuesSequence[i];
654  }
655 
656  //special handling for x-values (if x-values do point to categories, indices are used instead )
657  Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY );
658  if( xProp.is() )
659  {
660  OUString aRole;
661  xProp->getPropertyValue("Role") >>= aRole;
662  if( aRole.match("values-x") )
663  {
664  //lcl_clearIfNoValuesButTextIsContained - replace by indices if the values are not appropriate
665  bool bHasValue = std::any_of(aValuesSequence.begin(), aValuesSequence.end(),
666  [](double fValue) { return !std::isnan( fValue ); });
667  if(!bHasValue)
668  {
669  //no double value is contained
670  //is there any text?
671  uno::Sequence< OUString > aStrings( lcl_DataSequenceToStringSequence( xSeq ) );
672  bool bHasText = std::any_of(aStrings.begin(), aStrings.end(),
673  [](const OUString& rString) { return !rString.isEmpty(); });
674  if( bHasText )
675  {
676  std::iota(aValuesSequence.begin(), aValuesSequence.end(), 1);
677  }
678  }
679  }
680  }
681 
682  ::std::copy( aValuesSequence.begin(), aValuesSequence.end(),
683  ::std::back_inserter( aResult ));
684  return aResult;
685 }
686 
687 bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
688 {
689  if( !xDataSequence.is() )
690  return false;
691  uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY );
692  if( xProp.is() )
693  {
694  uno::Sequence< sal_Int32 > aHiddenValues;
695  try
696  {
697  xProp->getPropertyValue("HiddenValues") >>= aHiddenValues;
698  if( !aHiddenValues.hasElements() )
699  return true;
700  }
701  catch( const uno::Exception& )
702  {
703  return true;
704  }
705  }
706  return xDataSequence->getData().hasElements();
707 }
708 
709 typedef vector< OUString > tStringVector;
710 typedef vector< vector< double > > t2DNumberContainer;
711 
712 struct lcl_TableData
713 {
714  t2DNumberContainer aDataInRows;
715  tStringVector aDataRangeRepresentations;
716 
717  tStringVector aColumnDescriptions;
718  tStringVector aColumnDescriptions_Ranges;
719 
720  tStringVector aRowDescriptions;
721  tStringVector aRowDescriptions_Ranges;
722 
723  Sequence< Sequence< uno::Any > > aComplexColumnDescriptions;//outer index is columns - inner index is level
724  Sequence< Sequence< uno::Any > > aComplexRowDescriptions;//outer index is rows - inner index is level
725 
726  ::std::vector< sal_Int32 > aHiddenColumns;
727 };
728 
729 typedef ::std::map< sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair >
730  lcl_DataSequenceMap;
731 
732 struct lcl_SequenceToMapElement
733 {
734  std::pair<const sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair>
735  operator() (const SchXMLExportHelper_Impl::tLabelValuesDataPair& rContent)
736  {
737  sal_Int32 nIndex = -1;
738  if( rContent.second.is()) //has values
739  {
740  OUString aRangeRep( rContent.second->getSourceRangeRepresentation());
741  nIndex = aRangeRep.toInt32();
742  }
743  else if( rContent.first.is()) //has labels
744  nIndex = rContent.first->getSourceRangeRepresentation().copy( sizeof("label ")).toInt32();
745  return std::make_pair(nIndex, rContent);
746  }
747 };
748 
749 void lcl_ReorderInternalSequencesAccordingToTheirRangeName(
751 {
752  lcl_DataSequenceMap aIndexSequenceMap;
753  ::std::transform( rInOutSequences.begin(), rInOutSequences.end(),
754  ::std::inserter( aIndexSequenceMap, aIndexSequenceMap.begin()),
755  lcl_SequenceToMapElement());
756 
757  rInOutSequences.clear();
758  sal_Int32 nIndex = 0;
759  for( const auto& rEntry : aIndexSequenceMap )
760  {
761  if( rEntry.first >= 0 )
762  {
763  // fill empty columns
764  rInOutSequences.insert(
765  rInOutSequences.end(),
766  rEntry.first - nIndex,
767  SchXMLExportHelper_Impl::tDataSequenceCont::value_type(
768  uno::Reference< chart2::data::XDataSequence >(),
769  uno::Reference< chart2::data::XDataSequence >() ));
770  nIndex = rEntry.first;
771  rInOutSequences.push_back( rEntry.second );
772  }
773 
774  ++nIndex;
775  }
776 }
777 
778 lcl_TableData lcl_getDataForLocalTable(
779  const SchXMLExportHelper_Impl::tDataSequenceCont & aSequencesToExport,
780  const Reference< chart2::XAnyDescriptionAccess >& xAnyDescriptionAccess,
781  const OUString& rCategoriesRange,
782  bool bSeriesFromColumns,
783  const Reference< chart2::data::XRangeXMLConversion > & xRangeConversion )
784 {
785  lcl_TableData aResult;
786 
787  try
788  {
789  Sequence< OUString > aSimpleCategories;
790  if( xAnyDescriptionAccess.is() )
791  {
792  //categories
793  if( bSeriesFromColumns )
794  {
795  aSimpleCategories = xAnyDescriptionAccess->getRowDescriptions();
796  aResult.aComplexRowDescriptions = xAnyDescriptionAccess->getAnyRowDescriptions();
797  }
798  else
799  {
800  aSimpleCategories = xAnyDescriptionAccess->getColumnDescriptions();
801  aResult.aComplexColumnDescriptions = xAnyDescriptionAccess->getAnyColumnDescriptions();
802  }
803  }
804 
805  //series values and series labels
806  SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences = aSequencesToExport.size();
807 
808  auto nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport ));
809  if( aSimpleCategories.getLength() > nMaxSequenceLength )
810  {
811  aSimpleCategories.realloc(nMaxSequenceLength);//#i110617#
812  }
813  size_t nNumColumns( bSeriesFromColumns ? nNumSequences : nMaxSequenceLength );
814  size_t nNumRows( bSeriesFromColumns ? nMaxSequenceLength : nNumSequences );
815 
816  // resize data
817  aResult.aDataInRows.resize( nNumRows );
818  double fNan = 0.0;
819  ::rtl::math::setNan( &fNan );
820 
821  for (auto& aData: aResult.aDataInRows)
822  aData.resize(nNumColumns, fNan);
823  aResult.aColumnDescriptions.resize( nNumColumns );
824  aResult.aComplexColumnDescriptions.realloc( nNumColumns );
825  aResult.aRowDescriptions.resize( nNumRows );
826  aResult.aComplexRowDescriptions.realloc( nNumRows );
827 
828  tStringVector& rCategories = bSeriesFromColumns ? aResult.aRowDescriptions : aResult.aColumnDescriptions;
829  tStringVector& rLabels = bSeriesFromColumns ? aResult.aColumnDescriptions : aResult.aRowDescriptions;
830 
831  //categories
832  lcl_SequenceToVector( aSimpleCategories, rCategories );
833  if( !rCategoriesRange.isEmpty() )
834  {
835  OUString aRange(rCategoriesRange);
836  if( xRangeConversion.is())
837  aRange = xRangeConversion->convertRangeToXML( aRange );
838  if( bSeriesFromColumns )
839  aResult.aRowDescriptions_Ranges.push_back( aRange );
840  else
841  aResult.aColumnDescriptions_Ranges.push_back( aRange );
842  }
843 
844  // iterate over all sequences
845  size_t nSeqIdx = 0;
846  Sequence< Sequence< OUString > > aComplexLabels(nNumSequences);
847  for( const auto& rDataSequence : aSequencesToExport )
848  {
849  OUString aRange;
850  Sequence< OUString >& rCurrentComplexLabel = aComplexLabels[nSeqIdx];
851  if( rDataSequence.first.is())
852  {
853  lcl_getLabelStringSequence( rCurrentComplexLabel, rDataSequence.first );
854  rLabels[nSeqIdx] = lcl_flattenStringSequence( rCurrentComplexLabel );
855  aRange = rDataSequence.first->getSourceRangeRepresentation();
856  if( xRangeConversion.is())
857  aRange = xRangeConversion->convertRangeToXML( aRange );
858  }
859  else if( rDataSequence.second.is())
860  {
861  rCurrentComplexLabel.realloc(1);
862  rLabels[nSeqIdx] = rCurrentComplexLabel[0] = lcl_flattenStringSequence(
863  rDataSequence.second->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE ));
864  }
865  if( bSeriesFromColumns )
866  aResult.aColumnDescriptions_Ranges.push_back( aRange );
867  else
868  aResult.aRowDescriptions_Ranges.push_back( aRange );
869 
870  ::std::vector< double > aNumbers( lcl_getAllValuesFromSequence( rDataSequence.second ));
871  if( bSeriesFromColumns )
872  {
873  const sal_Int32 nSize( static_cast< sal_Int32 >( aNumbers.size()));
874  for( sal_Int32 nIdx=0; nIdx<nSize; ++nIdx )
875  aResult.aDataInRows[nIdx][nSeqIdx] = aNumbers[nIdx];
876  }
877  else
878  aResult.aDataInRows[nSeqIdx] = aNumbers;
879 
880  if( rDataSequence.second.is())
881  {
882  aRange = rDataSequence.second->getSourceRangeRepresentation();
883  if( xRangeConversion.is())
884  aRange = xRangeConversion->convertRangeToXML( aRange );
885  }
886  aResult.aDataRangeRepresentations.push_back( aRange );
887 
888  //is column hidden?
889  if( !lcl_SequenceHasUnhiddenData(rDataSequence.first) && !lcl_SequenceHasUnhiddenData(rDataSequence.second) )
890  aResult.aHiddenColumns.push_back(nSeqIdx);
891 
892  ++nSeqIdx;
893  }
894  Sequence< Sequence< Any > >& rComplexAnyLabels = bSeriesFromColumns ? aResult.aComplexColumnDescriptions : aResult.aComplexRowDescriptions;//#i116544#
895  rComplexAnyLabels.realloc(aComplexLabels.getLength());
896  for( sal_Int32 nN=0; nN<aComplexLabels.getLength();nN++ )
897  {
898  Sequence< OUString >& rSource = aComplexLabels[nN];
899  Sequence< Any >& rTarget = rComplexAnyLabels[nN];
900  rTarget.realloc( rSource.getLength() );
901  for( sal_Int32 i=0; i<rSource.getLength(); i++ )
902  rTarget[i] <<= rSource[i];
903  }
904  }
905  catch( const uno::Exception & )
906  {
907  TOOLS_INFO_EXCEPTION("xmloff.chart", "something went wrong during table data collection");
908  }
909 
910  return aResult;
911 }
912 
913 void lcl_exportNumberFormat( const OUString& rPropertyName, const Reference< beans::XPropertySet >& xPropSet,
915 {
916  if( xPropSet.is())
917  {
918  sal_Int32 nNumberFormat = 0;
919  Any aNumAny = xPropSet->getPropertyValue( rPropertyName );
920  if( (aNumAny >>= nNumberFormat) && (nNumberFormat != -1) )
921  rExport.addDataStyle( nNumberFormat );
922  }
923 }
924 
925 ::std::vector< Reference< chart2::data::XDataSequence > >
926  lcl_getErrorBarSequences( const Reference< beans::XPropertySet > & xErrorBarProp )
927 {
928  ::std::vector< Reference< chart2::data::XDataSequence > > aResult;
929  Reference< chart2::data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY );
930  if( !xErrorBarDataSource.is())
931  return aResult;
932 
933  const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences(
934  xErrorBarDataSource->getDataSequences());
935  for( const auto& rSequence : aSequences )
936  {
937  try
938  {
939  if( rSequence.is())
940  {
941  Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues());
942  Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
943  OUString aRole;
944  if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) &&
945  aRole.match( "error-bars-" ))
946  {
947  aResult.push_back( xSequence );
948  }
949  }
950  }
951  catch( const uno::Exception & )
952  {
953  TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exporting error bar ranges" );
954  }
955  }
956 
957  return aResult;
958 }
959 
960 bool lcl_exportDomainForThisSequence( const Reference< chart2::data::XDataSequence >& rValues, OUString& rFirstRangeForThisDomainIndex, SvXMLExport& rExport )
961 {
962  bool bDomainExported = false;
963  if( rValues.is())
964  {
965  Reference< chart2::XChartDocument > xNewDoc( rExport.GetModel(), uno::UNO_QUERY );
966  OUString aRange( lcl_ConvertRange( rValues->getSourceRangeRepresentation(), xNewDoc ) );
967 
968  //work around error in OOo 2.0 (problems with multiple series having a domain element)
969  if( rFirstRangeForThisDomainIndex.isEmpty() || aRange != rFirstRangeForThisDomainIndex )
970  {
972  SvXMLElementExport aDomain( rExport, XML_NAMESPACE_CHART, XML_DOMAIN, true, true );
973  bDomainExported = true;
974  }
975 
976  if( rFirstRangeForThisDomainIndex.isEmpty() )
977  rFirstRangeForThisDomainIndex = aRange;
978  }
979  return bDomainExported;
980 }
981 
982 } // anonymous namespace
983 
984 
986  : m_pImpl( new SchXMLExportHelper_Impl( rExport, rASPool ) )
987 {
988 }
989 
991 {
992 }
993 
994 const OUString& SchXMLExportHelper::getChartCLSID() const
995 {
996  return m_pImpl->msCLSID;
997 }
998 
999 void SchXMLExportHelper::SetSourceShellID( const OUString& rShellID )
1000 {
1001  m_pImpl->maSrcShellID = rShellID;
1002 }
1003 
1004 void SchXMLExportHelper::SetDestinationShellID( const OUString& rShellID )
1005 {
1006  m_pImpl->maDestShellID = rShellID;
1007 }
1008 
1010 {
1011  return mxPropertySetMapper;
1012 }
1013 
1015 {
1016  if( mxExpPropMapper.is())
1017  {
1018  //ToDo: when embedded in calc/writer this is not necessary because the
1019  // numberformatter is shared between both documents
1021 
1022  // export chart auto styles
1024 
1025  // export auto styles for additional shapes
1026  mrExport.GetShapeExport()->exportAutoStyles();
1027  // and for text in additional shapes
1028  mrExport.GetTextParagraphExport()->exportTextAutoStyles();
1029  }
1030 }
1031 
1032 // private methods
1033 
1035  SvXMLExport& rExport,
1036  SvXMLAutoStylePoolP& rASPool ) :
1037  mrExport( rExport ),
1038  mrAutoStylePool( rASPool ),
1039  mxPropertySetMapper( new XMLChartPropertySetMapper( true ) ),
1040  mxExpPropMapper( new XMLChartExportPropertyMapper( mxPropertySetMapper, rExport ) ),
1041  mbHasCategoryLabels( false ),
1042  mbRowSourceColumns( true ),
1043  msCLSID( SvGlobalName( SO3_SCH_CLASSID ).GetHexName() )
1044 {
1045  // register chart auto-style family
1048  OUString( XML_STYLE_FAMILY_SCH_CHART_NAME ),
1049  mxExpPropMapper.get(),
1050  OUString( XML_STYLE_FAMILY_SCH_CHART_PREFIX ));
1051 
1052  // register shape family
1056  mxExpPropMapper.get(),
1058  // register paragraph family also for shapes
1062  mxExpPropMapper.get(),
1063  OUString( 'P' ));
1064  // register text family also for shapes
1067  GetXMLToken( XML_TEXT ),
1068  mxExpPropMapper.get(),
1069  OUString( 'T' ));
1070 }
1071 
1072 void SchXMLExportHelper_Impl::collectAutoStyles( Reference< chart::XChartDocument > const & rChartDoc )
1073 {
1074  parseDocument( rChartDoc, false );
1075 }
1076 
1077 void SchXMLExportHelper_Impl::exportChart( Reference< chart::XChartDocument > const & rChartDoc,
1078  bool bIncludeTable )
1079 {
1080  parseDocument( rChartDoc, true, bIncludeTable );
1081  SAL_WARN_IF( !maAutoStyleNameQueue.empty(), "xmloff.chart", "There are still remaining autostyle names in the queue" );
1082 }
1083 
1084 static OUString lcl_GetStringFromNumberSequence( const css::uno::Sequence< sal_Int32 >& rSequenceMapping, bool bRemoveOneFromEachIndex /*should be true if having categories*/ )
1085 {
1086  OUStringBuffer aBuf;
1087  bool bHasPredecessor = false;
1088  for( sal_Int32 nIndex : rSequenceMapping )
1089  {
1090  if( bRemoveOneFromEachIndex )
1091  --nIndex;
1092  if(nIndex>=0)
1093  {
1094  if(bHasPredecessor)
1095  aBuf.append( ' ' );
1096  aBuf.append( nIndex );
1097  bHasPredecessor = true;
1098  }
1099  }
1100  return aBuf.makeStringAndClear();
1101 }
1102 
1104 void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > const & rChartDoc,
1105  bool bExportContent,
1106  bool bIncludeTable )
1107 {
1108  Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY );
1109  if( !rChartDoc.is() || !xNewDoc.is() )
1110  {
1111  SAL_WARN("xmloff.chart", "No XChartDocument was given for export." );
1112  return;
1113  }
1114 
1115  mxExpPropMapper->setChartDoc(xNewDoc);
1116 
1117  awt::Size aPageSize( getPageSize( xNewDoc ));
1118  if( bExportContent )
1119  addSize( aPageSize );
1120  Reference< chart::XDiagram > xDiagram = rChartDoc->getDiagram();
1121  Reference< chart2::XDiagram > xNewDiagram;
1122  if( xNewDoc.is())
1123  xNewDiagram.set( xNewDoc->getFirstDiagram());
1124 
1125  //todo remove if model changes are notified and view is updated automatically
1126  if( bExportContent )
1127  {
1128  Reference< util::XRefreshable > xRefreshable( xNewDoc, uno::UNO_QUERY );
1129  if( xRefreshable.is() )
1130  xRefreshable->refresh();
1131  }
1132 
1133  // get Properties of ChartDocument
1134  bool bHasMainTitle = false;
1135  bool bHasSubTitle = false;
1136  bool bHasLegend = false;
1137  util::DateTime aNullDate(0,0,0,0,30,12,1899, false);
1138 
1139  std::vector< XMLPropertyState > aPropertyStates;
1140 
1141  Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY );
1142  if( xDocPropSet.is())
1143  {
1144  try
1145  {
1146  Any aAny = xDocPropSet->getPropertyValue("HasMainTitle");
1147  aAny >>= bHasMainTitle;
1148  aAny = xDocPropSet->getPropertyValue("HasSubTitle");
1149  aAny >>= bHasSubTitle;
1150  aAny = xDocPropSet->getPropertyValue("HasLegend");
1151  aAny >>= bHasLegend;
1152  if ( bIncludeTable )
1153  {
1154  aAny = xDocPropSet->getPropertyValue("NullDate");
1155  if ( !aAny.hasValue() )
1156  {
1157  Reference<container::XChild> xChild(rChartDoc, uno::UNO_QUERY );
1158  if ( xChild.is() )
1159  {
1160  Reference< beans::XPropertySet > xParentDoc( xChild->getParent(),uno::UNO_QUERY);
1161  if ( xParentDoc.is() && xParentDoc->getPropertySetInfo()->hasPropertyByName("NullDate") )
1162  aAny = xParentDoc->getPropertyValue("NullDate");
1163  }
1164  }
1165 
1166  aAny >>= aNullDate;
1167  }
1168  }
1169  catch( const beans::UnknownPropertyException & )
1170  {
1171  SAL_WARN("xmloff.chart", "Required property not found in ChartDocument" );
1172  }
1173  }
1174 
1175  if ( bIncludeTable && (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 ) )
1176  {
1178  {
1179  OUStringBuffer sBuffer;
1180  ::sax::Converter::convertDateTime(sBuffer, aNullDate, nullptr);
1181  mrExport.AddAttribute( XML_NAMESPACE_TABLE,XML_DATE_VALUE,sBuffer.makeStringAndClear());
1183  }
1184  }
1185 
1186  // chart element
1187  std::unique_ptr<SvXMLElementExport> xElChart;
1188 
1189  // get property states for autostyles
1190  if( mxExpPropMapper.is())
1191  {
1192  Reference< beans::XPropertySet > xPropSet = rChartDoc->getArea();
1193  if( xPropSet.is())
1194  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1195  }
1196 
1197  if( bExportContent )
1198  {
1199  //export data provider in xlink:href attribute
1200  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
1201  if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
1202  {
1203  OUString aDataProviderURL( ".." );
1204  if( xNewDoc->hasInternalDataProvider() )
1205  aDataProviderURL = ".";
1206  else //special handling for data base data provider necessary
1207  {
1208  Reference< chart2::data::XDatabaseDataProvider > xDBDataProvider( xNewDoc->getDataProvider(), uno::UNO_QUERY );
1209  if( xDBDataProvider.is() )
1210  aDataProviderURL = ".";
1211  }
1212  mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aDataProviderURL );
1214  }
1215 
1216  Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xNewDoc->getDataProvider(), uno::UNO_QUERY);
1217  if (xPivotTableDataProvider.is() && nCurrentODFVersion > SvtSaveOptions::ODFSVER_012)
1218  {
1219  OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName();
1221  }
1222 
1223  OUString sChartType( xDiagram->getDiagramType() );
1224 
1225  // attributes
1226  // determine class
1227  if( !sChartType.isEmpty())
1228  {
1229  enum XMLTokenEnum eXMLChartType = SchXMLTools::getTokenByChartType( sChartType, true /* bUseOldNames */ );
1230 
1231  SAL_WARN_IF( eXMLChartType == XML_TOKEN_INVALID, "xmloff.chart", "invalid chart class" );
1232  if( eXMLChartType == XML_TOKEN_INVALID )
1233  eXMLChartType = XML_BAR;
1234 
1235  if( eXMLChartType == XML_ADD_IN )
1236  {
1237  // sChartType is the service-name of the add-in
1240  XML_NAMESPACE_OOO, sChartType) );
1241  }
1242  else if( eXMLChartType != XML_TOKEN_INVALID )
1243  {
1246  XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) );
1247  }
1248 
1249  //column-mapping or row-mapping
1250  if( maSequenceMapping.hasElements() )
1251  {
1253  if( mbRowSourceColumns )
1255  OUString aSequenceMappingStr( lcl_GetStringFromNumberSequence(
1256  maSequenceMapping, mbHasCategoryLabels && !xNewDoc->hasInternalDataProvider() ) );
1257 
1259  ::xmloff::token::GetXMLToken( eTransToken ),
1260  aSequenceMappingStr );
1261  }
1262  }
1263  // write style name
1264  AddAutoStyleAttribute( aPropertyStates );
1265 
1266  //element
1267  xElChart.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_CHART, true, true ));
1268  }
1269  else // autostyles
1270  {
1271  CollectAutoStyle( aPropertyStates );
1272  }
1273  // remove property states for autostyles
1274  aPropertyStates.clear();
1275 
1276  // title element
1277  if( bHasMainTitle )
1278  {
1279  // get property states for autostyles
1280  if( mxExpPropMapper.is())
1281  {
1282  Reference< beans::XPropertySet > xPropSet( rChartDoc->getTitle(), uno::UNO_QUERY );
1283  if( xPropSet.is())
1284  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1285  }
1286  if( bExportContent )
1287  {
1288  Reference< drawing::XShape > xShape = rChartDoc->getTitle();
1289  if( xShape.is()) // && "hasTitleBeenMoved"
1290  addPosition( xShape );
1291 
1292  // write style name
1293  AddAutoStyleAttribute( aPropertyStates );
1294 
1295  // element
1296  SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true );
1297 
1298  // content (text:p)
1299  Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1300  if( xPropSet.is())
1301  {
1302  Any aAny( xPropSet->getPropertyValue( "String" ));
1303  OUString aText;
1304  aAny >>= aText;
1305  exportText( aText );
1306  }
1307  }
1308  else // autostyles
1309  {
1310  CollectAutoStyle( aPropertyStates );
1311  }
1312  // remove property states for autostyles
1313  aPropertyStates.clear();
1314  }
1315 
1316  // subtitle element
1317  if( bHasSubTitle )
1318  {
1319  // get property states for autostyles
1320  if( mxExpPropMapper.is())
1321  {
1322  Reference< beans::XPropertySet > xPropSet( rChartDoc->getSubTitle(), uno::UNO_QUERY );
1323  if( xPropSet.is())
1324  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1325  }
1326 
1327  if( bExportContent )
1328  {
1329  Reference< drawing::XShape > xShape = rChartDoc->getSubTitle();
1330  if( xShape.is())
1331  addPosition( xShape );
1332 
1333  // write style name
1334  AddAutoStyleAttribute( aPropertyStates );
1335 
1336  // element (has no subelements)
1337  SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, true, true );
1338 
1339  // content (text:p)
1340  Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1341  if( xPropSet.is())
1342  {
1343  Any aAny( xPropSet->getPropertyValue( "String" ));
1344  OUString aText;
1345  aAny >>= aText;
1346  exportText( aText );
1347  }
1348  }
1349  else // autostyles
1350  {
1351  CollectAutoStyle( aPropertyStates );
1352  }
1353  // remove property states for autostyles
1354  aPropertyStates.clear();
1355  }
1356 
1357  // legend element
1358  if( bHasLegend )
1359  {
1360  // get property states for autostyles
1361  if( mxExpPropMapper.is())
1362  {
1363  Reference< beans::XPropertySet > xPropSet( rChartDoc->getLegend(), uno::UNO_QUERY );
1364  if( xPropSet.is())
1365  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1366  }
1367 
1368  if( bExportContent )
1369  {
1370  Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY );
1371  if( xProp.is())
1372  {
1373  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
1374 
1375  // export legend anchor position
1376  try
1377  {
1378  Any aAny( xProp->getPropertyValue("Alignment"));
1381  }
1382  catch( const beans::UnknownPropertyException & )
1383  {
1384  SAL_WARN("xmloff.chart", "Property Align not found in ChartLegend" );
1385  }
1386 
1387  // export legend overlay
1388  try
1389  {
1390  if (nCurrentODFVersion > SvtSaveOptions::ODFSVER_012)
1391  {
1392  Any aAny( xProp->getPropertyValue("Overlay"));
1393  if(aAny.get<bool>())
1394  mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_OVERLAY, OUString::boolean(true));
1395  }
1396  }
1397  catch( const beans::UnknownPropertyException & )
1398  {
1399  SAL_WARN("xmloff.chart", "Property Overlay not found in ChartLegend" );
1400  }
1401 
1402  // export absolute legend position
1403  Reference< drawing::XShape > xLegendShape( xProp, uno::UNO_QUERY );
1404  addPosition( xLegendShape );
1405 
1406  // export legend size
1407  if (xLegendShape.is() && nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
1408  {
1409  try
1410  {
1411  chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH;
1412  OUString aExpansionString;
1413  Any aAny( xProp->getPropertyValue("Expansion"));
1414  bool bHasExpansion = (aAny >>= nLegendExpansion);
1415  if( bHasExpansion && SchXMLEnumConverter::getLegendExpansionConverter().exportXML( aExpansionString, aAny, mrExport.GetMM100UnitConverter() ) )
1416  {
1418  if( nLegendExpansion == chart::ChartLegendExpansion_CUSTOM)
1419  {
1420  awt::Size aSize( xLegendShape->getSize() );
1421  // tdf#131966: chart legend attributes width and height shouldn't be exported to ODF 1.2 (strict)
1422  if (nCurrentODFVersion > SvtSaveOptions::ODFSVER_012)
1423  addSize( aSize, true );
1424  OUStringBuffer aAspectRatioString;
1426  aAspectRatioString,
1427  (aSize.Height == 0
1428  ? 1.0
1429  : double(aSize.Width)/double(aSize.Height)));
1430  mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO, aAspectRatioString.makeStringAndClear() );
1431  }
1432  }
1433  }
1434  catch( const beans::UnknownPropertyException & )
1435  {
1436  SAL_WARN("xmloff.chart", "Property Expansion not found in ChartLegend" );
1437  }
1438  }
1439  }
1440 
1441  // write style name
1442  AddAutoStyleAttribute( aPropertyStates );
1443 
1444  // element
1445  SvXMLElementExport aLegend( mrExport, XML_NAMESPACE_CHART, XML_LEGEND, true, true );
1446  }
1447  else // autostyles
1448  {
1449  CollectAutoStyle( aPropertyStates );
1450  }
1451  // remove property states for autostyles
1452  aPropertyStates.clear();
1453  }
1454 
1455  // plot-area element
1456  if( xDiagram.is())
1457  exportPlotArea( xDiagram, xNewDiagram, aPageSize, bExportContent, bIncludeTable );
1458 
1459  // export additional shapes
1460  if( xDocPropSet.is() )
1461  {
1462  if( bExportContent )
1463  {
1464  if( mxAdditionalShapes.is())
1465  {
1466  // can't call exportShapes with all shapes because the
1467  // initialisation happened with the complete draw page and not
1468  // the XShapes object used here. Thus the shapes have to be
1469  // exported one by one
1471  Reference< drawing::XShape > xShape;
1472  const sal_Int32 nShapeCount( mxAdditionalShapes->getCount());
1473  for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ )
1474  {
1475  mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape;
1476  SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" );
1477  if( ! xShape.is())
1478  continue;
1479 
1480  rShapeExport->exportShape( xShape );
1481  }
1482  // this would be the easier way if it worked:
1483  //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes );
1484  }
1485  }
1486  else
1487  {
1488  // get a sequence of non-chart shapes (inserted via clipboard)
1489  try
1490  {
1491  Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes");
1492  aShapesAny >>= mxAdditionalShapes;
1493  }
1494  catch( const uno::Exception & )
1495  {
1496  TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found" );
1497  }
1498 
1499  if( mxAdditionalShapes.is())
1500  {
1501  // seek shapes has to be called for the whole page because in
1502  // the shape export the vector of shapes is accessed via the
1503  // ZOrder which might be (actually is) larger than the number of
1504  // shapes in mxAdditionalShapes
1505  Reference< drawing::XDrawPageSupplier > xSupplier( rChartDoc, uno::UNO_QUERY );
1506  SAL_WARN_IF( !xSupplier.is(), "xmloff.chart", "Cannot retrieve draw page to initialize shape export" );
1507  if( xSupplier.is() )
1508  {
1509  Reference< drawing::XShapes > xDrawPage = xSupplier->getDrawPage();
1510  SAL_WARN_IF( !xDrawPage.is(), "xmloff.chart", "Invalid draw page for initializing shape export" );
1511  if( xDrawPage.is())
1512  mrExport.GetShapeExport()->seekShapes( xDrawPage );
1513  }
1514 
1515  // can't call collectShapesAutoStyles with all shapes because
1516  // the initialisation happened with the complete draw page and
1517  // not the XShapes object used here. Thus the shapes have to be
1518  // exported one by one
1520  Reference< drawing::XShape > xShape;
1521  const sal_Int32 nShapeCount( mxAdditionalShapes->getCount());
1522  for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ )
1523  {
1524  mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape;
1525  SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" );
1526  if( ! xShape.is())
1527  continue;
1528 
1529  rShapeExport->collectShapeAutoStyles( xShape );
1530  }
1531  }
1532  }
1533  }
1534 
1535  // table element
1536  // (is included as subelement of chart)
1537  if( bExportContent )
1538  {
1539  // #85929# always export table, otherwise clipboard may lose data
1540  exportTable();
1541  }
1542 }
1543 
1544 static void lcl_exportComplexLabel( const Sequence< uno::Any >& rComplexLabel, SvXMLExport& rExport )
1545 {
1546  sal_Int32 nLength = rComplexLabel.getLength();
1547  if( nLength<=1 )
1548  return;
1549  SvXMLElementExport aTextList( rExport, XML_NAMESPACE_TEXT, XML_LIST, true, true );
1550  for(const auto& rElem : rComplexLabel)
1551  {
1552  SvXMLElementExport aListItem( rExport, XML_NAMESPACE_TEXT, XML_LIST_ITEM, true, true );
1553  OUString aString;
1554  if( !(rElem >>= aString) )
1555  {
1556  //todo?
1557  }
1558  SchXMLTools::exportText( rExport, aString, false /*bConvertTabsLFs*/ );
1559  }
1560 }
1561 
1563 {
1564  // table element
1566 
1567  try
1568  {
1569  bool bProtected = false;
1570  Reference< beans::XPropertySet > xProps( mrExport.GetModel(), uno::UNO_QUERY_THROW );
1571  if ( ( xProps->getPropertyValue("DisableDataTableDialog") >>= bProtected ) &&
1572  bProtected )
1573  {
1575  }
1576  }
1577  catch ( const uno::Exception& )
1578  {
1579  }
1580 
1581  SvXMLElementExport aTable( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true );
1582 
1583  bool bHasOwnData = false;
1584  Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
1585  Reference< chart2::data::XRangeXMLConversion > xRangeConversion;
1586  if( xNewDoc.is())
1587  {
1588  bHasOwnData = xNewDoc->hasInternalDataProvider();
1589  xRangeConversion.set( xNewDoc->getDataProvider(), uno::UNO_QUERY );
1590  }
1591 
1592  Reference< chart2::XAnyDescriptionAccess > xAnyDescriptionAccess;
1593  {
1594  Reference< chart::XChartDocument > xChartDoc( mrExport.GetModel(), uno::UNO_QUERY );
1595  if( xChartDoc.is() )
1596  xAnyDescriptionAccess.set( xChartDoc->getData(), uno::UNO_QUERY );
1597  }
1598 
1599  if( bHasOwnData )
1600  lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport );
1601  lcl_TableData aData( lcl_getDataForLocalTable( m_aDataSequencesToExport
1602  , xAnyDescriptionAccess, maCategoriesRange
1603  , mbRowSourceColumns, xRangeConversion ));
1604 
1605  tStringVector::const_iterator aDataRangeIter( aData.aDataRangeRepresentations.begin());
1606  const tStringVector::const_iterator aDataRangeEndIter( aData.aDataRangeRepresentations.end());
1607 
1608  tStringVector::const_iterator aRowDescriptions_RangeIter( aData.aRowDescriptions_Ranges.begin());
1609  const tStringVector::const_iterator aRowDescriptions_RangeEnd( aData.aRowDescriptions_Ranges.end());
1610 
1611  // declare columns
1612  {
1614  SvXMLElementExport aHeaderColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true );
1615  }
1616  {
1618 
1619  sal_Int32 nNextIndex = 0;
1620  for(sal_Int32 nHiddenIndex : aData.aHiddenColumns)
1621  {
1622  //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste )
1623  if( nHiddenIndex > nNextIndex )
1624  {
1625  sal_Int64 nRepeat = static_cast< sal_Int64 >( nHiddenIndex - nNextIndex );
1626  if(nRepeat>1)
1628  OUString::number( nRepeat ));
1630  }
1633  nNextIndex = nHiddenIndex+1;
1634  }
1635 
1636  sal_Int32 nEndIndex = aData.aColumnDescriptions.size()-1;
1637  if( nEndIndex >= nNextIndex )
1638  {
1639  sal_Int64 nRepeat = static_cast< sal_Int64 >( nEndIndex - nNextIndex + 1 );
1640  if(nRepeat>1)
1642  OUString::number( nRepeat ));
1644  }
1645  }
1646 
1647  // export rows with content
1648  //export header row
1649  {
1652 
1653  //first one empty cell for the row descriptions
1654  {
1655  SvXMLElementExport aEmptyCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true );
1656  SvXMLElementExport aEmptyParagraph( mrExport, XML_NAMESPACE_TEXT, XML_P, true, true );
1657  }
1658 
1659  //export column descriptions
1660  tStringVector::const_iterator aColumnDescriptions_RangeIter( aData.aColumnDescriptions_Ranges.begin());
1661  const tStringVector::const_iterator aColumnDescriptions_RangeEnd( aData.aColumnDescriptions_Ranges.end());
1662  const Sequence< Sequence< uno::Any > >& rComplexColumnDescriptions = aData.aComplexColumnDescriptions;
1663  sal_Int32 nComplexCount = rComplexColumnDescriptions.getLength();
1664  sal_Int32 nC = 0;
1665  for( const auto& rDesc : aData.aColumnDescriptions )
1666  {
1667  bool bExportString = true;
1668  if( nC < nComplexCount )
1669  {
1670  const Sequence< uno::Any >& rComplexLabel = rComplexColumnDescriptions[nC];
1671  if( rComplexLabel.hasElements() )
1672  {
1673  double fValue=0.0;
1674  if( rComplexLabel[0] >>=fValue )
1675  {
1676  bExportString = false;
1677 
1679  msStringBuffer, fValue);
1680  msString = msStringBuffer.makeStringAndClear();
1683  }
1684  }
1685  }
1686  if( bExportString )
1687  {
1689  }
1690 
1692  exportText( rDesc );
1693  if( nC < nComplexCount )
1694  lcl_exportComplexLabel( rComplexColumnDescriptions[nC], mrExport );
1695  if( !bHasOwnData && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd )
1696  {
1697  // remind the original range to allow a correct re-association when copying via clipboard
1698  if (!(*aColumnDescriptions_RangeIter).isEmpty())
1699  SchXMLTools::exportRangeToSomewhere( mrExport, *aColumnDescriptions_RangeIter );
1700  ++aColumnDescriptions_RangeIter;
1701  }
1702 
1703  nC++;
1704  }
1705  SAL_WARN_IF( !bHasOwnData && (aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" );
1706  } // closing row and header-rows elements
1707 
1708  // export value rows
1709  {
1711  tStringVector::const_iterator aRowDescriptionsIter( aData.aRowDescriptions.begin());
1712  const Sequence< Sequence< uno::Any > >& rComplexRowDescriptions = aData.aComplexRowDescriptions;
1713  sal_Int32 nComplexCount = rComplexRowDescriptions.getLength();
1714  sal_Int32 nC = 0;
1715 
1716  for( const auto& rRow : aData.aDataInRows )
1717  {
1719 
1720  //export row descriptions
1721  {
1722  bool bExportString = true;
1723  if( nC < nComplexCount )
1724  {
1725  const Sequence< uno::Any >& rComplexLabel = rComplexRowDescriptions[nC];
1726  if( rComplexLabel.hasElements() )
1727  {
1728  double fValue=0.0;
1729  if( rComplexLabel[0] >>=fValue )
1730  {
1731  bExportString = false;
1732 
1734  msString = msStringBuffer.makeStringAndClear();
1737  }
1738  }
1739  }
1740  if( bExportString )
1741  {
1743  }
1744 
1746  if( aRowDescriptionsIter != aData.aRowDescriptions.end())
1747  {
1748  exportText( *aRowDescriptionsIter );
1749  if( nC < nComplexCount )
1750  lcl_exportComplexLabel( rComplexRowDescriptions[nC], mrExport );
1751  if( !bHasOwnData && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd )
1752  {
1753  // remind the original range to allow a correct re-association when copying via clipboard
1754  SchXMLTools::exportRangeToSomewhere( mrExport, *aRowDescriptions_RangeIter );
1755  ++aRowDescriptions_RangeIter;
1756  }
1757  ++aRowDescriptionsIter;
1758  }
1759  }
1760 
1761  //export row values
1762  for( t2DNumberContainer::value_type::const_iterator aColIt( rRow.begin());
1763  aColIt != rRow.end(); ++aColIt )
1764  {
1766  msString = msStringBuffer.makeStringAndClear();
1770  exportText( msString ); // do not convert tabs and lfs
1771  if( ( !bHasOwnData && aDataRangeIter != aDataRangeEndIter ) &&
1772  ( mbRowSourceColumns || (aColIt == rRow.begin()) ) )
1773  {
1774  // remind the original range to allow a correct re-association when copying via clipboard
1775  if (!(*aDataRangeIter).isEmpty())
1776  SchXMLTools::exportRangeToSomewhere( mrExport, *aDataRangeIter );
1777  ++aDataRangeIter;
1778  }
1779  }
1780 
1781  ++nC;
1782  }
1783  }
1784 
1785  // if range iterator was used it should have reached its end
1786  SAL_WARN_IF( !bHasOwnData && (aDataRangeIter != aDataRangeEndIter), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" );
1787  SAL_WARN_IF( !bHasOwnData && (aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" );
1788 }
1789 
1790 namespace
1791 {
1792 
1793 Reference< chart2::XCoordinateSystem > lcl_getCooSys( const Reference< chart2::XDiagram > & xNewDiagram )
1794 {
1795  Reference< chart2::XCoordinateSystem > xCooSys;
1796  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDiagram, uno::UNO_QUERY );
1797  if(xCooSysCnt.is())
1798  {
1799  Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
1800  if(aCooSysSeq.hasElements())
1801  xCooSys = aCooSysSeq[0];
1802  }
1803  return xCooSys;
1804 }
1805 
1806 Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& xCooSys,
1807  enum XMLTokenEnum eDimension, bool bPrimary=true )
1808 {
1809  Reference< chart2::XAxis > xNewAxis;
1810  try
1811  {
1812  if( xCooSys.is() )
1813  {
1814  sal_Int32 nDimensionIndex=0;
1815  switch( eDimension )
1816  {
1817  case XML_X:
1818  nDimensionIndex=0;
1819  break;
1820  case XML_Y:
1821  nDimensionIndex=1;
1822  break;
1823  case XML_Z:
1824  nDimensionIndex=2;
1825  break;
1826  default:
1827  break;
1828  }
1829 
1830  xNewAxis = xCooSys->getAxisByDimension( nDimensionIndex, bPrimary ? 0 : 1 );
1831  }
1832  }
1833  catch( const uno::Exception & )
1834  {
1835  }
1836  return xNewAxis;
1837 }
1838 
1839 }
1840 
1842  const Reference< chart::XDiagram >& xDiagram,
1843  const Reference< chart2::XDiagram >& xNewDiagram,
1844  const awt::Size & rPageSize,
1845  bool bExportContent,
1846  bool bIncludeTable )
1847 {
1848  SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
1849  if( ! xDiagram.is())
1850  return;
1851 
1852  // variables for autostyles
1854  std::vector< XMLPropertyState > aPropertyStates;
1855 
1856  msStringBuffer.setLength( 0 );
1857 
1858  // plot-area element
1859 
1860  std::unique_ptr<SvXMLElementExport> xElPlotArea;
1861  // get property states for autostyles
1862  xPropSet.set( xDiagram, uno::UNO_QUERY );
1863  if( xPropSet.is())
1864  {
1865  if( mxExpPropMapper.is())
1866  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
1867  }
1868  if( bExportContent )
1869  {
1870  rtl::Reference< XMLShapeExport > rShapeExport;
1871 
1872  // write style name
1873  AddAutoStyleAttribute( aPropertyStates );
1874 
1875  if( !msChartAddress.isEmpty() )
1876  {
1877  if( !bIncludeTable )
1879 
1880  Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY );
1881  if( xDoc.is() )
1882  {
1883  Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY );
1884  if( xDocProp.is())
1885  {
1886  Any aAny;
1887 
1888  try
1889  {
1890  bool bFirstCol = false, bFirstRow = false;
1891 
1892  aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstColumn" );
1893  aAny >>= bFirstCol;
1894  aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstRow" );
1895  aAny >>= bFirstRow;
1896 
1897  if( bFirstCol || bFirstRow )
1898  {
1901  ( bFirstCol
1902  ? ( bFirstRow
1906  }
1907  }
1908  catch( const beans::UnknownPropertyException & )
1909  {
1910  SAL_WARN("xmloff.chart", "Properties missing" );
1911  }
1912  }
1913  }
1914  }
1915 
1916  // attributes
1917  if( xDiagram.is())
1918  {
1919  addPosition( xDiagram );
1920  addSize( xDiagram );
1921  }
1922 
1923  bool bIs3DChart = false;
1924 
1925  if( xPropSet.is())
1926  {
1927  Any aAny;
1928 
1929  // 3d attributes
1930  try
1931  {
1932  aAny = xPropSet->getPropertyValue("Dim3D");
1933  aAny >>= bIs3DChart;
1934 
1935  if( bIs3DChart )
1936  {
1937  rShapeExport = mrExport.GetShapeExport();
1938  if( rShapeExport.is())
1939  rShapeExport->export3DSceneAttributes( xPropSet );
1940  }
1941  }
1942  catch( const uno::Exception & )
1943  {
1944  TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught");
1945  }
1946  }
1947 
1948  // plot-area element
1949  xElPlotArea.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_PLOT_AREA, true, true ));
1950 
1951  //inner position rectangle element
1952  exportCoordinateRegion( xDiagram );
1953 
1954  // light sources (inside plot area element)
1955  if( bIs3DChart &&
1956  rShapeExport.is())
1957  rShapeExport->export3DLamps( xPropSet );
1958  }
1959  else // autostyles
1960  {
1961  CollectAutoStyle( aPropertyStates );
1962  }
1963  // remove property states for autostyles
1964  aPropertyStates.clear();
1965 
1966  // axis elements
1967  exportAxes( xDiagram, xNewDiagram, bExportContent );
1968 
1969  // series elements
1970  Reference< chart2::XAxis > xSecondYAxis = lcl_getAxis( lcl_getCooSys( xNewDiagram ), XML_Y, false );
1971  exportSeries( xNewDiagram, rPageSize, bExportContent, xSecondYAxis.is() );
1972 
1973  // stock-chart elements
1974  OUString sChartType ( xDiagram->getDiagramType());
1975  if( sChartType == "com.sun.star.chart.StockDiagram" )
1976  {
1977  Reference< chart::XStatisticDisplay > xStockPropProvider( xDiagram, uno::UNO_QUERY );
1978  if( xStockPropProvider.is())
1979  {
1980  // stock-gain-marker
1981  Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getUpBar();
1982  if( xStockPropSet.is())
1983  {
1984  aPropertyStates.clear();
1985  aPropertyStates = mxExpPropMapper->Filter( xStockPropSet );
1986 
1987  if( !aPropertyStates.empty() )
1988  {
1989  if( bExportContent )
1990  {
1991  AddAutoStyleAttribute( aPropertyStates );
1992 
1994  }
1995  else
1996  {
1997  CollectAutoStyle( aPropertyStates );
1998  }
1999  }
2000  }
2001 
2002  // stock-loss-marker
2003  xStockPropSet = xStockPropProvider->getDownBar();
2004  if( xStockPropSet.is())
2005  {
2006  aPropertyStates.clear();
2007  aPropertyStates = mxExpPropMapper->Filter( xStockPropSet );
2008 
2009  if( !aPropertyStates.empty() )
2010  {
2011  if( bExportContent )
2012  {
2013  AddAutoStyleAttribute( aPropertyStates );
2014 
2016  }
2017  else
2018  {
2019  CollectAutoStyle( aPropertyStates );
2020  }
2021  }
2022  }
2023 
2024  // stock-range-line
2025  xStockPropSet = xStockPropProvider->getMinMaxLine();
2026  if( xStockPropSet.is())
2027  {
2028  aPropertyStates.clear();
2029  aPropertyStates = mxExpPropMapper->Filter( xStockPropSet );
2030 
2031  if( !aPropertyStates.empty() )
2032  {
2033  if( bExportContent )
2034  {
2035  AddAutoStyleAttribute( aPropertyStates );
2036 
2038  }
2039  else
2040  {
2041  CollectAutoStyle( aPropertyStates );
2042  }
2043  }
2044  }
2045  }
2046  }
2047 
2048  // wall and floor element
2049  Reference< chart::X3DDisplay > xWallFloorSupplier( xDiagram, uno::UNO_QUERY );
2050  if( mxExpPropMapper.is() &&
2051  xWallFloorSupplier.is())
2052  {
2053  // remove property states for autostyles
2054  aPropertyStates.clear();
2055 
2056  Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall();
2057  if( xWallPropSet.is())
2058  {
2059  aPropertyStates = mxExpPropMapper->Filter( xWallPropSet );
2060 
2061  if( !aPropertyStates.empty() )
2062  {
2063  // write element
2064  if( bExportContent )
2065  {
2066  // add style name attribute
2067  AddAutoStyleAttribute( aPropertyStates );
2068 
2070  }
2071  else // autostyles
2072  {
2073  CollectAutoStyle( aPropertyStates );
2074  }
2075  }
2076  }
2077 
2078  // floor element
2079  // remove property states for autostyles
2080  aPropertyStates.clear();
2081 
2082  Reference< beans::XPropertySet > xFloorPropSet = xWallFloorSupplier->getFloor();
2083  if( xFloorPropSet.is())
2084  {
2085  aPropertyStates = mxExpPropMapper->Filter( xFloorPropSet );
2086 
2087  if( !aPropertyStates.empty() )
2088  {
2089  // write element
2090  if( bExportContent )
2091  {
2092  // add style name attribute
2093  AddAutoStyleAttribute( aPropertyStates );
2094 
2095  SvXMLElementExport aFloor( mrExport, XML_NAMESPACE_CHART, XML_FLOOR, true, true );
2096  }
2097  else // autostyles
2098  {
2099  CollectAutoStyle( aPropertyStates );
2100  }
2101  }
2102  }
2103  }
2104 }
2105 
2106 void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference< chart::XDiagram >& xDiagram )
2107 {
2108  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2109  if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
2110  return;
2111 
2112  Reference< chart::XDiagramPositioning > xDiaPos( xDiagram, uno::UNO_QUERY );
2113  SAL_WARN_IF( !xDiaPos.is(), "xmloff.chart", "Invalid xDiaPos as parameter" );
2114  if( !xDiaPos.is() )
2115  return;
2116 
2117  awt::Rectangle aRect( xDiaPos->calculateDiagramPositionExcludingAxes() );
2118  addPosition( awt::Point(aRect.X,aRect.Y) );
2119  addSize( awt::Size(aRect.Width,aRect.Height) );
2120 
2121  SvXMLElementExport aCoordinateRegion( mrExport, XML_NAMESPACE_CHART_EXT, XML_COORDINATE_REGION, true, true );//#i100778# todo: change to chart namespace in future - dependent on fileformat
2122 }
2123 
2124 namespace
2125 {
2126  XMLTokenEnum lcl_getTimeUnitToken( sal_Int32 nTimeUnit )
2127  {
2129  switch( nTimeUnit )
2130  {
2131  case css::chart::TimeUnit::YEAR:
2132  eToken = XML_YEARS;
2133  break;
2134  case css::chart::TimeUnit::MONTH:
2135  eToken = XML_MONTHS;
2136  break;
2137  default://days
2138  break;
2139  }
2140  return eToken;
2141  }
2142 }
2143 
2145 {
2146  if( !rAxisProps.is() )
2147  return;
2148 
2149  chart::TimeIncrement aIncrement;
2150  if( rAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement )
2151  {
2152  sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY;
2153  if( aIncrement.TimeResolution >>= nTimeResolution )
2154  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, lcl_getTimeUnitToken( nTimeResolution ) );
2155 
2156  chart::TimeInterval aInterval;
2157  if( aIncrement.MajorTimeInterval >>= aInterval )
2158  {
2159  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, OUString::number(aInterval.Number) );
2160  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) );
2161  }
2162  if( aIncrement.MinorTimeInterval >>= aInterval )
2163  {
2164  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, OUString::number(aInterval.Number) );
2165  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) );
2166  }
2167 
2168  SvXMLElementExport aDateScale( mrExport, XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, true, true );//#i25706#todo: change namespace for next ODF version
2169  }
2170 }
2171 
2173 {
2174  if( !rTitleProps.is() )
2175  return;
2176  std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( rTitleProps );
2177  if( bExportContent )
2178  {
2179  OUString aText;
2180  Any aAny( rTitleProps->getPropertyValue( "String" ));
2181  aAny >>= aText;
2182 
2183  Reference< drawing::XShape > xShape( rTitleProps, uno::UNO_QUERY );
2184  if( xShape.is())
2185  addPosition( xShape );
2186 
2187  AddAutoStyleAttribute( aPropertyStates );
2188  SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true );
2189 
2190  // paragraph containing title
2191  exportText( aText );
2192  }
2193  else
2194  {
2195  CollectAutoStyle( aPropertyStates );
2196  }
2197  aPropertyStates.clear();
2198 }
2199 
2200 void SchXMLExportHelper_Impl::exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent )
2201 {
2202  if( !rGridProperties.is() )
2203  return;
2204  std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( rGridProperties );
2205  if( bExportContent )
2206  {
2207  AddAutoStyleAttribute( aPropertyStates );
2210  }
2211  else
2212  {
2213  CollectAutoStyle( aPropertyStates );
2214  }
2215  aPropertyStates.clear();
2216 }
2217 
2218 namespace
2219 {
2220 
2221 //returns true if a date scale needs to be exported
2222 bool lcl_exportAxisType( const Reference< chart2::XAxis >& rChart2Axis, SvXMLExport& rExport)
2223 {
2224  bool bExportDateScale = false;
2225  if( !rChart2Axis.is() )
2226  return bExportDateScale;
2227 
2228  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2229  if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
2230  return bExportDateScale;
2231 
2232  chart2::ScaleData aScale( rChart2Axis->getScaleData() );
2233  //#i25706#todo: change namespace for next ODF version
2234  sal_uInt16 nNameSpace = XML_NAMESPACE_CHART_EXT;
2235 
2236  switch(aScale.AxisType)
2237  {
2238  case chart2::AxisType::CATEGORY:
2239  if( aScale.AutoDateAxis )
2240  {
2241  rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO );
2242  bExportDateScale = true;
2243  }
2244  else
2245  rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_TEXT );
2246  break;
2247  case chart2::AxisType::DATE:
2248  rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_DATE );
2249  bExportDateScale = true;
2250  break;
2251  default: //AUTOMATIC
2252  rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO );
2253  break;
2254  }
2255 
2256  return bExportDateScale;
2257 }
2258 
2259 void disableLinkedNumberFormat(
2260  std::vector<XMLPropertyState>& rPropStates, const rtl::Reference<XMLPropertySetMapper>& rMapper )
2261 {
2262  for (XMLPropertyState & rState : rPropStates)
2263  {
2264  if (rState.mnIndex < 0 || rMapper->GetEntryCount() <= rState.mnIndex)
2265  continue;
2266 
2267  OUString aXMLName = rMapper->GetEntryXMLName(rState.mnIndex);
2268 
2269  if (aXMLName != "link-data-style-to-source")
2270  continue;
2271 
2272  // Entry found. Set the value to false and bail out.
2273  rState.maValue <<= false;
2274  return;
2275  }
2276 
2277  // Entry not found. Insert a new entry for this.
2278  sal_Int32 nIndex = rMapper->GetEntryIndex(XML_NAMESPACE_CHART, "link-data-style-to-source", 0);
2279  XMLPropertyState aState(nIndex);
2280  aState.maValue <<= false;
2281  rPropStates.push_back(aState);
2282 }
2283 
2284 }
2285 
2287  enum XMLTokenEnum eDimension,
2288  enum XMLTokenEnum eAxisName,
2289  const Reference< beans::XPropertySet >& rAxisProps,
2290  const Reference< chart2::XAxis >& rChart2Axis,
2291  const OUString& rCategoriesRange,
2292  bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid,
2293  bool bExportContent, OUString sChartType )
2294 {
2295  std::vector< XMLPropertyState > aPropertyStates;
2296  std::unique_ptr<SvXMLElementExport> pAxis;
2297 
2298  // get property states for autostyles
2299  if( rAxisProps.is() && mxExpPropMapper.is() )
2300  {
2301  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2302  if (nCurrentODFVersion > SvtSaveOptions::ODFSVER_012 && eDimension == XML_X)
2303  {
2304  chart2::ScaleData aScaleData(rChart2Axis->getScaleData());
2305  bool bShiftedCatPos = aScaleData.ShiftedCategoryPosition;
2306  if (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram")
2307  {
2308  if (!bShiftedCatPos)
2309  rAxisProps->setPropertyValue("MajorOrigin", uno::makeAny(0.0));
2310  }
2311  else if (bShiftedCatPos)
2312  rAxisProps->setPropertyValue("MajorOrigin", uno::makeAny(0.5));
2313  }
2314 
2315  lcl_exportNumberFormat( "NumberFormat", rAxisProps, mrExport );
2316  aPropertyStates = mxExpPropMapper->Filter( rAxisProps );
2317 
2318  if (!maSrcShellID.isEmpty() && !maDestShellID.isEmpty() && maSrcShellID != maDestShellID)
2319  {
2320  // Disable link to source number format property when pasting to
2321  // a different doc shell. These shell ID's should be both empty
2322  // during real ODF export.
2323  disableLinkedNumberFormat(aPropertyStates, mxExpPropMapper->getPropertySetMapper());
2324  }
2325  }
2326 
2327  bool bExportDateScale = false;
2328  if( bExportContent )
2329  {
2332  AddAutoStyleAttribute( aPropertyStates ); // write style name
2333  if( !rCategoriesRange.isEmpty() )
2334  bExportDateScale = lcl_exportAxisType( rChart2Axis, mrExport );
2335 
2336  // open axis element
2337  pAxis.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, true, true ));
2338  }
2339  else
2340  {
2341  CollectAutoStyle( aPropertyStates );
2342  }
2343  aPropertyStates.clear();
2344 
2345  //date scale
2346  if( bExportDateScale )
2347  exportDateScale( rAxisProps );
2348 
2350  Reference< beans::XPropertySet > xMajorGridProps;
2351  Reference< beans::XPropertySet > xMinorGridProps;
2352  Reference< chart::XAxis > xAxis( rAxisProps, uno::UNO_QUERY );
2353  if( xAxis.is() )
2354  {
2355  xTitleProps = bHasTitle ? xAxis->getAxisTitle() : nullptr;
2356  xMajorGridProps = bHasMajorGrid ? xAxis->getMajorGrid() : nullptr;
2357  xMinorGridProps = bHasMinorGrid ? xAxis->getMinorGrid() : nullptr;
2358  }
2359 
2360  // axis-title
2361  exportAxisTitle( xTitleProps , bExportContent );
2362 
2363  // categories if we have a categories chart
2364  if( bExportContent && !rCategoriesRange.isEmpty() )
2365  {
2367  SvXMLElementExport aCategories( mrExport, XML_NAMESPACE_CHART, XML_CATEGORIES, true, true );
2368  }
2369 
2370  // grid
2371  exportGrid( xMajorGridProps, true, bExportContent );
2372  exportGrid( xMinorGridProps, false, bExportContent );
2373 }
2374 
2376  const Reference< chart::XDiagram > & xDiagram,
2377  const Reference< chart2::XDiagram > & xNewDiagram,
2378  bool bExportContent )
2379 {
2380  SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" );
2381  if( ! xDiagram.is())
2382  return;
2383 
2384  // get some properties from document first
2385  bool bHasXAxis = false,
2386  bHasYAxis = false,
2387  bHasZAxis = false,
2388  bHasSecondaryXAxis = false,
2389  bHasSecondaryYAxis = false;
2390  bool bHasXAxisTitle = false,
2391  bHasYAxisTitle = false,
2392  bHasZAxisTitle = false,
2393  bHasSecondaryXAxisTitle = false,
2394  bHasSecondaryYAxisTitle = false;
2395  bool bHasXAxisMajorGrid = false,
2396  bHasXAxisMinorGrid = false,
2397  bHasYAxisMajorGrid = false,
2398  bHasYAxisMinorGrid = false,
2399  bHasZAxisMajorGrid = false,
2400  bHasZAxisMinorGrid = false;
2401 
2402  // get multiple properties using XMultiPropertySet
2403  MultiPropertySetHandler aDiagramProperties (xDiagram);
2404 
2405  aDiagramProperties.Add ("HasXAxis", bHasXAxis);
2406  aDiagramProperties.Add ("HasYAxis", bHasYAxis);
2407  aDiagramProperties.Add ("HasZAxis", bHasZAxis);
2408  aDiagramProperties.Add ("HasSecondaryXAxis", bHasSecondaryXAxis);
2409  aDiagramProperties.Add ("HasSecondaryYAxis", bHasSecondaryYAxis);
2410 
2411  aDiagramProperties.Add ("HasXAxisTitle", bHasXAxisTitle);
2412  aDiagramProperties.Add ("HasYAxisTitle", bHasYAxisTitle);
2413  aDiagramProperties.Add ("HasZAxisTitle", bHasZAxisTitle);
2414  aDiagramProperties.Add ("HasSecondaryXAxisTitle", bHasSecondaryXAxisTitle);
2415  aDiagramProperties.Add ("HasSecondaryYAxisTitle", bHasSecondaryYAxisTitle);
2416 
2417  aDiagramProperties.Add ("HasXAxisGrid", bHasXAxisMajorGrid);
2418  aDiagramProperties.Add ("HasYAxisGrid", bHasYAxisMajorGrid);
2419  aDiagramProperties.Add ("HasZAxisGrid", bHasZAxisMajorGrid);
2420 
2421  aDiagramProperties.Add ("HasXAxisHelpGrid", bHasXAxisMinorGrid);
2422  aDiagramProperties.Add ("HasYAxisHelpGrid", bHasYAxisMinorGrid);
2423  aDiagramProperties.Add ("HasZAxisHelpGrid", bHasZAxisMinorGrid);
2424 
2425  if ( ! aDiagramProperties.GetProperties ())
2426  {
2427  SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram");
2428  }
2429 
2430  Reference< chart2::XCoordinateSystem > xCooSys( lcl_getCooSys(xNewDiagram) );
2431 
2432  // write an axis element also if the axis itself is not visible, but a grid or a title
2433 
2434  OUString aCategoriesRange;
2435  Reference< chart::XAxisSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY );
2436  OUString sChartType = xDiagram->getDiagramType();
2437 
2438  // x axis
2439 
2440  Reference< css::chart2::XAxis > xNewAxis = lcl_getAxis( xCooSys, XML_X );
2441  if( xNewAxis.is() )
2442  {
2443  Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(0) : nullptr, uno::UNO_QUERY );
2444  if( mbHasCategoryLabels && bExportContent )
2445  {
2446  Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) );
2447  if( xCategories.is() )
2448  {
2449  Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() );
2450  if( xValues.is() )
2451  {
2452  Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2453  maCategoriesRange = xValues->getSourceRangeRepresentation();
2454  aCategoriesRange = lcl_ConvertRange( maCategoriesRange, xNewDoc );
2455  }
2456  }
2457  }
2458  exportAxis( XML_X, XML_PRIMARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasXAxisTitle, bHasXAxisMajorGrid, bHasXAxisMinorGrid, bExportContent, sChartType );
2459  aCategoriesRange.clear();
2460  }
2461 
2462  // secondary x axis
2463 
2464  xNewAxis = lcl_getAxis( xCooSys, XML_X, false );
2465  if( xNewAxis.is() )
2466  {
2467  Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY );
2468  exportAxis( XML_X, XML_SECONDARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryXAxisTitle, false, false, bExportContent, sChartType );
2469  }
2470 
2471  // y axis
2472 
2473  xNewAxis = lcl_getAxis( xCooSys, XML_Y );
2474  if( xNewAxis.is() )
2475  {
2476  Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(1) : nullptr, uno::UNO_QUERY );
2477  exportAxis( XML_Y, XML_PRIMARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasYAxisTitle, bHasYAxisMajorGrid, bHasYAxisMinorGrid, bExportContent, sChartType );
2478  }
2479 
2480  // secondary y axis
2481 
2482  xNewAxis = lcl_getAxis( xCooSys, XML_Y, false );
2483  if( xNewAxis.is() )
2484  {
2485  Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY );
2486  exportAxis( XML_Y, XML_SECONDARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryYAxisTitle, false, false, bExportContent, sChartType );
2487  }
2488 
2489  // z axis
2490 
2491  xNewAxis = lcl_getAxis( xCooSys, XML_Z );
2492  if( xNewAxis.is() )
2493  {
2494  Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(2) : nullptr, uno::UNO_QUERY );
2495  exportAxis( XML_Z, XML_PRIMARY_Z, xAxisProps, xNewAxis, aCategoriesRange, bHasZAxisTitle, bHasZAxisMajorGrid, bHasZAxisMinorGrid, bExportContent, sChartType );
2496  }
2497 }
2498 
2499 namespace
2500 {
2501  bool lcl_hasNoValuesButText( const uno::Reference< chart2::data::XDataSequence >& xDataSequence )
2502  {
2503  if( !xDataSequence.is() )
2504  return false;//have no data
2505 
2506  Sequence< uno::Any > aData;
2507  Reference< chart2::data::XNumericalDataSequence > xNumericalDataSequence( xDataSequence, uno::UNO_QUERY );
2508  if( xNumericalDataSequence.is() )
2509  {
2510  Sequence< double > aDoubles( xNumericalDataSequence->getNumericalData() );
2511  if (std::any_of(aDoubles.begin(), aDoubles.end(), [](double fDouble) { return !std::isnan( fDouble ); }))
2512  return false;//have double value
2513  }
2514  else
2515  {
2516  aData = xDataSequence->getData();
2517  double fDouble = 0.0;
2518  bool bHaveDouble = std::any_of(aData.begin(), aData.end(),
2519  [&fDouble](const uno::Any& rData) { return (rData >>= fDouble) && !std::isnan( fDouble ); });
2520  if (bHaveDouble)
2521  return false;//have double value
2522  }
2523  //no values found
2524 
2525  Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY );
2526  if( xTextualDataSequence.is() )
2527  {
2528  uno::Sequence< OUString > aStrings( xTextualDataSequence->getTextualData() );
2529  if (std::any_of(aStrings.begin(), aStrings.end(), [](const OUString& rString) { return !rString.isEmpty(); }))
2530  return true;//have text
2531  }
2532  else
2533  {
2534  if( !aData.hasElements() )
2535  aData = xDataSequence->getData();
2536  OUString aString;
2537  bool bHaveText = std::any_of(aData.begin(), aData.end(),
2538  [&aString](const uno::Any& rData) { return (rData >>= aString) && !aString.isEmpty(); });
2539  if (bHaveText)
2540  return true;//have text
2541  }
2542  //no doubles and no texts
2543  return false;
2544  }
2545 }
2546 
2548  const Reference< chart2::XDiagram > & xNewDiagram,
2549  const awt::Size & rPageSize,
2550  bool bExportContent,
2551  bool bHasTwoYAxes )
2552 {
2553  Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY );
2554  if( ! xBCooSysCnt.is())
2555  return;
2556  Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2557 
2558  OUString aFirstXDomainRange;
2559  OUString aFirstYDomainRange;
2560 
2561  std::vector< XMLPropertyState > aPropertyStates;
2562 
2563  const Sequence< Reference< chart2::XCoordinateSystem > >
2564  aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
2565  for( const auto& rCooSys : aCooSysSeq )
2566  {
2567  Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY );
2568  if( ! xCTCnt.is())
2569  continue;
2570  const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
2571  for( const auto& rChartType : aCTSeq )
2572  {
2573  Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY );
2574  if( ! xDSCnt.is())
2575  continue;
2576  // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
2577  OUString aChartType( rChartType->getChartType());
2578  OUString aLabelRole = rChartType->getRoleOfSequenceForSeriesLabel();
2579 
2580  // special export for stock charts
2581  if ( aChartType == "com.sun.star.chart2.CandleStickChartType" )
2582  {
2583  bool bJapaneseCandleSticks = false;
2584  Reference< beans::XPropertySet > xCTProp( rChartType, uno::UNO_QUERY );
2585  if( xCTProp.is())
2586  xCTProp->getPropertyValue("Japanese") >>= bJapaneseCandleSticks;
2588  xDSCnt->getDataSeries(), xNewDiagram, bJapaneseCandleSticks, bExportContent );
2589  continue;
2590  }
2591 
2592  // export dataseries for current chart-type
2593  Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
2594  for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx )
2595  {
2596  // export series
2597  Reference< chart2::data::XDataSource > xSource( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY );
2598  if( xSource.is())
2599  {
2600  std::unique_ptr<SvXMLElementExport> pSeries;
2601  Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
2602  xSource->getDataSequences());
2603  sal_Int32 nMainSequenceIndex = -1;
2604  sal_Int32 nSeriesLength = 0;
2605  sal_Int32 nAttachedAxis = chart::ChartAxisAssign::PRIMARY_Y;
2606  bool bHasMeanValueLine = false;
2608  tLabelValuesDataPair aSeriesLabelValuesPair;
2609 
2610  // search for main sequence and create a series element
2611  {
2612  Reference< chart2::data::XDataSequence > xValuesSeq;
2613  Reference< chart2::data::XDataSequence > xLabelSeq;
2614  sal_Int32 nSeqIdx=0;
2615  for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2616  {
2617  OUString aRole;
2618  Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2619  if( nMainSequenceIndex==-1 )
2620  {
2621  Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2622  if( xSeqProp.is())
2623  xSeqProp->getPropertyValue("Role") >>= aRole;
2624  // "main" sequence
2625  if( aRole == aLabelRole )
2626  {
2627  xValuesSeq.set( xTempValueSeq );
2628  xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2629  nMainSequenceIndex = nSeqIdx;
2630  }
2631  }
2632  sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2633  if( nSeriesLength < nSequenceLength )
2634  nSeriesLength = nSequenceLength;
2635  }
2636 
2637  // have found the main sequence, then xValuesSeq and
2638  // xLabelSeq contain those. Otherwise both are empty
2639  {
2640  // get property states for autostyles
2641  try
2642  {
2644  aSeriesSeq[nSeriesIdx], mrExport.GetModel() );
2645  }
2646  catch( const uno::Exception & )
2647  {
2648  TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" );
2649  continue;
2650  }
2651  if( xPropSet.is())
2652  {
2653  // determine attached axis
2654  try
2655  {
2656  Any aAny( xPropSet->getPropertyValue( "Axis" ));
2657  aAny >>= nAttachedAxis;
2658 
2659  aAny = xPropSet->getPropertyValue( "MeanValue" );
2660  aAny >>= bHasMeanValueLine;
2661  }
2662  catch( const beans::UnknownPropertyException & )
2663  {
2664  TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
2665  }
2666 
2667  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2668  if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
2669  {
2670  lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport );
2671  lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport );
2672  }
2673 
2674  if( mxExpPropMapper.is())
2675  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
2676  }
2677 
2678  if( bExportContent )
2679  {
2680  if( bHasTwoYAxes )
2681  {
2682  if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
2684  else
2686  }
2687 
2688  // write style name
2689  AddAutoStyleAttribute( aPropertyStates );
2690 
2691  if( xValuesSeq.is())
2693  lcl_ConvertRange(
2694  xValuesSeq->getSourceRangeRepresentation(),
2695  xNewDoc ));
2696  else
2697  // #i75297# allow empty series, export empty range to have all ranges on import
2699 
2700  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2701  if (nCurrentODFVersion > SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
2702  {
2703  if (xPropSet.is())
2704  {
2705  Any aAny = xPropSet->getPropertyValue("ShowLegendEntry");
2706  if (!aAny.get<bool>())
2707  {
2708  mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
2709  }
2710  }
2711  }
2712 
2713  if (xLabelSeq.is())
2714  {
2715  // Check if the label is direct string value rather than a reference.
2716  bool bHasString = false;
2717  uno::Reference<beans::XPropertySet> xLSProp(xLabelSeq, uno::UNO_QUERY);
2718  if (xLSProp.is())
2719  {
2720  try
2721  {
2722  xLSProp->getPropertyValue("HasStringLabel") >>= bHasString;
2723  }
2724  catch (const beans::UnknownPropertyException&) {}
2725  }
2726 
2727  OUString aRange = xLabelSeq->getSourceRangeRepresentation();
2728 
2729  if (bHasString)
2730  {
2733  }
2734  else
2735  {
2738  lcl_ConvertRange(
2739  xLabelSeq->getSourceRangeRepresentation(), xNewDoc));
2740  }
2741  }
2742 
2743  if( xLabelSeq.is() || xValuesSeq.is() )
2744  aSeriesLabelValuesPair = tLabelValuesDataPair( xLabelSeq, xValuesSeq );
2745 
2746  // chart-type for mixed types
2747  enum XMLTokenEnum eCTToken(
2748  SchXMLTools::getTokenByChartType( aChartType, false /* bUseOldNames */ ));
2749  //@todo: get token for current charttype
2752  XML_NAMESPACE_CHART, GetXMLToken( eCTToken )));
2753 
2754  // open series element until end of for loop
2755  pSeries.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ));
2756  }
2757  else // autostyles
2758  {
2759  CollectAutoStyle( aPropertyStates );
2760  }
2761  // remove property states for autostyles
2762  aPropertyStates.clear();
2763  }
2764  }
2765 
2766  // export domain elements if we have a series parent element
2767  if( pSeries )
2768  {
2769  // domain elements
2770  if( bExportContent )
2771  {
2772  bool bIsScatterChart = aChartType == "com.sun.star.chart2.ScatterChartType";
2773  bool bIsBubbleChart = aChartType == "com.sun.star.chart2.BubbleChartType";
2774  Reference< chart2::data::XDataSequence > xYValuesForBubbleChart;
2775  if( bIsBubbleChart )
2776  {
2777  Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-y" ) );
2778  if( xSequence.is() )
2779  {
2780  xYValuesForBubbleChart = xSequence->getValues();
2781  if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart, aFirstYDomainRange, mrExport ) )
2782  xYValuesForBubbleChart = nullptr;
2783  }
2784  }
2785  if( bIsScatterChart || bIsBubbleChart )
2786  {
2787  Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-x" ) );
2788  if( xSequence.is() )
2789  {
2790  Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2791  if( lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ) )
2792  m_aDataSequencesToExport.emplace_back(
2793  uno::Reference< chart2::data::XDataSequence >(), xValues );
2794  }
2795  else if( nSeriesIdx==0 )
2796  {
2797  //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly
2798  Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) );
2799  if( xCategories.is() )
2800  {
2801  Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() );
2802  if( !lcl_hasNoValuesButText( xValues ) )
2803  lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport );
2804  }
2805  }
2806  }
2807  if( xYValuesForBubbleChart.is() )
2808  m_aDataSequencesToExport.emplace_back(
2809  uno::Reference< chart2::data::XDataSequence >(), xYValuesForBubbleChart );
2810  }
2811  }
2812 
2813  // add sequences for main sequence after domain sequences,
2814  // so that the export of the local table has the correct order
2815  if( bExportContent &&
2816  (aSeriesLabelValuesPair.first.is() || aSeriesLabelValuesPair.second.is()))
2817  m_aDataSequencesToExport.push_back( aSeriesLabelValuesPair );
2818 
2819  // statistical objects:
2820  // regression curves and mean value lines
2821  if( bHasMeanValueLine &&
2822  xPropSet.is() &&
2823  mxExpPropMapper.is() )
2824  {
2826  try
2827  {
2828  Any aPropAny( xPropSet->getPropertyValue( "DataMeanValueProperties" ));
2829  aPropAny >>= xStatProp;
2830  }
2831  catch( const uno::Exception & )
2832  {
2833  TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" );
2834  }
2835 
2836  if( xStatProp.is() )
2837  {
2838  aPropertyStates = mxExpPropMapper->Filter( xStatProp );
2839 
2840  if( !aPropertyStates.empty() )
2841  {
2842  // write element
2843  if( bExportContent )
2844  {
2845  // add style name attribute
2846  AddAutoStyleAttribute( aPropertyStates );
2847 
2849  }
2850  else // autostyles
2851  {
2852  CollectAutoStyle( aPropertyStates );
2853  }
2854  }
2855  }
2856  }
2857 
2858  if( xPropSet.is() &&
2859  mxExpPropMapper.is() )
2860  {
2861  exportRegressionCurve( aSeriesSeq[nSeriesIdx], rPageSize, bExportContent );
2862  }
2863 
2864  exportErrorBar( xPropSet,false, bExportContent ); // X ErrorBar
2865  exportErrorBar( xPropSet,true, bExportContent ); // Y ErrorBar
2866 
2868  uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ),
2869  nSeriesLength, xNewDiagram, bExportContent );
2870 
2871  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2872  if (bExportContent && nCurrentODFVersion > SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
2873  {
2874  Sequence< OUString > aSupportedMappings = rChartType->getSupportedPropertyRoles();
2875  exportPropertyMapping( xSource, aSupportedMappings );
2876  }
2877 
2878  // close series element
2879  pSeries.reset();
2880  }
2881  }
2882  aPropertyStates.clear();
2883  }
2884  }
2885 }
2886 
2888  const Reference< chart2::data::XDataSource > & xSource, const Sequence< OUString >& rSupportedMappings )
2889 {
2890  Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
2891  Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
2892  xSource->getDataSequences());
2893 
2894  for(const auto& rSupportedMapping : rSupportedMappings)
2895  {
2896  Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, rSupportedMapping ) );
2897  if(xSequence.is())
2898  {
2899  Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2900  if( xValues.is())
2901  {
2904  lcl_ConvertRange(
2905  xValues->getSourceRangeRepresentation(),
2906  xNewDoc ));
2908 
2909  // register range for data table export
2910  m_aDataSequencesToExport.emplace_back(
2911  uno::Reference< chart2::data::XDataSequence >(), xValues );
2912  }
2913  }
2914  }
2915 }
2916 
2918  const Reference< chart2::XDataSeries >& xSeries,
2919  const awt::Size& rPageSize,
2920  bool bExportContent )
2921 {
2922  OSL_ASSERT( mxExpPropMapper.is());
2923 
2924  Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, uno::UNO_QUERY );
2925  if( xRegressionCurveContainer.is() )
2926  {
2927  const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
2928 
2929  for( const auto& xRegCurve : aRegCurveSeq )
2930  {
2931  std::vector< XMLPropertyState > aEquationPropertyStates;
2932  if (!xRegCurve.is())
2933  continue;
2934 
2935  Reference< beans::XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
2936  if( !xProperties.is() )
2937  continue;
2938 
2939  Reference< lang::XServiceName > xServiceName( xProperties, uno::UNO_QUERY );
2940  if( !xServiceName.is() )
2941  continue;
2942 
2943  bool bShowEquation = false;
2944  bool bShowRSquared = false;
2945  bool bExportEquation = false;
2946 
2947  OUString aService = xServiceName->getServiceName();
2948 
2949  std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( xProperties );
2950 
2951  // Add service name (which is regression type)
2952  sal_Int32 nIndex = GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE);
2953  XMLPropertyState property(nIndex, uno::makeAny(aService));
2954  aPropertyStates.push_back(property);
2955 
2956  Reference< beans::XPropertySet > xEquationProperties;
2957  xEquationProperties.set( xRegCurve->getEquationProperties() );
2958  if( xEquationProperties.is())
2959  {
2960  xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation;
2961  xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowRSquared;
2962 
2963  bExportEquation = ( bShowEquation || bShowRSquared );
2964  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
2965  if (nCurrentVersion < SvtSaveOptions::ODFSVER_012)
2966  {
2967  bExportEquation=false;
2968  }
2969  if( bExportEquation )
2970  {
2971  // number format
2972  sal_Int32 nNumberFormat = 0;
2973  if( (xEquationProperties->getPropertyValue("NumberFormat") >>= nNumberFormat ) &&
2974  nNumberFormat != -1 )
2975  {
2976  mrExport.addDataStyle( nNumberFormat );
2977  }
2978  aEquationPropertyStates = mxExpPropMapper->Filter( xEquationProperties );
2979  }
2980  }
2981 
2982  if( !aPropertyStates.empty() || bExportEquation )
2983  {
2984  // write element
2985  if( bExportContent )
2986  {
2987  // add style name attribute
2988  if( !aPropertyStates.empty())
2989  {
2990  AddAutoStyleAttribute( aPropertyStates );
2991  }
2992 
2993  SvXMLElementExport aRegressionExport( mrExport, XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, true, true );
2994  if( bExportEquation )
2995  {
2997  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, (bShowRSquared ? XML_TRUE : XML_FALSE) );
2998 
2999  // export position
3000  chart2::RelativePosition aRelativePosition;
3001  if( xEquationProperties->getPropertyValue( "RelativePosition" ) >>= aRelativePosition )
3002  {
3003  double fX = aRelativePosition.Primary * rPageSize.Width;
3004  double fY = aRelativePosition.Secondary * rPageSize.Height;
3005  awt::Point aPos;
3006  aPos.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
3007  aPos.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
3008  addPosition( aPos );
3009  }
3010 
3011  if( !aEquationPropertyStates.empty())
3012  {
3013  AddAutoStyleAttribute( aEquationPropertyStates );
3014  }
3015 
3017  }
3018  }
3019  else // autostyles
3020  {
3021  if( !aPropertyStates.empty())
3022  {
3023  CollectAutoStyle( aPropertyStates );
3024  }
3025  if( bExportEquation && !aEquationPropertyStates.empty())
3026  {
3027  CollectAutoStyle( aEquationPropertyStates );
3028  }
3029  }
3030  }
3031  }
3032  }
3033 }
3034 
3036  bool bYError, bool bExportContent )
3037 {
3038  assert(mxExpPropMapper.is());
3039 
3040  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
3041 
3043  if (!bYError && nCurrentVersion < SvtSaveOptions::ODFSVER_012)
3044  return;
3045 
3046  if (xSeriesProp.is())
3047  {
3048  bool bNegative = false, bPositive = false;
3049  sal_Int32 nErrorBarStyle = chart::ErrorBarStyle::NONE;
3050  Reference< beans::XPropertySet > xErrorBarProp;
3051 
3052  try
3053  {
3054  Any aAny = xSeriesProp->getPropertyValue( bYError ? OUString("ErrorBarY") : OUString("ErrorBarX") );
3055  aAny >>= xErrorBarProp;
3056 
3057  if ( xErrorBarProp.is() )
3058  {
3059  aAny = xErrorBarProp->getPropertyValue("ShowNegativeError" );
3060  aAny >>= bNegative;
3061 
3062  aAny = xErrorBarProp->getPropertyValue("ShowPositiveError" );
3063  aAny >>= bPositive;
3064 
3065  aAny = xErrorBarProp->getPropertyValue("ErrorBarStyle" );
3066  aAny >>= nErrorBarStyle;
3067  }
3068  }
3069  catch( const beans::UnknownPropertyException & )
3070  {
3071  TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" );
3072  }
3073 
3074  if( nErrorBarStyle != chart::ErrorBarStyle::NONE && (bNegative || bPositive))
3075  {
3076  if( bExportContent && nErrorBarStyle == chart::ErrorBarStyle::FROM_DATA )
3077  {
3078  // register data ranges for error bars for export in local table
3079  ::std::vector< Reference< chart2::data::XDataSequence > > aErrorBarSequences(
3080  lcl_getErrorBarSequences( xErrorBarProp ));
3081  for( const auto& rErrorBarSequence : aErrorBarSequences )
3082  {
3083  m_aDataSequencesToExport.emplace_back(
3084  uno::Reference< chart2::data::XDataSequence >(), rErrorBarSequence );
3085  }
3086  }
3087 
3088  std::vector< XMLPropertyState > aPropertyStates = mxExpPropMapper->Filter( xErrorBarProp );
3089 
3090  if( !aPropertyStates.empty() )
3091  {
3092  // write element
3093  if( bExportContent )
3094  {
3095  // add style name attribute
3096  AddAutoStyleAttribute( aPropertyStates );
3097 
3098  if (nCurrentVersion >= SvtSaveOptions::ODFSVER_012)
3099  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, bYError ? XML_Y : XML_X );//#i114149#
3101  }
3102  else // autostyles
3103  {
3104  CollectAutoStyle( aPropertyStates );
3105  }
3106  }
3107  }
3108  }
3109 }
3110 
3112  const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
3113  const Reference< chart2::XDiagram > & xDiagram,
3114  bool bJapaneseCandleSticks,
3115  bool bExportContent )
3116 {
3117 
3118  for( const auto& xSeries : aSeriesSeq )
3119  {
3120  sal_Int32 nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries )
3121  ? chart::ChartAxisAssign::PRIMARY_Y
3122  : chart::ChartAxisAssign::SECONDARY_Y;
3123 
3124  Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
3125  if( xSource.is())
3126  {
3127  // export series in correct order (as we don't store roles)
3128  // with japanese candlesticks: open, low, high, close
3129  // otherwise: low, high, close
3130  Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt(
3131  xSource->getDataSequences());
3132 
3133  sal_Int32 nSeriesLength =
3134  lcl_getSequenceLengthByRole( aSeqCnt, "values-last");
3135 
3136  if( bExportContent )
3137  {
3138  Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY );
3139  //@todo: export data points
3140 
3141  //TODO: moggi: same code three times
3142  // open
3143  if( bJapaneseCandleSticks )
3144  {
3145  tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3146  aSeqCnt, "values-first", xNewDoc, m_aDataSequencesToExport ));
3147  if( !aRanges.second.isEmpty())
3149  if( !aRanges.first.isEmpty())
3151  if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3153  else
3155  SvXMLElementExport aOpenSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3156  // export empty data points
3157  exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3158  }
3159 
3160  // low
3161  {
3162  tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3163  aSeqCnt, "values-min", xNewDoc, m_aDataSequencesToExport ));
3164  if( !aRanges.second.isEmpty())
3166  if( !aRanges.first.isEmpty())
3168  if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3170  else
3172  SvXMLElementExport aLowSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3173  // export empty data points
3174  exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3175  }
3176 
3177  // high
3178  {
3179  tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3180  aSeqCnt, "values-max", xNewDoc, m_aDataSequencesToExport ));
3181  if( !aRanges.second.isEmpty())
3183  if( !aRanges.first.isEmpty())
3185  if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3187  else
3189  SvXMLElementExport aHighSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3190  // export empty data points
3191  exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3192  }
3193 
3194  // close
3195  {
3196  tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole(
3197  aSeqCnt, "values-last", xNewDoc, m_aDataSequencesToExport ));
3198  if( !aRanges.second.isEmpty())
3200  if( !aRanges.first.isEmpty())
3202  if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y )
3204  else
3206  SvXMLElementExport aCloseSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true );
3207  // export empty data points
3208  exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent );
3209  }
3210  }
3211  else // autostyles
3212  {
3213  // for close series
3214  }
3215  // remove property states for autostyles
3216  }
3217  }
3218 }
3219 
3221  const uno::Reference< beans::XPropertySet > & xSeriesProperties,
3222  sal_Int32 nSeriesLength,
3223  const uno::Reference< chart2::XDiagram > & xDiagram,
3224  bool bExportContent )
3225 {
3226  // data-points
3227 
3228  // write data-points only if they contain autostyles
3229  // objects with equal autostyles are grouped using the attribute
3230  // repeat="number"
3231 
3232  // Note: if only the nth data-point has autostyles there is an element
3233  // without style and repeat="n-1" attribute written in advance.
3234 
3235  // the sequence aDataPointSeq contains indices of data-points that
3236  // do have own attributes. This increases the performance substantially.
3237 
3238  // more performant version for #93600#
3239  if (!mxExpPropMapper.is())
3240  return;
3241 
3242  uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
3243 
3244  std::vector< XMLPropertyState > aPropertyStates;
3245 
3246  bool bVaryColorsByPoint = false;
3247  Sequence< sal_Int32 > aDataPointSeq;
3248  Sequence<sal_Int32> deletedLegendEntriesSeq;
3249  if( xSeriesProperties.is())
3250  {
3251  xSeriesProperties->getPropertyValue("AttributedDataPoints") >>= aDataPointSeq;
3252  xSeriesProperties->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint;
3253 
3254  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
3255  if (nCurrentODFVersion > SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older
3256  xSeriesProperties->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq;
3257  }
3258 
3259  sal_Int32 nSize = aDataPointSeq.getLength();
3260  SAL_WARN_IF( nSize > nSeriesLength, "xmloff.chart", "Too many point attributes" );
3261 
3262  const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
3263  sal_Int32 nElement;
3264  sal_Int32 nRepeat;
3265  Reference< chart2::XColorScheme > xColorScheme;
3266  if( xDiagram.is())
3267  xColorScheme.set( xDiagram->getDefaultColorScheme());
3268 
3269  ::std::vector< SchXMLDataPointStruct > aDataPointVector;
3270 
3271  sal_Int32 nLastIndex = -1;
3272 
3273  // collect elements
3274  if( bVaryColorsByPoint && xColorScheme.is() )
3275  {
3276  ::std::set< sal_Int32 > aAttrPointSet;
3277  ::std::copy( pPoints, pPoints + aDataPointSeq.getLength(),
3278  ::std::inserter( aAttrPointSet, aAttrPointSet.begin()));
3279  const ::std::set< sal_Int32 >::const_iterator aEndIt( aAttrPointSet.end());
3280  for( nElement = 0; nElement < nSeriesLength; ++nElement )
3281  {
3282  aPropertyStates.clear();
3283  uno::Reference< beans::XPropertySet > xPropSet;
3284  bool bExportNumFmt = false;
3285  if( aAttrPointSet.find( nElement ) != aEndIt )
3286  {
3287  try
3288  {
3290  xSeries, nElement, mrExport.GetModel() );
3291  bExportNumFmt = true;
3292  }
3293  catch( const uno::Exception & )
3294  {
3295  TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3296  }
3297  }
3298  else
3299  {
3300  // property set only containing the color
3301  xPropSet.set( new ::xmloff::chart::ColorPropertySet(
3302  xColorScheme->getColorByIndex( nElement )));
3303  }
3304  SAL_WARN_IF( !xPropSet.is(), "xmloff.chart", "Pie Segments should have properties" );
3305  if( xPropSet.is())
3306  {
3307  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
3308  if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012 && bExportNumFmt)
3309  {
3310  lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport );
3311  lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport );
3312  }
3313 
3314  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
3315  if( !aPropertyStates.empty() )
3316  {
3317  if( bExportContent )
3318  {
3319  // write data-point with style
3320  SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3321 
3322  SchXMLDataPointStruct aPoint;
3323  aPoint.maStyleName = maAutoStyleNameQueue.front();
3324  if(bExportNumFmt)
3325  aPoint.mCustomLabelText = lcl_getCustomLabelField(nElement, xSeries);
3326  maAutoStyleNameQueue.pop();
3327  aDataPointVector.push_back( aPoint );
3328  }
3329  else
3330  {
3331  CollectAutoStyle( aPropertyStates );
3332  }
3333  }
3334  }
3335  }
3336  SAL_WARN_IF( bExportContent && (static_cast<sal_Int32>(aDataPointVector.size()) != nSeriesLength), "xmloff.chart", "not enough data points on content export" );
3337  }
3338  else
3339  {
3340  for( sal_Int32 nCurrIndex : aDataPointSeq )
3341  {
3342  aPropertyStates.clear();
3343  //assuming sorted indices in pPoints
3344 
3345  if( nCurrIndex<0 || nCurrIndex>=nSeriesLength )
3346  break;
3347 
3348  // write leading empty data points
3349  if( nCurrIndex - nLastIndex > 1 )
3350  {
3351  SchXMLDataPointStruct aPoint;
3352  aPoint.mnRepeat = nCurrIndex - nLastIndex - 1;
3353  aDataPointVector.push_back( aPoint );
3354  }
3355 
3356  uno::Reference< beans::XPropertySet > xPropSet;
3357  // get property states
3358  try
3359  {
3361  xSeries, nCurrIndex, mrExport.GetModel() );
3362  }
3363  catch( const uno::Exception & )
3364  {
3365  TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" );
3366  }
3367  if( xPropSet.is())
3368  {
3369  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(SvtSaveOptions().GetODFSaneDefaultVersion());
3370  if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012)
3371  {
3372  lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport );
3373  lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport );
3374  }
3375 
3376  aPropertyStates = mxExpPropMapper->Filter( xPropSet );
3377  if( !aPropertyStates.empty() )
3378  {
3379  if( bExportContent )
3380  {
3381  // write data-point with style
3382  SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3383  SchXMLDataPointStruct aPoint;
3384  aPoint.maStyleName = maAutoStyleNameQueue.front();
3385  aPoint.mCustomLabelText = lcl_getCustomLabelField(nCurrIndex, xSeries);
3386  aPoint.mCustomLabelPos = lcl_getCustomLabelPosition(nCurrIndex, xSeries);
3387  maAutoStyleNameQueue.pop();
3388 
3389  aDataPointVector.push_back( aPoint );
3390  nLastIndex = nCurrIndex;
3391  }
3392  else
3393  {
3394  CollectAutoStyle( aPropertyStates );
3395  }
3396  continue;
3397  }
3398  }
3399 
3400  // if we get here the property states are empty
3401  SchXMLDataPointStruct aPoint;
3402  aDataPointVector.push_back( aPoint );
3403 
3404  nLastIndex = nCurrIndex;
3405  }
3406  // final empty elements
3407  nRepeat = nSeriesLength - nLastIndex - 1;
3408  if( nRepeat > 0 )
3409  {
3410  SchXMLDataPointStruct aPoint;
3411  aPoint.mnRepeat = nRepeat;
3412  aDataPointVector.push_back( aPoint );
3413  }
3414  }
3415 
3416  if (!bExportContent)
3417  return;
3418 
3419  // write elements (merge equal ones)
3420  SchXMLDataPointStruct aPoint;
3421  SchXMLDataPointStruct aLastPoint;
3422 
3423  // initialize so that it doesn't matter if
3424  // the element is counted in the first iteration
3425  aLastPoint.mnRepeat = 0;
3426  sal_Int32 nIndex = 0;
3427  for( const auto& rPoint : aDataPointVector )
3428  {
3429  aPoint = rPoint;
3430 
3431  if( aPoint.maStyleName == aLastPoint.maStyleName && aLastPoint.mCustomLabelText.getLength() < 1 &&
3432  aLastPoint.mCustomLabelPos.Primary == 0.0 && aLastPoint.mCustomLabelPos.Secondary == 0.0 )
3433  aPoint.mnRepeat += aLastPoint.mnRepeat;
3434  else if( aLastPoint.mnRepeat > 0 )
3435  {
3436  // write last element
3437  if( !aLastPoint.maStyleName.isEmpty() )
3438  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName );
3439 
3440  if( aLastPoint.mnRepeat > 1 )
3442  OUString::number( ( aLastPoint.mnRepeat ) ));
3443 
3444  for (auto& deletedLegendEntry : deletedLegendEntriesSeq)
3445  {
3446  if (nIndex == deletedLegendEntry)
3447  {
3448  mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
3449  break;
3450  }
3451  }
3452  nIndex++;
3453  exportCustomLabelPosition(aLastPoint.mCustomLabelPos);
3454  SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true );
3455  exportCustomLabel(aLastPoint.mCustomLabelText);
3456  }
3457  aLastPoint = aPoint;
3458  }
3459  // write last element if it hasn't been written in last iteration
3460  if( aPoint.maStyleName == aLastPoint.maStyleName )
3461  {
3462  if( !aLastPoint.maStyleName.isEmpty() )
3463  mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName );
3464 
3465  if( aLastPoint.mnRepeat > 1 )
3467  OUString::number( ( aLastPoint.mnRepeat ) ));
3468 
3469  for (auto& deletedLegendEntry : deletedLegendEntriesSeq)
3470  {
3471  if (nIndex == deletedLegendEntry)
3472  {
3473  mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true));
3474  break;
3475  }
3476  }
3477 
3478  exportCustomLabelPosition(aLastPoint.mCustomLabelPos);
3479  SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true );
3480  exportCustomLabel(aLastPoint.mCustomLabelText);
3481  }
3482 }
3483 
3484 void SchXMLExportHelper_Impl::exportCustomLabel( const CustomLabelSeq & xCustomLabel )
3485 {
3486  if( xCustomLabel.getLength() < 1 )
3487  return; // nothing to export
3488 
3490  SvXMLElementExport aPara( mrExport, XML_NAMESPACE_TEXT, XML_P, true, false );
3491  for( const Reference<chart2::XDataPointCustomLabelField>& label : xCustomLabel )
3492  {
3493  // TODO add style
3494  SvXMLElementExport aSpan( mrExport, XML_NAMESPACE_TEXT, XML_SPAN, true, false);
3495  mrExport.GetDocHandler()->characters(label->getString());
3496  }
3497 }
3498 
3499 void SchXMLExportHelper_Impl::exportCustomLabelPosition( const chart2::RelativePosition & xCustomLabelPosition)
3500 {
3501  if( xCustomLabelPosition.Primary == 0.0 && xCustomLabelPosition.Secondary == 0.0 )
3502  return; // nothing to export
3503 
3504  OUStringBuffer aCustomLabelPosString;
3505  ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Primary);
3506  mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_X, aCustomLabelPosString.makeStringAndClear());
3507 
3508  ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Secondary);
3509  mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_Y, aCustomLabelPosString.makeStringAndClear());
3510 }
3511 
3512 void SchXMLExportHelper_Impl::addPosition( const awt::Point & rPosition )
3513 {
3515  msStringBuffer, rPosition.X );
3516  msString = msStringBuffer.makeStringAndClear();
3518 
3520  msStringBuffer, rPosition.Y );
3521  msString = msStringBuffer.makeStringAndClear();
3523 }
3524 
3525 void SchXMLExportHelper_Impl::addPosition( const Reference< drawing::XShape >& xShape )
3526 {
3527  if( xShape.is())
3528  addPosition( xShape->getPosition());
3529 }
3530 
3531 void SchXMLExportHelper_Impl::addSize( const awt::Size & rSize, bool bIsOOoNamespace)
3532 {
3534  msStringBuffer, rSize.Width );
3535  msString = msStringBuffer.makeStringAndClear();
3537 
3539  msStringBuffer, rSize.Height);
3540  msString = msStringBuffer.makeStringAndClear();
3541  mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG, XML_HEIGHT, msString );
3542 }
3543 
3544 void SchXMLExportHelper_Impl::addSize( const Reference< drawing::XShape >& xShape )
3545 {
3546  if( xShape.is())
3547  addSize( xShape->getSize() );
3548 }
3549 
3550 awt::Size SchXMLExportHelper_Impl::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc )
3551 {
3552  awt::Size aSize( 8000, 7000 );
3553  uno::Reference< embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY );
3554  SAL_WARN_IF( !xVisualObject.is(), "xmloff.chart", "need XVisualObject for page size" );
3555  if( xVisualObject.is() )
3556  aSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
3557 
3558  return aSize;
3559 }
3560 
3561 void SchXMLExportHelper_Impl::CollectAutoStyle( const std::vector< XMLPropertyState >& aStates )
3562 {
3563  if( !aStates.empty() )
3565 }
3566 
3567 void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates )
3568 {
3569  if( !aStates.empty() )
3570  {
3571  SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" );
3572 
3574  maAutoStyleNameQueue.pop();
3575  }
3576 }
3577 
3578 void SchXMLExportHelper_Impl::exportText( const OUString& rText )
3579 {
3580  SchXMLTools::exportText( mrExport, rText, false/*bConvertTabsLFs*/ );
3581 }
3582 
3583 
3585  OUString const& implementationName, SvXMLExportFlags nExportFlags)
3586  : SvXMLExport(util::MeasureUnit::CM, xContext, implementationName, ::xmloff::token::XML_CHART,
3587  nExportFlags)
3588  , maAutoStylePool(new SchXMLAutoStylePoolP(*this))
3589  , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool))
3590 {
3593 }
3594 
3596 {
3597 }
3598 
3600 {
3601  maExportHelper->SetSourceShellID(GetSourceShellID());
3602  maExportHelper->SetDestinationShellID(GetDestinationShellID());
3603 
3604  Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3605  maExportHelper->m_pImpl->InitRangeSegmentationProperties( xChartDoc );
3606  return SvXMLExport::exportDoc( eClass );
3607 }
3608 
3610 {
3611  // not available in chart
3612  SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" );
3613 }
3614 
3616 {
3618 
3620  return;
3621 
3622  // there are no styles that require their own autostyles
3624  {
3625  Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3626  if( xChartDoc.is())
3627  {
3628  maExportHelper->m_pImpl->collectAutoStyles( xChartDoc );
3629  }
3630  else
3631  {
3632  SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3633  }
3634  }
3635  mbAutoStylesCollected = true;
3636 }
3637 
3639 {
3641 
3643  {
3644  Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3645  if( xChartDoc.is())
3646  {
3647  maExportHelper->m_pImpl->exportAutoStyles();
3648  }
3649  else
3650  {
3651  SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" );
3652  }
3653  }
3654 }
3655 
3657 {
3658  Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY );
3659  if( xChartDoc.is())
3660  {
3661  // determine if data comes from the outside
3662  bool bIncludeTable = true;
3663 
3664  Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
3665  if( xNewDoc.is())
3666  {
3667  // check if we have own data. If so we must not export the complete
3668  // range string, as this is our only indicator for having own or
3669  // external data. @todo: fix this in the file format!
3670  Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
3671  if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
3672  {
3673  bIncludeTable = false;
3674  }
3675  }
3676  else
3677  {
3678  Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY );
3679  if( xServ.is())
3680  {
3681  if( xServ->supportsService( "com.sun.star.chart.ChartTableAddressSupplier" ))
3682  {
3683  Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY );
3684  if( xProp.is())
3685  {
3686  Any aAny;
3687  try
3688  {
3689  OUString sChartAddress;
3690  aAny = xProp->getPropertyValue( "ChartRangeAddress" );
3691  aAny >>= sChartAddress;
3692  maExportHelper->m_pImpl->SetChartRangeAddress( sChartAddress );
3693 
3694  // do not include own table if there are external addresses
3695  bIncludeTable = sChartAddress.isEmpty();
3696  }
3697  catch( const beans::UnknownPropertyException & )
3698  {
3699  SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" );
3700  }
3701  }
3702  }
3703  }
3704  }
3705  maExportHelper->m_pImpl->exportChart( xChartDoc, bIncludeTable );
3706  }
3707  else
3708  {
3709  SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" );
3710  }
3711 }
3712 
3714 {
3715  return maExportHelper->m_pImpl->GetPropertySetMapper();
3716 }
3717 
3718 void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc )
3719 {
3720  if( xChartDoc.is())
3721  try
3722  {
3723  Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
3724  SAL_WARN_IF( !xDataProvider.is(), "xmloff.chart", "No DataProvider" );
3725  if( xDataProvider.is())
3726  {
3727  Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels ));
3728  const Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource ));
3729  OUString sCellRange, sBrokenRange;
3730  bool bBrokenRangeAvailable = false;
3731  for( const auto& rArg : aArgs )
3732  {
3733  if ( rArg.Name == "CellRangeRepresentation" )
3734  rArg.Value >>= sCellRange;
3735  else if ( rArg.Name == "BrokenCellRangeForExport" )
3736  {
3737  if( rArg.Value >>= sBrokenRange )
3738  bBrokenRangeAvailable = true;
3739  }
3740  else if ( rArg.Name == "DataRowSource" )
3741  {
3742  chart::ChartDataRowSource eRowSource;
3743  rArg.Value >>= eRowSource;
3744  mbRowSourceColumns = ( eRowSource == chart::ChartDataRowSource_COLUMNS );
3745  }
3746  else if ( rArg.Name == "SequenceMapping" )
3747  rArg.Value >>= maSequenceMapping;
3748  }
3749 
3750  // #i79009# For Writer we have to export a broken version of the
3751  // range, where every row number is not too large, so that older
3752  // version can correctly read those files.
3753  msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange);
3754  if( !msChartAddress.isEmpty() )
3755  {
3756  // convert format to XML-conform one
3757  Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY );
3758  if( xConversion.is())
3759  msChartAddress = xConversion->convertRangeToXML( msChartAddress );
3760  }
3761  }
3762  }
3763  catch( const uno::Exception & )
3764  {
3765  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
3766  }
3767 }
3768 
3769 // first version: everything goes in one storage
3770 
3771 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
3773  uno::Sequence<uno::Any> const& /*rSeq*/)
3774 {
3775  return cppu::acquire(
3776  new SchXMLExport(pCtx, "SchXMLExport.Compact",
3780 }
3781 
3782 // Oasis format
3783 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
3785  uno::Sequence<uno::Any> const& /*rSeq*/)
3786 {
3787  return cppu::acquire(
3788  new SchXMLExport(pCtx, "SchXMLExport.Oasis.Compact",
3793 }
3794 
3795 // multiple storage version: one for content / styles / meta
3796 
3797 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
3799  uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
3800 {
3801  return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Styles", SvXMLExportFlags::STYLES));
3802 }
3803 
3804 // Oasis format
3805 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
3807  uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
3808 {
3809  return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Styles",
3811 }
3812 
3814 {
3815  return Sequence< OUString > { "com.sun.star.comp.Chart.XMLContentExporter" };
3816 }
3817 
3819 {
3820  return "SchXMLExport.Content";
3821 }
3822 
3823 Reference< uno::XInterface > SchXMLExport_Content_createInstance(const Reference< lang::XMultiServiceFactory > & rSMgr)
3824 {
3826 }
3827 
3828 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
3830  uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
3831 {
3832  return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Content",
3836 }
3837 
3838 // Oasis format
3839 
3840 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
3842  uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
3843 {
3844  return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Meta",
3846 }
3847 
3848 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::SvRef< SvBaseLink > xSink
constexpr sal_uInt16 XML_NAMESPACE_LO_EXT
Definition: xmlnmspe.hxx:80
virtual void ExportAutoStyles_() override
Override this method to export the contents of .
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Chart_XMLOasisExporter_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
constexpr sal_uInt16 XML_NAMESPACE_STYLE
Definition: xmlnmspe.hxx:30
sal_Int32 nIndex
static css::awt::Size getPageSize(const css::uno::Reference< css::chart2::XChartDocument > &xChartDoc)
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Chart_XMLOasisStylesExporter_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
rtl::Reference< XMLShapeExport > const & GetShapeExport()
Definition: xmlexp.hxx:569
SchXMLExport(const css::uno::Reference< css::uno::XComponentContext > &xContext, OUString const &implementationName, SvXMLExportFlags nExportFlags)
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Chart_XMLOasisMetaExporter_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
const char aData[]
virtual void ExportMasterStyles_() override
Override this method to export the contents of .
void exportGrid(const Reference< beans::XPropertySet > &rGridProperties, bool bMajor, bool bExportContent)
void exportCoordinateRegion(const css::uno::Reference< css::chart::XDiagram > &xDiagram)
void exportSeries(const css::uno::Reference< css::chart2::XDiagram > &xNewDiagram, const css::awt::Size &rPageSize, bool bExportContent, bool bHasTwoYAxes)
virtual void exportAutoDataStyles()
Definition: xmlexp.cxx:1836
static css::uno::Reference< css::beans::XPropertySet > createOldAPISeriesPropertySet(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, const css::uno::Reference< css::frame::XModel > &xChartModel)
rtl::Reference< XMLTextParagraphExport > const & GetTextParagraphExport()
Definition: xmlexp.hxx:561
void parseDocument(css::uno::Reference< css::chart::XChartDocument > const &rChartDoc, bool bExportContent, bool bIncludeTable=false)
if bExportContent is false the auto-styles are collected
const SvXMLUnitConverter & GetMM100UnitConverter() const
Definition: xmlexp.hxx:395
constexpr sal_uInt16 XML_NAMESPACE_CHART_EXT
Definition: xmlnmspe.hxx:77
SvXMLExportFlags
Definition: xmlexp.hxx:89
constexpr sal_uInt16 XML_NAMESPACE_CHART
Definition: xmlnmspe.hxx:41
FilterGroup & rTarget
aBuf
const ContentProperties & rData
void exportAxis(enum XMLTokenEnum eDimension, enum XMLTokenEnum eAxisName, const Reference< beans::XPropertySet > &rAxisProps, const Reference< chart2::XAxis > &rChart2Axis, const OUString &rCategoriesRanges, bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, bool bExportContent, OUString sChartType)
constexpr sal_uInt16 XML_NAMESPACE_TEXT
Definition: xmlnmspe.hxx:31
virtual void ExportContent_() override
Override this method to export the content of .
#define XML_STYLE_FAMILY_SCH_CHART_NAME
Definition: families.hxx:43
const css::uno::Reference< css::xml::sax::XDocumentHandler > & GetDocHandler() const
Definition: xmlexp.hxx:386
#define XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX
Definition: families.hxx:37
void collectAutoStyles(css::uno::Reference< css::chart::XChartDocument > const &rChartDoc)
parse chart and collect all auto-styles used in current pool
virtual ErrCode exportDoc(enum::xmloff::token::XMLTokenEnum eClass=::xmloff::token::XML_TOKEN_INVALID)
Definition: xmlexp.cxx:1232
static::std::vector< double > lcl_getAllValuesFromSequence(const Reference< chart2::data::XDataSequence > &xSeq)
::std::pair< css::uno::Reference< css::chart2::data::XDataSequence >, css::uno::Reference< css::chart2::data::XDataSequence > > tLabelValuesDataPair
void exportDateScale(const Reference< beans::XPropertySet > &rAxisProps)
rtl::Reference< SchXMLExportHelper > maExportHelper
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
virtual bool exportXML(OUString &rStrExpValue, const css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Exports the given value according to the XML-data-type corresponding to the derived class...
OUStringBuffer msStringBuffer
const css::uno::Reference< css::frame::XModel > & GetModel() const
Definition: xmlexp.hxx:415
rtl::Reference< XMLChartExportPropertyMapper > mxExpPropMapper
void AddAutoStyleAttribute(const std::vector< XMLPropertyState > &aStates)
void exportAxes(const css::uno::Reference< css::chart::XDiagram > &xDiagram, const css::uno::Reference< css::chart2::XDiagram > &xNewDiagram, bool bExportContent)
virtual ~SchXMLExport() override
void AddAttribute(sal_uInt16 nPrefix, const char *pName, const OUString &rValue)
Definition: xmlexp.cxx:926
Sequence< OUString > SchXMLExport_Content_getSupportedServiceNames()
Reference< uno::XInterface > SchXMLExport_Content_createInstance(const Reference< lang::XMultiServiceFactory > &rSMgr)
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:47
#define XML_STYLE_FAMILY_SCH_CHART_PREFIX
Definition: families.hxx:44
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Chart_XMLExporter_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
void exportRegressionCurve(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, const css::awt::Size &rPageSize, bool bExportContent)
OUString const & GetDestinationShellID() const
Definition: xmlexp.cxx:1445
#define XML_STYLE_FAMILY_SD_GRAPHICS_NAME
Definition: families.hxx:36
bool mbAutoStylesCollected
Definition: xmlexp.hxx:263
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
returns the deterministic version for odf export
Definition: xmlexp.cxx:2312
css::uno::Sequence< sal_Int32 > maSequenceMapping
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Chart_XMLStylesExporter_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
#define DBG_UNHANDLED_EXCEPTION(...)
std::unique_ptr< SchXMLExportHelper_Impl > m_pImpl
void addSize(const css::awt::Size &rSize, bool bIsOOoNamespace=false)
add svg size as attribute for current element
OUString Add(XmlStyleFamily nFamily, const ::std::vector< XMLPropertyState > &rProperties)
Add an item set to the pool and return its generated name.
void exportCustomLabelPosition(const chart2::RelativePosition &xCustomLabelPosition)
int i
static css::uno::Reference< css::beans::XPropertySet > createOldAPIDataPointPropertySet(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, sal_Int32 nPointIndex, const css::uno::Reference< css::frame::XModel > &xChartModel)
void exportCandleStickSeries(const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > &aSeriesSeq, const css::uno::Reference< css::chart2::XDiagram > &xDiagram, bool bJapaneseCandleSticks, bool bExportContent)
OUString m_aRole
void InitRangeSegmentationProperties(const css::uno::Reference< css::chart2::XChartDocument > &xChartDoc)
virtual ~SchXMLExportHelper() override
void AddFamily(XmlStyleFamily nFamily, const OUString &rStrName, SvXMLExportPropertyMapper *pMapper, const OUString &aStrPrefix)
register a new family with its appropriate instance of a derivation of XMLPropertySetMapper for famil...
Definition: xmlaustp.cxx:273
void exportPropertyMapping(const css::uno::Reference< css::chart2::data::XDataSource > &xSource, const Sequence< OUString > &rSupportedMappings)
rtl::Reference< XMLPropertySetMapper > const & GetPropertySetMapper() const
static void convertDateTime(OUStringBuffer &rBuffer, const css::util::DateTime &rDateTime, sal_Int16 const *pTimeZoneOffset, bool bAddTimeIf0AM=false)
constexpr sal_uInt16 XML_NAMESPACE_OOO
Definition: xmlnmspe.hxx:62
OUString SchXMLExport_Content_getImplementationName()
With this class you can export a element containing its data as element o...
static XMLEnumPropertyHdl & getLegendPositionConverter()
const OUString & getChartCLSID() const
returns the string corresponding to the current FileFormat CLSID for Chart
SchXMLExportHelper(SvXMLExport &rExport, SvXMLAutoStylePoolP &rASPool)
OUString GetQNameByKey(sal_uInt16 nKey, const OUString &rLocalName, bool bCache=true) const
Definition: nmspmap.cxx:187
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
void exportAutoStyles()
write the styles collected into the current pool as elements
void exportText(SvXMLExport &rExport, const OUString &rText, bool bConvertTabsLFs)
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Chart_XMLOasisContentExporter_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
static::std::vector< css::uno::Reference< css::chart2::XDataSeries > > getDataSeriesFromDiagram(const css::uno::Reference< css::chart2::XDiagram > &xDiagram)
const SvXMLNamespaceMap & GetNamespaceMap() const
Definition: xmlexp.hxx:392
void SetChartRangeAddress(const OUString &rAddress)
void exportText(const OUString &rText)
exports a string as a paragraph element
void exportCustomLabel(const CustomLabelSeq &xCustomLabel)
virtual ErrCode exportDoc(enum::xmloff::token::XMLTokenEnum eClass=::xmloff::token::XML_TOKEN_INVALID) override
void exportRangeToSomewhere(SvXMLExport &rExport, const OUString &rValue)
#define TOOLS_INFO_EXCEPTION(area, stream)
constexpr sal_uInt16 XML_NAMESPACE_XLINK
Definition: xmlnmspe.hxx:35
void exportPlotArea(const css::uno::Reference< css::chart::XDiagram > &xDiagram, const css::uno::Reference< css::chart2::XDiagram > &xNewDiagram, const css::awt::Size &rPageSize, bool bExportContent, bool bIncludeTable)
void Add(const OUString &sName, T &rValue)
Add a property to handle.
static constexpr OUStringLiteral gsTableName
void CollectAutoStyle(const std::vector< XMLPropertyState > &aStates)
const rtl::Reference< XMLPropertySetMapper > & GetPropertySetMapper() const
static void lcl_exportComplexLabel(const Sequence< uno::Any > &rComplexLabel, SvXMLExport &rExport)
rtl::Reference< XMLPropertySetMapper > mxPropertySetMapper
#define XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE
Definition: PropertyMap.hxx:85
css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes
SvXMLNamespaceMap & GetNamespaceMap_()
Definition: xmlexp.hxx:181
#define SAL_WARN_IF(condition, area, stream)
SchXMLExportHelper_Impl(SvXMLExport &rExport, SvXMLAutoStylePoolP &rASPool)
void SetSourceShellID(const OUString &rShellID)
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3366
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Handling of tokens in XML:
void exportXML(XmlStyleFamily nFamily) const
Export all item sets ofs a certain class in the order in that they have been added.
Definition: xmlaustp.cxx:369
constexpr sal_uInt16 XML_NAMESPACE_TABLE
Definition: xmlnmspe.hxx:32
void addPosition(const css::awt::Point &rPosition)
add svg position as attribute for current element
void collectAutoStyles() override
OUString const & GetSourceShellID() const
Definition: xmlexp.cxx:1440
#define SAL_INFO(area, stream)
#define SO3_SCH_CLASSID
This class lets you get the values from an object that either supports the interface XPropertySet or ...
Smart struct to transport an Any with an index to the appropriate property-name.
Definition: maptype.hxx:104
SvXMLAutoStylePoolP & mrAutoStylePool
sal_uInt16 Add(const OUString &rPrefix, const OUString &rName, sal_uInt16 nKey=XML_NAMESPACE_UNKNOWN)
Definition: nmspmap.cxx:103
Reference< XComponentContext > getProcessComponentContext()
static XMLEnumPropertyHdl & getLegendExpansionConverter()
Sequence< sal_Int8 > aSeq
void exportDataPoints(const css::uno::Reference< css::beans::XPropertySet > &xSeriesProperties, sal_Int32 nSeriesLength, const css::uno::Reference< css::chart2::XDiagram > &xDiagram, bool bExportContent)
void SetDestinationShellID(const OUString &rShellID)
void exportAxisTitle(const Reference< beans::XPropertySet > &rTitleProps, bool bExportContent)
::std::queue< OUString > maAutoStyleNameQueue
first parseDocument: collect autostyles and store names in this queue second parseDocument: export co...
void exportErrorBar(const css::uno::Reference< beans::XPropertySet > &xSeriesProp, bool bYError, bool bExportContent)
void exportChart(css::uno::Reference< css::chart::XChartDocument > const &rChartDoc, bool bIncludeTable)
export the element corresponding to rChartDoc if bIncludeTable is true, the chart data is exported as element (inside the chart element).
#define SAL_WARN(area, stream)
sal_Int32 nLength
Definition: xmltoken.cxx:36
XMLTokenEnum getTokenByChartType(const OUString &rChartTypeService, bool bUseOldNames)
XMLTokenEnum eToken
Definition: xmltoken.cxx:40
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
def label(st)
::std::vector< tLabelValuesDataPair > tDataSequenceCont
static OUString lcl_GetStringFromNumberSequence(const css::uno::Sequence< sal_Int32 > &rSequenceMapping, bool bRemoveOneFromEachIndex)
virtual void addDataStyle(const sal_Int32 nNumberFormat, bool bTimeFormat=false)
Definition: xmlexp.cxx:1824
css::uno::Any const SvXMLExport & rExport
Definition: ImageStyle.hxx:38
bool GetProperties()
Try to get the values for all properties added with the Add method.
constexpr sal_uInt16 XML_NAMESPACE_SVG
Definition: xmlnmspe.hxx:40
SvXMLExportFlags getExportFlags() const
Definition: xmlexp.hxx:477
tDataSequenceCont m_aDataSequencesToExport
void convertMeasureToXML(OUStringBuffer &rBuffer, sal_Int32 nMeasure) const
convert measure to string: from meCoreMeasureUnit to meXMLMeasureUnit
Definition: xmluconv.cxx:181
constexpr sal_uInt16 XML_NAMESPACE_OFFICE
Definition: xmlnmspe.hxx:29
virtual void collectAutoStyles()
Definition: xmlexp.cxx:1715