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