/* -*- 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_chart2.hxx" #include "ExplicitCategoriesProvider.hxx" #include "DiagramHelper.hxx" #include "CommonConverters.hxx" #include "DataSourceHelper.hxx" #include "ChartModelHelper.hxx" #include "ContainerHelper.hxx" #include "macros.hxx" //............................................................................. 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; using ::rtl::OUString; using ::std::vector; ExplicitCategoriesProvider::ExplicitCategoriesProvider( const Reference< chart2::XCoordinateSystem >& xCooSysModel , const uno::Reference< frame::XModel >& xChartModel ) : m_bDirty(true) , m_xCooSysModel( xCooSysModel ) , m_xOriginalCategories() { try { if( xCooSysModel.is() ) { uno::Reference< XAxis > xAxis( xCooSysModel->getAxisByDimension(0,0) ); if( xAxis.is() ) m_xOriginalCategories = xAxis->getScaleData().Categories; } if( m_xOriginalCategories.is() ) { Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY ); if( xChartDoc.is() ) { uno::Reference< data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); if( xDataProvider.is() ) { OUString aCatgoriesRange( DataSourceHelper::getRangeFromValues( m_xOriginalCategories ) ); const bool bFirstCellAsLabel = false; const bool bHasCategories = false; const uno::Sequence< sal_Int32 > aSequenceMapping; uno::Reference< data::XDataSource > xColumnCategoriesSource( xDataProvider->createDataSource( DataSourceHelper::createArguments( aCatgoriesRange, aSequenceMapping, true /*bUseColumns*/ , bFirstCellAsLabel, bHasCategories ) ) ); uno::Reference< data::XDataSource > xRowCategoriesSource( xDataProvider->createDataSource( DataSourceHelper::createArguments( aCatgoriesRange, aSequenceMapping, false /*bUseColumns*/ , bFirstCellAsLabel, bHasCategories ) ) ); if( xColumnCategoriesSource.is() && xRowCategoriesSource.is() ) { Sequence< Reference< data::XLabeledDataSequence> > aColumns = xColumnCategoriesSource->getDataSequences(); Sequence< Reference< data::XLabeledDataSequence> > aRows = xRowCategoriesSource->getDataSequences(); sal_Int32 nColumnCount = aColumns.getLength(); sal_Int32 nRowCount = aRows.getLength(); if( nColumnCount>1 && nRowCount>1 ) { //we have complex categories //->split them in the direction of the first series //detect whether the first series is a row or a column bool bSeriesUsesColumns = true; ::std::vector< Reference< XDataSeries > > aSeries( ChartModelHelper::getDataSeries( xChartModel ) ); if( !aSeries.empty() ) { uno::Reference< data::XDataSource > xSeriesSource( aSeries.front(), uno::UNO_QUERY ); ::rtl::OUString aStringDummy; bool bDummy; uno::Sequence< sal_Int32 > aSeqDummy; DataSourceHelper::readArguments( xDataProvider->detectArguments( xSeriesSource), aStringDummy, aSeqDummy, bSeriesUsesColumns, bDummy, bDummy ); } if( bSeriesUsesColumns ) m_aSplitCategoriesList=aColumns; else m_aSplitCategoriesList=aRows; } } } } if( !m_aSplitCategoriesList.getLength() ) { m_aSplitCategoriesList.realloc(1); m_aSplitCategoriesList[0]=m_xOriginalCategories; } } } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } ExplicitCategoriesProvider::~ExplicitCategoriesProvider() { } const Sequence< Reference< data::XLabeledDataSequence> >& ExplicitCategoriesProvider::getSplitCategoriesList() { return m_aSplitCategoriesList; } bool ExplicitCategoriesProvider::hasComplexCategories() const { return m_aSplitCategoriesList.getLength() > 1; } sal_Int32 ExplicitCategoriesProvider::getCategoryLevelCount() const { sal_Int32 nCount = m_aSplitCategoriesList.getLength(); if(!nCount) nCount = 1; return nCount; } std::vector lcl_getLimitingBorders( const std::vector< ComplexCategory >& rComplexCategories ) { std::vector aLimitingBorders; std::vector< ComplexCategory >::const_iterator aIt( rComplexCategories.begin() ); std::vector< ComplexCategory >::const_iterator aEnd( rComplexCategories.end() ); sal_Int32 nBorderIndex = 0; /*border below the index*/ for( ; aIt != aEnd; ++aIt ) { ComplexCategory aComplexCategory(*aIt); nBorderIndex += aComplexCategory.Count; aLimitingBorders.push_back(nBorderIndex); } return aLimitingBorders; } uno::Sequence< rtl::OUString > lcl_DataToStringSequence( const uno::Reference< data::XDataSequence >& xDataSequence ) { uno::Sequence< rtl::OUString > aStrings; OSL_ASSERT( xDataSequence.is()); if( !xDataSequence.is() ) return aStrings; uno::Reference< data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY ); if( xTextualDataSequence.is() ) { aStrings = xTextualDataSequence->getTextualData(); } else { uno::Sequence< uno::Any > aValues = xDataSequence->getData(); aStrings.realloc(aValues.getLength()); for(sal_Int32 nN=aValues.getLength();nN--;) aValues[nN] >>= aStrings[nN]; } return aStrings; } SplitCategoriesProvider::~SplitCategoriesProvider() { } class SplitCategoriesProvider_ForLabeledDataSequences : public SplitCategoriesProvider { public: explicit SplitCategoriesProvider_ForLabeledDataSequences( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XLabeledDataSequence> >& rSplitCategoriesList ) : m_rSplitCategoriesList( rSplitCategoriesList ) {} virtual ~SplitCategoriesProvider_ForLabeledDataSequences() {} virtual sal_Int32 getLevelCount() const; virtual uno::Sequence< rtl::OUString > getStringsForLevel( sal_Int32 nIndex ) const; private: const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XLabeledDataSequence> >& m_rSplitCategoriesList; }; sal_Int32 SplitCategoriesProvider_ForLabeledDataSequences::getLevelCount() const { return m_rSplitCategoriesList.getLength(); } uno::Sequence< rtl::OUString > SplitCategoriesProvider_ForLabeledDataSequences::getStringsForLevel( sal_Int32 nLevel ) const { uno::Sequence< rtl::OUString > aRet; Reference< data::XLabeledDataSequence > xLabeledDataSequence( m_rSplitCategoriesList[nLevel] ); if( xLabeledDataSequence.is() ) aRet = lcl_DataToStringSequence( xLabeledDataSequence->getValues() ); return aRet; } std::vector< ComplexCategory > lcl_DataSequenceToComplexCategoryVector( const uno::Sequence< rtl::OUString >& rStrings , const std::vector& rLimitingBorders, bool bCreateSingleCategories ) { std::vector< ComplexCategory > aResult; sal_Int32 nMaxCount = rStrings.getLength(); OUString aPrevious; sal_Int32 nCurrentCount=0; for( sal_Int32 nN=0; nN& rComplexCategories ) { sal_Int32 nCount = 0; std::vector< ComplexCategory >::iterator aIt( rComplexCategories.begin() ); std::vector< ComplexCategory >::const_iterator aEnd( rComplexCategories.end() ); for( ; aIt != aEnd; ++aIt ) nCount+=aIt->Count; return nCount; } Sequence< OUString > lcl_getExplicitSimpleCategories( const SplitCategoriesProvider& rSplitCategoriesProvider, ::std::vector< ::std::vector< ComplexCategory > >& rComplexCats ) { Sequence< OUString > aRet; rComplexCats.clear(); sal_Int32 nLCount = rSplitCategoriesProvider.getLevelCount(); for( sal_Int32 nL = 0; nL < nLCount; nL++ ) { std::vector aLimitingBorders; if(nL>0) aLimitingBorders = lcl_getLimitingBorders( rComplexCats.back() ); rComplexCats.push_back( lcl_DataSequenceToComplexCategoryVector( rSplitCategoriesProvider.getStringsForLevel(nL), aLimitingBorders, nL==(nLCount-1) ) ); } std::vector< std::vector< ComplexCategory > >::iterator aOuterIt( rComplexCats.begin() ); std::vector< std::vector< ComplexCategory > >::const_iterator aOuterEnd( rComplexCats.end() ); //ensure that the category count is the same on each level sal_Int32 nMaxCategoryCount = 0; { for( aOuterIt=rComplexCats.begin(); aOuterIt != aOuterEnd; ++aOuterIt ) { sal_Int32 nCurrentCount = lcl_getCategoryCount( *aOuterIt ); nMaxCategoryCount = std::max( nCurrentCount, nMaxCategoryCount ); } for( aOuterIt=rComplexCats.begin(); aOuterIt != aOuterEnd; ++aOuterIt ) { sal_Int32 nCurrentCount = lcl_getCategoryCount( *aOuterIt ); if( nCurrentCount< nMaxCategoryCount ) { ComplexCategory& rComplexCategory = aOuterIt->back(); rComplexCategory.Count += (nMaxCategoryCount-nCurrentCount); } } } //create a list with an element for every index std::vector< std::vector< ComplexCategory > > aComplexCatsPerIndex; for( aOuterIt=rComplexCats.begin() ; aOuterIt != aOuterEnd; ++aOuterIt ) { std::vector< ComplexCategory > aSingleLevel; std::vector< ComplexCategory >::iterator aIt( aOuterIt->begin() ); std::vector< ComplexCategory >::const_iterator aEnd( aOuterIt->end() ); for( ; aIt != aEnd; ++aIt ) { ComplexCategory aComplexCategory( *aIt ); sal_Int32 nCount = aComplexCategory.Count; while( nCount-- ) aSingleLevel.push_back(aComplexCategory); } aComplexCatsPerIndex.push_back( aSingleLevel ); } if(nMaxCategoryCount) { aRet.realloc(nMaxCategoryCount); aOuterEnd = aComplexCatsPerIndex.end(); OUString aSpace(C2U(" ")); for(sal_Int32 nN=0; nN ExplicitCategoriesProvider::getExplicitSimpleCategories( const SplitCategoriesProvider& rSplitCategoriesProvider ) { vector< vector< ComplexCategory > > aComplexCats; return lcl_getExplicitSimpleCategories( rSplitCategoriesProvider, aComplexCats ); } void ExplicitCategoriesProvider::init() { if( m_bDirty ) { m_aExplicitCategories.realloc(0); m_aComplexCats.clear();//not one per index if( m_xOriginalCategories.is() ) { if( !hasComplexCategories() ) m_aExplicitCategories = DataSequenceToStringSequence(m_xOriginalCategories->getValues()); else m_aExplicitCategories = lcl_getExplicitSimpleCategories( SplitCategoriesProvider_ForLabeledDataSequences( m_aSplitCategoriesList ), m_aComplexCats ); } if(!m_aExplicitCategories.getLength()) m_aExplicitCategories = DiagramHelper::generateAutomaticCategoriesFromCooSys( m_xCooSysModel ); m_bDirty = false; } } Sequence< ::rtl::OUString > ExplicitCategoriesProvider::getSimpleCategories() { init(); return m_aExplicitCategories; } std::vector< ComplexCategory > ExplicitCategoriesProvider::getCategoriesByLevel( sal_Int32 nLevel ) { std::vector< ComplexCategory > aRet; init(); sal_Int32 nMaxIndex = m_aComplexCats.size()-1; if( nLevel >= 0 && nLevel <= nMaxIndex ) aRet = m_aComplexCats[nMaxIndex-nLevel]; return aRet; } // static OUString ExplicitCategoriesProvider::getCategoryByIndex( const Reference< XCoordinateSystem >& xCooSysModel , const uno::Reference< frame::XModel >& xChartModel , sal_Int32 nIndex ) { if( xCooSysModel.is()) { ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSysModel, xChartModel ); Sequence< OUString > aCategories( aExplicitCategoriesProvider.getSimpleCategories()); if( nIndex < aCategories.getLength()) return aCategories[ nIndex ]; } return OUString(); } //............................................................................. } //namespace chart //............................................................................. /* vim:set shiftwidth=4 softtabstop=4 expandtab: */