office-gobmx/chart2/source/tools/DiagramHelper.cxx
2011-03-29 21:39:42 +01:00

1740 lines
67 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "DiagramHelper.hxx"
#include "LegendHelper.hxx"
#include "PropertyHelper.hxx"
#include "macros.hxx"
#include "DataSeriesHelper.hxx"
#include "AxisHelper.hxx"
#include "ContainerHelper.hxx"
#include "ChartTypeHelper.hxx"
#include "ChartModelHelper.hxx"
#include "CommonConverters.hxx"
#include "ExplicitCategoriesProvider.hxx"
#include "servicenames_charttypes.hxx"
#include "ChartModelHelper.hxx"
#include "RelativePositionHelper.hxx"
#include "ControllerLockGuard.hxx"
#include "NumberFormatterWrapper.hxx"
#include <com/sun/star/chart/MissingValueTreatment.hpp>
#include <com/sun/star/chart/XChartDocument.hpp>
#include <com/sun/star/chart/XDiagramPositioning.hpp>
#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
#include <com/sun/star/chart2/XTitled.hpp>
#include <com/sun/star/chart2/XChartTypeContainer.hpp>
#include <com/sun/star/chart2/XChartTypeTemplate.hpp>
#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
#include <com/sun/star/chart2/InterpretedData.hpp>
#include <com/sun/star/chart2/AxisType.hpp>
#include <com/sun/star/chart2/DataPointGeometry3D.hpp>
#include <com/sun/star/chart2/RelativePosition.hpp>
#include <com/sun/star/chart2/RelativeSize.hpp>
#include <com/sun/star/util/NumberFormat.hpp>
#include <com/sun/star/util/XModifiable.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <unotools/saveopt.hxx>
#include <rtl/math.hxx>
#include <svl/zformat.hxx>
// header for class Application
#include <vcl/svapp.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::chart2;
using namespace ::std;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Any;
using ::rtl::OUString;
using ::com::sun::star::chart2::XAnyDescriptionAccess;
namespace chart
{
DiagramHelper::tTemplateWithServiceName
DiagramHelper::getTemplateForDiagram(
const Reference< XDiagram > & xDiagram,
const Reference< lang::XMultiServiceFactory > & xChartTypeManager,
const OUString & rPreferredTemplateName )
{
DiagramHelper::tTemplateWithServiceName aResult;
if( ! (xChartTypeManager.is() && xDiagram.is()))
return aResult;
Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames());
const sal_Int32 nLength = aServiceNames.getLength();
bool bHasPreferredTemplate = (rPreferredTemplateName.getLength() > 0);
bool bTemplateFound = false;
if( bHasPreferredTemplate )
{
Reference< XChartTypeTemplate > xTempl(
xChartTypeManager->createInstance( rPreferredTemplateName ), uno::UNO_QUERY );
if( xTempl.is() &&
xTempl->matchesTemplate( xDiagram, sal_True ))
{
aResult.first = xTempl;
aResult.second = rPreferredTemplateName;
bTemplateFound = true;
}
}
for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i )
{
try
{
if( ! bHasPreferredTemplate ||
! rPreferredTemplateName.equals( aServiceNames[ i ] ))
{
Reference< XChartTypeTemplate > xTempl(
xChartTypeManager->createInstance( aServiceNames[ i ] ), uno::UNO_QUERY_THROW );
if( xTempl->matchesTemplate( xDiagram, sal_True ))
{
aResult.first = xTempl;
aResult.second = aServiceNames[ i ];
bTemplateFound = true;
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
return aResult;
}
void DiagramHelper::setVertical(
const Reference< XDiagram > & xDiagram,
bool bVertical /* = true */ )
{
try
{
Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
if( xCnt.is())
{
Sequence< Reference< XCoordinateSystem > > aCooSys(
xCnt->getCoordinateSystems());
uno::Any aValue;
aValue <<= bVertical;
for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
{
uno::Reference< XCoordinateSystem > xCooSys( aCooSys[i] );
Reference< beans::XPropertySet > xProp( xCooSys, uno::UNO_QUERY );
bool bChanged = false;
if( xProp.is() )
{
bool bOldSwap = sal_False;
if( !(xProp->getPropertyValue( C2U("SwapXAndYAxis") ) >>= bOldSwap)
|| bVertical != bOldSwap )
bChanged = true;
if( bChanged )
xProp->setPropertyValue( C2U("SwapXAndYAxis"), aValue );
}
if( xCooSys.is() )
{
const sal_Int32 nDimensionCount( xCooSys->getDimension() );
sal_Int32 nDimIndex = 0;
for(nDimIndex=0; nDimIndex<nDimensionCount; ++nDimIndex)
{
const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
{
Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimIndex,nI ));
if( xAxis.is() )
{
//adapt title rotation only when axis swapping has changed
if( bChanged )
{
Reference< XTitled > xTitled( xAxis, uno::UNO_QUERY );
if( xTitled.is())
{
Reference< beans::XPropertySet > xTitleProps( xTitled->getTitleObject(), uno::UNO_QUERY );
if( !xTitleProps.is() )
continue;
double fAngleDegree = 0.0;
xTitleProps->getPropertyValue( C2U( "TextRotation" ) ) >>= fAngleDegree;
if( !::rtl::math::approxEqual( fAngleDegree, 0.0 )
&& !::rtl::math::approxEqual( fAngleDegree, 90.0 ) )
continue;
double fNewAngleDegree = 0.0;
if( !bVertical && nDimIndex == 1 )
fNewAngleDegree = 90.0;
else if( bVertical && nDimIndex == 0 )
fNewAngleDegree = 90.0;
xTitleProps->setPropertyValue( C2U( "TextRotation" ), uno::makeAny( fNewAngleDegree ));
}
}
}
}
}
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
bool DiagramHelper::getVertical( const uno::Reference< chart2::XDiagram > & xDiagram,
bool& rbFound, bool& rbAmbiguous )
{
bool bValue = false;
rbFound = false;
rbAmbiguous = false;
Reference< XCoordinateSystemContainer > xCnt( xDiagram, uno::UNO_QUERY );
if( xCnt.is())
{
Sequence< Reference< XCoordinateSystem > > aCooSys(
xCnt->getCoordinateSystems());
for( sal_Int32 i=0; i<aCooSys.getLength(); ++i )
{
Reference< beans::XPropertySet > xProp( aCooSys[i], uno::UNO_QUERY );
if( xProp.is())
{
bool bCurrent = false;
if( xProp->getPropertyValue( C2U("SwapXAndYAxis") ) >>= bCurrent )
{
if( !rbFound )
{
bValue = bCurrent;
rbFound = true;
}
else if( bCurrent != bValue )
{
// ambiguous -> choose always first found
rbAmbiguous = true;
}
}
}
}
}
return bValue;
}
void DiagramHelper::setStackMode(
const Reference< XDiagram > & xDiagram,
StackMode eStackMode,
bool bOnlyAtFirstChartType /* = true */
)
{
try
{
if( eStackMode == StackMode_AMBIGUOUS )
return;
bool bValueFound = false;
bool bIsAmbiguous = false;
StackMode eOldStackMode = DiagramHelper::getStackMode( xDiagram, bValueFound, bIsAmbiguous );
if( eStackMode == eOldStackMode && !bIsAmbiguous )
return;
StackingDirection eNewDirection = StackingDirection_NO_STACKING;
if( eStackMode == StackMode_Y_STACKED || eStackMode == StackMode_Y_STACKED_PERCENT )
eNewDirection = StackingDirection_Y_STACKING;
else if( eStackMode == StackMode_Z_STACKED )
eNewDirection = StackingDirection_Z_STACKING;
uno::Any aNewDirection( uno::makeAny(eNewDirection) );
sal_Bool bPercent = sal_False;
if( eStackMode == StackMode_Y_STACKED_PERCENT )
bPercent = sal_True;
//iterate through all coordinate systems
uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
if( !xCooSysContainer.is() )
return;
uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
{
uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
//set correct percent stacking
const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1);
for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
{
Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI ));
if( xAxis.is())
{
chart2::ScaleData aScaleData = xAxis->getScaleData();
if( (aScaleData.AxisType==AxisType::PERCENT) != bPercent )
{
if( bPercent )
aScaleData.AxisType = AxisType::PERCENT;
else
aScaleData.AxisType = AxisType::REALNUMBER;
xAxis->setScaleData( aScaleData );
}
}
}
//iterate through all chart types in the current coordinate system
uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
if( !xChartTypeContainer.is() )
continue;
uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
sal_Int32 nMax = aChartTypeList.getLength();
if( bOnlyAtFirstChartType
&& nMax >= 1 )
nMax = 1;
for( sal_Int32 nT = 0; nT < nMax; ++nT )
{
uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
//iterate through all series in this chart type
uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
OSL_ASSERT( xDataSeriesContainer.is());
if( !xDataSeriesContainer.is() )
continue;
uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
{
Reference< beans::XPropertySet > xProp( aSeriesList[nS], uno::UNO_QUERY );
if(xProp.is())
xProp->setPropertyValue( C2U( "StackingDirection" ), aNewDirection );
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
StackMode DiagramHelper::getStackMode( const Reference< XDiagram > & xDiagram, bool& rbFound, bool& rbAmbiguous )
{
rbFound=false;
rbAmbiguous=false;
StackMode eGlobalStackMode = StackMode_NONE;
//iterate through all coordinate systems
uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
if( !xCooSysContainer.is() )
return eGlobalStackMode;
uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
{
uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
//iterate through all chart types in the current coordinate system
uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
if( !xChartTypeContainer.is() )
continue;
uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
{
uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType(
xChartType, rbFound, rbAmbiguous, xCooSys );
if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 )
{
rbAmbiguous = true;
return eGlobalStackMode;
}
eGlobalStackMode = eLocalStackMode;
}
}
return eGlobalStackMode;
}
StackMode DiagramHelper::getStackModeFromChartType(
const Reference< XChartType > & xChartType,
bool& rbFound, bool& rbAmbiguous,
const Reference< XCoordinateSystem > & xCorrespondingCoordinateSystem )
{
StackMode eStackMode = StackMode_NONE;
rbFound = false;
rbAmbiguous = false;
try
{
Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
Sequence< Reference< chart2::XDataSeries > > aSeries( xDSCnt->getDataSeries());
chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING;
bool bDirectionInitialized = false;
// first series is irrelvant for stacking, start with second, unless
// there is only one series
const sal_Int32 nSeriesCount = aSeries.getLength();
sal_Int32 i = (nSeriesCount == 1) ? 0: 1;
for( ; i<nSeriesCount; ++i )
{
rbFound = true;
Reference< beans::XPropertySet > xProp( aSeries[i], uno::UNO_QUERY_THROW );
chart2::StackingDirection eCurrentDirection = eCommonDirection;
// property is not MAYBEVOID
bool bSuccess = ( xProp->getPropertyValue( C2U("StackingDirection") ) >>= eCurrentDirection );
OSL_ASSERT( bSuccess );
(void)(bSuccess); // avoid warning in non-debug builds
if( ! bDirectionInitialized )
{
eCommonDirection = eCurrentDirection;
bDirectionInitialized = true;
}
else
{
if( eCommonDirection != eCurrentDirection )
{
rbAmbiguous = true;
break;
}
}
}
if( rbFound )
{
if( eCommonDirection == chart2::StackingDirection_Z_STACKING )
eStackMode = StackMode_Z_STACKED;
else if( eCommonDirection == chart2::StackingDirection_Y_STACKING )
{
eStackMode = StackMode_Y_STACKED;
// percent stacking
if( xCorrespondingCoordinateSystem.is() )
{
if( 1 < xCorrespondingCoordinateSystem->getDimension() )
{
sal_Int32 nAxisIndex = 0;
if( nSeriesCount )
nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(aSeries[0]);
Reference< chart2::XAxis > xAxis(
xCorrespondingCoordinateSystem->getAxisByDimension( 1,nAxisIndex ));
if( xAxis.is())
{
chart2::ScaleData aScaleData = xAxis->getScaleData();
if( aScaleData.AxisType==chart2::AxisType::PERCENT )
eStackMode = StackMode_Y_STACKED_PERCENT;
}
}
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
return eStackMode;
}
sal_Int32 DiagramHelper::getDimension( const Reference< XDiagram > & xDiagram )
{
// -1: not yet set
sal_Int32 nResult = -1;
try
{
Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
if( xCooSysCnt.is() )
{
Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
xCooSysCnt->getCoordinateSystems());
for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
{
Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
if(xCooSys.is())
{
nResult = xCooSys->getDimension();
break;
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
return nResult;
}
void DiagramHelper::setDimension(
const Reference< XDiagram > & xDiagram,
sal_Int32 nNewDimensionCount )
{
if( ! xDiagram.is())
return;
if( DiagramHelper::getDimension( xDiagram ) == nNewDimensionCount )
return;
try
{
bool rbFound = false;
bool rbAmbiguous = true;
StackMode eStackMode = DiagramHelper::getStackMode( xDiagram, rbFound, rbAmbiguous );
bool bIsSupportingOnlyDeepStackingFor3D=false;
//change all coordinate systems:
Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
{
Reference< XCoordinateSystem > xOldCooSys( aCooSysList[nCS], uno::UNO_QUERY );
Reference< XCoordinateSystem > xNewCooSys;
Reference< XChartTypeContainer > xChartTypeContainer( xOldCooSys, uno::UNO_QUERY );
if( !xChartTypeContainer.is() )
continue;
Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
{
Reference< XChartType > xChartType( aChartTypeList[nT], uno::UNO_QUERY );
bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType );
if(!xNewCooSys.is())
{
xNewCooSys = xChartType->createCoordinateSystem( nNewDimensionCount );
break;
}
//@todo make sure that all following charttypes are also capable of the new dimension
//otherwise separate them in a different group
//BM: might be done in replaceCoordinateSystem()
}
// replace the old coordinate system at all places where it was used
DiagramHelper::replaceCoordinateSystem( xDiagram, xOldCooSys, xNewCooSys );
}
//correct stack mode if necessary
if( nNewDimensionCount==3 && eStackMode != StackMode_Z_STACKED && bIsSupportingOnlyDeepStackingFor3D )
DiagramHelper::setStackMode( xDiagram, StackMode_Z_STACKED );
else if( nNewDimensionCount==2 && eStackMode == StackMode_Z_STACKED )
DiagramHelper::setStackMode( xDiagram, StackMode_NONE );
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
void DiagramHelper::replaceCoordinateSystem(
const Reference< XDiagram > & xDiagram,
const Reference< XCoordinateSystem > & xCooSysToReplace,
const Reference< XCoordinateSystem > & xReplacement )
{
OSL_ASSERT( xDiagram.is());
if( ! xDiagram.is())
return;
// update the coordinate-system container
Reference< XCoordinateSystemContainer > xCont( xDiagram, uno::UNO_QUERY );
if( xCont.is())
{
try
{
Reference< chart2::data::XLabeledDataSequence > xCategories = DiagramHelper::getCategoriesFromDiagram( xDiagram );
// move chart types of xCooSysToReplace to xReplacement
Reference< XChartTypeContainer > xCTCntCooSys( xCooSysToReplace, uno::UNO_QUERY_THROW );
Reference< XChartTypeContainer > xCTCntReplacement( xReplacement, uno::UNO_QUERY_THROW );
xCTCntReplacement->setChartTypes( xCTCntCooSys->getChartTypes());
xCont->removeCoordinateSystem( xCooSysToReplace );
xCont->addCoordinateSystem( xReplacement );
if( xCategories.is() )
DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram );
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
}
bool DiagramHelper::isSeriesAttachedToMainAxis(
const uno::Reference< chart2::XDataSeries >& xDataSeries )
{
sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
return (nAxisIndex==0);
}
bool DiagramHelper::attachSeriesToAxis( bool bAttachToMainAxis
, const uno::Reference< chart2::XDataSeries >& xDataSeries
, const uno::Reference< chart2::XDiagram >& xDiagram
, const uno::Reference< uno::XComponentContext > & xContext
, bool bAdaptAxes )
{
bool bChanged = false;
//set property at axis
Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW );
if( !xProp.is() )
return bChanged;
sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1;
sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
uno::Reference< chart2::XAxis > xOldAxis( DiagramHelper::getAttachedAxis( xDataSeries, xDiagram ) );
if( nOldAxisIndex != nNewAxisIndex )
{
try
{
xProp->setPropertyValue( C2U("AttachedAxisIndex"), uno::makeAny( nNewAxisIndex ) );
bChanged = true;
}
catch( const uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
if( bChanged && xDiagram.is() )
{
uno::Reference< XAxis > xAxis( AxisHelper::getAxis( 1, bAttachToMainAxis, xDiagram ) );
if(!xAxis.is()) //create an axis if necessary
xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, xDiagram, xContext );
if( bAdaptAxes )
{
AxisHelper::makeAxisVisible( xAxis );
AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, xDiagram );
}
}
return bChanged;
}
uno::Reference< XAxis > DiagramHelper::getAttachedAxis(
const uno::Reference< XDataSeries >& xSeries,
const uno::Reference< XDiagram >& xDiagram )
{
return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram );
}
uno::Reference< XChartType > DiagramHelper::getChartTypeOfSeries(
const uno::Reference< chart2::XDiagram >& xDiagram
, const uno::Reference< XDataSeries >& xGivenDataSeries )
{
if( !xGivenDataSeries.is() )
return 0;
if(!xDiagram.is())
return 0;
//iterate through the model to find the given xSeries
//the found parent indicates the charttype
//iterate through all coordinate systems
uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
if( !xCooSysContainer.is())
return 0;
uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
{
uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
//iterate through all chart types in the current coordinate system
uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
OSL_ASSERT( xChartTypeContainer.is());
if( !xChartTypeContainer.is() )
continue;
uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
{
uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
//iterate through all series in this chart type
uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
OSL_ASSERT( xDataSeriesContainer.is());
if( !xDataSeriesContainer.is() )
continue;
uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
{
if( xGivenDataSeries==aSeriesList[nS] )
return xChartType;
}
}
}
return 0;
}
::std::vector< Reference< XDataSeries > >
DiagramHelper::getDataSeriesFromDiagram(
const Reference< XDiagram > & xDiagram )
{
::std::vector< Reference< XDataSeries > > aResult;
try
{
Reference< XCoordinateSystemContainer > xCooSysCnt(
xDiagram, uno::UNO_QUERY_THROW );
Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
xCooSysCnt->getCoordinateSystems());
for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
{
Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
for( sal_Int32 j=0; j<aChartTypeSeq.getLength(); ++j )
{
Reference< XDataSeriesContainer > xDSCnt( aChartTypeSeq[j], uno::UNO_QUERY_THROW );
Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
::std::copy( aSeriesSeq.getConstArray(), aSeriesSeq.getConstArray() + aSeriesSeq.getLength(),
::std::back_inserter( aResult ));
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
return aResult;
}
Sequence< Sequence< Reference< XDataSeries > > >
DiagramHelper::getDataSeriesGroups( const Reference< XDiagram > & xDiagram )
{
vector< Sequence< Reference< XDataSeries > > > aResult;
//iterate through all coordinate systems
Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
if( xCooSysContainer.is() )
{
Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
{
//iterate through all chart types in the current coordinate system
Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
if( !xChartTypeContainer.is() )
continue;
Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
{
Reference< XDataSeriesContainer > xDataSeriesContainer( aChartTypeList[nT], uno::UNO_QUERY );
if( !xDataSeriesContainer.is() )
continue;
aResult.push_back( xDataSeriesContainer->getDataSeries() );
}
}
}
return ContainerHelper::ContainerToSequence( aResult );
}
Reference< XChartType >
DiagramHelper::getChartTypeByIndex( const Reference< XDiagram >& xDiagram, sal_Int32 nIndex )
{
Reference< XChartType > xChartType;
//iterate through all coordinate systems
Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
if( ! xCooSysContainer.is())
return xChartType;
Sequence< Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
sal_Int32 nTypesSoFar = 0;
for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
{
Reference< XChartTypeContainer > xChartTypeContainer( aCooSysList[nCS], uno::UNO_QUERY );
if( !xChartTypeContainer.is() )
continue;
Sequence< Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
if( nIndex >= 0 && nIndex < (nTypesSoFar + aChartTypeList.getLength()) )
{
xChartType.set( aChartTypeList[nIndex - nTypesSoFar] );
break;
}
nTypesSoFar += aChartTypeList.getLength();
}
return xChartType;
}
namespace
{
std::vector< Reference< XAxis > > lcl_getAxisHoldingCategoriesFromDiagram(
const Reference< XDiagram > & xDiagram )
{
std::vector< Reference< XAxis > > aRet;
Reference< XAxis > xResult;
// return first x-axis as fall-back
Reference< XAxis > xFallBack;
try
{
Reference< XCoordinateSystemContainer > xCooSysCnt(
xDiagram, uno::UNO_QUERY_THROW );
Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
xCooSysCnt->getCoordinateSystems());
for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
{
Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
OSL_ASSERT( xCooSys.is());
for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
{
const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
{
Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
OSL_ASSERT( xAxis.is());
if( xAxis.is())
{
ScaleData aScaleData = xAxis->getScaleData();
if( aScaleData.Categories.is() || (aScaleData.AxisType == AxisType::CATEGORY) )
{
aRet.push_back(xAxis);
}
if( (nN == 0) && !xFallBack.is())
xFallBack.set( xAxis );
}
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
if( aRet.empty() )
aRet.push_back(xFallBack);
return aRet;
}
} // anonymous namespace
bool DiagramHelper::isCategoryDiagram(
const Reference< XDiagram >& xDiagram )
{
try
{
Reference< XCoordinateSystemContainer > xCooSysCnt(
xDiagram, uno::UNO_QUERY_THROW );
Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
xCooSysCnt->getCoordinateSystems());
for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
{
Reference< XCoordinateSystem > xCooSys( aCooSysSeq[i] );
OSL_ASSERT( xCooSys.is());
for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
{
const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
{
Reference< XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
OSL_ASSERT( xAxis.is());
if( xAxis.is())
{
ScaleData aScaleData = xAxis->getScaleData();
if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
return true;
}
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
return false;
}
void DiagramHelper::setCategoriesToDiagram(
const Reference< chart2::data::XLabeledDataSequence >& xCategories,
const Reference< XDiagram >& xDiagram,
bool bSetAxisType /* = false */,
bool bCategoryAxis /* = true */ )
{
std::vector< Reference< chart2::XAxis > > aCatAxes(
lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
std::vector< Reference< chart2::XAxis > >::iterator aIt( aCatAxes.begin() );
std::vector< Reference< chart2::XAxis > >::const_iterator aEnd( aCatAxes.end() );
for( aIt = aCatAxes.begin(); aIt != aEnd; ++aIt )
{
Reference< chart2::XAxis > xCatAxis(*aIt);
if( xCatAxis.is())
{
ScaleData aScaleData( xCatAxis->getScaleData());
aScaleData.Categories = xCategories;
if( bSetAxisType )
{
if( bCategoryAxis )
aScaleData.AxisType = AxisType::CATEGORY;
else if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE )
aScaleData.AxisType = AxisType::REALNUMBER;
}
xCatAxis->setScaleData( aScaleData );
}
}
}
Reference< data::XLabeledDataSequence >
DiagramHelper::getCategoriesFromDiagram(
const Reference< XDiagram > & xDiagram )
{
Reference< data::XLabeledDataSequence > xResult;
try
{
std::vector< Reference< chart2::XAxis > > aCatAxes(
lcl_getAxisHoldingCategoriesFromDiagram( xDiagram ));
std::vector< Reference< chart2::XAxis > >::iterator aIt( aCatAxes.begin() );
std::vector< Reference< chart2::XAxis > >::const_iterator aEnd( aCatAxes.end() );
//search for first categories
if( aIt != aEnd )
{
Reference< chart2::XAxis > xCatAxis(*aIt);
if( xCatAxis.is())
{
ScaleData aScaleData( xCatAxis->getScaleData());
if( aScaleData.Categories.is() )
{
xResult.set( aScaleData.Categories );
uno::Reference<beans::XPropertySet> xProp(aScaleData.Categories->getValues(), uno::UNO_QUERY );
if( xProp.is() )
{
try
{
xProp->setPropertyValue( C2U( "Role" ), uno::makeAny( C2U("categories") ) );
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
}
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
return xResult;
}
void lcl_generateAutomaticCategoriesFromChartType(
Sequence< rtl::OUString >& rRet,
const Reference< XChartType >& xChartType )
{
if(!xChartType.is())
return;
rtl::OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() );
Reference< XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY );
if( xSeriesCnt.is() )
{
Sequence< Reference< XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries() );
for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
{
Reference< data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
if( !xDataSource.is() )
continue;
Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aMainSeq ));
if( !xLabeledSeq.is() )
continue;
Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() );
if( !xValueSeq.is() )
continue;
rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE );
if( rRet.getLength() )
return;
}
}
}
Sequence< rtl::OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const Reference< XCoordinateSystem > & xCooSys )
{
Sequence< rtl::OUString > aRet;
Reference< XChartTypeContainer > xTypeCntr( xCooSys, uno::UNO_QUERY );
if( xTypeCntr.is() )
{
Sequence< Reference< XChartType > > aChartTypes( xTypeCntr->getChartTypes() );
for( sal_Int32 nN=0; nN<aChartTypes.getLength(); nN++ )
{
lcl_generateAutomaticCategoriesFromChartType( aRet, aChartTypes[nN] );
if( aRet.getLength() )
return aRet;
}
}
return aRet;
}
Sequence< rtl::OUString > DiagramHelper::getExplicitSimpleCategories(
const Reference< XChartDocument >& xChartDoc )
{
Sequence< rtl::OUString > aRet;
uno::Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
if(xChartModel.is())
{
uno::Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, xChartModel );
aRet = aExplicitCategoriesProvider.getSimpleCategories();
}
return aRet;
}
namespace
{
void lcl_switchToDateCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
{
if( !xAxis.is() )
return;
if( !xChartDoc.is() )
return;
ScaleData aScale( xAxis->getScaleData() );
if( xChartDoc->hasInternalDataProvider() )
{
//remove all content the is not of type double and remove multiple level
Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY );
if( xDataAccess.is() )
{
Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() );
double fTest = 0.0;
double fNan = 0.0;
::rtl::math::setNan( & fNan );
sal_Int32 nN = aAnyCategories.getLength();
for( ; nN--; )
{
Sequence< Any >& rCat = aAnyCategories[nN];
if( rCat.getLength() > 1 )
rCat.realloc(1);
if( rCat.getLength() == 1 )
{
Any& rAny = rCat[0];
if( !(rAny>>=fTest) )
{
rAny = uno::makeAny(fNan);
}
}
}
xDataAccess->setAnyRowDescriptions( aAnyCategories );
}
//check the numberformat at the axis
Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY );
Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartDoc, uno::UNO_QUERY );
if( xAxisProps.is() && xNumberFormatsSupplier.is() )
{
sal_Int32 nNumberFormat = -1;
xAxisProps->getPropertyValue( C2U("NumberFormat") ) >>= nNumberFormat;
Reference< util::XNumberFormats > xNumberFormats = Reference< util::XNumberFormats >( xNumberFormatsSupplier->getNumberFormats() );
if( xNumberFormats.is() )
{
Reference< beans::XPropertySet > xKeyProps;
try
{
xKeyProps = xNumberFormats->getByKey( nNumberFormat );
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
sal_Int32 nType = util::NumberFormat::UNDEFINED;
if( xKeyProps.is() )
xKeyProps->getPropertyValue( C2U("Type") ) >>= nType;
if( !( nType & util::NumberFormat::DATE ) )
{
//set a date format to the axis
sal_Bool bCreate = sal_True;
const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE, rLocaleDataWrapper.getLocale(), bCreate );
if( aKeySeq.getLength() )
{
xAxisProps->setPropertyValue( C2U("NumberFormat"), uno::makeAny(aKeySeq[0]) );
}
}
}
}
}
if( aScale.AxisType != chart2::AxisType::DATE )
AxisHelper::removeExplicitScaling( aScale );
aScale.AxisType = chart2::AxisType::DATE;
xAxis->setScaleData( aScale );
}
void lcl_switchToTextCategories( const Reference< XChartDocument >& xChartDoc, const Reference< XAxis >& xAxis )
{
if( !xAxis.is() )
return;
if( !xChartDoc.is() )
return;
ScaleData aScale( xAxis->getScaleData() );
if( aScale.AxisType != chart2::AxisType::CATEGORY )
AxisHelper::removeExplicitScaling( aScale );
//todo migrate dates to text?
aScale.AxisType = chart2::AxisType::CATEGORY;
aScale.AutoDateAxis = false;
xAxis->setScaleData( aScale );
}
}
void DiagramHelper::switchToDateCategories( const Reference< XChartDocument >& xChartDoc )
{
Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
if(xChartModel.is())
{
ControllerLockGuard aCtrlLockGuard( xChartModel );
Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
if( xCooSys.is() )
{
Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
lcl_switchToDateCategories( xChartDoc, xAxis );
}
}
}
void DiagramHelper::switchToTextCategories( const Reference< XChartDocument >& xChartDoc )
{
Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
if(xChartModel.is())
{
ControllerLockGuard aCtrlLockGuard( xChartModel );
Reference< chart2::XCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( xChartModel ) );
if( xCooSys.is() )
{
Reference< XAxis > xAxis( xCooSys->getAxisByDimension(0,0) );
lcl_switchToTextCategories( xChartDoc, xAxis );
}
}
}
bool DiagramHelper::isSupportingDateAxis( const Reference< chart2::XDiagram >& xDiagram )
{
return ::chart::ChartTypeHelper::isSupportingDateAxis(
DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), DiagramHelper::getDimension( xDiagram ), 0 );
}
bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const Reference< util::XNumberFormats >& xNumberFormats )
{
bool bIsDate = false;
if( !xNumberFormats.is() )
return bIsDate;
Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat );
if( xKeyProps.is() )
{
sal_Int32 nType = util::NumberFormat::UNDEFINED;
xKeyProps->getPropertyValue( C2U("Type") ) >>= nType;
bIsDate = nType & util::NumberFormat::DATE;
}
return bIsDate;
}
sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
{
sal_Int32 nRet=-1;
Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
if( xNumberFormats.is() )
{
sal_Bool bCreate = sal_True;
const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE,
rLocaleDataWrapper.getLocale(), bCreate );
if( aKeySeq.getLength() )
{
nRet = aKeySeq[0];
}
}
//try to get a date format with full year display
NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
if( pNumFormatter )
{
const SvNumberformat* pFormat = pNumFormatter->GetEntry( nRet );
if( pFormat )
nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, pFormat->GetLanguage() );
}
return nRet;
}
sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier )
{
sal_Int32 nRet=-1;
Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() );
if( xNumberFormats.is() )
{
sal_Bool bCreate = sal_True;
const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper();
Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT,
rLocaleDataWrapper.getLocale(), bCreate );
if( aKeySeq.getLength() )
{
nRet = aKeySeq[0];
}
}
return nRet;
}
Sequence< Reference< XChartType > >
DiagramHelper::getChartTypesFromDiagram(
const Reference< XDiagram > & xDiagram )
{
::std::vector< Reference< XChartType > > aResult;
if(xDiagram.is())
try
{
Reference< XCoordinateSystemContainer > xCooSysCnt(
xDiagram, uno::UNO_QUERY_THROW );
Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
xCooSysCnt->getCoordinateSystems());
for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
{
Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
::std::copy( aChartTypeSeq.getConstArray(), aChartTypeSeq.getConstArray() + aChartTypeSeq.getLength(),
::std::back_inserter( aResult ));
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
return ContainerHelper::ContainerToSequence( aResult );
}
bool DiagramHelper::areChartTypesCompatible( const Reference< ::chart2::XChartType >& xFirstType,
const Reference< ::chart2::XChartType >& xSecondType )
{
if( !xFirstType.is() || !xSecondType.is() )
return false;
::std::vector< ::rtl::OUString > aFirstRoles( ContainerHelper::SequenceToVector( xFirstType->getSupportedMandatoryRoles() ) );
::std::vector< ::rtl::OUString > aSecondRoles( ContainerHelper::SequenceToVector( xSecondType->getSupportedMandatoryRoles() ) );
::std::sort( aFirstRoles.begin(), aFirstRoles.end() );
::std::sort( aSecondRoles.begin(), aSecondRoles.end() );
return ( aFirstRoles == aSecondRoles );
}
namespace
{
/**
* This method implements the logic of checking if a series can be moved
* forward/backward. Depending on the "bDoMove" parameter the series will
* be moved (bDoMove = true) or the function just will test if the
* series can be moved without doing the move (bDoMove = false).
*
* @param xDiagram
* Reference to the diagram that contains the series.
*
* @param xGivenDataSeries
* Reference to the series that should moved or tested for moving.
*
* @param bForward
* Direction in which the series should be moved or tested for moving.
*
* @param bDoMove
* Should this function really move the series (true) or just test if it is
* possible (false).
*
*
* @returns
* in case of bDoMove == true
* - True : if the move was done
* - False : the move failed
* in case of bDoMove == false
* - True : the series can be moved
* - False : the series can not be moved
*
*/
bool lcl_moveSeriesOrCheckIfMoveIsAllowed(
const Reference< XDiagram >& xDiagram,
const Reference< XDataSeries >& xGivenDataSeries,
bool bForward,
bool bDoMove )
{
bool bMovedOrMoveAllowed = false;
try
{
uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
//find position of series.
bool bFound = false;
if( xGivenDataSeries.is() && xCooSysContainer.is() )
{
uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
for( sal_Int32 nCS = 0; !bFound && nCS < aCooSysList.getLength(); ++nCS )
{
uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
//iterate through all chart types in the current coordinate system
uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
OSL_ASSERT( xChartTypeContainer.is());
if( !xChartTypeContainer.is() )
continue;
uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
uno::Reference< XChartType > xFormerChartType;
for( sal_Int32 nT = 0; !bFound && nT < aChartTypeList.getLength(); ++nT )
{
uno::Reference< XChartType > xCurrentChartType( aChartTypeList[nT] );
//iterate through all series in this chart type
uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xCurrentChartType, uno::UNO_QUERY );
OSL_ASSERT( xDataSeriesContainer.is());
if( !xDataSeriesContainer.is() )
continue;
uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
for( sal_Int32 nS = 0; !bFound && nS < aSeriesList.getLength(); ++nS )
{
// We found the series we are interrested in !
if( xGivenDataSeries==aSeriesList[nS] )
{
sal_Int32 nOldSeriesIndex = nS;
bFound = true;
try
{
sal_Int32 nNewSeriesIndex = nS;
if( bForward )
nNewSeriesIndex--;
else
nNewSeriesIndex++;
if( nNewSeriesIndex >= 0 && nNewSeriesIndex < aSeriesList.getLength() )
{
//move series in the same charttype
bMovedOrMoveAllowed = true;
if( bDoMove )
{
aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ];
aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries;
xDataSeriesContainer->setDataSeries( aSeriesList );
}
}
else if( nNewSeriesIndex<0 )
{
//exchange series with former charttype
if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) )
{
bMovedOrMoveAllowed = true;
if( bDoMove )
{
uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xFormerChartType, uno::UNO_QUERY );
if( xOtherDataSeriesContainer.is() )
{
uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
sal_Int32 nOtherSeriesIndex = aOtherSeriesList.getLength()-1;
if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
{
uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
aSeriesList[nOldSeriesIndex]=xExchangeSeries;
xDataSeriesContainer->setDataSeries(aSeriesList);
}
}
}
}
}
else if( nT+1 < aChartTypeList.getLength() )
{
//exchange series with next charttype
uno::Reference< XChartType > xOtherChartType( aChartTypeList[nT+1] );
if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) )
{
bMovedOrMoveAllowed = true;
if( bDoMove )
{
uno::Reference< XDataSeriesContainer > xOtherDataSeriesContainer( xOtherChartType, uno::UNO_QUERY );
if( xOtherDataSeriesContainer.is() )
{
uno::Sequence< uno::Reference< XDataSeries > > aOtherSeriesList( xOtherDataSeriesContainer->getDataSeries() );
sal_Int32 nOtherSeriesIndex = 0;
if( nOtherSeriesIndex >= 0 && nOtherSeriesIndex < aOtherSeriesList.getLength() )
{
uno::Reference< XDataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
xOtherDataSeriesContainer->setDataSeries(aOtherSeriesList);
aSeriesList[nOldSeriesIndex]=xExchangeSeries;
xDataSeriesContainer->setDataSeries(aSeriesList);
}
}
}
}
}
}
catch( util::CloseVetoException& )
{
}
catch( uno::RuntimeException& )
{
}
}
}
xFormerChartType = xCurrentChartType;
}
}
}
}
catch( util::CloseVetoException& )
{
}
catch( uno::RuntimeException& )
{
}
return bMovedOrMoveAllowed;
}
} // anonymous namespace
bool DiagramHelper::isSeriesMoveable(
const Reference< XDiagram >& xDiagram,
const Reference< XDataSeries >& xGivenDataSeries,
bool bForward )
{
bool bIsMoveable = false;
const bool bDoMove = false;
bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed(
xDiagram, xGivenDataSeries, bForward, bDoMove );
return bIsMoveable;
}
bool DiagramHelper::moveSeries( const Reference< XDiagram >& xDiagram, const Reference< XDataSeries >& xGivenDataSeries, bool bForward )
{
bool bMoved = false;
const bool bDoMove = true;
bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed(
xDiagram, xGivenDataSeries, bForward, bDoMove );
return bMoved;
}
bool DiagramHelper::isSupportingFloorAndWall( const Reference<
chart2::XDiagram >& xDiagram )
{
//pies and donuts currently do not support this because of wrong files from older versions
//todo: allow this in future again, if fileversion are available for ole objects (metastream)
//thus the wrong bottom can be removed on import
Sequence< Reference< chart2::XChartType > > aTypes(
::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) );
for( sal_Int32 nN = 0; nN < aTypes.getLength(); nN++ )
{
Reference< chart2::XChartType > xType( aTypes[nN] );
if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
return false;
if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
return false;
if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
return false;
}
return true;
}
bool DiagramHelper::isPieOrDonutChart( const ::com::sun::star::uno::Reference<
::com::sun::star::chart2::XDiagram >& xDiagram )
{
uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex(
xDiagram, 0 ) );
if( xChartType .is() )
{
rtl::OUString aChartType = xChartType->getChartType();
if( aChartType.equals(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
return true;
}
return false;
}
sal_Int32 DiagramHelper::getGeometry3D(
const uno::Reference< chart2::XDiagram > & xDiagram,
bool& rbFound, bool& rbAmbiguous )
{
sal_Int32 nCommonGeom( DataPointGeometry3D::CUBOID );
rbFound = false;
rbAmbiguous = false;
::std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
if( aSeriesVec.empty())
rbAmbiguous = true;
for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aIt =
aSeriesVec.begin(); aIt != aSeriesVec.end(); ++aIt )
{
try
{
sal_Int32 nGeom = 0;
Reference< beans::XPropertySet > xProp( *aIt, uno::UNO_QUERY_THROW );
if( xProp->getPropertyValue( C2U( "Geometry3D" )) >>= nGeom )
{
if( ! rbFound )
{
// first series
nCommonGeom = nGeom;
rbFound = true;
}
// further series: compare for uniqueness
else if( nCommonGeom != nGeom )
{
rbAmbiguous = true;
break;
}
}
}
catch( uno::Exception & ex )
{
ASSERT_EXCEPTION( ex );
}
}
return nCommonGeom;
}
void DiagramHelper::setGeometry3D(
const Reference< chart2::XDiagram > & xDiagram,
sal_Int32 nNewGeometry )
{
::std::vector< Reference< chart2::XDataSeries > > aSeriesVec(
DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
for( ::std::vector< Reference< chart2::XDataSeries > >::const_iterator aIt =
aSeriesVec.begin(); aIt != aSeriesVec.end(); ++aIt )
{
DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(
*aIt, C2U( "Geometry3D" ), uno::makeAny( nNewGeometry ));
}
}
sal_Int32 DiagramHelper::getCorrectedMissingValueTreatment(
const Reference< chart2::XDiagram > & xDiagram,
const Reference< chart2::XChartType >& xChartType )
{
sal_Int32 nResult = ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP;
uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments(
ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
if( xDiaProp.is() && (xDiaProp->getPropertyValue( C2U( "MissingValueTreatment" ) ) >>= nResult) )
{
//ensure that the set value is supported by this charttype
for( sal_Int32 nN = 0; nN < aAvailableMissingValueTreatments.getLength(); nN++ )
if( aAvailableMissingValueTreatments[nN] == nResult )
return nResult; //ok
}
//otherwise use the first supported one
if( aAvailableMissingValueTreatments.getLength() )
{
nResult = aAvailableMissingValueTreatments[0];
return nResult;
}
return nResult;
}
DiagramPositioningMode DiagramHelper::getDiagramPositioningMode( const uno::Reference<
chart2::XDiagram > & xDiagram )
{
DiagramPositioningMode eMode = DiagramPositioningMode_AUTO;
uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY );
if( xDiaProps.is() )
{
RelativePosition aRelPos;
RelativeSize aRelSize;
if( (xDiaProps->getPropertyValue(C2U("RelativePosition")) >>= aRelPos ) &&
(xDiaProps->getPropertyValue(C2U("RelativeSize")) >>= aRelSize ) )
{
bool bPosSizeExcludeAxes=false;
xDiaProps->getPropertyValue(C2U("PosSizeExcludeAxes")) >>= bPosSizeExcludeAxes;
if( bPosSizeExcludeAxes )
eMode = DiagramPositioningMode_EXCLUDING;
else
eMode = DiagramPositioningMode_INCLUDING;
}
}
return eMode;
}
void lcl_ensureRange0to1( double& rValue )
{
if(rValue<0.0)
rValue=0.0;
if(rValue>1.0)
rValue=1.0;
}
bool DiagramHelper::setDiagramPositioning( const uno::Reference< frame::XModel >& xChartModel,
const awt::Rectangle& rPosRect /*100th mm*/ )
{
ControllerLockGuard aCtrlLockGuard( xChartModel );
bool bChanged = false;
awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
if( !xDiaProps.is() )
return bChanged;
RelativePosition aOldPos;
RelativeSize aOldSize;
xDiaProps->getPropertyValue(C2U("RelativePosition") ) >>= aOldPos;
xDiaProps->getPropertyValue(C2U("RelativeSize") ) >>= aOldSize;
RelativePosition aNewPos;
aNewPos.Anchor = drawing::Alignment_TOP_LEFT;
aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width);
aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height);
chart2::RelativeSize aNewSize;
aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width);
aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height);
lcl_ensureRange0to1( aNewPos.Primary );
lcl_ensureRange0to1( aNewPos.Secondary );
lcl_ensureRange0to1( aNewSize.Primary );
lcl_ensureRange0to1( aNewSize.Secondary );
if( (aNewPos.Primary + aNewSize.Primary) > 1.0 )
aNewPos.Primary = 1.0 - aNewSize.Primary;
if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 )
aNewPos.Secondary = 1.0 - aNewSize.Secondary;
xDiaProps->setPropertyValue( C2U( "RelativePosition" ), uno::makeAny(aNewPos) );
xDiaProps->setPropertyValue( C2U( "RelativeSize" ), uno::makeAny(aNewSize) );
bChanged = (aOldPos.Anchor!=aNewPos.Anchor) ||
(aOldPos.Primary!=aNewPos.Primary) ||
(aOldPos.Secondary!=aNewPos.Secondary) ||
(aOldSize.Primary!=aNewSize.Primary) ||
(aOldSize.Secondary!=aNewSize.Secondary);
return bChanged;
}
awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const uno::Reference< frame::XModel >& xChartModel )
{
awt::Rectangle aRet(-1,-1,-1,-1);
uno::Reference< beans::XPropertySet > xDiaProps( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
if( !xDiaProps.is() )
return aRet;
awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) );
RelativePosition aRelPos;
RelativeSize aRelSize;
xDiaProps->getPropertyValue(C2U("RelativePosition") ) >>= aRelPos;
xDiaProps->getPropertyValue(C2U("RelativeSize") ) >>= aRelSize;
awt::Size aAbsSize(
static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ),
static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height ));
awt::Point aAbsPos(
static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ),
static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height ));
awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor );
aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height );
return aRet;
}
bool DiagramHelper::switchDiagramPositioningToExcludingPositioning(
const uno::Reference< frame::XModel >& xChartModel
, bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning )
{
//return true if something was changed
const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
if( nCurrentODFVersion == SvtSaveOptions::ODFVER_LATEST )//#i100778# todo: change this dependent on fileformat evolution
{
uno::Reference< ::com::sun::star::chart::XChartDocument > xOldDoc( xChartModel, uno::UNO_QUERY ) ;
if( xOldDoc.is() )
{
uno::Reference< ::com::sun::star::chart::XDiagramPositioning > xDiagramPositioning( xOldDoc->getDiagram(), uno::UNO_QUERY );
if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() )
&& !xDiagramPositioning->isExcludingDiagramPositioning() )
{
ControllerLockGuard aCtrlLockGuard( xChartModel );
uno::Reference< util::XModifiable > xModifiable( xChartModel, uno::UNO_QUERY );
bool bModelWasModified = xModifiable.is() && xModifiable->isModified();
xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() );
if(bResetModifiedState && !bModelWasModified && xModifiable.is() )
xModifiable->setModified(sal_False);
return true;
}
}
}
return false;
}
} // namespace chart
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */