diff options
Diffstat (limited to '')
-rw-r--r-- | chart2/source/view/axes/VAxisProperties.cxx | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/chart2/source/view/axes/VAxisProperties.cxx b/chart2/source/view/axes/VAxisProperties.cxx new file mode 100644 index 000000000..f8f177936 --- /dev/null +++ b/chart2/source/view/axes/VAxisProperties.cxx @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VAxisProperties.hxx" +#include <ViewDefines.hxx> +#include <Axis.hxx> +#include <AxisHelper.hxx> +#include <ChartModelHelper.hxx> +#include <ExplicitCategoriesProvider.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp> +#include <com/sun/star/chart2/AxisType.hpp> + +#include <tools/diagnose_ex.h> +#include <rtl/math.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart { + +AxisLabelAlignment::AxisLabelAlignment() : + mfLabelDirection(1.0), + mfInnerTickDirection(1.0), + meAlignment(LABEL_ALIGN_RIGHT_TOP) {} + +static sal_Int32 lcl_calcTickLengthForDepth(sal_Int32 nDepth,sal_Int32 nTickmarkStyle) +{ + sal_Int32 const nWidth = AXIS2D_TICKLENGTH; //@maybefuturetodo this length could be offered by the model + double fPercent = 1.0; + switch(nDepth) + { + case 0: + fPercent = 1.0; + break; + case 1: + fPercent = 0.75;//percentage like in the old chart + break; + case 2: + fPercent = 0.5; + break; + default: + fPercent = 0.3; + break; + } + if(nTickmarkStyle==3)//inner and outer tickmarks + fPercent*=2.0; + return static_cast<sal_Int32>(nWidth*fPercent); +} + +static double lcl_getTickOffset(sal_Int32 nLength,sal_Int32 nTickmarkStyle) +{ + double fPercent = 0.0; //0<=fPercent<=1 + //0.0: completely inner + //1.0: completely outer + //0.5: half and half + + /* + nTickmarkStyle: + 1: inner tickmarks + 2: outer tickmarks + 3: inner and outer tickmarks + */ + switch(nTickmarkStyle) + { + case 1: + fPercent = 0.0; + break; + case 2: + fPercent = 1.0; + break; + default: + fPercent = 0.5; + break; + } + return fPercent*nLength; +} + +TickmarkProperties AxisProperties::makeTickmarkProperties( + sal_Int32 nDepth ) const +{ + /* + nTickmarkStyle: + 1: inner tickmarks + 2: outer tickmarks + 3: inner and outer tickmarks + */ + sal_Int32 nTickmarkStyle = 1; + if(nDepth==0) + { + nTickmarkStyle = m_nMajorTickmarks; + if(!nTickmarkStyle) + { + //create major tickmarks as if they were minor tickmarks + nDepth = 1; + nTickmarkStyle = m_nMinorTickmarks; + } + } + else if( nDepth==1) + { + nTickmarkStyle = m_nMinorTickmarks; + } + + if (maLabelAlignment.mfInnerTickDirection == 0.0) + { + if( nTickmarkStyle != 0 ) + nTickmarkStyle = 3; //inner and outer tickmarks + } + + TickmarkProperties aTickmarkProperties; + aTickmarkProperties.Length = lcl_calcTickLengthForDepth(nDepth,nTickmarkStyle); + aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length,nTickmarkStyle)); + aTickmarkProperties.aLineProperties = makeLinePropertiesForDepth(); + return aTickmarkProperties; +} + +TickmarkProperties AxisProperties::makeTickmarkPropertiesForComplexCategories( + sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis ) const +{ + sal_Int32 nTickmarkStyle = (maLabelAlignment.mfLabelDirection == maLabelAlignment.mfInnerTickDirection) ? 2/*outside*/ : 1/*inside*/; + + TickmarkProperties aTickmarkProperties; + aTickmarkProperties.Length = nTickLength;// + nTextLevel*( lcl_calcTickLengthForDepth(0,nTickmarkStyle) ); + aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length+nTickStartDistanceToAxis,nTickmarkStyle)); + aTickmarkProperties.aLineProperties = makeLinePropertiesForDepth(); + return aTickmarkProperties; +} + +TickmarkProperties AxisProperties::getBiggestTickmarkProperties() +{ + TickmarkProperties aTickmarkProperties; + sal_Int32 nTickmarkStyle = 3;//inner and outer tickmarks + aTickmarkProperties.Length = lcl_calcTickLengthForDepth( 0/*nDepth*/,nTickmarkStyle ); + aTickmarkProperties.RelativePos = static_cast<sal_Int32>( lcl_getTickOffset( aTickmarkProperties.Length, nTickmarkStyle ) ); + return aTickmarkProperties; +} + +AxisProperties::AxisProperties( const rtl::Reference< Axis >& xAxisModel + , ExplicitCategoriesProvider* pExplicitCategoriesProvider ) + : m_xAxisModel(xAxisModel) + , m_nDimensionIndex(0) + , m_bIsMainAxis(true) + , m_bSwapXAndY(false) + , m_eCrossoverType( css::chart::ChartAxisPosition_ZERO ) + , m_eLabelPos( css::chart::ChartAxisLabelPosition_NEAR_AXIS ) + , m_eTickmarkPos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ) + , m_bCrossingAxisHasReverseDirection(false) + , m_bCrossingAxisIsCategoryAxes(false) + , m_bDisplayLabels( true ) + , m_bTryStaggeringFirst( false ) + , m_nNumberFormatKey(0) + , m_nMajorTickmarks(1) + , m_nMinorTickmarks(1) + , m_nAxisType(AxisType::REALNUMBER) + , m_bComplexCategories(false) + , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider) + , m_bLimitSpaceForLabels(false) +{ +} + +static LabelAlignment lcl_getLabelAlignmentForZAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_RIGHT ); + if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0) + aRet = LABEL_ALIGN_LEFT; + return aRet; +} + +static LabelAlignment lcl_getLabelAlignmentForYAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_RIGHT ); + if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0) + aRet = LABEL_ALIGN_LEFT; + return aRet; +} + +static LabelAlignment lcl_getLabelAlignmentForXAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_BOTTOM ); + if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0) + aRet = LABEL_ALIGN_TOP; + return aRet; +} + +void AxisProperties::initAxisPositioning( const uno::Reference< beans::XPropertySet >& xAxisProp ) +{ + if( !xAxisProp.is() ) + return; + try + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + xAxisProp->getPropertyValue("CrossoverPosition") >>= m_eCrossoverType; + if( m_eCrossoverType == css::chart::ChartAxisPosition_VALUE ) + { + double fValue = 0.0; + xAxisProp->getPropertyValue("CrossoverValue") >>= fValue; + + if( m_bCrossingAxisIsCategoryAxes ) + fValue = ::rtl::math::round(fValue); + m_pfMainLinePositionAtOtherAxis = fValue; + } + else if( m_eCrossoverType == css::chart::ChartAxisPosition_ZERO ) + m_pfMainLinePositionAtOtherAxis = 0.0; + + xAxisProp->getPropertyValue("LabelPosition") >>= m_eLabelPos; + xAxisProp->getPropertyValue("MarkPosition") >>= m_eTickmarkPos; + } + else + { + m_eCrossoverType = css::chart::ChartAxisPosition_START; + if( m_bIsMainAxis == m_bCrossingAxisHasReverseDirection ) + m_eCrossoverType = css::chart::ChartAxisPosition_END; + m_eLabelPos = css::chart::ChartAxisLabelPosition_NEAR_AXIS; + m_eTickmarkPos = css::chart::ChartAxisMarkPosition_AT_LABELS; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void AxisProperties::init( bool bCartesian ) +{ + if( !m_xAxisModel.is() ) + return; + + if( m_nDimensionIndex<2 ) + initAxisPositioning( m_xAxisModel ); + + ScaleData aScaleData = m_xAxisModel->getScaleData(); + if( m_nDimensionIndex==0 ) + AxisHelper::checkDateAxis( aScaleData, m_pExplicitCategoriesProvider, bCartesian ); + m_nAxisType = aScaleData.AxisType; + + if( bCartesian ) + { + if( m_nDimensionIndex == 0 && m_nAxisType == AxisType::CATEGORY + && m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() ) + m_bComplexCategories = true; + + if( m_eCrossoverType == css::chart::ChartAxisPosition_END ) + maLabelAlignment.mfInnerTickDirection = m_bCrossingAxisHasReverseDirection ? 1.0 : -1.0; + else + maLabelAlignment.mfInnerTickDirection = m_bCrossingAxisHasReverseDirection ? -1.0 : 1.0; + + if( m_eLabelPos == css::chart::ChartAxisLabelPosition_NEAR_AXIS ) + maLabelAlignment.mfLabelDirection = maLabelAlignment.mfInnerTickDirection; + else if( m_eLabelPos == css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE ) + maLabelAlignment.mfLabelDirection = -maLabelAlignment.mfInnerTickDirection; + else if( m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_START ) + maLabelAlignment.mfLabelDirection = m_bCrossingAxisHasReverseDirection ? -1 : 1; + else if( m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + maLabelAlignment.mfLabelDirection = m_bCrossingAxisHasReverseDirection ? 1 : -1; + + if( m_nDimensionIndex==2 ) + maLabelAlignment.meAlignment = lcl_getLabelAlignmentForZAxis(*this); + else + { + bool bIsYAxisPosition = (m_nDimensionIndex==1 && !m_bSwapXAndY) + || (m_nDimensionIndex==0 && m_bSwapXAndY); + if( bIsYAxisPosition ) + { + maLabelAlignment.mfLabelDirection *= -1.0; + maLabelAlignment.mfInnerTickDirection *= -1.0; + + maLabelAlignment.meAlignment = lcl_getLabelAlignmentForYAxis(*this); + } + else + maLabelAlignment.meAlignment = lcl_getLabelAlignmentForXAxis(*this); + } + } + + try + { + //init LineProperties + m_aLineProperties.initFromPropertySet( m_xAxisModel ); + + //init display labels + m_xAxisModel->getPropertyValue( "DisplayLabels" ) >>= m_bDisplayLabels; + + // Init layout strategy hint for axis labels. + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + m_xAxisModel->getPropertyValue( "TryStaggeringFirst" ) >>= m_bTryStaggeringFirst; + + //init TickmarkProperties + m_xAxisModel->getPropertyValue( "MajorTickmarks" ) >>= m_nMajorTickmarks; + m_xAxisModel->getPropertyValue( "MinorTickmarks" ) >>= m_nMinorTickmarks; + + sal_Int32 nMaxDepth = 0; + if(m_nMinorTickmarks!=0) + nMaxDepth=2; + else if(m_nMajorTickmarks!=0) + nMaxDepth=1; + + m_aTickmarkPropertiesList.clear(); + for( sal_Int32 nDepth=0; nDepth<nMaxDepth; nDepth++ ) + { + TickmarkProperties aTickmarkProperties = makeTickmarkProperties( nDepth ); + m_aTickmarkPropertiesList.push_back( aTickmarkProperties ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +AxisLabelProperties::AxisLabelProperties() + : m_aFontReferenceSize( ChartModelHelper::getDefaultPageSize() ) + , m_aMaximumSpaceForLabels( 0 , 0, m_aFontReferenceSize.Width, m_aFontReferenceSize.Height ) + , m_nNumberFormatKey(0) + , m_eStaggering( AxisLabelStaggering::SideBySide ) + , m_bLineBreakAllowed( false ) + , m_bOverlapAllowed( false ) + , m_bStackCharacters( false ) + , m_fRotationAngleDegree( 0.0 ) + , m_nRhythm( 1 ) +{ + +} + +void AxisLabelProperties::init( const rtl::Reference< Axis >& xAxisModel ) +{ + if(!xAxisModel.is()) + return; + + try + { + xAxisModel->getPropertyValue( "TextBreak" ) >>= m_bLineBreakAllowed; + xAxisModel->getPropertyValue( "TextOverlap" ) >>= m_bOverlapAllowed; + xAxisModel->getPropertyValue( "StackCharacters" ) >>= m_bStackCharacters; + xAxisModel->getPropertyValue( "TextRotation" ) >>= m_fRotationAngleDegree; + + css::chart::ChartAxisArrangeOrderType eArrangeOrder; + xAxisModel->getPropertyValue( "ArrangeOrder" ) >>= eArrangeOrder; + switch(eArrangeOrder) + { + case css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE: + m_eStaggering = AxisLabelStaggering::SideBySide; + break; + case css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN: + m_eStaggering = AxisLabelStaggering::StaggerEven; + break; + case css::chart::ChartAxisArrangeOrderType_STAGGER_ODD: + m_eStaggering = AxisLabelStaggering::StaggerOdd; + break; + default: + m_eStaggering = AxisLabelStaggering::StaggerAuto; + break; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +bool AxisLabelProperties::isStaggered() const +{ + return ( m_eStaggering == AxisLabelStaggering::StaggerOdd || m_eStaggering == AxisLabelStaggering::StaggerEven ); +} + +void AxisLabelProperties::autoRotate45() +{ + m_fRotationAngleDegree = 45; + m_bLineBreakAllowed = false; + m_eStaggering = AxisLabelStaggering::SideBySide; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |