Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
5 : : * This Source Code Form is subject to the terms of the Mozilla Public
6 : : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
11 : : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : : * contributor license agreements. See the NOTICE file distributed
13 : : * with this work for additional information regarding copyright
14 : : * ownership. The ASF licenses this file to you under the Apache
15 : : * License, Version 2.0 (the "License"); you may not use this file
16 : : * except in compliance with the License. You may obtain a copy of
17 : : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : : */
19 : :
20 : : #include "oox/drawingml/chart/converterbase.hxx"
21 : :
22 : : #include <com/sun/star/chart/XAxisXSupplier.hpp>
23 : : #include <com/sun/star/chart/XAxisYSupplier.hpp>
24 : : #include <com/sun/star/chart/XAxisZSupplier.hpp>
25 : : #include <com/sun/star/chart/XChartDocument.hpp>
26 : : #include <com/sun/star/chart/XSecondAxisTitleSupplier.hpp>
27 : : #include <com/sun/star/chart2/RelativePosition.hpp>
28 : : #include <com/sun/star/chart2/RelativeSize.hpp>
29 : : #include <com/sun/star/drawing/FillStyle.hpp>
30 : : #include <com/sun/star/drawing/LineStyle.hpp>
31 : : #include <com/sun/star/frame/XModel.hpp>
32 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 : : #include "basegfx/numeric/ftools.hxx"
34 : : #include "oox/core/xmlfilterbase.hxx"
35 : : #include "oox/drawingml/theme.hxx"
36 : :
37 : : namespace oox {
38 : : namespace drawingml {
39 : : namespace chart {
40 : :
41 : : // ============================================================================
42 : :
43 : : namespace cssc = ::com::sun::star::chart;
44 : :
45 : : using namespace ::com::sun::star::awt;
46 : : using namespace ::com::sun::star::chart2;
47 : : using namespace ::com::sun::star::drawing;
48 : : using namespace ::com::sun::star::frame;
49 : : using namespace ::com::sun::star::lang;
50 : : using namespace ::com::sun::star::uno;
51 : :
52 : : using ::oox::core::XmlFilterBase;
53 : : using ::rtl::OUString;
54 : :
55 : : // ============================================================================
56 : :
57 : : namespace {
58 : :
59 : 0 : struct TitleKey : public ::std::pair< ObjectType, ::std::pair< sal_Int32, sal_Int32 > >
60 : : {
61 : 0 : inline explicit TitleKey( ObjectType eObjType, sal_Int32 nMainIdx = -1, sal_Int32 nSubIdx = -1 )
62 : 0 : { first = eObjType; second.first = nMainIdx; second.second = nSubIdx; }
63 : : };
64 : :
65 : : // ----------------------------------------------------------------------------
66 : :
67 : : /** A helper structure to store all data related to title objects. Needed for
68 : : the conversion of manual title positions that needs the old Chart1 API.
69 : : */
70 [ # # ][ # # ]: 0 : struct TitleLayoutInfo
71 : : {
72 : : typedef Reference< XShape > (*GetShapeFunc)( const Reference< cssc::XChartDocument >& );
73 : :
74 : : Reference< XTitle > mxTitle; /// The API title object.
75 : : ModelRef< LayoutModel > mxLayout; /// The layout model, if existing.
76 : : GetShapeFunc mpGetShape; /// Helper function to receive the title shape.
77 : :
78 [ # # ]: 0 : inline explicit TitleLayoutInfo() : mpGetShape( 0 ) {}
79 : :
80 : : void convertTitlePos(
81 : : ConverterRoot& rRoot,
82 : : const Reference< cssc::XChartDocument >& rxChart1Doc );
83 : : };
84 : :
85 : 0 : void TitleLayoutInfo::convertTitlePos( ConverterRoot& rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc )
86 : : {
87 [ # # ][ # # ]: 0 : if( mxTitle.is() && mpGetShape ) try
[ # # ]
88 : : {
89 : : // try to get the title shape
90 [ # # ][ # # ]: 0 : Reference< XShape > xTitleShape( mpGetShape( rxChart1Doc ), UNO_SET_THROW );
91 : : // get title rotation angle, needed for correction of position of top-left edge
92 : 0 : double fAngle = 0.0;
93 [ # # ]: 0 : PropertySet aTitleProp( mxTitle );
94 [ # # ]: 0 : aTitleProp.getProperty( fAngle, PROP_TextRotation );
95 : : // convert the position
96 [ # # ]: 0 : LayoutModel& rLayout = mxLayout.getOrCreate();
97 [ # # ]: 0 : LayoutConverter aLayoutConv( rRoot, rLayout );
98 [ # # ][ # # ]: 0 : aLayoutConv.convertFromModel( xTitleShape, fAngle );
[ # # ][ # # ]
99 : : }
100 : 0 : catch( Exception& )
101 : : {
102 : : }
103 : 0 : }
104 : :
105 : : // ----------------------------------------------------------------------------
106 : :
107 : : /* The following local functions implement getting the XShape interface of all
108 : : supported title objects (chart and axes). This needs some effort due to the
109 : : design of the old Chart1 API used to access these objects. */
110 : :
111 : : /** A code fragment that returns a shape object from the passed shape supplier
112 : : using the specified interface function. Checks a boolean property first. */
113 : : #define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
114 : : PropertySet aPropSet( shape_supplier ); \
115 : : if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \
116 : : return shape_supplier->supplier_func(); \
117 : : return Reference< XShape >(); \
118 : :
119 : : /** Implements a function returning the drawing shape of an axis title, if
120 : : existing, using the specified API interface and its function. */
121 : : #define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
122 : : Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
123 : : { \
124 : : Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
125 : : OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
126 : : }
127 : :
128 : : /** Returns the drawing shape of the main title, if existing. */
129 : 0 : Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc )
130 : : {
131 [ # # ][ # # ]: 0 : OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
132 : : }
133 : :
134 [ # # ][ # # ]: 0 : OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
135 [ # # ][ # # ]: 0 : OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
136 [ # # ][ # # ]: 0 : OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
137 [ # # ][ # # ]: 0 : OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
138 [ # # ][ # # ]: 0 : OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
139 : :
140 : : #undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
141 : : #undef OOX_IMPLEMENT_GETTITLESHAPE
142 : :
143 : : } // namespace
144 : :
145 : : // ============================================================================
146 : :
147 : : struct ConverterData
148 : : {
149 : : typedef ::std::map< TitleKey, TitleLayoutInfo > TitleMap;
150 : :
151 : : ObjectFormatter maFormatter;
152 : : TitleMap maTitles;
153 : : XmlFilterBase& mrFilter;
154 : : ChartConverter& mrConverter;
155 : : Reference< XChartDocument > mxDoc;
156 : : Size maSize;
157 : :
158 : : explicit ConverterData(
159 : : XmlFilterBase& rFilter,
160 : : ChartConverter& rChartConverter,
161 : : const ChartSpaceModel& rChartModel,
162 : : const Reference< XChartDocument >& rxChartDoc,
163 : : const Size& rChartSize );
164 : : ~ConverterData();
165 : : };
166 : :
167 : : // ----------------------------------------------------------------------------
168 : :
169 : 0 : ConverterData::ConverterData(
170 : : XmlFilterBase& rFilter,
171 : : ChartConverter& rChartConverter,
172 : : const ChartSpaceModel& rChartModel,
173 : : const Reference< XChartDocument >& rxChartDoc,
174 : : const Size& rChartSize ) :
175 : : maFormatter( rFilter, rxChartDoc, rChartModel ),
176 : : mrFilter( rFilter ),
177 : : mrConverter( rChartConverter ),
178 : : mxDoc( rxChartDoc ),
179 [ # # ]: 0 : maSize( rChartSize )
180 : : {
181 : : OSL_ENSURE( mxDoc.is(), "ConverterData::ConverterData - missing chart document" );
182 : : // lock the model to suppress internal updates during conversion
183 : : try
184 : : {
185 [ # # ]: 0 : Reference< XModel > xModel( mxDoc, UNO_QUERY_THROW );
186 [ # # ][ # # ]: 0 : xModel->lockControllers();
[ # # ]
187 : : }
188 [ # # ]: 0 : catch( Exception& )
189 : : {
190 : : }
191 : :
192 : : // prepare conversion of title positions
193 [ # # ][ # # ]: 0 : maTitles[ TitleKey( OBJECTTYPE_CHARTTITLE ) ].mpGetShape = lclGetMainTitleShape;
194 [ # # ][ # # ]: 0 : maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetXAxisTitleShape;
195 [ # # ][ # # ]: 0 : maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetYAxisTitleShape;
196 [ # # ][ # # ]: 0 : maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Z_AXIS ) ].mpGetShape = lclGetZAxisTitleShape;
197 [ # # ][ # # ]: 0 : maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetSecXAxisTitleShape;
198 [ # # ][ # # ]: 0 : maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetSecYAxisTitleShape;
199 : 0 : }
200 : :
201 : 0 : ConverterData::~ConverterData()
202 : : {
203 : : // unlock the model
204 : : try
205 : : {
206 [ # # ]: 0 : Reference< XModel > xModel( mxDoc, UNO_QUERY_THROW );
207 [ # # ][ # # ]: 0 : xModel->unlockControllers();
[ # # ]
208 : : }
209 [ # # ]: 0 : catch( Exception& )
210 : : {
211 : : }
212 : 0 : }
213 : :
214 : : // ============================================================================
215 : :
216 : 0 : ConverterRoot::ConverterRoot(
217 : : XmlFilterBase& rFilter,
218 : : ChartConverter& rChartConverter,
219 : : const ChartSpaceModel& rChartModel,
220 : : const Reference< XChartDocument >& rxChartDoc,
221 : : const Size& rChartSize ) :
222 [ # # ]: 0 : mxData( new ConverterData( rFilter, rChartConverter, rChartModel, rxChartDoc, rChartSize ) )
223 : : {
224 : 0 : }
225 : :
226 : 0 : ConverterRoot::~ConverterRoot()
227 : : {
228 [ # # ]: 0 : }
229 : :
230 : 0 : Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const
231 : : {
232 : 0 : Reference< XInterface > xInt;
233 : : try
234 : : {
235 [ # # ][ # # ]: 0 : xInt = mxData->mrFilter.getServiceFactory()->createInstance( rServiceName );
[ # # ][ # # ]
[ # # ]
236 : : }
237 [ # # ]: 0 : catch( Exception& )
238 : : {
239 : : }
240 : : OSL_ENSURE( xInt.is(), "ConverterRoot::createInstance - cannot create instance" );
241 : 0 : return xInt;
242 : : }
243 : :
244 : 0 : XmlFilterBase& ConverterRoot::getFilter() const
245 : : {
246 : 0 : return mxData->mrFilter;
247 : : }
248 : :
249 : 0 : ChartConverter* ConverterRoot::getChartConverter() const
250 : : {
251 : 0 : return &mxData->mrConverter;
252 : : }
253 : :
254 : 0 : Reference< XChartDocument > ConverterRoot::getChartDocument() const
255 : : {
256 : 0 : return mxData->mxDoc;
257 : : }
258 : :
259 : 0 : const Size& ConverterRoot::getChartSize() const
260 : : {
261 : 0 : return mxData->maSize;
262 : : }
263 : :
264 : 0 : ObjectFormatter& ConverterRoot::getFormatter() const
265 : : {
266 : 0 : return mxData->maFormatter;
267 : : }
268 : :
269 : 0 : void ConverterRoot::registerTitleLayout( const Reference< XTitle >& rxTitle,
270 : : const ModelRef< LayoutModel >& rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx )
271 : : {
272 : : OSL_ENSURE( rxTitle.is(), "ConverterRoot::registerTitleLayout - missing title object" );
273 [ # # ]: 0 : TitleLayoutInfo& rTitleInfo = mxData->maTitles[ TitleKey( eObjType, nMainIdx, nSubIdx ) ];
274 : : OSL_ENSURE( rTitleInfo.mpGetShape, "ConverterRoot::registerTitleLayout - invalid title key" );
275 : 0 : rTitleInfo.mxTitle = rxTitle;
276 : 0 : rTitleInfo.mxLayout = rxLayout;
277 : 0 : }
278 : :
279 : 0 : void ConverterRoot::convertTitlePositions()
280 : : {
281 : : try
282 : : {
283 [ # # ]: 0 : Reference< cssc::XChartDocument > xChart1Doc( mxData->mxDoc, UNO_QUERY_THROW );
284 [ # # ]: 0 : for( ConverterData::TitleMap::iterator aIt = mxData->maTitles.begin(), aEnd = mxData->maTitles.end(); aIt != aEnd; ++aIt )
285 [ # # ][ # # ]: 0 : aIt->second.convertTitlePos( *this, xChart1Doc );
286 : : }
287 : 0 : catch( Exception& )
288 : : {
289 : : }
290 : 0 : }
291 : :
292 : : // ============================================================================
293 : :
294 : : namespace {
295 : :
296 : : /** Returns a position value in the chart area in 1/100 mm. */
297 : 0 : sal_Int32 lclCalcPosition( sal_Int32 nChartSize, double fPos, sal_Int32 nPosMode )
298 : : {
299 [ # # # ]: 0 : switch( nPosMode )
300 : : {
301 : : case XML_edge: // absolute start position as factor of chart size
302 : 0 : return getLimitedValue< sal_Int32, double >( nChartSize * fPos + 0.5, 0, nChartSize );
303 : : case XML_factor: // position relative to object default position
304 : : OSL_FAIL( "lclCalcPosition - relative positioning not supported" );
305 : 0 : return -1;
306 : : };
307 : :
308 : : OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
309 : 0 : return -1;
310 : : }
311 : :
312 : : /** Returns a size value in the chart area in 1/100 mm. */
313 : 0 : sal_Int32 lclCalcSize( sal_Int32 nPos, sal_Int32 nChartSize, double fSize, sal_Int32 nSizeMode )
314 : : {
315 : 0 : sal_Int32 nValue = getLimitedValue< sal_Int32, double >( nChartSize * fSize + 0.5, 0, nChartSize );
316 [ # # # ]: 0 : switch( nSizeMode )
317 : : {
318 : : case XML_factor: // passed value is width/height
319 : 0 : return nValue;
320 : : case XML_edge: // passed value is right/bottom position
321 : 0 : return nValue - nPos + 1;
322 : : };
323 : :
324 : : OSL_FAIL( "lclCalcSize - unknown size mode" );
325 : 0 : return -1;
326 : : }
327 : :
328 : : /** Returns a relative size value in the chart area. */
329 : 0 : double lclCalcRelSize( double fPos, double fSize, sal_Int32 nSizeMode )
330 : : {
331 [ # # # ]: 0 : switch( nSizeMode )
332 : : {
333 : : case XML_factor: // passed value is width/height
334 : 0 : break;
335 : : case XML_edge: // passed value is right/bottom position
336 : 0 : fSize -= fPos;
337 : 0 : break;
338 : : default:
339 : : OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
340 : 0 : fSize = 0.0;
341 : : };
342 : 0 : return getLimitedValue< double, double >( fSize, 0.0, 1.0 - fPos );
343 : : }
344 : :
345 : : } // namespace
346 : :
347 : : // ----------------------------------------------------------------------------
348 : :
349 : 0 : LayoutConverter::LayoutConverter( const ConverterRoot& rParent, LayoutModel& rModel ) :
350 : 0 : ConverterBase< LayoutModel >( rParent, rModel )
351 : : {
352 : 0 : }
353 : :
354 : 0 : LayoutConverter::~LayoutConverter()
355 : : {
356 [ # # ]: 0 : }
357 : :
358 : 0 : bool LayoutConverter::calcAbsRectangle( Rectangle& orRect ) const
359 : : {
360 [ # # ]: 0 : if( !mrModel.mbAutoLayout )
361 : : {
362 : 0 : const Size& rChartSize = getChartSize();
363 : 0 : orRect.X = lclCalcPosition( rChartSize.Width, mrModel.mfX, mrModel.mnXMode );
364 : 0 : orRect.Y = lclCalcPosition( rChartSize.Height, mrModel.mfY, mrModel.mnYMode );
365 [ # # ][ # # ]: 0 : if( (orRect.X >= 0) && (orRect.Y >= 0) )
366 : : {
367 : 0 : orRect.Width = lclCalcSize( orRect.X, rChartSize.Width, mrModel.mfW, mrModel.mnWMode );
368 : 0 : orRect.Height = lclCalcSize( orRect.Y, rChartSize.Height, mrModel.mfH, mrModel.mnHMode );
369 [ # # ][ # # ]: 0 : return (orRect.Width > 0) && (orRect.Height > 0);
370 : : }
371 : : }
372 : 0 : return false;
373 : : }
374 : :
375 : 0 : bool LayoutConverter::convertFromModel( PropertySet& rPropSet )
376 : : {
377 [ # # ][ # # ]: 0 : if( !mrModel.mbAutoLayout &&
[ # # ][ # # ]
[ # # ]
378 : : (mrModel.mnXMode == XML_edge) && (mrModel.mfX >= 0.0) &&
379 : : (mrModel.mnYMode == XML_edge) && (mrModel.mfY >= 0.0) )
380 : : {
381 : : RelativePosition aPos(
382 [ # # ]: 0 : getLimitedValue< double, double >( mrModel.mfX, 0.0, 1.0 ),
383 [ # # ]: 0 : getLimitedValue< double, double >( mrModel.mfY, 0.0, 1.0 ),
384 : 0 : Alignment_TOP_LEFT );
385 [ # # ]: 0 : rPropSet.setProperty( PROP_RelativePosition, aPos );
386 : :
387 : : RelativeSize aSize(
388 [ # # ]: 0 : lclCalcRelSize( aPos.Primary, mrModel.mfW, mrModel.mnWMode ),
389 [ # # ]: 0 : lclCalcRelSize( aPos.Secondary, mrModel.mfH, mrModel.mnHMode ) );
390 [ # # ][ # # ]: 0 : if( (aSize.Primary > 0.0) && (aSize.Secondary > 0.0) )
391 : : {
392 [ # # ]: 0 : rPropSet.setProperty( PROP_RelativeSize, aSize );
393 : 0 : return true;
394 : : }
395 : : }
396 : 0 : return false;
397 : : }
398 : :
399 : 0 : bool LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle )
400 : : {
401 [ # # ]: 0 : if( !mrModel.mbAutoLayout )
402 : : {
403 [ # # ]: 0 : const Size& rChartSize = getChartSize();
404 : : Point aShapePos(
405 [ # # ]: 0 : lclCalcPosition( rChartSize.Width, mrModel.mfX, mrModel.mnXMode ),
406 [ # # ]: 0 : lclCalcPosition( rChartSize.Height, mrModel.mfY, mrModel.mnYMode ) );
407 [ # # ][ # # ]: 0 : if( (aShapePos.X >= 0) && (aShapePos.Y >= 0) )
408 : : {
409 : : // the call to XShape.getSize() may recalc the chart view
410 [ # # ][ # # ]: 0 : Size aShapeSize = rxShape->getSize();
411 : : // rotated shapes need special handling...
412 : 0 : double fSin = fabs( sin( fRotationAngle * F_PI180 ) );
413 : : // add part of height to X direction, if title is rotated down
414 [ # # ]: 0 : if( fRotationAngle > 180.0 )
415 : 0 : aShapePos.X += static_cast< sal_Int32 >( fSin * aShapeSize.Height + 0.5 );
416 : : // add part of width to Y direction, if title is rotated up
417 [ # # ]: 0 : else if( fRotationAngle > 0.0 )
418 : 0 : aShapePos.Y += static_cast< sal_Int32 >( fSin * aShapeSize.Width + 0.5 );
419 : : // set the resulting position at the shape
420 [ # # ][ # # ]: 0 : rxShape->setPosition( aShapePos );
421 : 0 : return true;
422 : : }
423 : : }
424 : 0 : return false;
425 : : }
426 : :
427 : : // ============================================================================
428 : :
429 : : } // namespace chart
430 : : } // namespace drawingml
431 [ + - ][ + - ]: 285 : } // namespace oox
432 : :
433 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|