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