1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "oox/drawingml/chart/typegroupconverter.hxx"
25
26 #include <com/sun/star/chart/DataLabelPlacement.hpp>
27 #include <com/sun/star/chart2/CurveStyle.hpp>
28 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
29 #include <com/sun/star/chart2/StackingDirection.hpp>
30 #include <com/sun/star/chart2/Symbol.hpp>
31 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
32 #include <com/sun/star/chart2/XCoordinateSystem.hpp>
33 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
34 #include <com/sun/star/chart2/data/XDataSink.hpp>
35 #include <com/sun/star/drawing/LineStyle.hpp>
36 #include "oox/drawingml/lineproperties.hxx"
37 #include "oox/drawingml/chart/seriesconverter.hxx"
38 #include "oox/drawingml/chart/typegroupmodel.hxx"
39 #include "oox/helper/containerhelper.hxx"
40
41 namespace oox {
42 namespace drawingml {
43 namespace chart {
44
45 // ============================================================================
46
47 using namespace ::com::sun::star::beans;
48 using namespace ::com::sun::star::chart2;
49 using namespace ::com::sun::star::chart2::data;
50 using namespace ::com::sun::star::uno;
51
52 using ::rtl::OUString;
53
54 // ============================================================================
55
56 namespace {
57
58 // chart type service names
59 const sal_Char SERVICE_CHART2_AREA[] = "com.sun.star.chart2.AreaChartType";
60 const sal_Char SERVICE_CHART2_CANDLE[] = "com.sun.star.chart2.CandleStickChartType";
61 const sal_Char SERVICE_CHART2_COLUMN[] = "com.sun.star.chart2.ColumnChartType";
62 const sal_Char SERVICE_CHART2_LINE[] = "com.sun.star.chart2.LineChartType";
63 const sal_Char SERVICE_CHART2_NET[] = "com.sun.star.chart2.NetChartType";
64 const sal_Char SERVICE_CHART2_FILLEDNET[] = "com.sun.star.chart2.FilledNetChartType";
65 const sal_Char SERVICE_CHART2_PIE[] = "com.sun.star.chart2.PieChartType";
66 const sal_Char SERVICE_CHART2_SCATTER[] = "com.sun.star.chart2.ScatterChartType";
67 const sal_Char SERVICE_CHART2_BUBBLE[] = "com.sun.star.chart2.BubbleChartType";
68 const sal_Char SERVICE_CHART2_SURFACE[] = "com.sun.star.chart2.ColumnChartType"; // Todo
69
70 namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
71
72 static const TypeGroupInfo spTypeInfos[] =
73 {
74 // type-id type-category service varied-point-color default label pos comb2d supp3d polar area2d 1stvis xcateg swap stack revers betw picopt
75 { TYPEID_BAR, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, true, true, false, true, false, true, false, true, false, true, true },
76 { TYPEID_HORBAR, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, false, true, false, true, false, true, true, true, false, true, true },
77 { TYPEID_LINE, TYPECATEGORY_LINE, SERVICE_CHART2_LINE, VARPOINTMODE_SINGLE, csscd::RIGHT, true, true, false, false, false, true, false, true, false, true, false },
78 { TYPEID_AREA, TYPECATEGORY_LINE, SERVICE_CHART2_AREA, VARPOINTMODE_NONE, csscd::CENTER, true, true, false, true, false, true, false, true, true, false, false },
79 { TYPEID_STOCK, TYPECATEGORY_LINE, SERVICE_CHART2_CANDLE, VARPOINTMODE_NONE, csscd::RIGHT, true, false, false, false, false, true, false, true, false, true, false },
80 { TYPEID_RADARLINE, TYPECATEGORY_RADAR, SERVICE_CHART2_NET, VARPOINTMODE_SINGLE, csscd::TOP, false, false, true, false, false, true, false, false, false, false, false },
81 { TYPEID_RADARAREA, TYPECATEGORY_RADAR, SERVICE_CHART2_FILLEDNET, VARPOINTMODE_NONE, csscd::TOP, false, false, true, true, false, true, false, false, true, false, false },
82 { TYPEID_PIE, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, true, true, false, false, false, false, false },
83 { TYPEID_DOUGHNUT, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, false, true, false, false, false, false, false },
84 { TYPEID_OFPIE, TYPECATEGORY_PIE, SERVICE_CHART2_PIE, VARPOINTMODE_MULTI, csscd::AVOID_OVERLAP, false, true, true, true, true, true, false, false, false, false, false },
85 { TYPEID_SCATTER, TYPECATEGORY_SCATTER, SERVICE_CHART2_SCATTER, VARPOINTMODE_SINGLE, csscd::RIGHT, true, true, false, false, false, false, false, false, false, false, false },
86 { TYPEID_BUBBLE, TYPECATEGORY_SCATTER, SERVICE_CHART2_BUBBLE, VARPOINTMODE_SINGLE, csscd::RIGHT, false, false, false, true, false, false, false, false, false, false, false },
87 { TYPEID_SURFACE, TYPECATEGORY_SURFACE, SERVICE_CHART2_SURFACE, VARPOINTMODE_NONE, csscd::RIGHT, false, true, false, true, false, true, false, false, false, false, false }
88 };
89
90 static const TypeGroupInfo saUnknownTypeInfo =
91 { TYPEID_UNKNOWN, TYPECATEGORY_BAR, SERVICE_CHART2_COLUMN, VARPOINTMODE_SINGLE, csscd::OUTSIDE, true, true, false, true, false, true, false, true, false, true, true };
92
lclGetTypeInfoFromTypeId(TypeId eTypeId)93 const TypeGroupInfo& lclGetTypeInfoFromTypeId( TypeId eTypeId )
94 {
95 const TypeGroupInfo* pEnd = STATIC_ARRAY_END( spTypeInfos );
96 for( const TypeGroupInfo* pIt = spTypeInfos; pIt != pEnd; ++pIt )
97 if( pIt->meTypeId == eTypeId )
98 return *pIt;
99 OSL_ENSURE( eTypeId == TYPEID_UNKNOWN, "lclGetTypeInfoFromTypeId - unexpected chart type identifier" );
100 return saUnknownTypeInfo;
101 }
102
103 } // namespace
104
105 // ============================================================================
106
UpDownBarsConverter(const ConverterRoot & rParent,UpDownBarsModel & rModel)107 UpDownBarsConverter::UpDownBarsConverter( const ConverterRoot& rParent, UpDownBarsModel& rModel ) :
108 ConverterBase< UpDownBarsModel >( rParent, rModel )
109 {
110 }
111
~UpDownBarsConverter()112 UpDownBarsConverter::~UpDownBarsConverter()
113 {
114 }
115
convertFromModel(const Reference<XChartType> & rxChartType)116 void UpDownBarsConverter::convertFromModel( const Reference< XChartType >& rxChartType )
117 {
118 PropertySet aTypeProp( rxChartType );
119
120 // upbar format
121 Reference< XPropertySet > xWhitePropSet;
122 if( aTypeProp.getProperty( xWhitePropSet, PROP_WhiteDay ) )
123 {
124 PropertySet aPropSet( xWhitePropSet );
125 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxUpBars, OBJECTTYPE_UPBAR );
126 }
127
128 // downbar format
129 Reference< XPropertySet > xBlackPropSet;
130 if( aTypeProp.getProperty( xBlackPropSet, PROP_BlackDay ) )
131 {
132 PropertySet aPropSet( xBlackPropSet );
133 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxDownBars, OBJECTTYPE_DOWNBAR );
134 }
135 }
136
137 // ============================================================================
138
TypeGroupConverter(const ConverterRoot & rParent,TypeGroupModel & rModel)139 TypeGroupConverter::TypeGroupConverter( const ConverterRoot& rParent, TypeGroupModel& rModel ) :
140 ConverterBase< TypeGroupModel >( rParent, rModel ),
141 mb3dChart( false )
142 {
143 TypeId eTypeId = TYPEID_UNKNOWN;
144 switch( mrModel.mnTypeId )
145 {
146 #define ENSURE_AXESCOUNT( min, max ) OSL_ENSURE( (min <= (int)mrModel.maAxisIds.size()) && ((int)mrModel.maAxisIds.size() <= max), "TypeGroupConverter::TypeGroupConverter - invalid axes count" )
147 case C_TOKEN( area3DChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_AREA; mb3dChart = true; break;
148 case C_TOKEN( areaChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_AREA; mb3dChart = false; break;
149 case C_TOKEN( bar3DChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_BAR; mb3dChart = true; break;
150 case C_TOKEN( barChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_BAR; mb3dChart = false; break;
151 case C_TOKEN( bubbleChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_BUBBLE; mb3dChart = false; break;
152 case C_TOKEN( doughnutChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_DOUGHNUT; mb3dChart = false; break;
153 case C_TOKEN( line3DChart ): ENSURE_AXESCOUNT( 3, 3 ); eTypeId = TYPEID_LINE; mb3dChart = true; break;
154 case C_TOKEN( lineChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_LINE; mb3dChart = false; break;
155 case C_TOKEN( ofPieChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_OFPIE; mb3dChart = false; break;
156 case C_TOKEN( pie3DChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_PIE; mb3dChart = true; break;
157 case C_TOKEN( pieChart ): ENSURE_AXESCOUNT( 0, 0 ); eTypeId = TYPEID_PIE; mb3dChart = false; break;
158 case C_TOKEN( radarChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_RADARLINE; mb3dChart = false; break;
159 case C_TOKEN( scatterChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_SCATTER; mb3dChart = false; break;
160 case C_TOKEN( stockChart ): ENSURE_AXESCOUNT( 2, 2 ); eTypeId = TYPEID_STOCK; mb3dChart = false; break;
161 case C_TOKEN( surface3DChart ): ENSURE_AXESCOUNT( 3, 3 ); eTypeId = TYPEID_SURFACE; mb3dChart = true; break;
162 case C_TOKEN( surfaceChart ): ENSURE_AXESCOUNT( 2, 3 ); eTypeId = TYPEID_SURFACE; mb3dChart = true; break; // 3D bar chart from all surface charts
163 default: OSL_ENSURE( false, "TypeGroupConverter::TypeGroupConverter - unknown chart type" );
164 #undef ENSURE_AXESCOUNT
165 }
166
167 // special handling for some chart types
168 switch( eTypeId )
169 {
170 case TYPEID_BAR:
171 if( mrModel.mnBarDir == XML_bar )
172 eTypeId = TYPEID_HORBAR;
173 break;
174 case TYPEID_RADARLINE:
175 if( mrModel.mnRadarStyle == XML_filled )
176 eTypeId = TYPEID_RADARAREA;
177 break;
178 case TYPEID_SURFACE:
179 // create a deep 3D bar chart from surface charts
180 mrModel.mnGrouping = XML_standard;
181 break;
182 default:;
183 }
184
185 // set the chart type info struct for the current chart type
186 maTypeInfo = lclGetTypeInfoFromTypeId( eTypeId );
187 }
188
~TypeGroupConverter()189 TypeGroupConverter::~TypeGroupConverter()
190 {
191 }
192
isStacked() const193 bool TypeGroupConverter::isStacked() const
194 {
195 return maTypeInfo.mbSupportsStacking && (mrModel.mnGrouping == XML_stacked);
196 }
197
isPercent() const198 bool TypeGroupConverter::isPercent() const
199 {
200 return maTypeInfo.mbSupportsStacking && (mrModel.mnGrouping == XML_percentStacked);
201 }
202
is3dChart() const203 bool TypeGroupConverter::is3dChart() const
204 {
205 return mb3dChart;
206 }
207
isWall3dChart() const208 bool TypeGroupConverter::isWall3dChart() const
209 {
210 return mb3dChart && (maTypeInfo.meTypeCategory != TYPECATEGORY_PIE);
211 }
212
isDeep3dChart() const213 bool TypeGroupConverter::isDeep3dChart() const
214 {
215 return isWall3dChart() && (mrModel.mnGrouping == XML_standard);
216 }
217
isSeriesFrameFormat() const218 bool TypeGroupConverter::isSeriesFrameFormat() const
219 {
220 return mb3dChart || maTypeInfo.mbSeriesIsFrame2d;
221 }
222
getSeriesObjectType() const223 ObjectType TypeGroupConverter::getSeriesObjectType() const
224 {
225 return mb3dChart ? OBJECTTYPE_FILLEDSERIES3D :
226 (maTypeInfo.mbSeriesIsFrame2d ? OBJECTTYPE_FILLEDSERIES2D : OBJECTTYPE_LINEARSERIES2D);
227 }
228
isReverseSeries() const229 bool TypeGroupConverter::isReverseSeries() const
230 {
231 return maTypeInfo.mbReverseSeries && !mb3dChart && !isStacked() && !isPercent();
232 }
233
getSingleSeriesTitle() const234 OUString TypeGroupConverter::getSingleSeriesTitle() const
235 {
236 OUString aSeriesTitle;
237 if( !mrModel.maSeries.empty() && (maTypeInfo.mbSingleSeriesVis || (mrModel.maSeries.size() == 1)) )
238 if( const TextModel* pText = mrModel.maSeries.front()->mxText.get() )
239 if( const DataSequenceModel* pDataSeq = pText->mxDataSeq.get() )
240 if( !pDataSeq->maData.empty() )
241 pDataSeq->maData.begin()->second >>= aSeriesTitle;
242 return aSeriesTitle;
243 }
244
createCoordinateSystem()245 Reference< XCoordinateSystem > TypeGroupConverter::createCoordinateSystem()
246 {
247 // find service name for coordinate system
248 OUString aServiceName;
249 if( maTypeInfo.mbPolarCoordSystem )
250 {
251 if( mb3dChart )
252 aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.PolarCoordinateSystem3d" );
253 else
254 aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.PolarCoordinateSystem2d" );
255 }
256 else
257 {
258 if( mb3dChart )
259 aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.CartesianCoordinateSystem3d" );
260 else
261 aServiceName = CREATE_OUSTRING( "com.sun.star.chart2.CartesianCoordinateSystem2d" );
262 }
263
264 // create the coordinate system object
265 Reference< XCoordinateSystem > xCoordSystem( createInstance( aServiceName ), UNO_QUERY );
266
267 // swap X and Y axis
268 if( maTypeInfo.mbSwappedAxesSet )
269 {
270 PropertySet aPropSet( xCoordSystem );
271 aPropSet.setProperty( PROP_SwapXAndYAxis, true );
272 }
273
274 return xCoordSystem;
275 }
276
createCategorySequence()277 Reference< XLabeledDataSequence > TypeGroupConverter::createCategorySequence()
278 {
279 Reference< XLabeledDataSequence > xLabeledSeq;
280 /* Find first existing category sequence. The bahaviour of Excel 2007 is
281 different to Excel 2003, which always used the category sequence of the
282 first series, even if it was empty. */
283 for( TypeGroupModel::SeriesVector::iterator aIt = mrModel.maSeries.begin(), aEnd = mrModel.maSeries.end(); !xLabeledSeq.is() && (aIt != aEnd); ++aIt )
284 {
285 if( (*aIt)->maSources.has( SeriesModel::CATEGORIES ) )
286 {
287 SeriesConverter aSeriesConv( *this, **aIt );
288 xLabeledSeq = aSeriesConv.createCategorySequence( CREATE_OUSTRING( "categories" ) );
289 }
290 }
291 return xLabeledSeq;
292 }
293
convertFromModel(const Reference<XDiagram> & rxDiagram,const Reference<XCoordinateSystem> & rxCoordSystem,sal_Int32 nAxesSetIdx,bool bSupportsVaryColorsByPoint)294 void TypeGroupConverter::convertFromModel( const Reference< XDiagram >& rxDiagram,
295 const Reference< XCoordinateSystem >& rxCoordSystem,
296 sal_Int32 nAxesSetIdx, bool bSupportsVaryColorsByPoint )
297 {
298 try
299 {
300 // create the chart type object
301 OUString aService = OUString::createFromAscii( maTypeInfo.mpcServiceName );
302 Reference< XChartType > xChartType( createInstance( aService ), UNO_QUERY_THROW );
303
304 // additional properties
305 PropertySet aDiaProp( rxDiagram );
306 PropertySet aTypeProp( xChartType );
307 switch( maTypeInfo.meTypeCategory )
308 {
309 case TYPECATEGORY_BAR:
310 {
311 Sequence< sal_Int32 > aInt32Seq( 2 );
312 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = mrModel.mnOverlap;
313 aTypeProp.setProperty( PROP_OverlapSequence, aInt32Seq );
314 aInt32Seq[ 0 ] = aInt32Seq[ 1 ] = mrModel.mnGapWidth;
315 aTypeProp.setProperty( PROP_GapwidthSequence, aInt32Seq );
316 }
317 break;
318 case TYPECATEGORY_PIE:
319 {
320 aTypeProp.setProperty( PROP_UseRings, maTypeInfo.meTypeId == TYPEID_DOUGHNUT );
321 /* #i85166# starting angle of first pie slice. 3D pie charts
322 use Y rotation setting in view3D element. Of-pie charts do
323 not support pie rotation. */
324 if( !is3dChart() && (maTypeInfo.meTypeId != TYPEID_OFPIE) )
325 convertPieRotation( aDiaProp, mrModel.mnFirstAngle );
326 }
327 break;
328 default:;
329 }
330
331 // create converter objects for all series models
332 typedef RefVector< SeriesConverter > SeriesConvVector;
333 SeriesConvVector aSeries;
334 for( TypeGroupModel::SeriesVector::iterator aIt = mrModel.maSeries.begin(), aEnd = mrModel.maSeries.end(); aIt != aEnd; ++aIt )
335 aSeries.push_back( SeriesConvVector::value_type( new SeriesConverter( *this, **aIt ) ) );
336
337 // reverse series order for some unstacked 2D chart types
338 if( isReverseSeries() )
339 ::std::reverse( aSeries.begin(), aSeries.end() );
340
341 // decide whether to use varying colors for each data point
342 bool bVaryColorsByPoint = bSupportsVaryColorsByPoint && mrModel.mbVaryColors;
343 switch( maTypeInfo.meVarPointMode )
344 {
345 case VARPOINTMODE_NONE: bVaryColorsByPoint = false; break;
346 case VARPOINTMODE_SINGLE: bVaryColorsByPoint &= (mrModel.maSeries.size() == 1); break;
347 case VARPOINTMODE_MULTI: break;
348 }
349
350 /* Stock chart needs special processing. Create one 'big' series with
351 data sequences of different roles. */
352 if( maTypeInfo.meTypeId == TYPEID_STOCK )
353 {
354 // create the data series object
355 Reference< XDataSeries > xDataSeries( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.DataSeries" ) ), UNO_QUERY );
356 Reference< XDataSink > xDataSink( xDataSeries, UNO_QUERY );
357 if( xDataSink.is() )
358 {
359 // create a list of data sequences from all series
360 ::std::vector< Reference< XLabeledDataSequence > > aLabeledSeqVec;
361 OSL_ENSURE( aSeries.size() >= 3, "TypeGroupConverter::convertFromModel - too few stock chart series" );
362 int nRoleIdx = (aSeries.size() == 3) ? 1 : 0;
363 for( SeriesConvVector::iterator aIt = aSeries.begin(), aEnd = aSeries.end(); (nRoleIdx < 4) && (aIt != aEnd); ++nRoleIdx, ++aIt )
364 {
365 // create a data sequence with a specific role
366 OUString aRole;
367 switch( nRoleIdx )
368 {
369 case 0: aRole = CREATE_OUSTRING( "values-first" ); break;
370 case 1: aRole = CREATE_OUSTRING( "values-max" ); break;
371 case 2: aRole = CREATE_OUSTRING( "values-min" ); break;
372 case 3: aRole = CREATE_OUSTRING( "values-last" ); break;
373 }
374 Reference< XLabeledDataSequence > xDataSeq = (*aIt)->createValueSequence( aRole );
375 if( xDataSeq.is() )
376 aLabeledSeqVec.push_back( xDataSeq );
377 }
378
379 // attach labeled data sequences to series and insert series into chart type
380 xDataSink->setData( ContainerHelper::vectorToSequence( aLabeledSeqVec ) );
381
382 // formatting of high/low lines
383 aTypeProp.setProperty( PROP_ShowHighLow, true );
384 PropertySet aSeriesProp( xDataSeries );
385 if( mrModel.mxHiLowLines.is() )
386 getFormatter().convertFrameFormatting( aSeriesProp, mrModel.mxHiLowLines, OBJECTTYPE_HILOLINE );
387 else
388 // hi/low-lines cannot be switched off via "ShowHighLow" property (?)
389 aSeriesProp.setProperty( PROP_LineStyle, ::com::sun::star::drawing::LineStyle_NONE );
390
391 // formatting of up/down bars
392 bool bUpDownBars = mrModel.mxUpDownBars.is();
393 aTypeProp.setProperty( PROP_Japanese, bUpDownBars );
394 aTypeProp.setProperty( PROP_ShowFirst, bUpDownBars );
395 if( bUpDownBars )
396 {
397 UpDownBarsConverter aUpDownConv( *this, *mrModel.mxUpDownBars );
398 aUpDownConv.convertFromModel( xChartType );
399 }
400
401 // insert the series into the chart type object
402 insertDataSeries( xChartType, xDataSeries, nAxesSetIdx );
403 }
404 }
405 else
406 {
407 for( SeriesConvVector::iterator aIt = aSeries.begin(), aEnd = aSeries.end(); aIt != aEnd; ++aIt )
408 {
409 SeriesConverter& rSeriesConv = **aIt;
410 Reference< XDataSeries > xDataSeries = rSeriesConv.createDataSeries( *this, bVaryColorsByPoint );
411 insertDataSeries( xChartType, xDataSeries, nAxesSetIdx );
412
413 /* Excel does not use the value of the c:smooth element of the
414 chart type to set a default line smoothing for the data
415 series. Line smoothing is always controlled by the c:smooth
416 element of the respective data series. If the element in the
417 data series is missing, line smoothing is off, regardless of
418 the c:smooth element of the chart type. */
419 #if !OOX_CHART_SMOOTHED_PER_SERIES
420 if( rSeriesConv.getModel().mbSmooth )
421 convertLineSmooth( aTypeProp, true );
422 #endif
423 }
424 }
425
426 // add chart type object to coordinate system
427 Reference< XChartTypeContainer > xChartTypeCont( rxCoordSystem, UNO_QUERY_THROW );
428 xChartTypeCont->addChartType( xChartType );
429
430 // set existence of bar connector lines at diagram (only in stacked 2D bar charts)
431 if( mrModel.mxSerLines.is() && !mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR) && (isStacked() || isPercent()) )
432 aDiaProp.setProperty( PROP_ConnectBars, true );
433 }
434 catch( Exception& )
435 {
436 OSL_ENSURE( false, "TypeGroupConverter::convertFromModel - cannot add chart type" );
437 }
438 }
439
convertMarker(PropertySet & rPropSet,sal_Int32 nOoxSymbol,sal_Int32 nOoxSize) const440 void TypeGroupConverter::convertMarker( PropertySet& rPropSet, sal_Int32 nOoxSymbol, sal_Int32 nOoxSize ) const
441 {
442 if( !isSeriesFrameFormat() )
443 {
444 namespace cssc = ::com::sun::star::chart2;
445
446 // symbol style
447 cssc::Symbol aSymbol;
448 aSymbol.Style = cssc::SymbolStyle_STANDARD;
449 switch( nOoxSymbol ) // compare with XclChPropSetHelper::WriteMarkerProperties in xlchart.cxx
450 {
451 case XML_auto: aSymbol.Style = cssc::SymbolStyle_AUTO; break;
452 case XML_none: aSymbol.Style = cssc::SymbolStyle_NONE; break;
453 case XML_square: aSymbol.StandardSymbol = 0; break; // square
454 case XML_diamond: aSymbol.StandardSymbol = 1; break; // diamond
455 case XML_triangle: aSymbol.StandardSymbol = 3; break; // arrow up
456 case XML_x: aSymbol.StandardSymbol = 10; break; // X, legacy bow tie
457 case XML_star: aSymbol.StandardSymbol = 12; break; // asterisk, legacy sand glass
458 case XML_dot: aSymbol.StandardSymbol = 4; break; // arrow right
459 case XML_dash: aSymbol.StandardSymbol = 13; break; // horizontal bar, legacy arrow down
460 case XML_circle: aSymbol.StandardSymbol = 8; break; // circle, legacy arrow right
461 case XML_plus: aSymbol.StandardSymbol = 11; break; // plus, legacy arrow left
462 }
463
464 // symbol size (points in OOXML, 1/100 mm in Chart2)
465 sal_Int32 nSize = static_cast< sal_Int32 >( nOoxSize * (2540.0 / 72.0) + 0.5 );
466 aSymbol.Size.Width = aSymbol.Size.Height = nSize;
467
468 // set the property
469 rPropSet.setProperty( PROP_Symbol, aSymbol );
470 }
471 }
472
convertLineSmooth(PropertySet & rPropSet,bool bOoxSmooth) const473 void TypeGroupConverter::convertLineSmooth( PropertySet& rPropSet, bool bOoxSmooth ) const
474 {
475 if( !isSeriesFrameFormat() && (maTypeInfo.meTypeCategory != TYPECATEGORY_RADAR) )
476 {
477 namespace cssc = ::com::sun::star::chart2;
478 cssc::CurveStyle eCurveStyle = bOoxSmooth ? cssc::CurveStyle_CUBIC_SPLINES : cssc::CurveStyle_LINES;
479 rPropSet.setProperty( PROP_CurveStyle, eCurveStyle );
480 }
481 }
482
convertBarGeometry(PropertySet & rPropSet,sal_Int32 nOoxShape) const483 void TypeGroupConverter::convertBarGeometry( PropertySet& rPropSet, sal_Int32 nOoxShape ) const
484 {
485 if( mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR) )
486 {
487 namespace cssc = ::com::sun::star::chart2;
488
489 sal_Int32 nGeom3d = cssc::DataPointGeometry3D::CUBOID;
490 switch( nOoxShape )
491 {
492 case XML_box: nGeom3d = cssc::DataPointGeometry3D::CUBOID; break;
493 case XML_cone: nGeom3d = cssc::DataPointGeometry3D::CONE; break;
494 case XML_coneToMax: nGeom3d = cssc::DataPointGeometry3D::CONE; break;
495 case XML_cylinder: nGeom3d = cssc::DataPointGeometry3D::CYLINDER; break;
496 case XML_pyramid: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break;
497 case XML_pyramidToMax: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break;
498 default: OSL_ENSURE( false, "TypeGroupConverter::convertBarGeometry - unknown 3D bar shape type" );
499 }
500 rPropSet.setProperty( PROP_Geometry3D, nGeom3d );
501 }
502 }
503
convertPieRotation(PropertySet & rPropSet,sal_Int32 nOoxAngle) const504 void TypeGroupConverter::convertPieRotation( PropertySet& rPropSet, sal_Int32 nOoxAngle ) const
505 {
506 if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE )
507 {
508 // map OOXML [0,360] clockwise (0deg top) to Chart2 counterclockwise (0deg left)
509 sal_Int32 nAngle = (450 - nOoxAngle) % 360;
510 rPropSet.setProperty( PROP_StartingAngle, nAngle );
511 }
512 }
513
convertPieExplosion(PropertySet & rPropSet,sal_Int32 nOoxExplosion) const514 void TypeGroupConverter::convertPieExplosion( PropertySet& rPropSet, sal_Int32 nOoxExplosion ) const
515 {
516 if( maTypeInfo.meTypeCategory == TYPECATEGORY_PIE )
517 {
518 // pie explosion restricted to 100% in Chart2, set as double in range [0,1]
519 double fOffset = getLimitedValue< double >( nOoxExplosion / 100.0, 0.0, 1.0 );
520 rPropSet.setProperty( PROP_Offset, fOffset );
521 }
522 }
523
524 // private --------------------------------------------------------------------
525
insertDataSeries(const Reference<XChartType> & rxChartType,const Reference<XDataSeries> & rxSeries,sal_Int32 nAxesSetIdx)526 void TypeGroupConverter::insertDataSeries( const Reference< XChartType >& rxChartType, const Reference< XDataSeries >& rxSeries, sal_Int32 nAxesSetIdx )
527 {
528 if( rxSeries.is() )
529 {
530 PropertySet aSeriesProp( rxSeries );
531
532 // series stacking mode
533 namespace cssc = ::com::sun::star::chart2;
534 cssc::StackingDirection eStacking = cssc::StackingDirection_NO_STACKING;
535 // stacked overrides deep-3d
536 if( isStacked() || isPercent() )
537 eStacking = cssc::StackingDirection_Y_STACKING;
538 else if( isDeep3dChart() )
539 eStacking = cssc::StackingDirection_Z_STACKING;
540 aSeriesProp.setProperty( PROP_StackingDirection, eStacking );
541
542 // additional series properties
543 aSeriesProp.setProperty( PROP_AttachedAxisIndex, nAxesSetIdx );
544
545 // insert series into container
546 try
547 {
548 Reference< XDataSeriesContainer > xSeriesCont( rxChartType, UNO_QUERY_THROW );
549 xSeriesCont->addDataSeries( rxSeries );
550 }
551 catch( Exception& )
552 {
553 OSL_ENSURE( false, "TypeGroupConverter::insertDataSeries - cannot add data series" );
554 }
555 }
556 }
557
558 // ============================================================================
559
560 } // namespace chart
561 } // namespace drawingml
562 } // namespace oox
563