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  aSequence.realloc( nSequenceSize );
323 
324  int nPos = 0;
325  for( auto& pParagraph : rParagraphs )
326  {
327  for( auto& pRun : pParagraph->getRuns() )
328  {
329  css::uno::Reference< XDataPointCustomLabelField > xCustomLabel = DataPointCustomLabelField::create( xContext );
330 
331  // Store properties
332  oox::PropertySet aPropertySet( xCustomLabel );
333  convertTextProperty( aPropertySet, getFormatter(), mrModel.mxText->mxTextBody );
334  pRun->getTextCharacterProperties().pushToPropSet( aPropertySet, getFilter() );
335 
336  TextField* pField = nullptr;
337  if( ( pField = dynamic_cast< TextField* >( pRun.get() ) ) )
338  {
339  xCustomLabel->setString( pField->getText() );
340  xCustomLabel->setFieldType( lcl_ConvertFieldNameToFieldEnum( pField->getType() ) );
341  xCustomLabel->setGuid( pField->getUuid() );
342  }
343  else if( pRun )
344  {
345  xCustomLabel->setString( pRun->getText() );
346  xCustomLabel->setFieldType( DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT );
347  }
348  aSequence[ nPos++ ] = xCustomLabel;
349  }
350 
351  if( nParagraphs > 1 && nPos < nSequenceSize )
352  {
353  css::uno::Reference< XDataPointCustomLabelField > xCustomLabel = DataPointCustomLabelField::create( xContext );
354  xCustomLabel->setFieldType( DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_NEWLINE );
355  xCustomLabel->setString("\n");
356  aSequence[ nPos++ ] = xCustomLabel;
357  }
358  }
359 
360  aPropSet.setProperty( PROP_CustomLabelFields, makeAny( aSequence ) );
361  convertTextProperty(aPropSet, getFormatter(), mrModel.mxText->mxTextBody);
362  }
363  }
364  catch( Exception& )
365  {
366  }
367 }
368 
370  ConverterBase< DataLabelsModel >( rParent, rModel )
371 {
372 }
373 
375 {
376 }
377 
378 namespace
379 {
381 void InheritFromDataLabelsTextProps(const DataLabelsModel& rLabels, const DataLabelModel& rLabel)
382 {
383  // See if <c:dLbls> contains text properties to inherit.
384  if (!rLabels.mxTextProp.is() || rLabels.mxTextProp->getParagraphs().empty())
385  {
386  return;
387  }
388 
389  const std::shared_ptr<TextParagraph>& rLabelsParagraph = rLabels.mxTextProp->getParagraphs()[0];
390 
391  // See if <c:dLbl> lacks text properties.
392  if (rLabel.mxTextProp.is())
393  {
394  return;
395  }
396 
397  if (!rLabel.mxText || !rLabel.mxText->mxTextBody
398  || rLabel.mxText->mxTextBody->getParagraphs().empty())
399  {
400  return;
401  }
402 
403  const std::shared_ptr<TextParagraph>& rLabelParagraph
404  = rLabel.mxText->mxTextBody->getParagraphs()[0];
405 
406  // Inherit rLabel.mxText's char props from rLabels.mxTextProp's char props.
407  TextCharacterProperties aCharProps;
408  aCharProps.assignUsed(rLabelsParagraph->getProperties().getTextCharacterProperties());
409  aCharProps.assignUsed(rLabelParagraph->getProperties().getTextCharacterProperties());
410  rLabelParagraph->getProperties().getTextCharacterProperties().assignUsed(aCharProps);
411 }
412 }
413 
415 {
416  PropertySet aPropSet( rxDataSeries );
417  if( !mrModel.mbDeleted )
418  {
419  bool bMSO2007Doc = getFilter().isMSO2007Document();
420  bool bHasInternalData = getChartDocument()->hasInternalDataProvider();
421 
422  lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, true, false, bHasInternalData, bMSO2007Doc );
423 
424  if (mrModel.mxShapeProp)
425  {
426  // Import baseline border properties for these data labels.
427  importBorderProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper());
428  uno::Reference<lang::XMultiServiceFactory> xFactory(getChartDocument(), uno::UNO_QUERY);
430  importFillProperties(aPropSet, *mrModel.mxShapeProp, getFilter().getGraphicHelper(),
431  rHelper);
432  }
433  }
434  // import leaderline of data labels
436  aPropSet.setProperty( PROP_ShowCustomLeaderLines, false );
437 
438  // data point label settings
439  for (auto const& pointLabel : mrModel.maPointLabels)
440  {
441  if (pointLabel->maNumberFormat.maFormatCode.isEmpty())
442  pointLabel->maNumberFormat = mrModel.maNumberFormat;
443  InheritFromDataLabelsTextProps(mrModel, *pointLabel);
444 
445  DataLabelConverter aLabelConv(*this, *pointLabel);
446  aLabelConv.convertFromModel( rxDataSeries, rTypeGroup );
447  }
448 }
449 
451  ConverterBase< ErrorBarModel >( rParent, rModel )
452 {
453 }
454 
456 {
457 }
458 
460 {
461  bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both);
462  bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both);
463  if( !(bShowPos || bShowNeg) )
464  return;
465 
466  try
467  {
468  Reference< XPropertySet > xErrorBar( createInstance( "com.sun.star.chart2.ErrorBar" ), UNO_QUERY_THROW );
469  PropertySet aBarProp( xErrorBar );
470 
471  // plus/minus bars
472  aBarProp.setProperty( PROP_ShowPositiveError, bShowPos );
473  aBarProp.setProperty( PROP_ShowNegativeError, bShowNeg );
474 
475  // type of displayed error
476  namespace cssc = ::com::sun::star::chart;
477  switch( mrModel.mnValueType )
478  {
479  case XML_cust:
480  {
481  // #i87806# manual error bars
482  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::FROM_DATA );
483  // attach data sequences to error bar
484  Reference< XDataSink > xDataSink( xErrorBar, UNO_QUERY );
485  if( xDataSink.is() )
486  {
487  // create vector of all value sequences
488  ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
489  // add positive values
490  if( bShowPos )
491  {
493  if( xValueSeq.is() )
494  aLabeledSeqVec.push_back( xValueSeq );
495  }
496  // add negative values
497  if( bShowNeg )
498  {
500  if( xValueSeq.is() )
501  aLabeledSeqVec.push_back( xValueSeq );
502  }
503  // attach labeled data sequences to series
504  if( aLabeledSeqVec.empty() )
505  xErrorBar.clear();
506  else
507  xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
508  }
509  }
510  break;
511  case XML_fixedVal:
512  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::ABSOLUTE );
513  aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
514  aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
515  break;
516  case XML_percentage:
517  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::RELATIVE );
518  aBarProp.setProperty( PROP_PositiveError, mrModel.mfValue );
519  aBarProp.setProperty( PROP_NegativeError, mrModel.mfValue );
520  break;
521  case XML_stdDev:
522  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_DEVIATION );
523  aBarProp.setProperty( PROP_Weight, mrModel.mfValue );
524  break;
525  case XML_stdErr:
526  aBarProp.setProperty( PROP_ErrorBarStyle, cssc::ErrorBarStyle::STANDARD_ERROR );
527  break;
528  default:
529  OSL_FAIL( "ErrorBarConverter::convertFromModel - unknown error bar type" );
530  xErrorBar.clear();
531  }
532 
533  // error bar formatting
535 
536  if( xErrorBar.is() )
537  {
538  PropertySet aSeriesProp( rxDataSeries );
539  switch( mrModel.mnDirection )
540  {
541  case XML_x: aSeriesProp.setProperty( PROP_ErrorBarX, xErrorBar ); break;
542  case XML_y: aSeriesProp.setProperty( PROP_ErrorBarY, xErrorBar ); break;
543  default: OSL_FAIL( "ErrorBarConverter::convertFromModel - invalid error bar direction" );
544  }
545  }
546  }
547  catch( Exception& )
548  {
549  OSL_FAIL( "ErrorBarConverter::convertFromModel - error while creating error bars" );
550  }
551 }
552 
554 {
555  OUString aRole;
556  switch( eSourceType )
557  {
558  case ErrorBarModel::PLUS:
559  switch( mrModel.mnDirection )
560  {
561  case XML_x: aRole = "error-bars-x-positive"; break;
562  case XML_y: aRole = "error-bars-y-positive"; break;
563  }
564  break;
566  switch( mrModel.mnDirection )
567  {
568  case XML_x: aRole = "error-bars-x-negative"; break;
569  case XML_y: aRole = "error-bars-y-negative"; break;
570  }
571  break;
572  }
573  OSL_ENSURE( !aRole.isEmpty(), "ErrorBarConverter::createLabeledDataSequence - invalid error bar direction" );
574  return lclCreateLabeledDataSequence( *this, mrModel.maSources.get( eSourceType ).get(), aRole );
575 }
576 
578  ConverterBase< TrendlineLabelModel >( rParent, rModel )
579 {
580 }
581 
583 {
584 }
585 
587 {
588  // formatting
590 }
591 
593  ConverterBase< TrendlineModel >( rParent, rModel )
594 {
595 }
596 
598 {
599 }
600 
602 {
603  try
604  {
605  // trend line type
606  OUString aServiceName;
607  switch( mrModel.mnTypeId )
608  {
609  case XML_exp:
610  aServiceName = "com.sun.star.chart2.ExponentialRegressionCurve";
611  break;
612  case XML_linear:
613  aServiceName = "com.sun.star.chart2.LinearRegressionCurve";
614  break;
615  case XML_log:
616  aServiceName = "com.sun.star.chart2.LogarithmicRegressionCurve";
617  break;
618  case XML_movingAvg:
619  aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve";
620  break;
621  case XML_poly:
622  aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve";
623  break;
624  case XML_power:
625  aServiceName = "com.sun.star.chart2.PotentialRegressionCurve";
626  break;
627  default:
628  OSL_FAIL( "TrendlineConverter::convertFromModel - unknown trendline type" );
629  }
630  if( !aServiceName.isEmpty() )
631  {
632  Reference< XRegressionCurve > xRegCurve( createInstance( aServiceName ), UNO_QUERY_THROW );
633  PropertySet aPropSet( xRegCurve );
634 
635  // Name
636  aPropSet.setProperty( PROP_CurveName, mrModel.maName );
637  aPropSet.setProperty( PROP_PolynomialDegree, mrModel.mnOrder );
638  aPropSet.setProperty( PROP_MovingAveragePeriod, mrModel.mnPeriod );
639 
640  // Intercept
641  bool hasIntercept = mrModel.mfIntercept.has();
642  aPropSet.setProperty( PROP_ForceIntercept, hasIntercept);
643  if (hasIntercept)
644  aPropSet.setProperty( PROP_InterceptValue, mrModel.mfIntercept.get());
645 
646  // Extrapolation
647  if (mrModel.mfForward.has())
648  aPropSet.setProperty( PROP_ExtrapolateForward, mrModel.mfForward.get() );
649  if (mrModel.mfBackward.has())
650  aPropSet.setProperty( PROP_ExtrapolateBackward, mrModel.mfBackward.get() );
651 
652  // trendline formatting
654 
655  // #i83100# show equation and correlation coefficient
656  PropertySet aLabelProp( xRegCurve->getEquationProperties() );
657  aLabelProp.setProperty( PROP_ShowEquation, mrModel.mbDispEquation );
658  aLabelProp.setProperty( PROP_ShowCorrelationCoefficient, mrModel.mbDispRSquared );
659 
660  // #i83100# formatting of the equation text box
662  {
663  TrendlineLabelConverter aLabelConv( *this, mrModel.mxLabel.getOrCreate() );
664  aLabelConv.convertFromModel( aLabelProp );
665  }
666 
667  // unsupported: #i5085# manual trendline size
668  // unsupported: #i34093# manual crossing point
669 
670  Reference< XRegressionCurveContainer > xRegCurveCont( rxDataSeries, UNO_QUERY_THROW );
671  xRegCurveCont->addRegressionCurve( xRegCurve );
672  }
673  }
674  catch( Exception& )
675  {
676  OSL_FAIL( "TrendlineConverter::convertFromModel - error while creating trendline" );
677  }
678 }
679 
681  ConverterBase< DataPointModel >( rParent, rModel )
682 {
683 }
684 
686 {
687 }
688 
690  const TypeGroupConverter& rTypeGroup, const SeriesModel& rSeries )
691 {
692  bool bMSO2007Doc = getFilter().isMSO2007Document();
693  try
694  {
695  PropertySet aPropSet( rxDataSeries->getDataPointByIndex( mrModel.mnIndex ) );
696 
697  // data point marker
699  rTypeGroup.convertMarker( aPropSet, mrModel.monMarkerSymbol.get( rSeries.mnMarkerSymbol ),
701 
702  // data point pie explosion
704  rTypeGroup.convertPieExplosion( aPropSet, mrModel.monExplosion.get() );
705 
706  // point formatting
707  if( mrModel.mxShapeProp.is() )
708  {
709  if( rTypeGroup.getTypeInfo().mbPictureOptions )
711  else
713  }
714  else if (rSeries.mxShapeProp.is())
715  {
716  getFormatter().convertFrameFormatting( aPropSet, rSeries.mxShapeProp, rTypeGroup.getSeriesObjectType(), rSeries.mnIndex );
717  }
718  }
719  catch( Exception& )
720  {
721  }
722 }
723 
725  ConverterBase< SeriesModel >( rParent, rModel )
726 {
727 }
728 
730 {
731 }
732 
734 {
736 }
737 
739 {
740  return createLabeledDataSequence( SeriesModel::VALUES, rRole, true );
741 }
742 
744 {
745  const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
746 
747  // create the data series object
748  Reference< XDataSeries > xDataSeries( createInstance( "com.sun.star.chart2.DataSeries" ), UNO_QUERY );
749  PropertySet aSeriesProp( xDataSeries );
750 
751  // attach data and title sequences to series
752  sal_Int32 nDataPointCount = 0;
753  Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
754  if( xDataSink.is() )
755  {
756  // create vector of all value sequences
757  ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
758  // add Y values
759  Reference< XLabeledDataSequence > xYValueSeq = createValueSequence( "values-y" );
760  if( xYValueSeq.is() )
761  {
762  aLabeledSeqVec.push_back( xYValueSeq );
763  Reference< XDataSequence > xValues = xYValueSeq->getValues();
764  if( xValues.is() )
765  nDataPointCount = xValues->getData().getLength();
766 
767  if (!nDataPointCount)
768  // No values present. Don't create a data series.
769  return Reference<XDataSeries>();
770  }
771  // add X values of scatter and bubble charts
772  if( !rTypeInfo.mbCategoryAxis )
773  {
775  if( xXValueSeq.is() )
776  aLabeledSeqVec.push_back( xXValueSeq );
777  // add size values of bubble charts
778  if( rTypeInfo.meTypeId == TYPEID_BUBBLE )
779  {
781  if( xSizeValueSeq.is() )
782  aLabeledSeqVec.push_back( xSizeValueSeq );
783  }
784  }
785  // attach labeled data sequences to series
786  if( !aLabeledSeqVec.empty() )
787  xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
788  }
789 
790  // error bars
791  for (auto const& errorBar : mrModel.maErrorBars)
792  {
793  ErrorBarConverter aErrorBarConv(*this, *errorBar);
794  aErrorBarConv.convertFromModel( xDataSeries );
795  }
796 
797  // trendlines
798  for (auto const& trendLine : mrModel.maTrendlines)
799  {
800  TrendlineConverter aTrendlineConv(*this, *trendLine);
801  aTrendlineConv.convertFromModel( xDataSeries );
802  }
803 
804  // data point markers
806 #if OOX_CHART_SMOOTHED_PER_SERIES
807  // #i66858# smoothed series lines
808  rTypeGroup.convertLineSmooth( aSeriesProp, mrModel.mbSmooth );
809 #endif
810  // 3D bar style (not possible to set at chart type -> set at all series)
811  rTypeGroup.convertBarGeometry( aSeriesProp, mrModel.monShape.get( rTypeGroup.getModel().mnShape ) );
812  // pie explosion (restricted to [0%,100%] in Chart2)
813  rTypeGroup.convertPieExplosion( aSeriesProp, mrModel.mnExplosion );
814 
815  // series formatting
816  ObjectFormatter& rFormatter = getFormatter();
817  ObjectType eObjType = rTypeGroup.getSeriesObjectType();
818  bool bMSO2007Doc = getFilter().isMSO2007Document();
819  if( rTypeInfo.mbPictureOptions )
820  rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(bMSO2007Doc), eObjType, mrModel.mnIndex );
821  else
822  rFormatter.convertFrameFormatting( aSeriesProp, mrModel.mxShapeProp, eObjType, mrModel.mnIndex );
823 
824  // set the (unused) property default value used by the Chart2 templates (true for pie/doughnut charts)
825  bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
826  aSeriesProp.setProperty( PROP_VaryColorsByPoint, bVaryColorsByPoint );
827 
828  // own area formatting for every data point (TODO: varying line color not supported)
829  // #i91271# always set area formatting for every point in pie/doughnut charts to override their automatic point formatting
830  if( bIsPie || (bVaryColorsByPoint && rTypeGroup.isSeriesFrameFormat() && ObjectFormatter::isAutomaticFill( mrModel.mxShapeProp )) )
831  {
832  /* Set the series point number as color cycle size at the object
833  formatter to get correct start-shade/end-tint. TODO: in doughnut
834  charts, the sizes of the series may vary, need to use the maximum
835  point count of all series. */
836  sal_Int32 nOldMax = rFormatter.getMaxSeriesIndex();
837  if( bVaryColorsByPoint )
838  rFormatter.setMaxSeriesIndex( nDataPointCount - 1 );
839  for( sal_Int32 nIndex = 0; nIndex < nDataPointCount; ++nIndex )
840  {
841  try
842  {
843  PropertySet aPointProp( xDataSeries->getDataPointByIndex( nIndex ) );
844  rFormatter.convertAutomaticFill( aPointProp, eObjType, bVaryColorsByPoint ? nIndex : mrModel.mnIndex );
845  }
846  catch( Exception& )
847  {
848  }
849  }
850  rFormatter.setMaxSeriesIndex( nOldMax );
851  }
852 
853  // data point settings
854  for (auto const& point : mrModel.maPoints)
855  {
856  DataPointConverter aPointConv(*this, *point);
857  aPointConv.convertFromModel( xDataSeries, rTypeGroup, mrModel );
858  }
859 
860  /* Series data label settings. If and only if the series does not contain
861  a c:dLbls element, then the c:dLbls element of the parent chart type is
862  used (data label settings of the parent chart type are *not* merged
863  into own existing data label settings). */
865  if( xLabels.is() )
866  {
867  if( xLabels->maNumberFormat.maFormatCode.isEmpty() )
868  {
869  // Use number format code from Value series
871  if( pValues )
872  xLabels->maNumberFormat.maFormatCode = pValues->mxDataSeq->maFormatCode;
873  }
874  DataLabelsConverter aLabelsConv( *this, *xLabels );
875  aLabelsConv.convertFromModel( xDataSeries, rTypeGroup );
876  }
877 
878  return xDataSeries;
879 }
880 
881 // private --------------------------------------------------------------------
882 
884  SeriesModel::SourceType eSourceType, const OUString& rRole, bool bUseTextLabel )
885 {
886  DataSourceModel* pValues = mrModel.maSources.get( eSourceType ).get();
887  TextModel* pTitle = bUseTextLabel ? mrModel.mxText.get() : nullptr;
888  return lclCreateLabeledDataSequence( *this, pValues, rRole, pTitle );
889 }
890 
891 } // namespace oox
892 
893 /* 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
Manual or linked text for this data point label.
Definition: seriesmodel.hxx:57
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.
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.
bool mbShowLeaderLines
Formatting of connector lines between data points and labels.
Definition: seriesmodel.hxx:70
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.
bool mbDeleted
True = show data point value.
Definition: seriesmodel.hxx:44
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
bool mbDispEquation
Type of the trendline.
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:56
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
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.