Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "VAxisProperties.hxx"
21 : #include "macros.hxx"
22 : #include "ViewDefines.hxx"
23 : #include "CommonConverters.hxx"
24 : #include "AxisHelper.hxx"
25 : #include "DiagramHelper.hxx"
26 : #include "ChartModelHelper.hxx"
27 :
28 : #include <com/sun/star/beans/XPropertySet.hpp>
29 : #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
30 : #include <com/sun/star/drawing/LineStyle.hpp>
31 : #include <com/sun/star/text/WritingMode2.hpp>
32 :
33 : using namespace ::com::sun::star;
34 : using namespace ::com::sun::star::chart2;
35 :
36 : namespace chart {
37 :
38 2123 : AxisLabelAlignment::AxisLabelAlignment() :
39 : mfLabelDirection(1.0),
40 : mfInnerTickDirection(1.0),
41 2123 : meAlignment(LABEL_ALIGN_RIGHT_TOP) {}
42 :
43 2614 : sal_Int32 lcl_calcTickLengthForDepth(sal_Int32 nDepth,sal_Int32 nTickmarkStyle)
44 : {
45 2614 : sal_Int32 nWidth = AXIS2D_TICKLENGTH; //@maybefuturetodo this length could be offered by the model
46 2614 : double fPercent = 1.0;
47 2614 : switch(nDepth)
48 : {
49 : case 0:
50 2372 : fPercent = 1.0;
51 2372 : break;
52 : case 1:
53 242 : fPercent = 0.75;//percentage like in the old chart
54 242 : break;
55 : case 2:
56 0 : fPercent = 0.5;
57 0 : break;
58 : default:
59 0 : fPercent = 0.3;
60 0 : break;
61 : }
62 2614 : if(nTickmarkStyle==3)//inner and outer tickmarks
63 398 : fPercent*=2.0;
64 2614 : return static_cast<sal_Int32>(nWidth*fPercent);
65 : }
66 :
67 2614 : double lcl_getTickOffset(sal_Int32 nLength,sal_Int32 nTickmarkStyle)
68 : {
69 2614 : double fPercent = 0.0; //0<=fPercent<=1
70 : //0.0: completely inner
71 : //1.0: completely outer
72 : //0.5: half and half
73 :
74 : /*
75 : nTickmarkStyle:
76 : 1: inner tickmarks
77 : 2: outer tickmarks
78 : 3: inner and outer tickmarks
79 : */
80 2614 : switch(nTickmarkStyle)
81 : {
82 : case 1:
83 2 : fPercent = 0.0;
84 2 : break;
85 : case 2:
86 1735 : fPercent = 1.0;
87 1735 : break;
88 : default:
89 877 : fPercent = 0.5;
90 877 : break;
91 : }
92 2614 : return fPercent*nLength;
93 : }
94 :
95 2222 : TickmarkProperties AxisProperties::makeTickmarkProperties(
96 : sal_Int32 nDepth ) const
97 : {
98 : /*
99 : nTickmarkStyle:
100 : 1: inner tickmarks
101 : 2: outer tickmarks
102 : 3: inner and outer tickmarks
103 : */
104 2222 : sal_Int32 nTickmarkStyle = 1;
105 2222 : if(nDepth==0)
106 : {
107 1981 : nTickmarkStyle = m_nMajorTickmarks;
108 1981 : if(!nTickmarkStyle)
109 : {
110 : //create major tickmarks as if they were minor tickmarks
111 1 : nDepth = 1;
112 1 : nTickmarkStyle = m_nMinorTickmarks;
113 : }
114 : }
115 241 : else if( nDepth==1)
116 : {
117 241 : nTickmarkStyle = m_nMinorTickmarks;
118 : }
119 :
120 2222 : if (maLabelAlignment.mfInnerTickDirection == 0.0)
121 : {
122 2 : if( nTickmarkStyle != 0 )
123 2 : nTickmarkStyle = 3; //inner and outer tickmarks
124 : }
125 :
126 2222 : TickmarkProperties aTickmarkProperties;
127 2222 : aTickmarkProperties.Length = lcl_calcTickLengthForDepth(nDepth,nTickmarkStyle);
128 2222 : aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length,nTickmarkStyle));
129 2222 : aTickmarkProperties.aLineProperties = this->makeLinePropertiesForDepth( nDepth );
130 2222 : return aTickmarkProperties;
131 : }
132 :
133 0 : TickmarkProperties AxisProperties::makeTickmarkPropertiesForComplexCategories(
134 : sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis, sal_Int32 /*nTextLevel*/ ) const
135 : {
136 0 : sal_Int32 nTickmarkStyle = (maLabelAlignment.mfLabelDirection == maLabelAlignment.mfInnerTickDirection) ? 2/*outside*/ : 1/*inside*/;
137 :
138 0 : TickmarkProperties aTickmarkProperties;
139 0 : aTickmarkProperties.Length = nTickLength;// + nTextLevel*( lcl_calcTickLengthForDepth(0,nTickmarkStyle) );
140 0 : aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length+nTickStartDistanceToAxis,nTickmarkStyle));
141 0 : aTickmarkProperties.aLineProperties = this->makeLinePropertiesForDepth( 0 );
142 0 : return aTickmarkProperties;
143 : }
144 :
145 392 : TickmarkProperties AxisProperties::getBiggestTickmarkProperties()
146 : {
147 392 : TickmarkProperties aTickmarkProperties;
148 392 : sal_Int32 nDepth = 0;
149 392 : sal_Int32 nTickmarkStyle = 3;//inner and outer tickmarks
150 392 : aTickmarkProperties.Length = lcl_calcTickLengthForDepth( nDepth,nTickmarkStyle );
151 392 : aTickmarkProperties.RelativePos = static_cast<sal_Int32>( lcl_getTickOffset( aTickmarkProperties.Length, nTickmarkStyle ) );
152 392 : return aTickmarkProperties;
153 : }
154 :
155 2123 : 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( ::com::sun::star::chart::ChartAxisPosition_ZERO )
162 : , m_eLabelPos( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS )
163 : , m_eTickmarkPos( ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS )
164 : , m_bCrossingAxisHasReverseDirection(false)
165 : , m_bCrossingAxisIsCategoryAxes(false)
166 : , m_bDisplayLabels( true )
167 : , m_nNumberFormatKey(0)
168 : , m_nMajorTickmarks(1)
169 : , m_nMinorTickmarks(1)
170 : , m_aTickmarkPropertiesList()
171 : , m_aLineProperties()
172 : //for category axes
173 : , m_nAxisType(AxisType::REALNUMBER)
174 : , m_bComplexCategories(false)
175 : , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider)
176 2123 : , m_xAxisTextProvider(0)
177 : {
178 2123 : }
179 :
180 2137 : AxisProperties::AxisProperties( const AxisProperties& rAxisProperties )
181 : : m_xAxisModel( rAxisProperties.m_xAxisModel )
182 : , m_nDimensionIndex( rAxisProperties.m_nDimensionIndex )
183 : , m_bIsMainAxis( rAxisProperties.m_bIsMainAxis )
184 : , m_bSwapXAndY( rAxisProperties.m_bSwapXAndY )
185 : , m_eCrossoverType( rAxisProperties.m_eCrossoverType )
186 : , m_eLabelPos( rAxisProperties.m_eLabelPos )
187 : , m_eTickmarkPos( rAxisProperties.m_eTickmarkPos )
188 : , m_bCrossingAxisHasReverseDirection( rAxisProperties.m_bCrossingAxisHasReverseDirection )
189 : , m_bCrossingAxisIsCategoryAxes( rAxisProperties.m_bCrossingAxisIsCategoryAxes )
190 : , maLabelAlignment( rAxisProperties.maLabelAlignment )
191 : , m_bDisplayLabels( rAxisProperties.m_bDisplayLabels )
192 : , m_nNumberFormatKey( rAxisProperties.m_nNumberFormatKey )
193 : , m_nMajorTickmarks( rAxisProperties.m_nMajorTickmarks )
194 : , m_nMinorTickmarks( rAxisProperties.m_nMinorTickmarks )
195 : , m_aTickmarkPropertiesList( rAxisProperties.m_aTickmarkPropertiesList )
196 : , m_aLineProperties( rAxisProperties.m_aLineProperties )
197 : //for category axes
198 : , m_nAxisType( rAxisProperties.m_nAxisType )
199 : , m_bComplexCategories( rAxisProperties.m_bComplexCategories )
200 : , m_pExplicitCategoriesProvider( rAxisProperties.m_pExplicitCategoriesProvider )
201 2137 : , m_xAxisTextProvider( rAxisProperties.m_xAxisTextProvider )
202 : {
203 2137 : if( rAxisProperties.m_pfMainLinePositionAtOtherAxis )
204 1995 : m_pfMainLinePositionAtOtherAxis.reset(*rAxisProperties.m_pfMainLinePositionAtOtherAxis);
205 2137 : if( rAxisProperties.m_pfExrtaLinePositionAtOtherAxis )
206 0 : m_pfExrtaLinePositionAtOtherAxis.reset(*rAxisProperties.m_pfExrtaLinePositionAtOtherAxis);
207 2137 : }
208 :
209 49 : LabelAlignment lcl_getLabelAlignmentForZAxis( const AxisProperties& rAxisProperties )
210 : {
211 49 : LabelAlignment aRet( LABEL_ALIGN_RIGHT );
212 49 : if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0)
213 0 : aRet = LABEL_ALIGN_LEFT;
214 49 : return aRet;
215 : }
216 :
217 1036 : LabelAlignment lcl_getLabelAlignmentForYAxis( const AxisProperties& rAxisProperties )
218 : {
219 1036 : LabelAlignment aRet( LABEL_ALIGN_RIGHT );
220 1036 : if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0)
221 959 : aRet = LABEL_ALIGN_LEFT;
222 1036 : return aRet;
223 : }
224 :
225 1034 : LabelAlignment lcl_getLabelAlignmentForXAxis( const AxisProperties& rAxisProperties )
226 : {
227 1034 : LabelAlignment aRet( LABEL_ALIGN_BOTTOM );
228 1034 : if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0)
229 57 : aRet = LABEL_ALIGN_TOP;
230 1034 : return aRet;
231 : }
232 :
233 2125 : void AxisProperties::initAxisPositioning( const uno::Reference< beans::XPropertySet >& xAxisProp )
234 : {
235 2125 : if( !xAxisProp.is() )
236 2125 : return;
237 : try
238 : {
239 2125 : if( AxisHelper::isAxisPositioningEnabled() )
240 : {
241 2125 : xAxisProp->getPropertyValue("CrossoverPosition") >>= m_eCrossoverType;
242 2125 : if( ::com::sun::star::chart::ChartAxisPosition_VALUE == m_eCrossoverType )
243 : {
244 68 : double fValue = 0.0;
245 68 : xAxisProp->getPropertyValue("CrossoverValue") >>= fValue;
246 :
247 68 : if( m_bCrossingAxisIsCategoryAxes )
248 2 : fValue = ::rtl::math::round(fValue);
249 68 : m_pfMainLinePositionAtOtherAxis.reset(fValue);
250 : }
251 2057 : else if( ::com::sun::star::chart::ChartAxisPosition_ZERO == m_eCrossoverType )
252 1915 : m_pfMainLinePositionAtOtherAxis.reset(0.0);
253 :
254 2125 : xAxisProp->getPropertyValue("LabelPosition") >>= m_eLabelPos;
255 2125 : xAxisProp->getPropertyValue("MarkPosition") >>= m_eTickmarkPos;
256 : }
257 : else
258 : {
259 0 : m_eCrossoverType = ::com::sun::star::chart::ChartAxisPosition_START;
260 0 : if( m_bIsMainAxis == m_bCrossingAxisHasReverseDirection )
261 0 : m_eCrossoverType = ::com::sun::star::chart::ChartAxisPosition_END;
262 0 : m_eLabelPos = ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS;
263 0 : m_eTickmarkPos = ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS;
264 : }
265 : }
266 0 : catch( const uno::Exception& e )
267 : {
268 : ASSERT_EXCEPTION( e );
269 : }
270 : }
271 :
272 2125 : void AxisProperties::init( bool bCartesian )
273 : {
274 : uno::Reference< beans::XPropertySet > xProp =
275 2125 : uno::Reference<beans::XPropertySet>::query( this->m_xAxisModel );
276 2125 : if( !xProp.is() )
277 2125 : return;
278 :
279 2125 : if( m_nDimensionIndex<2 )
280 2076 : initAxisPositioning( xProp );
281 :
282 4250 : ScaleData aScaleData = m_xAxisModel->getScaleData();
283 2125 : if( m_nDimensionIndex==0 )
284 1040 : AxisHelper::checkDateAxis( aScaleData, m_pExplicitCategoriesProvider, bCartesian );
285 2125 : m_nAxisType = aScaleData.AxisType;
286 :
287 2125 : if( bCartesian )
288 : {
289 5272 : if( m_nDimensionIndex == 0 && m_nAxisType == AxisType::CATEGORY
290 3097 : && m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() )
291 0 : m_bComplexCategories = true;
292 :
293 2119 : if( ::com::sun::star::chart::ChartAxisPosition_END == m_eCrossoverType )
294 20 : maLabelAlignment.mfInnerTickDirection = m_bCrossingAxisHasReverseDirection ? 1.0 : -1.0;
295 : else
296 2099 : maLabelAlignment.mfInnerTickDirection = m_bCrossingAxisHasReverseDirection ? -1.0 : 1.0;
297 :
298 2119 : if( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS == m_eLabelPos )
299 1997 : maLabelAlignment.mfLabelDirection = maLabelAlignment.mfInnerTickDirection;
300 122 : else if( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE == m_eLabelPos )
301 57 : maLabelAlignment.mfLabelDirection = -maLabelAlignment.mfInnerTickDirection;
302 65 : else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == m_eLabelPos )
303 65 : maLabelAlignment.mfLabelDirection = m_bCrossingAxisHasReverseDirection ? -1 : 1;
304 0 : else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == m_eLabelPos )
305 0 : maLabelAlignment.mfLabelDirection = m_bCrossingAxisHasReverseDirection ? 1 : -1;
306 :
307 2119 : if( m_nDimensionIndex==2 )
308 49 : maLabelAlignment.meAlignment = lcl_getLabelAlignmentForZAxis(*this);
309 : else
310 : {
311 3106 : bool bIsYAxisPosition = (m_nDimensionIndex==1 && !m_bSwapXAndY)
312 3132 : || (m_nDimensionIndex==0 && m_bSwapXAndY);
313 2070 : if( bIsYAxisPosition )
314 : {
315 1036 : maLabelAlignment.mfLabelDirection *= -1.0;
316 1036 : maLabelAlignment.mfInnerTickDirection *= -1.0;
317 : }
318 :
319 2070 : if( bIsYAxisPosition )
320 1036 : maLabelAlignment.meAlignment = lcl_getLabelAlignmentForYAxis(*this);
321 : else
322 1034 : maLabelAlignment.meAlignment = lcl_getLabelAlignmentForXAxis(*this);
323 : }
324 : }
325 :
326 : try
327 : {
328 : //init LineProperties
329 2125 : m_aLineProperties.initFromPropertySet( xProp );
330 :
331 : //init display labels
332 2125 : xProp->getPropertyValue( "DisplayLabels" ) >>= m_bDisplayLabels;
333 :
334 : //init TickmarkProperties
335 2125 : xProp->getPropertyValue( "MajorTickmarks" ) >>= m_nMajorTickmarks;
336 2125 : xProp->getPropertyValue( "MinorTickmarks" ) >>= m_nMinorTickmarks;
337 :
338 2125 : sal_Int32 nMaxDepth = 0;
339 2125 : if(m_nMinorTickmarks!=0)
340 241 : nMaxDepth=2;
341 1884 : else if(m_nMajorTickmarks!=0)
342 1740 : nMaxDepth=1;
343 :
344 2125 : this->m_aTickmarkPropertiesList.clear();
345 4347 : for( sal_Int32 nDepth=0; nDepth<nMaxDepth; nDepth++ )
346 : {
347 2222 : TickmarkProperties aTickmarkProperties = this->makeTickmarkProperties( nDepth );
348 2222 : this->m_aTickmarkPropertiesList.push_back( aTickmarkProperties );
349 2222 : }
350 : }
351 0 : catch( const uno::Exception& e )
352 : {
353 : ASSERT_EXCEPTION( e );
354 2125 : }
355 : }
356 :
357 2135 : AxisLabelProperties::AxisLabelProperties()
358 : : m_aFontReferenceSize( ChartModelHelper::getDefaultPageSize() )
359 : , m_aMaximumSpaceForLabels( 0 , 0, m_aFontReferenceSize.Width, m_aFontReferenceSize.Height )
360 : , nNumberFormatKey(0)
361 : , eStaggering( SIDE_BY_SIDE )
362 : , bLineBreakAllowed( false )
363 : , bOverlapAllowed( false )
364 : , bStackCharacters( false )
365 : , fRotationAngleDegree( 0.0 )
366 : , nRhythm( 1 )
367 2135 : , bRhythmIsFix(false)
368 : {
369 :
370 2135 : }
371 :
372 1938 : void AxisLabelProperties::init( const uno::Reference< XAxis >& xAxisModel )
373 : {
374 : uno::Reference< beans::XPropertySet > xProp =
375 1938 : uno::Reference<beans::XPropertySet>::query( xAxisModel );
376 1938 : if(xProp.is())
377 : {
378 : try
379 : {
380 1938 : xProp->getPropertyValue( "TextBreak" ) >>= this->bLineBreakAllowed;
381 1938 : xProp->getPropertyValue( "TextOverlap" ) >>= this->bOverlapAllowed;
382 1938 : xProp->getPropertyValue( "StackCharacters" ) >>= this->bStackCharacters;
383 1938 : xProp->getPropertyValue( "TextRotation" ) >>= this->fRotationAngleDegree;
384 :
385 : ::com::sun::star::chart::ChartAxisArrangeOrderType eArrangeOrder;
386 1938 : xProp->getPropertyValue( "ArrangeOrder" ) >>= eArrangeOrder;
387 1938 : switch(eArrangeOrder)
388 : {
389 : case ::com::sun::star::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE:
390 318 : this->eStaggering = SIDE_BY_SIDE;
391 318 : break;
392 : case ::com::sun::star::chart::ChartAxisArrangeOrderType_STAGGER_EVEN:
393 20 : this->eStaggering = STAGGER_EVEN;
394 20 : break;
395 : case ::com::sun::star::chart::ChartAxisArrangeOrderType_STAGGER_ODD:
396 38 : this->eStaggering = STAGGER_ODD;
397 38 : break;
398 : default:
399 1562 : this->eStaggering = STAGGER_AUTO;
400 1562 : break;
401 : }
402 : }
403 0 : catch( const uno::Exception& e )
404 : {
405 : ASSERT_EXCEPTION( e );
406 : }
407 1938 : }
408 1938 : }
409 :
410 10239 : bool AxisLabelProperties::isStaggered() const
411 : {
412 10239 : return ( STAGGER_ODD == eStaggering || STAGGER_EVEN == eStaggering );
413 : }
414 :
415 26 : void AxisLabelProperties::autoRotate45()
416 : {
417 26 : fRotationAngleDegree = 45;
418 26 : bLineBreakAllowed = false;
419 26 : eStaggering = SIDE_BY_SIDE;
420 26 : }
421 :
422 : } //namespace chart
423 :
424 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|