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