1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
30 #include "VAxisProperties.hxx"
31 #include "macros.hxx"
32 #include "ViewDefines.hxx"
33 #include "CommonConverters.hxx"
34 #include "AxisHelper.hxx"
35 #include "DiagramHelper.hxx"
36 #include "ChartModelHelper.hxx"
37 
38 #include <tools/color.hxx>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
41 #include <com/sun/star/drawing/LineStyle.hpp>
42 #include <com/sun/star/text/WritingMode2.hpp>
43 
44 //.............................................................................
45 namespace chart
46 {
47 //.............................................................................
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::chart2;
50 
51 sal_Int32 lcl_calcTickLengthForDepth(sal_Int32 nDepth,sal_Int32 nTickmarkStyle)
52 {
53     sal_Int32 nWidth = AXIS2D_TICKLENGTH; //@maybefuturetodo this length could be offered by the model
54     double fPercent = 1.0;
55     switch(nDepth)
56     {
57         case 0:
58             fPercent = 1.0;
59             break;
60         case 1:
61             fPercent = 0.75;//percentage like in the old chart
62             break;
63         case 2:
64             fPercent = 0.5;
65             break;
66         default:
67             fPercent = 0.3;
68             break;
69     }
70     if(nTickmarkStyle==3)//inner and outer tickmarks
71         fPercent*=2.0;
72     return static_cast<sal_Int32>(nWidth*fPercent);
73 }
74 
75 double lcl_getTickOffset(sal_Int32 nLength,sal_Int32 nTickmarkStyle)
76 {
77     double fPercent = 0.0; //0<=fPercent<=1
78     //0.0: completly inner
79     //1.0: completly outer
80     //0.5: half and half
81 
82     /*
83     nTickmarkStyle:
84     1: inner tickmarks
85     2: outer tickmarks
86     3: inner and outer tickmarks
87     */
88     switch(nTickmarkStyle)
89     {
90         case 1:
91             fPercent = 0.0;
92             break;
93         case 2:
94             fPercent = 1.0;
95             break;
96         default:
97             fPercent = 0.5;
98             break;
99     }
100     return fPercent*nLength;
101 }
102 
103 VLineProperties AxisProperties::makeLinePropertiesForDepth( sal_Int32 /* nDepth */ ) const
104 {
105     //@todo get this from somewhere; maybe for each subincrement
106     //so far the model does not offer different settings for each tick depth
107     return m_aLineProperties;
108 }
109 
110 TickmarkProperties AxisProperties::makeTickmarkProperties(
111                         sal_Int32 nDepth ) const
112 {
113     /*
114     nTickmarkStyle:
115     1: inner tickmarks
116     2: outer tickmarks
117     3: inner and outer tickmarks
118     */
119     sal_Int32 nTickmarkStyle = 1;
120     if(nDepth==0)
121     {
122         nTickmarkStyle = m_nMajorTickmarks;
123         if(!nTickmarkStyle)
124         {
125             //create major tickmarks as if they were minor tickmarks
126             nDepth = 1;
127             nTickmarkStyle = m_nMinorTickmarks;
128         }
129     }
130     else if( nDepth==1)
131     {
132         nTickmarkStyle = m_nMinorTickmarks;
133     }
134 
135     if( m_fInnerDirectionSign == 0.0 )
136     {
137         if( nTickmarkStyle != 0 )
138             nTickmarkStyle = 3; //inner and outer tickmarks
139     }
140 
141     TickmarkProperties aTickmarkProperties;
142     aTickmarkProperties.Length = lcl_calcTickLengthForDepth(nDepth,nTickmarkStyle);
143     aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length,nTickmarkStyle));
144     aTickmarkProperties.aLineProperties = this->makeLinePropertiesForDepth( nDepth );
145     return aTickmarkProperties;
146 }
147 
148 TickmarkProperties AxisProperties::makeTickmarkPropertiesForComplexCategories(
149     sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis, sal_Int32 /*nTextLevel*/ ) const
150 {
151     sal_Int32 nTickmarkStyle = (m_fLabelDirectionSign==m_fInnerDirectionSign) ? 2/*outside*/ : 1/*inside*/;
152 
153     TickmarkProperties aTickmarkProperties;
154     aTickmarkProperties.Length = nTickLength;// + nTextLevel*( lcl_calcTickLengthForDepth(0,nTickmarkStyle) );
155     aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length+nTickStartDistanceToAxis,nTickmarkStyle));
156     aTickmarkProperties.aLineProperties = this->makeLinePropertiesForDepth( 0 );
157     return aTickmarkProperties;
158 }
159 
160 TickmarkProperties AxisProperties::getBiggestTickmarkProperties()
161 {
162     TickmarkProperties aTickmarkProperties;
163     sal_Int32 nDepth = 0;
164     sal_Int32 nTickmarkStyle = 3;//inner and outer tickmarks
165     aTickmarkProperties.Length = lcl_calcTickLengthForDepth( nDepth,nTickmarkStyle );
166     aTickmarkProperties.RelativePos = static_cast<sal_Int32>( lcl_getTickOffset( aTickmarkProperties.Length, nTickmarkStyle ) );
167     return aTickmarkProperties;
168 }
169 
170 //--------------------------------------------------------------------------
171 
172 AxisProperties::AxisProperties( const uno::Reference< XAxis >& xAxisModel
173                               , ExplicitCategoriesProvider* pExplicitCategoriesProvider )
174     : m_xAxisModel(xAxisModel)
175     , m_nDimensionIndex(0)
176     , m_bIsMainAxis(true)
177     , m_bSwapXAndY(false)
178     , m_eCrossoverType( ::com::sun::star::chart::ChartAxisPosition_ZERO )
179     , m_eLabelPos( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS )
180     , m_eTickmarkPos( ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS )
181     , m_pfMainLinePositionAtOtherAxis(NULL)
182     , m_pfExrtaLinePositionAtOtherAxis(NULL)
183     , m_bCrossingAxisHasReverseDirection(false)
184     , m_bCrossingAxisIsCategoryAxes(false)
185     , m_fLabelDirectionSign(1.0)
186     , m_fInnerDirectionSign(1.0)
187     , m_aLabelAlignment(LABEL_ALIGN_RIGHT_TOP)
188     , m_bDisplayLabels( true )
189     , m_nNumberFormatKey(0)
190     , m_nMajorTickmarks(1)
191     , m_nMinorTickmarks(1)
192     , m_aTickmarkPropertiesList()
193     , m_aLineProperties()
194     //for category axes
195     , m_nAxisType(AxisType::REALNUMBER)
196     , m_bComplexCategories(false)
197     , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider)
198     , m_xAxisTextProvider(0)
199 {
200 }
201 
202 AxisProperties::AxisProperties( const AxisProperties& rAxisProperties )
203     : m_xAxisModel( rAxisProperties.m_xAxisModel )
204     , m_nDimensionIndex( m_nDimensionIndex )
205     , m_bIsMainAxis( rAxisProperties.m_bIsMainAxis )
206     , m_bSwapXAndY( rAxisProperties.m_bSwapXAndY )
207     , m_eCrossoverType( rAxisProperties.m_eCrossoverType )
208     , m_eLabelPos( rAxisProperties.m_eLabelPos )
209     , m_eTickmarkPos( rAxisProperties.m_eTickmarkPos )
210     , m_pfMainLinePositionAtOtherAxis( NULL )
211     , m_pfExrtaLinePositionAtOtherAxis( NULL )
212     , m_bCrossingAxisHasReverseDirection( rAxisProperties.m_bCrossingAxisHasReverseDirection )
213     , m_bCrossingAxisIsCategoryAxes( rAxisProperties.m_bCrossingAxisIsCategoryAxes )
214     , m_fLabelDirectionSign( rAxisProperties.m_fLabelDirectionSign )
215     , m_fInnerDirectionSign( rAxisProperties.m_fInnerDirectionSign )
216     , m_aLabelAlignment( rAxisProperties.m_aLabelAlignment )
217     , m_bDisplayLabels( rAxisProperties.m_bDisplayLabels )
218     , m_nNumberFormatKey( rAxisProperties.m_nNumberFormatKey )
219     , m_nMajorTickmarks( rAxisProperties.m_nMajorTickmarks )
220     , m_nMinorTickmarks( rAxisProperties.m_nMinorTickmarks )
221     , m_aTickmarkPropertiesList( rAxisProperties.m_aTickmarkPropertiesList )
222     , m_aLineProperties( rAxisProperties.m_aLineProperties )
223     //for category axes
224     , m_nAxisType( rAxisProperties.m_nAxisType )
225     , m_bComplexCategories( rAxisProperties.m_bComplexCategories )
226     , m_pExplicitCategoriesProvider( rAxisProperties.m_pExplicitCategoriesProvider )
227     , m_xAxisTextProvider( rAxisProperties.m_xAxisTextProvider )
228 {
229     if( rAxisProperties.m_pfMainLinePositionAtOtherAxis )
230         m_pfMainLinePositionAtOtherAxis = new double(*rAxisProperties.m_pfMainLinePositionAtOtherAxis);
231     if( rAxisProperties.m_pfExrtaLinePositionAtOtherAxis )
232         m_pfExrtaLinePositionAtOtherAxis = new double (*rAxisProperties.m_pfExrtaLinePositionAtOtherAxis);
233 }
234 
235 AxisProperties::~AxisProperties()
236 {
237     delete m_pfMainLinePositionAtOtherAxis;
238     delete m_pfExrtaLinePositionAtOtherAxis;
239 }
240 
241 LabelAlignment lcl_getLabelAlignmentForZAxis( const AxisProperties& rAxisProperties )
242 {
243     LabelAlignment aRet( LABEL_ALIGN_RIGHT );
244     if( rAxisProperties.m_fLabelDirectionSign<0 )
245         aRet = LABEL_ALIGN_LEFT;
246     return aRet;
247 }
248 
249 LabelAlignment lcl_getLabelAlignmentForYAxis( const AxisProperties& rAxisProperties )
250 {
251     LabelAlignment aRet( LABEL_ALIGN_RIGHT );
252     if( rAxisProperties.m_fLabelDirectionSign<0 )
253         aRet = LABEL_ALIGN_LEFT;
254     return aRet;
255 }
256 
257 LabelAlignment lcl_getLabelAlignmentForXAxis( const AxisProperties& rAxisProperties )
258 {
259     LabelAlignment aRet( LABEL_ALIGN_BOTTOM );
260     if( rAxisProperties.m_fLabelDirectionSign<0 )
261         aRet = LABEL_ALIGN_TOP;
262     return aRet;
263 }
264 
265 void AxisProperties::initAxisPositioning( const uno::Reference< beans::XPropertySet >& xAxisProp )
266 {
267     if( !xAxisProp.is() )
268         return;
269     try
270     {
271         if( AxisHelper::isAxisPositioningEnabled() )
272         {
273             xAxisProp->getPropertyValue(C2U( "CrossoverPosition" )) >>= m_eCrossoverType;
274             if( ::com::sun::star::chart::ChartAxisPosition_VALUE == m_eCrossoverType )
275             {
276                 double fValue = 0.0;
277                 xAxisProp->getPropertyValue(C2U( "CrossoverValue" )) >>= fValue;
278 
279                 if( m_bCrossingAxisIsCategoryAxes )
280                     fValue = ::rtl::math::round(fValue);
281                 m_pfMainLinePositionAtOtherAxis = new double(fValue);
282             }
283             else if( ::com::sun::star::chart::ChartAxisPosition_ZERO == m_eCrossoverType )
284                 m_pfMainLinePositionAtOtherAxis = new double(0.0);
285 
286             xAxisProp->getPropertyValue(C2U( "LabelPosition" )) >>= m_eLabelPos;
287             xAxisProp->getPropertyValue(C2U( "MarkPosition" )) >>= m_eTickmarkPos;
288         }
289         else
290         {
291             m_eCrossoverType = ::com::sun::star::chart::ChartAxisPosition_START;
292             if( m_bIsMainAxis == m_bCrossingAxisHasReverseDirection )
293                 m_eCrossoverType = ::com::sun::star::chart::ChartAxisPosition_END;
294             m_eLabelPos = ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS;
295             m_eTickmarkPos = ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS;
296         }
297     }
298     catch( uno::Exception& e )
299     {
300         ASSERT_EXCEPTION( e );
301     }
302 }
303 
304 void AxisProperties::init( bool bCartesian )
305 {
306     uno::Reference< beans::XPropertySet > xProp =
307         uno::Reference<beans::XPropertySet>::query( this->m_xAxisModel );
308     if( !xProp.is() )
309         return;
310 
311     if( m_nDimensionIndex<2 )
312         initAxisPositioning( xProp );
313 
314     ScaleData aScaleData = m_xAxisModel->getScaleData();
315     if( m_nDimensionIndex==0 )
316         AxisHelper::checkDateAxis( aScaleData, m_pExplicitCategoriesProvider, bCartesian );
317     m_nAxisType = aScaleData.AxisType;
318 
319     if( bCartesian )
320     {
321         if( m_nDimensionIndex == 0 && m_nAxisType == AxisType::CATEGORY
322                 && m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() )
323             m_bComplexCategories = true;
324 
325         if( ::com::sun::star::chart::ChartAxisPosition_END == m_eCrossoverType )
326             m_fInnerDirectionSign = m_bCrossingAxisHasReverseDirection ? 1 : -1;
327         else
328             m_fInnerDirectionSign = m_bCrossingAxisHasReverseDirection ? -1 : 1;
329 
330         if( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS == m_eLabelPos )
331             m_fLabelDirectionSign = m_fInnerDirectionSign;
332         else if( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE == m_eLabelPos )
333             m_fLabelDirectionSign = -m_fInnerDirectionSign;
334         else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == m_eLabelPos )
335             m_fLabelDirectionSign = m_bCrossingAxisHasReverseDirection ? -1 : 1;
336         else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == m_eLabelPos )
337             m_fLabelDirectionSign = m_bCrossingAxisHasReverseDirection ? 1 : -1;
338 
339         if( m_nDimensionIndex==2 )
340             m_aLabelAlignment = lcl_getLabelAlignmentForZAxis(*this);
341         else
342         {
343             bool bIsYAxisPosition = (m_nDimensionIndex==1 && !m_bSwapXAndY)
344                 || (m_nDimensionIndex==0 && m_bSwapXAndY);
345             if( bIsYAxisPosition )
346             {
347                 m_fLabelDirectionSign*=-1;
348                 m_fInnerDirectionSign*=-1;
349             }
350 
351             if( bIsYAxisPosition )
352                 m_aLabelAlignment = lcl_getLabelAlignmentForYAxis(*this);
353             else
354                 m_aLabelAlignment = lcl_getLabelAlignmentForXAxis(*this);
355         }
356     }
357 
358     try
359     {
360         //init LineProperties
361         m_aLineProperties.initFromPropertySet( xProp );
362 
363         //init display labels
364         xProp->getPropertyValue( C2U( "DisplayLabels" ) ) >>= m_bDisplayLabels;
365 
366         //init TickmarkProperties
367         xProp->getPropertyValue( C2U( "MajorTickmarks" ) ) >>= m_nMajorTickmarks;
368         xProp->getPropertyValue( C2U( "MinorTickmarks" ) ) >>= m_nMinorTickmarks;
369 
370         sal_Int32 nMaxDepth = 0;
371         if(m_nMinorTickmarks!=0)
372             nMaxDepth=2;
373         else if(m_nMajorTickmarks!=0)
374             nMaxDepth=1;
375 
376         this->m_aTickmarkPropertiesList.clear();
377         for( sal_Int32 nDepth=0; nDepth<nMaxDepth; nDepth++ )
378         {
379             TickmarkProperties aTickmarkProperties = this->makeTickmarkProperties( nDepth );
380             this->m_aTickmarkPropertiesList.push_back( aTickmarkProperties );
381         }
382     }
383     catch( uno::Exception& e )
384 	{
385         ASSERT_EXCEPTION( e );
386     }
387 }
388 
389 //-----------------------------------------------------------------------------
390 
391 AxisLabelProperties::AxisLabelProperties()
392                         : m_aFontReferenceSize( ChartModelHelper::getDefaultPageSize() )
393                         , m_aMaximumSpaceForLabels( 0 , 0, m_aFontReferenceSize.Width, m_aFontReferenceSize.Height )
394                         , nNumberFormatKey(0)
395                         , eStaggering( SIDE_BY_SIDE )
396                         , bLineBreakAllowed( false )
397                         , bOverlapAllowed( false )
398                         , bStackCharacters( false )
399                         , fRotationAngleDegree( 0.0 )
400                         , nRhythm( 1 )
401                         , bRhythmIsFix(false)
402 {
403     /*
404     aLocale.Language = C2U( "en" );
405     aLocale.Country  = C2U( "US" );
406 
407     //aLocale.Language = C2U( "ar" );
408     //aLocale.Country  = C2U( "IR" );
409 
410     //aLocale.Language = C2U( "ja" );
411     //aLocale.Country  = C2U( "JP" );
412     */
413 }
414 
415 void AxisLabelProperties::init( const uno::Reference< XAxis >& xAxisModel )
416 {
417     uno::Reference< beans::XPropertySet > xProp =
418         uno::Reference<beans::XPropertySet>::query( xAxisModel );
419     if(xProp.is())
420     {
421         try
422         {
423             xProp->getPropertyValue( C2U( "TextBreak" ) ) >>= this->bLineBreakAllowed;
424             xProp->getPropertyValue( C2U( "TextOverlap" ) ) >>= this->bOverlapAllowed;
425             xProp->getPropertyValue( C2U( "StackCharacters" ) ) >>= this->bStackCharacters;
426             xProp->getPropertyValue( C2U( "TextRotation" ) ) >>= this->fRotationAngleDegree;
427 
428             ::com::sun::star::chart::ChartAxisArrangeOrderType eArrangeOrder;
429             xProp->getPropertyValue( C2U( "ArrangeOrder" ) ) >>= eArrangeOrder;
430             switch(eArrangeOrder)
431             {
432                 case ::com::sun::star::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE:
433                     this->eStaggering = SIDE_BY_SIDE;
434                     break;
435                 case ::com::sun::star::chart::ChartAxisArrangeOrderType_STAGGER_EVEN:
436                     this->eStaggering = STAGGER_EVEN;
437                     break;
438                 case ::com::sun::star::chart::ChartAxisArrangeOrderType_STAGGER_ODD:
439                     this->eStaggering = STAGGER_ODD;
440                     break;
441                 default:
442                     this->eStaggering = STAGGER_AUTO;
443                     break;
444             }
445         }
446         catch( uno::Exception& e )
447 	    {
448             ASSERT_EXCEPTION( e );
449         }
450     }
451 }
452 
453 /*
454 sal_Int16 getSwappedWritingMode( sal_Int16 nWritingMode )
455 {
456     //LR_TB == LT
457     //RL_TB == RT (Arabic, Hebrew)
458     //TB_RL == TR (Japanese, Chinese, Korean)
459     // ?? TL (Mongolian) see also text::WritingMode2
460 
461     switch(nWritingMode)
462     {
463         case text::WritingMode2::RL_TB:
464             return  text::WritingMode2::TB_RL;
465         case text::WritingMode2::TB_RL:
466             return  text::WritingMode2::RL_TB;
467         case text::WritingMode2::LR_TB:
468             return  text::WritingMode2::TB_LR;
469         default:
470             return  text::WritingMode2::LR_TB;
471     }
472 }
473 */
474 
475 sal_Bool AxisLabelProperties::getIsStaggered() const
476 {
477     if( STAGGER_ODD == eStaggering || STAGGER_EVEN == eStaggering )
478         return sal_True;
479     return sal_False;
480 }
481 
482 //.............................................................................
483 } //namespace chart
484 //.............................................................................
485