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