use insert function instead of for loop
[LibreOffice.git] / oox / source / drawingml / chart / converterbase.cxx
blobd7130ec9795dac5ff2667a42b5a1002d7a44e08c
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/chart2/XTitle.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/uno/XComponentContext.hpp>
33 #include <osl/diagnose.h>
34 #include <sal/log.hxx>
35 #include <basegfx/numeric/ftools.hxx>
36 #include <oox/core/xmlfilterbase.hxx>
37 #include <oox/helper/helper.hxx>
38 #include <oox/token/properties.hxx>
39 #include <oox/token/tokens.hxx>
42 namespace oox::drawingml::chart {
44 namespace cssc = ::com::sun::star::chart;
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::chart2;
48 using namespace ::com::sun::star::drawing;
49 using namespace ::com::sun::star::lang;
50 using namespace ::com::sun::star::uno;
52 using ::oox::core::XmlFilterBase;
54 namespace {
56 struct TitleKey : public ::std::pair< ObjectType, ::std::pair< sal_Int32, sal_Int32 > >
58 explicit TitleKey( ObjectType eObjType, sal_Int32 nMainIdx = -1, sal_Int32 nSubIdx = -1 )
59 { first = eObjType; second.first = nMainIdx; second.second = nSubIdx; }
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.
65 struct TitleLayoutInfo
67 typedef Reference< XShape > (*GetShapeFunc)( const Reference< cssc::XChartDocument >& );
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.
73 explicit TitleLayoutInfo() : mpGetShape( nullptr ) {}
75 void convertTitlePos(
76 ConverterRoot const & rRoot,
77 const Reference< cssc::XChartDocument >& rxChart1Doc );
80 void TitleLayoutInfo::convertTitlePos( ConverterRoot const & rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc )
82 if( !(mxTitle.is() && mpGetShape) )
83 return;
85 try
87 // try to get the title shape
88 Reference< XShape > xTitleShape = mpGetShape( rxChart1Doc );
89 if (!xTitleShape)
91 SAL_WARN("oox", "failed to get a TitleShape");
92 return;
94 // get title rotation angle, needed for correction of position of top-left edge
95 double fAngle = 0.0;
96 PropertySet aTitleProp( mxTitle );
97 aTitleProp.getProperty( fAngle, PROP_TextRotation );
98 // convert the position
99 LayoutModel& rLayout = mxLayout.getOrCreate();
100 LayoutConverter aLayoutConv( rRoot, rLayout );
101 aLayoutConv.convertFromModel( xTitleShape, fAngle );
103 catch( Exception& )
108 /* The following local functions implement getting the XShape interface of all
109 supported title objects (chart and axes). This needs some effort due to the
110 design of the old Chart1 API used to access these objects. */
112 /** A code fragment that returns a shape object from the passed shape supplier
113 using the specified interface function. Checks a boolean property first. */
114 #define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
115 PropertySet aPropSet( shape_supplier ); \
116 if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \
117 return shape_supplier->supplier_func(); \
118 return Reference< XShape >(); \
120 /** Implements a function returning the drawing shape of an axis title, if
121 existing, using the specified API interface and its function. */
122 #define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
123 Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
125 Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
126 OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
129 /** Returns the drawing shape of the main title, if existing. */
130 Reference< XShape > lclGetMainTitleShape( const Reference< cssc::XChartDocument >& rxChart1Doc )
132 OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc, getTitle, HasMainTitle )
135 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape, XAxisXSupplier, getXAxisTitle, HasXAxisTitle )
136 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape, XAxisYSupplier, getYAxisTitle, HasYAxisTitle )
137 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape, XAxisZSupplier, getZAxisTitle, HasZAxisTitle )
138 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape, XSecondAxisTitleSupplier, getSecondXAxisTitle, HasSecondaryXAxisTitle )
139 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape, XSecondAxisTitleSupplier, getSecondYAxisTitle, HasSecondaryYAxisTitle )
141 #undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
142 #undef OOX_IMPLEMENT_GETTITLESHAPE
144 } // namespace
146 struct ConverterData
148 ObjectFormatter maFormatter;
149 std::map< TitleKey, TitleLayoutInfo >
150 maTitles;
151 XmlFilterBase& mrFilter;
152 ChartConverter& mrConverter;
153 Reference< XChartDocument > mxDoc;
154 awt::Size maSize;
156 explicit ConverterData(
157 XmlFilterBase& rFilter,
158 ChartConverter& rChartConverter,
159 const ChartSpaceModel& rChartModel,
160 const Reference< XChartDocument >& rxChartDoc,
161 const awt::Size& rChartSize );
162 ~ConverterData();
165 ConverterData::ConverterData(
166 XmlFilterBase& rFilter,
167 ChartConverter& rChartConverter,
168 const ChartSpaceModel& rChartModel,
169 const Reference< XChartDocument >& rxChartDoc,
170 const awt::Size& rChartSize ) :
171 maFormatter( rFilter, rxChartDoc, rChartModel ),
172 mrFilter( rFilter ),
173 mrConverter( rChartConverter ),
174 mxDoc( rxChartDoc ),
175 maSize( rChartSize )
177 OSL_ENSURE( mxDoc.is(), "ConverterData::ConverterData - missing chart document" );
178 // lock the model to suppress internal updates during conversion
181 mxDoc->lockControllers();
183 catch( Exception& )
187 // prepare conversion of title positions
188 maTitles[ TitleKey( OBJECTTYPE_CHARTTITLE ) ].mpGetShape = lclGetMainTitleShape;
189 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetXAxisTitleShape;
190 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetYAxisTitleShape;
191 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_PRIM_AXESSET, API_Z_AXIS ) ].mpGetShape = lclGetZAxisTitleShape;
192 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_X_AXIS ) ].mpGetShape = lclGetSecXAxisTitleShape;
193 maTitles[ TitleKey( OBJECTTYPE_AXISTITLE, API_SECN_AXESSET, API_Y_AXIS ) ].mpGetShape = lclGetSecYAxisTitleShape;
196 ConverterData::~ConverterData()
198 // unlock the model
201 mxDoc->unlockControllers();
203 catch( Exception& )
208 ConverterRoot::ConverterRoot(
209 XmlFilterBase& rFilter,
210 ChartConverter& rChartConverter,
211 const ChartSpaceModel& rChartModel,
212 const Reference< XChartDocument >& rxChartDoc,
213 const awt::Size& rChartSize ) :
214 mxData( std::make_shared<ConverterData>( rFilter, rChartConverter, rChartModel, rxChartDoc, rChartSize ) )
218 ConverterRoot::~ConverterRoot()
222 Reference< XInterface > ConverterRoot::createInstance( const OUString& rServiceName ) const
224 Reference< XInterface > xInt;
227 Reference<XMultiServiceFactory> xMSF(getComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW);
229 xInt = xMSF->createInstance( rServiceName );
231 catch( Exception& )
234 OSL_ENSURE( xInt.is(), "ConverterRoot::createInstance - cannot create instance" );
235 return xInt;
238 Reference< XComponentContext > const & ConverterRoot::getComponentContext() const
240 return mxData->mrFilter.getComponentContext();
243 XmlFilterBase& ConverterRoot::getFilter() const
245 return mxData->mrFilter;
248 ChartConverter& ConverterRoot::getChartConverter() const
250 return mxData->mrConverter;
253 Reference< XChartDocument > const & ConverterRoot::getChartDocument() const
255 return mxData->mxDoc;
258 const awt::Size& ConverterRoot::getChartSize() const
260 return mxData->maSize;
263 ObjectFormatter& ConverterRoot::getFormatter() const
265 return mxData->maFormatter;
268 void ConverterRoot::registerTitleLayout( const Reference< XTitle >& rxTitle,
269 const ModelRef< LayoutModel >& rxLayout, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx )
271 OSL_ENSURE( rxTitle.is(), "ConverterRoot::registerTitleLayout - missing title object" );
272 TitleLayoutInfo& rTitleInfo = mxData->maTitles[ TitleKey( eObjType, nMainIdx, nSubIdx ) ];
273 OSL_ENSURE( rTitleInfo.mpGetShape, "ConverterRoot::registerTitleLayout - invalid title key" );
274 rTitleInfo.mxTitle = rxTitle;
275 rTitleInfo.mxLayout = rxLayout;
278 void ConverterRoot::convertTitlePositions()
282 Reference< cssc::XChartDocument > xChart1Doc( mxData->mxDoc, UNO_QUERY_THROW );
283 for (auto & title : mxData->maTitles)
284 title.second.convertTitlePos( *this, xChart1Doc );
286 catch( Exception& )
291 namespace {
293 /** Returns a position value in the chart area in 1/100 mm. */
294 sal_Int32 lclCalcPosition( sal_Int32 nChartSize, double fPos, sal_Int32 nPosMode )
296 switch( nPosMode )
298 case XML_edge: // absolute start position as factor of chart size
299 return getLimitedValue< sal_Int32, double >( nChartSize * fPos + 0.5, 0, nChartSize );
300 case XML_factor: // position relative to object default position
301 OSL_FAIL( "lclCalcPosition - relative positioning not supported" );
302 return -1;
305 OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
306 return -1;
309 /** Returns a size value in the chart area in 1/100 mm. */
310 sal_Int32 lclCalcSize( sal_Int32 nPos, sal_Int32 nChartSize, double fSize, sal_Int32 nSizeMode )
312 sal_Int32 nValue = getLimitedValue< sal_Int32, double >( nChartSize * fSize + 0.5, 0, nChartSize );
313 switch( nSizeMode )
315 case XML_factor: // passed value is width/height
316 return nValue;
317 case XML_edge: // passed value is right/bottom position
318 return nValue - nPos + 1;
321 OSL_FAIL( "lclCalcSize - unknown size mode" );
322 return -1;
325 /** Returns a relative size value in the chart area. */
326 double lclCalcRelSize( double fPos, double fSize, sal_Int32 nSizeMode )
328 switch( nSizeMode )
330 case XML_factor: // passed value is width/height
331 break;
332 case XML_edge: // passed value is right/bottom position
333 fSize -= fPos;
334 break;
335 default:
336 OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
337 fSize = 0.0;
339 return getLimitedValue< double, double >( fSize, 0.0, 1.0 - fPos );
342 } // namespace
344 LayoutConverter::LayoutConverter( const ConverterRoot& rParent, LayoutModel& rModel ) :
345 ConverterBase< LayoutModel >( rParent, rModel )
349 LayoutConverter::~LayoutConverter()
353 bool LayoutConverter::calcAbsRectangle( awt::Rectangle& orRect ) const
355 if( !mrModel.mbAutoLayout )
357 awt::Size aChartSize = getChartSize();
358 if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
360 aChartSize = getDefaultPageSize();
362 orRect.X = lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode );
363 orRect.Y = lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode );
364 if( (orRect.X >= 0) && (orRect.Y >= 0) )
366 orRect.Width = lclCalcSize( orRect.X, aChartSize.Width, mrModel.mfW, mrModel.mnWMode );
367 orRect.Height = lclCalcSize( orRect.Y, aChartSize.Height, mrModel.mfH, mrModel.mnHMode );
368 return (orRect.Width > 0) && (orRect.Height > 0);
371 return false;
374 bool LayoutConverter::convertFromModel( PropertySet& rPropSet )
376 if( !mrModel.mbAutoLayout &&
377 (mrModel.mnXMode == XML_edge) && (mrModel.mfX >= 0.0) &&
378 (mrModel.mnYMode == XML_edge) && (mrModel.mfY >= 0.0) )
380 RelativePosition aPos(
381 getLimitedValue< double, double >( mrModel.mfX, 0.0, 1.0 ),
382 getLimitedValue< double, double >( mrModel.mfY, 0.0, 1.0 ),
383 Alignment_TOP_LEFT );
384 rPropSet.setProperty( PROP_RelativePosition, aPos );
386 RelativeSize aSize(
387 lclCalcRelSize( aPos.Primary, mrModel.mfW, mrModel.mnWMode ),
388 lclCalcRelSize( aPos.Secondary, mrModel.mfH, mrModel.mnHMode ) );
389 if( (aSize.Primary > 0.0) && (aSize.Secondary > 0.0) )
391 rPropSet.setProperty( PROP_RelativeSize, aSize );
392 return true;
395 return false;
398 void LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle )
400 if( mrModel.mbAutoLayout )
401 return;
403 awt::Size aChartSize = getChartSize();
404 if( aChartSize.Width <= 0 || aChartSize.Height <= 0 )
406 aChartSize = getDefaultPageSize();
408 awt::Point aShapePos(
409 lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode ),
410 lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode ) );
411 if( (aShapePos.X < 0) || (aShapePos.Y < 0) )
412 return;
414 bool bPropSet = false;
415 // the call to XShape.getSize() may recalc the chart view
416 awt::Size aShapeSize = rxShape->getSize();
417 // rotated shapes need special handling...
418 if( aShapeSize.Height > 0 || aShapeSize.Width > 0 )
420 double fSin = fabs(sin(basegfx::deg2rad(fRotationAngle)));
421 // add part of height to X direction, if title is rotated down
422 if( fRotationAngle > 180.0 )
423 aShapePos.X += static_cast<sal_Int32>(fSin * aShapeSize.Height + 0.5);
424 // add part of width to Y direction, if title is rotated up
425 else if( fRotationAngle > 0.0 )
426 aShapePos.Y += static_cast<sal_Int32>(fSin * aShapeSize.Width + 0.5);
428 else if( fRotationAngle == 90.0 || fRotationAngle == 270.0 )
430 PropertySet aShapeProp( rxShape );
431 RelativePosition aPos(
432 getLimitedValue< double, double >(mrModel.mfX, 0.0, 1.0),
433 getLimitedValue< double, double >(mrModel.mfY, 0.0, 1.0),
434 fRotationAngle == 90.0 ? Alignment_TOP_RIGHT : Alignment_BOTTOM_LEFT );
435 // set the resulting position at the shape
436 if( aShapeProp.setProperty(PROP_RelativePosition, aPos) )
437 bPropSet = true;
439 // set the resulting position at the shape
440 if( !bPropSet )
441 rxShape->setPosition( aShapePos );
444 } // namespace oox
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */