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 "VAxisProperties.hxx"
21 #include <ViewDefines.hxx>
22 #include <AxisHelper.hxx>
23 #include <ChartModelHelper.hxx>
24 #include <ExplicitCategoriesProvider.hxx>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
28 #include <com/sun/star/chart2/AxisType.hpp>
29 #include <com/sun/star/chart2/XAxis.hpp>
31 #include <tools/diagnose_ex.h>
32 #include <rtl/math.hxx>
34 using namespace ::com::sun::star
;
35 using namespace ::com::sun::star::chart2
;
39 AxisLabelAlignment::AxisLabelAlignment() :
40 mfLabelDirection(1.0),
41 mfInnerTickDirection(1.0),
42 meAlignment(LABEL_ALIGN_RIGHT_TOP
) {}
44 static sal_Int32
lcl_calcTickLengthForDepth(sal_Int32 nDepth
,sal_Int32 nTickmarkStyle
)
46 sal_Int32
const nWidth
= AXIS2D_TICKLENGTH
; //@maybefuturetodo this length could be offered by the model
47 double fPercent
= 1.0;
54 fPercent
= 0.75;//percentage like in the old chart
63 if(nTickmarkStyle
==3)//inner and outer tickmarks
65 return static_cast<sal_Int32
>(nWidth
*fPercent
);
68 static double lcl_getTickOffset(sal_Int32 nLength
,sal_Int32 nTickmarkStyle
)
70 double fPercent
= 0.0; //0<=fPercent<=1
71 //0.0: completely inner
72 //1.0: completely outer
79 3: inner and outer tickmarks
81 switch(nTickmarkStyle
)
93 return fPercent
*nLength
;
96 TickmarkProperties
AxisProperties::makeTickmarkProperties(
97 sal_Int32 nDepth
) const
103 3: inner and outer tickmarks
105 sal_Int32 nTickmarkStyle
= 1;
108 nTickmarkStyle
= m_nMajorTickmarks
;
111 //create major tickmarks as if they were minor tickmarks
113 nTickmarkStyle
= m_nMinorTickmarks
;
118 nTickmarkStyle
= m_nMinorTickmarks
;
121 if (maLabelAlignment
.mfInnerTickDirection
== 0.0)
123 if( nTickmarkStyle
!= 0 )
124 nTickmarkStyle
= 3; //inner and outer tickmarks
127 TickmarkProperties aTickmarkProperties
;
128 aTickmarkProperties
.Length
= lcl_calcTickLengthForDepth(nDepth
,nTickmarkStyle
);
129 aTickmarkProperties
.RelativePos
= static_cast<sal_Int32
>(lcl_getTickOffset(aTickmarkProperties
.Length
,nTickmarkStyle
));
130 aTickmarkProperties
.aLineProperties
= makeLinePropertiesForDepth();
131 return aTickmarkProperties
;
134 TickmarkProperties
AxisProperties::makeTickmarkPropertiesForComplexCategories(
135 sal_Int32 nTickLength
, sal_Int32 nTickStartDistanceToAxis
) const
137 sal_Int32 nTickmarkStyle
= (maLabelAlignment
.mfLabelDirection
== maLabelAlignment
.mfInnerTickDirection
) ? 2/*outside*/ : 1/*inside*/;
139 TickmarkProperties aTickmarkProperties
;
140 aTickmarkProperties
.Length
= nTickLength
;// + nTextLevel*( lcl_calcTickLengthForDepth(0,nTickmarkStyle) );
141 aTickmarkProperties
.RelativePos
= static_cast<sal_Int32
>(lcl_getTickOffset(aTickmarkProperties
.Length
+nTickStartDistanceToAxis
,nTickmarkStyle
));
142 aTickmarkProperties
.aLineProperties
= makeLinePropertiesForDepth();
143 return aTickmarkProperties
;
146 TickmarkProperties
AxisProperties::getBiggestTickmarkProperties()
148 TickmarkProperties aTickmarkProperties
;
149 sal_Int32 nTickmarkStyle
= 3;//inner and outer tickmarks
150 aTickmarkProperties
.Length
= lcl_calcTickLengthForDepth( 0/*nDepth*/,nTickmarkStyle
);
151 aTickmarkProperties
.RelativePos
= static_cast<sal_Int32
>( lcl_getTickOffset( aTickmarkProperties
.Length
, nTickmarkStyle
) );
152 return aTickmarkProperties
;
155 AxisProperties::AxisProperties( const uno::Reference
< XAxis
>& xAxisModel
156 , ExplicitCategoriesProvider
* pExplicitCategoriesProvider
)
157 : m_xAxisModel(xAxisModel
)
158 , m_nDimensionIndex(0)
159 , m_bIsMainAxis(true)
160 , m_bSwapXAndY(false)
161 , m_eCrossoverType( css::chart::ChartAxisPosition_ZERO
)
162 , m_eLabelPos( css::chart::ChartAxisLabelPosition_NEAR_AXIS
)
163 , m_eTickmarkPos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS
)
164 , m_bCrossingAxisHasReverseDirection(false)
165 , m_bCrossingAxisIsCategoryAxes(false)
166 , m_bDisplayLabels( true )
167 , m_bTryStaggeringFirst( false )
168 , m_nNumberFormatKey(0)
169 , m_nMajorTickmarks(1)
170 , m_nMinorTickmarks(1)
171 , m_aTickmarkPropertiesList()
172 , m_aLineProperties()
174 , m_nAxisType(AxisType::REALNUMBER
)
175 , m_bComplexCategories(false)
176 , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider
)
177 , m_bLimitSpaceForLabels(false)
181 static LabelAlignment
lcl_getLabelAlignmentForZAxis( const AxisProperties
& rAxisProperties
)
183 LabelAlignment
aRet( LABEL_ALIGN_RIGHT
);
184 if (rAxisProperties
.maLabelAlignment
.mfLabelDirection
< 0)
185 aRet
= LABEL_ALIGN_LEFT
;
189 static LabelAlignment
lcl_getLabelAlignmentForYAxis( const AxisProperties
& rAxisProperties
)
191 LabelAlignment
aRet( LABEL_ALIGN_RIGHT
);
192 if (rAxisProperties
.maLabelAlignment
.mfLabelDirection
< 0)
193 aRet
= LABEL_ALIGN_LEFT
;
197 static LabelAlignment
lcl_getLabelAlignmentForXAxis( const AxisProperties
& rAxisProperties
)
199 LabelAlignment
aRet( LABEL_ALIGN_BOTTOM
);
200 if (rAxisProperties
.maLabelAlignment
.mfLabelDirection
< 0)
201 aRet
= LABEL_ALIGN_TOP
;
205 void AxisProperties::initAxisPositioning( const uno::Reference
< beans::XPropertySet
>& xAxisProp
)
207 if( !xAxisProp
.is() )
211 if( AxisHelper::isAxisPositioningEnabled() )
213 xAxisProp
->getPropertyValue("CrossoverPosition") >>= m_eCrossoverType
;
214 if( m_eCrossoverType
== css::chart::ChartAxisPosition_VALUE
)
217 xAxisProp
->getPropertyValue("CrossoverValue") >>= fValue
;
219 if( m_bCrossingAxisIsCategoryAxes
)
220 fValue
= ::rtl::math::round(fValue
);
221 m_pfMainLinePositionAtOtherAxis
= fValue
;
223 else if( m_eCrossoverType
== css::chart::ChartAxisPosition_ZERO
)
224 m_pfMainLinePositionAtOtherAxis
= 0.0;
226 xAxisProp
->getPropertyValue("LabelPosition") >>= m_eLabelPos
;
227 xAxisProp
->getPropertyValue("MarkPosition") >>= m_eTickmarkPos
;
231 m_eCrossoverType
= css::chart::ChartAxisPosition_START
;
232 if( m_bIsMainAxis
== m_bCrossingAxisHasReverseDirection
)
233 m_eCrossoverType
= css::chart::ChartAxisPosition_END
;
234 m_eLabelPos
= css::chart::ChartAxisLabelPosition_NEAR_AXIS
;
235 m_eTickmarkPos
= css::chart::ChartAxisMarkPosition_AT_LABELS
;
238 catch( const uno::Exception
& )
240 TOOLS_WARN_EXCEPTION("chart2", "" );
244 void AxisProperties::init( bool bCartesian
)
246 uno::Reference
< beans::XPropertySet
> xProp
=
247 uno::Reference
<beans::XPropertySet
>::query( m_xAxisModel
);
251 if( m_nDimensionIndex
<2 )
252 initAxisPositioning( xProp
);
254 ScaleData aScaleData
= m_xAxisModel
->getScaleData();
255 if( m_nDimensionIndex
==0 )
256 AxisHelper::checkDateAxis( aScaleData
, m_pExplicitCategoriesProvider
, bCartesian
);
257 m_nAxisType
= aScaleData
.AxisType
;
261 if( m_nDimensionIndex
== 0 && m_nAxisType
== AxisType::CATEGORY
262 && m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->hasComplexCategories() )
263 m_bComplexCategories
= true;
265 if( m_eCrossoverType
== css::chart::ChartAxisPosition_END
)
266 maLabelAlignment
.mfInnerTickDirection
= m_bCrossingAxisHasReverseDirection
? 1.0 : -1.0;
268 maLabelAlignment
.mfInnerTickDirection
= m_bCrossingAxisHasReverseDirection
? -1.0 : 1.0;
270 if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_NEAR_AXIS
)
271 maLabelAlignment
.mfLabelDirection
= maLabelAlignment
.mfInnerTickDirection
;
272 else if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE
)
273 maLabelAlignment
.mfLabelDirection
= -maLabelAlignment
.mfInnerTickDirection
;
274 else if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_OUTSIDE_START
)
275 maLabelAlignment
.mfLabelDirection
= m_bCrossingAxisHasReverseDirection
? -1 : 1;
276 else if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_OUTSIDE_END
)
277 maLabelAlignment
.mfLabelDirection
= m_bCrossingAxisHasReverseDirection
? 1 : -1;
279 if( m_nDimensionIndex
==2 )
280 maLabelAlignment
.meAlignment
= lcl_getLabelAlignmentForZAxis(*this);
283 bool bIsYAxisPosition
= (m_nDimensionIndex
==1 && !m_bSwapXAndY
)
284 || (m_nDimensionIndex
==0 && m_bSwapXAndY
);
285 if( bIsYAxisPosition
)
287 maLabelAlignment
.mfLabelDirection
*= -1.0;
288 maLabelAlignment
.mfInnerTickDirection
*= -1.0;
291 if( bIsYAxisPosition
)
292 maLabelAlignment
.meAlignment
= lcl_getLabelAlignmentForYAxis(*this);
294 maLabelAlignment
.meAlignment
= lcl_getLabelAlignmentForXAxis(*this);
300 //init LineProperties
301 m_aLineProperties
.initFromPropertySet( xProp
);
303 //init display labels
304 xProp
->getPropertyValue( "DisplayLabels" ) >>= m_bDisplayLabels
;
306 // Init layout strategy hint for axis labels.
307 // Compatibility option: starting from LibreOffice 5.1 the rotated
308 // layout is preferred to staggering for axis labels.
309 xProp
->getPropertyValue( "TryStaggeringFirst" ) >>= m_bTryStaggeringFirst
;
311 //init TickmarkProperties
312 xProp
->getPropertyValue( "MajorTickmarks" ) >>= m_nMajorTickmarks
;
313 xProp
->getPropertyValue( "MinorTickmarks" ) >>= m_nMinorTickmarks
;
315 sal_Int32 nMaxDepth
= 0;
316 if(m_nMinorTickmarks
!=0)
318 else if(m_nMajorTickmarks
!=0)
321 m_aTickmarkPropertiesList
.clear();
322 for( sal_Int32 nDepth
=0; nDepth
<nMaxDepth
; nDepth
++ )
324 TickmarkProperties aTickmarkProperties
= makeTickmarkProperties( nDepth
);
325 m_aTickmarkPropertiesList
.push_back( aTickmarkProperties
);
328 catch( const uno::Exception
& )
330 TOOLS_WARN_EXCEPTION("chart2", "" );
334 AxisLabelProperties::AxisLabelProperties()
335 : m_aFontReferenceSize( ChartModelHelper::getDefaultPageSize() )
336 , m_aMaximumSpaceForLabels( 0 , 0, m_aFontReferenceSize
.Width
, m_aFontReferenceSize
.Height
)
337 , nNumberFormatKey(0)
338 , eStaggering( AxisLabelStaggering::SideBySide
)
339 , bLineBreakAllowed( false )
340 , bOverlapAllowed( false )
341 , bStackCharacters( false )
342 , fRotationAngleDegree( 0.0 )
348 void AxisLabelProperties::init( const uno::Reference
< XAxis
>& xAxisModel
)
350 uno::Reference
< beans::XPropertySet
> xProp
=
351 uno::Reference
<beans::XPropertySet
>::query( xAxisModel
);
357 xProp
->getPropertyValue( "TextBreak" ) >>= bLineBreakAllowed
;
358 xProp
->getPropertyValue( "TextOverlap" ) >>= bOverlapAllowed
;
359 xProp
->getPropertyValue( "StackCharacters" ) >>= bStackCharacters
;
360 xProp
->getPropertyValue( "TextRotation" ) >>= fRotationAngleDegree
;
362 css::chart::ChartAxisArrangeOrderType eArrangeOrder
;
363 xProp
->getPropertyValue( "ArrangeOrder" ) >>= eArrangeOrder
;
364 switch(eArrangeOrder
)
366 case css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE
:
367 eStaggering
= AxisLabelStaggering::SideBySide
;
369 case css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN
:
370 eStaggering
= AxisLabelStaggering::StaggerEven
;
372 case css::chart::ChartAxisArrangeOrderType_STAGGER_ODD
:
373 eStaggering
= AxisLabelStaggering::StaggerOdd
;
376 eStaggering
= AxisLabelStaggering::StaggerAuto
;
380 catch( const uno::Exception
& )
382 TOOLS_WARN_EXCEPTION("chart2", "" );
386 bool AxisLabelProperties::isStaggered() const
388 return ( eStaggering
== AxisLabelStaggering::StaggerOdd
|| eStaggering
== AxisLabelStaggering::StaggerEven
);
391 void AxisLabelProperties::autoRotate45()
393 fRotationAngleDegree
= 45;
394 bLineBreakAllowed
= false;
395 eStaggering
= AxisLabelStaggering::SideBySide
;
400 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */