diff options
Diffstat (limited to '')
-rw-r--r-- | chart2/source/tools/AxisHelper.cxx | 1151 |
1 files changed, 1151 insertions, 0 deletions
diff --git a/chart2/source/tools/AxisHelper.cxx b/chart2/source/tools/AxisHelper.cxx new file mode 100644 index 000000000..a44fb567a --- /dev/null +++ b/chart2/source/tools/AxisHelper.cxx @@ -0,0 +1,1151 @@ +/* -*- 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 <AxisHelper.hxx> +#include <DiagramHelper.hxx> +#include <Diagram.hxx> +#include <ChartTypeHelper.hxx> +#include <ChartType.hxx> +#include <Axis.hxx> +#include <AxisIndexDefines.hxx> +#include <DataSource.hxx> +#include <LinePropertiesHelper.hxx> +#include <servicenames_coosystems.hxx> +#include <DataSeries.hxx> +#include <DataSeriesHelper.hxx> +#include <Scaling.hxx> +#include <ChartModel.hxx> +#include <ChartModelHelper.hxx> +#include <DataSourceHelper.hxx> +#include <ReferenceSizeProvider.hxx> +#include <ExplicitCategoriesProvider.hxx> +#include <unonames.hxx> +#include <BaseCoordinateSystem.hxx> + +#include <o3tl/safeint.hxx> +#include <unotools/saveopt.hxx> + +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart2/AxisType.hpp> + +#include <sal/log.hxx> + +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/sequence.hxx> +#include <tools/diagnose_ex.h> + +#include <cstddef> +#include <map> + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +Reference< chart2::XScaling > AxisHelper::createLinearScaling() +{ + return new LinearScaling( 1.0, 0.0 ); +} + +Reference< chart2::XScaling > AxisHelper::createLogarithmicScaling( double fBase ) +{ + return new LogarithmicScaling( fBase ); +} + +ScaleData AxisHelper::createDefaultScale() +{ + ScaleData aScaleData; + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + aScaleData.AutoDateAxis = true; + aScaleData.ShiftedCategoryPosition = false; + Sequence< SubIncrement > aSubIncrements{ SubIncrement() }; + aScaleData.IncrementData.SubIncrements = aSubIncrements; + return aScaleData; +} + +void AxisHelper::removeExplicitScaling( ScaleData& rScaleData ) +{ + uno::Any aEmpty; + rScaleData.Minimum = rScaleData.Maximum = rScaleData.Origin = aEmpty; + rScaleData.Scaling = nullptr; + ScaleData aDefaultScale( createDefaultScale() ); + rScaleData.IncrementData = aDefaultScale.IncrementData; + rScaleData.TimeIncrement = aDefaultScale.TimeIncrement; +} + +bool AxisHelper::isLogarithmic( const Reference< XScaling >& xScaling ) +{ + Reference< lang::XServiceName > xServiceName( xScaling, uno::UNO_QUERY ); + return xServiceName.is() + && xServiceName->getServiceName() == "com.sun.star.chart2.LogarithmicScaling"; +} + +chart2::ScaleData AxisHelper::getDateCheckedScale( const rtl::Reference< Axis >& xAxis, ChartModel& rModel ) +{ + ScaleData aScale = xAxis->getScaleData(); + rtl::Reference< BaseCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( &rModel ) ); + if( aScale.AutoDateAxis && aScale.AxisType == AxisType::CATEGORY ) + { + sal_Int32 nDimensionIndex=0; sal_Int32 nAxisIndex=0; + AxisHelper::getIndicesForAxis(xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionIndex ); + if( bChartTypeAllowsDateAxis ) + aScale.AxisType = AxisType::DATE; + } + if( aScale.AxisType == AxisType::DATE ) + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel ); + if( !aExplicitCategoriesProvider.isDateAxis() ) + aScale.AxisType = AxisType::CATEGORY; + } + return aScale; +} + +void AxisHelper::checkDateAxis( chart2::ScaleData& rScale, ExplicitCategoriesProvider* pExplicitCategoriesProvider, bool bChartTypeAllowsDateAxis ) +{ + if( rScale.AutoDateAxis && rScale.AxisType == AxisType::CATEGORY && bChartTypeAllowsDateAxis ) + { + rScale.AxisType = AxisType::DATE; + removeExplicitScaling( rScale ); + } + if( rScale.AxisType == AxisType::DATE && (!pExplicitCategoriesProvider || !pExplicitCategoriesProvider->isDateAxis()) ) + { + rScale.AxisType = AxisType::CATEGORY; + removeExplicitScaling( rScale ); + } +} + +sal_Int32 AxisHelper::getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis + , const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem + , const rtl::Reference<ChartModel>& xChartDoc + , bool bSearchForParallelAxisIfNothingIsFound ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast<Axis*>(xAxis.get()); + assert(pAxis || !xAxis); + return getExplicitNumberFormatKeyForAxis(pAxis, xCorrespondingCoordinateSystem, xChartDoc, bSearchForParallelAxisIfNothingIsFound); +} + +sal_Int32 AxisHelper::getExplicitNumberFormatKeyForAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem + , const rtl::Reference<ChartModel>& xChartDoc + , bool bSearchForParallelAxisIfNothingIsFound ) +{ + sal_Int32 nNumberFormatKey(0); + sal_Int32 nAxisIndex = 0; + sal_Int32 nDimensionIndex = 1; + AxisHelper::getIndicesForAxis( xAxis, xCorrespondingCoordinateSystem, nDimensionIndex, nAxisIndex ); + + if (!xAxis.is()) + return 0; + + bool bLinkToSource = true; + xAxis->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource; + xAxis->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey; + + if (bLinkToSource) + { + bool bFormatSet = false; + //check whether we have a percent scale -> use percent format + if (xChartDoc) + { + ScaleData aData = AxisHelper::getDateCheckedScale( xAxis, *xChartDoc ); + if( aData.AxisType==AxisType::PERCENT ) + { + sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( xChartDoc ); + if( nPercentFormat != -1 ) + { + nNumberFormatKey = nPercentFormat; + bFormatSet = true; + } + } + else if( aData.AxisType==AxisType::DATE ) + { + if( aData.Categories.is() ) + { + Reference< data::XDataSequence > xSeq( aData.Categories->getValues()); + if( xSeq.is() && !( xChartDoc.is() && xChartDoc->hasInternalDataProvider()) ) + nNumberFormatKey = xSeq->getNumberFormatKeyByIndex( -1 ); + else + nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc ); + bFormatSet = true; + } + } + else if( xChartDoc.is() && xChartDoc->hasInternalDataProvider() && nDimensionIndex == 0 ) //maybe date axis + { + rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram() ); + if( DiagramHelper::isSupportingDateAxis( xDiagram ) ) + { + nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc ); + } + else + { + rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *xChartDoc ); + if( xSource.is() ) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aXValues( + DataSeriesHelper::getAllDataSequencesByRole( xSource->getDataSequences(), "values-x" ) ); + if( aXValues.empty() ) + { + uno::Reference< chart2::data::XLabeledDataSequence > xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram ) ); + if( xCategories.is() ) + { + Reference< data::XDataSequence > xSeq( xCategories->getValues()); + if( xSeq.is() ) + { + bool bHasValidDoubles = false; + double fTest=0.0; + Sequence< uno::Any > aCats( xSeq->getData() ); + sal_Int32 nCount = aCats.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + if( (aCats[i]>>=fTest) && !std::isnan(fTest) ) + { + bHasValidDoubles=true; + break; + } + } + if( bHasValidDoubles ) + nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc ); + } + } + } + } + } + bFormatSet = true; + } + } + + if( !bFormatSet ) + { + std::map< sal_Int32, sal_Int32 > aKeyMap; + bool bNumberFormatKeyFoundViaAttachedData = false; + + try + { + OUString aRoleToMatch; + if( nDimensionIndex == 0 ) + aRoleToMatch = "values-x"; + const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCorrespondingCoordinateSystem->getChartTypes2()); + for( rtl::Reference< ChartType > const & chartType : aChartTypes ) + { + if( nDimensionIndex != 0 ) + aRoleToMatch = ChartTypeHelper::getRoleOfSequenceForYAxisNumberFormatDetection( chartType ); + for( rtl::Reference< DataSeries > const & xDataSeries : chartType->getDataSeries2() ) + { + if( nDimensionIndex == 1 ) + { + //only take those series into account that are attached to this axis + sal_Int32 nAttachedAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + if( nAttachedAxisIndex != nAxisIndex ) + continue; + } + + Reference< data::XLabeledDataSequence > xLabeledSeq( + DataSeriesHelper::getDataSequenceByRole( xDataSeries, aRoleToMatch ) ); + + if( !xLabeledSeq.is() && nDimensionIndex==0 ) + { + ScaleData aData = xAxis->getScaleData(); + xLabeledSeq = aData.Categories; + } + + if( xLabeledSeq.is() ) + { + Reference< data::XDataSequence > xSeq( xLabeledSeq->getValues()); + if( xSeq.is() ) + { + sal_Int32 nKey = xSeq->getNumberFormatKeyByIndex( -1 ); + // increase frequency + aKeyMap[ nKey ] ++; + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( ! aKeyMap.empty()) + { + sal_Int32 nMaxFreq = 0; + // find most frequent key + for (auto const& elem : aKeyMap) + { + SAL_INFO( + "chart2.tools", + "NumberFormatKey " << elem.first << " appears " + << elem.second << " times"); + // all values must at least be 1 + if( elem.second > nMaxFreq ) + { + nNumberFormatKey = elem.first; + bNumberFormatKeyFoundViaAttachedData = true; + nMaxFreq = elem.second; + } + } + } + + if( bSearchForParallelAxisIfNothingIsFound ) + { + //no format is set to this axis and no data is set to this axis + //--> try to obtain the format from the parallel y-axis + if( !bNumberFormatKeyFoundViaAttachedData && nDimensionIndex == 1 ) + { + sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1; + rtl::Reference< Axis > xParallelAxis = AxisHelper::getAxis( 1, nParallelAxisIndex, xCorrespondingCoordinateSystem ); + nNumberFormatKey = AxisHelper::getExplicitNumberFormatKeyForAxis(xParallelAxis, xCorrespondingCoordinateSystem, xChartDoc, false); + } + } + } + } + + return nNumberFormatKey; +} + +rtl::Reference< Axis > AxisHelper::createAxis( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex // 0==main or 1==secondary axis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys + , const Reference< uno::XComponentContext > & xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + if( !xContext.is() || !xCooSys.is() ) + return nullptr; + if( nDimensionIndex >= xCooSys->getDimension() ) + return nullptr; + + rtl::Reference< Axis > xAxis = new Axis(); + + xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex ); + + if( nAxisIndex>0 )//when inserting secondary axes copy some things from the main axis + { + css::chart::ChartAxisPosition eNewAxisPos( css::chart::ChartAxisPosition_END ); + + rtl::Reference< Axis > xMainAxis = xCooSys->getAxisByDimension2( nDimensionIndex, 0 ); + if( xMainAxis.is() ) + { + ScaleData aScale = xAxis->getScaleData(); + ScaleData aMainScale = xMainAxis->getScaleData(); + + aScale.AxisType = aMainScale.AxisType; + aScale.AutoDateAxis = aMainScale.AutoDateAxis; + aScale.Categories = aMainScale.Categories; + aScale.Orientation = aMainScale.Orientation; + aScale.ShiftedCategoryPosition = aMainScale.ShiftedCategoryPosition; + + xAxis->setScaleData( aScale ); + + //ensure that the second axis is not placed on the main axis + css::chart::ChartAxisPosition eMainAxisPos( css::chart::ChartAxisPosition_ZERO ); + xMainAxis->getPropertyValue("CrossoverPosition") >>= eMainAxisPos; + if( eMainAxisPos == css::chart::ChartAxisPosition_END ) + eNewAxisPos = css::chart::ChartAxisPosition_START; + } + + xAxis->setPropertyValue("CrossoverPosition", uno::Any(eNewAxisPos) ); + } + + try + { + // set correct initial AutoScale + if( pRefSizeProvider ) + pRefSizeProvider->setValuesAtPropertySet( xAxis ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xAxis; +} + +rtl::Reference< Axis > AxisHelper::createAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram + , const Reference< uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + OSL_ENSURE( xContext.is(), "need a context to create an axis" ); + if( !xContext.is() ) + return nullptr; + + sal_Int32 nAxisIndex = bMainAxis ? MAIN_AXIS_INDEX : SECONDARY_AXIS_INDEX; + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ); + + // create axis + return AxisHelper::createAxis( + nDimensionIndex, nAxisIndex, xCooSys, xContext, pRefSizeProvider ); +} + +void AxisHelper::showAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram + , const Reference< uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + if( !xDiagram.is() ) + return; + + bool bNewAxisCreated = false; + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ); + if( !xAxis.is() && xContext.is() ) + { + // create axis + bNewAxisCreated = true; + xAxis = AxisHelper::createAxis( nDimensionIndex, bMainAxis, xDiagram, xContext, pRefSizeProvider ); + } + + OSL_ASSERT( xAxis.is()); + if( !bNewAxisCreated ) //default is true already if created + AxisHelper::makeAxisVisible( xAxis ); +} + +void AxisHelper::showGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< Diagram >& xDiagram ) +{ + if( !xDiagram.is() ) + return; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex ); + if(!xCooSys.is()) + return; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys ); + if(!xAxis.is()) + { + //hhhh todo create axis without axis visibility + } + if(!xAxis.is()) + return; + + if( bMainGrid ) + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + else + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( auto const & i : aSubGrids ) + AxisHelper::makeGridVisible( i ); + } +} + +void AxisHelper::makeAxisVisible( const rtl::Reference< Axis >& xAxis ) +{ + if( xAxis.is() ) + { + xAxis->setPropertyValue( "Show", uno::Any( true ) ); + LinePropertiesHelper::SetLineVisible( xAxis ); + xAxis->setPropertyValue( "DisplayLabels", uno::Any( true ) ); + } +} + +void AxisHelper::makeGridVisible( const Reference< beans::XPropertySet >& xGridProperties ) +{ + if( xGridProperties.is() ) + { + xGridProperties->setPropertyValue( "Show", uno::Any( true ) ); + LinePropertiesHelper::SetLineVisible( xGridProperties ); + } +} + +void AxisHelper::hideAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + AxisHelper::makeAxisInvisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) ); +} + +void AxisHelper::makeAxisInvisible( const rtl::Reference< Axis >& xAxis ) +{ + if( xAxis.is() ) + { + xAxis->setPropertyValue( "Show", uno::Any( false ) ); + } +} + +void AxisHelper::hideAxisIfNoDataIsAttached( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram ) +{ + //axis is hidden if no data is attached anymore but data is available + bool bOtherSeriesAttachedToThisAxis = false; + std::vector< rtl::Reference< DataSeries > > aSeriesVector = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + for (auto const& series : aSeriesVector) + { + rtl::Reference< Axis > xCurrentAxis = DiagramHelper::getAttachedAxis(series, xDiagram ); + if( xCurrentAxis==xAxis ) + { + bOtherSeriesAttachedToThisAxis = true; + break; + } + } + if(!bOtherSeriesAttachedToThisAxis && !aSeriesVector.empty() ) + AxisHelper::makeAxisInvisible( xAxis ); +} + +void AxisHelper::hideGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< Diagram >& xDiagram ) +{ + if( !xDiagram.is() ) + return; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex ); + if(!xCooSys.is()) + return; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys ); + if(!xAxis.is()) + return; + + if( bMainGrid ) + AxisHelper::makeGridInvisible( xAxis->getGridProperties() ); + else + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( auto const & i : aSubGrids) + AxisHelper::makeGridInvisible( i ); + } +} + +void AxisHelper::makeGridInvisible( const Reference< beans::XPropertySet >& xGridProperties ) +{ + if( xGridProperties.is() ) + { + xGridProperties->setPropertyValue( "Show", uno::Any( false ) ); + } +} + +bool AxisHelper::isGridShown( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< Diagram >& xDiagram ) +{ + bool bRet = false; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex ); + if(!xCooSys.is()) + return bRet; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys ); + if(!xAxis.is()) + return bRet; + + if( bMainGrid ) + bRet = AxisHelper::isGridVisible( xAxis->getGridProperties() ); + else + { + Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + if( aSubGrids.hasElements() ) + bRet = AxisHelper::isGridVisible( aSubGrids[0] ); + } + + return bRet; +} + +rtl::Reference< ::chart::BaseCoordinateSystem > AxisHelper::getCoordinateSystemByIndex( + const rtl::Reference< Diagram >& xDiagram, sal_Int32 nIndex ) +{ + if(!xDiagram.is()) + return nullptr; + auto & rCooSysList = xDiagram->getBaseCoordinateSystems(); + if(0<=nIndex && o3tl::make_unsigned(nIndex) < rCooSysList.size()) + return rCooSysList[nIndex]; + return nullptr; +} + +rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + rtl::Reference< Axis > xRet; + try + { + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ); + xRet = AxisHelper::getAxis( nDimensionIndex, bMainAxis ? 0 : 1, xCooSys ); + } + catch( const uno::Exception & ) + { + } + return xRet; +} + +rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + rtl::Reference< Axis > xRet; + if(!xCooSys.is()) + return xRet; + + if(nDimensionIndex >= xCooSys->getDimension()) + return xRet; + + if(nAxisIndex > xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex)) + return xRet; + + assert(nAxisIndex >= 0); + assert(nDimensionIndex >= 0); + xRet = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + return xRet; +} + +rtl::Reference< Axis > AxisHelper::getCrossingMainAxis( const Reference< chart2::XAxis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast<Axis*>(xAxis.get()); + assert(pAxis || !xAxis); + return getCrossingMainAxis(pAxis, xCooSys); +} + +rtl::Reference< Axis > AxisHelper::getCrossingMainAxis( const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + sal_Int32 nDimensionIndex = 0; + sal_Int32 nAxisIndex = 0; + AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + if( nDimensionIndex==2 ) + { + nDimensionIndex=1; + bool bSwapXY = false; + if( (xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXY) && bSwapXY ) + nDimensionIndex=0; + } + else if( nDimensionIndex==1 ) + nDimensionIndex=0; + else + nDimensionIndex=1; + return AxisHelper::getAxis( nDimensionIndex, 0, xCooSys ); +} + +rtl::Reference< Axis > AxisHelper::getParallelAxis( const Reference< XAxis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + try + { + sal_Int32 nCooSysIndex=-1; + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ) ) + { + sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1; + return getAxis( nDimensionIndex, nParallelAxisIndex, getCoordinateSystemByIndex( xDiagram, nCooSysIndex ) ); + } + } + catch( const uno::RuntimeException& ) + { + } + return nullptr; +} + +bool AxisHelper::isAxisShown( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + return AxisHelper::isAxisVisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) ); +} + +bool AxisHelper::isAxisVisible( const Reference< XAxis >& xAxis ) +{ + bool bRet = false; + + Reference< beans::XPropertySet > xProps( xAxis, uno::UNO_QUERY ); + if( xProps.is() ) + { + xProps->getPropertyValue( "Show" ) >>= bRet; + bRet = bRet && ( LinePropertiesHelper::IsLineVisible( xProps ) + || areAxisLabelsVisible( xProps ) ); + } + + return bRet; +} + +bool AxisHelper::areAxisLabelsVisible( const Reference< beans::XPropertySet >& xAxisProperties ) +{ + bool bRet = false; + if( xAxisProperties.is() ) + { + xAxisProperties->getPropertyValue( "DisplayLabels" ) >>= bRet; + } + return bRet; +} + +bool AxisHelper::isGridVisible( const Reference< beans::XPropertySet >& xGridproperties ) +{ + bool bRet = false; + + if( xGridproperties.is() ) + { + xGridproperties->getPropertyValue( "Show" ) >>= bRet; + bRet = bRet && LinePropertiesHelper::IsLineVisible( xGridproperties ); + } + + return bRet; +} + +Reference< beans::XPropertySet > AxisHelper::getGridProperties( + const rtl::Reference< BaseCoordinateSystem >& xCooSys + , sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex, sal_Int32 nSubGridIndex ) +{ + Reference< beans::XPropertySet > xRet; + + rtl::Reference< Axis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ) ); + if( xAxis.is() ) + { + if( nSubGridIndex<0 ) + xRet.set( xAxis->getGridProperties() ); + else + { + Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + if (nSubGridIndex < aSubGrids.getLength()) + xRet.set( aSubGrids[nSubGridIndex] ); + } + } + + return xRet; +} + +sal_Int32 AxisHelper::getDimensionIndexOfAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + sal_Int32 nDimensionIndex = -1; + sal_Int32 nCooSysIndex = -1; + sal_Int32 nAxisIndex = -1; + AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex , nDimensionIndex, nAxisIndex ); + return nDimensionIndex; +} + +bool AxisHelper::getIndicesForAxis( + const Reference< chart2::XAxis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys + , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast<Axis*>(xAxis.get()); + assert(pAxis || !xAxis); + return getIndicesForAxis(pAxis, xCooSys, rOutDimensionIndex, rOutAxisIndex); +} + +bool AxisHelper::getIndicesForAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys + , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + //returns true if indices are found + + rOutDimensionIndex = -1; + rOutAxisIndex = -1; + + if( !xCooSys || !xAxis ) + return false; + + rtl::Reference< Axis > xCurrentAxis; + sal_Int32 nDimensionCount( xCooSys->getDimension() ); + for( sal_Int32 nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ ) + { + sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ ) + { + xCurrentAxis = xCooSys->getAxisByDimension2(nDimensionIndex,nAxisIndex); + if( xCurrentAxis == xAxis ) + { + rOutDimensionIndex = nDimensionIndex; + rOutAxisIndex = nAxisIndex; + return true; + } + } + } + return false; +} + +bool AxisHelper::getIndicesForAxis( const Reference< chart2::XAxis >& xAxis, const rtl::Reference< Diagram >& xDiagram + , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast<Axis*>(xAxis.get()); + assert(pAxis || !xAxis); + return getIndicesForAxis(pAxis, xDiagram, rOutCooSysIndex, rOutDimensionIndex, rOutAxisIndex); +} + +bool AxisHelper::getIndicesForAxis( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram + , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + //returns true if indices are found + + rOutCooSysIndex = -1; + rOutDimensionIndex = -1; + rOutAxisIndex = -1; + + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList = xDiagram->getBaseCoordinateSystems(); + for( std::size_t nC=0; nC < aCooSysList.size(); ++nC ) + { + if( AxisHelper::getIndicesForAxis( xAxis, aCooSysList[nC], rOutDimensionIndex, rOutAxisIndex ) ) + { + rOutCooSysIndex = nC; + return true; + } + } + + return false; +} + +std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfCoordinateSystem( + const rtl::Reference< BaseCoordinateSystem >& xCooSys + , bool bOnlyVisible /* = false */ ) +{ + std::vector< rtl::Reference< Axis > > aAxisVector; + + if(xCooSys.is()) + { + sal_Int32 nMaxDimensionIndex = xCooSys->getDimension() -1; + if( nMaxDimensionIndex>=0 ) + { + sal_Int32 nDimensionIndex = 0; + for(; nDimensionIndex<=nMaxDimensionIndex; ++nDimensionIndex) + { + const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + try + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + if( xAxis.is() ) + { + bool bAddAxis = true; + if( bOnlyVisible ) + { + if( !(xAxis->getPropertyValue( "Show") >>= bAddAxis) ) + bAddAxis = false; + } + if( bAddAxis ) + aAxisVector.push_back( xAxis ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + } + + return aAxisVector; +} + +std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfDiagram( + const rtl::Reference< Diagram >& xDiagram + , bool bOnlyVisible ) +{ + std::vector< rtl::Reference< Axis > > aAxisVector; + + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + std::vector< rtl::Reference< Axis > > aAxesPerCooSys = AxisHelper::getAllAxesOfCoordinateSystem( coords, bOnlyVisible ); + aAxisVector.insert( aAxisVector.end(), aAxesPerCooSys.begin(), aAxesPerCooSys.end() ); + } + + return aAxisVector; +} + +Sequence< Reference< beans::XPropertySet > > AxisHelper::getAllGrids( const rtl::Reference< Diagram >& xDiagram ) +{ + const std::vector< rtl::Reference< Axis > > aAllAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + std::vector< Reference< beans::XPropertySet > > aGridVector; + + for( rtl::Reference< Axis > const & xAxis : aAllAxes ) + { + Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() ); + if( xGridProperties.is() ) + aGridVector.push_back( xGridProperties ); + + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( Reference< beans::XPropertySet > const & xSubGrid : aSubGrids ) + { + if( xSubGrid.is() ) + aGridVector.push_back( xSubGrid ); + } + } + + return comphelper::containerToSequence( aGridVector ); +} + +void AxisHelper::getAxisOrGridPossibilities( Sequence< sal_Bool >& rPossibilityList + , const rtl::Reference< Diagram>& xDiagram, bool bAxis ) +{ + rPossibilityList.realloc(6); + sal_Bool* pPossibilityList = rPossibilityList.getArray(); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + //set possibilities: + sal_Int32 nIndex=0; + rtl::Reference< ChartType > xChartType = DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + for(nIndex=0;nIndex<3;nIndex++) + pPossibilityList[nIndex]=ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nIndex); + for(nIndex=3;nIndex<6;nIndex++) + if( bAxis ) + pPossibilityList[nIndex]=ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount); + else + pPossibilityList[nIndex] = rPossibilityList[nIndex-3]; +} + +bool AxisHelper::isSecondaryYAxisNeeded( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + if( !xCooSys.is() ) + return false; + + const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & chartType : aChartTypes ) + { + const std::vector< rtl::Reference< DataSeries > > & aSeriesList = chartType->getDataSeries2(); + for( sal_Int32 nS = aSeriesList.size(); nS-- ; ) + { + sal_Int32 nAttachedAxisIndex = 0; + if( ( aSeriesList[nS]->getPropertyValue( "AttachedAxisIndex" ) >>= nAttachedAxisIndex ) && + nAttachedAxisIndex>0 ) + return true; + } + } + return false; +} + +bool AxisHelper::shouldAxisBeDisplayed( const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + bool bRet = false; + + if( xAxis.is() && xCooSys.is() ) + { + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) + { + sal_Int32 nDimensionCount = xCooSys->getDimension(); + rtl::Reference< ChartType > xChartType( AxisHelper::getChartTypeByIndex( xCooSys, 0 ) ); + + bool bMainAxis = (nAxisIndex==MAIN_AXIS_INDEX); + if( bMainAxis ) + bRet = ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nDimensionIndex); + else + bRet = ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount); + } + } + + return bRet; +} + +void AxisHelper::getAxisOrGridExistence( Sequence< sal_Bool >& rExistenceList + , const rtl::Reference< Diagram>& xDiagram, bool bAxis ) +{ + rExistenceList.realloc(6); + sal_Bool* pExistenceList = rExistenceList.getArray(); + + if(bAxis) + { + sal_Int32 nN; + for(nN=0;nN<3;nN++) + pExistenceList[nN] = AxisHelper::isAxisShown( nN, true, xDiagram ); + for(nN=3;nN<6;nN++) + pExistenceList[nN] = AxisHelper::isAxisShown( nN%3, false, xDiagram ); + } + else + { + sal_Int32 nN; + + for(nN=0;nN<3;nN++) + pExistenceList[nN] = AxisHelper::isGridShown( nN, 0, true, xDiagram ); + for(nN=3;nN<6;nN++) + pExistenceList[nN] = AxisHelper::isGridShown( nN%3, 0, false, xDiagram ); + } +} + +bool AxisHelper::changeVisibilityOfAxes( const rtl::Reference< Diagram >& xDiagram + , const Sequence< sal_Bool >& rOldExistenceList + , const Sequence< sal_Bool >& rNewExistenceList + , const Reference< uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + bool bChanged = false; + for(sal_Int32 nN=0;nN<6;nN++) + { + if(rOldExistenceList[nN]!=rNewExistenceList[nN]) + { + bChanged = true; + if(rNewExistenceList[nN]) + { + AxisHelper::showAxis( nN%3, nN<3, xDiagram, xContext, pRefSizeProvider ); + } + else + AxisHelper::hideAxis( nN%3, nN<3, xDiagram ); + } + } + return bChanged; +} + +bool AxisHelper::changeVisibilityOfGrids( const rtl::Reference< Diagram >& xDiagram + , const Sequence< sal_Bool >& rOldExistenceList + , const Sequence< sal_Bool >& rNewExistenceList ) +{ + bool bChanged = false; + for(sal_Int32 nN=0;nN<6;nN++) + { + if(rOldExistenceList[nN]!=rNewExistenceList[nN]) + { + bChanged = true; + if(rNewExistenceList[nN]) + AxisHelper::showGrid( nN%3, 0, nN<3, xDiagram ); + else + AxisHelper::hideGrid( nN%3, 0, nN<3, xDiagram ); + } + } + return bChanged; +} + +rtl::Reference< BaseCoordinateSystem > AxisHelper::getCoordinateSystemOfAxis( + const Reference< XAxis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast<Axis*>(xAxis.get()); + assert(pAxis || !xAxis); + return getCoordinateSystemOfAxis(pAxis, xDiagram); +} + +rtl::Reference< BaseCoordinateSystem > AxisHelper::getCoordinateSystemOfAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + if (!xDiagram) + return nullptr; + + rtl::Reference< BaseCoordinateSystem > xRet; + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + std::vector< rtl::Reference< Axis > > aAllAxis = AxisHelper::getAllAxesOfCoordinateSystem( xCooSys ); + + auto aFound = std::find( aAllAxis.begin(), aAllAxis.end(), xAxis ); + if( aFound != aAllAxis.end()) + { + xRet = xCooSys; + break; + } + } + return xRet; +} + +rtl::Reference< ChartType > AxisHelper::getChartTypeByIndex( const rtl::Reference< BaseCoordinateSystem >& xCooSys, sal_Int32 nIndex ) +{ + rtl::Reference< ChartType > xChartType; + + if( xCooSys.is() ) + { + const std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); + if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < aChartTypeList.size() ) + xChartType = aChartTypeList[nIndex]; + } + + return xChartType; +} + +void AxisHelper::setRTLAxisLayout( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + if( !xCooSys.is() ) + return; + + bool bCartesian = xCooSys->getViewServiceName() == CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME; + if( !bCartesian ) + return; + + bool bVertical = false; + xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bVertical; + + sal_Int32 nHorizontalAxisDimension = bVertical ? 1 : 0; + sal_Int32 nVerticalAxisDimension = bVertical ? 0 : 1; + + try + { + //reverse direction for horizontal main axis + rtl::Reference< Axis > xHorizontalMainAxis = AxisHelper::getAxis( nHorizontalAxisDimension, MAIN_AXIS_INDEX, xCooSys ); + if( xHorizontalMainAxis.is() ) + { + chart2::ScaleData aScale = xHorizontalMainAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_REVERSE; + xHorizontalMainAxis->setScaleData(aScale); + } + + //mathematical direction for vertical main axis + rtl::Reference< Axis > xVerticalMainAxis = AxisHelper::getAxis( nVerticalAxisDimension, MAIN_AXIS_INDEX, xCooSys ); + if( xVerticalMainAxis.is() ) + { + chart2::ScaleData aScale = xVerticalMainAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xVerticalMainAxis->setScaleData(aScale); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + + try + { + //reverse direction for horizontal secondary axis + rtl::Reference< Axis > xHorizontalSecondaryAxis = AxisHelper::getAxis( nHorizontalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys ); + if( xHorizontalSecondaryAxis.is() ) + { + chart2::ScaleData aScale = xHorizontalSecondaryAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_REVERSE; + xHorizontalSecondaryAxis->setScaleData(aScale); + } + + //mathematical direction for vertical secondary axis + rtl::Reference< Axis > xVerticalSecondaryAxis = AxisHelper::getAxis( nVerticalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys ); + if( xVerticalSecondaryAxis.is() ) + { + chart2::ScaleData aScale = xVerticalSecondaryAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xVerticalSecondaryAxis->setScaleData(aScale); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +rtl::Reference< ChartType > AxisHelper::getFirstChartTypeWithSeriesAttachedToAxisIndex( const rtl::Reference< Diagram >& xDiagram, const sal_Int32 nAttachedAxisIndex ) +{ + rtl::Reference< ChartType > xChartType; + std::vector< rtl::Reference< DataSeries > > aSeriesVector = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + for (auto const& series : aSeriesVector) + { + sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series); + if( nAttachedAxisIndex == nCurrentIndex ) + { + xChartType = DiagramHelper::getChartTypeOfSeries(xDiagram, series); + if(xChartType.is()) + break; + } + } + return xChartType; +} + +bool AxisHelper::isAxisPositioningEnabled() +{ + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(GetODFSaneDefaultVersion()); + return nCurrentVersion >= SvtSaveOptions::ODFSVER_012; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |