Update ooo320-m1
[ooovba.git] / oox / source / drawingml / chart / plotareaconverter.cxx
blob94acaa4c13c183ad38b3f2ebbf2c2d4374ac58b7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: plotareaconverter.cxx,v $
11 * $Revision: 1.4 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 #include "oox/drawingml/chart/plotareaconverter.hxx"
33 #include <com/sun/star/drawing/Direction3D.hpp>
34 #include <com/sun/star/drawing/ProjectionMode.hpp>
35 #include <com/sun/star/drawing/ShadeMode.hpp>
36 #include <com/sun/star/chart2/XChartDocument.hpp>
37 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
38 #include <com/sun/star/chart2/XDiagram.hpp>
39 #include "oox/drawingml/chart/axisconverter.hxx"
40 #include "oox/drawingml/chart/plotareamodel.hxx"
41 #include "oox/drawingml/chart/typegroupconverter.hxx"
42 #include "properties.hxx"
44 using ::rtl::OUString;
45 using ::com::sun::star::uno::Reference;
46 using ::com::sun::star::uno::Sequence;
47 using ::com::sun::star::uno::Exception;
48 using ::com::sun::star::uno::UNO_QUERY_THROW;
49 using ::com::sun::star::chart2::XCoordinateSystem;
50 using ::com::sun::star::chart2::XCoordinateSystemContainer;
51 using ::com::sun::star::chart2::XDiagram;
53 namespace oox {
54 namespace drawingml {
55 namespace chart {
57 // ============================================================================
59 namespace {
61 /** Axes set model. This is a helper class for the plot area converter. */
62 struct AxesSetModel
64 typedef ModelVector< TypeGroupModel > TypeGroupVector;
65 typedef ModelMap< sal_Int32, AxisModel > AxisMap;
67 TypeGroupVector maTypeGroups;
68 AxisMap maAxes;
70 inline explicit AxesSetModel() {}
71 inline ~AxesSetModel() {}
74 // ============================================================================
76 /** Axes set converter. This is a helper class for the plot area converter. */
77 class AxesSetConverter : public ConverterBase< AxesSetModel >
79 public:
80 explicit AxesSetConverter( const ConverterRoot& rParent, AxesSetModel& rModel );
81 virtual ~AxesSetConverter();
83 /** Converts the axes set model to a chart2 diagram. Returns an automatic
84 chart title from a single series title, if possible. */
85 void convertFromModel(
86 const Reference< XDiagram >& rxDiagram,
87 View3DModel& rView3DModel,
88 sal_Int32 nAxesSetIdx,
89 bool bSupportsVaryColorsByPoint );
91 /** Returns the automatic chart title if the axes set contains only one series. */
92 inline const ::rtl::OUString& getAutomaticTitle() const { return maAutoTitle; }
93 /** Returns true, if the chart is three-dimensional. */
94 inline bool is3dChart() const { return mb3dChart; }
95 /** Returns true, if chart type supports wall and floor format in 3D mode. */
96 inline bool isWall3dChart() const { return mbWall3dChart; }
98 private:
99 ::rtl::OUString maAutoTitle;
100 bool mb3dChart;
101 bool mbWall3dChart;
104 // ----------------------------------------------------------------------------
106 AxesSetConverter::AxesSetConverter( const ConverterRoot& rParent, AxesSetModel& rModel ) :
107 ConverterBase< AxesSetModel >( rParent, rModel ),
108 mb3dChart( false ),
109 mbWall3dChart( false )
113 AxesSetConverter::~AxesSetConverter()
117 ModelRef< AxisModel > lclGetOrCreateAxis( const AxesSetModel::AxisMap& rFromAxes, sal_Int32 nAxisIdx, sal_Int32 nDefTypeId )
119 ModelRef< AxisModel > xAxis = rFromAxes.get( nAxisIdx );
120 if( !xAxis )
121 xAxis.create( nDefTypeId ).mbDeleted = true; // missing axis is invisible
122 return xAxis;
125 void AxesSetConverter::convertFromModel( const Reference< XDiagram >& rxDiagram,
126 View3DModel& rView3DModel, sal_Int32 nAxesSetIdx, bool bSupportsVaryColorsByPoint )
128 // create type group converter objects for all type groups
129 typedef RefVector< TypeGroupConverter > TypeGroupConvVector;
130 TypeGroupConvVector aTypeGroups;
131 for( AxesSetModel::TypeGroupVector::iterator aIt = mrModel.maTypeGroups.begin(), aEnd = mrModel.maTypeGroups.end(); aIt != aEnd; ++aIt )
132 aTypeGroups.push_back( TypeGroupConvVector::value_type( new TypeGroupConverter( *this, **aIt ) ) );
134 OSL_ENSURE( !aTypeGroups.empty(), "AxesSetConverter::convertFromModel - no type groups in axes set" );
135 if( !aTypeGroups.empty() ) try
137 // first type group needed for coordinate system and axis conversion
138 TypeGroupConverter& rFirstTypeGroup = *aTypeGroups.front();
140 // get automatic chart title, if there is only one type group
141 if( aTypeGroups.size() == 1 )
142 maAutoTitle = rFirstTypeGroup.getSingleSeriesTitle();
144 /* Create a coordinate system. For now, all type groups from all axes sets
145 have to be inserted into one coordinate system. Later, chart2 should
146 support using one coordinate system for each axes set. */
147 Reference< XCoordinateSystem > xCoordSystem;
148 Reference< XCoordinateSystemContainer > xCoordSystemCont( rxDiagram, UNO_QUERY_THROW );
149 Sequence< Reference< XCoordinateSystem > > aCoordSystems = xCoordSystemCont->getCoordinateSystems();
150 if( aCoordSystems.hasElements() )
152 OSL_ENSURE( aCoordSystems.getLength() == 1, "AxesSetConverter::convertFromModel - too many coordinate systems" );
153 xCoordSystem = aCoordSystems[ 0 ];
154 OSL_ENSURE( xCoordSystem.is(), "AxesSetConverter::convertFromModel - invalid coordinate system" );
156 else
158 xCoordSystem = rFirstTypeGroup.createCoordinateSystem();
159 if( xCoordSystem.is() )
160 xCoordSystemCont->addCoordinateSystem( xCoordSystem );
163 // 3D view settings
164 mb3dChart = rFirstTypeGroup.is3dChart();
165 mbWall3dChart = rFirstTypeGroup.isWall3dChart();
166 if( mb3dChart )
168 View3DConverter aView3DConv( *this, rView3DModel );
169 aView3DConv.convertFromModel( rxDiagram, rFirstTypeGroup );
172 /* Convert all chart type groups. Each type group will add its series
173 to the data provider attached to the chart document. */
174 if( xCoordSystem.is() )
176 // convert all axes (create missing axis models)
177 ModelRef< AxisModel > xXAxis = lclGetOrCreateAxis( mrModel.maAxes, API_X_AXIS, rFirstTypeGroup.getTypeInfo().mbCategoryAxis ? C_TOKEN( catAx ) : C_TOKEN( valAx ) );
178 ModelRef< AxisModel > xYAxis = lclGetOrCreateAxis( mrModel.maAxes, API_Y_AXIS, C_TOKEN( valAx ) );
180 AxisConverter aXAxisConv( *this, *xXAxis );
181 aXAxisConv.convertFromModel( xCoordSystem, rFirstTypeGroup, xYAxis.get(), nAxesSetIdx, API_X_AXIS );
182 AxisConverter aYAxisConv( *this, *xYAxis );
183 aYAxisConv.convertFromModel( xCoordSystem, rFirstTypeGroup, xXAxis.get(), nAxesSetIdx, API_Y_AXIS );
185 if( rFirstTypeGroup.isDeep3dChart() )
187 ModelRef< AxisModel > xZAxis = lclGetOrCreateAxis( mrModel.maAxes, API_Z_AXIS, C_TOKEN( serAx ) );
188 AxisConverter aZAxisConv( *this, *xZAxis );
189 aZAxisConv.convertFromModel( xCoordSystem, rFirstTypeGroup, 0, nAxesSetIdx, API_Z_AXIS );
192 // convert all chart type groups, this converts all series data and formatting
193 for( TypeGroupConvVector::iterator aTIt = aTypeGroups.begin(), aTEnd = aTypeGroups.end(); aTIt != aTEnd; ++aTIt )
194 (*aTIt)->convertFromModel( rxDiagram, xCoordSystem, nAxesSetIdx, bSupportsVaryColorsByPoint );
197 catch( Exception& )
202 } // namespace
204 // ============================================================================
206 View3DConverter::View3DConverter( const ConverterRoot& rParent, View3DModel& rModel ) :
207 ConverterBase< View3DModel >( rParent, rModel )
211 View3DConverter::~View3DConverter()
215 void View3DConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, TypeGroupConverter& rTypeGroup )
217 namespace cssd = ::com::sun::star::drawing;
218 PropertySet aPropSet( rxDiagram );
220 sal_Int32 nRotationY = 0;
221 sal_Int32 nRotationX = 0;
222 bool bRightAngled = false;
223 sal_Int32 nAmbientColor = 0;
224 sal_Int32 nLightColor = 0;
226 if( rTypeGroup.getTypeInfo().meTypeCategory == TYPECATEGORY_PIE )
228 // Y rotation used as 'first pie slice angle' in 3D pie charts
229 rTypeGroup.convertPieRotation( aPropSet, mrModel.monRotationY.get( 0 ) );
230 // X rotation a.k.a. elevation (map OOXML [0..90] to Chart2 [-90,0])
231 nRotationX = getLimitedValue< sal_Int32, sal_Int32 >( mrModel.monRotationX.get( 15 ), 0, 90 ) - 90;
232 // no right-angled axes in pie charts
233 bRightAngled = false;
234 // ambient color (Gray 30%)
235 nAmbientColor = 0xB3B3B3;
236 // light color (Gray 70%)
237 nLightColor = 0x4C4C4C;
239 else // 3D bar/area/line charts
241 // Y rotation (OOXML [0..359], Chart2 [-179,180])
242 nRotationY = mrModel.monRotationY.get( 20 );
243 // X rotation a.k.a. elevation (OOXML [-90..90], Chart2 [-179,180])
244 nRotationX = getLimitedValue< sal_Int32, sal_Int32 >( mrModel.monRotationX.get( 15 ), -90, 90 );
245 // right-angled axes
246 bRightAngled = mrModel.mbRightAngled;
247 // ambient color (Gray 20%)
248 nAmbientColor = 0xCCCCCC;
249 // light color (Gray 60%)
250 nLightColor = 0x666666;
253 // Y rotation (map OOXML [0..359] to Chart2 [-179,180])
254 nRotationY %= 360;
255 if( nRotationY > 180 ) nRotationY -= 360;
256 /* Perspective (map OOXML [0..200] to Chart2 [0,100]). Seems that MSO 2007 is
257 buggy here, the XML plugin of MSO 2003 writes the correct perspective in
258 the range from 0 to 100. We will emulate the wrong behaviour of MSO 2007. */
259 sal_Int32 nPerspective = getLimitedValue< sal_Int32, sal_Int32 >( mrModel.mnPerspective / 2, 0, 100 );
260 // projection mode (parallel axes, if right-angled, #i90360# or if perspective is at 0%)
261 bool bParallel = bRightAngled || (nPerspective == 0);
262 cssd::ProjectionMode eProjMode = bParallel ? cssd::ProjectionMode_PARALLEL : cssd::ProjectionMode_PERSPECTIVE;
264 // set rotation properties
265 aPropSet.setProperty( PROP_RotationVertical, nRotationY );
266 aPropSet.setProperty( PROP_RotationHorizontal, nRotationX );
267 aPropSet.setProperty( PROP_Perspective, nPerspective );
268 aPropSet.setProperty( PROP_RightAngledAxes, bRightAngled );
269 aPropSet.setProperty( PROP_D3DScenePerspective, eProjMode );
271 // set light settings
272 aPropSet.setProperty( PROP_D3DSceneShadeMode, cssd::ShadeMode_FLAT );
273 aPropSet.setProperty( PROP_D3DSceneAmbientColor, nAmbientColor );
274 aPropSet.setProperty( PROP_D3DSceneLightOn1, false );
275 aPropSet.setProperty( PROP_D3DSceneLightOn2, true );
276 aPropSet.setProperty( PROP_D3DSceneLightColor2, nLightColor );
277 aPropSet.setProperty( PROP_D3DSceneLightDirection2, cssd::Direction3D( 0.2, 0.4, 1.0 ) );
280 // ============================================================================
282 WallFloorConverter::WallFloorConverter( const ConverterRoot& rParent, WallFloorModel& rModel ) :
283 ConverterBase< WallFloorModel >( rParent, rModel )
287 WallFloorConverter::~WallFloorConverter()
291 void WallFloorConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, ObjectType eObjType )
293 if( rxDiagram.is() )
295 PropertySet aPropSet;
296 switch( eObjType )
298 case OBJECTTYPE_FLOOR: aPropSet.set( rxDiagram->getFloor() ); break;
299 case OBJECTTYPE_WALL: aPropSet.set( rxDiagram->getWall() ); break;
300 default: OSL_ENSURE( false, "WallFloorConverter::convertFromModel - invalid object type" );
302 if( aPropSet.is() )
303 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, mrModel.mxPicOptions.getOrCreate(), eObjType );
307 // ============================================================================
309 PlotAreaConverter::PlotAreaConverter( const ConverterRoot& rParent, PlotAreaModel& rModel ) :
310 ConverterBase< PlotAreaModel >( rParent, rModel ),
311 mb3dChart( false ),
312 mbWall3dChart( false )
316 PlotAreaConverter::~PlotAreaConverter()
320 void PlotAreaConverter::convertFromModel( View3DModel& rView3DModel )
322 /* Create the diagram object and attach it to the chart document. One
323 diagram is used to carry all coordinate systems and data series. */
324 Reference< XDiagram > xDiagram;
327 xDiagram.set( createInstance( CREATE_OUSTRING( "com.sun.star.chart2.Diagram" ) ), UNO_QUERY_THROW );
328 getChartDocument()->setFirstDiagram( xDiagram );
330 catch( Exception& )
334 // store all axis models in a map, keyed by axis identifier
335 typedef ModelMap< sal_Int32, AxisModel > AxisMap;
336 AxisMap aAxisMap;
337 for( PlotAreaModel::AxisVector::iterator aAIt = mrModel.maAxes.begin(), aAEnd = mrModel.maAxes.end(); aAIt != aAEnd; ++aAIt )
339 PlotAreaModel::AxisVector::value_type xAxis = *aAIt;
340 OSL_ENSURE( xAxis->mnAxisId >= 0, "PlotAreaConverter::convertFromModel - invalid axis identifier" );
341 OSL_ENSURE( !aAxisMap.has( xAxis->mnAxisId ), "PlotAreaConverter::convertFromModel - axis identifiers not unique" );
342 if( xAxis->mnAxisId >= 0 )
343 aAxisMap[ xAxis->mnAxisId ] = xAxis;
346 // group the type group models into different axes sets
347 typedef ModelVector< AxesSetModel > AxesSetVector;
348 AxesSetVector aAxesSets;
349 sal_Int32 nMaxSeriesIdx = -1;
350 for( PlotAreaModel::TypeGroupVector::iterator aTIt = mrModel.maTypeGroups.begin(), aTEnd = mrModel.maTypeGroups.end(); aTIt != aTEnd; ++aTIt )
352 PlotAreaModel::TypeGroupVector::value_type xTypeGroup = *aTIt;
353 if( !xTypeGroup->maSeries.empty() )
355 // try to find a compatible axes set for the type group
356 AxesSetModel* pAxesSet = 0;
357 for( AxesSetVector::iterator aASIt = aAxesSets.begin(), aASEnd = aAxesSets.end(); !pAxesSet && (aASIt != aASEnd); ++aASIt )
358 if( (*aASIt)->maTypeGroups.front()->maAxisIds == xTypeGroup->maAxisIds )
359 pAxesSet = aASIt->get();
361 // not possible to insert into an existing axes set -> start a new axes set
362 if( !pAxesSet )
364 pAxesSet = &aAxesSets.create();
365 // find axis models used by the type group
366 const TypeGroupModel::AxisIdVector& rAxisIds = xTypeGroup->maAxisIds;
367 if( rAxisIds.size() >= 1 )
368 pAxesSet->maAxes[ API_X_AXIS ] = aAxisMap.get( rAxisIds[ 0 ] );
369 if( rAxisIds.size() >= 2 )
370 pAxesSet->maAxes[ API_Y_AXIS ] = aAxisMap.get( rAxisIds[ 1 ] );
371 if( rAxisIds.size() >= 3 )
372 pAxesSet->maAxes[ API_Z_AXIS ] = aAxisMap.get( rAxisIds[ 2 ] );
375 // insert the type group model
376 pAxesSet->maTypeGroups.push_back( xTypeGroup );
378 // collect the maximum series index for automatic series formatting
379 for( TypeGroupModel::SeriesVector::iterator aSIt = xTypeGroup->maSeries.begin(), aSEnd = xTypeGroup->maSeries.end(); aSIt != aSEnd; ++aSIt )
380 nMaxSeriesIdx = ::std::max( nMaxSeriesIdx, (*aSIt)->mnIndex );
383 getFormatter().setMaxSeriesIndex( nMaxSeriesIdx );
385 // varying point colors only for single series in single chart type
386 bool bSupportsVaryColorsByPoint = mrModel.maTypeGroups.size() == 1;
388 // convert all axes sets
389 for( AxesSetVector::iterator aASBeg = aAxesSets.begin(), aASIt = aASBeg, aASEnd = aAxesSets.end(); aASIt != aASEnd; ++aASIt )
391 AxesSetConverter aAxesSetConv( *this, **aASIt );
392 sal_Int32 nAxesSetIdx = static_cast< sal_Int32 >( aASIt - aASBeg );
393 aAxesSetConv.convertFromModel( xDiagram, rView3DModel, nAxesSetIdx, bSupportsVaryColorsByPoint );
394 if( nAxesSetIdx == 0 )
396 maAutoTitle = aAxesSetConv.getAutomaticTitle();
397 mb3dChart = aAxesSetConv.is3dChart();
398 mbWall3dChart = aAxesSetConv.isWall3dChart();
400 else
402 maAutoTitle = OUString();
406 // plot area formatting
407 if( xDiagram.is() && !mb3dChart )
409 PropertySet aPropSet( xDiagram->getWall() );
410 getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, OBJECTTYPE_PLOTAREA2D );
414 // ============================================================================
416 } // namespace chart
417 } // namespace drawingml
418 } // namespace oox