/* -*- 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 <ChartModel.hxx>
#include <ExplicitCategoriesProvider.hxx>
#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp>
#include <com/sun/star/chart2/AxisType.hpp>
#include <comphelper/diagnose_ex.hxx>
#include <rtl/math.hxx>
#include <utility>
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 nTickmarkStyl
e)
{
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(rtl::Reference<::chart::Axis> xAxisModel,
ExplicitCategoriesProvider* pExplicitCategoriesProvider,
rtl::Reference<::chart::DataTable> const & xDataTableModel)
: m_xAxisModel(std::move(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_bDisplayDataTable(false )
, m_bDataTableAlignAxisValuesWithColumns(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 )
, m_xDataTableModel(xDataTableModel)
{
}
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(u"CrossoverPosition" _ustr) >>= m_eCrossoverType;
if ( m_eCrossoverType == css::chart::ChartAxisPosition_VALUE )
{
double fValue = 0.0;
xAxisProp->getPropertyValue(u"CrossoverValue" _ustr) >>= 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(u"LabelPosition" _ustr) >>= m_eLabelPos;
xAxisProp->getPropertyValue(u"MarkPosition" _ustr) >>= 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_bSwapXAndY && m_nDimensionIndex == 0) || (m_bSwapXAndY && m_nDimensionIndex == 1))
{
m_bDisplayDataTable = m_xDataTableModel.is();
}
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( u"DisplayLabels" _ustr ) >>= 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( u"TryStaggeringFirst" _ustr ) >>= m_bTryStaggeringFirst;
//init TickmarkProperties
m_xAxisModel->getPropertyValue( u"MajorTickmarks" _ustr ) >>= m_nMajorTickmarks;
m_xAxisModel->getPropertyValue( u"MinorTickmarks" _ustr ) >>= 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" , "" );
}
if (m_bDisplayDataTable)
{
m_bDataTableAlignAxisValuesWithColumns = (m_nDimensionIndex == 0);
if (m_nDimensionIndex == 0)
{
m_bDisplayLabels = false ;
}
}
}
AxisLabelProperties::AxisLabelProperties()
: m_aFontReferenceSize( ChartModel::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( u"TextBreak" _ustr ) >>= m_bLineBreakAllowed;
xAxisModel->getPropertyValue( u"TextOverlap" _ustr ) >>= m_bOverlapAllowed;
xAxisModel->getPropertyValue( u"StackCharacters" _ustr ) >>= m_bStackCharacters;
xAxisModel->getPropertyValue( u"TextRotation" _ustr ) >>= m_fRotationAngleDegree;
css::chart::ChartAxisArrangeOrderType eArrangeOrder;
xAxisModel->getPropertyValue( u"ArrangeOrder" _ustr ) >>= 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: */
Messung V0.5 C=90 H=88 G=88
¤ Dauer der Verarbeitung: 0.5 Sekunden
¤
*© Formatika GbR, Deutschland