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 <comphelper/processfactory.hxx>
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
;
57 struct TitleKey
: public ::std::pair
< ObjectType
, ::std::pair
< sal_Int32
, sal_Int32
> >
59 inline explicit TitleKey( ObjectType eObjType
, sal_Int32 nMainIdx
= -1, sal_Int32 nSubIdx
= -1 )
60 { first
= eObjType
; second
.first
= nMainIdx
; second
.second
= nSubIdx
; }
63 /** A helper structure to store all data related to title objects. Needed for
64 the conversion of manual title positions that needs the old Chart1 API.
66 struct TitleLayoutInfo
68 typedef Reference
< XShape
> (*GetShapeFunc
)( const Reference
< cssc::XChartDocument
>& );
70 Reference
< XTitle
> mxTitle
; /// The API title object.
71 ModelRef
< LayoutModel
> mxLayout
; /// The layout model, if existing.
72 GetShapeFunc mpGetShape
; /// Helper function to receive the title shape.
74 inline explicit TitleLayoutInfo() : mpGetShape( 0 ) {}
78 const Reference
< cssc::XChartDocument
>& rxChart1Doc
);
81 void TitleLayoutInfo::convertTitlePos( ConverterRoot
& rRoot
, const Reference
< cssc::XChartDocument
>& rxChart1Doc
)
83 if( mxTitle
.is() && mpGetShape
) try
85 // try to get the title shape
86 Reference
< XShape
> xTitleShape
= mpGetShape( rxChart1Doc
);
87 // get title rotation angle, needed for correction of position of top-left edge
89 PropertySet
aTitleProp( mxTitle
);
90 aTitleProp
.getProperty( fAngle
, PROP_TextRotation
);
91 // convert the position
92 LayoutModel
& rLayout
= mxLayout
.getOrCreate();
93 LayoutConverter
aLayoutConv( rRoot
, rLayout
);
94 aLayoutConv
.convertFromModel( xTitleShape
, fAngle
);
101 /* The following local functions implement getting the XShape interface of all
102 supported title objects (chart and axes). This needs some effort due to the
103 design of the old Chart1 API used to access these objects. */
105 /** A code fragment that returns a shape object from the passed shape supplier
106 using the specified interface function. Checks a boolean property first. */
107 #define OOX_FRAGMENT_GETTITLESHAPE( shape_supplier, supplier_func, property_name ) \
108 PropertySet aPropSet( shape_supplier ); \
109 if( shape_supplier.is() && aPropSet.getBoolProperty( PROP_##property_name ) ) \
110 return shape_supplier->supplier_func(); \
111 return Reference< XShape >(); \
113 /** Implements a function returning the drawing shape of an axis title, if
114 existing, using the specified API interface and its function. */
115 #define OOX_DEFINEFUNC_GETAXISTITLESHAPE( func_name, interface_type, supplier_func, property_name ) \
116 Reference< XShape > func_name( const Reference< cssc::XChartDocument >& rxChart1Doc ) \
118 Reference< cssc::interface_type > xAxisSupp( rxChart1Doc->getDiagram(), UNO_QUERY ); \
119 OOX_FRAGMENT_GETTITLESHAPE( xAxisSupp, supplier_func, property_name ) \
122 /** Returns the drawing shape of the main title, if existing. */
123 Reference
< XShape
> lclGetMainTitleShape( const Reference
< cssc::XChartDocument
>& rxChart1Doc
)
125 OOX_FRAGMENT_GETTITLESHAPE( rxChart1Doc
, getTitle
, HasMainTitle
)
128 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetXAxisTitleShape
, XAxisXSupplier
, getXAxisTitle
, HasXAxisTitle
)
129 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetYAxisTitleShape
, XAxisYSupplier
, getYAxisTitle
, HasYAxisTitle
)
130 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetZAxisTitleShape
, XAxisZSupplier
, getZAxisTitle
, HasZAxisTitle
)
131 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecXAxisTitleShape
, XSecondAxisTitleSupplier
, getSecondXAxisTitle
, HasSecondaryXAxisTitle
)
132 OOX_DEFINEFUNC_GETAXISTITLESHAPE( lclGetSecYAxisTitleShape
, XSecondAxisTitleSupplier
, getSecondYAxisTitle
, HasSecondaryYAxisTitle
)
134 #undef OOX_DEFINEFUNC_GETAXISTITLESHAPE
135 #undef OOX_IMPLEMENT_GETTITLESHAPE
141 typedef ::std::map
< TitleKey
, TitleLayoutInfo
> TitleMap
;
143 ObjectFormatter maFormatter
;
145 XmlFilterBase
& mrFilter
;
146 ChartConverter
& mrConverter
;
147 Reference
< XChartDocument
> mxDoc
;
150 explicit ConverterData(
151 XmlFilterBase
& rFilter
,
152 ChartConverter
& rChartConverter
,
153 const ChartSpaceModel
& rChartModel
,
154 const Reference
< XChartDocument
>& rxChartDoc
,
155 const awt::Size
& rChartSize
);
159 ConverterData::ConverterData(
160 XmlFilterBase
& rFilter
,
161 ChartConverter
& rChartConverter
,
162 const ChartSpaceModel
& rChartModel
,
163 const Reference
< XChartDocument
>& rxChartDoc
,
164 const awt::Size
& rChartSize
) :
165 maFormatter( rFilter
, rxChartDoc
, rChartModel
),
167 mrConverter( rChartConverter
),
171 OSL_ENSURE( mxDoc
.is(), "ConverterData::ConverterData - missing chart document" );
172 // lock the model to suppress internal updates during conversion
175 mxDoc
->lockControllers();
181 // prepare conversion of title positions
182 maTitles
[ TitleKey( OBJECTTYPE_CHARTTITLE
) ].mpGetShape
= lclGetMainTitleShape
;
183 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_PRIM_AXESSET
, API_X_AXIS
) ].mpGetShape
= lclGetXAxisTitleShape
;
184 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_PRIM_AXESSET
, API_Y_AXIS
) ].mpGetShape
= lclGetYAxisTitleShape
;
185 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_PRIM_AXESSET
, API_Z_AXIS
) ].mpGetShape
= lclGetZAxisTitleShape
;
186 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_SECN_AXESSET
, API_X_AXIS
) ].mpGetShape
= lclGetSecXAxisTitleShape
;
187 maTitles
[ TitleKey( OBJECTTYPE_AXISTITLE
, API_SECN_AXESSET
, API_Y_AXIS
) ].mpGetShape
= lclGetSecYAxisTitleShape
;
190 ConverterData::~ConverterData()
195 mxDoc
->unlockControllers();
202 ConverterRoot::ConverterRoot(
203 XmlFilterBase
& rFilter
,
204 ChartConverter
& rChartConverter
,
205 const ChartSpaceModel
& rChartModel
,
206 const Reference
< XChartDocument
>& rxChartDoc
,
207 const awt::Size
& rChartSize
) :
208 mxData( new ConverterData( rFilter
, rChartConverter
, rChartModel
, rxChartDoc
, rChartSize
) )
212 ConverterRoot::~ConverterRoot()
216 Reference
< XInterface
> ConverterRoot::createInstance( const OUString
& rServiceName
) const
218 Reference
< XInterface
> xInt
;
221 Reference
<XMultiServiceFactory
> xMSF
= Reference
<XMultiServiceFactory
>(getComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW
);
223 xInt
= xMSF
->createInstance( rServiceName
);
228 OSL_ENSURE( xInt
.is(), "ConverterRoot::createInstance - cannot create instance" );
232 Reference
< XComponentContext
> ConverterRoot::getComponentContext() const
234 return mxData
->mrFilter
.getComponentContext();
237 XmlFilterBase
& ConverterRoot::getFilter() const
239 return mxData
->mrFilter
;
242 ChartConverter
* ConverterRoot::getChartConverter() const
244 return &mxData
->mrConverter
;
247 Reference
< XChartDocument
> ConverterRoot::getChartDocument() const
249 return mxData
->mxDoc
;
252 const awt::Size
& ConverterRoot::getChartSize() const
254 return mxData
->maSize
;
257 ObjectFormatter
& ConverterRoot::getFormatter() const
259 return mxData
->maFormatter
;
262 void ConverterRoot::registerTitleLayout( const Reference
< XTitle
>& rxTitle
,
263 const ModelRef
< LayoutModel
>& rxLayout
, ObjectType eObjType
, sal_Int32 nMainIdx
, sal_Int32 nSubIdx
)
265 OSL_ENSURE( rxTitle
.is(), "ConverterRoot::registerTitleLayout - missing title object" );
266 TitleLayoutInfo
& rTitleInfo
= mxData
->maTitles
[ TitleKey( eObjType
, nMainIdx
, nSubIdx
) ];
267 OSL_ENSURE( rTitleInfo
.mpGetShape
, "ConverterRoot::registerTitleLayout - invalid title key" );
268 rTitleInfo
.mxTitle
= rxTitle
;
269 rTitleInfo
.mxLayout
= rxLayout
;
272 void ConverterRoot::convertTitlePositions()
276 Reference
< cssc::XChartDocument
> xChart1Doc( mxData
->mxDoc
, UNO_QUERY_THROW
);
277 for( ConverterData::TitleMap::iterator aIt
= mxData
->maTitles
.begin(), aEnd
= mxData
->maTitles
.end(); aIt
!= aEnd
; ++aIt
)
278 aIt
->second
.convertTitlePos( *this, xChart1Doc
);
287 /** Returns a position value in the chart area in 1/100 mm. */
288 sal_Int32
lclCalcPosition( sal_Int32 nChartSize
, double fPos
, sal_Int32 nPosMode
)
292 case XML_edge
: // absolute start position as factor of chart size
293 return getLimitedValue
< sal_Int32
, double >( nChartSize
* fPos
+ 0.5, 0, nChartSize
);
294 case XML_factor
: // position relative to object default position
295 OSL_FAIL( "lclCalcPosition - relative positioning not supported" );
299 OSL_FAIL( "lclCalcPosition - unknown positioning mode" );
303 /** Returns a size value in the chart area in 1/100 mm. */
304 sal_Int32
lclCalcSize( sal_Int32 nPos
, sal_Int32 nChartSize
, double fSize
, sal_Int32 nSizeMode
)
306 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( nChartSize
* fSize
+ 0.5, 0, nChartSize
);
309 case XML_factor
: // passed value is width/height
311 case XML_edge
: // passed value is right/bottom position
312 return nValue
- nPos
+ 1;
315 OSL_FAIL( "lclCalcSize - unknown size mode" );
319 /** Returns a relative size value in the chart area. */
320 double lclCalcRelSize( double fPos
, double fSize
, sal_Int32 nSizeMode
)
324 case XML_factor
: // passed value is width/height
326 case XML_edge
: // passed value is right/bottom position
330 OSL_ENSURE( false, "lclCalcRelSize - unknown size mode" );
333 return getLimitedValue
< double, double >( fSize
, 0.0, 1.0 - fPos
);
338 LayoutConverter::LayoutConverter( const ConverterRoot
& rParent
, LayoutModel
& rModel
) :
339 ConverterBase
< LayoutModel
>( rParent
, rModel
)
343 LayoutConverter::~LayoutConverter()
347 bool LayoutConverter::calcAbsRectangle( awt::Rectangle
& orRect
) const
349 if( !mrModel
.mbAutoLayout
)
351 const awt::Size
& rChartSize
= getChartSize();
352 orRect
.X
= lclCalcPosition( rChartSize
.Width
, mrModel
.mfX
, mrModel
.mnXMode
);
353 orRect
.Y
= lclCalcPosition( rChartSize
.Height
, mrModel
.mfY
, mrModel
.mnYMode
);
354 if( (orRect
.X
>= 0) && (orRect
.Y
>= 0) )
356 orRect
.Width
= lclCalcSize( orRect
.X
, rChartSize
.Width
, mrModel
.mfW
, mrModel
.mnWMode
);
357 orRect
.Height
= lclCalcSize( orRect
.Y
, rChartSize
.Height
, mrModel
.mfH
, mrModel
.mnHMode
);
358 return (orRect
.Width
> 0) && (orRect
.Height
> 0);
364 bool LayoutConverter::convertFromModel( PropertySet
& rPropSet
)
366 if( !mrModel
.mbAutoLayout
&&
367 (mrModel
.mnXMode
== XML_edge
) && (mrModel
.mfX
>= 0.0) &&
368 (mrModel
.mnYMode
== XML_edge
) && (mrModel
.mfY
>= 0.0) )
370 RelativePosition
aPos(
371 getLimitedValue
< double, double >( mrModel
.mfX
, 0.0, 1.0 ),
372 getLimitedValue
< double, double >( mrModel
.mfY
, 0.0, 1.0 ),
373 Alignment_TOP_LEFT
);
374 rPropSet
.setProperty( PROP_RelativePosition
, aPos
);
377 lclCalcRelSize( aPos
.Primary
, mrModel
.mfW
, mrModel
.mnWMode
),
378 lclCalcRelSize( aPos
.Secondary
, mrModel
.mfH
, mrModel
.mnHMode
) );
379 if( (aSize
.Primary
> 0.0) && (aSize
.Secondary
> 0.0) )
381 rPropSet
.setProperty( PROP_RelativeSize
, aSize
);
388 bool LayoutConverter::convertFromModel( const Reference
< XShape
>& rxShape
, double fRotationAngle
)
390 if( !mrModel
.mbAutoLayout
)
392 const awt::Size
& rChartSize
= getChartSize();
393 awt::Point
aShapePos(
394 lclCalcPosition( rChartSize
.Width
, mrModel
.mfX
, mrModel
.mnXMode
),
395 lclCalcPosition( rChartSize
.Height
, mrModel
.mfY
, mrModel
.mnYMode
) );
396 if( (aShapePos
.X
>= 0) && (aShapePos
.Y
>= 0) )
398 // the call to XShape.getSize() may recalc the chart view
399 awt::Size aShapeSize
= rxShape
->getSize();
400 // rotated shapes need special handling...
401 double fSin
= fabs( sin( fRotationAngle
* F_PI180
) );
402 // add part of height to X direction, if title is rotated down
403 if( fRotationAngle
> 180.0 )
404 aShapePos
.X
+= static_cast< sal_Int32
>( fSin
* aShapeSize
.Height
+ 0.5 );
405 // add part of width to Y direction, if title is rotated up
406 else if( fRotationAngle
> 0.0 )
407 aShapePos
.Y
+= static_cast< sal_Int32
>( fSin
* aShapeSize
.Width
+ 0.5 );
408 // set the resulting position at the shape
409 rxShape
->setPosition( aShapePos
);
417 } // namespace drawingml
420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */