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