LibreOffice Module oox (master)  1
chartexport.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 <oox/token/namespaces.hxx>
21 #include <oox/token/properties.hxx>
22 #include <oox/token/tokens.hxx>
26 #include <oox/export/utils.hxx>
28 
29 #include <cstdio>
30 #include <limits>
31 
32 #include <com/sun/star/awt/Gradient.hpp>
33 #include <com/sun/star/chart/XChartDocument.hpp>
34 #include <com/sun/star/chart/ChartLegendPosition.hpp>
35 #include <com/sun/star/chart/XTwoAxisXSupplier.hpp>
36 #include <com/sun/star/chart/XTwoAxisYSupplier.hpp>
37 #include <com/sun/star/chart/XAxisZSupplier.hpp>
38 #include <com/sun/star/chart/ChartDataRowSource.hpp>
39 #include <com/sun/star/chart/X3DDisplay.hpp>
40 #include <com/sun/star/chart/XStatisticDisplay.hpp>
41 #include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
42 #include <com/sun/star/chart/ChartSymbolType.hpp>
43 #include <com/sun/star/chart/ChartAxisMarks.hpp>
44 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
45 #include <com/sun/star/chart/ChartAxisPosition.hpp>
46 #include <com/sun/star/chart/ChartSolidType.hpp>
47 #include <com/sun/star/chart/DataLabelPlacement.hpp>
48 #include <com/sun/star/chart/ErrorBarStyle.hpp>
49 #include <com/sun/star/chart/MissingValueTreatment.hpp>
50 #include <com/sun/star/chart/XDiagramPositioning.hpp>
51 #include <com/sun/star/chart/TimeIncrement.hpp>
52 #include <com/sun/star/chart/TimeInterval.hpp>
53 #include <com/sun/star/chart/TimeUnit.hpp>
54 
55 #include <com/sun/star/chart2/RelativePosition.hpp>
56 #include <com/sun/star/chart2/RelativeSize.hpp>
57 #include <com/sun/star/chart2/XChartDocument.hpp>
58 #include <com/sun/star/chart2/XDiagram.hpp>
59 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
60 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
61 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
62 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
63 #include <com/sun/star/chart2/DataPointLabel.hpp>
64 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
65 #include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
66 #include <com/sun/star/chart2/Symbol.hpp>
67 #include <com/sun/star/chart2/data/XDataSource.hpp>
68 #include <com/sun/star/chart2/data/XDataProvider.hpp>
69 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
70 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
71 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
72 #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
73 #include <com/sun/star/chart2/AxisType.hpp>
74 
75 #include <com/sun/star/beans/XPropertySet.hpp>
76 #include <com/sun/star/container/XNameAccess.hpp>
77 #include <com/sun/star/drawing/XShape.hpp>
78 #include <com/sun/star/drawing/XShapes.hpp>
79 #include <com/sun/star/drawing/FillStyle.hpp>
80 #include <com/sun/star/drawing/LineStyle.hpp>
81 #include <com/sun/star/awt/XBitmap.hpp>
82 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
83 #include <com/sun/star/lang/XServiceName.hpp>
84 
85 #include <com/sun/star/table/CellAddress.hpp>
86 #include <com/sun/star/sheet/XFormulaParser.hpp>
87 #include <com/sun/star/sheet/FormulaToken.hpp>
88 #include <com/sun/star/sheet/AddressConvention.hpp>
89 
90 #include <com/sun/star/container/XNamed.hpp>
91 #include <com/sun/star/embed/XVisualObject.hpp>
92 #include <com/sun/star/embed/Aspects.hpp>
93 
95 #include <comphelper/random.hxx>
96 #include <utility>
98 #include "ColorPropertySet.hxx"
99 
100 #include <svl/zforlist.hxx>
101 #include <svl/numuno.hxx>
102 #include <tools/diagnose_ex.h>
103 #include <sal/log.hxx>
104 
105 #include <set>
106 #include <unordered_set>
107 
108 #include <o3tl/temporary.hxx>
109 #include <o3tl/sorted_vector.hxx>
110 
111 using namespace css;
112 using namespace css::uno;
113 using namespace css::drawing;
114 using namespace ::oox::core;
115 using css::beans::PropertyValue;
116 using css::beans::XPropertySet;
117 using css::container::XNamed;
118 using css::table::CellAddress;
119 using css::sheet::XFormulaParser;
120 using ::oox::core::XmlFilterBase;
121 using ::sax_fastparser::FSHelperPtr;
122 
123 namespace cssc = css::chart;
124 
125 namespace oox::drawingml {
126 
127 namespace {
128 
129 bool isPrimaryAxes(sal_Int32 nIndex)
130 {
131  assert(nIndex == 0 || nIndex == 1);
132  return nIndex != 1;
133 }
134 
135 class lcl_MatchesRole
136 {
137 public:
138  explicit lcl_MatchesRole( const OUString & aRole ) :
139  m_aRole( aRole )
140  {}
141 
142  bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const
143  {
144  if( !xSeq.is() )
145  return false;
146  Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY );
147  OUString aRole;
148 
149  return ( xProp.is() &&
150  (xProp->getPropertyValue( "Role" ) >>= aRole ) &&
151  m_aRole == aRole );
152  }
153 
154 private:
155  OUString m_aRole;
156 };
157 
158 }
159 
161 {
163  try
164  {
166  xDiagram, uno::UNO_QUERY_THROW );
168  xCooSysCnt->getCoordinateSystems());
169  for( const auto& xCooSys : aCooSysSeq )
170  {
171  OSL_ASSERT( xCooSys.is());
172  for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
173  {
174  const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
175  for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
176  {
177  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI );
178  OSL_ASSERT( xAxis.is());
179  if( xAxis.is())
180  {
181  chart2::ScaleData aScaleData = xAxis->getScaleData();
182  if( aScaleData.Categories.is())
183  {
184  xResult.set( aScaleData.Categories );
185  break;
186  }
187  }
188  }
189  }
190  }
191  }
192  catch( const uno::Exception & )
193  {
195  }
196 
197  return xResult;
198 }
199 
203  const OUString & rRole )
204 {
206 
207  const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray();
208  const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength();
210  ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole ));
211 
212  if( pMatch != pEnd )
213  return *pMatch;
214 
215  return aNoResult;
216 }
217 
219 {
220  //categories are always the first sequence
221  Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
223  return xCategories.is();
224 }
225 
227 {
228  bool bCategoryPositionShifted = false;
229  try
230  {
232  xDiagram, uno::UNO_QUERY_THROW);
234  xCooSysCnt->getCoordinateSystems());
235  for (const auto& xCooSys : aCooSysSeq)
236  {
237  OSL_ASSERT(xCooSys.is());
238  if( 0 < xCooSys->getDimension() && 0 <= xCooSys->getMaximumAxisIndexByDimension(0) )
239  {
240  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension(0, 0);
241  OSL_ASSERT(xAxis.is());
242  if (xAxis.is())
243  {
244  chart2::ScaleData aScaleData = xAxis->getScaleData();
245  bCategoryPositionShifted = aScaleData.ShiftedCategoryPosition;
246  break;
247  }
248  }
249  }
250  }
251  catch (const uno::Exception&)
252  {
254  }
255 
256  return bCategoryPositionShifted;
257 }
258 
259 static sal_Int32 lcl_getCategoryAxisType( const Reference< chart2::XDiagram >& xDiagram, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
260 {
261  sal_Int32 nAxisType = -1;
262  try
263  {
265  xDiagram, uno::UNO_QUERY_THROW);
267  xCooSysCnt->getCoordinateSystems());
268  for( const auto& xCooSys : aCooSysSeq )
269  {
270  OSL_ASSERT(xCooSys.is());
271  if( nDimensionIndex < xCooSys->getDimension() && nAxisIndex <= xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex) )
272  {
273  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension(nDimensionIndex, nAxisIndex);
274  OSL_ASSERT(xAxis.is());
275  if( xAxis.is() )
276  {
277  chart2::ScaleData aScaleData = xAxis->getScaleData();
278  nAxisType = aScaleData.AxisType;
279  break;
280  }
281  }
282  }
283  }
284  catch (const uno::Exception&)
285  {
287  }
288 
289  return nAxisType;
290 }
291 
292 static OUString lclGetTimeUnitToken( sal_Int32 nTimeUnit )
293 {
294  switch( nTimeUnit )
295  {
296  case cssc::TimeUnit::DAY: return "days";
297  case cssc::TimeUnit::MONTH: return "months";
298  case cssc::TimeUnit::YEAR: return "years";
299  default: OSL_ENSURE(false, "lclGetTimeUnitToken - unexpected time unit");
300  }
301  return "days";
302 }
303 
304 static cssc::TimeIncrement lcl_getDateTimeIncrement( const Reference< chart2::XDiagram >& xDiagram, sal_Int32 nAxisIndex )
305 {
306  cssc::TimeIncrement aTimeIncrement;
307  try
308  {
310  xDiagram, uno::UNO_QUERY_THROW);
312  xCooSysCnt->getCoordinateSystems());
313  for( const auto& xCooSys : aCooSysSeq )
314  {
315  OSL_ASSERT(xCooSys.is());
316  if( 0 < xCooSys->getDimension() && nAxisIndex <= xCooSys->getMaximumAxisIndexByDimension(0) )
317  {
318  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension(0, nAxisIndex);
319  OSL_ASSERT(xAxis.is());
320  if( xAxis.is() )
321  {
322  chart2::ScaleData aScaleData = xAxis->getScaleData();
323  aTimeIncrement = aScaleData.TimeIncrement;
324  break;
325  }
326  }
327  }
328  }
329  catch (const uno::Exception&)
330  {
332  }
333 
334  return aTimeIncrement;
335 }
336 
338  const Reference< chart2::XDataSeries > & xDataSeries )
339 {
340  bool bResult=true;
341 
342  try
343  {
344  sal_Int32 nAxisIndex = 0;
345  Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
346  xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex;
347  bResult = (0==nAxisIndex);
348  }
349  catch( const uno::Exception & )
350  {
352  }
353 
354  return bResult;
355 }
356 
357 static OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence )
358 {
359  OUStringBuffer aResult;
360  bool bPrecedeWithSpace = false;
361  for( const auto& rString : rSequence )
362  {
363  if( !rString.isEmpty())
364  {
365  if( bPrecedeWithSpace )
366  aResult.append( ' ' );
367  aResult.append( rString );
368  bPrecedeWithSpace = true;
369  }
370  }
371  return aResult.makeStringAndClear();
372 }
373 
375 {
376  Sequence< OUString > aLabels;
377 
378  uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY );
379  if( xTextualDataSequence.is())
380  {
381  aLabels = xTextualDataSequence->getTextualData();
382  }
383  else if( xLabelSeq.is())
384  {
385  const Sequence< uno::Any > aAnies( xLabelSeq->getData());
386  aLabels.realloc( aAnies.getLength());
387  for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
388  aAnies[i] >>= aLabels[i];
389  }
390 
391  return aLabels;
392 }
393 
395  const Reference< chart2::data::XDataSequence > & xCategories,
396  ::std::vector< OUString > & rOutCategories )
397 {
398  OSL_ASSERT( xCategories.is());
399  if( !xCategories.is())
400  return;
401  Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xCategories, uno::UNO_QUERY );
402  if( xTextualDataSequence.is())
403  {
404  rOutCategories.clear();
405  Sequence< OUString > aTextData( xTextualDataSequence->getTextualData());
406  rOutCategories.insert( rOutCategories.end(), aTextData.begin(), aTextData.end() );
407  }
408  else
409  {
410  Sequence< uno::Any > aAnies( xCategories->getData());
411  rOutCategories.resize( aAnies.getLength());
412  for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
413  aAnies[i] >>= rOutCategories[i];
414  }
415 }
416 
417 static ::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq )
418 {
419  ::std::vector< double > aResult;
420 
421  Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY );
422  if( xNumSeq.is())
423  {
424  Sequence< double > aValues( xNumSeq->getNumericalData());
425  aResult.insert( aResult.end(), aValues.begin(), aValues.end() );
426  }
427  else if( xSeq.is())
428  {
429  Sequence< uno::Any > aAnies( xSeq->getData());
430  aResult.resize( aAnies.getLength(), std::numeric_limits<double>::quiet_NaN() );
431  for( sal_Int32 i=0; i<aAnies.getLength(); ++i )
432  aAnies[i] >>= aResult[i];
433  }
434  return aResult;
435 }
436 
437 static sal_Int32 lcl_getChartType( std::u16string_view sChartType )
438 {
439  chart::TypeId eChartTypeId = chart::TYPEID_UNKNOWN;
440  if( sChartType == u"com.sun.star.chart.BarDiagram"
441  || sChartType == u"com.sun.star.chart2.ColumnChartType" )
442  eChartTypeId = chart::TYPEID_BAR;
443  else if( sChartType == u"com.sun.star.chart.AreaDiagram"
444  || sChartType == u"com.sun.star.chart2.AreaChartType" )
445  eChartTypeId = chart::TYPEID_AREA;
446  else if( sChartType == u"com.sun.star.chart.LineDiagram"
447  || sChartType == u"com.sun.star.chart2.LineChartType" )
448  eChartTypeId = chart::TYPEID_LINE;
449  else if( sChartType == u"com.sun.star.chart.PieDiagram"
450  || sChartType == u"com.sun.star.chart2.PieChartType" )
451  eChartTypeId = chart::TYPEID_PIE;
452  else if( sChartType == u"com.sun.star.chart.DonutDiagram"
453  || sChartType == u"com.sun.star.chart2.DonutChartType" )
454  eChartTypeId = chart::TYPEID_DOUGHNUT;
455  else if( sChartType == u"com.sun.star.chart.XYDiagram"
456  || sChartType == u"com.sun.star.chart2.ScatterChartType" )
457  eChartTypeId = chart::TYPEID_SCATTER;
458  else if( sChartType == u"com.sun.star.chart.NetDiagram"
459  || sChartType == u"com.sun.star.chart2.NetChartType" )
460  eChartTypeId = chart::TYPEID_RADARLINE;
461  else if( sChartType == u"com.sun.star.chart.FilledNetDiagram"
462  || sChartType == u"com.sun.star.chart2.FilledNetChartType" )
463  eChartTypeId = chart::TYPEID_RADARAREA;
464  else if( sChartType == u"com.sun.star.chart.StockDiagram"
465  || sChartType == u"com.sun.star.chart2.CandleStickChartType" )
466  eChartTypeId = chart::TYPEID_STOCK;
467  else if( sChartType == u"com.sun.star.chart.BubbleDiagram"
468  || sChartType == u"com.sun.star.chart2.BubbleChartType" )
469  eChartTypeId = chart::TYPEID_BUBBLE;
470 
471  return eChartTypeId;
472 }
473 
474 static sal_Int32 lcl_generateRandomValue()
475 {
476  return comphelper::rng::uniform_int_distribution(0, 100000000-1);
477 }
478 
479 static sal_Int32 lcl_getAlphaFromTransparenceGradient(const awt::Gradient& rGradient, bool bStart)
480 {
481  // Our alpha is a gray color value.
482  sal_uInt8 nRed = ::Color(ColorTransparency, bStart ? rGradient.StartColor : rGradient.EndColor).GetRed();
483  // drawingML alpha is a percentage on a 0..100000 scale.
484  return (255 - nRed) * oox::drawingml::MAX_PERCENT / 255;
485 }
486 
487 ChartExport::ChartExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, Reference< frame::XModel > const & xModel, XmlFilterBase* pFB, DocumentType eDocumentType )
488  : DrawingML( std::move(pFS), pFB, eDocumentType )
489  , mnXmlNamespace( nXmlNamespace )
490  , mnSeriesCount(0)
491  , mxChartModel( xModel )
492  , mpURLTransformer(std::make_shared<URLTransformer>())
493  , mbHasCategoryLabels( false )
494  , mbHasZAxis( false )
495  , mbIs3DChart( false )
496  , mbStacked(false)
497  , mbPercent(false)
498 {
499 }
500 
501 void ChartExport::SetURLTranslator(const std::shared_ptr<URLTransformer>& pTransformer)
502 {
503  mpURLTransformer = pTransformer;
504 }
505 
507 {
508  OUString sChartType = mxDiagram->getDiagramType();
509  return lcl_getChartType( sChartType );
510 }
511 
512 namespace {
513 
514 uno::Sequence< beans::PropertyValue > createArguments(
515  const OUString & rRangeRepresentation, bool bUseColumns)
516 {
517  css::chart::ChartDataRowSource eRowSource = css::chart::ChartDataRowSource_ROWS;
518  if (bUseColumns)
519  eRowSource = css::chart::ChartDataRowSource_COLUMNS;
520 
521  uno::Sequence< beans::PropertyValue > aArguments(4);
522  aArguments[0] = beans::PropertyValue("DataRowSource"
523  , -1, uno::Any(eRowSource)
524  , beans::PropertyState_DIRECT_VALUE);
525  aArguments[1] = beans::PropertyValue("FirstCellAsLabel"
526  , -1, uno::Any(false)
527  , beans::PropertyState_DIRECT_VALUE);
528  aArguments[2] = beans::PropertyValue("HasCategories"
529  , -1, uno::Any(false)
530  , beans::PropertyState_DIRECT_VALUE);
531  aArguments[3] = beans::PropertyValue("CellRangeRepresentation"
532  , -1, uno::Any(rRangeRepresentation)
533  , beans::PropertyState_DIRECT_VALUE);
534 
535  return aArguments;
536 }
537 
538 Reference<chart2::XDataSeries> getPrimaryDataSeries(const Reference<chart2::XChartType>& xChartType)
539 {
540  Reference< chart2::XDataSeriesContainer > xDSCnt(xChartType, uno::UNO_QUERY_THROW);
541 
542  // export dataseries for current chart-type
543  const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq(xDSCnt->getDataSeries());
544  for (const auto& rSeries : aSeriesSeq)
545  {
546  Reference<chart2::XDataSeries> xSource(rSeries, uno::UNO_QUERY);
547  if (xSource.is())
548  return xSource;
549  }
550 
552 }
553 
554 }
555 
557 {
558  Reference< chart2::XChartDocument > xChartDoc(getModel(), uno::UNO_QUERY);
559  OSL_ASSERT(xChartDoc.is());
560  if (xChartDoc.is())
561  {
562  Reference< chart2::data::XDataProvider > xDataProvider(xChartDoc->getDataProvider());
563  OSL_ENSURE(xDataProvider.is(), "No DataProvider");
564  if (xDataProvider.is())
565  {
566  //detect whether the first series is a row or a column
567  bool bSeriesUsesColumns = true;
568  Reference< chart2::XDiagram > xDiagram(xChartDoc->getFirstDiagram());
569  try
570  {
571  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(xDiagram, uno::UNO_QUERY_THROW);
572  const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(xCooSysCnt->getCoordinateSystems());
573  for (const auto& rCooSys : aCooSysSeq)
574  {
575  const Reference< chart2::XChartTypeContainer > xCTCnt(rCooSys, uno::UNO_QUERY_THROW);
576  const Sequence< Reference< chart2::XChartType > > aChartTypeSeq(xCTCnt->getChartTypes());
577  for (const auto& rChartType : aChartTypeSeq)
578  {
579  Reference< chart2::XDataSeries > xDataSeries = getPrimaryDataSeries(rChartType);
580  if (xDataSeries.is())
581  {
582  uno::Reference< chart2::data::XDataSource > xSeriesSource(xDataSeries, uno::UNO_QUERY);
583  const uno::Sequence< beans::PropertyValue > rArguments = xDataProvider->detectArguments(xSeriesSource);
584  for (const beans::PropertyValue& rProperty : rArguments)
585  {
586  if (rProperty.Name == "DataRowSource")
587  {
588  css::chart::ChartDataRowSource eRowSource;
589  if (rProperty.Value >>= eRowSource)
590  {
591  bSeriesUsesColumns = (eRowSource == css::chart::ChartDataRowSource_COLUMNS);
592  break;
593  }
594  }
595  }
596  }
597  }
598  }
599  }
600  catch (const uno::Exception &)
601  {
602  DBG_UNHANDLED_EXCEPTION("chart2");
603  }
604  // detect we have an inner data table or not
605  if (xChartDoc->hasInternalDataProvider() && rRange == "categories")
606  {
607  try
608  {
609  css::uno::Reference< css::chart2::XAnyDescriptionAccess > xDataAccess(xChartDoc->getDataProvider(), uno::UNO_QUERY);
610  const Sequence< Sequence< uno::Any > >aAnyCategories(bSeriesUsesColumns ? xDataAccess->getAnyRowDescriptions() : xDataAccess->getAnyColumnDescriptions());
611  auto pMax = std::max_element(aAnyCategories.begin(), aAnyCategories.end(),
612  [](const Sequence<uno::Any>& a, const Sequence<uno::Any>& b) {
613  return a.getLength() < b.getLength(); });
614 
615  //minimum is 1!
616  if (pMax != aAnyCategories.end() && pMax->getLength() > 1)
617  {
618  sal_Int32 nLevelCount = pMax->getLength();
619  //we have complex categories
620  //sort the categories name
621  Sequence<Sequence<OUString>>aFinalSplitSource(nLevelCount);
622  for (sal_Int32 i = 0; i < nLevelCount; i++)
623  {
624  sal_Int32 nElemLabel = 0;
625  aFinalSplitSource[nLevelCount - i - 1].realloc(aAnyCategories.getLength());
626  for (auto const& elemLabel : aAnyCategories)
627  {
628  // make sure elemLabel[i] exists!
629  if (elemLabel.getLength() > i)
630  {
631  aFinalSplitSource[nLevelCount - i - 1][nElemLabel] = elemLabel[i].get<OUString>();
632  nElemLabel++;
633  }
634  }
635  }
636  return aFinalSplitSource;
637  }
638  }
639  catch (const uno::Exception &)
640  {
642  }
643  }
644  else
645  {
646  try
647  {
648  uno::Reference< chart2::data::XDataSource > xCategoriesSource(xDataProvider->createDataSource(
649  createArguments(rRange, bSeriesUsesColumns)));
650 
651  if (xCategoriesSource.is())
652  {
653  const Sequence< Reference< chart2::data::XLabeledDataSequence >> aCategories = xCategoriesSource->getDataSequences();
654  if (aCategories.getLength() > 1)
655  {
656  //we have complex categories
657  //sort the categories name
658  Sequence<Sequence<OUString>> aFinalSplitSource(aCategories.getLength());
659  std::transform(aCategories.begin(), aCategories.end(),
660  std::reverse_iterator(aFinalSplitSource.end()),
662  return lcl_getLabelSequence(xCat->getValues()); });
663  return aFinalSplitSource;
664  }
665  }
666  }
667  catch (const uno::Exception &)
668  {
670  }
671  }
672  }
673  }
674 
676 }
677 
678 OUString ChartExport::parseFormula( const OUString& rRange )
679 {
680  OUString aResult;
682  uno::Reference< lang::XMultiServiceFactory > xSF = GetFB()->getModelFactory();
683  if( xSF.is() )
684  {
685  try
686  {
687  xParser.set( xSF->createInstance("com.sun.star.sheet.FormulaParser"), UNO_QUERY );
688  }
689  catch( Exception& )
690  {
691  }
692  }
693 
694  SAL_WARN_IF(!xParser.is(), "oox", "creating formula parser failed");
695 
696  if( xParser.is() )
697  {
698  Reference< XPropertySet > xParserProps( xParser, uno::UNO_QUERY );
699  // rRange is the result of a
700  // css::chart2::data::XDataSequence::getSourceRangeRepresentation()
701  // call that returns the range in the document's current UI notation.
702  // Creating a FormulaParser defaults to the same notation, for
703  // parseFormula() do not attempt to override the FormulaConvention
704  // property with css::sheet::AddressConvention::OOO or some such.
705  /* TODO: it would be much better to introduce a
706  * getSourceRangeRepresentation(css::sheet::AddressConvention) to
707  * return the ranges in a specific convention than converting them with
708  * the overhead of creating an XFormulaParser for each... */
709  uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( rRange, CellAddress( 0, 0, 0 ) );
710  if( xParserProps.is() )
711  {
712  xParserProps->setPropertyValue("FormulaConvention", uno::makeAny(css::sheet::AddressConvention::XL_OOX) );
713  }
714  aResult = xParser->printFormula( aTokens, CellAddress( 0, 0, 0 ) );
715  }
716  else
717  {
718  //FIXME: currently just using simple converter, e.g $Sheet1.$A$1:$C$1 -> Sheet1!$A$1:$C$1
719  OUString aRange( rRange );
720  if( aRange.startsWith("$") )
721  aRange = aRange.copy(1);
722  aRange = aRange.replaceAll(".$", "!$" );
723  aResult = aRange;
724  }
725 
726  return aResult;
727 }
728 
729 void ChartExport::WriteChartObj( const Reference< XShape >& xShape, sal_Int32 nID, sal_Int32 nChartCount )
730 {
731  FSHelperPtr pFS = GetFS();
732 
733  Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
734 
735  pFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
736 
737  pFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
738 
739  // TODO: get the correct chart name chart id
740  OUString sName = "Object 1";
741  Reference< XNamed > xNamed( xShape, UNO_QUERY );
742  if (xNamed.is())
743  sName = xNamed->getName();
744 
745  pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
746  XML_id, OString::number(nID),
747  XML_name, sName);
748 
749  OUString sURL;
750  if ( GetProperty( xShapeProps, "URL" ) )
751  mAny >>= sURL;
752  if( !sURL.isEmpty() )
753  {
754  OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
756  mpURLTransformer->getTransformedString(sURL),
757  mpURLTransformer->isExternalURL(sURL));
758 
759  mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
760  }
761  pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
762 
763  pFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
764 
765  if( GetDocumentType() == DOCUMENT_PPTX )
766  pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
767  pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
768 
769  // visual chart properties
771 
772  // writer chart object
773  pFS->startElement(FSNS(XML_a, XML_graphic));
774  pFS->startElement( FSNS( XML_a, XML_graphicData ),
775  XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart" );
776  OUString sId;
777  const char* sFullPath = nullptr;
778  const char* sRelativePath = nullptr;
779  switch( GetDocumentType() )
780  {
781  case DOCUMENT_DOCX:
782  {
783  sFullPath = "word/charts/chart";
784  sRelativePath = "charts/chart";
785  break;
786  }
787  case DOCUMENT_PPTX:
788  {
789  sFullPath = "ppt/charts/chart";
790  sRelativePath = "../charts/chart";
791  break;
792  }
793  case DOCUMENT_XLSX:
794  {
795  sFullPath = "xl/charts/chart";
796  sRelativePath = "../charts/chart";
797  break;
798  }
799  default:
800  {
801  sFullPath = "charts/chart";
802  sRelativePath = "charts/chart";
803  break;
804  }
805  }
806  OUString sFullStream = OUStringBuffer()
807  .appendAscii(sFullPath)
808  .append(OUString::number(nChartCount) + ".xml")
809  .makeStringAndClear();
810  OUString sRelativeStream = OUStringBuffer()
811  .appendAscii(sRelativePath)
812  .append(OUString::number(nChartCount) + ".xml" )
813  .makeStringAndClear();
815  sFullStream,
816  sRelativeStream,
817  pFS->getOutputStream(),
818  "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
819  OUStringToOString(oox::getRelationship(Relationship::CHART), RTL_TEXTENCODING_UTF8).getStr(),
820  &sId );
821 
822  XmlFilterBase* pFB = GetFB();
823  pFS->singleElement( FSNS( XML_c, XML_chart ),
824  FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart)),
825  FSNS(XML_xmlns, XML_r), pFB->getNamespaceURL(OOX_NS(officeRel)),
826  FSNS(XML_r, XML_id), sId );
827 
828  pFS->endElement( FSNS( XML_a, XML_graphicData ) );
829  pFS->endElement( FSNS( XML_a, XML_graphic ) );
830  pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
831 
832  SetFS( pChart );
833  ExportContent();
834 }
835 
837 {
838  if( !xChartDoc.is())
839  return;
840 
841  try
842  {
843  Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
844  OSL_ENSURE( xDataProvider.is(), "No DataProvider" );
845  if( xDataProvider.is())
846  {
848  }
849  }
850  catch( const uno::Exception & )
851  {
853  }
854 }
855 
857 {
858  Reference< chart2::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
859  OSL_ASSERT( xChartDoc.is() );
860  if( !xChartDoc.is() )
861  return;
862  InitRangeSegmentationProperties( xChartDoc );
863  // TODO: export chart
864  ExportContent_( );
865 }
866 
868 {
869  Reference< css::chart::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
870  if( xChartDoc.is())
871  {
872  // determine if data comes from the outside
873  bool bIncludeTable = true;
874 
875  Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
876  if( xNewDoc.is())
877  {
878  // check if we have own data. If so we must not export the complete
879  // range string, as this is our only indicator for having own or
880  // external data. @todo: fix this in the file format!
881  Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY );
882  if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" ))
883  {
884  bIncludeTable = false;
885  }
886  }
887  exportChartSpace( xChartDoc, bIncludeTable );
888  }
889  else
890  {
891  OSL_FAIL( "Couldn't export chart due to wrong XModel" );
892  }
893 }
894 
896  bool bIncludeTable )
897 {
898  FSHelperPtr pFS = GetFS();
899  XmlFilterBase* pFB = GetFB();
900  pFS->startElement( FSNS( XML_c, XML_chartSpace ),
901  FSNS( XML_xmlns, XML_c ), pFB->getNamespaceURL(OOX_NS(dmlChart)),
902  FSNS( XML_xmlns, XML_a ), pFB->getNamespaceURL(OOX_NS(dml)),
903  FSNS( XML_xmlns, XML_r ), pFB->getNamespaceURL(OOX_NS(officeRel)));
904  // TODO: get the correct editing language
905  pFS->singleElement(FSNS(XML_c, XML_lang), XML_val, "en-US");
906 
907  pFS->singleElement(FSNS(XML_c, XML_roundedCorners), XML_val, "0");
908 
909  if( !bIncludeTable )
910  {
911  // TODO:external data
912  }
913  //XML_chart
914  exportChart(xChartDoc);
915 
916  // TODO: printSettings
917  // TODO: style
918  // TODO: text properties
919  // TODO: shape properties
920  Reference< XPropertySet > xPropSet = xChartDoc->getArea();
921  if( xPropSet.is() )
922  exportShapeProps( xPropSet );
923 
924  //XML_externalData
925  exportExternalData(xChartDoc);
926 
927  // export additional shapes in chart
928  exportAdditionalShapes(xChartDoc);
929 
930  pFS->endElement( FSNS( XML_c, XML_chartSpace ) );
931 }
932 
934 {
935  // Embedded external data is grab bagged for docx file hence adding export part of
936  // external data for docx files only.
938  return;
939 
940  OUString externalDataPath;
941  Reference< beans::XPropertySet > xDocPropSet( xChartDoc->getDiagram(), uno::UNO_QUERY );
942  if( xDocPropSet.is())
943  {
944  try
945  {
946  Any aAny( xDocPropSet->getPropertyValue( "ExternalData" ));
947  aAny >>= externalDataPath;
948  }
949  catch( beans::UnknownPropertyException & )
950  {
951  SAL_WARN("oox", "Required property not found in ChartDocument");
952  }
953  }
954  if(externalDataPath.isEmpty())
955  return;
956 
957  // Here adding external data entry to relationship.
958  OUString relationPath = externalDataPath;
959  // Converting absolute path to relative path.
960  if( externalDataPath[ 0 ] != '.' && externalDataPath[ 1 ] != '.')
961  {
962  sal_Int32 nSepPos = externalDataPath.indexOf( '/', 0 );
963  if( nSepPos > 0)
964  {
965  relationPath = relationPath.copy( nSepPos, ::std::max< sal_Int32 >( externalDataPath.getLength(), 0 ) - nSepPos );
966  relationPath = ".." + relationPath;
967  }
968  }
969  FSHelperPtr pFS = GetFS();
971  if (relationPath.endsWith(".bin"))
973 
974  OUString sRelId = GetFB()->addRelation(pFS->getOutputStream(),
975  type,
976  relationPath);
977  pFS->singleElementNS(XML_c, XML_externalData, FSNS(XML_r, XML_id), sRelId);
978 }
979 
981 {
982  Reference< beans::XPropertySet > xDocPropSet(xChartDoc, uno::UNO_QUERY);
983  if (!xDocPropSet.is())
984  return;
985 
986  css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes;
987  // get a sequence of non-chart shapes
988  try
989  {
990  Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes");
991  if( (aShapesAny >>= mxAdditionalShapes) && mxAdditionalShapes.is() )
992  {
993  OUString sId;
994  const char* sFullPath = nullptr;
995  const char* sRelativePath = nullptr;
996  sal_Int32 nDrawing = getNewDrawingUniqueId();
997 
998  switch (GetDocumentType())
999  {
1000  case DOCUMENT_DOCX:
1001  {
1002  sFullPath = "word/drawings/drawing";
1003  sRelativePath = "../drawings/drawing";
1004  break;
1005  }
1006  case DOCUMENT_PPTX:
1007  {
1008  sFullPath = "ppt/drawings/drawing";
1009  sRelativePath = "../drawings/drawing";
1010  break;
1011  }
1012  case DOCUMENT_XLSX:
1013  {
1014  sFullPath = "xl/drawings/drawing";
1015  sRelativePath = "../drawings/drawing";
1016  break;
1017  }
1018  default:
1019  {
1020  sFullPath = "drawings/drawing";
1021  sRelativePath = "drawings/drawing";
1022  break;
1023  }
1024  }
1025  OUString sFullStream = OUStringBuffer()
1026  .appendAscii(sFullPath)
1027  .append(OUString::number(nDrawing) + ".xml")
1028  .makeStringAndClear();
1029  OUString sRelativeStream = OUStringBuffer()
1030  .appendAscii(sRelativePath)
1031  .append(OUString::number(nDrawing) + ".xml")
1032  .makeStringAndClear();
1033 
1035  sFullStream,
1036  sRelativeStream,
1037  GetFS()->getOutputStream(),
1038  "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml",
1039  OUStringToOString(oox::getRelationship(Relationship::CHARTUSERSHAPES), RTL_TEXTENCODING_UTF8).getStr(),
1040  &sId);
1041 
1042  GetFS()->singleElementNS(XML_c, XML_userShapes, FSNS(XML_r, XML_id), sId);
1043 
1044  XmlFilterBase* pFB = GetFB();
1045  pDrawing->startElement(FSNS(XML_c, XML_userShapes),
1046  FSNS(XML_xmlns, XML_cdr), pFB->getNamespaceURL(OOX_NS(dmlChartDr)),
1047  FSNS(XML_xmlns, XML_a), pFB->getNamespaceURL(OOX_NS(dml)),
1048  FSNS(XML_xmlns, XML_c), pFB->getNamespaceURL(OOX_NS(dmlChart)));
1049 
1050  const sal_Int32 nShapeCount(mxAdditionalShapes->getCount());
1051  for (sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
1052  {
1054  mxAdditionalShapes->getByIndex(nShapeId) >>= xShape;
1055  SAL_WARN_IF(!xShape.is(), "xmloff.chart", "Shape without an XShape?");
1056  if (!xShape.is())
1057  continue;
1058 
1059  // TODO: absSizeAnchor: we import both (absSizeAnchor and relSizeAnchor), but there is no essential difference between them.
1060  pDrawing->startElement(FSNS(XML_cdr, XML_relSizeAnchor));
1061  uno::Reference< beans::XPropertySet > xShapeProperties(xShape, uno::UNO_QUERY);
1062  if( xShapeProperties.is() )
1063  {
1064  Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1065  awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1066  WriteFromTo( xShape, aPageSize, pDrawing );
1067 
1068  ShapeExport aExport(XML_cdr, pDrawing, nullptr, GetFB(), GetDocumentType());
1069  aExport.WriteShape(xShape);
1070  }
1071  pDrawing->endElement(FSNS(XML_cdr, XML_relSizeAnchor));
1072  }
1073  pDrawing->endElement(FSNS(XML_c, XML_userShapes));
1074  }
1075  }
1076  catch (const uno::Exception&)
1077  {
1078  TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found");
1079  }
1080 }
1081 
1083 {
1084  Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY );
1085  mxDiagram.set( xChartDoc->getDiagram() );
1086  if( xNewDoc.is())
1087  mxNewDiagram.set( xNewDoc->getFirstDiagram());
1088 
1089  // get Properties of ChartDocument
1090  bool bHasMainTitle = false;
1091  OUString aSubTitle;
1092  bool bHasLegend = false;
1093  Reference< beans::XPropertySet > xDocPropSet( xChartDoc, uno::UNO_QUERY );
1094  if( xDocPropSet.is())
1095  {
1096  try
1097  {
1098  Any aAny( xDocPropSet->getPropertyValue("HasMainTitle"));
1099  aAny >>= bHasMainTitle;
1100  aAny = xDocPropSet->getPropertyValue("HasLegend");
1101  aAny >>= bHasLegend;
1102  }
1103  catch( beans::UnknownPropertyException & )
1104  {
1105  SAL_WARN("oox", "Required property not found in ChartDocument");
1106  }
1107  } // if( xDocPropSet.is())
1108 
1109  Reference< beans::XPropertySet > xPropSubTitle( xChartDoc->getSubTitle(), UNO_QUERY );
1110  if( xPropSubTitle.is())
1111  {
1112  try
1113  {
1114  xPropSubTitle->getPropertyValue("String") >>= aSubTitle;
1115  }
1116  catch( beans::UnknownPropertyException & )
1117  {
1118  }
1119  }
1120 
1121  // chart element
1122  FSHelperPtr pFS = GetFS();
1123  pFS->startElement(FSNS(XML_c, XML_chart));
1124 
1125  // titles
1126  if( bHasMainTitle )
1127  {
1128  exportTitle( xChartDoc->getTitle(), !aSubTitle.isEmpty() ? &aSubTitle : nullptr );
1129  pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0");
1130  }
1131  else if( !aSubTitle.isEmpty() )
1132  {
1133  exportTitle( xChartDoc->getSubTitle(), nullptr );
1134  pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0");
1135  }
1136  else
1137  {
1138  pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "1");
1139  }
1140 
1141  InitPlotArea( );
1142  if( mbIs3DChart )
1143  {
1144  exportView3D();
1145 
1146  // floor
1147  Reference< beans::XPropertySet > xFloor = mxNewDiagram->getFloor();
1148  if( xFloor.is() )
1149  {
1150  pFS->startElement(FSNS(XML_c, XML_floor));
1151  exportShapeProps( xFloor );
1152  pFS->endElement( FSNS( XML_c, XML_floor ) );
1153  }
1154 
1155  // LibreOffice doesn't distinguish between sideWall and backWall (both are using the same color).
1156  // It is controlled by the same Wall property.
1158  if( xWall.is() )
1159  {
1160  // sideWall
1161  pFS->startElement(FSNS(XML_c, XML_sideWall));
1162  exportShapeProps( xWall );
1163  pFS->endElement( FSNS( XML_c, XML_sideWall ) );
1164 
1165  // backWall
1166  pFS->startElement(FSNS(XML_c, XML_backWall));
1167  exportShapeProps( xWall );
1168  pFS->endElement( FSNS( XML_c, XML_backWall ) );
1169  }
1170 
1171  }
1172  // plot area
1173  exportPlotArea( xChartDoc );
1174  // legend
1175  if( bHasLegend )
1176  exportLegend( xChartDoc );
1177 
1178  uno::Reference<beans::XPropertySet> xDiagramPropSet(xChartDoc->getDiagram(), uno::UNO_QUERY);
1179  uno::Any aPlotVisOnly = xDiagramPropSet->getPropertyValue("IncludeHiddenCells");
1180  bool bIncludeHiddenCells = false;
1181  aPlotVisOnly >>= bIncludeHiddenCells;
1182  pFS->singleElement(FSNS(XML_c, XML_plotVisOnly), XML_val, ToPsz10(!bIncludeHiddenCells));
1183 
1185 
1186  pFS->endElement( FSNS( XML_c, XML_chart ) );
1187 }
1188 
1189 void ChartExport::exportMissingValueTreatment(const uno::Reference<beans::XPropertySet>& xPropSet)
1190 {
1191  if (!xPropSet.is())
1192  return;
1193 
1194  sal_Int32 nVal = 0;
1195  uno::Any aAny = xPropSet->getPropertyValue("MissingValueTreatment");
1196  if (!(aAny >>= nVal))
1197  return;
1198 
1199  const char* pVal = nullptr;
1200  switch (nVal)
1201  {
1202  case cssc::MissingValueTreatment::LEAVE_GAP:
1203  pVal = "gap";
1204  break;
1205  case cssc::MissingValueTreatment::USE_ZERO:
1206  pVal = "zero";
1207  break;
1208  case cssc::MissingValueTreatment::CONTINUE:
1209  pVal = "span";
1210  break;
1211  default:
1212  SAL_WARN("oox", "unknown MissingValueTreatment value");
1213  break;
1214  }
1215 
1216  FSHelperPtr pFS = GetFS();
1217  pFS->singleElement(FSNS(XML_c, XML_dispBlanksAs), XML_val, pVal);
1218 }
1219 
1221 {
1222  FSHelperPtr pFS = GetFS();
1223  pFS->startElement(FSNS(XML_c, XML_legend));
1224 
1225  Reference< beans::XPropertySet > xProp( xChartDoc->getLegend(), uno::UNO_QUERY );
1226  if( xProp.is() )
1227  {
1228  // position
1229  css::chart::ChartLegendPosition aLegendPos = css::chart::ChartLegendPosition_NONE;
1230  try
1231  {
1232  Any aAny( xProp->getPropertyValue( "Alignment" ));
1233  aAny >>= aLegendPos;
1234  }
1235  catch( beans::UnknownPropertyException & )
1236  {
1237  SAL_WARN("oox", "Property Align not found in ChartLegend");
1238  }
1239 
1240  const char* strPos = nullptr;
1241  switch( aLegendPos )
1242  {
1243  case css::chart::ChartLegendPosition_LEFT:
1244  strPos = "l";
1245  break;
1246  case css::chart::ChartLegendPosition_RIGHT:
1247  strPos = "r";
1248  break;
1249  case css::chart::ChartLegendPosition_TOP:
1250  strPos = "t";
1251  break;
1252  case css::chart::ChartLegendPosition_BOTTOM:
1253  strPos = "b";
1254  break;
1255  case css::chart::ChartLegendPosition_NONE:
1256  case css::chart::ChartLegendPosition::ChartLegendPosition_MAKE_FIXED_SIZE:
1257  // nothing
1258  break;
1259  }
1260 
1261  if( strPos != nullptr )
1262  {
1263  pFS->singleElement(FSNS(XML_c, XML_legendPos), XML_val, strPos);
1264  }
1265 
1266  // legendEntry
1267  Reference<chart2::XCoordinateSystemContainer> xCooSysContainer(mxNewDiagram, UNO_QUERY_THROW);
1268  const Sequence<Reference<chart2::XCoordinateSystem>> xCooSysSequence(xCooSysContainer->getCoordinateSystems());
1269 
1270  sal_Int32 nIndex = 0;
1271  bool bShowLegendEntry;
1272  for (const auto& rCooSys : xCooSysSequence)
1273  {
1274  PropertySet aCooSysProp(rCooSys);
1275  bool bSwapXAndY = aCooSysProp.getBoolProperty(PROP_SwapXAndYAxis);
1276 
1277  Reference<chart2::XChartTypeContainer> xChartTypeContainer(rCooSys, UNO_QUERY_THROW);
1278  const Sequence<Reference<chart2::XChartType>> xChartTypeSequence(xChartTypeContainer->getChartTypes());
1279  if (!xChartTypeSequence.hasElements())
1280  continue;
1281 
1282  for (const auto& rCT : xChartTypeSequence)
1283  {
1284  Reference<chart2::XDataSeriesContainer> xDSCont(rCT, UNO_QUERY);
1285  if (!xDSCont.is())
1286  continue;
1287 
1288  OUString aChartType(rCT->getChartType());
1289  bool bIsPie = lcl_getChartType(aChartType) == chart::TYPEID_PIE;
1290  if (bIsPie)
1291  {
1292  PropertySet xChartTypeProp(rCT);
1293  bIsPie = !xChartTypeProp.getBoolProperty(PROP_UseRings);
1294  }
1295  const Sequence<Reference<chart2::XDataSeries>> aDataSeriesSeq = xDSCont->getDataSeries();
1296  if (bSwapXAndY)
1297  nIndex += aDataSeriesSeq.getLength() - 1;
1298  for (const auto& rDataSeries : aDataSeriesSeq)
1299  {
1300  PropertySet aSeriesProp(rDataSeries);
1301  bool bVaryColorsByPoint = aSeriesProp.getBoolProperty(PROP_VaryColorsByPoint);
1302  if (bVaryColorsByPoint || bIsPie)
1303  {
1304  Sequence<sal_Int32> deletedLegendEntriesSeq;
1305  aSeriesProp.getProperty(deletedLegendEntriesSeq, PROP_DeletedLegendEntries);
1306  for (auto& deletedLegendEntry : deletedLegendEntriesSeq)
1307  {
1308  pFS->startElement(FSNS(XML_c, XML_legendEntry));
1309  pFS->singleElement(FSNS(XML_c, XML_idx), XML_val,
1310  OString::number(nIndex + deletedLegendEntry));
1311  pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, "1");
1312  pFS->endElement(FSNS(XML_c, XML_legendEntry));
1313  }
1314  Reference<chart2::data::XDataSource> xDSrc(rDataSeries, UNO_QUERY);
1315  if (!xDSrc.is())
1316  continue;
1317 
1318  const Sequence<Reference<chart2::data::XLabeledDataSequence>> aDataSeqs = xDSrc->getDataSequences();
1319  for (const auto& rDataSeq : aDataSeqs)
1320  {
1321  Reference<chart2::data::XDataSequence> xValues = rDataSeq->getValues();
1322  if (!xValues.is())
1323  continue;
1324 
1325  sal_Int32 nDataSeqSize = xValues->getData().getLength();
1326  nIndex += nDataSeqSize;
1327  }
1328  }
1329  else
1330  {
1331  bShowLegendEntry = aSeriesProp.getBoolProperty(PROP_ShowLegendEntry);
1332  if (!bShowLegendEntry)
1333  {
1334  pFS->startElement(FSNS(XML_c, XML_legendEntry));
1335  pFS->singleElement(FSNS(XML_c, XML_idx), XML_val,
1336  OString::number(nIndex));
1337  pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, "1");
1338  pFS->endElement(FSNS(XML_c, XML_legendEntry));
1339  }
1340  bSwapXAndY ? nIndex-- : nIndex++;
1341  }
1342  }
1343  if (bSwapXAndY)
1344  nIndex += aDataSeriesSeq.getLength() + 1;
1345  }
1346  }
1347 
1348  uno::Any aRelativePos = xProp->getPropertyValue("RelativePosition");
1349  if (aRelativePos.hasValue())
1350  {
1351  pFS->startElement(FSNS(XML_c, XML_layout));
1352  pFS->startElement(FSNS(XML_c, XML_manualLayout));
1353 
1354  pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1355  pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1356  chart2::RelativePosition aPos = aRelativePos.get<chart2::RelativePosition>();
1357 
1358  const double x = aPos.Primary;
1359  const double y = aPos.Secondary;
1360 
1361  pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1362  pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1363 
1364  uno::Any aRelativeSize = xProp->getPropertyValue("RelativeSize");
1365  if (aRelativeSize.hasValue())
1366  {
1367  chart2::RelativeSize aSize = aRelativeSize.get<chart2::RelativeSize>();
1368 
1369  const double w = aSize.Primary;
1370  const double h = aSize.Secondary;
1371 
1372  pFS->singleElement(FSNS(XML_c, XML_w), XML_val, OString::number(w));
1373 
1374  pFS->singleElement(FSNS(XML_c, XML_h), XML_val, OString::number(h));
1375  }
1376 
1377  SAL_WARN_IF(aPos.Anchor != css::drawing::Alignment_TOP_LEFT, "oox", "unsupported anchor position");
1378 
1379  pFS->endElement(FSNS(XML_c, XML_manualLayout));
1380  pFS->endElement(FSNS(XML_c, XML_layout));
1381  }
1382 
1383  if (strPos != nullptr)
1384  {
1385  uno::Any aOverlay = xProp->getPropertyValue("Overlay");
1386  if(aOverlay.get<bool>())
1387  pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "1");
1388  else
1389  pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "0");
1390  }
1391 
1392  // shape properties
1393  exportShapeProps( xProp );
1394 
1395  // draw-chart:txPr text properties
1396  exportTextProps( xProp );
1397  }
1398 
1399  pFS->endElement( FSNS( XML_c, XML_legend ) );
1400 }
1401 
1402 void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString* pSubText)
1403 {
1404  OUString sText;
1405  Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
1406  if( xPropSet.is())
1407  {
1408  xPropSet->getPropertyValue("String") >>= sText;
1409  }
1410 
1411  // tdf#101322: add subtitle to title
1412  if( pSubText )
1413  sText = sText.isEmpty() ? *pSubText : sText + "\n" + *pSubText;
1414 
1415  if( sText.isEmpty() )
1416  return;
1417 
1418  FSHelperPtr pFS = GetFS();
1419  pFS->startElement(FSNS(XML_c, XML_title));
1420 
1421  pFS->startElement(FSNS(XML_c, XML_tx));
1422  pFS->startElement(FSNS(XML_c, XML_rich));
1423 
1424  // TODO: bodyPr
1425  const char* sWritingMode = nullptr;
1426  bool bVertical = false;
1427  xPropSet->getPropertyValue("StackedText") >>= bVertical;
1428  if( bVertical )
1429  sWritingMode = "wordArtVert";
1430 
1431  sal_Int32 nRotation = 0;
1432  xPropSet->getPropertyValue("TextRotation") >>= nRotation;
1433 
1434  pFS->singleElement( FSNS( XML_a, XML_bodyPr ),
1435  XML_vert, sWritingMode,
1436  XML_rot, oox::drawingml::calcRotationValue(nRotation) );
1437  // TODO: lstStyle
1438  pFS->singleElement(FSNS(XML_a, XML_lstStyle));
1439  // FIXME: handle multiple paragraphs to parse aText
1440  pFS->startElement(FSNS(XML_a, XML_p));
1441 
1442  pFS->startElement(FSNS(XML_a, XML_pPr));
1443 
1444  bool bDummy = false;
1445  sal_Int32 nDummy;
1446  WriteRunProperties(xPropSet, false, XML_defRPr, true, bDummy, nDummy );
1447 
1448  pFS->endElement( FSNS( XML_a, XML_pPr ) );
1449 
1450  pFS->startElement(FSNS(XML_a, XML_r));
1451  bDummy = false;
1452  WriteRunProperties( xPropSet, false, XML_rPr, true, bDummy, nDummy );
1453  pFS->startElement(FSNS(XML_a, XML_t));
1454  pFS->writeEscaped( sText );
1455  pFS->endElement( FSNS( XML_a, XML_t ) );
1456  pFS->endElement( FSNS( XML_a, XML_r ) );
1457 
1458  pFS->endElement( FSNS( XML_a, XML_p ) );
1459 
1460  pFS->endElement( FSNS( XML_c, XML_rich ) );
1461  pFS->endElement( FSNS( XML_c, XML_tx ) );
1462 
1463  uno::Any aManualLayout = xPropSet->getPropertyValue("RelativePosition");
1464  if (aManualLayout.hasValue())
1465  {
1466  pFS->startElement(FSNS(XML_c, XML_layout));
1467  pFS->startElement(FSNS(XML_c, XML_manualLayout));
1468  pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1469  pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1470 
1471  Reference<embed::XVisualObject> xVisObject(mxChartModel, uno::UNO_QUERY);
1472  awt::Size aPageSize = xVisObject->getVisualAreaSize(embed::Aspects::MSOLE_CONTENT);
1473 
1474  awt::Size aSize = xShape->getSize();
1475  awt::Point aPos2 = xShape->getPosition();
1476  // rotated shapes need special handling...
1477  double fSin = fabs(sin(basegfx::deg2rad(nRotation*0.01)));
1478  // remove part of height from X direction, if title is rotated down
1479  if( nRotation*0.01 > 180.0 )
1480  aPos2.X -= static_cast<sal_Int32>(fSin * aSize.Height + 0.5);
1481  // remove part of width from Y direction, if title is rotated up
1482  else if( nRotation*0.01 > 0.0 )
1483  aPos2.Y -= static_cast<sal_Int32>(fSin * aSize.Width + 0.5);
1484 
1485  double x = static_cast<double>(aPos2.X) / static_cast<double>(aPageSize.Width);
1486  double y = static_cast<double>(aPos2.Y) / static_cast<double>(aPageSize.Height);
1487  /*
1488  pFS->singleElement(FSNS(XML_c, XML_wMode), XML_val, "edge");
1489  pFS->singleElement(FSNS(XML_c, XML_hMode), XML_val, "edge");
1490  */
1491  pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1492  pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1493  /*
1494  pFS->singleElement(FSNS(XML_c, XML_w), XML_val, "");
1495  pFS->singleElement(FSNS(XML_c, XML_h), XML_val, "");
1496  */
1497  pFS->endElement(FSNS(XML_c, XML_manualLayout));
1498  pFS->endElement(FSNS(XML_c, XML_layout));
1499  }
1500 
1501  pFS->singleElement(FSNS(XML_c, XML_overlay), XML_val, "0");
1502 
1503  // shape properties
1504  if( xPropSet.is() )
1505  {
1506  exportShapeProps( xPropSet );
1507  }
1508 
1509  pFS->endElement( FSNS( XML_c, XML_title ) );
1510 }
1511 
1512 namespace {
1513 
1514  std::vector<Sequence<Reference<chart2::XDataSeries> > > splitDataSeriesByAxis(const Reference< chart2::XChartType >& xChartType)
1515  {
1516  std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitSeries;
1517  std::map<sal_Int32, size_t> aMapAxisToIndex;
1518 
1519  Reference< chart2::XDataSeriesContainer > xDSCnt(xChartType, uno::UNO_QUERY);
1520  if (xDSCnt.is())
1521  {
1522  sal_Int32 nAxisIndexOfFirstSeries = -1;
1523  const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq(xDSCnt->getDataSeries());
1524  for (const uno::Reference<chart2::XDataSeries>& xSeries : aSeriesSeq)
1525  {
1526  Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
1527  if (!xPropSet.is())
1528  continue;
1529 
1530  sal_Int32 nAxisIndex = -1;
1531  uno::Any aAny = xPropSet->getPropertyValue("AttachedAxisIndex");
1532  aAny >>= nAxisIndex;
1533  size_t nVectorPos = 0;
1534  if (nAxisIndexOfFirstSeries == -1)
1535  {
1536  nAxisIndexOfFirstSeries = nAxisIndex;
1537  }
1538 
1539  auto it = aMapAxisToIndex.find(nAxisIndex);
1540  if (it == aMapAxisToIndex.end())
1541  {
1542  aSplitSeries.emplace_back();
1543  nVectorPos = aSplitSeries.size() - 1;
1544  aMapAxisToIndex.insert(std::pair<sal_Int32, size_t>(nAxisIndex, nVectorPos));
1545  }
1546  else
1547  {
1548  nVectorPos = it->second;
1549  }
1550 
1551  uno::Sequence<Reference<chart2::XDataSeries> >& rAxisSeriesSeq = aSplitSeries[nVectorPos];
1552  sal_Int32 nLength = rAxisSeriesSeq.getLength();
1553  rAxisSeriesSeq.realloc(nLength + 1);
1554  rAxisSeriesSeq[nLength] = xSeries;
1555  }
1556  // if the first series attached to secondary axis, then export those series first, which are attached to primary axis
1557  // also the MS Office export every time in this order
1558  if (aSplitSeries.size() > 1 && nAxisIndexOfFirstSeries == 1)
1559  {
1560  std::swap(aSplitSeries[0], aSplitSeries[1]);
1561  }
1562  }
1563 
1564  return aSplitSeries;
1565  }
1566 
1567 }
1568 
1570 {
1571  Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( mxNewDiagram, uno::UNO_QUERY );
1572  if( ! xBCooSysCnt.is())
1573  return;
1574 
1575  // plot-area element
1576 
1577  FSHelperPtr pFS = GetFS();
1578  pFS->startElement(FSNS(XML_c, XML_plotArea));
1579 
1580  Reference<beans::XPropertySet> xWall(mxNewDiagram, uno::UNO_QUERY);
1581  if( xWall.is() )
1582  {
1583  uno::Any aAny = xWall->getPropertyValue("RelativePosition");
1584  if (aAny.hasValue())
1585  {
1586  chart2::RelativePosition aPos = aAny.get<chart2::RelativePosition>();
1587  aAny = xWall->getPropertyValue("RelativeSize");
1588  chart2::RelativeSize aSize = aAny.get<chart2::RelativeSize>();
1589  uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( xChartDoc->getDiagram(), uno::UNO_QUERY );
1590  exportManualLayout(aPos, aSize, xDiagramPositioning->isExcludingDiagramPositioning() );
1591  }
1592  }
1593 
1594  // chart type
1596  aCooSysSeq( xBCooSysCnt->getCoordinateSystems());
1597 
1598  // tdf#123647 Save empty chart as empty bar chart.
1599  if (!aCooSysSeq.hasElements())
1600  {
1601  pFS->startElement(FSNS(XML_c, XML_barChart));
1602  pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, "col");
1603  pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, "clustered");
1604  pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
1605  exportAxesId(true);
1606  pFS->endElement(FSNS(XML_c, XML_barChart));
1607  }
1608 
1609  for( const auto& rCS : aCooSysSeq )
1610  {
1611  Reference< chart2::XChartTypeContainer > xCTCnt( rCS, uno::UNO_QUERY );
1612  if( ! xCTCnt.is())
1613  continue;
1614  mnSeriesCount=0;
1615  const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
1616  for( const auto& rCT : aCTSeq )
1617  {
1618  Reference< chart2::XDataSeriesContainer > xDSCnt( rCT, uno::UNO_QUERY );
1619  if( ! xDSCnt.is())
1620  return;
1621  Reference< chart2::XChartType > xChartType( rCT, uno::UNO_QUERY );
1622  if( ! xChartType.is())
1623  continue;
1624  // note: if xDSCnt.is() then also aCTSeq[nCTIdx]
1625  OUString aChartType( xChartType->getChartType());
1626  sal_Int32 eChartType = lcl_getChartType( aChartType );
1627  switch( eChartType )
1628  {
1629  case chart::TYPEID_BAR:
1630  {
1631  exportBarChart( xChartType );
1632  break;
1633  }
1634  case chart::TYPEID_AREA:
1635  {
1636  exportAreaChart( xChartType );
1637  break;
1638  }
1639  case chart::TYPEID_LINE:
1640  {
1641  exportLineChart( xChartType );
1642  break;
1643  }
1644  case chart::TYPEID_BUBBLE:
1645  {
1646  exportBubbleChart( xChartType );
1647  break;
1648  }
1649  case chart::TYPEID_OFPIE:
1650  {
1651  break;
1652  }
1654  case chart::TYPEID_PIE:
1655  {
1656  exportPieChart( xChartType );
1657  break;
1658  }
1661  {
1662  exportRadarChart( xChartType );
1663  break;
1664  }
1665  case chart::TYPEID_SCATTER:
1666  {
1667  exportScatterChart( xChartType );
1668  break;
1669  }
1670  case chart::TYPEID_STOCK:
1671  {
1672  exportStockChart( xChartType );
1673  break;
1674  }
1675  case chart::TYPEID_SURFACE:
1676  {
1677  exportSurfaceChart( xChartType );
1678  break;
1679  }
1680  default:
1681  {
1682  SAL_WARN("oox", "ChartExport::exportPlotArea -- not support chart type");
1683  break;
1684  }
1685  }
1686 
1687  }
1688  }
1689  //Axis Data
1690  exportAxes( );
1691  // Data Table
1692  exportDataTable();
1693 
1694  // shape properties
1695  /*
1696  * Export the Plot area Shape Properties
1697  * eg: Fill and Outline
1698  */
1699  Reference< css::chart::X3DDisplay > xWallFloorSupplier( mxDiagram, uno::UNO_QUERY );
1700  // tdf#114139 For 2D charts Plot Area equivalent is Chart Wall.
1701  // Unfortunately LibreOffice doesn't have Plot Area equivalent for 3D charts.
1702  // It means that Plot Area couldn't be displayed and changed for 3D chars in LibreOffice.
1703  // We cannot write Wall attributes into Plot Area for 3D charts, because Wall us used as background wall.
1704  if( !mbIs3DChart && xWallFloorSupplier.is() )
1705  {
1706  Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall();
1707  if( xWallPropSet.is() )
1708  {
1709  uno::Any aAny = xWallPropSet->getPropertyValue("LineStyle");
1710  sal_Int32 eChartType = getChartType( );
1711  // Export LineStyle_NONE instead of default linestyle of PlotArea border, because LibreOffice
1712  // make invisible the Wall shape properties, in case of these charts. Or in the future set
1713  // the default LineStyle of these charts to LineStyle_NONE.
1714  bool noSupportWallProp = ( (eChartType == chart::TYPEID_PIE) || (eChartType == chart::TYPEID_RADARLINE) || (eChartType == chart::TYPEID_RADARAREA) );
1715  if ( noSupportWallProp && (aAny != drawing::LineStyle_NONE) )
1716  {
1717  xWallPropSet->setPropertyValue( "LineStyle", uno::Any(drawing::LineStyle_NONE) );
1718  }
1719  exportShapeProps( xWallPropSet );
1720  }
1721  }
1722 
1723  pFS->endElement( FSNS( XML_c, XML_plotArea ) );
1724 
1725 }
1726 
1727 void ChartExport::exportManualLayout(const css::chart2::RelativePosition& rPos,
1728  const css::chart2::RelativeSize& rSize,
1729  const bool bIsExcludingDiagramPositioning)
1730 {
1731  FSHelperPtr pFS = GetFS();
1732  pFS->startElement(FSNS(XML_c, XML_layout));
1733  pFS->startElement(FSNS(XML_c, XML_manualLayout));
1734 
1735  // By default layoutTarget is set to "outer" and we shouldn't save it in that case
1736  if ( bIsExcludingDiagramPositioning )
1737  {
1738  pFS->singleElement(FSNS(XML_c, XML_layoutTarget), XML_val, "inner");
1739  }
1740  pFS->singleElement(FSNS(XML_c, XML_xMode), XML_val, "edge");
1741  pFS->singleElement(FSNS(XML_c, XML_yMode), XML_val, "edge");
1742 
1743  double x = rPos.Primary;
1744  double y = rPos.Secondary;
1745  const double w = rSize.Primary;
1746  const double h = rSize.Secondary;
1747  switch (rPos.Anchor)
1748  {
1749  case drawing::Alignment_LEFT:
1750  y -= (h/2);
1751  break;
1752  case drawing::Alignment_TOP_LEFT:
1753  break;
1754  case drawing::Alignment_BOTTOM_LEFT:
1755  y -= h;
1756  break;
1757  case drawing::Alignment_TOP:
1758  x -= (w/2);
1759  break;
1760  case drawing::Alignment_CENTER:
1761  x -= (w/2);
1762  y -= (h/2);
1763  break;
1764  case drawing::Alignment_BOTTOM:
1765  x -= (w/2);
1766  y -= h;
1767  break;
1768  case drawing::Alignment_TOP_RIGHT:
1769  x -= w;
1770  break;
1771  case drawing::Alignment_BOTTOM_RIGHT:
1772  x -= w;
1773  y -= h;
1774  break;
1775  case drawing::Alignment_RIGHT:
1776  y -= (h/2);
1777  x -= w;
1778  break;
1779  default:
1780  SAL_WARN("oox", "unhandled alignment case for manual layout export " << static_cast<sal_uInt16>(rPos.Anchor));
1781  }
1782 
1783  pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(x));
1784 
1785  pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(y));
1786 
1787  pFS->singleElement(FSNS(XML_c, XML_w), XML_val, OString::number(w));
1788 
1789  pFS->singleElement(FSNS(XML_c, XML_h), XML_val, OString::number(h));
1790 
1791  pFS->endElement(FSNS(XML_c, XML_manualLayout));
1792  pFS->endElement(FSNS(XML_c, XML_layout));
1793 }
1794 
1796 {
1797  // Similar to DrawingML::WriteFill, but gradient access via name
1798  if (!GetProperty( xPropSet, "FillStyle" ))
1799  return;
1800  FillStyle aFillStyle(FillStyle_NONE);
1801  mAny >>= aFillStyle;
1802 
1803  // map full transparent background to no fill
1804  if (aFillStyle == FillStyle_SOLID && GetProperty( xPropSet, "FillTransparence" ))
1805  {
1806  sal_Int16 nVal = 0;
1807  mAny >>= nVal;
1808  if ( nVal == 100 )
1809  aFillStyle = FillStyle_NONE;
1810  }
1811  OUString sFillTransparenceGradientName;
1812  if (aFillStyle == FillStyle_SOLID
1813  && GetProperty(xPropSet, "FillTransparenceGradientName") && (mAny >>= sFillTransparenceGradientName)
1814  && !sFillTransparenceGradientName.isEmpty())
1815  {
1816  awt::Gradient aTransparenceGradient;
1817  uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1818  uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1819  uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1820  rTransparenceValue >>= aTransparenceGradient;
1821  if (aTransparenceGradient.StartColor == 0xffffff && aTransparenceGradient.EndColor == 0xffffff)
1822  aFillStyle = FillStyle_NONE;
1823  }
1824  switch( aFillStyle )
1825  {
1826  case FillStyle_SOLID:
1827  exportSolidFill(xPropSet);
1828  break;
1829  case FillStyle_GRADIENT :
1830  exportGradientFill( xPropSet );
1831  break;
1832  case FillStyle_BITMAP :
1833  exportBitmapFill( xPropSet );
1834  break;
1835  case FillStyle_HATCH:
1836  exportHatch(xPropSet);
1837  break;
1838  case FillStyle_NONE:
1839  mpFS->singleElementNS(XML_a, XML_noFill);
1840  break;
1841  default:
1842  ;
1843  }
1844 }
1845 
1847 {
1848  // Similar to DrawingML::WriteSolidFill, but gradient access via name
1849  // and currently no InteropGrabBag
1850  // get fill color
1851  if (!GetProperty( xPropSet, "FillColor" ))
1852  return;
1853  sal_uInt32 nFillColor = mAny.get<sal_uInt32>();
1854 
1855  sal_Int32 nAlpha = MAX_PERCENT;
1856  if (GetProperty( xPropSet, "FillTransparence" ))
1857  {
1858  sal_Int32 nTransparency = 0;
1859  mAny >>= nTransparency;
1860  // Calculate alpha value (see oox/source/drawingml/color.cxx : getTransparency())
1861  nAlpha = (MAX_PERCENT - ( PER_PERCENT * nTransparency ) );
1862  }
1863  // OOXML has no separate transparence gradient but uses transparency in the gradient stops.
1864  // So we merge transparency and color and use gradient fill in such case.
1865  awt::Gradient aTransparenceGradient;
1866  bool bNeedGradientFill(false);
1867  OUString sFillTransparenceGradientName;
1868  if (GetProperty(xPropSet, "FillTransparenceGradientName")
1869  && (mAny >>= sFillTransparenceGradientName)
1870  && !sFillTransparenceGradientName.isEmpty())
1871  {
1872  uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1873  uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1874  uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1875  rTransparenceValue >>= aTransparenceGradient;
1876  if (aTransparenceGradient.StartColor != aTransparenceGradient.EndColor)
1877  bNeedGradientFill = true;
1878  else if (aTransparenceGradient.StartColor != 0)
1879  nAlpha = lcl_getAlphaFromTransparenceGradient(aTransparenceGradient, true);
1880  }
1881  // write XML
1882  if (bNeedGradientFill)
1883  {
1884  awt::Gradient aPseudoColorGradient;
1885  aPseudoColorGradient.XOffset = aTransparenceGradient.XOffset;
1886  aPseudoColorGradient.YOffset = aTransparenceGradient.YOffset;
1887  aPseudoColorGradient.StartIntensity = 100;
1888  aPseudoColorGradient.EndIntensity = 100;
1889  aPseudoColorGradient.Angle = aTransparenceGradient.Angle;
1890  aPseudoColorGradient.Border = aTransparenceGradient.Border;
1891  aPseudoColorGradient.Style = aTransparenceGradient.Style;
1892  aPseudoColorGradient.StartColor = nFillColor;
1893  aPseudoColorGradient.EndColor = nFillColor;
1894  aPseudoColorGradient.StepCount = aTransparenceGradient.StepCount;
1895  mpFS->startElementNS(XML_a, XML_gradFill, XML_rotWithShape, "0");
1896  WriteGradientFill(aPseudoColorGradient, aTransparenceGradient);
1897  mpFS->endElementNS(XML_a, XML_gradFill);
1898  }
1899  else
1900  WriteSolidFill(::Color(ColorTransparency, nFillColor & 0xffffff), nAlpha);
1901 }
1902 
1904 {
1905  if (!xPropSet.is())
1906  return;
1907 
1908  if (GetProperty(xPropSet, "FillHatchName"))
1909  {
1910  OUString aHatchName;
1911  mAny >>= aHatchName;
1912  uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1913  uno::Reference< container::XNameAccess > xHatchTable( xFact->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY );
1914  uno::Any rValue = xHatchTable->getByName(aHatchName);
1915  css::drawing::Hatch aHatch;
1916  rValue >>= aHatch;
1917  WritePattFill(xPropSet, aHatch);
1918  }
1919 
1920 }
1921 
1923 {
1924  if( !xPropSet.is() )
1925  return;
1926 
1927  OUString sFillBitmapName;
1928  xPropSet->getPropertyValue("FillBitmapName") >>= sFillBitmapName;
1929 
1930  uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1931  try
1932  {
1933  uno::Reference< container::XNameAccess > xBitmapTable( xFact->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY );
1934  uno::Any rValue = xBitmapTable->getByName( sFillBitmapName );
1935  if (rValue.has<uno::Reference<awt::XBitmap>>())
1936  {
1937  uno::Reference<awt::XBitmap> xBitmap = rValue.get<uno::Reference<awt::XBitmap>>();
1938  uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1939  if (xGraphic.is())
1940  {
1941  WriteXGraphicBlipFill(xPropSet, xGraphic, XML_a, true, true);
1942  }
1943  }
1944  }
1945  catch (const uno::Exception &)
1946  {
1947  TOOLS_WARN_EXCEPTION("oox", "ChartExport::exportBitmapFill");
1948  }
1949 }
1950 
1952 {
1953  if( !xPropSet.is() )
1954  return;
1955 
1956  OUString sFillGradientName;
1957  xPropSet->getPropertyValue("FillGradientName") >>= sFillGradientName;
1958 
1959  uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
1960  try
1961  {
1962  uno::Reference< container::XNameAccess > xGradient( xFact->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY );
1963  uno::Any rGradientValue = xGradient->getByName( sFillGradientName );
1964  awt::Gradient aGradient;
1965  if( rGradientValue >>= aGradient )
1966  {
1967  awt::Gradient aTransparenceGradient;
1968  mpFS->startElementNS(XML_a, XML_gradFill);
1969  OUString sFillTransparenceGradientName;
1970  if( (xPropSet->getPropertyValue("FillTransparenceGradientName") >>= sFillTransparenceGradientName) && !sFillTransparenceGradientName.isEmpty())
1971  {
1972  uno::Reference< container::XNameAccess > xTransparenceGradient(xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY);
1973  uno::Any rTransparenceValue = xTransparenceGradient->getByName(sFillTransparenceGradientName);
1974  rTransparenceValue >>= aTransparenceGradient;
1975  WriteGradientFill(aGradient, aTransparenceGradient);
1976  }
1977  else
1978  {
1979  WriteGradientFill(aGradient, aTransparenceGradient, xPropSet);
1980  }
1981  mpFS->endElementNS(XML_a, XML_gradFill);
1982  }
1983  }
1984  catch (const uno::Exception &)
1985  {
1986  TOOLS_INFO_EXCEPTION("oox", "ChartExport::exportGradientFill");
1987  }
1988 }
1989 
1991 {
1992  FSHelperPtr pFS = GetFS();
1993  Reference< beans::XPropertySet > aPropSet( mxDiagram, uno::UNO_QUERY );
1994 
1995  bool bShowVBorder = false;
1996  bool bShowHBorder = false;
1997  bool bShowOutline = false;
1998 
1999  if (GetProperty( aPropSet, "DataTableHBorder"))
2000  mAny >>= bShowHBorder;
2001  if (GetProperty( aPropSet, "DataTableVBorder"))
2002  mAny >>= bShowVBorder;
2003  if (GetProperty( aPropSet, "DataTableOutline"))
2004  mAny >>= bShowOutline;
2005 
2006  if (!(bShowVBorder || bShowHBorder || bShowOutline))
2007  return;
2008 
2009  pFS->startElement(FSNS(XML_c, XML_dTable));
2010  if (bShowHBorder)
2011  pFS->singleElement( FSNS( XML_c, XML_showHorzBorder ),
2012  XML_val, "1" );
2013  if (bShowVBorder)
2014  pFS->singleElement(FSNS(XML_c, XML_showVertBorder), XML_val, "1");
2015  if (bShowOutline)
2016  pFS->singleElement(FSNS(XML_c, XML_showOutline), XML_val, "1");
2017 
2018  pFS->endElement( FSNS( XML_c, XML_dTable));
2019 
2020 }
2022 {
2023  FSHelperPtr pFS = GetFS();
2024  const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2025  for (const auto& splitDataSeries : aSplitDataSeries)
2026  {
2027  if (!splitDataSeries.hasElements())
2028  continue;
2029 
2030  sal_Int32 nTypeId = XML_areaChart;
2031  if (mbIs3DChart)
2032  nTypeId = XML_area3DChart;
2033  pFS->startElement(FSNS(XML_c, nTypeId));
2034 
2035  exportGrouping();
2036  bool bPrimaryAxes = true;
2037  exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2038  exportAxesId(bPrimaryAxes);
2039 
2040  pFS->endElement(FSNS(XML_c, nTypeId));
2041  }
2042 }
2043 
2045 {
2046  sal_Int32 nTypeId = XML_barChart;
2047  if (mbIs3DChart)
2048  nTypeId = XML_bar3DChart;
2049  FSHelperPtr pFS = GetFS();
2050 
2051  const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2052  for (const auto& splitDataSeries : aSplitDataSeries)
2053  {
2054  if (!splitDataSeries.hasElements())
2055  continue;
2056 
2057  pFS->startElement(FSNS(XML_c, nTypeId));
2058  // bar direction
2059  bool bVertical = false;
2060  Reference< XPropertySet > xPropSet(mxDiagram, uno::UNO_QUERY);
2061  if (GetProperty(xPropSet, "Vertical"))
2062  mAny >>= bVertical;
2063 
2064  const char* bardir = bVertical ? "bar" : "col";
2065  pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, bardir);
2066 
2067  exportGrouping(true);
2068 
2069  exportVaryColors(xChartType);
2070 
2071  bool bPrimaryAxes = true;
2072  exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2073 
2074  Reference< XPropertySet > xTypeProp(xChartType, uno::UNO_QUERY);
2075 
2076  if (xTypeProp.is() && GetProperty(xTypeProp, "GapwidthSequence"))
2077  {
2078  uno::Sequence< sal_Int32 > aBarPositionSequence;
2079  mAny >>= aBarPositionSequence;
2080  if (aBarPositionSequence.hasElements())
2081  {
2082  sal_Int32 nGapWidth = aBarPositionSequence[0];
2083  pFS->singleElement(FSNS(XML_c, XML_gapWidth), XML_val, OString::number(nGapWidth));
2084  }
2085  }
2086 
2087  if (mbIs3DChart)
2088  {
2089  // Shape
2090  namespace cssc = css::chart;
2091  sal_Int32 nGeom3d = cssc::ChartSolidType::RECTANGULAR_SOLID;
2092  if (xPropSet.is() && GetProperty(xPropSet, "SolidType"))
2093  mAny >>= nGeom3d;
2094  const char* sShapeType = nullptr;
2095  switch (nGeom3d)
2096  {
2097  case cssc::ChartSolidType::RECTANGULAR_SOLID:
2098  sShapeType = "box";
2099  break;
2100  case cssc::ChartSolidType::CONE:
2101  sShapeType = "cone";
2102  break;
2103  case cssc::ChartSolidType::CYLINDER:
2104  sShapeType = "cylinder";
2105  break;
2106  case cssc::ChartSolidType::PYRAMID:
2107  sShapeType = "pyramid";
2108  break;
2109  }
2110  pFS->singleElement(FSNS(XML_c, XML_shape), XML_val, sShapeType);
2111  }
2112 
2113  //overlap
2114  if (!mbIs3DChart && xTypeProp.is() && GetProperty(xTypeProp, "OverlapSequence"))
2115  {
2116  uno::Sequence< sal_Int32 > aBarPositionSequence;
2117  mAny >>= aBarPositionSequence;
2118  if (aBarPositionSequence.hasElements())
2119  {
2120  sal_Int32 nOverlap = aBarPositionSequence[0];
2121  // Stacked/Percent Bar/Column chart Overlap-workaround
2122  // Export the Overlap value with 100% for stacked charts,
2123  // because the default overlap value of the Bar/Column chart is 0% and
2124  // LibreOffice do nothing with the overlap value in Stacked charts case,
2125  // unlike the MS Office, which is interpreted differently.
2126  if ((mbStacked || mbPercent) && nOverlap != 100)
2127  {
2128  nOverlap = 100;
2129  pFS->singleElement(FSNS(XML_c, XML_overlap), XML_val, OString::number(nOverlap));
2130  }
2131  else // Normal bar chart
2132  {
2133  pFS->singleElement(FSNS(XML_c, XML_overlap), XML_val, OString::number(nOverlap));
2134  }
2135  }
2136  }
2137 
2138  exportAxesId(bPrimaryAxes);
2139 
2140  pFS->endElement(FSNS(XML_c, nTypeId));
2141  }
2142 }
2143 
2145 {
2146  FSHelperPtr pFS = GetFS();
2147  const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2148  for (const auto& splitDataSeries : aSplitDataSeries)
2149  {
2150  if (!splitDataSeries.hasElements())
2151  continue;
2152 
2153  pFS->startElement(FSNS(XML_c, XML_bubbleChart));
2154 
2155  exportVaryColors(xChartType);
2156 
2157  bool bPrimaryAxes = true;
2158  exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2159 
2160  exportAxesId(bPrimaryAxes);
2161 
2162  pFS->endElement(FSNS(XML_c, XML_bubbleChart));
2163  }
2164 }
2165 
2167 {
2168  FSHelperPtr pFS = GetFS();
2169  pFS->startElement(FSNS(XML_c, XML_doughnutChart));
2170 
2171  exportVaryColors(xChartType);
2172 
2173  bool bPrimaryAxes = true;
2174  exportAllSeries(xChartType, bPrimaryAxes);
2175  // firstSliceAng
2177  //FIXME: holeSize
2178  pFS->singleElement(FSNS(XML_c, XML_holeSize), XML_val, OString::number(50));
2179 
2180  pFS->endElement( FSNS( XML_c, XML_doughnutChart ) );
2181 }
2182 
2184 {
2185  FSHelperPtr pFS = GetFS();
2186  const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2187  for (const auto& splitDataSeries : aSplitDataSeries)
2188  {
2189  if (!splitDataSeries.hasElements())
2190  continue;
2191 
2192  sal_Int32 nTypeId = XML_lineChart;
2193  if( mbIs3DChart )
2194  nTypeId = XML_line3DChart;
2195  pFS->startElement(FSNS(XML_c, nTypeId));
2196 
2197  exportGrouping( );
2198 
2199  exportVaryColors(xChartType);
2200  // TODO: show marker symbol in series?
2201  bool bPrimaryAxes = true;
2202  exportSeries(xChartType, splitDataSeries, bPrimaryAxes);
2203 
2204  // show marker?
2205  sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
2206  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
2207  if( GetProperty( xPropSet, "SymbolType" ) )
2208  mAny >>= nSymbolType;
2209 
2210  if( !mbIs3DChart )
2211  {
2212  exportHiLowLines();
2213  exportUpDownBars(xChartType);
2214  const char* marker = nSymbolType == css::chart::ChartSymbolType::NONE? "0":"1";
2215  pFS->singleElement(FSNS(XML_c, XML_marker), XML_val, marker);
2216  }
2217 
2218  exportAxesId(bPrimaryAxes, true);
2219 
2220  pFS->endElement( FSNS( XML_c, nTypeId ) );
2221  }
2222 }
2223 
2225 {
2226  sal_Int32 eChartType = getChartType( );
2227  if(eChartType == chart::TYPEID_DOUGHNUT)
2228  {
2229  exportDoughnutChart( xChartType );
2230  return;
2231  }
2232  FSHelperPtr pFS = GetFS();
2233  sal_Int32 nTypeId = XML_pieChart;
2234  if( mbIs3DChart )
2235  nTypeId = XML_pie3DChart;
2236  pFS->startElement(FSNS(XML_c, nTypeId));
2237 
2238  exportVaryColors(xChartType);
2239 
2240  bool bPrimaryAxes = true;
2241  exportAllSeries(xChartType, bPrimaryAxes);
2242 
2243  if( !mbIs3DChart )
2244  {
2245  // firstSliceAng
2247  }
2248 
2249  pFS->endElement( FSNS( XML_c, nTypeId ) );
2250 }
2251 
2253 {
2254  FSHelperPtr pFS = GetFS();
2255  pFS->startElement(FSNS(XML_c, XML_radarChart));
2256 
2257  // radarStyle
2258  sal_Int32 eChartType = getChartType( );
2259  const char* radarStyle = nullptr;
2260  if( eChartType == chart::TYPEID_RADARAREA )
2261  radarStyle = "filled";
2262  else
2263  radarStyle = "marker";
2264  pFS->singleElement(FSNS(XML_c, XML_radarStyle), XML_val, radarStyle);
2265 
2266  exportVaryColors(xChartType);
2267  bool bPrimaryAxes = true;
2268  exportAllSeries(xChartType, bPrimaryAxes);
2269  exportAxesId(bPrimaryAxes);
2270 
2271  pFS->endElement( FSNS( XML_c, XML_radarChart ) );
2272 }
2273 
2275  const css::uno::Sequence<css::uno::Reference<chart2::XDataSeries>>* pSeries)
2276 {
2277  FSHelperPtr pFS = GetFS();
2278  pFS->startElement(FSNS(XML_c, XML_scatterChart));
2279  // TODO:scatterStyle
2280 
2281  sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE;
2282  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
2283  if( GetProperty( xPropSet, "SymbolType" ) )
2284  mAny >>= nSymbolType;
2285 
2286  const char* scatterStyle = "lineMarker";
2287  if (nSymbolType == css::chart::ChartSymbolType::NONE)
2288  {
2289  scatterStyle = "line";
2290  }
2291 
2292  pFS->singleElement(FSNS(XML_c, XML_scatterStyle), XML_val, scatterStyle);
2293 
2294  exportVaryColors(xChartType);
2295  // FIXME: should export xVal and yVal
2296  bool bPrimaryAxes = true;
2297  if (pSeries)
2298  exportSeries(xChartType, *pSeries, bPrimaryAxes);
2299  exportAxesId(bPrimaryAxes);
2300 
2301  pFS->endElement( FSNS( XML_c, XML_scatterChart ) );
2302 }
2303 
2305 {
2306  const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2307  bool bExported = false;
2308  for (const auto& splitDataSeries : aSplitDataSeries)
2309  {
2310  if (!splitDataSeries.hasElements())
2311  continue;
2312 
2313  bExported = true;
2314  exportScatterChartSeries(xChartType, &splitDataSeries);
2315  }
2316  if (!bExported)
2317  exportScatterChartSeries(xChartType, nullptr);
2318 }
2319 
2321 {
2322  FSHelperPtr pFS = GetFS();
2323  const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType);
2324  for (const auto& splitDataSeries : aSplitDataSeries)
2325  {
2326  if (!splitDataSeries.hasElements())
2327  continue;
2328 
2329  pFS->startElement(FSNS(XML_c, XML_stockChart));
2330 
2331  bool bPrimaryAxes = true;
2332  exportCandleStickSeries(splitDataSeries, bPrimaryAxes);
2333 
2334  // export stock properties
2335  Reference< css::chart::XStatisticDisplay > xStockPropProvider(mxDiagram, uno::UNO_QUERY);
2336  if (xStockPropProvider.is())
2337  {
2338  exportHiLowLines();
2339  exportUpDownBars(xChartType);
2340  }
2341 
2342  exportAxesId(bPrimaryAxes);
2343 
2344  pFS->endElement(FSNS(XML_c, XML_stockChart));
2345  }
2346 }
2347 
2349 {
2350  FSHelperPtr pFS = GetFS();
2351  // export the chart property
2352  Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
2353 
2354  if (!xChartPropProvider.is())
2355  return;
2356 
2357  Reference< beans::XPropertySet > xStockPropSet = xChartPropProvider->getMinMaxLine();
2358  if( !xStockPropSet.is() )
2359  return;
2360 
2361  pFS->startElement(FSNS(XML_c, XML_hiLowLines));
2362  exportShapeProps( xStockPropSet );
2363  pFS->endElement( FSNS( XML_c, XML_hiLowLines ) );
2364 }
2365 
2367 {
2368  if(xChartType->getChartType() != "com.sun.star.chart2.CandleStickChartType")
2369  return;
2370 
2371  FSHelperPtr pFS = GetFS();
2372  // export the chart property
2373  Reference< css::chart::XStatisticDisplay > xChartPropProvider( mxDiagram, uno::UNO_QUERY );
2374  if(!xChartPropProvider.is())
2375  return;
2376 
2377  // updownbar
2378  pFS->startElement(FSNS(XML_c, XML_upDownBars));
2379  // TODO: gapWidth
2380  pFS->singleElement(FSNS(XML_c, XML_gapWidth), XML_val, OString::number(150));
2381 
2382  Reference< beans::XPropertySet > xChartPropSet = xChartPropProvider->getUpBar();
2383  if( xChartPropSet.is() )
2384  {
2385  pFS->startElement(FSNS(XML_c, XML_upBars));
2386  // For Linechart with UpDownBars, spPr is not getting imported
2387  // so no need to call the exportShapeProps() for LineChart
2388  if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
2389  {
2390  exportShapeProps(xChartPropSet);
2391  }
2392  pFS->endElement( FSNS( XML_c, XML_upBars ) );
2393  }
2394  xChartPropSet = xChartPropProvider->getDownBar();
2395  if( xChartPropSet.is() )
2396  {
2397  pFS->startElement(FSNS(XML_c, XML_downBars));
2398  if(xChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType")
2399  {
2400  exportShapeProps(xChartPropSet);
2401  }
2402  pFS->endElement( FSNS( XML_c, XML_downBars ) );
2403  }
2404  pFS->endElement( FSNS( XML_c, XML_upDownBars ) );
2405 }
2406 
2408 {
2409  FSHelperPtr pFS = GetFS();
2410  sal_Int32 nTypeId = XML_surfaceChart;
2411  if( mbIs3DChart )
2412  nTypeId = XML_surface3DChart;
2413  pFS->startElement(FSNS(XML_c, nTypeId));
2414  exportVaryColors(xChartType);
2415  bool bPrimaryAxes = true;
2416  exportAllSeries(xChartType, bPrimaryAxes);
2417  exportAxesId(bPrimaryAxes);
2418 
2419  pFS->endElement( FSNS( XML_c, nTypeId ) );
2420 }
2421 
2422 void ChartExport::exportAllSeries(const Reference<chart2::XChartType>& xChartType, bool& rPrimaryAxes)
2423 {
2424  Reference< chart2::XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY );
2425  if( ! xDSCnt.is())
2426  return;
2427 
2428  // export dataseries for current chart-type
2429  Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries());
2430  exportSeries(xChartType, aSeriesSeq, rPrimaryAxes);
2431 }
2432 
2434 {
2435  FSHelperPtr pFS = GetFS();
2436  try
2437  {
2438  Reference<chart2::XDataSeries> xDataSeries = getPrimaryDataSeries(xChartType);
2439  Reference<beans::XPropertySet> xDataSeriesProps(xDataSeries, uno::UNO_QUERY_THROW);
2440  Any aAnyVaryColors = xDataSeriesProps->getPropertyValue("VaryColorsByPoint");
2441  bool bVaryColors = false;
2442  aAnyVaryColors >>= bVaryColors;
2443  pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, ToPsz10(bVaryColors));
2444  }
2445  catch (...)
2446  {
2447  pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
2448  }
2449 }
2450 
2452  const Sequence<Reference<chart2::XDataSeries> >& rSeriesSeq, bool& rPrimaryAxes )
2453 {
2454  OUString aLabelRole = xChartType->getRoleOfSequenceForSeriesLabel();
2455  OUString aChartType( xChartType->getChartType());
2456  sal_Int32 eChartType = lcl_getChartType( aChartType );
2457 
2458  for( const auto& rSeries : rSeriesSeq )
2459  {
2460  // export series
2461  Reference< chart2::data::XDataSource > xSource( rSeries, uno::UNO_QUERY );
2462  if( xSource.is())
2463  {
2464  Reference< chart2::XDataSeries > xDataSeries( xSource, uno::UNO_QUERY );
2466  xSource->getDataSequences());
2467  // search for main sequence and create a series element
2468  {
2469  sal_Int32 nMainSequenceIndex = -1;
2470  sal_Int32 nSeriesLength = 0;
2473  sal_Int32 nSeqIdx=0;
2474  for( ; nSeqIdx<aSeqCnt.getLength(); ++nSeqIdx )
2475  {
2476  Reference< chart2::data::XDataSequence > xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() );
2477  if( nMainSequenceIndex==-1 )
2478  {
2479  Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY );
2480  OUString aRole;
2481  if( xSeqProp.is())
2482  xSeqProp->getPropertyValue("Role") >>= aRole;
2483  // "main" sequence
2484  if( aRole == aLabelRole )
2485  {
2486  xValuesSeq.set( xTempValueSeq );
2487  xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel());
2488  nMainSequenceIndex = nSeqIdx;
2489  }
2490  }
2491  sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0));
2492  if( nSeriesLength < nSequenceLength )
2493  nSeriesLength = nSequenceLength;
2494  }
2495 
2496  // have found the main sequence, then xValuesSeq and
2497  // xLabelSeq contain those. Otherwise both are empty
2498  {
2499  FSHelperPtr pFS = GetFS();
2500 
2501  pFS->startElement(FSNS(XML_c, XML_ser));
2502 
2503  // TODO: idx and order
2504  pFS->singleElement( FSNS( XML_c, XML_idx ),
2505  XML_val, OString::number(mnSeriesCount) );
2506  pFS->singleElement( FSNS( XML_c, XML_order ),
2507  XML_val, OString::number(mnSeriesCount++) );
2508 
2509  // export label
2510  if( xLabelSeq.is() )
2511  exportSeriesText( xLabelSeq );
2512 
2513  Reference<XPropertySet> xPropSet(xDataSeries, UNO_QUERY_THROW);
2514  if( GetProperty( xPropSet, "AttachedAxisIndex") )
2515  {
2516  sal_Int32 nLocalAttachedAxis = 0;
2517  mAny >>= nLocalAttachedAxis;
2518  rPrimaryAxes = isPrimaryAxes(nLocalAttachedAxis);
2519  }
2520 
2521  // export shape properties
2523  rSeries, getModel() );
2524  if( xOldPropSet.is() )
2525  {
2526  exportShapeProps( xOldPropSet );
2527  }
2528 
2529  switch( eChartType )
2530  {
2531  case chart::TYPEID_BUBBLE:
2532  case chart::TYPEID_HORBAR:
2533  case chart::TYPEID_BAR:
2534  {
2535  pFS->singleElement(FSNS(XML_c, XML_invertIfNegative), XML_val, "0");
2536  }
2537  break;
2538  case chart::TYPEID_LINE:
2539  {
2540  exportMarker(xOldPropSet);
2541  break;
2542  }
2543  case chart::TYPEID_PIE:
2545  {
2546  if( xOldPropSet.is() && GetProperty( xOldPropSet, "SegmentOffset") )
2547  {
2548  sal_Int32 nOffset = 0;
2549  mAny >>= nOffset;
2550  pFS->singleElement( FSNS( XML_c, XML_explosion ),
2551  XML_val, OString::number( nOffset ) );
2552  }
2553  break;
2554  }
2555  case chart::TYPEID_SCATTER:
2556  {
2557  exportMarker(xOldPropSet);
2558  break;
2559  }
2561  {
2562  exportMarker(xOldPropSet);
2563  break;
2564  }
2565  }
2566 
2567  // export data points
2568  exportDataPoints( uno::Reference< beans::XPropertySet >( rSeries, uno::UNO_QUERY ), nSeriesLength, eChartType );
2569 
2570  // export data labels
2571  exportDataLabels(rSeries, nSeriesLength, eChartType);
2572 
2573  exportTrendlines( rSeries );
2574 
2575  if( eChartType != chart::TYPEID_PIE &&
2576  eChartType != chart::TYPEID_RADARLINE )
2577  {
2578  //export error bars here
2579  Reference< XPropertySet > xSeriesPropSet( xSource, uno::UNO_QUERY );
2580  Reference< XPropertySet > xErrorBarYProps;
2581  xSeriesPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarYProps;
2582  if(xErrorBarYProps.is())
2583  exportErrorBar(xErrorBarYProps, true);
2584  if (eChartType != chart::TYPEID_BAR &&
2585  eChartType != chart::TYPEID_HORBAR)
2586  {
2587  Reference< XPropertySet > xErrorBarXProps;
2588  xSeriesPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarXProps;
2589  if(xErrorBarXProps.is())
2590  exportErrorBar(xErrorBarXProps, false);
2591  }
2592  }
2593 
2594  // export categories
2595  if( eChartType != chart::TYPEID_SCATTER && eChartType != chart::TYPEID_BUBBLE && mxCategoriesValues.is() )
2597 
2598  if( (eChartType == chart::TYPEID_SCATTER)
2599  || (eChartType == chart::TYPEID_BUBBLE) )
2600  {
2601  // export xVal
2603  if( xSequence.is() )
2604  {
2605  Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2606  if( xValues.is() )
2607  exportSeriesValues( xValues, XML_xVal );
2608  }
2609  else if( mxCategoriesValues.is() )
2611  }
2612 
2613  if( eChartType == chart::TYPEID_BUBBLE )
2614  {
2615  // export yVal
2617  if( xSequence.is() )
2618  {
2619  Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() );
2620  if( xValues.is() )
2621  exportSeriesValues( xValues, XML_yVal );
2622  }
2623  }
2624 
2625  // export values
2626  if( xValuesSeq.is() )
2627  {
2628  sal_Int32 nYValueType = XML_val;
2629  if( eChartType == chart::TYPEID_SCATTER )
2630  nYValueType = XML_yVal;
2631  else if( eChartType == chart::TYPEID_BUBBLE )
2632  nYValueType = XML_bubbleSize;
2633  exportSeriesValues( xValuesSeq, nYValueType );
2634  }
2635 
2636  if( eChartType == chart::TYPEID_SCATTER
2637  || eChartType == chart::TYPEID_LINE )
2638  exportSmooth();
2639 
2640  // tdf103988: "corrupted" files with Bubble chart opening in MSO
2641  if( eChartType == chart::TYPEID_BUBBLE )
2642  pFS->singleElement(FSNS(XML_c, XML_bubble3D), XML_val, "0");
2643 
2644  pFS->endElement( FSNS( XML_c, XML_ser ) );
2645  }
2646  }
2647  }
2648  }
2649 }
2650 
2652  const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq,
2653  bool& rPrimaryAxes)
2654 {
2655  for( const Reference< chart2::XDataSeries >& xSeries : aSeriesSeq )
2656  {
2657  rPrimaryAxes = lcl_isSeriesAttachedToFirstAxis(xSeries);
2658 
2659  Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
2660  if( xSource.is())
2661  {
2662  // export series in correct order (as we don't store roles)
2663  // with japanese candlesticks: open, low, high, close
2664  // otherwise: low, high, close
2666  xSource->getDataSequences());
2667 
2668  const char* sSeries[] = {"values-first","values-max","values-min","values-last",nullptr};
2669 
2670  for( sal_Int32 idx = 0; sSeries[idx] != nullptr ; idx++ )
2671  {
2672  Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( lcl_getDataSequenceByRole( aSeqCnt, OUString::createFromAscii(sSeries[idx]) ) );
2673  if( xLabeledSeq.is())
2674  {
2675  Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel());
2676  Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues());
2677  {
2678  FSHelperPtr pFS = GetFS();
2679  pFS->startElement(FSNS(XML_c, XML_ser));
2680 
2681  // TODO: idx and order
2682  // idx attribute should start from 1 and not from 0.
2683  pFS->singleElement( FSNS( XML_c, XML_idx ),
2684  XML_val, OString::number(idx+1) );
2685  pFS->singleElement( FSNS( XML_c, XML_order ),
2686  XML_val, OString::number(idx+1) );
2687 
2688  // export label
2689  if( xLabelSeq.is() )
2690  exportSeriesText( xLabelSeq );
2691 
2692  // TODO:export shape properties
2693 
2694  // export categories
2695  if( mxCategoriesValues.is() )
2697 
2698  // export values
2699  if( xValueSeq.is() )
2700  exportSeriesValues( xValueSeq );
2701 
2702  pFS->endElement( FSNS( XML_c, XML_ser ) );
2703  }
2704  }
2705  }
2706  }
2707  }
2708 }
2709 
2711 {
2712  FSHelperPtr pFS = GetFS();
2713  pFS->startElement(FSNS(XML_c, XML_tx));
2714 
2715  OUString aCellRange = xValueSeq->getSourceRangeRepresentation();
2716  aCellRange = parseFormula( aCellRange );
2717  pFS->startElement(FSNS(XML_c, XML_strRef));
2718 
2719  pFS->startElement(FSNS(XML_c, XML_f));
2720  pFS->writeEscaped( aCellRange );
2721  pFS->endElement( FSNS( XML_c, XML_f ) );
2722 
2723  OUString aLabelString = lcl_flattenStringSequence(lcl_getLabelSequence(xValueSeq));
2724  pFS->startElement(FSNS(XML_c, XML_strCache));
2725  pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, "1");
2726  pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, "0");
2727  pFS->startElement(FSNS(XML_c, XML_v));
2728  pFS->writeEscaped( aLabelString );
2729  pFS->endElement( FSNS( XML_c, XML_v ) );
2730  pFS->endElement( FSNS( XML_c, XML_pt ) );
2731  pFS->endElement( FSNS( XML_c, XML_strCache ) );
2732  pFS->endElement( FSNS( XML_c, XML_strRef ) );
2733  pFS->endElement( FSNS( XML_c, XML_tx ) );
2734 }
2735 
2737 {
2738  FSHelperPtr pFS = GetFS();
2739  pFS->startElement(FSNS(XML_c, nValueType));
2740 
2741  OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2742  const Sequence< Sequence< OUString >> aFinalSplitSource = (nValueType == XML_cat) ? getSplitCategoriesList(aCellRange) : Sequence< Sequence< OUString>>(0);
2743  aCellRange = parseFormula( aCellRange );
2744 
2745  if(aFinalSplitSource.getLength() > 1)
2746  {
2747  // export multi level category axis labels
2748  pFS->startElement(FSNS(XML_c, XML_multiLvlStrRef));
2749 
2750  pFS->startElement(FSNS(XML_c, XML_f));
2751  pFS->writeEscaped(aCellRange);
2752  pFS->endElement(FSNS(XML_c, XML_f));
2753 
2754  pFS->startElement(FSNS(XML_c, XML_multiLvlStrCache));
2755  pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(aFinalSplitSource[0].getLength()));
2756  for(const auto& rSeq : aFinalSplitSource)
2757  {
2758  pFS->startElement(FSNS(XML_c, XML_lvl));
2759  for(sal_Int32 j = 0; j < rSeq.getLength(); j++)
2760  {
2761  if(!rSeq[j].isEmpty())
2762  {
2763  pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(j));
2764  pFS->startElement(FSNS(XML_c, XML_v));
2765  pFS->writeEscaped(rSeq[j]);
2766  pFS->endElement(FSNS(XML_c, XML_v));
2767  pFS->endElement(FSNS(XML_c, XML_pt));
2768  }
2769  }
2770  pFS->endElement(FSNS(XML_c, XML_lvl));
2771  }
2772 
2773  pFS->endElement(FSNS(XML_c, XML_multiLvlStrCache));
2774  pFS->endElement(FSNS(XML_c, XML_multiLvlStrRef));
2775  }
2776  else
2777  {
2778  // export single category axis labels
2779  pFS->startElement(FSNS(XML_c, XML_strRef));
2780 
2781  pFS->startElement(FSNS(XML_c, XML_f));
2782  pFS->writeEscaped(aCellRange);
2783  pFS->endElement(FSNS(XML_c, XML_f));
2784 
2785  ::std::vector< OUString > aCategories;
2786  lcl_fillCategoriesIntoStringVector(xValueSeq, aCategories);
2787  sal_Int32 ptCount = aCategories.size();
2788  pFS->startElement(FSNS(XML_c, XML_strCache));
2789  pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(ptCount));
2790  for (sal_Int32 i = 0; i < ptCount; i++)
2791  {
2792  pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(i));
2793  pFS->startElement(FSNS(XML_c, XML_v));
2794  pFS->writeEscaped(aCategories[i]);
2795  pFS->endElement(FSNS(XML_c, XML_v));
2796  pFS->endElement(FSNS(XML_c, XML_pt));
2797  }
2798 
2799  pFS->endElement(FSNS(XML_c, XML_strCache));
2800  pFS->endElement(FSNS(XML_c, XML_strRef));
2801  }
2802 
2803  pFS->endElement( FSNS( XML_c, nValueType ) );
2804 }
2805 
2806 void ChartExport::exportSeriesValues( const Reference< chart2::data::XDataSequence > & xValueSeq, sal_Int32 nValueType )
2807 {
2808  FSHelperPtr pFS = GetFS();
2809  pFS->startElement(FSNS(XML_c, nValueType));
2810 
2811  OUString aCellRange = xValueSeq.is() ? xValueSeq->getSourceRangeRepresentation() : OUString();
2812  aCellRange = parseFormula( aCellRange );
2813  // TODO: need to handle XML_multiLvlStrRef according to aCellRange
2814  pFS->startElement(FSNS(XML_c, XML_numRef));
2815 
2816  pFS->startElement(FSNS(XML_c, XML_f));
2817  pFS->writeEscaped( aCellRange );
2818  pFS->endElement( FSNS( XML_c, XML_f ) );
2819 
2820  ::std::vector< double > aValues = lcl_getAllValuesFromSequence( xValueSeq );
2821  sal_Int32 ptCount = aValues.size();
2822  pFS->startElement(FSNS(XML_c, XML_numCache));
2823  pFS->startElement(FSNS(XML_c, XML_formatCode));
2824  // TODO: what format code?
2825  pFS->writeEscaped( "General" );
2826  pFS->endElement( FSNS( XML_c, XML_formatCode ) );
2827  pFS->singleElement(FSNS(XML_c, XML_ptCount), XML_val, OString::number(ptCount));
2828 
2829  for( sal_Int32 i = 0; i < ptCount; i++ )
2830  {
2831  if (!std::isnan(aValues[i]))
2832  {
2833  pFS->startElement(FSNS(XML_c, XML_pt), XML_idx, OString::number(i));
2834  pFS->startElement(FSNS(XML_c, XML_v));
2835  pFS->write(aValues[i]);
2836  pFS->endElement(FSNS(XML_c, XML_v));
2837  pFS->endElement(FSNS(XML_c, XML_pt));
2838  }
2839  }
2840 
2841  pFS->endElement( FSNS( XML_c, XML_numCache ) );
2842  pFS->endElement( FSNS( XML_c, XML_numRef ) );
2843  pFS->endElement( FSNS( XML_c, nValueType ) );
2844 }
2845 
2847 {
2848  FSHelperPtr pFS = GetFS();
2849  pFS->startElement(FSNS(XML_c, XML_spPr));
2850 
2851  exportFill( xPropSet );
2852  WriteOutline( xPropSet, getModel() );
2853 
2854  pFS->endElement( FSNS( XML_c, XML_spPr ) );
2855 }
2856 
2858 {
2859  FSHelperPtr pFS = GetFS();
2860  pFS->startElement(FSNS(XML_c, XML_txPr));
2861 
2862  sal_Int32 nRotation = 0;
2863  const char* textWordWrap = nullptr;
2864 
2865  if (auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xPropSet, uno::UNO_QUERY))
2866  {
2867  double fMultiplier = 0.0;
2868  // We have at least two possible units of returned value: degrees (e.g., for data labels),
2869  // and 100ths of degree (e.g., for axes labels). The latter is returned as an Any wrapping
2870  // a sal_Int32 value (see WrappedTextRotationProperty::convertInnerToOuterValue), while
2871  // the former is double. So we could test the contained type to decide which multiplier to
2872  // use. But testing the service info should be more robust.
2873  if (xServiceInfo->supportsService("com.sun.star.chart.ChartAxis"))
2874  fMultiplier = -600.0;
2875  else if (xServiceInfo->supportsService("com.sun.star.chart2.DataSeries") || xServiceInfo->supportsService("com.sun.star.chart2.DataPointProperties"))
2876  {
2877  fMultiplier = -60000.0;
2878  bool bTextWordWrap = false;
2879  if ((xPropSet->getPropertyValue("TextWordWrap") >>= bTextWordWrap) && bTextWordWrap)
2880  textWordWrap = "square";
2881  else
2882  textWordWrap = "none";
2883  }
2884 
2885  if (fMultiplier)
2886  {
2887  double fTextRotation = 0.0;
2888  uno::Any aAny = xPropSet->getPropertyValue("TextRotation");
2889  if (aAny.hasValue() && (aAny >>= fTextRotation))
2890  {
2891  fTextRotation *= fMultiplier;
2892  // The MS Office UI allows values only in range of [-90,90].
2893  if (fTextRotation < -5400000.0 && fTextRotation > -16200000.0)
2894  {
2895  // Reflect the angle if the value is between 90° and 270°
2896  fTextRotation += 10800000.0;
2897  }
2898  else if (fTextRotation <= -16200000.0)
2899  {
2900  fTextRotation += 21600000.0;
2901  }
2902  nRotation = std::round(fTextRotation);
2903  }
2904  }
2905  }
2906 
2907  if (nRotation)
2908  pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_rot, OString::number(nRotation), XML_wrap, textWordWrap);
2909  else
2910  pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_wrap, textWordWrap);
2911 
2912  pFS->singleElement(FSNS(XML_a, XML_lstStyle));
2913 
2914  pFS->startElement(FSNS(XML_a, XML_p));
2915  pFS->startElement(FSNS(XML_a, XML_pPr));
2916 
2917  WriteRunProperties(xPropSet, false, XML_defRPr, true, o3tl::temporary(false),
2918  o3tl::temporary(sal_Int32()));
2919 
2920  pFS->endElement(FSNS(XML_a, XML_pPr));
2921  pFS->endElement(FSNS(XML_a, XML_p));
2922  pFS->endElement(FSNS(XML_c, XML_txPr));
2923 }
2924 
2926 {
2927  Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
2928 
2929  // Check for supported services and then the properties provided by this service.
2930  Reference<lang::XServiceInfo> xServiceInfo (mxDiagram, uno::UNO_QUERY);
2931  if (xServiceInfo.is())
2932  {
2933  if (xServiceInfo->supportsService("com.sun.star.chart.ChartAxisZSupplier"))
2934  {
2935  xDiagramProperties->getPropertyValue("HasZAxis") >>= mbHasZAxis;
2936  }
2937  }
2938 
2939  xDiagramProperties->getPropertyValue("Dim3D") >>= mbIs3DChart;
2940 
2941  if( mbHasCategoryLabels && mxNewDiagram.is())
2942  {
2944  if( xCategories.is() )
2945  {
2946  mxCategoriesValues.set( xCategories->getValues() );
2947  }
2948  }
2949 }
2950 
2952 {
2953  sal_Int32 nSize = maAxes.size();
2954  // let's export the axis types in the right order
2955  for ( sal_Int32 nSortIdx = AXIS_PRIMARY_X; nSortIdx <= AXIS_SECONDARY_Y; nSortIdx++ )
2956  {
2957  for ( sal_Int32 nIdx = 0; nIdx < nSize; nIdx++ )
2958  {
2959  if (nSortIdx == maAxes[nIdx].nAxisType)
2960  exportAxis( maAxes[nIdx] );
2961  }
2962  }
2963 }
2964 
2965 namespace {
2966 
2967 sal_Int32 getXAxisTypeByChartType(sal_Int32 eChartType)
2968 {
2969  if( (eChartType == chart::TYPEID_SCATTER)
2970  || (eChartType == chart::TYPEID_BUBBLE) )
2971  return XML_valAx;
2972  else if( eChartType == chart::TYPEID_STOCK )
2973  return XML_dateAx;
2974 
2975  return XML_catAx;
2976 }
2977 
2978 sal_Int32 getRealXAxisType(sal_Int32 nAxisType)
2979 {
2980  if( nAxisType == chart2::AxisType::CATEGORY )
2981  return XML_catAx;
2982  else if( nAxisType == chart2::AxisType::DATE )
2983  return XML_dateAx;
2984  else if( nAxisType == chart2::AxisType::SERIES )
2985  return XML_serAx;
2986 
2987  return XML_valAx;
2988 }
2989 
2990 }
2991 
2992 void ChartExport::exportAxis(const AxisIdPair& rAxisIdPair)
2993 {
2994  // get some properties from document first
2995  bool bHasXAxisTitle = false,
2996  bHasYAxisTitle = false,
2997  bHasZAxisTitle = false,
2998  bHasSecondaryXAxisTitle = false,
2999  bHasSecondaryYAxisTitle = false;
3000  bool bHasXAxisMajorGrid = false,
3001  bHasXAxisMinorGrid = false,
3002  bHasYAxisMajorGrid = false,
3003  bHasYAxisMinorGrid = false,
3004  bHasZAxisMajorGrid = false,
3005  bHasZAxisMinorGrid = false;
3006 
3007  Reference< XPropertySet > xDiagramProperties (mxDiagram, uno::UNO_QUERY);
3008 
3009  xDiagramProperties->getPropertyValue("HasXAxisTitle") >>= bHasXAxisTitle;
3010  xDiagramProperties->getPropertyValue("HasYAxisTitle") >>= bHasYAxisTitle;
3011  xDiagramProperties->getPropertyValue("HasZAxisTitle") >>= bHasZAxisTitle;
3012  xDiagramProperties->getPropertyValue("HasSecondaryXAxisTitle") >>= bHasSecondaryXAxisTitle;
3013  xDiagramProperties->getPropertyValue("HasSecondaryYAxisTitle") >>= bHasSecondaryYAxisTitle;
3014 
3015  xDiagramProperties->getPropertyValue("HasXAxisGrid") >>= bHasXAxisMajorGrid;
3016  xDiagramProperties->getPropertyValue("HasYAxisGrid") >>= bHasYAxisMajorGrid;
3017  xDiagramProperties->getPropertyValue("HasZAxisGrid") >>= bHasZAxisMajorGrid;
3018 
3019  xDiagramProperties->getPropertyValue("HasXAxisHelpGrid") >>= bHasXAxisMinorGrid;
3020  xDiagramProperties->getPropertyValue("HasYAxisHelpGrid") >>= bHasYAxisMinorGrid;
3021  xDiagramProperties->getPropertyValue("HasZAxisHelpGrid") >>= bHasZAxisMinorGrid;
3022 
3023  Reference< XPropertySet > xAxisProp;
3024  Reference< drawing::XShape > xAxisTitle;
3027  sal_Int32 nAxisType = XML_catAx;
3028  const char* sAxPos = nullptr;
3029 
3030  switch( rAxisIdPair.nAxisType )
3031  {
3032  case AXIS_PRIMARY_X:
3033  {
3034  Reference< css::chart::XAxisXSupplier > xAxisXSupp( mxDiagram, uno::UNO_QUERY );
3035  if( xAxisXSupp.is())
3036  xAxisProp = xAxisXSupp->getXAxis();
3037  if( bHasXAxisTitle )
3038  xAxisTitle = xAxisXSupp->getXAxisTitle();
3039  if( bHasXAxisMajorGrid )
3040  xMajorGrid = xAxisXSupp->getXMainGrid();
3041  if( bHasXAxisMinorGrid )
3042  xMinorGrid = xAxisXSupp->getXHelpGrid();
3043 
3044  nAxisType = lcl_getCategoryAxisType(mxNewDiagram, 0, 0);
3045  if( nAxisType != -1 )
3046  nAxisType = getRealXAxisType(nAxisType);
3047  else
3048  nAxisType = getXAxisTypeByChartType( getChartType() );
3049  // FIXME: axPos, need to check axis direction
3050  sAxPos = "b";
3051  break;
3052  }
3053  case AXIS_PRIMARY_Y:
3054  {
3055  Reference< css::chart::XAxisYSupplier > xAxisYSupp( mxDiagram, uno::UNO_QUERY );
3056  if( xAxisYSupp.is())
3057  xAxisProp = xAxisYSupp->getYAxis();
3058  if( bHasYAxisTitle )
3059  xAxisTitle = xAxisYSupp->getYAxisTitle();
3060  if( bHasYAxisMajorGrid )
3061  xMajorGrid = xAxisYSupp->getYMainGrid();
3062  if( bHasYAxisMinorGrid )
3063  xMinorGrid = xAxisYSupp->getYHelpGrid();
3064 
3065  nAxisType = XML_valAx;
3066  // FIXME: axPos, need to check axis direction
3067  sAxPos = "l";
3068  break;
3069  }
3070  case AXIS_PRIMARY_Z:
3071  {
3072  Reference< css::chart::XAxisZSupplier > xAxisZSupp( mxDiagram, uno::UNO_QUERY );
3073  if( xAxisZSupp.is())
3074  xAxisProp = xAxisZSupp->getZAxis();
3075  if( bHasZAxisTitle )
3076  xAxisTitle = xAxisZSupp->getZAxisTitle();
3077  if( bHasZAxisMajorGrid )
3078  xMajorGrid = xAxisZSupp->getZMainGrid();
3079  if( bHasZAxisMinorGrid )
3080  xMinorGrid = xAxisZSupp->getZHelpGrid();
3081 
3082  sal_Int32 eChartType = getChartType( );
3083  if( (eChartType == chart::TYPEID_SCATTER)
3084  || (eChartType == chart::TYPEID_BUBBLE) )
3085  nAxisType = XML_valAx;
3086  else if( eChartType == chart::TYPEID_STOCK )
3087  nAxisType = XML_dateAx;
3088  else if( eChartType == chart::TYPEID_BAR || eChartType == chart::TYPEID_AREA )
3089  nAxisType = XML_serAx;
3090  // FIXME: axPos, need to check axis direction
3091  sAxPos = "b";
3092  break;
3093  }
3094  case AXIS_SECONDARY_X:
3095  {
3096  Reference< css::chart::XTwoAxisXSupplier > xAxisTwoXSupp( mxDiagram, uno::UNO_QUERY );
3097  if( xAxisTwoXSupp.is())
3098  xAxisProp = xAxisTwoXSupp->getSecondaryXAxis();
3099  if( bHasSecondaryXAxisTitle )
3100  {
3101  Reference< css::chart::XSecondAxisTitleSupplier > xAxisSupp( mxDiagram, uno::UNO_QUERY );
3102  xAxisTitle = xAxisSupp->getSecondXAxisTitle();
3103  }
3104 
3105  nAxisType = lcl_getCategoryAxisType(mxNewDiagram, 0, 1);
3106  if( nAxisType != -1 )
3107  nAxisType = getRealXAxisType(nAxisType);
3108  else
3109  nAxisType = getXAxisTypeByChartType( getChartType() );
3110  // FIXME: axPos, need to check axis direction
3111  sAxPos = "t";
3112  break;
3113  }
3114  case AXIS_SECONDARY_Y:
3115  {
3116  Reference< css::chart::XTwoAxisYSupplier > xAxisTwoYSupp( mxDiagram, uno::UNO_QUERY );
3117  if( xAxisTwoYSupp.is())
3118  xAxisProp = xAxisTwoYSupp->getSecondaryYAxis();
3119  if( bHasSecondaryYAxisTitle )
3120  {
3121  Reference< css::chart::XSecondAxisTitleSupplier > xAxisSupp( mxDiagram, uno::UNO_QUERY );
3122  xAxisTitle = xAxisSupp->getSecondYAxisTitle();
3123  }
3124 
3125  nAxisType = XML_valAx;
3126  // FIXME: axPos, need to check axis direction
3127  sAxPos = "r";
3128  break;
3129  }
3130  }
3131 
3132  _exportAxis(xAxisProp, xAxisTitle, xMajorGrid, xMinorGrid, nAxisType, sAxPos, rAxisIdPair);
3133 }
3134 
3136  const Reference< XPropertySet >& xAxisProp,
3137  const Reference< drawing::XShape >& xAxisTitle,
3138  const Reference< XPropertySet >& xMajorGrid,
3139  const Reference< XPropertySet >& xMinorGrid,
3140  sal_Int32 nAxisType,
3141  const char* sAxisPos,
3142  const AxisIdPair& rAxisIdPair )
3143 {
3144  FSHelperPtr pFS = GetFS();
3145  pFS->startElement(FSNS(XML_c, nAxisType));
3146  pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(rAxisIdPair.nAxisId));
3147 
3148  pFS->startElement(FSNS(XML_c, XML_scaling));
3149 
3150  // logBase, min, max
3151  if(GetProperty( xAxisProp, "Logarithmic" ) )
3152  {
3153  bool bLogarithmic = false;
3154  mAny >>= bLogarithmic;
3155  if( bLogarithmic )
3156  {
3157  // default value is 10?
3158  pFS->singleElement(FSNS(XML_c, XML_logBase), XML_val, OString::number(10));
3159  }
3160  }
3161 
3162  // orientation: minMax, maxMin
3163  bool bReverseDirection = false;
3164  if(GetProperty( xAxisProp, "ReverseDirection" ) )
3165  mAny >>= bReverseDirection;
3166 
3167  const char* orientation = bReverseDirection ? "maxMin":"minMax";
3168  pFS->singleElement(FSNS(XML_c, XML_orientation), XML_val, orientation);
3169 
3170  bool bAutoMax = false;
3171  if(GetProperty( xAxisProp, "AutoMax" ) )
3172  mAny >>= bAutoMax;
3173 
3174  if( !bAutoMax && (GetProperty( xAxisProp, "Max" ) ) )
3175  {
3176  double dMax = 0;
3177  mAny >>= dMax;
3178  pFS->singleElement(FSNS(XML_c, XML_max), XML_val, OString::number(dMax));
3179  }
3180 
3181  bool bAutoMin = false;
3182  if(GetProperty( xAxisProp, "AutoMin" ) )
3183  mAny >>= bAutoMin;
3184 
3185  if( !bAutoMin && (GetProperty( xAxisProp, "Min" ) ) )
3186  {
3187  double dMin = 0;
3188  mAny >>= dMin;
3189  pFS->singleElement(FSNS(XML_c, XML_min), XML_val, OString::number(dMin));
3190  }
3191 
3192  pFS->endElement( FSNS( XML_c, XML_scaling ) );
3193 
3194  bool bVisible = true;
3195  if( xAxisProp.is() )
3196  {
3197  xAxisProp->getPropertyValue("Visible") >>= bVisible;
3198  }
3199 
3200  // only export each axis only once non-deleted
3201  bool bDeleted = maExportedAxis.find(rAxisIdPair.nAxisType) != maExportedAxis.end();
3202 
3203  if (!bDeleted)
3204  maExportedAxis.insert(rAxisIdPair.nAxisType);
3205 
3206  pFS->singleElement(FSNS(XML_c, XML_delete), XML_val, !bDeleted && bVisible ? "0" : "1");
3207 
3208  // FIXME: axPos, need to check the property "ReverseDirection"
3209  pFS->singleElement(FSNS(XML_c, XML_axPos), XML_val, sAxisPos);
3210  // major grid line
3211  if( xMajorGrid.is())
3212  {
3213  pFS->startElement(FSNS(XML_c, XML_majorGridlines));
3214  exportShapeProps( xMajorGrid );
3215  pFS->endElement( FSNS( XML_c, XML_majorGridlines ) );
3216  }
3217 
3218  // minor grid line
3219  if( xMinorGrid.is())
3220  {
3221  pFS->startElement(FSNS(XML_c, XML_minorGridlines));
3222  exportShapeProps( xMinorGrid );
3223  pFS->endElement( FSNS( XML_c, XML_minorGridlines ) );
3224  }
3225 
3226  // title
3227  if( xAxisTitle.is() )
3228  exportTitle( xAxisTitle );
3229 
3230  bool bLinkedNumFmt = true;
3231  if (GetProperty(xAxisProp, "LinkNumberFormatToSource"))
3232  mAny >>= bLinkedNumFmt;
3233 
3234  OUString aNumberFormatString("General");
3235  if (GetProperty(xAxisProp, "NumberFormat"))
3236  {
3237  sal_Int32 nKey = 0;
3238  mAny >>= nKey;
3239  aNumberFormatString = getNumberFormatCode(nKey);
3240  }
3241 
3242  OString sNumberFormatString = OUStringToOString(aNumberFormatString, RTL_TEXTENCODING_UTF8);
3243  pFS->singleElement(FSNS(XML_c, XML_numFmt),
3244  XML_formatCode, sNumberFormatString.getStr(),
3245  XML_sourceLinked, bLinkedNumFmt ? "1" : "0");
3246 
3247  // majorTickMark
3248  sal_Int32 nValue = 0;
3249  if(GetProperty( xAxisProp, "Marks" ) )
3250  {
3251  mAny >>= nValue;
3252  bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
3253  bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
3254  const char* majorTickMark = nullptr;
3255  if( bInner && bOuter )
3256  majorTickMark = "cross";
3257  else if( bInner )
3258  majorTickMark = "in";
3259  else if( bOuter )
3260  majorTickMark = "out";
3261  else
3262  majorTickMark = "none";
3263  pFS->singleElement(FSNS(XML_c, XML_majorTickMark), XML_val, majorTickMark);
3264  }
3265  // minorTickMark
3266  if(GetProperty( xAxisProp, "HelpMarks" ) )
3267  {
3268  mAny >>= nValue;
3269  bool bInner = nValue & css::chart::ChartAxisMarks::INNER;
3270  bool bOuter = nValue & css::chart::ChartAxisMarks::OUTER;
3271  const char* minorTickMark = nullptr;
3272  if( bInner && bOuter )
3273  minorTickMark = "cross";
3274  else if( bInner )
3275  minorTickMark = "in";
3276  else if( bOuter )
3277  minorTickMark = "out";
3278  else
3279  minorTickMark = "none";
3280  pFS->singleElement(FSNS(XML_c, XML_minorTickMark), XML_val, minorTickMark);
3281  }
3282  // tickLblPos
3283  const char* sTickLblPos = nullptr;
3284  bool bDisplayLabel = true;
3285  if(GetProperty( xAxisProp, "DisplayLabels" ) )
3286  mAny >>= bDisplayLabel;
3287  if( bDisplayLabel && (GetProperty( xAxisProp, "LabelPosition" ) ) )
3288  {
3289  css::chart::ChartAxisLabelPosition eLabelPosition = css::chart::ChartAxisLabelPosition_NEAR_AXIS;
3290  mAny >>= eLabelPosition;
3291  switch( eLabelPosition )
3292  {
3293  case css::chart::ChartAxisLabelPosition_NEAR_AXIS:
3294  case css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE:
3295  sTickLblPos = "nextTo";
3296  break;
3297  case css::chart::ChartAxisLabelPosition_OUTSIDE_START:
3298  sTickLblPos = "low";
3299  break;
3300  case css::chart::ChartAxisLabelPosition_OUTSIDE_END:
3301  sTickLblPos = "high";
3302  break;
3303  default:
3304  sTickLblPos = "nextTo";
3305  break;
3306  }
3307  }
3308  else
3309  {
3310  sTickLblPos = "none";
3311  }
3312  pFS->singleElement(FSNS(XML_c, XML_tickLblPos), XML_val, sTickLblPos);
3313 
3314  // shape properties
3315  exportShapeProps( xAxisProp );
3316 
3317  exportTextProps(xAxisProp);
3318 
3319  pFS->singleElement(FSNS(XML_c, XML_crossAx), XML_val, OString::number(rAxisIdPair.nCrossAx));
3320 
3321  // crosses & crossesAt
3322  bool bCrossesValue = false;
3323  const char* sCrosses = nullptr;
3324  // do not export the CrossoverPosition/CrossoverValue, if the axis is deleted and not visible
3325  if( GetProperty( xAxisProp, "CrossoverPosition" ) && !bDeleted && bVisible )
3326  {
3327  css::chart::ChartAxisPosition ePosition( css::chart::ChartAxisPosition_ZERO );
3328  mAny >>= ePosition;
3329  switch( ePosition )
3330  {
3331  case css::chart::ChartAxisPosition_START:
3332  sCrosses = "min";
3333  break;
3334  case css::chart::ChartAxisPosition_END:
3335  sCrosses = "max";
3336  break;
3337  case css::chart::ChartAxisPosition_ZERO:
3338  sCrosses = "autoZero";
3339  break;
3340  default:
3341  bCrossesValue = true;
3342  break;
3343  }
3344  }
3345 
3346  if( bCrossesValue && GetProperty( xAxisProp, "CrossoverValue" ) )
3347  {
3348  double dValue = 0;
3349  mAny >>= dValue;
3350  pFS->singleElement(FSNS(XML_c, XML_crossesAt), XML_val, OString::number(dValue));
3351  }
3352  else
3353  {
3354  if(sCrosses)
3355  {
3356  pFS->singleElement(FSNS(XML_c, XML_crosses), XML_val, sCrosses);
3357  }
3358  }
3359 
3360  if( ( nAxisType == XML_catAx )
3361  || ( nAxisType == XML_dateAx ) )
3362  {
3363  // FIXME: seems not support? use default value,
3364  const char* const isAuto = "1";
3365  pFS->singleElement(FSNS(XML_c, XML_auto), XML_val, isAuto);
3366 
3367  if( nAxisType == XML_catAx )
3368  {
3369  // FIXME: seems not support? lblAlgn
3370  const char* const sLblAlgn = "ctr";
3371  pFS->singleElement(FSNS(XML_c, XML_lblAlgn), XML_val, sLblAlgn);
3372  }
3373 
3374  // FIXME: seems not support? lblOffset
3375  pFS->singleElement(FSNS(XML_c, XML_lblOffset), XML_val, OString::number(100));
3376 
3377  // export baseTimeUnit, majorTimeUnit, minorTimeUnit of Date axis
3378  if( nAxisType == XML_dateAx )
3379  {
3380  sal_Int32 nAxisIndex = -1;
3381  if( rAxisIdPair.nAxisType == AXIS_PRIMARY_X )
3382  nAxisIndex = 0;
3383  else if( rAxisIdPair.nAxisType == AXIS_SECONDARY_X )
3384  nAxisIndex = 1;
3385 
3386  cssc::TimeIncrement aTimeIncrement = lcl_getDateTimeIncrement( mxNewDiagram, nAxisIndex );
3387  sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY;
3388  if( aTimeIncrement.TimeResolution >>= nTimeResolution )
3389  pFS->singleElement(FSNS(XML_c, XML_baseTimeUnit), XML_val, lclGetTimeUnitToken(nTimeResolution));
3390 
3391  cssc::TimeInterval aInterval;
3392  if( aTimeIncrement.MajorTimeInterval >>= aInterval )
3393  {
3394  pFS->singleElement(FSNS(XML_c, XML_majorUnit), XML_val, OString::number(aInterval.Number));
3395  pFS->singleElement(FSNS(XML_c, XML_majorTimeUnit), XML_val, lclGetTimeUnitToken(aInterval.TimeUnit));
3396  }
3397  if( aTimeIncrement.MinorTimeInterval >>= aInterval )
3398  {
3399  pFS->singleElement(FSNS(XML_c, XML_minorUnit), XML_val, OString::number(aInterval.Number));
3400  pFS->singleElement(FSNS(XML_c, XML_minorTimeUnit), XML_val, lclGetTimeUnitToken(aInterval.TimeUnit));
3401  }
3402  }
3403 
3404  // FIXME: seems not support? noMultiLvlLbl
3405  pFS->singleElement(FSNS(XML_c, XML_noMultiLvlLbl), XML_val, OString::number(0));
3406  }
3407 
3408  // crossBetween
3409  if( nAxisType == XML_valAx )
3410  {
3412  pFS->singleElement(FSNS(XML_c, XML_crossBetween), XML_val, "between");
3413  else
3414  pFS->singleElement(FSNS(XML_c, XML_crossBetween), XML_val, "midCat");
3415  }
3416 
3417  // majorUnit
3418  bool bAutoStepMain = false;
3419  if(GetProperty( xAxisProp, "AutoStepMain" ) )
3420  mAny >>= bAutoStepMain;
3421 
3422  if( !bAutoStepMain && (GetProperty( xAxisProp, "StepMain" ) ) )
3423  {
3424  double dMajorUnit = 0;
3425  mAny >>= dMajorUnit;
3426  pFS->singleElement(FSNS(XML_c, XML_majorUnit), XML_val, OString::number(dMajorUnit));
3427  }
3428  // minorUnit
3429  bool bAutoStepHelp = false;
3430  if(GetProperty( xAxisProp, "AutoStepHelp" ) )
3431  mAny >>= bAutoStepHelp;
3432 
3433  if( !bAutoStepHelp && (GetProperty( xAxisProp, "StepHelp" ) ) )
3434  {
3435  double dMinorUnit = 0;
3436  mAny >>= dMinorUnit;
3437  if( GetProperty( xAxisProp, "StepHelpCount" ) )
3438  {
3439  sal_Int32 dMinorUnitCount = 0;
3440  mAny >>= dMinorUnitCount;
3441  // tdf#114168 Don't save minor unit if number of step help count is 5 (which is default for MS Excel),
3442  // to allow proper .xlsx import. If minorUnit is set and majorUnit not, then it is impossible
3443  // to calculate StepHelpCount.
3444  if( dMinorUnitCount != 5 )
3445  {
3446  pFS->singleElement( FSNS( XML_c, XML_minorUnit ),
3447  XML_val, OString::number( dMinorUnit ) );
3448  }
3449  }
3450  }
3451 
3452  if( nAxisType == XML_valAx && GetProperty( xAxisProp, "DisplayUnits" ) )
3453  {
3454  bool bDisplayUnits = false;
3455  mAny >>= bDisplayUnits;
3456  if(bDisplayUnits)
3457  {
3458  if(GetProperty( xAxisProp, "BuiltInUnit" ))
3459  {
3460  OUString aVal;
3461  mAny >>= aVal;
3462  if(!aVal.isEmpty())
3463  {
3464  pFS->startElement(FSNS(XML_c, XML_dispUnits));
3465 
3466  pFS->singleElement(FSNS(XML_c, XML_builtInUnit), XML_val, aVal);
3467 
3468  pFS->singleElement(FSNS( XML_c, XML_dispUnitsLbl ));
3469  pFS->endElement( FSNS( XML_c, XML_dispUnits ) );
3470  }
3471  }
3472  }
3473  }
3474 
3475  pFS->endElement( FSNS( XML_c, nAxisType ) );
3476 }
3477 
3478 namespace {
3479 
3480 struct LabelPlacementParam
3481 {
3482  bool mbExport;
3483  sal_Int32 meDefault;
3484 
3485  std::unordered_set<sal_Int32> maAllowedValues;
3486 
3487  LabelPlacementParam(bool bExport, sal_Int32 nDefault) :
3488  mbExport(bExport),
3489  meDefault(nDefault),
3490  maAllowedValues(
3491  {
3492  css::chart::DataLabelPlacement::OUTSIDE,
3493  css::chart::DataLabelPlacement::INSIDE,
3494  css::chart::DataLabelPlacement::CENTER,
3495  css::chart::DataLabelPlacement::NEAR_ORIGIN,
3496  css::chart::DataLabelPlacement::TOP,
3497  css::chart::DataLabelPlacement::BOTTOM,
3498  css::chart::DataLabelPlacement::LEFT,
3499  css::chart::DataLabelPlacement::RIGHT,
3500  css::chart::DataLabelPlacement::AVOID_OVERLAP
3501  }
3502  )
3503  {}
3504 };
3505 
3506 const char* toOOXMLPlacement( sal_Int32 nPlacement )
3507 {
3508  switch (nPlacement)
3509  {
3510  case css::chart::DataLabelPlacement::OUTSIDE: return "outEnd";
3511  case css::chart::DataLabelPlacement::INSIDE: return "inEnd";
3512  case css::chart::DataLabelPlacement::CENTER: return "ctr";
3513  case css::chart::DataLabelPlacement::NEAR_ORIGIN: return "inBase";
3514  case css::chart::DataLabelPlacement::TOP: return "t";
3515  case css::chart::DataLabelPlacement::BOTTOM: return "b";
3516  case css::chart::DataLabelPlacement::LEFT: return "l";
3517  case css::chart::DataLabelPlacement::RIGHT: return "r";
3518  case css::chart::DataLabelPlacement::CUSTOM:
3519  case css::chart::DataLabelPlacement::AVOID_OVERLAP: return "bestFit";
3520  default:
3521  ;
3522  }
3523 
3524  return "outEnd";
3525 }
3526 
3527 OUString getFieldTypeString( const chart2::DataPointCustomLabelFieldType aType )
3528 {
3529  switch (aType)
3530  {
3531  case chart2::DataPointCustomLabelFieldType_CATEGORYNAME:
3532  return "CATEGORYNAME";
3533 
3534  case chart2::DataPointCustomLabelFieldType_SERIESNAME:
3535  return "SERIESNAME";
3536 
3537  case chart2::DataPointCustomLabelFieldType_VALUE:
3538  return "VALUE";
3539 
3540  case chart2::DataPointCustomLabelFieldType_CELLREF:
3541  return "CELLREF";
3542 
3543  case chart2::DataPointCustomLabelFieldType_CELLRANGE:
3544  return "CELLRANGE";
3545 
3546  default:
3547  break;
3548  }
3549  return OUString();
3550 }
3551 
3552 void writeRunProperties( ChartExport* pChartExport, Reference<XPropertySet> const & xPropertySet )
3553 {
3554  bool bDummy = false;
3555  sal_Int32 nDummy;
3556  pChartExport->WriteRunProperties(xPropertySet, false, XML_rPr, true, bDummy, nDummy);
3557 }
3558 
3559 void writeCustomLabel( const FSHelperPtr& pFS, ChartExport* pChartExport,
3560  const Sequence<Reference<chart2::XDataPointCustomLabelField>>& rCustomLabelFields )
3561 {
3562  pFS->startElement(FSNS(XML_c, XML_tx));
3563  pFS->startElement(FSNS(XML_c, XML_rich));
3564 
3565  // TODO: body properties?
3566  pFS->singleElement(FSNS(XML_a, XML_bodyPr));
3567 
3568  OUString sFieldType;
3569  pFS->startElement(FSNS(XML_a, XML_p));
3570 
3571  for (auto& rField : rCustomLabelFields)
3572  {
3573  Reference<XPropertySet> xPropertySet(rField, UNO_QUERY);
3574  chart2::DataPointCustomLabelFieldType aType = rField->getFieldType();
3575  sFieldType.clear();
3576  bool bNewParagraph = false;
3577 
3578  if (aType == chart2::DataPointCustomLabelFieldType_NEWLINE)
3579  bNewParagraph = true;
3580  else if (aType != chart2::DataPointCustomLabelFieldType_TEXT)
3581  sFieldType = getFieldTypeString(aType);
3582 
3583  if (bNewParagraph)
3584  {
3585  pFS->endElement(FSNS(XML_a, XML_p));
3586  pFS->startElement(FSNS(XML_a, XML_p));
3587  continue;
3588  }
3589 
3590  if (sFieldType.isEmpty())
3591  {
3592  // Normal text run
3593  pFS->startElement(FSNS(XML_a, XML_r));
3594  writeRunProperties(pChartExport, xPropertySet);
3595 
3596  pFS->startElement(FSNS(XML_a, XML_t));
3597  pFS->writeEscaped(rField->getString());
3598  pFS->endElement(FSNS(XML_a, XML_t));
3599 
3600  pFS->endElement(FSNS(XML_a, XML_r));
3601  }
3602  else
3603  {
3604  // Field
3605  pFS->startElement(FSNS(XML_a, XML_fld), XML_id, rField->getGuid(), XML_type,
3606  sFieldType);
3607  writeRunProperties(pChartExport, xPropertySet);
3608 
3609  pFS->startElement(FSNS(XML_a, XML_t));
3610  pFS->writeEscaped(rField->getString());
3611  pFS->endElement(FSNS(XML_a, XML_t));
3612 
3613  pFS->endElement(FSNS(XML_a, XML_fld));
3614  }
3615  }
3616 
3617  pFS->endElement(FSNS(XML_a, XML_p));
3618  pFS->endElement(FSNS(XML_c, XML_rich));
3619  pFS->endElement(FSNS(XML_c, XML_tx));
3620 }
3621 
3622 void writeLabelProperties( const FSHelperPtr& pFS, ChartExport* pChartExport,
3623  const uno::Reference<beans::XPropertySet>& xPropSet, const LabelPlacementParam& rLabelParam )
3624 {
3625  if (!xPropSet.is())
3626  return;
3627 
3628  chart2::DataPointLabel aLabel;
3629  Sequence<Reference<chart2::XDataPointCustomLabelField>> aCustomLabelFields;
3630  sal_Int32 nLabelBorderWidth = 0;
3631  sal_Int32 nLabelBorderColor = 0x00FFFFFF;
3632  sal_Int32 nLabelFillColor = -1;
3633 
3634  xPropSet->getPropertyValue("Label") >>= aLabel;
3635  xPropSet->getPropertyValue("CustomLabelFields") >>= aCustomLabelFields;
3636  xPropSet->getPropertyValue("LabelBorderWidth") >>= nLabelBorderWidth;
3637  xPropSet->getPropertyValue("LabelBorderColor") >>= nLabelBorderColor;
3638  xPropSet->getPropertyValue("LabelFillColor") >>= nLabelFillColor;
3639 
3640  if (nLabelBorderWidth > 0 || nLabelFillColor != -1)
3641  {
3642  pFS->startElement(FSNS(XML_c, XML_spPr));
3643 
3644  if (nLabelFillColor != -1)
3645  {
3646  pFS->startElement(FSNS(XML_a, XML_solidFill));
3647 
3648  OString aStr = OString::number(nLabelFillColor, 16).toAsciiUpperCase();
3649  pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr);
3650 
3651  pFS->endElement(FSNS(XML_a, XML_solidFill));
3652  }
3653 
3654  if (nLabelBorderWidth > 0)
3655  {
3656  pFS->startElement(FSNS(XML_a, XML_ln), XML_w,
3657  OString::number(convertHmmToEmu(nLabelBorderWidth)));
3658 
3659  if (nLabelBorderColor != -1)
3660  {
3661  pFS->startElement(FSNS(XML_a, XML_solidFill));
3662 
3663  OString aStr = OString::number(nLabelBorderColor, 16).toAsciiUpperCase();
3664  pFS->singleElement(FSNS(XML_a, XML_srgbClr), XML_val, aStr);
3665 
3666  pFS->endElement(FSNS(XML_a, XML_solidFill));
3667  }
3668 
3669  pFS->endElement(FSNS(XML_a, XML_ln));
3670  }
3671 
3672  pFS->endElement(FSNS(XML_c, XML_spPr));
3673  }
3674 
3675  pChartExport->exportTextProps(xPropSet);
3676 
3677  if (aCustomLabelFields.hasElements())
3678  writeCustomLabel(pFS, pChartExport, aCustomLabelFields);
3679 
3680  if (rLabelParam.mbExport)
3681  {
3682  sal_Int32 nLabelPlacement = rLabelParam.meDefault;
3683  if (xPropSet->getPropertyValue("LabelPlacement") >>= nLabelPlacement)
3684  {
3685  if (!rLabelParam.maAllowedValues.count(nLabelPlacement))
3686  nLabelPlacement = rLabelParam.meDefault;
3687  pFS->singleElement(FSNS(XML_c, XML_dLblPos), XML_val, toOOXMLPlacement(nLabelPlacement));
3688  }
3689  }
3690 
3691  pFS->singleElement(FSNS(XML_c, XML_showLegendKey), XML_val, ToPsz10(aLabel.ShowLegendSymbol));
3692  pFS->singleElement(FSNS(XML_c, XML_showVal), XML_val, ToPsz10(aLabel.ShowNumber));
3693  pFS->singleElement(FSNS(XML_c, XML_showCatName), XML_val, ToPsz10(aLabel.ShowCategoryName));
3694  pFS->singleElement(FSNS(XML_c, XML_showSerName), XML_val, ToPsz10(aLabel.ShowSeriesName));
3695  pFS->singleElement(FSNS(XML_c, XML_showPercent), XML_val, ToPsz10(aLabel.ShowNumberInPercent));
3696 
3697  // Export the text "separator" if exists
3698  uno::Any aAny = xPropSet->getPropertyValue("LabelSeparator");
3699  if( aAny.hasValue() )
3700  {
3701  OUString nLabelSeparator;
3702  aAny >>= nLabelSeparator;
3703  pFS->startElement(FSNS(XML_c, XML_separator));
3704  pFS->writeEscaped( nLabelSeparator );
3705  pFS->endElement( FSNS( XML_c, XML_separator ) );
3706  }
3707 }
3708 
3709 }
3710 
3712  const uno::Reference<chart2::XDataSeries> & xSeries, sal_Int32 nSeriesLength, sal_Int32 eChartType )
3713 {
3714  if (!xSeries.is() || nSeriesLength <= 0)
3715  return;
3716 
3717  uno::Reference<beans::XPropertySet> xPropSet(xSeries, uno::UNO_QUERY);
3718  if (!xPropSet.is())
3719  return;
3720 
3721  FSHelperPtr pFS = GetFS();
3722  pFS->startElement(FSNS(XML_c, XML_dLbls));
3723 
3724  bool bLinkedNumFmt = true;
3725  if (GetProperty(xPropSet, "LinkNumberFormatToSource"))
3726  mAny >>= bLinkedNumFmt;
3727 
3728  chart2::DataPointLabel aLabel;
3729  bool bLabelIsNumberFormat = true;
3730  if( xPropSet->getPropertyValue("Label") >>= aLabel )
3731  bLabelIsNumberFormat = aLabel.ShowNumber;
3732 
3733  if (GetProperty(xPropSet, bLabelIsNumberFormat ? OUString("NumberFormat") : OUString("PercentageNumberFormat")))
3734  {
3735  sal_Int32 nKey = 0;
3736  mAny >>= nKey;
3737 
3738  OUString aNumberFormatString = getNumberFormatCode(nKey);
3739  OString sNumberFormatString = OUStringToOString(aNumberFormatString, RTL_TEXTENCODING_UTF8);
3740 
3741  pFS->singleElement(FSNS(XML_c, XML_numFmt),
3742  XML_formatCode, sNumberFormatString,
3743  XML_sourceLinked, ToPsz10(bLinkedNumFmt));
3744  }
3745 
3746  uno::Sequence<sal_Int32> aAttrLabelIndices;
3747  xPropSet->getPropertyValue("AttributedDataPoints") >>= aAttrLabelIndices;
3748 
3749  // We must not export label placement property when the chart type doesn't
3750  // support this option in MS Office, else MS Office would think the file
3751  // is corrupt & refuse to open it.
3752 
3753  const chart::TypeGroupInfo& rInfo = chart::GetTypeGroupInfo(static_cast<chart::TypeId>(eChartType));
3754  LabelPlacementParam aParam(!mbIs3DChart, rInfo.mnDefLabelPos);
3755  switch (eChartType) // diagram chart type
3756  {
3757  case chart::TYPEID_PIE:
3759  aParam.mbExport = false;
3760  else
3761  // All pie charts support label placement.
3762  aParam.mbExport = true;
3763  break;
3764  case chart::TYPEID_AREA:
3767  // These chart types don't support label placement.
3768  aParam.mbExport = false;
3769  break;
3770  case chart::TYPEID_BAR:
3771  if (mbStacked || mbPercent)
3772  {
3773  aParam.maAllowedValues.clear();
3774  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3775  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3776  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3777  aParam.meDefault = css::chart::DataLabelPlacement::CENTER;
3778  }
3779  else // Clustered bar chart
3780  {
3781  aParam.maAllowedValues.clear();
3782  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::CENTER);
3783  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::INSIDE);
3784  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::OUTSIDE);
3785  aParam.maAllowedValues.insert(css::chart::DataLabelPlacement::NEAR_ORIGIN);
3786  aParam.meDefault = css::chart::DataLabelPlacement::OUTSIDE;
3787  }
3788  break;
3789  default:
3790  ;
3791  }
3792 
3793  for (const sal_Int32 nIdx : std::as_const(aAttrLabelIndices))
3794  {
3795  uno::Reference<beans::XPropertySet> xLabelPropSet = xSeries->getDataPointByIndex(nIdx);
3796 
3797  if (!xLabelPropSet.is())
3798  continue;
3799 
3800  pFS->startElement(FSNS(XML_c, XML_dLbl));
3801  pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nIdx));
3802 
3803  // export custom position of data label
3804  if( eChartType != chart::TYPEID_PIE )
3805  {
3806  chart2::RelativePosition aCustomLabelPosition;
3807  if( xLabelPropSet->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition )
3808  {
3809  pFS->startElement(FSNS(XML_c, XML_layout));
3810  pFS->startElement(FSNS(XML_c, XML_manualLayout));
3811 
3812  pFS->singleElement(FSNS(XML_c, XML_x), XML_val, OString::number(aCustomLabelPosition.Primary));
3813  pFS->singleElement(FSNS(XML_c, XML_y), XML_val, OString::number(aCustomLabelPosition.Secondary));
3814 
3815  SAL_WARN_IF(aCustomLabelPosition.Anchor != css::drawing::Alignment_TOP_LEFT, "oox", "unsupported anchor position");
3816 
3817  pFS->endElement(FSNS(XML_c, XML_manualLayout));
3818  pFS->endElement(FSNS(XML_c, XML_layout));
3819  }
3820  }
3821 
3822  if( GetProperty(xLabelPropSet, "LinkNumberFormatToSource") )
3823  mAny >>= bLinkedNumFmt;
3824 
3825  if( xLabelPropSet->getPropertyValue("Label") >>= aLabel )
3826  bLabelIsNumberFormat = aLabel.ShowNumber;
3827  else
3828  bLabelIsNumberFormat = true;
3829 
3830  if (GetProperty(xLabelPropSet, bLabelIsNumberFormat ? OUString("NumberFormat") : OUString("PercentageNumberFormat")))
3831  {
3832  sal_Int32 nKey = 0;
3833  mAny >>= nKey;
3834 
3835  OUString aNumberFormatString = getNumberFormatCode(nKey);
3836  OString sNumberFormatString = OUStringToOString(aNumberFormatString, RTL_TEXTENCODING_UTF8);
3837 
3838  pFS->singleElement(FSNS(XML_c, XML_numFmt), XML_formatCode, sNumberFormatString.getStr(),
3839  XML_sourceLinked, ToPsz10(bLinkedNumFmt));
3840  }
3841 
3842  // Individual label property that overwrites the baseline.
3843  writeLabelProperties(pFS, this, xLabelPropSet, aParam);
3844  pFS->endElement(FSNS(XML_c, XML_dLbl));
3845  }
3846 
3847  // Baseline label properties for all labels.
3848  writeLabelProperties(pFS, this, xPropSet, aParam);
3849 
3850  bool bShowLeaderLines = false;
3851  xPropSet->getPropertyValue("ShowCustomLeaderLines") >>= bShowLeaderLines;
3852  pFS->singleElement(FSNS(XML_c, XML_showLeaderLines), XML_val, ToPsz10(bShowLeaderLines));
3853 
3854  // Export leader line
3855  if( eChartType != chart::TYPEID_PIE )
3856  {
3857  pFS->startElement(FSNS(XML_c, XML_extLst));
3858  pFS->startElement(FSNS(XML_c, XML_ext), XML_uri, "{CE6537A1-D6FC-4f65-9D91-7224C49458BB}", FSNS(XML_xmlns, XML_c15), GetFB()->getNamespaceURL(OOX_NS(c15)));
3859  pFS->singleElement(FSNS(XML_c15, XML_showLeaderLines), XML_val, ToPsz10(bShowLeaderLines));
3860  pFS->endElement(FSNS(XML_c, XML_ext));
3861  pFS->endElement(FSNS(XML_c, XML_extLst));
3862  }
3863  pFS->endElement(FSNS(XML_c, XML_dLbls));
3864 }
3865 
3867  const uno::Reference< beans::XPropertySet > & xSeriesProperties,
3868  sal_Int32 nSeriesLength, sal_Int32 eChartType )
3869 {
3870  uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY );
3871  bool bVaryColorsByPoint = false;
3872  Sequence< sal_Int32 > aDataPointSeq;
3873  if( xSeriesProperties.is())
3874  {
3875  Any aAny = xSeriesProperties->getPropertyValue( "AttributedDataPoints" );
3876  aAny >>= aDataPointSeq;
3877  xSeriesProperties->getPropertyValue( "VaryColorsByPoint" ) >>= bVaryColorsByPoint;
3878  }
3879 
3880  const sal_Int32 * pPoints = aDataPointSeq.getConstArray();
3881  sal_Int32 nElement;
3882  Reference< chart2::XColorScheme > xColorScheme;
3883  if( mxNewDiagram.is())
3884  xColorScheme.set( mxNewDiagram->getDefaultColorScheme());
3885 
3886  if( bVaryColorsByPoint && xColorScheme.is() )
3887  {
3888  o3tl::sorted_vector< sal_Int32 > aAttrPointSet;
3889  aAttrPointSet.reserve(aDataPointSeq.getLength());
3890  for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
3891  aAttrPointSet.insert(*p);
3892  const auto aEndIt = aAttrPointSet.end();
3893  for( nElement = 0; nElement < nSeriesLength; ++nElement )
3894  {
3895  uno::Reference< beans::XPropertySet > xPropSet;
3896  if( aAttrPointSet.find( nElement ) != aEndIt )
3897  {
3898  try
3899  {
3901  xSeries, nElement, getModel() );
3902  }
3903  catch( const uno::Exception & )
3904  {
3905  DBG_UNHANDLED_EXCEPTION( "oox", "Exception caught during Export of data point" );
3906  }
3907  }
3908  else
3909  {
3910  // property set only containing the color
3911  xPropSet.set( new ColorPropertySet( ColorTransparency, xColorScheme->getColorByIndex( nElement )));
3912  }
3913 
3914  if( xPropSet.is() )
3915  {
3916  FSHelperPtr pFS = GetFS();
3917  pFS->startElement(FSNS(XML_c, XML_dPt));
3918  pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nElement));
3919 
3920  switch (eChartType)
3921  {
3922  case chart::TYPEID_PIE:
3924  {
3925  if( xPropSet.is() && GetProperty( xPropSet, "SegmentOffset") )
3926  {
3927  sal_Int32 nOffset = 0;
3928  mAny >>= nOffset;
3929  if (nOffset)
3930  pFS->singleElement( FSNS( XML_c, XML_explosion ),
3931  XML_val, OString::number( nOffset ) );
3932  }
3933  break;
3934  }
3935  default:
3936  break;
3937  }
3938  exportShapeProps( xPropSet );
3939 
3940  pFS->endElement( FSNS( XML_c, XML_dPt ) );
3941  }
3942  }
3943  }
3944 
3945  // Export Data Point Property in Charts even if the VaryColors is false
3946  if( bVaryColorsByPoint )
3947  return;
3948 
3949  o3tl::sorted_vector< sal_Int32 > aAttrPointSet;
3950  aAttrPointSet.reserve(aDataPointSeq.getLength());
3951  for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p)
3952  aAttrPointSet.insert(*p);
3953  const auto aEndIt = aAttrPointSet.end();
3954  for( nElement = 0; nElement < nSeriesLength; ++nElement )
3955  {
3956  uno::Reference< beans::XPropertySet > xPropSet;
3957  if( aAttrPointSet.find( nElement ) != aEndIt )
3958  {
3959  try
3960  {
3962  xSeries, nElement, getModel() );
3963  }
3964  catch( const uno::Exception & )
3965  {
3966  DBG_UNHANDLED_EXCEPTION( "oox", "Exception caught during Export of data point" );
3967  }
3968  }
3969 
3970  if( xPropSet.is() )
3971  {
3972  FSHelperPtr pFS = GetFS();
3973  pFS->startElement(FSNS(XML_c, XML_dPt));
3974  pFS->singleElement(FSNS(XML_c, XML_idx), XML_val, OString::number(nElement));
3975 
3976  switch( eChartType )
3977  {
3978  case chart::TYPEID_BUBBLE:
3979  case chart::TYPEID_HORBAR:
3980  case chart::TYPEID_BAR:
3981  pFS->singleElement(FSNS(XML_c, XML_invertIfNegative), XML_val, "0");
3982  exportShapeProps(xPropSet);
3983  break;
3984 
3985  case chart::TYPEID_LINE:
3986  case chart::TYPEID_SCATTER:
3988  exportMarker(xPropSet);
3989  break;
3990 
3991  default:
3992  exportShapeProps(xPropSet);
3993  break;
3994  }
3995 
3996  pFS->endElement( FSNS( XML_c, XML_dPt ) );
3997  }
3998  }
3999 }
4000 
4001 void ChartExport::exportAxesId(bool bPrimaryAxes, bool bCheckCombinedAxes)
4002 {
4003  sal_Int32 nAxisIdx, nAxisIdy;
4004  bool bPrimaryAxisExists = false;
4005  bool bSecondaryAxisExists = false;
4006  // let's check which axis already exists and which axis is attached to the actual dataseries
4007  if (maAxes.size() >= 2)
4008  {
4009  bPrimaryAxisExists = bPrimaryAxes && maAxes[1].nAxisType == AXIS_PRIMARY_Y;
4010  bSecondaryAxisExists = !bPrimaryAxes && maAxes[1].nAxisType == AXIS_SECONDARY_Y;
4011  }
4012  // tdf#114181 keep axes of combined charts
4013  if ( bCheckCombinedAxes && ( bPrimaryAxisExists || bSecondaryAxisExists ) )
4014  {
4015  nAxisIdx = maAxes[0].nAxisId;
4016  nAxisIdy = maAxes[1].nAxisId;
4017  }
4018  else
4019  {
4020  nAxisIdx = lcl_generateRandomValue();
4021  nAxisIdy = lcl_generateRandomValue();
4022  AxesType eXAxis = bPrimaryAxes ? AXIS_PRIMARY_X : AXIS_SECONDARY_X;
4023  AxesType eYAxis = bPrimaryAxes ? AXIS_PRIMARY_Y : AXIS_SECONDARY_Y;
4024  maAxes.emplace_back( eXAxis, nAxisIdx, nAxisIdy );
4025  maAxes.emplace_back( eYAxis, nAxisIdy, nAxisIdx );
4026  }
4027  FSHelperPtr pFS = GetFS();
4028  pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdx));
4029  pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdy));
4030  if (mbHasZAxis)
4031  {
4032  sal_Int32 nAxisIdz = 0;
4033  if( isDeep3dChart() )
4034  {
4035  nAxisIdz = lcl_generateRandomValue();
4036  maAxes.emplace_back( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy );
4037  }
4038  pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, OString::number(nAxisIdz));
4039  }
4040 }
4041 
4043 {
4044  FSHelperPtr pFS = GetFS();
4045  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4046  // grouping
4047  if( GetProperty( xPropSet, "Stacked" ) )
4048  mAny >>= mbStacked;
4049  if( GetProperty( xPropSet, "Percent" ) )
4050  mAny >>= mbPercent;
4051 
4052  const char* grouping = nullptr;
4053  if (mbStacked)
4054  grouping = "stacked";
4055  else if (mbPercent)
4056  grouping = "percentStacked";
4057  else
4058  {
4059  if( isBar && !isDeep3dChart() )
4060  {
4061  grouping = "clustered";
4062  }
4063  else
4064  grouping = "standard";
4065  }
4066  pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, grouping);
4067 }
4068 
4070 {
4071  FSHelperPtr pFS = GetFS();
4072  Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, UNO_QUERY );
4073  if( !xRegressionCurveContainer.is() )
4074  return;
4075 
4076  const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves();
4077  for( const Reference< chart2::XRegressionCurve >& xRegCurve : aRegCurveSeq )
4078  {
4079  if (!xRegCurve.is())
4080  continue;
4081 
4082  Reference< XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY );
4083 
4084  OUString aService;
4085  Reference< lang::XServiceName > xServiceName( xProperties, UNO_QUERY );
4086  if( !xServiceName.is() )
4087  continue;
4088 
4089  aService = xServiceName->getServiceName();
4090 
4091  if(aService != "com.sun.star.chart2.LinearRegressionCurve" &&
4092  aService != "com.sun.star.chart2.ExponentialRegressionCurve" &&
4093  aService != "com.sun.star.chart2.LogarithmicRegressionCurve" &&
4094  aService != "com.sun.star.chart2.PotentialRegressionCurve" &&
4095  aService != "com.sun.star.chart2.PolynomialRegressionCurve" &&
4096  aService != "com.sun.star.chart2.MovingAverageRegressionCurve")
4097  continue;
4098 
4099  pFS->startElement(FSNS(XML_c, XML_trendline));
4100 
4101  OUString aName;
4102  xProperties->getPropertyValue("CurveName") >>= aName;
4103  if(!aName.isEmpty())
4104  {
4105  pFS->startElement(FSNS(XML_c, XML_name));
4106  pFS->writeEscaped(aName);
4107  pFS->endElement( FSNS( XML_c, XML_name) );
4108  }
4109 
4110  exportShapeProps( xProperties );
4111 
4112  if( aService == "com.sun.star.chart2.LinearRegressionCurve" )
4113  {
4114  pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "linear");
4115  }
4116  else if( aService == "com.sun.star.chart2.ExponentialRegressionCurve" )
4117  {
4118  pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "exp");
4119  }
4120  else if( aService == "com.sun.star.chart2.LogarithmicRegressionCurve" )
4121  {
4122  pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "log");
4123  }
4124  else if( aService == "com.sun.star.chart2.PotentialRegressionCurve" )
4125  {
4126  pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "power");
4127  }
4128  else if( aService == "com.sun.star.chart2.PolynomialRegressionCurve" )
4129  {
4130  pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "poly");
4131 
4132  sal_Int32 aDegree = 2;
4133  xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
4134  pFS->singleElement(FSNS(XML_c, XML_order), XML_val, OString::number(aDegree));
4135  }
4136  else if( aService == "com.sun.star.chart2.MovingAverageRegressionCurve" )
4137  {
4138  pFS->singleElement(FSNS(XML_c, XML_trendlineType), XML_val, "movingAvg");
4139 
4140  sal_Int32 aPeriod = 2;
4141  xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
4142 
4143  pFS->singleElement(FSNS(XML_c, XML_period), XML_val, OString::number(aPeriod));
4144  }
4145  else
4146  {
4147  // should never happen
4148  // This would produce invalid OOXML files so we check earlier for the type
4149  assert(false);
4150  }
4151 
4152  double fExtrapolateForward = 0.0;
4153  double fExtrapolateBackward = 0.0;
4154 
4155  xProperties->getPropertyValue("ExtrapolateForward") >>= fExtrapolateForward;
4156  xProperties->getPropertyValue("ExtrapolateBackward") >>= fExtrapolateBackward;
4157 
4158  pFS->singleElement( FSNS( XML_c, XML_forward ),
4159  XML_val, OString::number(fExtrapolateForward) );
4160 
4161  pFS->singleElement( FSNS( XML_c, XML_backward ),
4162  XML_val, OString::number(fExtrapolateBackward) );
4163 
4164  bool bForceIntercept = false;
4165  xProperties->getPropertyValue("ForceIntercept") >>= bForceIntercept;
4166 
4167  if (bForceIntercept)
4168  {
4169  double fInterceptValue = 0.0;
4170  xProperties->getPropertyValue("InterceptValue") >>= fInterceptValue;
4171 
4172  pFS->singleElement( FSNS( XML_c, XML_intercept ),
4173  XML_val, OString::number(fInterceptValue) );
4174  }
4175 
4176  // Equation properties
4177  Reference< XPropertySet > xEquationProperties( xRegCurve->getEquationProperties() );
4178 
4179  // Show Equation
4180  bool bShowEquation = false;
4181  xEquationProperties->getPropertyValue("ShowEquation") >>= bShowEquation;
4182 
4183  // Show R^2
4184  bool bShowCorrelationCoefficient = false;
4185  xEquationProperties->getPropertyValue("ShowCorrelationCoefficient") >>= bShowCorrelationCoefficient;
4186 
4187  pFS->singleElement( FSNS( XML_c, XML_dispRSqr ),
4188  XML_val, ToPsz10(bShowCorrelationCoefficient) );
4189 
4190  pFS->singleElement(FSNS(XML_c, XML_dispEq), XML_val, ToPsz10(bShowEquation));
4191 
4192  pFS->endElement( FSNS( XML_c, XML_trendline ) );
4193  }
4194 }
4195 
4197 {
4198  chart2::Symbol aSymbol;
4199  if( GetProperty( xPropSet, "Symbol" ) )
4200  mAny >>= aSymbol;
4201 
4202  if(aSymbol.Style != chart2::SymbolStyle_STANDARD && aSymbol.Style != chart2::SymbolStyle_NONE)
4203  return;
4204 
4205  FSHelperPtr pFS = GetFS();
4206  pFS->startElement(FSNS(XML_c, XML_marker));
4207 
4208  sal_Int32 nSymbol = aSymbol.StandardSymbol;
4209  // TODO: more properties support for marker
4210  const char* pSymbolType; // no initialization here, to let compiler warn if we have a code path
4211  // where it stays uninitialized
4212  switch( nSymbol )
4213  {
4214  case 0:
4215  pSymbolType = "square";
4216  break;
4217  case 1:
4218  pSymbolType = "diamond";
4219  break;
4220  case 2:
4221  case 3:
4222  case 4:
4223  case 5:
4224  pSymbolType = "triangle";
4225  break;
4226  case 8:
4227  pSymbolType = "circle";
4228  break;
4229  case 9:
4230  pSymbolType = "star";
4231  break;
4232  case 10:
4233  pSymbolType = "x"; // in MS office 2010 built in symbol marker 'X' is represented as 'x'
4234  break;
4235  case 11:
4236  pSymbolType = "plus";
4237  break;
4238  case 13:
4239  pSymbolType = "dash";
4240  break;
4241  default:
4242  pSymbolType = "square";
4243  break;
4244  }
4245 
4246  bool bSkipFormatting = false;
4247  if (aSymbol.Style == chart2::SymbolStyle_NONE)
4248  {
4249  bSkipFormatting = true;
4250  pSymbolType = "none";
4251  }
4252 
4253  pFS->singleElement(FSNS(XML_c, XML_symbol), XML_val, pSymbolType);
4254 
4255  if (!bSkipFormatting)
4256  {
4257  awt::Size aSymbolSize = aSymbol.Size;
4258  sal_Int32 nSize = std::max( aSymbolSize.Width, aSymbolSize.Height );
4259 
4260  nSize = nSize/250.0*7.0 + 1; // just guessed based on some test cases,
4261  //the value is always 1 less than the actual value.
4262  nSize = std::clamp( int(nSize), 2, 72 );
4263  pFS->singleElement(FSNS(XML_c, XML_size), XML_val, OString::number(nSize));
4264 
4265  pFS->startElement(FSNS(XML_c, XML_spPr));
4266 
4267  util::Color aColor = aSymbol.FillColor;
4268  if (GetProperty(xPropSet, "Color"))
4269  mAny >>= aColor;
4270 
4271  if (aColor == -1)
4272  {
4273  pFS->singleElement(FSNS(XML_a, XML_noFill));
4274  }
4275  else
4277 
4278  pFS->endElement( FSNS( XML_c, XML_spPr ) );
4279  }
4280 
4281  pFS->endElement( FSNS( XML_c, XML_marker ) );
4282 }
4283 
4285 {
4286  FSHelperPtr pFS = GetFS();
4287  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY );
4288  sal_Int32 nSplineType = 0;
4289  if( GetProperty( xPropSet, "SplineType" ) )
4290  mAny >>= nSplineType;
4291  const char* pVal = nSplineType != 0 ? "1" : "0";
4292  pFS->singleElement(FSNS(XML_c, XML_smooth), XML_val, pVal);
4293 }
4294 
4296 {
4297  FSHelperPtr pFS = GetFS();
4298  sal_Int32 nStartingAngle = 0;
4299  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4300  if( GetProperty( xPropSet, "StartingAngle" ) )
4301  mAny >>= nStartingAngle;
4302 
4303  // convert to ooxml angle
4304  nStartingAngle = (450 - nStartingAngle ) % 360;
4305  pFS->singleElement(FSNS(XML_c, XML_firstSliceAng), XML_val, OString::number(nStartingAngle));
4306 }
4307 
4308 namespace {
4309 
4310 const char* getErrorBarStyle(sal_Int32 nErrorBarStyle)
4311 {
4312  switch(nErrorBarStyle)
4313  {
4314  case cssc::ErrorBarStyle::NONE:
4315  return nullptr;
4316  case cssc::ErrorBarStyle::VARIANCE:
4317  break;
4318  case cssc::ErrorBarStyle::STANDARD_DEVIATION:
4319  return "stdDev";
4320  case cssc::ErrorBarStyle::ABSOLUTE:
4321  return "fixedVal";
4322  case cssc::ErrorBarStyle::RELATIVE:
4323  return "percentage";
4324  case cssc::ErrorBarStyle::ERROR_MARGIN:
4325  break;
4326  case cssc::ErrorBarStyle::STANDARD_ERROR:
4327  return "stdErr";
4328  case cssc::ErrorBarStyle::FROM_DATA:
4329  return "cust";
4330  default:
4331  assert(false && "can't happen");
4332  }
4333  return nullptr;
4334 }
4335 
4336 Reference< chart2::data::XDataSequence> getLabeledSequence(
4337  const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences,
4338  bool bPositive )
4339 {
4340  OUString aDirection;
4341  if(bPositive)
4342  aDirection = "positive";
4343  else
4344  aDirection = "negative";
4345 
4346  for( const auto& rSequence : aSequences )
4347  {
4348  if( rSequence.is())
4349  {
4350  uno::Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues());
4351  uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW );
4352  OUString aRole;
4353  if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) &&
4354  aRole.match( "error-bars" ) && aRole.indexOf(aDirection) >= 0 )
4355  {
4356  return xSequence;
4357  }
4358  }
4359  }
4360 
4361  return Reference< chart2::data::XDataSequence > ();
4362 }
4363 
4364 }
4365 
4366 void ChartExport::exportErrorBar(const Reference< XPropertySet>& xErrorBarProps, bool bYError)
4367 {
4368  sal_Int32 nErrorBarStyle = cssc::ErrorBarStyle::NONE;
4369  xErrorBarProps->getPropertyValue("ErrorBarStyle") >>= nErrorBarStyle;
4370  const char* pErrorBarStyle = getErrorBarStyle(nErrorBarStyle);
4371  if(!pErrorBarStyle)
4372  return;
4373 
4374  FSHelperPtr pFS = GetFS();
4375  pFS->startElement(FSNS(XML_c, XML_errBars));
4376  pFS->singleElement(FSNS(XML_c, XML_errDir), XML_val, bYError ? "y" : "x");
4377  bool bPositive = false, bNegative = false;
4378  xErrorBarProps->getPropertyValue("ShowPositiveError") >>= bPositive;
4379  xErrorBarProps->getPropertyValue("ShowNegativeError") >>= bNegative;
4380  const char* pErrBarType;
4381  if(bPositive && bNegative)
4382  pErrBarType = "both";
4383  else if(bPositive)
4384  pErrBarType = "plus";
4385  else if(bNegative)
4386  pErrBarType = "minus";
4387  else
4388  {
4389  // what the hell should we do now?
4390  // at least this makes the file valid
4391  pErrBarType = "both";
4392  }
4393  pFS->singleElement(FSNS(XML_c, XML_errBarType), XML_val, pErrBarType);
4394  pFS->singleElement(FSNS(XML_c, XML_errValType), XML_val, pErrorBarStyle);
4395  pFS->singleElement(FSNS(XML_c, XML_noEndCap), XML_val, "0");
4396  if(nErrorBarStyle == cssc::ErrorBarStyle::FROM_DATA)
4397  {
4398  uno::Reference< chart2::data::XDataSource > xDataSource(xErrorBarProps, uno::UNO_QUERY);
4400  xDataSource->getDataSequences();
4401 
4402  if(bPositive)
4403  {
4404  exportSeriesValues(getLabeledSequence(aSequences, true), XML_plus);
4405  }
4406 
4407  if(bNegative)
4408  {
4409  exportSeriesValues(getLabeledSequence(aSequences, false), XML_minus);
4410  }
4411  }
4412  else
4413  {
4414  double nVal = 0.0;
4415  if(nErrorBarStyle == cssc::ErrorBarStyle::STANDARD_DEVIATION)
4416  {
4417  xErrorBarProps->getPropertyValue("Weight") >>= nVal;
4418  }
4419  else
4420  {
4421  if(bPositive)
4422  xErrorBarProps->getPropertyValue("PositiveError") >>= nVal;
4423  else
4424  xErrorBarProps->getPropertyValue("NegativeError") >>= nVal;
4425  }
4426 
4427  pFS->singleElement(FSNS(XML_c, XML_val), XML_val, OString::number(nVal));
4428  }
4429 
4430  exportShapeProps( xErrorBarProps );
4431 
4432  pFS->endElement( FSNS( XML_c, XML_errBars) );
4433 }
4434 
4436 {
4437  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4438  if( !xPropSet.is() )
4439  return;
4440  FSHelperPtr pFS = GetFS();
4441  pFS->startElement(FSNS(XML_c, XML_view3D));
4442  sal_Int32 eChartType = getChartType( );
4443  // rotX
4444  if( GetProperty( xPropSet, "RotationHorizontal" ) )
4445  {
4446  sal_Int32 nRotationX = 0;
4447  mAny >>= nRotationX;
4448  if( nRotationX < 0 )
4449  {
4450  if(eChartType == chart::TYPEID_PIE)
4451  {
4452  /* In OOXML we get value in 0..90 range for pie chart X rotation , whereas we expect it to be in -90..90 range,
4453  so we convert that during import. It is modified in View3DConverter::convertFromModel()
4454  here we convert it back to 0..90 as we received in import */
4455  nRotationX += 90; // X rotation (map Chart2 [-179,180] to OOXML [0..90])
4456  }
4457  else
4458  nRotationX += 360; // X rotation (map Chart2 [-179,180] to OOXML [-90..90])
4459  }
4460  pFS->singleElement(FSNS(XML_c, XML_rotX), XML_val, OString::number(nRotationX));
4461  }
4462  // rotY
4463  if( GetProperty( xPropSet, "RotationVertical" ) )
4464  {
4465  // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
4466  if( eChartType == chart::TYPEID_PIE && GetProperty( xPropSet, "StartingAngle" ) )
4467  {
4468  // Y rotation used as 'first pie slice angle' in 3D pie charts
4469  sal_Int32 nStartingAngle=0;
4470  mAny >>= nStartingAngle;
4471  // convert to ooxml angle
4472  nStartingAngle = (450 - nStartingAngle ) % 360;
4473  pFS->singleElement(FSNS(XML_c, XML_rotY), XML_val, OString::number(nStartingAngle));
4474  }
4475  else
4476  {
4477  sal_Int32 nRotationY = 0;
4478  mAny >>= nRotationY;
4479  // Y rotation (map Chart2 [-179,180] to OOXML [0..359])
4480  if( nRotationY < 0 )
4481  nRotationY += 360;
4482  pFS->singleElement(FSNS(XML_c, XML_rotY), XML_val, OString::number(nRotationY));
4483  }
4484  }
4485  // rAngAx
4486  if( GetProperty( xPropSet, "RightAngledAxes" ) )
4487  {
4488  bool bRightAngled = false;
4489  mAny >>= bRightAngled;
4490  const char* sRightAngled = bRightAngled ? "1":"0";
4491  pFS->singleElement(FSNS(XML_c, XML_rAngAx), XML_val, sRightAngled);
4492  }
4493  // perspective
4494  if( GetProperty( xPropSet, "Perspective" ) )
4495  {
4496  sal_Int32 nPerspective = 0;
4497  mAny >>= nPerspective;
4498  // map Chart2 [0,100] to OOXML [0..200]
4499  nPerspective *= 2;
4500  pFS->singleElement(FSNS(XML_c, XML_perspective), XML_val, OString::number(nPerspective));
4501  }
4502  pFS->endElement( FSNS( XML_c, XML_view3D ) );
4503 }
4504 
4506 {
4507  bool isDeep = false;
4508  if( mbIs3DChart )
4509  {
4510  Reference< XPropertySet > xPropSet( mxDiagram , uno::UNO_QUERY);
4511  if( GetProperty( xPropSet, "Deep" ) )
4512  mAny >>= isDeep;
4513  }
4514  return isDeep;
4515 }
4516 
4517 OUString ChartExport::getNumberFormatCode(sal_Int32 nKey) const
4518 {
4519  /* XXX if this was called more than one or two times per export the two
4520  * SvNumberFormatter instances and NfKeywordTable should be member
4521  * variables and initialized only once. */
4522 
4523  OUString aCode("General"); // init with fallback
4524  uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(mxChartModel, uno::UNO_QUERY_THROW);
4525  SvNumberFormatsSupplierObj* pSupplierObj = comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>( xNumberFormatsSupplier);
4526  if (!pSupplierObj)
4527  return aCode;
4528 
4529  SvNumberFormatter* pNumberFormatter = pSupplierObj->GetNumberFormatter();
4530  if (!pNumberFormatter)
4531  return aCode;
4532 
4534  NfKeywordTable aKeywords;
4535  aTempFormatter.FillKeywordTableForExcel( aKeywords);
4536  aCode = pNumberFormatter->GetFormatStringForExcel( nKey, aKeywords, aTempFormatter);
4537 
4538  return aCode;
4539 }
4540 
4541 }// oox
4542 
4543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::chart::XDiagram > mxDiagram
void WritePattFill(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
const char * sName
Definition: olehelper.cxx:92
void _exportAxis(const css::uno::Reference< css::beans::XPropertySet > &xAxisProp, const css::uno::Reference< css::drawing::XShape > &xAxisTitle, const css::uno::Reference< css::beans::XPropertySet > &xMajorGrid, const css::uno::Reference< css::beans::XPropertySet > &xMinorGrid, sal_Int32 nAxisType, const char *sAxisPos, const AxisIdPair &rAxisIdPair)
void exportTextProps(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportSeriesText(const css::uno::Reference< css::chart2::data::XDataSequence > &xValueSeq)
bool hasValue()
sal_Int32 nIndex
bool bVisible
css::uno::Reference< css::chart2::XDiagram > mxNewDiagram
std::unordered_set< sal_Int32 > maAllowedValues
#define LANGUAGE_ENGLISH_US
void WriteXGraphicBlipFill(css::uno::Reference< css::beans::XPropertySet > const &rXPropSet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic, sal_Int32 nXmlNamespace, bool bWriteMode, bool bRelPathToMedia=false)
Definition: drawingml.cxx:1553
bool getProperty(Type &orValue, sal_Int32 nPropId) const
Gets the specified property from the property set.
Definition: propertyset.hxx:94
const sal_Int32 PER_PERCENT
void exportBubbleChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
static css::uno::Reference< css::beans::XPropertySet > createOldAPISeriesPropertySet(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, const css::uno::Reference< css::frame::XModel > &xChartModel)
static sal_Int32 lcl_getChartType(std::u16string_view sChartType)
void WriteShapeTransformation(const css::uno::Reference< css::drawing::XShape > &rXShape, sal_Int32 nXmlNamespace, bool bFlipH=false, bool bFlipV=false, bool bSuppressRotation=false, bool bSuppressFlipping=false, bool bFlippedBeforeRotation=false)
Definition: drawingml.cxx:1771
void exportCandleStickSeries(const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > &aSeriesSeq, bool &rPrimaryAxes)
void exportSeriesValues(const css::uno::Reference< css::chart2::data::XDataSequence > &xValueSeq, sal_Int32 nValueType=XML_val)
void exportTitle(const css::uno::Reference< css::drawing::XShape > &xShape, const OUString *pSubText=nullptr)
static bool lcl_isSeriesAttachedToFirstAxis(const Reference< chart2::XDataSeries > &xDataSeries)
void FillKeywordTableForExcel(NfKeywordTable &rKeywords)
const_iterator find(const Value &x) const
const css::uno::Reference< css::frame::XModel > & getModel() const
::sax_fastparser::FSHelperPtr mpFS
Definition: drawingml.hxx:160
std::shared_ptr< T > make_shared(Args &&...args)
void exportAdditionalShapes(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
float x
static constexpr const char * ToPsz10(bool b)
Definition: utils.hxx:49
static::std::vector< double > lcl_getAllValuesFromSequence(const Reference< chart2::data::XDataSequence > &xSeq)
bool GetProperty(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &aName)
Definition: drawingml.cxx:261
std::set< sal_Int32 > maExportedAxis
css::uno::Any const & rValue
void exportGrouping(bool isBar=false)
void exportScatterChartSeries(const css::uno::Reference< css::chart2::XChartType > &xChartType, const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries >> *pSeries)
Sequence< PropertyValue > aArguments
void WriteSolidFill(::Color nColor, sal_Int32 nAlpha=MAX_PERCENT)
Definition: drawingml.cxx:401
OUString getNamespaceURL(sal_Int32 nNSID) const
void exportPieChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportRadarChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportMissingValueTreatment(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
ShapeExport & WriteShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Write the DrawingML for a particular shape.
Definition: shapes.cxx:1567
void exportHatch(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void WriteChartObj(const css::uno::Reference< css::drawing::XShape > &xShape, sal_Int32 nID, sal_Int32 nChartCount)
void SetURLTranslator(const std::shared_ptr< URLTransformer > &pTransformer)
void exportErrorBar(const css::uno::Reference< css::beans::XPropertySet > &xErrorBarProps, bool bYError)
void reserve(size_type amount)
void exportExternalData(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void exportSeries(const css::uno::Reference< css::chart2::XChartType > &xChartType, const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > &rSeriesSeq, bool &rPrimaryAxes)
sax_fastparser::FSHelperPtr CreateOutputStream(const OUString &sFullStream, std::u16string_view sRelativeStream, const css::uno::Reference< css::io::XOutputStream > &xParentRelation, const char *sContentType, const char *sRelationshipType, OUString *pRelationshipId)
Definition: drawingml.cxx:3994
void exportVaryColors(const css::uno::Reference< css::chart2::XChartType > &xChartType)
static cssc::TimeIncrement lcl_getDateTimeIncrement(const Reference< chart2::XDiagram > &xDiagram, sal_Int32 nAxisIndex)
std::shared_ptr< URLTransformer > mpURLTransformer
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
OUString getRelationship(Relationship eRelationship)
bool getOutputStream(ProgramOptions const &options, OString const &extension, std::ostream **ppOutputStream, OString &targetSourceFileName, OString &tmpSourceFileName)
const ::sax_fastparser::FSHelperPtr & GetFS() const
Definition: drawingml.hxx:207
float y
void exportAreaChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportShapeProps(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
static Reference< chart2::data::XLabeledDataSequence > lcl_getCategories(const Reference< chart2::XDiagram > &xDiagram)
void exportLineChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportStockChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
#define DBG_UNHANDLED_EXCEPTION(...)
DocumentType GetDocumentType() const
Definition: drawingml.hxx:209
css::uno::Reference< css::chart2::data::XDataSequence > mxCategoriesValues
TypeId
Enumerates different chart types.
#define TOOLS_WARN_EXCEPTION(area, stream)
Contains info for a chart type related to the OpenOffice.org chart module.
void exportSeriesCategory(const css::uno::Reference< css::chart2::data::XDataSequence > &xValueSeq, sal_Int32 nValueType=XML_cat)
OString calcRotationValue(sal_Int32 nRotation)
nRotation is a 100th of a degree and the return value is in a 60,000th of a degree ...
void WriteGradientFill(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
static sal_Int32 lcl_generateRandomValue()
uno_Any a
static sal_Int32 lcl_getCategoryAxisType(const Reference< chart2::XDiagram > &xDiagram, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex)
css::drawing::Direction3D aDirection
const sal_Int32 MAX_PERCENT
void exportAllSeries(const css::uno::Reference< css::chart2::XChartType > &xChartType, bool &rPrimaryAxes)
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)
OUString GetFormatStringForExcel(sal_uInt32 nKey, const NfKeywordTable &rKeywords, SvNumberFormatter &rTempFormatter) const
static sal_Int32 getNewDrawingUniqueId()
Definition: drawingml.hxx:339
OUString m_aRole
const TypeGroupInfo & GetTypeGroupInfo(TypeId eType)
sal_Int64 convertHmmToEmu(sal_Int32 nValue)
Converts the passed 32-bit integer value from 1/100 mm to EMUs.
float u
Pie-to-pie or pie-to-bar chart.
sal_Int32 w
void WriteRunProperties(const css::uno::Reference< css::beans::XPropertySet > &rRun, bool bIsField, sal_Int32 nElement, bool bCheckDirect, bool &rbOverridingCharHeight, sal_Int32 &rnCharHeight, sal_Int16 nScriptType=css::i18n::ScriptType::LATIN, const css::uno::Reference< css::beans::XPropertySet > &rXShapePropSet={})
Definition: drawingml.cxx:1891
constexpr double deg2rad(double v)
OUString parseFormula(const OUString &rRange)
ColorTransparency
const_iterator end() const
void exportBarChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
A wrapper for a UNO property set.
Definition: propertyset.hxx:57
std::shared_ptr< FastSerializerHelper > FSHelperPtr
void exportChartSpace(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc, bool bIncludeTable)
constexpr T & temporary(T &&x)
void exportTrendlines(const css::uno::Reference< css::chart2::XDataSeries > &xSeries)
const sal_uInt16 idx[]
void WriteOutline(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, css::uno::Reference< css::frame::XModel > const &xModel=nullptr)
Definition: drawingml.cxx:816
sal_Int32 mnDefLabelPos
Mode for varying point colors.
void exportChart(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void exportBitmapFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportDataLabels(const css::uno::Reference< css::chart2::XDataSeries > &xSeries, sal_Int32 nSeriesLength, sal_Int32 eChartType)
void exportLegend(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
void exportFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
#define TOOLS_INFO_EXCEPTION(area, stream)
void exportDataPoints(const css::uno::Reference< css::beans::XPropertySet > &xSeriesProperties, sal_Int32 nSeriesLength, sal_Int32 eChartType)
const css::uno::Reference< css::lang::XMultiServiceFactory > & getModelFactory() const
Returns the service factory provided by the document model (always existing).
Definition: filterbase.cxx:222
bool mbExport
bool getBoolProperty(sal_Int32 nPropId) const
Gets the specified boolean property from the property set.
Definition: propertyset.hxx:99
static void lcl_fillCategoriesIntoStringVector(const Reference< chart2::data::XDataSequence > &xCategories,::std::vector< OUString > &rOutCategories)
css::uno::Reference< css::frame::XModel > mxChartModel
css::uno::Sequence< css::uno::Sequence< rtl::OUString > > getSplitCategoriesList(const OUString &rRange)
static bool lcl_isCategoryAxisShifted(const Reference< chart2::XDiagram > &xDiagram)
void exportAxis(const AxisIdPair &rAxisIdPair)
static OUString lclGetTimeUnitToken(sal_Int32 nTimeUnit)
static sal_Int32 lcl_getAlphaFromTransparenceGradient(const awt::Gradient &rGradient, bool bStart)
static Reference< chart2::data::XLabeledDataSequence > lcl_getDataSequenceByRole(const Sequence< Reference< chart2::data::XLabeledDataSequence > > &aLabeledSeq, const OUString &rRole)
void exportUpDownBars(const css::uno::Reference< css::chart2::XChartType > &xChartType)
void exportSurfaceChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
#define SAL_WARN_IF(condition, area, stream)
unsigned char sal_uInt8
orientation
void exportSolidFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
void exportScatterChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
static void WriteFromTo(const css::uno::Reference< css::drawing::XShape > &rXShape, const css::awt::Size &aPageSize, const sax_fastparser::FSHelperPtr &pDrawing)
Definition: drawingml.cxx:5216
void SetFS(::sax_fastparser::FSHelperPtr pFS)
Definition: drawingml.hxx:206
OUString aName
::oox::core::XmlFilterBase * GetFB()
Definition: drawingml.hxx:208
if(aStr!=aBuf) UpdateName_Impl(m_xFollowLb.get()
int uniform_int_distribution(int a, int b)
void exportDoughnutChart(const css::uno::Reference< css::chart2::XChartType > &xChartType)
SvNumberFormatter * GetNumberFormatter() const
OUString aLabel
void * p
Reference< XComponentContext > getProcessComponentContext()
double getLength(const B2DPolygon &rCandidate)
void exportPlotArea(const css::uno::Reference< css::chart::XChartDocument > &rChartDoc)
constexpr sal_Int32 FSNS(sal_Int32 namespc, sal_Int32 element)
void exportMarker(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
sal_Int32 meDefault
OUString sId
void exportGradientFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
::oox::core::XmlFilterBase * mpFB
Definition: drawingml.hxx:161
ResultType type
static OUString lcl_flattenStringSequence(const Sequence< OUString > &rSequence)
#define SAL_WARN(area, stream)
static Sequence< OUString > lcl_getLabelSequence(const Reference< chart2::data::XDataSequence > &xLabelSeq)
sal_Int32 nLength
void exportManualLayout(const css::chart2::RelativePosition &rPos, const css::chart2::RelativeSize &rSize, const bool bIsExcludingDiagramPositioning)
std::pair< const_iterator, bool > insert(Value &&x)
void exportAxesId(bool bPrimaryAxes, bool bCheckCombinedAxes=false)
static bool lcl_hasCategoryLabels(const Reference< chart2::XChartDocument > &xChartDoc)
sal_Int32 h
OUString addRelation(const OUString &rType, std::u16string_view rTarget)
Adds new relation.
aStr
OUString getNumberFormatCode(sal_Int32 nKey) const
sal_Int16 nValue
void InitRangeSegmentationProperties(const css::uno::Reference< css::chart2::XChartDocument > &xChartDoc)