/************************************************************************* * * 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 #include #include "InternalDataProvider.hxx" #include "LabeledDataSequence.hxx" #include "DataSource.hxx" #include "PropertyHelper.hxx" #include "macros.hxx" #include "XMLRangeHelper.hxx" #include "ContainerHelper.hxx" #include "CommonConverters.hxx" #include "CommonFunctors.hxx" #include "UncachedDataSequence.hxx" #include "DataSourceHelper.hxx" #include "ChartModelHelper.hxx" #include "DiagramHelper.hxx" #include "ExplicitCategoriesProvider.hxx" #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::std; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::rtl::OUString; using ::rtl::OUStringBuffer; namespace chart { // ================================================================================ namespace { // note: in xmloff this name is used to indicate usage of own data static const ::rtl::OUString lcl_aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart.InternalDataProvider" )); static const ::rtl::OUString lcl_aCategoriesRangeName( RTL_CONSTASCII_USTRINGPARAM( "categories" )); static const ::rtl::OUString lcl_aCategoriesLevelRangeNamePrefix( RTL_CONSTASCII_USTRINGPARAM( "categoriesL " )); //L <-> level static const ::rtl::OUString lcl_aCategoriesPointRangeNamePrefix( RTL_CONSTASCII_USTRINGPARAM( "categoriesP " )); //P <-> point static const ::rtl::OUString lcl_aCategoriesRoleName( RTL_CONSTASCII_USTRINGPARAM( "categories" )); static const ::rtl::OUString lcl_aLabelRangePrefix( RTL_CONSTASCII_USTRINGPARAM( "label " )); static const ::rtl::OUString lcl_aCompleteRange( RTL_CONSTASCII_USTRINGPARAM( "all" )); typedef ::std::multimap< OUString, uno::WeakReference< chart2::data::XDataSequence > > lcl_tSequenceMap; struct lcl_setModified : public ::std::unary_function< lcl_tSequenceMap, void > { void operator() ( const lcl_tSequenceMap::value_type & rMapEntry ) { // convert weak reference to reference Reference< chart2::data::XDataSequence > xSeq( rMapEntry.second ); if( xSeq.is()) { Reference< util::XModifiable > xMod( xSeq, uno::UNO_QUERY ); if( xMod.is()) xMod->setModified( sal_True ); } } }; struct lcl_internalizeSeries : public ::std::unary_function< Reference< chart2::XDataSeries >, void > { lcl_internalizeSeries( InternalData & rInternalData, InternalDataProvider & rProvider, bool bConnectToModel, bool bDataInColumns ) : m_rInternalData( rInternalData ), m_rProvider( rProvider ), m_bConnectToModel( bConnectToModel ), m_bDataInColumns( bDataInColumns ) {} void operator() ( const Reference< chart2::XDataSeries > & xSeries ) { Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); Reference< chart2::data::XDataSink > xSink( xSeries, uno::UNO_QUERY ); if( xSource.is() && xSink.is() ) { Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeriesData = xSource->getDataSequences(); Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeriesData( aOldSeriesData.getLength() ); for( sal_Int32 i=0; i xValues( aOldSeriesData[i]->getValues(), uno::UNO_QUERY ); Reference< chart2::data::XTextualDataSequence > xLabel( aOldSeriesData[i]->getLabel(), uno::UNO_QUERY ); Reference< chart2::data::XDataSequence > xNewValues; if( xValues.is() ) { ::std::vector< double > aValues( ContainerHelper::SequenceToVector( xValues->getNumericalData())); if( m_bDataInColumns ) m_rInternalData.setColumnValues( nNewIndex, aValues ); else m_rInternalData.setRowValues( nNewIndex, aValues ); if( m_bConnectToModel ) { xNewValues.set( m_rProvider.createDataSequenceByRangeRepresentation( aIdentifier )); comphelper::copyProperties( Reference< beans::XPropertySet >( xValues, uno::UNO_QUERY ), Reference< beans::XPropertySet >( xNewValues, uno::UNO_QUERY )); } } if( xLabel.is() ) { if( m_bDataInColumns ) m_rInternalData.setComplexColumnLabel( nNewIndex, ContainerHelper::SequenceToVector( xLabel->getTextualData() ) ); else m_rInternalData.setComplexRowLabel( nNewIndex, ContainerHelper::SequenceToVector( xLabel->getTextualData() ) ); if( m_bConnectToModel ) { Reference< chart2::data::XDataSequence > xNewLabel( m_rProvider.createDataSequenceByRangeRepresentation( lcl_aLabelRangePrefix + aIdentifier )); comphelper::copyProperties( Reference< beans::XPropertySet >( xLabel, uno::UNO_QUERY ), Reference< beans::XPropertySet >( xNewLabel, uno::UNO_QUERY )); aNewSeriesData[i] = Reference< chart2::data::XLabeledDataSequence >( new LabeledDataSequence( xNewValues, xNewLabel )); } } else { if( m_bConnectToModel ) aNewSeriesData[i] = Reference< chart2::data::XLabeledDataSequence >( new LabeledDataSequence( xNewValues )); } } if( m_bConnectToModel ) xSink->setData( aNewSeriesData ); } } private: InternalData & m_rInternalData; InternalDataProvider & m_rProvider; bool m_bConnectToModel; bool m_bDataInColumns; }; struct lcl_makeAnyFromLevelVector : public ::std::unary_function< vector< OUString >, uno::Any > { public: explicit lcl_makeAnyFromLevelVector( sal_Int32 nLevel ) : m_nLevel( nLevel ) {} uno::Any operator() ( const vector< OUString >& rVector ) { OUString aString; if( m_nLevel < static_cast< sal_Int32 >(rVector.size()) ) aString = rVector[m_nLevel]; return uno::makeAny( aString ); } private: sal_Int32 m_nLevel; }; struct lcl_getStringFromLevelVector : public ::std::unary_function< vector< OUString >, OUString > { public: explicit lcl_getStringFromLevelVector( sal_Int32 nLevel ) : m_nLevel( nLevel ) {} OUString operator() ( const vector< OUString >& rVector ) { OUString aString; if( m_nLevel < static_cast< sal_Int32 >(rVector.size()) ) aString = rVector[m_nLevel]; return aString; } private: sal_Int32 m_nLevel; }; struct lcl_setStringAtLevel : public ::std::binary_function< vector< OUString >, OUString, vector< OUString > > { public: explicit lcl_setStringAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) {} vector< OUString > operator() ( const vector< OUString >& rVector, const OUString& rNewText ) { vector< OUString > aRet( rVector ); if( m_nLevel >= static_cast< sal_Int32 >(aRet.size()) ) aRet.resize( m_nLevel+1 ); aRet[ m_nLevel ]=rNewText; return aRet; } private: sal_Int32 m_nLevel; }; struct lcl_insertStringAtLevel : public ::std::unary_function< vector< OUString >, void > { public: explicit lcl_insertStringAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) {} void operator() ( vector< OUString >& rVector ) { if( m_nLevel > static_cast< sal_Int32 >(rVector.size()) ) rVector.resize( m_nLevel ); vector< OUString >::iterator aIt( rVector.begin() ); for( sal_Int32 nN=0; aIt, void > { public: explicit lcl_removeStringAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) {} void operator() ( vector< OUString >& rVector ) { vector< OUString >::iterator aIt( rVector.begin() ); for( sal_Int32 nN=0; aIt lcl_AnyToStringVector( const Sequence< uno::Any >& aAnySeq ) { vector< OUString > aStringVec; transform( aAnySeq.getConstArray(), aAnySeq.getConstArray() + aAnySeq.getLength(), back_inserter( aStringVec ), CommonFunctors::AnyToString() ); return aStringVec; } Sequence< OUString > lcl_AnyToStringSequence( const Sequence< uno::Any >& aAnySeq ) { Sequence< OUString > aResult; aResult.realloc( aAnySeq.getLength() ); transform( aAnySeq.getConstArray(), aAnySeq.getConstArray() + aAnySeq.getLength(), aResult.getArray(), CommonFunctors::AnyToString() ); return aResult; } } // anonymous namespace // ================================================================================ InternalDataProvider::InternalDataProvider( const Reference< uno::XComponentContext > & /*_xContext*/) : m_bDataInColumns( true ) {} InternalDataProvider::InternalDataProvider( const Reference< chart2::XChartDocument > & xChartDoc, bool bConnectToModel ) : m_bDataInColumns( true ) { try { Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartDoc ) ); if( xDiagram.is()) { Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY ); //data in columns? { ::rtl::OUString aRangeString; bool bFirstCellAsLabel = true; bool bHasCategories = true; uno::Sequence< sal_Int32 > aSequenceMapping; DataSourceHelper::detectRangeSegmentation( xChartModel, aRangeString, aSequenceMapping, m_bDataInColumns, bFirstCellAsLabel, bHasCategories ); } // categories { vector< vector< OUString > > aNewCategories;//inner count is level { ExplicitCategoriesProvider aExplicitCategoriesProvider( ChartModelHelper::getFirstCoordinateSystem(xChartModel), xChartModel ); const Sequence< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList( aExplicitCategoriesProvider.getSplitCategoriesList() ); sal_Int32 nLevelCount = rSplitCategoriesList.getLength(); for( sal_Int32 nL = 0; nL xLDS( rSplitCategoriesList[nL] ); if( !xLDS.is() ) continue; Reference< chart2::data::XTextualDataSequence > xSeq( xLDS->getValues(), uno::UNO_QUERY ); Sequence< OUString > aStringSeq; if( xSeq.is() ) aStringSeq = xSeq->getTextualData(); // @todo: be able to deal with XDataSequence, too sal_Int32 nLength = aStringSeq.getLength(); if( static_cast< sal_Int32 >(aNewCategories.size()) < nLength ) aNewCategories.resize( nLength ); transform( aNewCategories.begin(), aNewCategories.end(), aStringSeq.getConstArray(), aNewCategories.begin(), lcl_setStringAtLevel(nL) ); } if( !nLevelCount ) { Sequence< OUString > aSimplecategories = aExplicitCategoriesProvider.getSimpleCategories(); sal_Int32 nLength = aSimplecategories.getLength(); aNewCategories.reserve( nLength ); for( sal_Int32 nN=0; nN aStringVector(1); aStringVector[0] = aSimplecategories[nN]; aNewCategories.push_back( aStringVector ); } } } if( m_bDataInColumns ) m_aInternalData.setComplexRowLabels( aNewCategories ); else m_aInternalData.setComplexColumnLabels( aNewCategories ); if( bConnectToModel ) DiagramHelper::setCategoriesToDiagram( new LabeledDataSequence( createDataSequenceByRangeRepresentation( lcl_aCategoriesRangeName )), xDiagram ); } // data series ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( ChartModelHelper::getDataSeries( xChartDoc )); ::std::for_each( aSeriesVector.begin(), aSeriesVector.end(), lcl_internalizeSeries( m_aInternalData, *this, bConnectToModel, m_bDataInColumns ) ); } } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } // copy-CTOR InternalDataProvider::InternalDataProvider( const InternalDataProvider & rOther ) : impl::InternalDataProvider_Base(), m_aSequenceMap( rOther.m_aSequenceMap ), m_aInternalData( rOther.m_aInternalData ), m_bDataInColumns( rOther.m_bDataInColumns ) {} InternalDataProvider::~InternalDataProvider() {} void InternalDataProvider::lcl_addDataSequenceToMap( const OUString & rRangeRepresentation, const Reference< chart2::data::XDataSequence > & xSequence ) { m_aSequenceMap.insert( tSequenceMap::value_type( rRangeRepresentation, uno::WeakReference< chart2::data::XDataSequence >( xSequence ))); } void InternalDataProvider::lcl_deleteMapReferences( const OUString & rRangeRepresentation ) { // set sequence to deleted by setting its range to an empty string tSequenceMapRange aRange( m_aSequenceMap.equal_range( rRangeRepresentation )); for( tSequenceMap::iterator aIt( aRange.first ); aIt != aRange.second; ++aIt ) { Reference< chart2::data::XDataSequence > xSeq( aIt->second ); if( xSeq.is()) { Reference< container::XNamed > xNamed( xSeq, uno::UNO_QUERY ); if( xNamed.is()) xNamed->setName( OUString()); } } // remove from map m_aSequenceMap.erase( aRange.first, aRange.second ); } void InternalDataProvider::lcl_adaptMapReferences( const OUString & rOldRangeRepresentation, const OUString & rNewRangeRepresentation ) { tSequenceMapRange aRange( m_aSequenceMap.equal_range( rOldRangeRepresentation )); tSequenceMap aNewElements; for( tSequenceMap::iterator aIt( aRange.first ); aIt != aRange.second; ++aIt ) { Reference< chart2::data::XDataSequence > xSeq( aIt->second ); if( xSeq.is()) { Reference< container::XNamed > xNamed( xSeq, uno::UNO_QUERY ); if( xNamed.is()) xNamed->setName( rNewRangeRepresentation ); } aNewElements.insert( tSequenceMap::value_type( rNewRangeRepresentation, aIt->second )); } // erase map values for old index m_aSequenceMap.erase( aRange.first, aRange.second ); // add new entries for values with new index ::std::copy( aNewElements.begin(), aNewElements.end(), ::std::inserter( m_aSequenceMap, m_aSequenceMap.upper_bound( rNewRangeRepresentation ))); } void InternalDataProvider::lcl_increaseMapReferences( sal_Int32 nBegin, sal_Int32 nEnd ) { for( sal_Int32 nIndex = nEnd - 1; nIndex >= nBegin; --nIndex ) { lcl_adaptMapReferences( OUString::valueOf( nIndex ), OUString::valueOf( nIndex + 1 )); lcl_adaptMapReferences( lcl_aLabelRangePrefix + OUString::valueOf( nIndex ), lcl_aLabelRangePrefix + OUString::valueOf( nIndex + 1 )); } } void InternalDataProvider::lcl_decreaseMapReferences( sal_Int32 nBegin, sal_Int32 nEnd ) { for( sal_Int32 nIndex = nBegin; nIndex < nEnd; ++nIndex ) { lcl_adaptMapReferences( OUString::valueOf( nIndex ), OUString::valueOf( nIndex - 1 )); lcl_adaptMapReferences( lcl_aLabelRangePrefix + OUString::valueOf( nIndex ), lcl_aLabelRangePrefix + OUString::valueOf( nIndex - 1 )); } } Reference< chart2::data::XDataSequence > InternalDataProvider::lcl_createDataSequenceAndAddToMap( const OUString & rRangeRepresentation ) { Reference< chart2::data::XDataSequence > xSeq( new UncachedDataSequence( this, rRangeRepresentation )); lcl_addDataSequenceToMap( rRangeRepresentation, xSeq ); return xSeq; } Reference< chart2::data::XDataSequence > InternalDataProvider::lcl_createDataSequenceAndAddToMap( const OUString & rRangeRepresentation, const OUString & rRole ) { Reference< chart2::data::XDataSequence > xSeq( new UncachedDataSequence( this, rRangeRepresentation, rRole )); lcl_addDataSequenceToMap( rRangeRepresentation, xSeq ); return xSeq; } void InternalDataProvider::createDefaultData() { m_aInternalData.createDefaultData(); } // ____ XDataProvider ____ ::sal_Bool SAL_CALL InternalDataProvider::createDataSourcePossible( const Sequence< beans::PropertyValue >& /* aArguments */ ) throw (uno::RuntimeException) { return true; } namespace { sal_Int32 lcl_getInnerLevelCount( const vector< vector< OUString > >& rLabels ) { sal_Int32 nCount = 1;//minimum is 1! vector< vector< OUString > >::const_iterator aLevelIt( rLabels.begin() ); vector< vector< OUString > >::const_iterator aLevelEnd( rLabels.end() ); for( ;aLevelIt!=aLevelEnd; ++aLevelIt ) { const vector< ::rtl::OUString >& rCurrentLevelLabels = *aLevelIt; nCount = std::max( rCurrentLevelLabels.size(), nCount ); } return nCount; } }//end anonymous namespace Reference< chart2::data::XDataSource > SAL_CALL InternalDataProvider::createDataSource( const Sequence< beans::PropertyValue >& aArguments ) throw (lang::IllegalArgumentException, uno::RuntimeException) { OUString aRangeRepresentation; bool bUseColumns = true; bool bFirstCellAsLabel = true; bool bHasCategories = true; uno::Sequence< sal_Int32 > aSequenceMapping; DataSourceHelper::readArguments( aArguments, aRangeRepresentation, aSequenceMapping, bUseColumns, bFirstCellAsLabel, bHasCategories ); if( aRangeRepresentation.equals( lcl_aCategoriesRangeName ) ) { //return split complex categories if we have any: ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aComplexCategories; vector< vector< OUString > > aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels()); if( bUseColumns==m_bDataInColumns ) { sal_Int32 nLevelCount = lcl_getInnerLevelCount( aCategories ); for( sal_Int32 nL=0; nL > aResultLSeqVec; // categories if( bHasCategories ) aResultLSeqVec.push_back( new LabeledDataSequence( lcl_createDataSequenceAndAddToMap( lcl_aCategoriesRangeName, lcl_aCategoriesRoleName ) ) ); // data with labels ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aDataVec; const sal_Int32 nCount = (bUseColumns ? m_aInternalData.getColumnCount() : m_aInternalData.getRowCount()); for( sal_Int32 nIdx=0; nIdx::size_type nOldIndex = aSequenceMapping[nNewIndex]; if( nOldIndex < aDataVec.size() ) { if( aDataVec[nOldIndex].is() ) { aResultLSeqVec.push_back( aDataVec[nOldIndex] ); aDataVec[nOldIndex] = 0; } } } //add left over data sequences to result ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::iterator aIt(aDataVec.begin()); const ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::const_iterator aEndIt(aDataVec.end()); for( ;aIt!=aEndIt; ++aIt) { if( aIt->is() ) aResultLSeqVec.push_back( *aIt ); } return new DataSource( ContainerHelper::ContainerToSequence(aResultLSeqVec) ); } Sequence< beans::PropertyValue > SAL_CALL InternalDataProvider::detectArguments( const Reference< chart2::data::XDataSource >& /* xDataSource */ ) throw (uno::RuntimeException) { Sequence< beans::PropertyValue > aArguments( 4 ); aArguments[0] = beans::PropertyValue( C2U("CellRangeRepresentation"), -1, uno::makeAny( lcl_aCompleteRange ), beans::PropertyState_DIRECT_VALUE ); aArguments[1] = beans::PropertyValue( C2U("DataRowSource"), -1, uno::makeAny( m_bDataInColumns ? ::com::sun::star::chart::ChartDataRowSource_COLUMNS : ::com::sun::star::chart::ChartDataRowSource_ROWS ), beans::PropertyState_DIRECT_VALUE ); // internal data always contains labels and categories aArguments[2] = beans::PropertyValue( C2U("FirstCellAsLabel"), -1, uno::makeAny( true ), beans::PropertyState_DIRECT_VALUE ); aArguments[3] = beans::PropertyValue( C2U("HasCategories"), -1, uno::makeAny( true ), beans::PropertyState_DIRECT_VALUE ); // #i85913# Sequence Mapping is not needed for internal data, as it is // applied to the data when the data source is created. return aArguments; } ::sal_Bool SAL_CALL InternalDataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& /* aRangeRepresentation */ ) throw (uno::RuntimeException) { return true; } Reference< chart2::data::XDataSequence > SAL_CALL InternalDataProvider::createDataSequenceByRangeRepresentation( const OUString& aRangeRepresentation ) throw (lang::IllegalArgumentException, uno::RuntimeException) { if( aRangeRepresentation.match( lcl_aCategoriesRangeName )) { OSL_ASSERT( aRangeRepresentation.equals( lcl_aCategoriesRangeName ) );//it is not expected nor implmented that only parts of the categories are really requested // categories return lcl_createDataSequenceAndAddToMap( lcl_aCategoriesRangeName, lcl_aCategoriesRoleName ); } else if( aRangeRepresentation.match( lcl_aLabelRangePrefix )) { // label sal_Int32 nIndex = aRangeRepresentation.copy( lcl_aLabelRangePrefix.getLength()).toInt32(); return lcl_createDataSequenceAndAddToMap( lcl_aLabelRangePrefix + OUString::valueOf( nIndex )); } else if( aRangeRepresentation.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "last" ))) { sal_Int32 nIndex = (m_bDataInColumns ? m_aInternalData.getColumnCount() : m_aInternalData.getRowCount()) - 1; return lcl_createDataSequenceAndAddToMap( OUString::valueOf( nIndex )); } else if( aRangeRepresentation.getLength()) { // data sal_Int32 nIndex = aRangeRepresentation.toInt32(); return lcl_createDataSequenceAndAddToMap( OUString::valueOf( nIndex )); } return Reference< chart2::data::XDataSequence >(); } Reference< sheet::XRangeSelection > SAL_CALL InternalDataProvider::getRangeSelection() throw (uno::RuntimeException) { // there is no range selection component return Reference< sheet::XRangeSelection >(); } // ____ XInternalDataProvider ____ ::sal_Bool SAL_CALL InternalDataProvider::hasDataByRangeRepresentation( const OUString& aRange ) throw (uno::RuntimeException) { sal_Bool bResult = false; if( aRange.match( lcl_aCategoriesRangeName )) { OSL_ASSERT( aRange.equals( lcl_aCategoriesRangeName ) );//it is not expected nor implmented that only parts of the categories are really requested bResult = true; } else if( aRange.match( lcl_aLabelRangePrefix )) { sal_Int32 nIndex = aRange.copy( lcl_aLabelRangePrefix.getLength()).toInt32(); bResult = (nIndex < (m_bDataInColumns ? m_aInternalData.getColumnCount(): m_aInternalData.getRowCount())); } else { sal_Int32 nIndex = aRange.toInt32(); bResult = (nIndex < (m_bDataInColumns ? m_aInternalData.getColumnCount(): m_aInternalData.getRowCount())); } return bResult; } Sequence< uno::Any > SAL_CALL InternalDataProvider::getDataByRangeRepresentation( const OUString& aRange ) throw (uno::RuntimeException) { Sequence< uno::Any > aResult; if( aRange.match( lcl_aLabelRangePrefix ) ) { sal_Int32 nIndex = aRange.copy( lcl_aLabelRangePrefix.getLength()).toInt32(); vector< OUString > aComplexLabel = m_bDataInColumns ? m_aInternalData.getComplexColumnLabel( nIndex ) : m_aInternalData.getComplexRowLabel( nIndex ); if( !aComplexLabel.empty() ) { aResult.realloc( aComplexLabel.size() ); transform( aComplexLabel.begin(), aComplexLabel.end(), aResult.getArray(), CommonFunctors::makeAny< OUString >()); } } else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) ) { sal_Int32 nPointIndex = aRange.copy( lcl_aCategoriesPointRangeNamePrefix.getLength() ).toInt32(); vector< OUString > aComplexCategory = m_bDataInColumns ? m_aInternalData.getComplexRowLabel( nPointIndex ) : m_aInternalData.getComplexColumnLabel( nPointIndex ); if( !aComplexCategory.empty() ) { aResult.realloc( aComplexCategory.size() ); transform( aComplexCategory.begin(), aComplexCategory.end(), aResult.getArray(), CommonFunctors::makeAny< OUString >()); } } else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) ) { sal_Int32 nLevel = aRange.copy( lcl_aCategoriesLevelRangeNamePrefix.getLength() ).toInt32(); vector< vector< OUString > > aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels()); if( nLevel < lcl_getInnerLevelCount( aCategories ) ) { aResult.realloc( aCategories.size() ); transform( aCategories.begin(), aCategories.end(), aResult.getArray(), lcl_makeAnyFromLevelVector(nLevel) ); } } else if( aRange.equals( lcl_aCategoriesRangeName ) ) { Sequence< OUString > aLabels = m_bDataInColumns ? this->getRowDescriptions() : this->getColumnDescriptions(); aResult.realloc( aLabels.getLength() ); transform( aLabels.getConstArray(), aLabels.getConstArray() + aLabels.getLength(), aResult.getArray(), CommonFunctors::makeAny< OUString >() ); } else { sal_Int32 nIndex = aRange.toInt32(); if( nIndex >= 0 ) { Sequence< double > aData; if( m_bDataInColumns ) aData = m_aInternalData.getColumnValues(nIndex); else aData = m_aInternalData.getRowValues(nIndex); if( aData.getLength() ) { aResult.realloc( aData.getLength()); transform( aData.getConstArray(), aData.getConstArray() + aData.getLength(), aResult.getArray(), CommonFunctors::makeAny< double >()); } } } return aResult; } void SAL_CALL InternalDataProvider::setDataByRangeRepresentation( const OUString& aRange, const Sequence< uno::Any >& aNewData ) throw (uno::RuntimeException) { if( aRange.match( lcl_aLabelRangePrefix ) ) { vector< OUString > aNewStrings( lcl_AnyToStringVector( aNewData ) ); sal_uInt32 nIndex = aRange.copy( lcl_aLabelRangePrefix.getLength()).toInt32(); if( m_bDataInColumns ) m_aInternalData.setComplexColumnLabel( nIndex, aNewStrings ); else m_aInternalData.setComplexRowLabel( nIndex, aNewStrings ); } else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) ) { vector< OUString > aNewStrings( lcl_AnyToStringVector( aNewData ) ); sal_Int32 nPointIndex = aRange.copy( lcl_aCategoriesLevelRangeNamePrefix.getLength()).toInt32(); if( m_bDataInColumns ) m_aInternalData.setComplexRowLabel( nPointIndex, aNewStrings ); else m_aInternalData.setComplexColumnLabel( nPointIndex, aNewStrings ); } else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) ) { vector< OUString > aNewStrings( lcl_AnyToStringVector( aNewData ) ); sal_Int32 nLevel = aRange.copy( lcl_aCategoriesLevelRangeNamePrefix.getLength()).toInt32(); vector< vector< OUString > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels(); //ensure equal length if( aNewStrings.size() > aComplexCategories.size() ) aComplexCategories.resize( aNewStrings.size() ); else if( aNewStrings.size() < aComplexCategories.size() ) aNewStrings.resize( aComplexCategories.size() ); transform( aComplexCategories.begin(), aComplexCategories.end(), aNewStrings.begin(), aComplexCategories.begin(), lcl_setStringAtLevel(nLevel) ); if( m_bDataInColumns ) m_aInternalData.setComplexRowLabels( aComplexCategories ); else m_aInternalData.setComplexColumnLabels( aComplexCategories ); } else if( aRange.equals( lcl_aCategoriesRangeName ) ) { if( m_bDataInColumns ) this->setRowDescriptions( lcl_AnyToStringSequence(aNewData) ); else this->setColumnDescriptions( lcl_AnyToStringSequence(aNewData) ); } else { sal_Int32 nIndex = aRange.toInt32(); if( nIndex>=0 ) { vector< double > aNewDataVec; transform( aNewData.getConstArray(), aNewData.getConstArray() + aNewData.getLength(), back_inserter( aNewDataVec ), CommonFunctors::AnyToDouble()); if( m_bDataInColumns ) m_aInternalData.setColumnValues( nIndex, aNewDataVec ); else m_aInternalData.setRowValues( nIndex, aNewDataVec ); } } } void SAL_CALL InternalDataProvider::insertSequence( ::sal_Int32 nAfterIndex ) throw (uno::RuntimeException) { if( m_bDataInColumns ) { lcl_increaseMapReferences( nAfterIndex + 1, m_aInternalData.getColumnCount()); m_aInternalData.insertColumn( nAfterIndex ); } else { lcl_increaseMapReferences( nAfterIndex + 1, m_aInternalData.getRowCount()); m_aInternalData.insertRow( nAfterIndex ); } } void SAL_CALL InternalDataProvider::deleteSequence( ::sal_Int32 nAtIndex ) throw (uno::RuntimeException) { lcl_deleteMapReferences( OUString::valueOf( nAtIndex )); lcl_deleteMapReferences( lcl_aLabelRangePrefix + OUString::valueOf( nAtIndex )); if( m_bDataInColumns ) { lcl_decreaseMapReferences( nAtIndex + 1, m_aInternalData.getColumnCount()); m_aInternalData.deleteColumn( nAtIndex ); } else { lcl_decreaseMapReferences( nAtIndex + 1, m_aInternalData.getRowCount()); m_aInternalData.deleteRow( nAtIndex ); } } void SAL_CALL InternalDataProvider::appendSequence() throw (uno::RuntimeException) { if( m_bDataInColumns ) m_aInternalData.appendColumn(); else m_aInternalData.appendRow(); } void SAL_CALL InternalDataProvider::insertComplexCategoryLevel( sal_Int32 nLevel ) throw (uno::RuntimeException) { OSL_ENSURE( nLevel> 0, "you can only insert category levels > 0" );//the first categories level cannot be deleted, check the calling code for error if( nLevel>0 ) { vector< vector< OUString > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels(); ::std::for_each( aComplexCategories.begin(), aComplexCategories.end(), lcl_insertStringAtLevel(nLevel) ); if( m_bDataInColumns ) m_aInternalData.setComplexRowLabels( aComplexCategories ); else m_aInternalData.setComplexColumnLabels( aComplexCategories ); tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); ::std::for_each( aRange.first, aRange.second, lcl_setModified()); } } void SAL_CALL InternalDataProvider::deleteComplexCategoryLevel( sal_Int32 nLevel ) throw (uno::RuntimeException) { OSL_ENSURE( nLevel>0, "you can only delete category levels > 0" );//the first categories level cannot be deleted, check the calling code for error if( nLevel>0 ) { vector< vector< OUString > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels(); ::std::for_each( aComplexCategories.begin(), aComplexCategories.end(), lcl_removeStringAtLevel(nLevel) ); if( m_bDataInColumns ) m_aInternalData.setComplexRowLabels( aComplexCategories ); else m_aInternalData.setComplexColumnLabels( aComplexCategories ); tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); ::std::for_each( aRange.first, aRange.second, lcl_setModified()); } } void SAL_CALL InternalDataProvider::insertDataPointForAllSequences( ::sal_Int32 nAfterIndex ) throw (uno::RuntimeException) { sal_Int32 nMaxRep = 0; if( m_bDataInColumns ) { m_aInternalData.insertRow( nAfterIndex ); nMaxRep = m_aInternalData.getColumnCount(); } else { m_aInternalData.insertColumn( nAfterIndex ); nMaxRep = m_aInternalData.getRowCount(); } // notify change to all affected ranges tSequenceMap::const_iterator aBegin( m_aSequenceMap.lower_bound( C2U("0"))); tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::valueOf( nMaxRep ))); ::std::for_each( aBegin, aEnd, lcl_setModified()); tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); ::std::for_each( aRange.first, aRange.second, lcl_setModified()); } void SAL_CALL InternalDataProvider::deleteDataPointForAllSequences( ::sal_Int32 nAtIndex ) throw (uno::RuntimeException) { sal_Int32 nMaxRep = 0; if( m_bDataInColumns ) { m_aInternalData.deleteRow( nAtIndex ); nMaxRep = m_aInternalData.getColumnCount(); } else { m_aInternalData.deleteColumn( nAtIndex ); nMaxRep = m_aInternalData.getRowCount(); } // notify change to all affected ranges tSequenceMap::const_iterator aBegin( m_aSequenceMap.lower_bound( C2U("0"))); tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::valueOf( nMaxRep ))); ::std::for_each( aBegin, aEnd, lcl_setModified()); tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); ::std::for_each( aRange.first, aRange.second, lcl_setModified()); } void SAL_CALL InternalDataProvider::swapDataPointWithNextOneForAllSequences( ::sal_Int32 nAtIndex ) throw (uno::RuntimeException) { if( m_bDataInColumns ) m_aInternalData.swapRowWithNext( nAtIndex ); else m_aInternalData.swapColumnWithNext( nAtIndex ); sal_Int32 nMaxRep = (m_bDataInColumns ? m_aInternalData.getColumnCount() : m_aInternalData.getRowCount()); // notify change to all affected ranges tSequenceMap::const_iterator aBegin( m_aSequenceMap.lower_bound( C2U("0"))); tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::valueOf( nMaxRep ))); ::std::for_each( aBegin, aEnd, lcl_setModified()); tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); ::std::for_each( aRange.first, aRange.second, lcl_setModified()); } void SAL_CALL InternalDataProvider::registerDataSequenceForChanges( const Reference< chart2::data::XDataSequence >& xSeq ) throw (uno::RuntimeException) { if( xSeq.is()) lcl_addDataSequenceToMap( xSeq->getSourceRangeRepresentation(), xSeq ); } // ____ XRangeXMLConversion ____ OUString SAL_CALL InternalDataProvider::convertRangeToXML( const OUString& aRangeRepresentation ) throw (lang::IllegalArgumentException, uno::RuntimeException) { XMLRangeHelper::CellRange aRange; aRange.aTableName = OUString(RTL_CONSTASCII_USTRINGPARAM("local-table")); // attention: this data provider has the limitation that it stores // internally if data comes from columns or rows. It is intended for // creating only one used data source. // @todo: add this information in the range representation strings if( aRangeRepresentation.match( lcl_aCategoriesRangeName )) { OSL_ASSERT( aRangeRepresentation.equals( lcl_aCategoriesRangeName ) );//it is not expected nor implmented that only parts of the categories are really requested aRange.aUpperLeft.bIsEmpty = false; if( m_bDataInColumns ) { aRange.aUpperLeft.nColumn = 0; aRange.aUpperLeft.nRow = 1; aRange.aLowerRight = aRange.aUpperLeft; aRange.aLowerRight.nRow = m_aInternalData.getRowCount(); } else { aRange.aUpperLeft.nColumn = 1; aRange.aUpperLeft.nRow = 0; aRange.aLowerRight = aRange.aUpperLeft; aRange.aLowerRight.nColumn = m_aInternalData.getColumnCount(); } } else if( aRangeRepresentation.match( lcl_aLabelRangePrefix )) { sal_Int32 nIndex = aRangeRepresentation.copy( lcl_aLabelRangePrefix.getLength()).toInt32(); aRange.aUpperLeft.bIsEmpty = false; aRange.aLowerRight.bIsEmpty = true; if( m_bDataInColumns ) { aRange.aUpperLeft.nColumn = nIndex + 1; aRange.aUpperLeft.nRow = 0; } else { aRange.aUpperLeft.nColumn = 0; aRange.aUpperLeft.nRow = nIndex + 1; } } else if( aRangeRepresentation.equals( lcl_aCompleteRange )) { aRange.aUpperLeft.bIsEmpty = false; aRange.aLowerRight.bIsEmpty = false; aRange.aUpperLeft.nColumn = 0; aRange.aUpperLeft.nRow = 0; aRange.aLowerRight.nColumn = m_aInternalData.getColumnCount(); aRange.aLowerRight.nRow = m_aInternalData.getRowCount(); } else { sal_Int32 nIndex = aRangeRepresentation.toInt32(); aRange.aUpperLeft.bIsEmpty = false; if( m_bDataInColumns ) { aRange.aUpperLeft.nColumn = nIndex + 1; aRange.aUpperLeft.nRow = 1; aRange.aLowerRight = aRange.aUpperLeft; aRange.aLowerRight.nRow = m_aInternalData.getRowCount(); } else { aRange.aUpperLeft.nColumn = 1; aRange.aUpperLeft.nRow = nIndex + 1; aRange.aLowerRight = aRange.aUpperLeft; aRange.aLowerRight.nColumn = m_aInternalData.getColumnCount(); } } return XMLRangeHelper::getXMLStringFromCellRange( aRange ); } OUString SAL_CALL InternalDataProvider::convertRangeFromXML( const OUString& aXMLRange ) throw (lang::IllegalArgumentException, uno::RuntimeException) { XMLRangeHelper::CellRange aRange( XMLRangeHelper::getCellRangeFromXMLString( aXMLRange )); if( aRange.aUpperLeft.bIsEmpty ) { OSL_ENSURE( aRange.aLowerRight.bIsEmpty, "Weird Range" ); return OUString(); } // "all" if( !aRange.aLowerRight.bIsEmpty && ( aRange.aUpperLeft.nColumn != aRange.aLowerRight.nColumn ) && ( aRange.aUpperLeft.nRow != aRange.aLowerRight.nRow ) ) return lcl_aCompleteRange; // attention: this data provider has the limitation that it stores // internally if data comes from columns or rows. It is intended for // creating only one used data source. // @todo: add this information in the range representation strings // data in columns if( m_bDataInColumns ) { if( aRange.aUpperLeft.nColumn == 0 ) return lcl_aCategoriesRangeName; if( aRange.aUpperLeft.nRow == 0 ) return lcl_aLabelRangePrefix + OUString::valueOf( aRange.aUpperLeft.nColumn - 1 ); return OUString::valueOf( aRange.aUpperLeft.nColumn - 1 ); } // data in rows if( aRange.aUpperLeft.nRow == 0 ) return lcl_aCategoriesRangeName; if( aRange.aUpperLeft.nColumn == 0 ) return lcl_aLabelRangePrefix + OUString::valueOf( aRange.aUpperLeft.nRow - 1 ); return OUString::valueOf( aRange.aUpperLeft.nRow - 1 ); } namespace { Sequence< Sequence< OUString > > lcl_convertComplexVectorToSequence( const vector< vector< OUString > >& rIn ) { Sequence< Sequence< OUString > > aRet; sal_Int32 nOuterCount = rIn.size(); if( nOuterCount ) { aRet.realloc(nOuterCount); for( sal_Int32 nN=0; nN > lcl_convertComplexSequenceToVector( const Sequence< Sequence< OUString > >& rIn ) { vector< vector< OUString > > aRet; sal_Int32 nOuterCount = rIn.getLength(); for( sal_Int32 nN=0; nN >& rComplexDescriptions ) : m_rComplexDescriptions( rComplexDescriptions ) {} virtual ~SplitCategoriesProvider_ForComplexDescriptions() {} virtual sal_Int32 getLevelCount() const; virtual uno::Sequence< rtl::OUString > getStringsForLevel( sal_Int32 nIndex ) const; private: const ::std::vector< ::std::vector< ::rtl::OUString > >& m_rComplexDescriptions; }; sal_Int32 SplitCategoriesProvider_ForComplexDescriptions::getLevelCount() const { return lcl_getInnerLevelCount( m_rComplexDescriptions ); } uno::Sequence< rtl::OUString > SplitCategoriesProvider_ForComplexDescriptions::getStringsForLevel( sal_Int32 nLevel ) const { uno::Sequence< rtl::OUString > aResult; if( nLevel < lcl_getInnerLevelCount( m_rComplexDescriptions ) ) { aResult.realloc( m_rComplexDescriptions.size() ); transform( m_rComplexDescriptions.begin(), m_rComplexDescriptions.end(), aResult.getArray(), lcl_getStringFromLevelVector(nLevel) ); } return aResult; } }//anonymous namespace // ____ XComplexDescriptionAccess ____ Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexRowDescriptions() throw (uno::RuntimeException) { return lcl_convertComplexVectorToSequence( m_aInternalData.getComplexRowLabels() ); } void SAL_CALL InternalDataProvider::setComplexRowDescriptions( const Sequence< Sequence< ::rtl::OUString > >& aRowDescriptions ) throw (uno::RuntimeException) { m_aInternalData.setComplexRowLabels( lcl_convertComplexSequenceToVector(aRowDescriptions) ); } Sequence< Sequence< ::rtl::OUString > > SAL_CALL InternalDataProvider::getComplexColumnDescriptions() throw (uno::RuntimeException) { return lcl_convertComplexVectorToSequence( m_aInternalData.getComplexColumnLabels() ); } void SAL_CALL InternalDataProvider::setComplexColumnDescriptions( const Sequence< Sequence< ::rtl::OUString > >& aColumnDescriptions ) throw (uno::RuntimeException) { m_aInternalData.setComplexColumnLabels( lcl_convertComplexSequenceToVector(aColumnDescriptions) ); } // ____ XChartDataArray ____ Sequence< Sequence< double > > SAL_CALL InternalDataProvider::getData() throw (uno::RuntimeException) { return m_aInternalData.getData(); } void SAL_CALL InternalDataProvider::setData( const Sequence< Sequence< double > >& rDataInRows ) throw (uno::RuntimeException) { return m_aInternalData.setData( rDataInRows ); } void SAL_CALL InternalDataProvider::setRowDescriptions( const Sequence< OUString >& aRowDescriptions ) throw (uno::RuntimeException) { vector< vector< OUString > > aComplexDescriptions( aRowDescriptions.getLength() ); transform( aComplexDescriptions.begin(), aComplexDescriptions.end(), aRowDescriptions.getConstArray(), aComplexDescriptions.begin(), lcl_setStringAtLevel(0) ); m_aInternalData.setComplexRowLabels( aComplexDescriptions ); } void SAL_CALL InternalDataProvider::setColumnDescriptions( const Sequence< OUString >& aColumnDescriptions ) throw (uno::RuntimeException) { vector< vector< OUString > > aComplexDescriptions( aColumnDescriptions.getLength() ); transform( aComplexDescriptions.begin(), aComplexDescriptions.end(), aColumnDescriptions.getConstArray(), aComplexDescriptions.begin(), lcl_setStringAtLevel(0) ); m_aInternalData.setComplexColumnLabels( aComplexDescriptions ); } Sequence< OUString > SAL_CALL InternalDataProvider::getRowDescriptions() throw (uno::RuntimeException) { vector< vector< OUString > > aComplexLabels( m_aInternalData.getComplexRowLabels() ); SplitCategoriesProvider_ForComplexDescriptions aProvider( aComplexLabels ); return ExplicitCategoriesProvider::getExplicitSimpleCategories( aProvider ); } Sequence< OUString > SAL_CALL InternalDataProvider::getColumnDescriptions() throw (uno::RuntimeException) { vector< vector< OUString > > aComplexLabels( m_aInternalData.getComplexColumnLabels() ); SplitCategoriesProvider_ForComplexDescriptions aProvider( aComplexLabels ); return ExplicitCategoriesProvider::getExplicitSimpleCategories( aProvider ); } // ____ XChartData (base of XChartDataArray) ____ void SAL_CALL InternalDataProvider::addChartDataChangeEventListener( const Reference< ::com::sun::star::chart::XChartDataChangeEventListener >& ) throw (uno::RuntimeException) { } void SAL_CALL InternalDataProvider::removeChartDataChangeEventListener( const Reference< ::com::sun::star::chart::XChartDataChangeEventListener >& ) throw (uno::RuntimeException) { } double SAL_CALL InternalDataProvider::getNotANumber() throw (uno::RuntimeException) { double fNan; ::rtl::math::setNan( & fNan ); return fNan; } ::sal_Bool SAL_CALL InternalDataProvider::isNotANumber( double nNumber ) throw (uno::RuntimeException) { return ::rtl::math::isNan( nNumber ) || ::rtl::math::isInf( nNumber ); } // lang::XInitialization: void SAL_CALL InternalDataProvider::initialize(const uno::Sequence< uno::Any > & _aArguments) throw (uno::RuntimeException, uno::Exception) { comphelper::SequenceAsHashMap aArgs(_aArguments); if ( aArgs.getUnpackedValueOrDefault(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CreateDefaultData")),sal_False) ) createDefaultData(); } // ____ XCloneable ____ Reference< util::XCloneable > SAL_CALL InternalDataProvider::createClone() throw (uno::RuntimeException) { return Reference< util::XCloneable >( new InternalDataProvider( *this )); } // ================================================================================ Sequence< OUString > InternalDataProvider::getSupportedServiceNames_Static() { Sequence< OUString > aServices( 1 ); aServices[ 0 ] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.data.DataProvider" )); return aServices; } // ================================================================================ APPHELPER_XSERVICEINFO_IMPL( InternalDataProvider, lcl_aServiceName ); } // namespace chart