LibreOffice Module oox (master)  1
seriesconverter.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 
21 
22 #include <com/sun/star/chart/DataLabelPlacement.hpp>
23 #include <com/sun/star/chart2/RelativePosition.hpp>
24 #include <com/sun/star/chart/ErrorBarStyle.hpp>
25 #include <com/sun/star/chart2/DataPointLabel.hpp>
26 #include <com/sun/star/drawing/Hatch.hpp>
27 #include <com/sun/star/chart2/XChartDocument.hpp>
28 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
29 #include <com/sun/star/chart2/DataPointCustomLabelField.hpp>
30 #include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
31 #include <com/sun/star/chart2/XDataSeries.hpp>
32 #include <com/sun/star/chart2/XRegressionCurve.hpp>
33 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
34 #include <com/sun/star/chart2/data/XDataSink.hpp>
35 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/drawing/FillStyle.hpp>
38 
39 #include <comphelper/sequence.hxx>
40 #include <osl/diagnose.h>
50 #include <oox/token/properties.hxx>
51 #include <oox/token/tokens.hxx>
54 #include <drawingml/textrun.hxx>
55 #include <drawingml/textfield.hxx>
56 #include <drawingml/textbody.hxx>
57 #include <drawingml/hatchmap.hxx>
58 
59 namespace oox::drawingml::chart {
60 
61 using namespace com::sun::star;
62 using namespace ::com::sun::star::beans;
63 using namespace ::com::sun::star::chart2;
64 using namespace ::com::sun::star::chart2::data;
65 using namespace ::com::sun::star::uno;
66 
67 namespace {
68 
69 Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
70  const ConverterRoot& rParent,
71  DataSourceModel* pValues, const OUString& rRole,
72  TextModel* pTitle = nullptr )
73 {
74  // create data sequence for values
75  Reference< XDataSequence > xValueSeq;
76  if( pValues )
77  {
78  DataSourceConverter aSourceConv( rParent, *pValues );
79  xValueSeq = aSourceConv.createDataSequence( rRole );
80  }
81 
82  // create data sequence for title
83  Reference< XDataSequence > xTitleSeq;
84  if( pTitle )
85  {
86  TextConverter aTextConv( rParent, *pTitle );
87  xTitleSeq = aTextConv.createDataSequence( "label" );
88  }
89 
90  // create the labeled data sequence, if values or title are present
91  Reference< XLabeledDataSequence > xLabeledSeq;
92  if( xValueSeq.is() || xTitleSeq.is() )
93  {
94  xLabeledSeq = LabeledDataSequence::create(rParent.getComponentContext());
95  if( xLabeledSeq.is() )
96  {
97  xLabeledSeq->setValues( xValueSeq );
98  xLabeledSeq->setLabel( xTitleSeq );
99  }
100  }
101  return xLabeledSeq;
102 }
103 
104 void convertTextProperty(PropertySet& rPropSet, ObjectFormatter& rFormatter,
106 {
107  rFormatter.convertTextFormatting( rPropSet, xTextProps, OBJECTTYPE_DATALABEL );
108  ObjectFormatter::convertTextRotation( rPropSet, xTextProps, false );
109  ObjectFormatter::convertTextWrap( rPropSet, xTextProps );
110 }
111 
112 void lclConvertLabelFormatting( PropertySet& rPropSet, ObjectFormatter& rFormatter,
113  DataLabelModelBase& rDataLabel, const TypeGroupConverter& rTypeGroup,
114  bool bDataSeriesLabel, bool bCustomLabelField, bool bHasInternalData, bool bMSO2007Doc )
115 {
116  const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
117 
118  /* Excel 2007 does not change the series setting for a single data point,
119  if none of some specific elements occur. But only one existing element
120  in a data point will reset most other of these elements from the series
121  (e.g.: series has <c:showVal>, data point has <c:showCatName>, this
122  will reset <c:showVal> for this point, unless <c:showVal> is repeated
123  in the data point). The elements <c:layout>, <c:numberFormat>,
124  <c:spPr>, <c:tx>, and <c:txPr> are not affected at all. */
125  bool bHasAnyElement = true;
126  if (bMSO2007Doc)
127  {
128  bHasAnyElement = rDataLabel.moaSeparator.has() || rDataLabel.monLabelPos.has() ||
129  rDataLabel.mobShowCatName.has() || rDataLabel.mobShowLegendKey.has() ||
130  rDataLabel.mobShowPercent.has() || rDataLabel.mobShowSerName.has() ||
131  rDataLabel.mobShowVal.has();
132  }
133 
134  bool bShowValue = !rDataLabel.mbDeleted && rDataLabel.mobShowVal.get( !bMSO2007Doc );
135  bool bShowPercent = !rDataLabel.mbDeleted && rDataLabel.mobShowPercent.get( !bMSO2007Doc ) && (rTypeInfo.meTypeCategory == TYPECATEGORY_PIE);
136  bool bShowCateg = !rDataLabel.mbDeleted && rDataLabel.mobShowCatName.get( !bMSO2007Doc );
137  bool bShowSerName = !rDataLabel.mbDeleted && rDataLabel.mobShowSerName.get( !bMSO2007Doc );
138  bool bShowSymbol = !rDataLabel.mbDeleted && rDataLabel.mobShowLegendKey.get( !bMSO2007Doc );
139 
140  // tdf#132174, tdf#136650: the inner data table has no own cell number format.
141  if( bHasInternalData && bShowValue && !bShowPercent )
142  rDataLabel.maNumberFormat.mbSourceLinked = false;
143 
144  // type of attached label
145  if( bHasAnyElement || rDataLabel.mbDeleted )
146  {
147  DataPointLabel aPointLabel( bShowValue, bShowPercent, bShowCateg, bShowSymbol, bCustomLabelField, bShowSerName );
148  rPropSet.setProperty( PROP_Label, aPointLabel );
149  }
150 
151  if( rDataLabel.mbDeleted )
152  return;
153 
154  // data label number format (percentage format wins over value format)
155  rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, false, bShowPercent );
156 
157  // data label text formatting (frame formatting not supported by Chart2)
158  if( bDataSeriesLabel || (rDataLabel.mxTextProp.is() && !rDataLabel.mxTextProp->getParagraphs().empty()) )
159  convertTextProperty(rPropSet, rFormatter, rDataLabel.mxTextProp);
160 
161  // data label separator (do not overwrite series separator, if no explicit point separator is present)
162  // Set the data label separator to "new line" if the value is shown as percentage with a category name,
163  // just like in MS-Office. In any other case the default separator will be a semicolon.
164  if( bShowPercent && !bShowValue && ( bDataSeriesLabel || rDataLabel.moaSeparator.has() ) )
165  rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "\n" ) );
166  else if( bDataSeriesLabel || rDataLabel.moaSeparator.has() )
167  rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "; " ) );
168 
169  // data label placement (do not overwrite series placement, if no explicit point placement is present)
170  if( !(bDataSeriesLabel || rDataLabel.monLabelPos.has()) )
171  return;
172 
173  namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
174  sal_Int32 nPlacement = -1;
175  switch( rDataLabel.monLabelPos.get( XML_TOKEN_INVALID ) )
176  {
177  case XML_outEnd: nPlacement = csscd::OUTSIDE; break;
178  case XML_inEnd: nPlacement = csscd::INSIDE; break;
179  case XML_ctr: nPlacement = csscd::CENTER; break;
180  case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break;
181  case XML_t: nPlacement = csscd::TOP; break;
182  case XML_b: nPlacement = csscd::BOTTOM; break;
183  case XML_l: nPlacement = csscd::LEFT; break;
184  case XML_r: nPlacement = csscd::RIGHT; break;
185  case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break;
186  }
187 
188  if( !bDataSeriesLabel && nPlacement == -1 )
189  return;
190 
191  if( nPlacement == -1 )
192  nPlacement = rTypeInfo.mnDefLabelPos;
193 
194  rPropSet.setProperty( PROP_LabelPlacement, nPlacement );
195 }
196 
197 void importBorderProperties( PropertySet& rPropSet, Shape& rShape, const GraphicHelper& rGraphicHelper )
198 {
199  LineProperties& rLP = rShape.getLineProperties();
200  // no fill has the same effect as no border so skip it
201  if (rLP.maLineFill.moFillType.get() == XML_noFill)
202  return;
203 
204  if (rLP.moLineWidth.has())
205  {
206  sal_Int32 nWidth = convertEmuToHmm(rLP.moLineWidth.get());
207  rPropSet.setProperty(PROP_LabelBorderWidth, uno::makeAny(nWidth));
208  rPropSet.setProperty(PROP_LabelBorderStyle, uno::makeAny(drawing::LineStyle_SOLID));
209  }
210  const Color& aColor = rLP.maLineFill.maFillColor;
211  ::Color nColor = aColor.getColor(rGraphicHelper);
212  rPropSet.setProperty(PROP_LabelBorderColor, uno::makeAny(nColor));
213 }
214 
215 void importFillProperties( PropertySet& rPropSet, Shape& rShape, const GraphicHelper& rGraphicHelper, ModelObjectHelper& rModelObjHelper )
216 {
217  FillProperties& rFP = rShape.getFillProperties();
218 
219  if (rFP.moFillType.has() && rFP.moFillType.get() == XML_solidFill)
220  {
221  rPropSet.setProperty(PROP_LabelFillStyle, drawing::FillStyle_SOLID);
222 
223  const Color& aColor = rFP.maFillColor;
224  ::Color nColor = aColor.getColor(rGraphicHelper);
225  rPropSet.setProperty(PROP_LabelFillColor, uno::makeAny(nColor));
226  }
227  else if(rFP.moFillType.has() && rFP.moFillType.get() == XML_pattFill)
228  {
229  rPropSet.setProperty(PROP_LabelFillStyle, drawing::FillStyle_HATCH);
230  rPropSet.setProperty(PROP_LabelFillBackground, true);
231 
232  Color aHatchColor( rFP.maPatternProps.maPattFgColor );
233  drawing::Hatch aHatch = createHatch(rFP.maPatternProps.moPattPreset.get(), aHatchColor.getColor(rGraphicHelper, 0));
234 
235  OUString sHatchName = rModelObjHelper.insertFillHatch(aHatch);
236  rPropSet.setProperty(PROP_LabelFillHatchName, sHatchName);
237 
238  const Color& aColor = rFP.maPatternProps.maPattBgColor;
239  ::Color nColor = aColor.getColor(rGraphicHelper);
240  rPropSet.setProperty(PROP_LabelFillColor, uno::makeAny(nColor));
241  }
242 
243 }
244 
245 DataPointCustomLabelFieldType lcl_ConvertFieldNameToFieldEnum( std::u16string_view rField )
246 {
247  if (rField == u"VALUE")
248  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_VALUE;
249  else if (rField == u"SERIESNAME")
250  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_SERIESNAME;
251  else if (rField == u"CATEGORYNAME")
252  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CATEGORYNAME;
253  else if (rField == u"CELLREF")
254  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLREF;
255  else if (rField == u"CELLRANGE")
256  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE;
257  else if (rField == u"PERCENTAGE")
258  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_PERCENTAGE;
259  else
260  return DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT;
261 }
262 
263 } // namespace
264 
266  ConverterBase< DataLabelModel >( rParent, rModel )
267 {
268 }
269 
271 {
272 }
273 
275 {
276  if (!rxDataSeries.is())
277  return;
278 
279  try
280  {
281  bool bMSO2007Doc = getFilter().isMSO2007Document();
282  bool bHasInternalData = getChartDocument()->hasInternalDataProvider();
283  bool bCustomLabelField = mrModel.mxText && mrModel.mxText->mxTextBody && !mrModel.mxText->mxTextBody->getParagraphs().empty();
284  PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
285 
286  lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, false, bCustomLabelField, bHasInternalData, bMSO2007Doc );
287 
288  const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
289  bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
290 
291  if( mrModel.mxLayout && !mrModel.mxLayout->mbAutoLayout )
292  {
293  RelativePosition aPos(mrModel.mxLayout->mfX, mrModel.mxLayout->mfY, css::drawing::Alignment_TOP_LEFT);
294  aPropSet.setProperty(PROP_CustomLabelPosition, aPos);
295  sal_Int32 nPlacement = -1;
296  if (bIsPie && aPropSet.getProperty(nPlacement, PROP_LabelPlacement)
297  && nPlacement == css::chart::DataLabelPlacement::AVOID_OVERLAP)
298  aPropSet.setProperty(PROP_LabelPlacement, css::chart::DataLabelPlacement::CUSTOM);
299  }
300 
301  if (mrModel.mxShapeProp)
302  {
303  importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
304  uno::Reference<lang::XMultiServiceFactory> xFactory(getChartDocument(), uno::UNO_QUERY);
306  importFillProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper(),
307  rHelper);
308  }
309  if( bCustomLabelField )
310  {
311  css::uno::Reference< XComponentContext > xContext = getComponentContext();
312 
313  auto& rParagraphs = mrModel.mxText->mxTextBody->getParagraphs();
314 
315  int nSequenceSize = 0;
316  for( auto& pParagraph : rParagraphs )
317  nSequenceSize += pParagraph->getRuns().size();
318 
319  int nParagraphs = rParagraphs.size();
320  if( nParagraphs > 1 )
321  nSequenceSize += nParagraphs - 1;
322 
323  OptValue< OUString > oaLabelText;
324  OptValue< OUString > oaCellRange;
326  {
327  const DataSourceModel* pLabelSource = mrModel.mrParent.mpLabelsSource;
328  if (pLabelSource && pLabelSource->mxDataSeq.is())
329  {
330  oaCellRange = pLabelSource->mxDataSeq->maFormula;
331  const auto& rLabelMap = pLabelSource->mxDataSeq->maData;
332  const auto& rKV = rLabelMap.find(mrModel.mnIndex);
333  if (rKV != rLabelMap.end())
334  rKV->second >>= oaLabelText.use();
335  }
336  }
337 
338  uno::Sequence< css::uno::Reference< XDataPointCustomLabelField > > aSequence( nSequenceSize );
339  auto aSequenceRange = asNonConstRange(aSequence);
340 
341  int nPos = 0;
342 
343  for( auto& pParagraph : rParagraphs )
344  {
345  for( auto& pRun : pParagraph->getRuns() )
346  {
347  css::uno::Reference< XDataPointCustomLabelField > xCustomLabel = DataPointCustomLabelField::create( xContext );
348 
349  // Store properties
350  oox::PropertySet aPropertySet( xCustomLabel );
351  convertTextProperty( aPropertySet, getFormatter(), mrModel.mxText->mxTextBody );
352  pRun->getTextCharacterProperties().pushToPropSet( aPropertySet, getFilter() );
353 
354  TextField* pField = nullptr;
355  if( ( pField = dynamic_cast< TextField* >( pRun.get() ) ) )
356  {
357  DataPointCustomLabelFieldType eType = lcl_ConvertFieldNameToFieldEnum( pField->getType() );
358 
359  if (eType == DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE && oaCellRange.has())
360  {
361  xCustomLabel->setCellRange( oaCellRange.get() );
362  xCustomLabel->setString( oaLabelText.get() );
363  xCustomLabel->setDataLabelsRange( true );
364  }
365  else
366  xCustomLabel->setString( pField->getText() );
367 
368  xCustomLabel->setFieldType( eType );
369  xCustomLabel->setGuid( pField->getUuid() );
370  }
371  else if( pRun )
372  {
373  xCustomLabel->setString( pRun->getText() );
374  xCustomLabel->setFieldType( DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT );
375  }
376  aSequenceRange[ nPos++ ] = xCustomLabel;
377  }
378 
379  if( nParagraphs > 1 && nPos < nSequenceSize )
380  {
381  css::uno::Reference< XDataPointCustomLabelField > xCustomLabel = DataPointCustomLabelField::create( xContext );
382  xCustomLabel->setFieldType( DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_NEWLINE );
383  xCustomLabel->setString("\n");
384  aSequenceRange[ nPos++ ] = xCustomLabel;
385  }
386  }
387 
388  aPropSet.setProperty( PROP_CustomLabelFields, makeAny( aSequence ) );
389  convertTextProperty(aPropSet, getFormatter(), mrModel.mxText->mxTextBody);
390  }
391  }
392  catch( Exception& )
393  {
394  }
395 }
396 
398  ConverterBase< DataLabelsModel >( rParent, rModel )
399 {
400 }
401 
403 {
404 }
405 
406 namespace
407 {
409 void InheritFromDataLabelsTextProps(const DataLabelsModel& rLabels, const DataLabelModel& rLabel)
410 {
411  // See if <c:dLbls> contains text properties to inherit.
412  if (!rLabels.mxTextProp.is() || rLabels.mxTextProp->getParagraphs().empty())
413  {
414  return;
415  }
416 
417  const std::shared_ptr<TextParagraph>& rLabelsParagraph = rLabels.mxTextProp->getParagraphs()[0];
418 
419  // See if <c:dLbl> lacks text properties.
420  if (rLabel.mxTextProp.is())
421  {
422  return;
423  }
424 
425  if (!rLabel.mxText || !rLabel.mxText->mxTextBody
426  || rLabel.mxText->mxTextBody->getParagraphs().empty())
427  {
428  return;
429  }
430 
431  const std::shared_ptr<TextParagraph>& rLabelParagraph
432  = rLabel.mxText->mxTextBody->getParagraphs()[0];
433 
434  // Inherit rLabel.mxText's char props from rLabels.mxTextProp's char props.
435  TextCharacterProperties aCharProps;
436  aCharProps.assignUsed(rLabelsParagraph->getProperties().getTextCharacterProperties());
437  aCharProps.assignUsed(rLabelParagraph->getProperties().getTextCharacterProperties());
438  rLabelParagraph->getProperties().getTextCharacterProperties().assignUsed(aCharProps);
439 }
440 }
441 
443 {
444  PropertySet aPropSet( rxDataSeries );
445  if( !mrModel.mbDeleted )
446  {
447  bool bMSO2007Doc = getFilter().isMSO2007Document();
448  bool bHasInternalData = getChartDocument()->hasInternalDataProvider();
449 
450  lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, true, false, bHasInternalData, bMSO2007Doc );
451 
452  if (mrModel.mxShapeProp)
453  {
454  // Import baseline border properties for these data labels.
455  importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
456  uno::Reference<lang::XMultiServiceFactory> xFactory(getChartDocument(), uno::UNO_QUERY);
458  importFillProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper(),
459  rHelper);
460  }
461  }
462  // import leaderline of data labels
464  aPropSet.setProperty( PROP_ShowCustomLeaderLines, false );
465 
466  // data point label settings
467  for (auto const& pointLabel : mrModel.maPointLabels)
468  {
469  if (pointLabel->maNumberFormat.maFormatCode.isEmpty())
470  pointLabel->maNumberFormat = mrModel.maNumberFormat;
471  InheritFromDataLabelsTextProps(mrModel, *pointLabel);
472 
473  DataLabelConverter aLabelConv(*this, *pointLabel);
474  aLabelConv.convertFromModel( rxDataSeries, rTypeGroup );
475  }
476 }
477 
479  ConverterBase< ErrorBarModel >( rParent, rModel )
480 {
481 }
482 
484 {
485 }
486 
488 {
489  bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both);
490  bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both);
491  if( !(bShowPos || bShowNeg) )
492  return;
493 
494  try
495  {
496  Reference< XPropertySet > xErrorBar( createInstance( "com.sun.star.chart2.ErrorBar" ), UNO_QUERY_THROW );
497  PropertySet aBarProp( xErrorBar );
498 
499  // plus/minus bars
500  aBarProp.setProperty( PROP_ShowPositiveError, bShowPos );
501  aBarProp.setProperty( PROP_ShowNegativeError, bShowNeg );
502 
503  // type of displayed error
504  namespace cssc = ::com::sun::star::chart;
505  switch( mrModel.mnValueType )
506  {
507  case XML_cust:
508  {
509  // #i87806# manual error bars
510  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::FROM_DATA );
511  // attach data sequences to error bar
512  Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
513  if( xDataSink.is() )
514  {
515  // create vector of all value sequences
516  ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
517  // add positive values
518  if( bShowPos )
519  {
521  if( xValueSeq.is() )
522  aLabeledSeqVec.push_back( xValueSeq );
523  }
524  // add negative values
525  if( bShowNeg )
526  {
528  if( xValueSeq.is() )
529  aLabeledSeqVec.push_back( xValueSeq );
530  }
531  // attach labeled data sequences to series
532  if( aLabeledSeqVec.empty() )
533  xErrorBar.clear();
534  else
535  xDataSink->setData( comphelper::containerToSequence( aLabeledSeqVec ) );
536  }
537  }
538  break;
539  case XML_fixedVal:
540  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::ABSOLUTE );
541  aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
542  aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
543  break;
544  case XML_percentage:
545  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::RELATIVE );
546  aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
547  aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
548  break;
549  case XML_stdDev:
550  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_DEVIATION );
551  aBarProp.setProperty( PROP_Weight, mrModel.mfValue );
552  break;
553  case XML_stdErr:
554  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_ERROR );
555  break;
556  default:
557  OSL_FAIL( "ErrorBarConverter::convertFromModel - unknown error bar type" );
558  xErrorBar.clear();
559  }
560 
561  // error bar formatting
563 
564  if( xErrorBar.is() )
565  {
566  PropertySet aSeriesProp( rxDataSeries );
567  switch( mrModel.mnDirection )
568  {
569  case XML_x: aSeriesProp.setProperty( PROP_ErrorBarX, xErrorBar ); break;
570  case XML_y: aSeriesProp.setProperty( PROP_ErrorBarY, xErrorBar ); break;
571  default: OSL_FAIL( "ErrorBarConverter::convertFromModel - invalid error bar direction" );
572  }
573  }
574  }
575  catch( Exception& )
576  {
577  OSL_FAIL( "ErrorBarConverter::convertFromModel - error while creating error bars" );
578  }
579 }
580 
582 {
583  OUString aRole;
584  switch( eSourceType )
585  {
586  case ErrorBarModel::PLUS:
587  switch( mrModel.mnDirection )
588  {
589  case XML_x: aRole = "error-bars-x-positive"; break;
590  case XML_y: aRole = "error-bars-y-positive"; break;
591  }
592  break;
594  switch( mrModel.mnDirection )
595  {
596  case XML_x: aRole = "error-bars-x-negative"; break;
597  case XML_y: aRole = "error-bars-y-negative"; break;
598  }
599  break;
600  }
601  OSL_ENSURE( !aRole.isEmpty(), "ErrorBarConverter::createLabeledDataSequence - invalid error bar direction" );
602  return lclCreateLabeledDataSequence( *this, mrModel.maSources.get( eSourceType ).get(), aRole );
603 }
604 
606  ConverterBase< TrendlineLabelModel >( rParent, rModel )
607 {
608 }
609 
611 {
612 }
613 
615 {
616  // formatting
618 }
619 
621  ConverterBase< TrendlineModel >( rParent, rModel )
622 {
623 }
624 
626 {
627 }
628 
630 {
631  try
632  {
633  // trend line type
634  OUString aServiceName;
635  switch( mrModel.mnTypeId )
636  {
637  case XML_exp:
638  aServiceName = "com.sun.star.chart2.ExponentialRegressionCurve";
639  break;
640  case XML_linear:
641  aServiceName = "com.sun.star.chart2.LinearRegressionCurve";
642  break;
643  case XML_log:
644  aServiceName = "com.sun.star.chart2.LogarithmicRegressionCurve";
645  break;
646  case XML_movingAvg:
647  aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve";
648  break;
649  case XML_poly:
650  aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve";
651  break;
652  case XML_power:
653  aServiceName = "com.sun.star.chart2.PotentialRegressionCurve";
654  break;
655  default:
656  OSL_FAIL( "TrendlineConverter::convertFromModel - unknown trendline type" );
657  }
658  if( !aServiceName.isEmpty() )
659  {
660  Reference< XRegressionCurve > xRegCurve( createInstance( aServiceName ), UNO_QUERY_THROW );
661  PropertySet aPropSet( xRegCurve );
662 
663  // Name
664  aPropSet.setProperty( PROP_CurveName, mrModel.maName );
665  aPropSet.setProperty( PROP_PolynomialDegree, mrModel.mnOrder );
666  aPropSet.setProperty( PROP_MovingAveragePeriod, mrModel.mnPeriod );
667 
668  // Intercept
669  bool hasIntercept = mrModel.mfIntercept.has();
670  aPropSet.setProperty( PROP_ForceIntercept, hasIntercept);
671  if (hasIntercept)
672  aPropSet.setProperty( PROP_InterceptValue, mrModel.mfIntercept.get());
673 
674  // Extrapolation
675  if (mrModel.mfForward.has())
676  aPropSet.setProperty( PROP_ExtrapolateForward, mrModel.mfForward.get() );
677  if (mrModel.mfBackward.has())
678  aPropSet.setProperty( PROP_ExtrapolateBackward, mrModel.mfBackward.get() );
679 
680  // trendline formatting
682 
683  // #i83100# show equation and correlation coefficient
684  PropertySet aLabelProp( xRegCurve->getEquationProperties() );
685  aLabelProp.setProperty( PROP_ShowEquation, mrModel.mbDispEquation );
686  aLabelProp.setProperty( PROP_ShowCorrelationCoefficient, mrModel.mbDispRSquared );
687 
688  // #i83100# formatting of the equation text box
690  {
691  TrendlineLabelConverter aLabelConv( *this, mrModel.mxLabel.getOrCreate() );
692  aLabelConv.convertFromModel( aLabelProp );
693  }
694 
695  // unsupported: #i5085# manual trendline size
696  // unsupported: #i34093# manual crossing point
697 
698  Reference< XRegressionCurveContainer > xRegCurveCont( rxDataSeries, UNO_QUERY_THROW );
699  xRegCurveCont->addRegressionCurve( xRegCurve );
700  }
701  }
702  catch( Exception& )
703  {
704  OSL_FAIL( "TrendlineConverter::convertFromModel - error while creating trendline" );
705  }
706 }
707 
709  ConverterBase< DataPointModel >( rParent, rModel )
710 {
711 }
712 
714 {
715 }
716 
718  const TypeGroupConverter& rTypeGroup, const SeriesModel& rSeries )
719 {
720  bool bMSO2007Doc = getFilter().isMSO2007Document();
721  try
722  {
723  PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
724 
725  // data point marker
727  rTypeGroup.convertMarker( aPropSet, mrModel.monMarkerSymbol.get( rSeries.mnMarkerSymbol ),
729 
730  // data point pie explosion
732  rTypeGroup.convertPieExplosion( aPropSet, mrModel.monExplosion.get() );
733 
734  // point formatting
735  if( mrModel.mxShapeProp.is() )
736  {
737  if( rTypeGroup.getTypeInfo().mbPictureOptions )
739  else
741  }
742  else if (rSeries.mxShapeProp.is())
743  {
744  getFormatter().convertFrameFormatting( aPropSet, rSeries.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
745  }
746  }
747  catch( Exception& )
748  {
749  }
750 }
751 
753  ConverterBase< SeriesModel >( rParent, rModel )
754 {
755 }
756 
758 {
759 }
760 
762 {
764 }
765 
767 {
768  return createLabeledDataSequence( SeriesModel::VALUES, rRole, true );
769 }
770 
772 {
773  const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
774 
775  // create the data series object
776  Reference< XDataSeries > xDataSeries( createInstance( "com.sun.star.chart2.DataSeries" ), UNO_QUERY );
777  PropertySet aSeriesProp( xDataSeries );
778 
779  // attach data and title sequences to series
780  sal_Int32 nDataPointCount = 0;
781  Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
782  if( xDataSink.is() )
783  {
784  // create vector of all value sequences
785  ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
786  // add Y values
787  Reference< XLabeledDataSequence > xYValueSeq = createValueSequence( "values-y" );
788  if( xYValueSeq.is() )
789  {
790  aLabeledSeqVec.push_back( xYValueSeq );
791  Reference< XDataSequence > xValues = xYValueSeq->getValues();
792  if( xValues.is() )
793  nDataPointCount = xValues->getData().getLength();
794 
795  if (!nDataPointCount)
796  // No values present. Don't create a data series.
797  return Reference<XDataSeries>();
798  }
799  // add X values of scatter and bubble charts
800  if( !rTypeInfo.mbCategoryAxis )
801  {
803  if( xXValueSeq.is() )
804  aLabeledSeqVec.push_back( xXValueSeq );
805  // add size values of bubble charts
806  if( rTypeInfo.meTypeId == TYPEID_BUBBLE )
807  {
809  if( xSizeValueSeq.is() )
810  aLabeledSeqVec.push_back( xSizeValueSeq );
811  }
812  }
813  // attach labeled data sequences to series
814  if( !aLabeledSeqVec.empty() )
815  xDataSink->setData( comphelper::containerToSequence( aLabeledSeqVec ) );
816  }
817 
818  // error bars
819  for (auto const& errorBar : mrModel.maErrorBars)
820  {
821  ErrorBarConverter aErrorBarConv(*this, *errorBar);
822  aErrorBarConv.convertFromModel( xDataSeries );
823  }
824 
825  // trendlines
826  for (auto const& trendLine : mrModel.maTrendlines)
827  {
828  TrendlineConverter aTrendlineConv(*this, *trendLine);
829  aTrendlineConv.convertFromModel( xDataSeries );
830  }
831 
832  // data point markers
834 #if OOX_CHART_SMOOTHED_PER_SERIES
835  // #i66858# smoothed series lines
836  rTypeGroup.convertLineSmooth( aSeriesProp, mrModel.mbSmooth );
837 #endif
838  // 3D bar style (not possible to set at chart type -> set at all series)
839  rTypeGroup.convertBarGeometry( aSeriesProp, mrModel.monShape.get( rTypeGroup.getModel().mnShape ) );
840  // pie explosion (restricted to [0%,100%] in Chart2)
841  rTypeGroup.convertPieExplosion( aSeriesProp, mrModel.mnExplosion );
842 
843  // series formatting
844  ObjectFormatter& rFormatter = getFormatter();
845  ObjectType eObjType = rTypeGroup.getSeriesObjectType();
846  bool bMSO2007Doc = getFilter().isMSO2007Document();
847  if( rTypeInfo.mbPictureOptions )
848  rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(bMSO2007Doc), eObjType, mrModel.mnIndex );
849  else
850  rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, eObjType, mrModel.mnIndex );
851 
852  // set the (unused) property default value used by the Chart2 templates (true for pie/doughnut charts)
853  bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
854  aSeriesProp.setProperty( PROP_VaryColorsByPoint, bVaryColorsByPoint );
855 
856  // own area formatting for every data point (TODO: varying line color not supported)
857  // #i91271# always set area formatting for every point in pie/doughnut charts to override their automatic point formatting
858  if( bIsPie || (bVaryColorsByPoint && rTypeGroup.isSeriesFrameFormat() && ObjectFormatter::isAutomaticFill( mrModel.mxShapeProp )) )
859  {
860  /* Set the series point number as color cycle size at the object
861  formatter to get correct start-shade/end-tint. TODO: in doughnut
862  charts, the sizes of the series may vary, need to use the maximum
863  point count of all series. */
864  sal_Int32 nOldMax = rFormatter.getMaxSeriesIndex();
865  if( bVaryColorsByPoint )
866  rFormatter.setMaxSeriesIndex( nDataPointCount - 1 );
867  for( sal_Int32 nIndex = 0; nIndex < nDataPointCount; ++nIndex )
868  {
869  try
870  {
871  PropertySet aPointProp( xDataSeries->getDataPointByIndex( nIndex ) );
872  rFormatter.convertAutomaticFill( aPointProp, eObjType, bVaryColorsByPoint ? nIndex : mrModel.mnIndex );
873  }
874  catch( Exception& )
875  {
876  }
877  }
878  rFormatter.setMaxSeriesIndex( nOldMax );
879  }
880 
881  // data point settings
882  for (auto const& point : mrModel.maPoints)
883  {
884  DataPointConverter aPointConv(*this, *point);
885  aPointConv.convertFromModel( xDataSeries, rTypeGroup, mrModel );
886  }
887 
888  /* Series data label settings. If and only if the series does not contain
889  a c:dLbls element, then the c:dLbls element of the parent chart type is
890  used (data label settings of the parent chart type are *not* merged
891  into own existing data label settings). */
893  if( xLabels.is() )
894  {
895  if( xLabels->maNumberFormat.maFormatCode.isEmpty() )
896  {
897  // Use number format code from Value series
899  if( pValues )
900  xLabels->maNumberFormat.maFormatCode = pValues->mxDataSeq->maFormatCode;
901  }
902  DataLabelsConverter aLabelsConv( *this, *xLabels );
903  aLabelsConv.convertFromModel( xDataSeries, rTypeGroup );
904  }
905 
906  return xDataSeries;
907 }
908 
909 // private --------------------------------------------------------------------
910 
912  SeriesModel::SourceType eSourceType, const OUString& rRole, bool bUseTextLabel )
913 {
914  DataSourceModel* pValues = mrModel.maSources.get( eSourceType ).get();
915  TextModel* pTitle = bUseTextLabel ? mrModel.mxText.get() : nullptr;
916  return lclCreateLabeledDataSequence( *this, pValues, rRole, pTitle );
917 }
918 
919 } // namespace oox
920 
921 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 mnIndex
True = show bubbles with 3D shade.
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
sal_Int32 mnExplosion
3D bar shape type.
DataLabelConverter(const ConverterRoot &rParent, DataLabelModel &rModel)
TextRef mxText
Data point marker formatting.
sal_Int32 nIndex
ModelObjectHelper & getModelObjectHelperForModel(const css::uno::Reference< css::lang::XMultiServiceFactory > &xFactory) const
Definition: filterbase.cxx:360
sal_Int32 mnIndex
Reference to the labels container.
Definition: seriesmodel.hxx:64
sal_Int32 convertEmuToHmm(sal_Int64 nValue)
Converts the passed 64-bit integer value from EMUs to 1/100 mm.
DataLabelsRef mxLabels
Series title source.
ShapeRef mxShapeProp
Source ranges for manual error bar values.
bool mbPictureOptions
True = data points can be stacked on each other.
void convertFromModel(const css::uno::Reference< css::chart2::XDataSeries > &rxDataSeries, const TypeGroupConverter &rTypeGroup, const SeriesModel &rSeries)
Converts settings for a data point in the passed series.
OptValue< bool > mobShowDataLabelsRange
True = show data point value.
Definition: seriesmodel.hxx:47
PictureOptionsRef mxPicOptions
Series formatting.
void convertAutomaticFill(PropertySet &rPropSet, ObjectType eObjType, sal_Int32 nSeriesIdx)
Sets automatic fill properties to the passed property set.
void convertFromModel(const css::uno::Reference< css::chart2::XDataSeries > &rxDataSeries)
Converts an OOXML trendline and inserts it into the passed data series.
TypeCategory meTypeCategory
Unique chart type identifier.
css::uno::Reference< css::chart2::data::XLabeledDataSequence > createLabeledDataSequence(ErrorBarModel::SourceType eSourceType)
Base class of all converter classes.
TrendlineConverter(const ConverterRoot &rParent, TrendlineModel &rModel)
void setMaxSeriesIndex(sal_Int32 nMaxSeriesIdx)
Sets the maximum series index used for color cycling/fading.
sal_Int32 mnMarkerSize
Series index used for automatic formatting.
DataPointVector maPoints
All trendlines of this series.
sal_Int32 mnTypeId
Moving average period in range [2, 255].
def point()
TrendlineLabelConverter(const ConverterRoot &rParent, TrendlineLabelModel &rModel)
DataLabelsConverter(const ConverterRoot &rParent, DataLabelsModel &rModel)
OptValue< sal_Int32 > monExplosion
Data point marker formatting.
OptValue< double > mfBackward
User-defined name of the trendline.
static bool isAutomaticFill(const ModelRef< Shape > &rxShapeProp)
Returns true, if the passed shape properties have automatic fill mode.
ObjectType getSeriesObjectType() const
Returns the object type for a series depending on the chart type.
void convertFromModel(const css::uno::Reference< css::chart2::XDataSeries > &rxDataSeries, const TypeGroupConverter &rTypeGroup)
Converts OOXML data label settings for the passed data point.
css::uno::Reference< css::uno::XInterface > createInstance(const OUString &rServiceName) const
Creates an instance for the passed service name, using the process service factory.
ObjectType
Enumerates different object types for specific automatic formatting behaviour.
sal_Int32 mnIndex
Pie slice moved from pie center.
OptValue< double > mfForward
Size of trendline before first data point.
const Type & get() const
Definition: helper.hxx:185
static void convertTextWrap(PropertySet &rPropSet, const ModelRef< TextBody > &rxTextProp)
Sets text wrap properties to the passed property set.
SeriesConverter(const ConverterRoot &rParent, SeriesModel &rModel)
void convertFrameFormatting(PropertySet &rPropSet, const ModelRef< Shape > &rxShapeProp, ObjectType eObjType, sal_Int32 nSeriesIdx=-1)
Sets frame formatting properties to the passed property set.
css::uno::Reference< css::chart2::data::XLabeledDataSequence > createLabeledDataSequence(SeriesModel::SourceType eSourceType, const OUString &rRole, bool bUseTextLabel)
ShapeRef mxMarkerProp
Fill bitmap settings.
TextBodyRef mxTextProp
Data label frame formatting.
Definition: seriesmodel.hxx:34
DocumentType eType
bool mbDispEquation
Type of the trendline.
Type & use()
Definition: helper.hxx:189
Contains info for a chart type related to the OpenOffice.org chart module.
DataPointConverter(const ConverterRoot &rParent, DataPointModel &rModel)
Contains tables for named drawing objects for a document model.
OptValue< sal_Int32 > monShape
Data point label settings for all points.
const OUString & getUuid() const
Definition: textfield.hxx:45
void convertFormatting(PropertySet &rPropSet, const ModelRef< Shape > &rxShapeProp, const ModelRef< TextBody > &rxTextProp, ObjectType eObjType)
Sets frame/text formatting properties to the passed property set.
sal_Int32 mnValueType
Type of the error bars (plus/minus/both).
sal_Int32 mnOrder
Crossing point with Y axis.
css::uno::Reference< css::chart2::data::XLabeledDataSequence > createCategorySequence(const OUString &rRole)
Creates a labeled data sequence object from category data link.
const ModelType & getModel() const
css::uno::Reference< css::uno::XComponentContext > const & getComponentContext() const
NumberFormat maNumberFormat
Data label text formatting.
Definition: seriesmodel.hxx:35
void convertMarker(PropertySet &rPropSet, sal_Int32 nOoxSymbol, sal_Int32 nOoxSize, const ModelRef< Shape > &xShapeProps) const
Sets the passed OOXML marker style at the passed property set.
static drawing::Hatch createHatch(sal_Int32 nHatchToken,::Color nColor)
Definition: hatchmap.hxx:18
void convertLineSmooth(PropertySet &rPropSet, bool bOoxSmooth) const
Sets the passed OOXML line smoothing at the passed property set.
TextRef mxText
Layout/position of the data point label frame.
Definition: seriesmodel.hxx:62
const DataSourceModel * mpLabelsSource
Formatting of connector lines between data points and labels.
Definition: seriesmodel.hxx:79
bool mbSmooth
True = invert negative data points.
A wrapper for a UNO property set.
Definition: propertyset.hxx:57
sal_Int32 mnShape
relative size of second pie/bar in pie-to charts (percent).
TextBodyRef mxTextProp
Label frame formatting.
TrendlineVector maTrendlines
All error bars of this series.
static void convertTextRotation(PropertySet &rPropSet, const ModelRef< TextBody > &rxTextProp, bool bSupportsStacked, sal_Int32 nDefaultRotation=0)
Sets text rotation properties to the passed property set.
ErrorBarVector maErrorBars
Series source ranges.
ShapeRef mxMarkerProp
Fill bitmap settings.
TrendlineLabelRef mxLabel
Trendline formatting.
sal_Int32 mnTypeId
Direction of the error bars (x/y).
mapped_type get(key_type nKey) const
Returns a reference to the object associated to the passed key, or an empty reference on error...
Definition: refmap.hxx:59
Radar charts (linear or filled).
void convertBarGeometry(PropertySet &rPropSet, sal_Int32 nOoxShape) const
Sets the passed OOXML bar 3D geometry at the passed property set.
ErrorBarConverter(const ConverterRoot &rParent, ErrorBarModel &rModel)
OUString insertFillHatch(const css::drawing::Hatch &rHatch)
sal_Int32 getMaxSeriesIndex() const
Returns the current maximum series index used for color cycling/fading.
bool mbDispRSquared
True = show equation of the trendline.
ShapeRef mxShapeProp
Explicit formatted data points.
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
OUString & getText()
Definition: textrun.hxx:37
void convertFromModel(PropertySet &rPropSet)
Converts the OOXML trendline label.
const OUString & getType() const
Definition: textfield.hxx:43
PictureOptionsRef mxPicOptions
Data point formatting.
bool isSeriesFrameFormat() const
Returns true, if this chart type supports area formatting for its series.
bool mbCategoryAxis
True = only first series visible (e.g. pie charts).
OptValue< sal_Int32 > monMarkerSymbol
Size of the series line marker (2...72).
void convertFromModel(const css::uno::Reference< css::chart2::XDataSeries > &rxDataSeries)
Converts an OOXML errorbar and inserts it into the passed data series.
sal_Int32 mnMarkerSymbol
Size of the series line marker (2...72).
::oox::core::XmlFilterBase & getFilter() const
Returns the filter object of the imported/exported document.
Reference< XSingleServiceFactory > xFactory
css::uno::Reference< css::chart2::data::XLabeledDataSequence > createValueSequence(const OUString &rRole)
Creates a labeled data sequence object from value data link.
css::uno::Reference< css::chart2::XChartDocument > const & getChartDocument() const
Returns the API chart document model.
void convertPieExplosion(PropertySet &rPropSet, sal_Int32 nOoxExplosion) const
Sets the passed OOXML pie explosion at the passed property set.
OptValue< double > mfIntercept
Size of trendline behind last data point.
double mfValue
Error line formatting.
bool has() const
Definition: helper.hxx:181
const DataLabelsModel & mrParent
Manual or linked text for this data point label.
Definition: seriesmodel.hxx:63
sal_Int32 mnPeriod
Polynomial order in range [2, 6].
sal_Int32 mnDirection
Fixed value for several error bar types.
OptValue< sal_Int32 > monMarkerSize
Pie slice moved from pie center.
DataLabelsRef mxLabels
List of axis identifiers used by this chart type.
bool setProperty(sal_Int32 nPropId, const Type &rValue)
Puts the passed value into the property set.
const TypeGroupInfo & getTypeInfo() const
Returns the type info struct that describes this chart type group.
sal_uInt16 nPos
void convertFromModel(const css::uno::Reference< css::chart2::XDataSeries > &rxDataSeries, const TypeGroupConverter &rTypeGroup)
Converts OOXML data label settings for the passed data series.
ObjectFormatter & getFormatter() const
Returns the object formatter.
bool differsFrom(const Type &rValue) const
Definition: helper.hxx:183
css::uno::Reference< css::chart2::XDataSeries > createDataSeries(const TypeGroupConverter &rTypeGroup, bool bVaryColorsByPoint)
Creates a data series object with initialized source links.
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)
OUString maName
Trendline label text object.