Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / oox / source / drawingml / chart / converterbase.cxx
blob0b6b876a11a0deafd296483906dcf404859b8bcb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawingml/chart/converterbase.hxx>
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/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/uno/XComponentContext.hpp>
34 #include <osl/diagnose.h>
35 #include <basegfx/numeric/ftools.hxx>
36 #include <oox/core/xmlfilterbase.hxx>
37 #include <oox/drawingml/theme.hxx>
38 #include <oox/token/properties.hxx>
39 #include <oox/token/tokens.hxx>
40 #include <comphelper/processfactory.hxx>
43 namespace oox {
44 namespace drawingml {
45 namespace chart {
47 namespace cssc = ::com::sun::star::chart;
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::chart2;
51 using namespace ::com::sun::star::drawing;
52 using namespace ::com::sun::star::lang;
53 using namespace ::com::sun::star::uno;
55 using ::oox::core::XmlFilterBase;
57 namespace {
59 struct TitleKey : public ::std::pair< ObjectType, ::std::pair< sal_Int32, sal_Int32 > >
61 explicit TitleKey( ObjectType eObjType, sal_Int32 nMainIdx = -1, sal_Int32 nSubIdx = -1 )
62 { first = eObjType; second.first = nMainIdx; second.second = nSubIdx; }
65 /** A helper structure to store all data related to title objects. Needed for
66 the conversion of manual title positions that needs the old Chart1 API.
68 struct TitleLayoutInfo
70 typedef Reference< XShape > (*GetShapeFunc)( const Reference< cssc::XChartDocument >& );
72 Reference< XTitle > mxTitle; /// The API title object.
73 ModelRef< LayoutModel > mxLayout; /// The layout model, if existing.
74 GetShapeFunc mpGetShape; /// Helper function to receive the title shape.
76 explicit TitleLayoutInfo() : mpGetShape( nullptr ) {}
78 void convertTitlePos(
79 ConverterRoot const & rRoot,
80 const Reference< cssc::XChartDocument >& rxChart1Doc );
83 void TitleLayoutInfo::convertTitlePos( ConverterRoot const & rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc )
85 if( mxTitle.is() && mpGetShape ) try
87 // try to get the title shape
88 Reference< XShape > xTitleShape = mpGetShape( rxChart1Doc );
89 // get title rotation angle, needed for correction of position of top-left edge
90 double fAngle = 0.0;
91 PropertySet aTitleProp( mxTitle );
92 aTitleProp.getProperty( fAngle, PROP_TextRotation );
93 // convert the position
94 LayoutModel& rLayout = mxLayout.getOrCreate();
95 LayoutConverter aLayoutConv( rRoot, rLayout );
96 aLayoutConv.convertFromModel( xTitleShape, fAngle );
98 catch( Exception& )
103 /* The following local functions implement getting the XShape interface of all
104 supported title objects (chart and axes). This needs some effort due to the
105 design of the old Chart1 API used to access these objects. */
107 /** A code fragment that returns a shape object from the passed shape supplier
108 using the specified interface function. Checks a boolean property first. */
109 #define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
110 PropertySet aPropSet( shape_supplier ); \
111 if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \
112 return shape_supplier->supplier_func(); \
113 return Reference< XShape >(); \
115 /** Implements a function returning the drawing shape of an axis title, if
116 existing, using the specified API interface and its function. */
117 #define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
118 Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
120 Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
121 OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
124 /** Returns the drawing shape of the main title, if existing. */
125 Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc )
127 OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle )
130 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle )
131 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle )
132 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle )
133 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle )
134 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle )
136 #undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
137 #undef OOX_IMPLEMENT_GETTITLESHAPE
139 } // namespace
141 struct ConverterData
143 typedef ::std::map< TitleKey, TitleLayoutInfo > TitleMap;
145 ObjectFormatter maFormatter;
146 TitleMap maTitles;
147 XmlFilterBase& mrFilter;
148 ChartConverter& mrConverter;
149 Reference< XChartDocument > mxDoc;
150 awt::Size const maSize;
152 explicit ConverterData(
153 XmlFilterBase& rFilter,
154 ChartConverter& rChartConverter,
155 const ChartSpaceModel& rChartModel,
156 const Reference< XChartDocument >& rxChartDoc,
157 const awt::Size& rChartSize );
158 ~ConverterData();
161 ConverterData::ConverterData(
162 XmlFilterBase& rFilter,
163 ChartConverter& rChartConverter,
164 const ChartSpaceModel& rChartModel,
165 const Reference< XChartDocument >& rxChartDoc,
166 const awt::Size& rChartSize ) :
167 maFormatter( rFilter, rxChartDoc, rChartModel ),
168 mrFilter( rFilter ),
169 mrConverter( rChartConverter ),
170 mxDoc( rxChartDoc ),
171 maSize( rChartSize )
173 OSL_ENSURE( mxDoc.is(), "ConverterData::ConverterData - missing chart document" );
174 // lock the model to suppress internal updates during conversion
177 mxDoc->lockControllers();
179 catch( Exception& )
183 // prepare conversion of title positions
184 maTitles[ TitleKey( OBJECTTYPE_CHARTTITLE ) ].mpGetShape = lclGetMainTitleShape;
185 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetXAxisTitleShape;
186 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetYAxisTitleShape;
187 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Z_AXIS ) ].mpGetShape = lclGetZAxisTitleShape;
188 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetSecXAxisTitleShape;
189 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetSecYAxisTitleShape;
192 ConverterData::~ConverterData()
194 // unlock the model
197 mxDoc->unlockControllers();
199 catch( Exception& )
204 ConverterRoot::ConverterRoot(
205 XmlFilterBase& rFilter,
206 ChartConverter& rChartConverter,
207 const ChartSpaceModel& rChartModel,
208 const Reference< XChartDocument >& rxChartDoc,
209 const awt::Size& rChartSize ) :
210 mxData( new ConverterData( rFilter, rChartConverter, rChartModel, rxChartDoc, rChartSize ) )
214 ConverterRoot::~ConverterRoot()
218 Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const
220 Reference< XInterface > xInt;
223 Reference<XMultiServiceFactory> xMSF(getComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW);
225 xInt = xMSF->createInstance( rServiceName );
227 catch( Exception& )
230 OSL_ENSURE( xInt.is(), "ConverterRoot::createInstance - cannot create instance" );
231 return xInt;
234 Reference< XComponentContext > const & ConverterRoot::getComponentContext() const
236 return mxData->mrFilter.getComponentContext();
239 XmlFilterBase& ConverterRoot::getFilter() const
241 return mxData->mrFilter;
244 ChartConverter& ConverterRoot::getChartConverter() const
246 return mxData->mrConverter;
249 Reference< XChartDocument > const & ConverterRoot::getChartDocument() const
251 return mxData->mxDoc;
254 const awt::Size& ConverterRoot::getChartSize() const
256 return mxData->maSize;
259 ObjectFormatter& ConverterRoot::getFormatter() const
261 return mxData->maFormatter;
264 void ConverterRoot::registerTitleLayout( const Reference< XTitle >& rxTitle,
265 const ModelRef< LayoutModel >& rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx )
267 OSL_ENSURE( rxTitle.is(), "ConverterRoot::registerTitleLayout - missing title object" );
268 TitleLayoutInfo& rTitleInfo = mxData->maTitles[ TitleKey( eObjType, nMainIdx, nSubIdx ) ];
269 OSL_ENSURE( rTitleInfo.mpGetShape, "ConverterRoot::registerTitleLayout - invalid title key" );
270 rTitleInfo.mxTitle = rxTitle;
271 rTitleInfo.mxLayout = rxLayout;
274 void ConverterRoot::convertTitlePositions()
278 Reference< cssc::XChartDocument > xChart1Doc( mxData->mxDoc, UNO_QUERY_THROW );
279 for (auto & title : mxData->maTitles)
280 title.second.convertTitlePos( *this, xChart1Doc );
282 catch( Exception& )
287 namespace {
289 /** Returns a position value in the chart area in 1/100 mm. */
290 sal_Int32 lclCalcPosition( sal_Int32 nChartSize, double fPos, sal_Int32 nPosMode )
292 switch( nPosMode )
294 case XML_edge: // absolute start position as factor of chart size
295 return getLimitedValue< sal_Int32, double >( nChartSize * fPos + 0.5, 0, nChartSize );
296 case XML_factor: // position relative to object default position
297 OSL_FAIL( "lclCalcPosition - relative positioning not supported" );
298 return -1;
301 OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
302 return -1;
305 /** Returns a size value in the chart area in 1/100 mm. */
306 sal_Int32 lclCalcSize( sal_Int32 nPos, sal_Int32 nChartSize, double fSize, sal_Int32 nSizeMode )
308 sal_Int32 nValue = getLimitedValue< sal_Int32, double >( nChartSize * fSize + 0.5, 0, nChartSize );
309 switch( nSizeMode )
311 case XML_factor: // passed value is width/height
312 return nValue;
313 case XML_edge: // passed value is right/bottom position
314 return nValue - nPos + 1;
317 OSL_FAIL( "lclCalcSize - unknown size mode" );
318 return -1;
321 /** Returns a relative size value in the chart area. */
322 double lclCalcRelSize( double fPos, double fSize, sal_Int32 nSizeMode )
324 switch( nSizeMode )
326 case XML_factor: // passed value is width/height
327 break;
328 case XML_edge: // passed value is right/bottom position
329 fSize -= fPos;
330 break;
331 default:
332 OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
333 fSize = 0.0;
335 return getLimitedValue< double, double >( fSize, 0.0, 1.0 - fPos );
338 } // namespace
340 LayoutConverter::LayoutConverter( const ConverterRoot& rParent, LayoutModel& rModel ) :
341 ConverterBase< LayoutModel >( rParent, rModel )
345 LayoutConverter::~LayoutConverter()
349 bool LayoutConverter::calcAbsRectangle( awt::Rectangle& orRect ) const
351 if( !mrModel.mbAutoLayout )
353 awt::Size aChartSize = getChartSize();
354 if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
356 aChartSize = getDefaultPageSize();
358 orRect.X = lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode );
359 orRect.Y = lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode );
360 if( (orRect.X >= 0) && (orRect.Y >= 0) )
362 orRect.Width = lclCalcSize( orRect.X, aChartSize.Width, mrModel.mfW, mrModel.mnWMode );
363 orRect.Height = lclCalcSize( orRect.Y, aChartSize.Height, mrModel.mfH, mrModel.mnHMode );
364 return (orRect.Width > 0) && (orRect.Height > 0);
367 return false;
370 bool LayoutConverter::convertFromModel( PropertySet& rPropSet )
372 if( !mrModel.mbAutoLayout &&
373 (mrModel.mnXMode == XML_edge) && (mrModel.mfX >= 0.0) &&
374 (mrModel.mnYMode == XML_edge) && (mrModel.mfY >= 0.0) )
376 RelativePosition aPos(
377 getLimitedValue< double, double >( mrModel.mfX, 0.0, 1.0 ),
378 getLimitedValue< double, double >( mrModel.mfY, 0.0, 1.0 ),
379 Alignment_TOP_LEFT );
380 rPropSet.setProperty( PROP_RelativePosition, aPos );
382 RelativeSize aSize(
383 lclCalcRelSize( aPos.Primary, mrModel.mfW, mrModel.mnWMode ),
384 lclCalcRelSize( aPos.Secondary, mrModel.mfH, mrModel.mnHMode ) );
385 if( (aSize.Primary > 0.0) && (aSize.Secondary > 0.0) )
387 rPropSet.setProperty( PROP_RelativeSize, aSize );
388 return true;
391 return false;
394 void LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle )
396 if( !mrModel.mbAutoLayout )
398 awt::Size aChartSize = getChartSize();
399 if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
401 aChartSize = getDefaultPageSize();
403 awt::Point aShapePos(
404 lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode ),
405 lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode ) );
406 if( (aShapePos.X >= 0) && (aShapePos.Y >= 0) )
408 bool bPropSet = false;
409 // the call to XShape.getSize() may recalc the chart view
410 awt::Size aShapeSize = rxShape->getSize();
411 // rotated shapes need special handling...
412 if( aShapeSize.Height > 0 || aShapeSize.Width > 0 )
414 double fSin = fabs(sin(basegfx::deg2rad(fRotationAngle)));
415 // add part of height to X direction, if title is rotated down
416 if( fRotationAngle > 180.0 )
417 aShapePos.X += static_cast<sal_Int32>(fSin * aShapeSize.Height + 0.5);
418 // add part of width to Y direction, if title is rotated up
419 else if( fRotationAngle > 0.0 )
420 aShapePos.Y += static_cast<sal_Int32>(fSin * aShapeSize.Width + 0.5);
422 else if( fRotationAngle == 90.0 || fRotationAngle == 270.0 )
424 PropertySet aShapeProp( rxShape );
425 RelativePosition aPos(
426 getLimitedValue< double, double >(mrModel.mfX, 0.0, 1.0),
427 getLimitedValue< double, double >(mrModel.mfY, 0.0, 1.0),
428 fRotationAngle == 90.0 ? Alignment_TOP_RIGHT : Alignment_BOTTOM_LEFT );
429 // set the resulting position at the shape
430 if( aShapeProp.setProperty(PROP_RelativePosition, aPos) )
431 bPropSet = true;
433 // set the resulting position at the shape
434 if( !bPropSet )
435 rxShape->setPosition( aShapePos );
440 } // namespace chart
441 } // namespace drawingml
442 } // namespace oox
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */