use insert function instead of for loop
[LibreOffice.git] / oox / source / drawingml / chart / typegroupconverter.cxx
blob71be134a9f0308c667dab711ea0f3545ad5b57b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawingml/chart/typegroupconverter.hxx>
22 #include <com/sun/star/chart/DataLabelPlacement.hpp>
23 #include <com/sun/star/chart2/CartesianCoordinateSystem2d.hpp>
24 #include <com/sun/star/chart2/CartesianCoordinateSystem3d.hpp>
25 #include <com/sun/star/chart2/PolarCoordinateSystem2d.hpp>
26 #include <com/sun/star/chart2/PolarCoordinateSystem3d.hpp>
27 #include <com/sun/star/chart2/CurveStyle.hpp>
28 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
29 #include <com/sun/star/chart2/PieChartSubType.hpp>
30 #include <com/sun/star/chart2/StackingDirection.hpp>
31 #include <com/sun/star/chart2/Symbol.hpp>
32 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
33 #include <com/sun/star/chart2/XCoordinateSystem.hpp>
34 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
35 #include <com/sun/star/chart2/XDiagram.hpp>
36 #include <com/sun/star/chart2/data/XDataSink.hpp>
37 #include <com/sun/star/drawing/LineStyle.hpp>
39 #include <comphelper/sequence.hxx>
40 #include <osl/diagnose.h>
41 #include <drawingml/lineproperties.hxx>
42 #include <drawingml/chart/seriesconverter.hxx>
43 #include <drawingml/chart/typegroupmodel.hxx>
44 #include <oox/core/xmlfilterbase.hxx>
45 #include <oox/token/namespaces.hxx>
46 #include <oox/token/properties.hxx>
47 #include <oox/token/tokens.hxx>
48 #include <tools/UnitConversion.hxx>
50 namespace oox::drawingml::chart {
52 using namespace ::com::sun::star::beans;
53 using namespace ::com::sun::star::chart2;
54 using namespace ::com::sun::star::chart2::data;
55 using namespace ::com::sun::star::uno;
57 namespace {
59 // chart type service names
60 const char SERVICE_CHART2_AREA[] = "com.sun.star.chart2.AreaChartType";
61 const char SERVICE_CHART2_CANDLE[] = "com.sun.star.chart2.CandleStickChartType";
62 const char SERVICE_CHART2_COLUMN[] = "com.sun.star.chart2.ColumnChartType";
63 const char SERVICE_CHART2_LINE[] = "com.sun.star.chart2.LineChartType";
64 const char SERVICE_CHART2_NET[] = "com.sun.star.chart2.NetChartType";
65 const char SERVICE_CHART2_FILLEDNET[] = "com.sun.star.chart2.FilledNetChartType";
66 const char SERVICE_CHART2_PIE[] = "com.sun.star.chart2.PieChartType";
67 const char SERVICE_CHART2_SCATTER[] = "com.sun.star.chart2.ScatterChartType";
68 const char SERVICE_CHART2_BUBBLE[] = "com.sun.star.chart2.BubbleChartType";
69 const char SERVICE_CHART2_SURFACE[] = "com.sun.star.chart2.ColumnChartType"; // Todo
70 const char SERVICE_CHART2_HISTO[] = "com.sun.star.chart2.HistogramChartType";
72 namespace csscd = css::chart::DataLabelPlacement;
74 const TypeGroupInfo spTypeInfos[] =
76 // type-id type-category service varied-point-color default label pos polar area2d 1stvis xcateg swap stack picopt
77 { TYPEID_BAR, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, false, true, false, true, false, true, true },
78 { TYPEID_HORBAR, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, false, true, false, true, true, true, true },
79 { TYPEID_HISTO, TYPECATEGORY_HISTO, SERVICE_CHART2_HISTO, VARPOINTMODE_SINGLE, csscd::OUTSIDE, false, true, false, true, true, true, true },
80 { TYPEID_LINE, TYPECATEGORY_LINE, SERVICE_CHART2_LINE, VARPOINTMODE_SINGLE, csscd::RIGHT, false, false, false, true, false, true, false },
81 { TYPEID_AREA, TYPECATEGORY_LINE, SERVICE_CHART2_AREA, VARPOINTMODE_NONE, csscd::CENTER, false, true, false, true, false, true, false },
82 { TYPEID_STOCK, TYPECATEGORY_LINE, SERVICE_CHART2_CANDLE, VARPOINTMODE_NONE, csscd::RIGHT, false, false, false, true, false, true, false },
83 { TYPEID_RADARLINE, TYPECATEGORY_RADAR, SERVICE_CHART2_NET, VARPOINTMODE_SINGLE, csscd::OUTSIDE, true, false, false, true, false, false, false },
84 { TYPEID_RADARAREA, TYPECATEGORY_RADAR, SERVICE_CHART2_FILLEDNET, VARPOINTMODE_NONE, csscd::OUTSIDE, true, true, false, true, false, false, false },
85 { TYPEID_PIE, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, true, true, true, true, false, false, false },
86 { TYPEID_DOUGHNUT, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, true, true, false, true, false, false, false },
87 { TYPEID_OFPIE, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, true, true, true, true, false, false, false },
88 { TYPEID_SCATTER, TYPECATEGORY_SCATTER, SERVICE_CHART2_SCATTER, VARPOINTMODE_SINGLE, csscd::RIGHT, false, false, false, false, false, false, false },
89 { TYPEID_BUBBLE, TYPECATEGORY_SCATTER, SERVICE_CHART2_BUBBLE, VARPOINTMODE_SINGLE, csscd::RIGHT, false, true, false, false, false, false, false },
90 { TYPEID_SURFACE, TYPECATEGORY_SURFACE, SERVICE_CHART2_SURFACE, VARPOINTMODE_NONE, csscd::RIGHT, false, true, false, true, false, false, false }
93 const TypeGroupInfo saUnknownTypeInfo =
94 { TYPEID_UNKNOWN, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, false, true, false, true, false, true, true };
96 const TypeGroupInfo& lclGetTypeInfoFromTypeId( TypeId eTypeId )
98 for( auto const &rIt : spTypeInfos)
100 if( rIt.meTypeId == eTypeId )
101 return rIt;
103 OSL_ENSURE( eTypeId == TYPEID_UNKNOWN, "lclGetTypeInfoFromTypeId - unexpected chart type identifier" );
104 return saUnknownTypeInfo;
107 } // namespace
109 const TypeGroupInfo& GetTypeGroupInfo( TypeId eType )
111 return lclGetTypeInfoFromTypeId(eType);
114 UpDownBarsConverter::UpDownBarsConverter( const ConverterRoot& rParent, UpDownBarsModel& rModel ) :
115 ConverterBase< UpDownBarsModel >( rParent, rModel )
119 UpDownBarsConverter::~UpDownBarsConverter()
123 void UpDownBarsConverter::convertFromModel( const Reference< XChartType >& rxChartType )
125 PropertySet aTypeProp( rxChartType );
127 // upbar format
128 Reference< XPropertySet > xWhitePropSet;
129 if( aTypeProp.getProperty( xWhitePropSet, PROP_WhiteDay ) )
131 PropertySet aPropSet( xWhitePropSet );
132 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxUpBars, OBJECTTYPE_UPBAR );
135 // downbar format
136 Reference< XPropertySet > xBlackPropSet;
137 if( aTypeProp.getProperty( xBlackPropSet, PROP_BlackDay ) )
139 PropertySet aPropSet( xBlackPropSet );
140 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxDownBars, OBJECTTYPE_DOWNBAR );
144 TypeGroupConverter::TypeGroupConverter( const ConverterRoot& rParent, TypeGroupModel& rModel ) :
145 ConverterBase< TypeGroupModel >( rParent, rModel ),
146 mb3dChart( false )
148 TypeId eTypeId = TYPEID_UNKNOWN;
149 switch( mrModel.mnTypeId )
151 #define ENSURE_AXESCOUNT( min, max ) OSL_ENSURE( (min <= static_cast<int>(mrModel.maAxisIds.size())) && (static_cast<int>(mrModel.maAxisIds.size()) <= max), "TypeGroupConverter::TypeGroupConverter - invalid axes count" )
152 case C_TOKEN( area3DChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_AREA; mb3dChart = true; break;
153 case C_TOKEN( areaChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_AREA; mb3dChart = false; break;
154 case C_TOKEN( bar3DChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_BAR; mb3dChart = true; break;
155 case C_TOKEN( barChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_BAR; mb3dChart = false; break;
156 case C_TOKEN( bubbleChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_BUBBLE; mb3dChart = false; break;
157 case C_TOKEN( doughnutChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_DOUGHNUT; mb3dChart = false; break;
158 case C_TOKEN( line3DChart ): ENSURE_AXESCOUNT( 3, 3 ); eTypeId = TYPEID_LINE; mb3dChart = true; break;
159 case C_TOKEN( lineChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_LINE; mb3dChart = false; break;
160 case C_TOKEN( ofPieChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_OFPIE; mb3dChart = false; break;
161 case C_TOKEN( pie3DChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_PIE; mb3dChart = true; break;
162 case C_TOKEN( pieChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_PIE; mb3dChart = false; break;
163 case C_TOKEN( radarChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_RADARLINE; mb3dChart = false; break;
164 case C_TOKEN( scatterChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_SCATTER; mb3dChart = false; break;
165 case C_TOKEN( stockChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_STOCK; mb3dChart = false; break;
166 case C_TOKEN( surface3DChart ): ENSURE_AXESCOUNT( 3, 3 ); eTypeId = TYPEID_SURFACE; mb3dChart = true; break;
167 case C_TOKEN( surfaceChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_SURFACE; mb3dChart = true; break; // 3D bar chart from all surface charts
168 default: OSL_FAIL( "TypeGroupConverter::TypeGroupConverter - unknown chart type" );
169 #undef ENSURE_AXESCOUNT
172 // special handling for some chart types
173 switch( eTypeId )
175 case TYPEID_BAR:
176 if( mrModel.mnBarDir == XML_bar )
177 eTypeId = TYPEID_HORBAR;
178 break;
179 case TYPEID_RADARLINE:
180 if( mrModel.mnRadarStyle == XML_filled )
181 eTypeId = TYPEID_RADARAREA;
182 break;
183 case TYPEID_SURFACE:
184 // create a deep 3D bar chart from surface charts
185 mrModel.mnGrouping = XML_standard;
186 break;
187 default:;
190 // set the chart type info struct for the current chart type
191 maTypeInfo = lclGetTypeInfoFromTypeId( eTypeId );
194 TypeGroupConverter::~TypeGroupConverter()
198 bool TypeGroupConverter::isStacked() const
200 return maTypeInfo.mbSupportsStacking && (mrModel.mnGrouping == XML_stacked);
203 bool TypeGroupConverter::isPercent() const
205 return maTypeInfo.mbSupportsStacking && (mrModel.mnGrouping == XML_percentStacked);
208 bool TypeGroupConverter::isWall3dChart() const
210 return mb3dChart && (maTypeInfo.meTypeCategory != TYPECATEGORY_PIE);
213 bool TypeGroupConverter::isDeep3dChart() const
215 return isWall3dChart() && (mrModel.mnGrouping == XML_standard);
218 bool TypeGroupConverter::isSeriesFrameFormat() const
220 return mb3dChart || maTypeInfo.mbSeriesIsFrame2d;
223 ObjectType TypeGroupConverter::getSeriesObjectType() const
225 return mb3dChart ? OBJECTTYPE_FILLEDSERIES3D :
226 (maTypeInfo.mbSeriesIsFrame2d ? OBJECTTYPE_FILLEDSERIES2D : OBJECTTYPE_LINEARSERIES2D);
229 OUString TypeGroupConverter::getSingleSeriesTitle() const
231 OUString aSeriesTitle;
232 if( !mrModel.maSeries.empty() && (maTypeInfo.mbSingleSeriesVis || (mrModel.maSeries.size() == 1)) )
233 if( const TextModel* pText = mrModel.maSeries.front()->mxText.get() )
234 if( const DataSequenceModel* pDataSeq = pText->mxDataSeq.get() )
235 if( !pDataSeq->maData.empty() )
236 pDataSeq->maData.begin()->second >>= aSeriesTitle;
237 return aSeriesTitle;
240 bool TypeGroupConverter::isSingleSeriesTitle() const
242 if (!mrModel.maSeries.empty() && (maTypeInfo.mbSingleSeriesVis || (mrModel.maSeries.size() == 1)) &&
243 mrModel.maSeries.front()->mxText.is())
244 return true;
246 return false;
249 Reference< XCoordinateSystem > TypeGroupConverter::createCoordinateSystem()
251 // create the coordinate system object
252 Reference< css::uno::XComponentContext > xContext = getComponentContext();
253 Reference< XCoordinateSystem > xCoordSystem;
254 if( maTypeInfo.mbPolarCoordSystem )
256 if( mb3dChart )
257 xCoordSystem = css::chart2::PolarCoordinateSystem3d::create(xContext);
258 else
259 xCoordSystem = css::chart2::PolarCoordinateSystem2d::create(xContext);
261 else
263 if( mb3dChart )
264 xCoordSystem = css::chart2::CartesianCoordinateSystem3d::create(xContext);
265 else
266 xCoordSystem = css::chart2::CartesianCoordinateSystem2d::create(xContext);
269 // swap X and Y axis
270 if( maTypeInfo.mbSwappedAxesSet )
272 PropertySet aPropSet( xCoordSystem );
273 aPropSet.setProperty( PROP_SwapXAndYAxis, true );
276 return xCoordSystem;
279 Reference< XLabeledDataSequence > TypeGroupConverter::createCategorySequence()
281 sal_Int32 nMaxValues = 0;
282 Reference< XLabeledDataSequence > xLabeledSeq;
283 /* Find first existing category sequence. The behaviour of Excel 2007 is
284 different to Excel 2003, which always used the category sequence of the
285 first series, even if it was empty. */
286 for (auto const& elem : mrModel.maSeries)
288 if( elem->maSources.has( SeriesModel::CATEGORIES ) )
290 SeriesConverter aSeriesConv(*this, *elem);
291 xLabeledSeq = aSeriesConv.createCategorySequence( u"categories"_ustr );
292 if (xLabeledSeq.is())
293 break;
295 else if( nMaxValues <= 0 && elem->maSources.has( SeriesModel::VALUES ) )
297 DataSourceModel *pValues = elem->maSources.get( SeriesModel::VALUES ).get();
298 if( pValues->mxDataSeq.is() )
299 nMaxValues = pValues->mxDataSeq->maData.size();
302 /* n#839727 Create Category Sequence when none are found */
303 if( !xLabeledSeq.is() && !mrModel.maSeries.empty() ) {
304 if( nMaxValues < 0 )
305 nMaxValues = 2;
306 typedef RefVector<SeriesModel> SeriesModelVector;
307 SeriesModelVector::value_type aModel = mrModel.maSeries.get(0);
308 if (!aModel->maSources.has(SeriesModel::CATEGORIES))
310 DataSourceModel &aSrc = aModel->maSources.create( SeriesModel::CATEGORIES );
311 DataSequenceModel &aSeq = aSrc.mxDataSeq.create();
312 aSeq.mnPointCount = nMaxValues;
313 for( sal_Int32 i = 0; i < nMaxValues; i++ )
314 aSeq.maData[ i ] <<= OUString::number( i + 1 );
316 SeriesConverter aSeriesConv( *this, *aModel );
317 xLabeledSeq = aSeriesConv.createCategorySequence( u"categories"_ustr );
319 return xLabeledSeq;
322 void TypeGroupConverter::convertFromModel( const Reference< XDiagram >& rxDiagram,
323 const Reference< XCoordinateSystem >& rxCoordSystem,
324 sal_Int32 nAxesSetIdx, bool bSupportsVaryColorsByPoint )
328 // create the chart type object
329 OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
330 Reference< XChartType > xChartType( createInstance( aService ), UNO_QUERY_THROW );
332 Reference< XChartTypeContainer > xChartTypeContOld( rxCoordSystem, UNO_QUERY_THROW );
333 Sequence< Reference< XChartType > > xOldChartTypes( xChartTypeContOld->getChartTypes() );
334 sal_Int32 nOldChartTypeIdx = -1;
336 // additional properties
337 PropertySet aDiaProp( rxDiagram );
338 PropertySet aTypeProp( xChartType );
339 switch( maTypeInfo.meTypeCategory )
341 case TYPECATEGORY_BAR:
343 Sequence< sal_Int32 > aInt32Seq{ mrModel.mnOverlap, mrModel.mnOverlap };
344 aTypeProp.setProperty( PROP_OverlapSequence, aInt32Seq );
345 aInt32Seq = { mrModel.mnGapWidth, mrModel.mnGapWidth };
346 aTypeProp.setProperty( PROP_GapwidthSequence, aInt32Seq );
348 break;
349 case TYPECATEGORY_PIE:
351 aTypeProp.setProperty( PROP_UseRings, maTypeInfo.meTypeId == TYPEID_DOUGHNUT );
352 /* #i85166# starting angle of first pie slice. 3D pie charts
353 use Y rotation setting in view3D element. Of-pie charts do
354 not support pie rotation. */
355 if( !is3dChart() && (maTypeInfo.meTypeId != TYPEID_OFPIE) )
356 convertPieRotation( aDiaProp, mrModel.mnFirstAngle );
358 if (maTypeInfo.meTypeId == TYPEID_OFPIE) {
359 aDiaProp.setProperty(PROP_SubPieType,
360 convertOfPieType(mrModel.mnOfPieType));
361 if (mrModel.mnSplitType == XML_auto ||
362 mrModel.mnSplitType == XML_pos) {
363 aDiaProp.setProperty(PROP_SplitPos, mrModel.mfSplitPos);
365 } else {
366 aDiaProp.setProperty(PROP_SubPieType, PieChartSubType_NONE);
369 break;
370 default:;
373 // create converter objects for all series models
374 typedef RefVector< SeriesConverter > SeriesConvVector;
375 SeriesConvVector aSeries;
376 for (auto const& elemSeries : mrModel.maSeries)
377 aSeries.push_back( std::make_shared<SeriesConverter>(*this, *elemSeries) );
379 // decide whether to use varying colors for each data point
380 bool bVaryColorsByPoint = bSupportsVaryColorsByPoint && mrModel.mbVaryColors;
381 switch( maTypeInfo.meVarPointMode )
383 case VARPOINTMODE_NONE: bVaryColorsByPoint = false; break;
384 case VARPOINTMODE_SINGLE: bVaryColorsByPoint &= (mrModel.maSeries.size() == 1); break;
385 case VARPOINTMODE_MULTI: break;
388 /* Stock chart needs special processing. Create one 'big' series with
389 data sequences of different roles. */
390 if( maTypeInfo.meTypeId == TYPEID_STOCK )
392 // create the data series object
393 Reference< XDataSeries > xDataSeries( createInstance( u"com.sun.star.chart2.DataSeries"_ustr ), UNO_QUERY );
394 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
395 if( xDataSink.is() )
397 // create a list of data sequences from all series
398 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
399 OSL_ENSURE( aSeries.size() >= 3, "TypeGroupConverter::convertFromModel - too few stock chart series" );
400 int nRoleIdx = (aSeries.size() == 3) ? 1 : 0;
401 for( auto& rxSeriesConv : aSeries )
403 // create a data sequence with a specific role
404 OUString aRole;
405 switch( nRoleIdx )
407 case 0: aRole = "values-first"; break;
408 case 1: aRole = "values-max"; break;
409 case 2: aRole = "values-min"; break;
410 case 3: aRole = "values-last"; break;
412 Reference< XLabeledDataSequence > xDataSeq = rxSeriesConv->createValueSequence( aRole );
413 if( xDataSeq.is() )
414 aLabeledSeqVec.push_back( xDataSeq );
416 ++nRoleIdx;
417 if (nRoleIdx >= 4)
418 break;
421 // attach labeled data sequences to series and insert series into chart type
422 xDataSink->setData( comphelper::containerToSequence( aLabeledSeqVec ) );
424 // formatting of high/low lines
425 aTypeProp.setProperty( PROP_ShowHighLow, true );
426 PropertySet aSeriesProp( xDataSeries );
427 if( mrModel.mxHiLowLines.is() )
428 getFormatter().convertFrameFormatting( aSeriesProp, mrModel.mxHiLowLines, OBJECTTYPE_HILOLINE );
429 else
430 // hi/low-lines cannot be switched off via "ShowHighLow" property (?)
431 aSeriesProp.setProperty( PROP_LineStyle, css::drawing::LineStyle_NONE );
433 // formatting of up/down bars
434 bool bUpDownBars = mrModel.mxUpDownBars.is();
435 aTypeProp.setProperty( PROP_Japanese, bUpDownBars );
436 aTypeProp.setProperty( PROP_ShowFirst, bUpDownBars );
437 if( bUpDownBars )
439 UpDownBarsConverter aUpDownConv( *this, *mrModel.mxUpDownBars );
440 aUpDownConv.convertFromModel( xChartType );
443 // insert the series into the chart type object
444 insertDataSeries( xChartType, xDataSeries, nAxesSetIdx );
447 else
449 for( sal_Int32 nCTIdx=0; nCTIdx<xOldChartTypes.getLength(); ++nCTIdx )
451 if ( xChartType->getChartType() == xOldChartTypes[nCTIdx]->getChartType() )
453 nOldChartTypeIdx = nCTIdx;
457 for (auto const& elem : aSeries)
459 SeriesConverter& rSeriesConv = *elem;
460 Reference< XDataSeries > xDataSeries = rSeriesConv.createDataSeries( *this, bVaryColorsByPoint );
461 insertDataSeries( nOldChartTypeIdx == -1 ? xChartType : xOldChartTypes[nOldChartTypeIdx], xDataSeries, nAxesSetIdx );
463 /* Excel does not use the value of the c:smooth element of the
464 chart type to set a default line smoothing for the data
465 series. Line smoothing is always controlled by the c:smooth
466 element of the respective data series. If the element in the
467 data series is missing, line smoothing is off, regardless of
468 the c:smooth element of the chart type. */
469 #if !OOX_CHART_SMOOTHED_PER_SERIES
470 if( rSeriesConv.getModel().mbSmooth )
471 convertLineSmooth( aTypeProp, true );
472 #endif
476 // add chart type object to coordinate system
477 Reference< XChartTypeContainer > xChartTypeCont( rxCoordSystem, UNO_QUERY_THROW );
478 if (nOldChartTypeIdx == -1)
480 xChartTypeCont->addChartType(xChartType);
483 // set existence of bar connector lines at diagram (only in stacked 2D bar charts)
484 if( mrModel.mxSerLines.is() && !mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR) && (isStacked() || isPercent()) )
485 aDiaProp.setProperty( PROP_ConnectBars, true );
487 catch( Exception& )
489 OSL_FAIL( "TypeGroupConverter::convertFromModel - cannot add chart type" );
493 void TypeGroupConverter::convertMarker( PropertySet& rPropSet, sal_Int32 nOoxSymbol, sal_Int32 nOoxSize,
494 const ModelRef< Shape >& xShapeProps ) const
496 if( isSeriesFrameFormat() )
497 return;
499 namespace cssc = css::chart2;
501 // symbol style
502 cssc::Symbol aSymbol;
503 aSymbol.Style = cssc::SymbolStyle_STANDARD;
504 switch( nOoxSymbol ) // compare with XclChPropSetHelper::WriteMarkerProperties in xlchart.cxx
506 case XML_auto: aSymbol.Style = cssc::SymbolStyle_AUTO; break;
507 case XML_none: aSymbol.Style = cssc::SymbolStyle_NONE; break;
508 case XML_square: aSymbol.StandardSymbol = 0; break; // square
509 case XML_diamond: aSymbol.StandardSymbol = 1; break; // diamond
510 case XML_triangle: aSymbol.StandardSymbol = 3; break; // arrow up
511 case XML_x: aSymbol.StandardSymbol = 10; break; // X, legacy bow tie
512 case XML_star: aSymbol.StandardSymbol = 12; break; // asterisk, legacy sand glass
513 case XML_dot: aSymbol.StandardSymbol = 4; break; // arrow right
514 case XML_dash: aSymbol.StandardSymbol = 13; break; // horizontal bar, legacy arrow down
515 case XML_circle: aSymbol.StandardSymbol = 8; break; // circle, legacy arrow right
516 case XML_plus: aSymbol.StandardSymbol = 11; break; // plus, legacy arrow left
519 // symbol size (points in OOXML, 1/100 mm in Chart2)
520 sal_Int32 nSize = convertPointToMm100(nOoxSize);
521 aSymbol.Size.Width = aSymbol.Size.Height = nSize;
523 if(xShapeProps.is())
525 Color aFillColor = xShapeProps->getFillProperties().maFillColor;
526 aSymbol.FillColor = sal_Int32(aFillColor.getColor(getFilter().getGraphicHelper()));
527 // tdf#124817: if there is no fill color, use line color of the symbol
528 if( aSymbol.FillColor < 0 )
530 Color aLineColor = xShapeProps->getLineProperties().maLineFill.maFillColor;
531 aSymbol.BorderColor = sal_Int32(aLineColor.getColor(getFilter().getGraphicHelper()));
532 rPropSet.setProperty(PROP_Color, aSymbol.BorderColor);
534 else
535 rPropSet.setProperty(PROP_Color, aSymbol.FillColor);
538 // set the property
539 rPropSet.setProperty( PROP_Symbol, aSymbol );
542 void TypeGroupConverter::convertLineSmooth( PropertySet& rPropSet, bool bOoxSmooth ) const
544 if( !isSeriesFrameFormat() && (maTypeInfo.meTypeCategory != TYPECATEGORY_RADAR) )
546 namespace cssc = css::chart2;
547 cssc::CurveStyle eCurveStyle = bOoxSmooth ? cssc::CurveStyle_CUBIC_SPLINES : cssc::CurveStyle_LINES;
548 rPropSet.setProperty( PROP_CurveStyle, eCurveStyle );
552 void TypeGroupConverter::convertBarGeometry( PropertySet& rPropSet, sal_Int32 nOoxShape ) const
554 if( !(mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR)) )
555 return;
557 namespace cssc = css::chart2;
559 sal_Int32 nGeom3d = cssc::DataPointGeometry3D::CUBOID;
560 switch( nOoxShape )
562 case XML_box: nGeom3d = cssc::DataPointGeometry3D::CUBOID; break;
563 case XML_cone: nGeom3d = cssc::DataPointGeometry3D::CONE; break;
564 case XML_coneToMax: nGeom3d = cssc::DataPointGeometry3D::CONE; break;
565 case XML_cylinder: nGeom3d = cssc::DataPointGeometry3D::CYLINDER; break;
566 case XML_pyramid: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break;
567 case XML_pyramidToMax: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break;
568 default: OSL_FAIL( "TypeGroupConverter::convertBarGeometry - unknown 3D bar shape type" );
570 rPropSet.setProperty( PROP_Geometry3D, nGeom3d );
573 void TypeGroupConverter::convertPieRotation( PropertySet& rPropSet, sal_Int32 nOoxAngle ) const
575 if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE )
577 // map OOXML [0,360] clockwise (0deg top) to Chart2 counterclockwise (0deg left)
578 sal_Int32 nAngle = (450 - nOoxAngle) % 360;
579 rPropSet.setProperty( PROP_StartingAngle, nAngle );
583 void TypeGroupConverter::convertPieExplosion( PropertySet& rPropSet, sal_Int32 nOoxExplosion ) const
585 if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE )
587 // pie explosion restricted to 100% in Chart2, set as double in range [0,1]
588 double fOffset = getLimitedValue< double >( nOoxExplosion / 100.0, 0.0, 1.0 );
589 rPropSet.setProperty( PROP_Offset, fOffset );
593 PieChartSubType TypeGroupConverter::convertOfPieType(sal_Int32 nOoxOfPieType ) const
595 if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE ) {
596 switch (nOoxOfPieType) {
597 case XML_pie:
598 return PieChartSubType_PIE;
599 break;
600 case XML_bar:
601 return PieChartSubType_BAR;
602 break;
603 default:
604 OSL_FAIL( "TypeGroupConverter::convertOfPieType - unknown of-pie type" );
605 return PieChartSubType_NONE;
607 } else {
608 return PieChartSubType_NONE;
613 // private --------------------------------------------------------------------
615 void TypeGroupConverter::insertDataSeries( const Reference< XChartType >& rxChartType, const Reference< XDataSeries >& rxSeries, sal_Int32 nAxesSetIdx )
617 if( !rxSeries.is() )
618 return;
620 PropertySet aSeriesProp( rxSeries );
622 // series stacking mode
623 namespace cssc = css::chart2;
624 cssc::StackingDirection eStacking = cssc::StackingDirection_NO_STACKING;
625 // stacked overrides deep-3d
626 if( isStacked() || isPercent() )
627 eStacking = cssc::StackingDirection_Y_STACKING;
628 else if( isDeep3dChart() )
629 eStacking = cssc::StackingDirection_Z_STACKING;
630 aSeriesProp.setProperty( PROP_StackingDirection, eStacking );
632 // additional series properties
633 aSeriesProp.setProperty( PROP_AttachedAxisIndex, nAxesSetIdx );
635 // insert series into container
638 Reference< XDataSeriesContainer > xSeriesCont( rxChartType, UNO_QUERY_THROW );
639 xSeriesCont->addDataSeries( rxSeries );
641 catch( Exception& )
643 OSL_FAIL( "TypeGroupConverter::insertDataSeries - cannot add data series" );
647 } // namespace oox
649 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */