/* -*- 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 <GridProperties.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/diagnose_ex.hxx>
#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;
aScaleData.IncrementData.SubIncrements = { SubIncrement() };
return aScaleData;
}
void AxisHelper::removeExplicitScaling( ScaleData& rScaleData )
{
rScaleData.Minimum = rScaleData.Maximum = rScaleData.Origin = uno::Any();
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 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( xDiagram->isSupportingDateAxis() )
{
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(), u"values-x"_ustr ) );
if( aXValues.empty() )
{
uno::Reference< chart2::data::XLabeledDataSequence > xCategories( xDiagram->getCategories() );
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(u"CrossoverPosition"_ustr) >>= eMainAxisPos;
if( eMainAxisPos == css::chart::ChartAxisPosition_END )
eNewAxisPos = css::chart::ChartAxisPosition_START;
}
xAxis->setPropertyValue(u"CrossoverPosition"_ustr, 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
return;
}
if( bMainGrid )
AxisHelper::makeGridVisible( xAxis->getGridProperties2() );
else
{
std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
for( auto const & i : aSubGrids )
AxisHelper::makeGridVisible( i );
}
}
void AxisHelper::makeAxisVisible( const rtl::Reference< Axis >& xAxis )
{
if( xAxis.is() )
{
xAxis->setPropertyValue( u"Show"_ustr, uno::Any( true ) );
LinePropertiesHelper::SetLineVisible( xAxis );
xAxis->setPropertyValue( u"DisplayLabels"_ustr, uno::Any( true ) );
}
}
void AxisHelper::makeGridVisible( const rtl::Reference< GridProperties >& xGridProperties )
{
if( xGridProperties.is() )
{
xGridProperties->setPropertyValue( u"Show"_ustr, 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( u"Show"_ustr, 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 = xDiagram->getDataSeries();
for (auto const& series : aSeriesVector)
{
rtl::Reference< Axis > xCurrentAxis = xDiagram->getAttachedAxis(series);
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->getGridProperties2() );
else
{
std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
for( auto const & i : aSubGrids)
AxisHelper::makeGridInvisible( i );
}
}
void AxisHelper::makeGridInvisible( const rtl::Reference< ::chart::GridProperties >& xGridProperties )
{
if( xGridProperties.is() )
{
xGridProperties->setPropertyValue( u"Show"_ustr, 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->getGridProperties2() );
else
{
std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
if( !aSubGrids.empty() )
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 aCooSysList = xDiagram->getBaseCoordinateSystems();
if(0<=nIndex && o3tl::make_unsigned(nIndex) < aCooSysList.size())
return aCooSysList[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 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( u"SwapXAndYAxis"_ustr ) >>= 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 rtl::Reference< Axis >& 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 rtl::Reference< Axis >& xAxis )
{
bool bRet = false;
if( xAxis.is() )
{
xAxis->getPropertyValue( u"Show"_ustr ) >>= bRet;
bRet = bRet && ( LinePropertiesHelper::IsLineVisible( xAxis )
|| areAxisLabelsVisible( xAxis ) );
}
return bRet;
}
bool AxisHelper::areAxisLabelsVisible( const rtl::Reference< Axis >& xAxis )
{
bool bRet = false;
if( xAxis.is() )
{
xAxis->getPropertyValue( u"DisplayLabels"_ustr ) >>= bRet;
}
return bRet;
}
bool AxisHelper::isGridVisible( const rtl::Reference< ::chart::GridProperties >& xGridproperties )
{
bool bRet = false;
if( xGridproperties.is() )
{
xGridproperties->getPropertyValue( u"Show"_ustr ) >>= bRet;
bRet = bRet && LinePropertiesHelper::IsLineVisible( xGridproperties );
}
return bRet;
}
rtl::Reference< GridProperties > AxisHelper::getGridProperties(
const rtl::Reference< BaseCoordinateSystem >& xCooSys
, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex, sal_Int32 nSubGridIndex )
{
rtl::Reference< GridProperties > xRet;
rtl::Reference< Axis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ) );
if( xAxis.is() )
{
if( nSubGridIndex<0 )
xRet = xAxis->getGridProperties2();
else
{
std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
if (nSubGridIndex < static_cast<sal_Int32>(aSubGrids.size()))
xRet = 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 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 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( u"Show"_ustr) >>= 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;
}
std::vector< rtl::Reference< GridProperties > > AxisHelper::getAllGrids( const rtl::Reference< Diagram >& xDiagram )
{
const std::vector< rtl::Reference< Axis > > aAllAxes = AxisHelper::getAllAxesOfDiagram( xDiagram );
std::vector< rtl::Reference< GridProperties > > aGridVector;
for( rtl::Reference< Axis > const & xAxis : aAllAxes )
{
rtl::Reference< GridProperties > xGridProperties( xAxis->getGridProperties2() );
if( xGridProperties.is() )
aGridVector.push_back( xGridProperties );
std::vector< rtl::Reference< GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
for( rtl::Reference< GridProperties > const & xSubGrid : aSubGrids )
{
if( xSubGrid.is() )
aGridVector.push_back( xSubGrid );
}
}
return 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 = -1;
if (xDiagram)
nDimensionCount = xDiagram->getDimension();
//set possibilities:
sal_Int32 nIndex=0;
rtl::Reference< ChartType > xChartType;
if (xDiagram)
xChartType = xDiagram->getChartTypeByIndex( 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( u"AttachedAxisIndex"_ustr ) >>= 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 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( u"SwapXAndYAxis"_ustr ) >>= 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 = xDiagram->getDataSeries();
for (auto const& series : aSeriesVector)
{
sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series);
if( nAttachedAxisIndex == nCurrentIndex )
{
xChartType = xDiagram->getChartTypeOfSeries(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: */
↑ V547 Expression 'bLinkToSource' is always true.
↑ V547 Expression 'bVertical' is always false.
↑ V547 Expression 'bVertical' is always false.