1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/frame/XModel.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.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>
46 namespace cssc
= ::com::sun::star::chart
;
48 using namespace ::com::sun::star
;
49 using namespace ::com::sun::star::chart2
;
50 using namespace ::com::sun::star::drawing
;
51 using namespace ::com::sun::star::frame
;
52 using namespace ::com::sun::star::lang
;
53 using namespace ::com::sun::star::uno
;
55 using ::oox::core::XmlFilterBase
;
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 ) {}
80 const Reference
< cssc::XChartDocument
>& rxChart1Doc
);
83 void TitleLayoutInfo::convertTitlePos( ConverterRoot
& 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
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
);
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
143 typedef ::std::map
< TitleKey
, TitleLayoutInfo
> TitleMap
;
145 ObjectFormatter maFormatter
;
147 XmlFilterBase
& mrFilter
;
148 ChartConverter
& mrConverter
;
149 Reference
< XChartDocument
> mxDoc
;
152 explicit ConverterData(
153 XmlFilterBase
& rFilter
,
154 ChartConverter
& rChartConverter
,
155 const ChartSpaceModel
& rChartModel
,
156 const Reference
< XChartDocument
>& rxChartDoc
,
157 const awt::Size
& rChartSize
);
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
),
169 mrConverter( rChartConverter
),
173 OSL_ENSURE( mxDoc
.is(), "ConverterData::ConverterData - missing chart document" );
174 // lock the model to suppress internal updates during conversion
177 mxDoc
->lockControllers();
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()
197 mxDoc
->unlockControllers();
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
);
230 OSL_ENSURE( xInt
.is(), "ConverterRoot::createInstance - cannot create instance" );
234 Reference
< XComponentContext
> 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
> 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( ConverterData::TitleMap::iterator aIt
= mxData
->maTitles
.begin(), aEnd
= mxData
->maTitles
.end(); aIt
!= aEnd
; ++aIt
)
280 aIt
->second
.convertTitlePos( *this, xChart1Doc
);
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
)
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" );
301 OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
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
);
311 case XML_factor
: // passed value is width/height
313 case XML_edge
: // passed value is right/bottom position
314 return nValue
- nPos
+ 1;
317 OSL_FAIL( "lclCalcSize - unknown size mode" );
321 /** Returns a relative size value in the chart area. */
322 double lclCalcRelSize( double fPos
, double fSize
, sal_Int32 nSizeMode
)
326 case XML_factor
: // passed value is width/height
328 case XML_edge
: // passed value is right/bottom position
332 OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
335 return getLimitedValue
< double, double >( fSize
, 0.0, 1.0 - fPos
);
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 const awt::Size
& rChartSize
= getChartSize();
354 orRect
.X
= lclCalcPosition( rChartSize
.Width
, mrModel
.mfX
, mrModel
.mnXMode
);
355 orRect
.Y
= lclCalcPosition( rChartSize
.Height
, mrModel
.mfY
, mrModel
.mnYMode
);
356 if( (orRect
.X
>= 0) && (orRect
.Y
>= 0) )
358 orRect
.Width
= lclCalcSize( orRect
.X
, rChartSize
.Width
, mrModel
.mfW
, mrModel
.mnWMode
);
359 orRect
.Height
= lclCalcSize( orRect
.Y
, rChartSize
.Height
, mrModel
.mfH
, mrModel
.mnHMode
);
360 return (orRect
.Width
> 0) && (orRect
.Height
> 0);
366 bool LayoutConverter::convertFromModel( PropertySet
& rPropSet
)
368 if( !mrModel
.mbAutoLayout
&&
369 (mrModel
.mnXMode
== XML_edge
) && (mrModel
.mfX
>= 0.0) &&
370 (mrModel
.mnYMode
== XML_edge
) && (mrModel
.mfY
>= 0.0) )
372 RelativePosition
aPos(
373 getLimitedValue
< double, double >( mrModel
.mfX
, 0.0, 1.0 ),
374 getLimitedValue
< double, double >( mrModel
.mfY
, 0.0, 1.0 ),
375 Alignment_TOP_LEFT
);
376 rPropSet
.setProperty( PROP_RelativePosition
, aPos
);
379 lclCalcRelSize( aPos
.Primary
, mrModel
.mfW
, mrModel
.mnWMode
),
380 lclCalcRelSize( aPos
.Secondary
, mrModel
.mfH
, mrModel
.mnHMode
) );
381 if( (aSize
.Primary
> 0.0) && (aSize
.Secondary
> 0.0) )
383 rPropSet
.setProperty( PROP_RelativeSize
, aSize
);
390 void LayoutConverter::convertFromModel( const Reference
< XShape
>& rxShape
, double fRotationAngle
)
392 if( !mrModel
.mbAutoLayout
)
394 const awt::Size
& rChartSize
= getChartSize();
395 awt::Point
aShapePos(
396 lclCalcPosition( rChartSize
.Width
, mrModel
.mfX
, mrModel
.mnXMode
),
397 lclCalcPosition( rChartSize
.Height
, mrModel
.mfY
, mrModel
.mnYMode
) );
398 if( (aShapePos
.X
>= 0) && (aShapePos
.Y
>= 0) )
400 // the call to XShape.getSize() may recalc the chart view
401 awt::Size aShapeSize
= rxShape
->getSize();
402 // rotated shapes need special handling...
403 double fSin
= fabs( sin( fRotationAngle
* F_PI180
) );
404 // add part of height to X direction, if title is rotated down
405 if( fRotationAngle
> 180.0 )
406 aShapePos
.X
+= static_cast< sal_Int32
>( fSin
* aShapeSize
.Height
+ 0.5 );
407 // add part of width to Y direction, if title is rotated up
408 else if( fRotationAngle
> 0.0 )
409 aShapePos
.Y
+= static_cast< sal_Int32
>( fSin
* aShapeSize
.Width
+ 0.5 );
410 // set the resulting position at the shape
411 rxShape
->setPosition( aShapePos
);
417 } // namespace drawingml
420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */