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 "oox/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/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 #include <comphelper/processfactory.hxx>
42 // ============================================================================
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::frame
;
50 using namespace ::com::sun::star::lang
;
51 using namespace ::com::sun::star::uno
;
53 using ::oox::core::XmlFilterBase
;
55 // ============================================================================
59 struct TitleKey
: public ::std::pair
< ObjectType
, ::std::pair
< sal_Int32
, sal_Int32
> >
61 inline explicit TitleKey( ObjectType eObjType
, sal_Int32 nMainIdx
= -1, sal_Int32 nSubIdx
= -1 )
62 { first
= eObjType
; second
.first
= nMainIdx
; second
.second
= nSubIdx
; }
65 // ----------------------------------------------------------------------------
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.
70 struct TitleLayoutInfo
72 typedef Reference
< XShape
> (*GetShapeFunc
)( const Reference
< cssc::XChartDocument
>& );
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.
78 inline explicit TitleLayoutInfo() : mpGetShape( 0 ) {}
82 const Reference
< cssc::XChartDocument
>& rxChart1Doc
);
85 void TitleLayoutInfo::convertTitlePos( ConverterRoot
& rRoot
, const Reference
< cssc::XChartDocument
>& rxChart1Doc
)
87 if( mxTitle
.is() && mpGetShape
) try
89 // try to get the title shape
90 Reference
< XShape
> xTitleShape( mpGetShape( rxChart1Doc
), UNO_SET_THROW
);
91 // get title rotation angle, needed for correction of position of top-left edge
93 PropertySet
aTitleProp( mxTitle
);
94 aTitleProp
.getProperty( fAngle
, PROP_TextRotation
);
95 // convert the position
96 LayoutModel
& rLayout
= mxLayout
.getOrCreate();
97 LayoutConverter
aLayoutConv( rRoot
, rLayout
);
98 aLayoutConv
.convertFromModel( xTitleShape
, fAngle
);
105 // ----------------------------------------------------------------------------
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. */
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 >(); \
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 ) \
124 Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
125 OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
128 /** Returns the drawing shape of the main title, if existing. */
129 Reference
< XShape
> lclGetMainTitleShape( const Reference
< cssc::XChartDocument
>& rxChart1Doc
)
131 OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc
, getTitle
, HasMainTitle
)
134 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape
, XAxisXSupplier
, getXAxisTitle
, HasXAxisTitle
)
135 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape
, XAxisYSupplier
, getYAxisTitle
, HasYAxisTitle
)
136 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape
, XAxisZSupplier
, getZAxisTitle
, HasZAxisTitle
)
137 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape
, XSecondAxisTitleSupplier
, getSecondXAxisTitle
, HasSecondaryXAxisTitle
)
138 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape
, XSecondAxisTitleSupplier
, getSecondYAxisTitle
, HasSecondaryYAxisTitle
)
140 #undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
141 #undef OOX_IMPLEMENT_GETTITLESHAPE
145 // ============================================================================
149 typedef ::std::map
< TitleKey
, TitleLayoutInfo
> TitleMap
;
151 ObjectFormatter maFormatter
;
153 XmlFilterBase
& mrFilter
;
154 ChartConverter
& mrConverter
;
155 Reference
< XChartDocument
> mxDoc
;
158 explicit ConverterData(
159 XmlFilterBase
& rFilter
,
160 ChartConverter
& rChartConverter
,
161 const ChartSpaceModel
& rChartModel
,
162 const Reference
< XChartDocument
>& rxChartDoc
,
163 const awt::Size
& rChartSize
);
167 // ----------------------------------------------------------------------------
169 ConverterData::ConverterData(
170 XmlFilterBase
& rFilter
,
171 ChartConverter
& rChartConverter
,
172 const ChartSpaceModel
& rChartModel
,
173 const Reference
< XChartDocument
>& rxChartDoc
,
174 const awt::Size
& rChartSize
) :
175 maFormatter( rFilter
, rxChartDoc
, rChartModel
),
177 mrConverter( rChartConverter
),
181 OSL_ENSURE( mxDoc
.is(), "ConverterData::ConverterData - missing chart document" );
182 // lock the model to suppress internal updates during conversion
185 Reference
< XModel
> xModel( mxDoc
, UNO_QUERY_THROW
);
186 xModel
->lockControllers();
192 // prepare conversion of title positions
193 maTitles
[ TitleKey( OBJECTTYPE_CHARTTITLE
) ].mpGetShape
= lclGetMainTitleShape
;
194 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_PRIM_AXESSET
, API_X_AXIS
) ].mpGetShape
= lclGetXAxisTitleShape
;
195 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_PRIM_AXESSET
, API_Y_AXIS
) ].mpGetShape
= lclGetYAxisTitleShape
;
196 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_PRIM_AXESSET
, API_Z_AXIS
) ].mpGetShape
= lclGetZAxisTitleShape
;
197 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_SECN_AXESSET
, API_X_AXIS
) ].mpGetShape
= lclGetSecXAxisTitleShape
;
198 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_SECN_AXESSET
, API_Y_AXIS
) ].mpGetShape
= lclGetSecYAxisTitleShape
;
201 ConverterData::~ConverterData()
206 Reference
< XModel
> xModel( mxDoc
, UNO_QUERY_THROW
);
207 xModel
->unlockControllers();
214 // ============================================================================
216 ConverterRoot::ConverterRoot(
217 XmlFilterBase
& rFilter
,
218 ChartConverter
& rChartConverter
,
219 const ChartSpaceModel
& rChartModel
,
220 const Reference
< XChartDocument
>& rxChartDoc
,
221 const awt::Size
& rChartSize
) :
222 mxData( new ConverterData( rFilter
, rChartConverter
, rChartModel
, rxChartDoc
, rChartSize
) )
226 ConverterRoot::~ConverterRoot()
230 Reference
< XInterface
> ConverterRoot::createInstance( const OUString
& rServiceName
) const
232 Reference
< XInterface
> xInt
;
235 xInt
= mxData
->mrFilter
.getServiceFactory()->createInstance( rServiceName
);
240 OSL_ENSURE( xInt
.is(), "ConverterRoot::createInstance - cannot create instance" );
244 Reference
< XComponentContext
> ConverterRoot::getComponentContext() const
246 return comphelper::getComponentContext(mxData
->mrFilter
.getServiceFactory());
249 XmlFilterBase
& ConverterRoot::getFilter() const
251 return mxData
->mrFilter
;
254 ChartConverter
* ConverterRoot::getChartConverter() const
256 return &mxData
->mrConverter
;
259 Reference
< XChartDocument
> ConverterRoot::getChartDocument() const
261 return mxData
->mxDoc
;
264 const awt::Size
& ConverterRoot::getChartSize() const
266 return mxData
->maSize
;
269 ObjectFormatter
& ConverterRoot::getFormatter() const
271 return mxData
->maFormatter
;
274 void ConverterRoot::registerTitleLayout( const Reference
< XTitle
>& rxTitle
,
275 const ModelRef
< LayoutModel
>& rxLayout
, ObjectType eObjType
, sal_Int32 nMainIdx
, sal_Int32 nSubIdx
)
277 OSL_ENSURE( rxTitle
.is(), "ConverterRoot::registerTitleLayout - missing title object" );
278 TitleLayoutInfo
& rTitleInfo
= mxData
->maTitles
[ TitleKey( eObjType
, nMainIdx
, nSubIdx
) ];
279 OSL_ENSURE( rTitleInfo
.mpGetShape
, "ConverterRoot::registerTitleLayout - invalid title key" );
280 rTitleInfo
.mxTitle
= rxTitle
;
281 rTitleInfo
.mxLayout
= rxLayout
;
284 void ConverterRoot::convertTitlePositions()
288 Reference
< cssc::XChartDocument
> xChart1Doc( mxData
->mxDoc
, UNO_QUERY_THROW
);
289 for( ConverterData::TitleMap::iterator aIt
= mxData
->maTitles
.begin(), aEnd
= mxData
->maTitles
.end(); aIt
!= aEnd
; ++aIt
)
290 aIt
->second
.convertTitlePos( *this, xChart1Doc
);
297 // ============================================================================
301 /** Returns a position value in the chart area in 1/100 mm. */
302 sal_Int32
lclCalcPosition( sal_Int32 nChartSize
, double fPos
, sal_Int32 nPosMode
)
306 case XML_edge
: // absolute start position as factor of chart size
307 return getLimitedValue
< sal_Int32
, double >( nChartSize
* fPos
+ 0.5, 0, nChartSize
);
308 case XML_factor
: // position relative to object default position
309 OSL_FAIL( "lclCalcPosition - relative positioning not supported" );
313 OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
317 /** Returns a size value in the chart area in 1/100 mm. */
318 sal_Int32
lclCalcSize( sal_Int32 nPos
, sal_Int32 nChartSize
, double fSize
, sal_Int32 nSizeMode
)
320 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( nChartSize
* fSize
+ 0.5, 0, nChartSize
);
323 case XML_factor
: // passed value is width/height
325 case XML_edge
: // passed value is right/bottom position
326 return nValue
- nPos
+ 1;
329 OSL_FAIL( "lclCalcSize - unknown size mode" );
333 /** Returns a relative size value in the chart area. */
334 double lclCalcRelSize( double fPos
, double fSize
, sal_Int32 nSizeMode
)
338 case XML_factor
: // passed value is width/height
340 case XML_edge
: // passed value is right/bottom position
344 OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
347 return getLimitedValue
< double, double >( fSize
, 0.0, 1.0 - fPos
);
352 // ----------------------------------------------------------------------------
354 LayoutConverter::LayoutConverter( const ConverterRoot
& rParent
, LayoutModel
& rModel
) :
355 ConverterBase
< LayoutModel
>( rParent
, rModel
)
359 LayoutConverter::~LayoutConverter()
363 bool LayoutConverter::calcAbsRectangle( awt::Rectangle
& orRect
) const
365 if( !mrModel
.mbAutoLayout
)
367 const awt::Size
& rChartSize
= getChartSize();
368 orRect
.X
= lclCalcPosition( rChartSize
.Width
, mrModel
.mfX
, mrModel
.mnXMode
);
369 orRect
.Y
= lclCalcPosition( rChartSize
.Height
, mrModel
.mfY
, mrModel
.mnYMode
);
370 if( (orRect
.X
>= 0) && (orRect
.Y
>= 0) )
372 orRect
.Width
= lclCalcSize( orRect
.X
, rChartSize
.Width
, mrModel
.mfW
, mrModel
.mnWMode
);
373 orRect
.Height
= lclCalcSize( orRect
.Y
, rChartSize
.Height
, mrModel
.mfH
, mrModel
.mnHMode
);
374 return (orRect
.Width
> 0) && (orRect
.Height
> 0);
380 bool LayoutConverter::convertFromModel( PropertySet
& rPropSet
)
382 if( !mrModel
.mbAutoLayout
&&
383 (mrModel
.mnXMode
== XML_edge
) && (mrModel
.mfX
>= 0.0) &&
384 (mrModel
.mnYMode
== XML_edge
) && (mrModel
.mfY
>= 0.0) )
386 RelativePosition
aPos(
387 getLimitedValue
< double, double >( mrModel
.mfX
, 0.0, 1.0 ),
388 getLimitedValue
< double, double >( mrModel
.mfY
, 0.0, 1.0 ),
389 Alignment_TOP_LEFT
);
390 rPropSet
.setProperty( PROP_RelativePosition
, aPos
);
393 lclCalcRelSize( aPos
.Primary
, mrModel
.mfW
, mrModel
.mnWMode
),
394 lclCalcRelSize( aPos
.Secondary
, mrModel
.mfH
, mrModel
.mnHMode
) );
395 if( (aSize
.Primary
> 0.0) && (aSize
.Secondary
> 0.0) )
397 rPropSet
.setProperty( PROP_RelativeSize
, aSize
);
404 bool LayoutConverter::convertFromModel( const Reference
< XShape
>& rxShape
, double fRotationAngle
)
406 if( !mrModel
.mbAutoLayout
)
408 const awt::Size
& rChartSize
= getChartSize();
409 awt::Point
aShapePos(
410 lclCalcPosition( rChartSize
.Width
, mrModel
.mfX
, mrModel
.mnXMode
),
411 lclCalcPosition( rChartSize
.Height
, mrModel
.mfY
, mrModel
.mnYMode
) );
412 if( (aShapePos
.X
>= 0) && (aShapePos
.Y
>= 0) )
414 // the call to XShape.getSize() may recalc the chart view
415 awt::Size aShapeSize
= rxShape
->getSize();
416 // rotated shapes need special handling...
417 double fSin
= fabs( sin( fRotationAngle
* F_PI180
) );
418 // add part of height to X direction, if title is rotated down
419 if( fRotationAngle
> 180.0 )
420 aShapePos
.X
+= static_cast< sal_Int32
>( fSin
* aShapeSize
.Height
+ 0.5 );
421 // add part of width to Y direction, if title is rotated up
422 else if( fRotationAngle
> 0.0 )
423 aShapePos
.Y
+= static_cast< sal_Int32
>( fSin
* aShapeSize
.Width
+ 0.5 );
424 // set the resulting position at the shape
425 rxShape
->setPosition( aShapePos
);
432 // ============================================================================
435 } // namespace drawingml
438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */