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>
23 #include <AxisHelper.hxx>
24 #include <ChartModelHelper.hxx>
25 #include <ExplicitCategoriesProvider.hxx>
27 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
28 #include <com/sun/star/chart2/AxisType.hpp>
30 #include <comphelper/diagnose_ex.hxx>
31 #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(rtl::Reference
<::chart::Axis
> xAxisModel
,
156 ExplicitCategoriesProvider
* pExplicitCategoriesProvider
,
157 rtl::Reference
<::chart::DataTable
> const& xDataTableModel
)
158 : m_xAxisModel(std::move(xAxisModel
))
159 , m_nDimensionIndex(0)
160 , m_bIsMainAxis(true)
161 , m_bSwapXAndY(false)
162 , m_eCrossoverType( css::chart::ChartAxisPosition_ZERO
)
163 , m_eLabelPos( css::chart::ChartAxisLabelPosition_NEAR_AXIS
)
164 , m_eTickmarkPos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS
)
165 , m_bCrossingAxisHasReverseDirection(false)
166 , m_bCrossingAxisIsCategoryAxes(false)
167 , m_bDisplayDataTable(false)
168 , m_bDataTableAlignAxisValuesWithColumns(false)
169 , m_bDisplayLabels( true )
170 , m_bTryStaggeringFirst( false )
171 , m_nNumberFormatKey(0)
172 , m_nMajorTickmarks(1)
173 , m_nMinorTickmarks(1)
174 , m_nAxisType(AxisType::REALNUMBER
)
175 , m_bComplexCategories(false)
176 , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider
)
177 , m_bLimitSpaceForLabels(false)
178 , m_xDataTableModel(xDataTableModel
)
182 static LabelAlignment
lcl_getLabelAlignmentForZAxis( const AxisProperties
& rAxisProperties
)
184 LabelAlignment
aRet( LABEL_ALIGN_RIGHT
);
185 if (rAxisProperties
.maLabelAlignment
.mfLabelDirection
< 0)
186 aRet
= LABEL_ALIGN_LEFT
;
190 static LabelAlignment
lcl_getLabelAlignmentForYAxis( const AxisProperties
& rAxisProperties
)
192 LabelAlignment
aRet( LABEL_ALIGN_RIGHT
);
193 if (rAxisProperties
.maLabelAlignment
.mfLabelDirection
< 0)
194 aRet
= LABEL_ALIGN_LEFT
;
198 static LabelAlignment
lcl_getLabelAlignmentForXAxis( const AxisProperties
& rAxisProperties
)
200 LabelAlignment
aRet( LABEL_ALIGN_BOTTOM
);
201 if (rAxisProperties
.maLabelAlignment
.mfLabelDirection
< 0)
202 aRet
= LABEL_ALIGN_TOP
;
206 void AxisProperties::initAxisPositioning( const uno::Reference
< beans::XPropertySet
>& xAxisProp
)
208 if( !xAxisProp
.is() )
212 if( AxisHelper::isAxisPositioningEnabled() )
214 xAxisProp
->getPropertyValue(u
"CrossoverPosition"_ustr
) >>= m_eCrossoverType
;
215 if( m_eCrossoverType
== css::chart::ChartAxisPosition_VALUE
)
218 xAxisProp
->getPropertyValue(u
"CrossoverValue"_ustr
) >>= fValue
;
220 if( m_bCrossingAxisIsCategoryAxes
)
221 fValue
= ::rtl::math::round(fValue
);
222 m_pfMainLinePositionAtOtherAxis
= fValue
;
224 else if( m_eCrossoverType
== css::chart::ChartAxisPosition_ZERO
)
225 m_pfMainLinePositionAtOtherAxis
= 0.0;
227 xAxisProp
->getPropertyValue(u
"LabelPosition"_ustr
) >>= m_eLabelPos
;
228 xAxisProp
->getPropertyValue(u
"MarkPosition"_ustr
) >>= m_eTickmarkPos
;
232 m_eCrossoverType
= css::chart::ChartAxisPosition_START
;
233 if( m_bIsMainAxis
== m_bCrossingAxisHasReverseDirection
)
234 m_eCrossoverType
= css::chart::ChartAxisPosition_END
;
235 m_eLabelPos
= css::chart::ChartAxisLabelPosition_NEAR_AXIS
;
236 m_eTickmarkPos
= css::chart::ChartAxisMarkPosition_AT_LABELS
;
239 catch( const uno::Exception
& )
241 TOOLS_WARN_EXCEPTION("chart2", "" );
245 void AxisProperties::init( bool bCartesian
)
247 if( !m_xAxisModel
.is() )
250 if( m_nDimensionIndex
<2 )
251 initAxisPositioning( m_xAxisModel
);
253 ScaleData aScaleData
= m_xAxisModel
->getScaleData();
254 if( m_nDimensionIndex
==0 )
255 AxisHelper::checkDateAxis( aScaleData
, m_pExplicitCategoriesProvider
, bCartesian
);
256 m_nAxisType
= aScaleData
.AxisType
;
260 if ((!m_bSwapXAndY
&& m_nDimensionIndex
== 0) || (m_bSwapXAndY
&& m_nDimensionIndex
== 1))
262 m_bDisplayDataTable
= m_xDataTableModel
.is();
265 if( m_nDimensionIndex
== 0 && m_nAxisType
== AxisType::CATEGORY
266 && m_pExplicitCategoriesProvider
&& m_pExplicitCategoriesProvider
->hasComplexCategories() )
267 m_bComplexCategories
= true;
269 if( m_eCrossoverType
== css::chart::ChartAxisPosition_END
)
270 maLabelAlignment
.mfInnerTickDirection
= m_bCrossingAxisHasReverseDirection
? 1.0 : -1.0;
272 maLabelAlignment
.mfInnerTickDirection
= m_bCrossingAxisHasReverseDirection
? -1.0 : 1.0;
274 if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_NEAR_AXIS
)
275 maLabelAlignment
.mfLabelDirection
= maLabelAlignment
.mfInnerTickDirection
;
276 else if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE
)
277 maLabelAlignment
.mfLabelDirection
= -maLabelAlignment
.mfInnerTickDirection
;
278 else if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_OUTSIDE_START
)
279 maLabelAlignment
.mfLabelDirection
= m_bCrossingAxisHasReverseDirection
? -1 : 1;
280 else if( m_eLabelPos
== css::chart::ChartAxisLabelPosition_OUTSIDE_END
)
281 maLabelAlignment
.mfLabelDirection
= m_bCrossingAxisHasReverseDirection
? 1 : -1;
283 if( m_nDimensionIndex
==2 )
284 maLabelAlignment
.meAlignment
= lcl_getLabelAlignmentForZAxis(*this);
287 bool bIsYAxisPosition
= (m_nDimensionIndex
==1 && !m_bSwapXAndY
)
288 || (m_nDimensionIndex
==0 && m_bSwapXAndY
);
289 if( bIsYAxisPosition
)
291 maLabelAlignment
.mfLabelDirection
*= -1.0;
292 maLabelAlignment
.mfInnerTickDirection
*= -1.0;
294 maLabelAlignment
.meAlignment
= lcl_getLabelAlignmentForYAxis(*this);
297 maLabelAlignment
.meAlignment
= lcl_getLabelAlignmentForXAxis(*this);
303 //init LineProperties
304 m_aLineProperties
.initFromPropertySet( m_xAxisModel
);
306 //init display labels
307 m_xAxisModel
->getPropertyValue( u
"DisplayLabels"_ustr
) >>= m_bDisplayLabels
;
309 // Init layout strategy hint for axis labels.
310 // Compatibility option: starting from LibreOffice 5.1 the rotated
311 // layout is preferred to staggering for axis labels.
312 m_xAxisModel
->getPropertyValue( u
"TryStaggeringFirst"_ustr
) >>= m_bTryStaggeringFirst
;
314 //init TickmarkProperties
315 m_xAxisModel
->getPropertyValue( u
"MajorTickmarks"_ustr
) >>= m_nMajorTickmarks
;
316 m_xAxisModel
->getPropertyValue( u
"MinorTickmarks"_ustr
) >>= m_nMinorTickmarks
;
318 sal_Int32 nMaxDepth
= 0;
319 if(m_nMinorTickmarks
!=0)
321 else if(m_nMajorTickmarks
!=0)
324 m_aTickmarkPropertiesList
.clear();
325 for( sal_Int32 nDepth
=0; nDepth
<nMaxDepth
; nDepth
++ )
327 TickmarkProperties aTickmarkProperties
= makeTickmarkProperties( nDepth
);
328 m_aTickmarkPropertiesList
.push_back( aTickmarkProperties
);
331 catch( const uno::Exception
& )
333 TOOLS_WARN_EXCEPTION("chart2", "" );
336 if (m_bDisplayDataTable
)
338 m_bDataTableAlignAxisValuesWithColumns
= (m_nDimensionIndex
== 0);
340 if (m_nDimensionIndex
== 0)
342 m_bDisplayLabels
= false;
348 AxisLabelProperties::AxisLabelProperties()
349 : m_aFontReferenceSize( ChartModelHelper::getDefaultPageSize() )
350 , m_aMaximumSpaceForLabels( 0 , 0, m_aFontReferenceSize
.Width
, m_aFontReferenceSize
.Height
)
351 , m_nNumberFormatKey(0)
352 , m_eStaggering( AxisLabelStaggering::SideBySide
)
353 , m_bLineBreakAllowed( false )
354 , m_bOverlapAllowed( false )
355 , m_bStackCharacters( false )
356 , m_fRotationAngleDegree( 0.0 )
362 void AxisLabelProperties::init( const rtl::Reference
< Axis
>& xAxisModel
)
369 xAxisModel
->getPropertyValue( u
"TextBreak"_ustr
) >>= m_bLineBreakAllowed
;
370 xAxisModel
->getPropertyValue( u
"TextOverlap"_ustr
) >>= m_bOverlapAllowed
;
371 xAxisModel
->getPropertyValue( u
"StackCharacters"_ustr
) >>= m_bStackCharacters
;
372 xAxisModel
->getPropertyValue( u
"TextRotation"_ustr
) >>= m_fRotationAngleDegree
;
374 css::chart::ChartAxisArrangeOrderType eArrangeOrder
;
375 xAxisModel
->getPropertyValue( u
"ArrangeOrder"_ustr
) >>= eArrangeOrder
;
376 switch(eArrangeOrder
)
378 case css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE
:
379 m_eStaggering
= AxisLabelStaggering::SideBySide
;
381 case css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN
:
382 m_eStaggering
= AxisLabelStaggering::StaggerEven
;
384 case css::chart::ChartAxisArrangeOrderType_STAGGER_ODD
:
385 m_eStaggering
= AxisLabelStaggering::StaggerOdd
;
388 m_eStaggering
= AxisLabelStaggering::StaggerAuto
;
392 catch( const uno::Exception
& )
394 TOOLS_WARN_EXCEPTION("chart2", "" );
398 bool AxisLabelProperties::isStaggered() const
400 return ( m_eStaggering
== AxisLabelStaggering::StaggerOdd
|| m_eStaggering
== AxisLabelStaggering::StaggerEven
);
403 void AxisLabelProperties::autoRotate45()
405 m_fRotationAngleDegree
= 45;
406 m_bLineBreakAllowed
= false;
407 m_eStaggering
= AxisLabelStaggering::SideBySide
;
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */