Files
loongoffice/chart2/source/tools/InternalDataProvider.cxx
Kohei Yoshida 6c4e21a234 bnc#812796: Correctly handle static value array for OOXML charts.
We need to pass the role of the data sequence in order to avoid unreliable
guess work when importing static value array.

Also, not all Excel's scatter plots have real numeric X values; some have
textural X values in which case Excel switch to generating 1, 2, 3, ... as
X values.  When importing to our chart implementation, using "categories" role
in such cases instead of "values-x" results in a more faithful chart rendering.

Change-Id: If4bc1f650bb024dcd1b1b36537f457fb38404a78
2014-07-02 20:56:31 -04:00

1557 lines
59 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <rtl/math.hxx>
#include <valarray>
#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 <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/chart2/data/XDataSequence.hpp>
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <rtl/ustrbuf.hxx>
#include <unotools/charclass.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <vector>
#include <algorithm>
using namespace ::com::sun::star;
using namespace ::std;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
namespace chart
{
namespace
{
// note: in xmloff this name is used to indicate usage of own data
static const OUString lcl_aServiceName( "com.sun.star.comp.chart.InternalDataProvider" );
static const OUString lcl_aCategoriesRangeName( "categories" );
static const OUString lcl_aCategoriesLevelRangeNamePrefix( "categoriesL " ); //L <-> level
static const OUString lcl_aCategoriesPointRangeNamePrefix( "categoriesP " ); //P <-> point
static const OUString lcl_aCategoriesRoleName( "categories" );
static const OUString lcl_aLabelRangePrefix( "label " );
static const OUString lcl_aCompleteRange( "all" );
typedef ::std::multimap< OUString, uno::WeakReference< chart2::data::XDataSequence > >
lcl_tSequenceMap;
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;
}
Sequence< uno::Any > lcl_StringToAnySequence( const Sequence< OUString >& aStringSeq )
{
Sequence< uno::Any > aResult;
aResult.realloc( aStringSeq.getLength() );
transform( aStringSeq.getConstArray(), aStringSeq.getConstArray() + aStringSeq.getLength(),
aResult.getArray(), CommonFunctors::makeAny< OUString >() );
return aResult;
}
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<aOldSeriesData.getLength(); ++i )
{
sal_Int32 nNewIndex( m_bDataInColumns ? m_rInternalData.appendColumn() : m_rInternalData.appendRow() );
OUString aIdentifier( OUString::number( nNewIndex ));
//@todo: deal also with genericXDataSequence
Reference< chart2::data::XNumericalDataSequence > 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( lcl_StringToAnySequence( xLabel->getTextualData() ) ) );
else
m_rInternalData.setComplexRowLabel( nNewIndex, ContainerHelper::SequenceToVector( lcl_StringToAnySequence( 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_copyFromLevel : public ::std::unary_function< vector< uno::Any >, uno::Any >
{
public:
explicit lcl_copyFromLevel( sal_Int32 nLevel ) : m_nLevel( nLevel )
{}
uno::Any operator() ( const vector< uno::Any >& rVector )
{
uno::Any aRet;
if( m_nLevel < static_cast< sal_Int32 >(rVector.size()) )
aRet = rVector[m_nLevel];
return aRet;
}
private:
sal_Int32 m_nLevel;
};
struct lcl_getStringFromLevelVector : public ::std::unary_function< vector< uno::Any >, OUString >
{
public:
explicit lcl_getStringFromLevelVector( sal_Int32 nLevel ) : m_nLevel( nLevel )
{}
OUString operator() ( const vector< uno::Any >& rVector )
{
OUString aString;
if( m_nLevel < static_cast< sal_Int32 >(rVector.size()) )
aString = CommonFunctors::AnyToString()(rVector[m_nLevel]);
return aString;
}
private:
sal_Int32 m_nLevel;
};
struct lcl_setAnyAtLevel : public ::std::binary_function< vector< uno::Any >, uno::Any, vector< uno::Any > >
{
public:
explicit lcl_setAnyAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel )
{}
vector< uno::Any > operator() ( const vector< uno::Any >& rVector, const uno::Any& rNewValue )
{
vector< uno::Any > aRet( rVector );
if( m_nLevel >= static_cast< sal_Int32 >(aRet.size()) )
aRet.resize( m_nLevel+1 );
aRet[ m_nLevel ]=rNewValue;
return aRet;
}
private:
sal_Int32 m_nLevel;
};
struct lcl_setAnyAtLevelFromStringSequence : public ::std::binary_function< vector< uno::Any >, OUString, vector< uno::Any > >
{
public:
explicit lcl_setAnyAtLevelFromStringSequence( sal_Int32 nLevel ) : m_nLevel( nLevel )
{}
vector< uno::Any > operator() ( const vector< uno::Any >& rVector, const OUString& rNewValue )
{
vector< uno::Any > aRet( rVector );
if( m_nLevel >= static_cast< sal_Int32 >(aRet.size()) )
aRet.resize( m_nLevel+1 );
aRet[ m_nLevel ]=uno::makeAny(rNewValue);
return aRet;
}
private:
sal_Int32 m_nLevel;
};
struct lcl_insertAnyAtLevel : public ::std::unary_function< vector< uno::Any >, void >
{
public:
explicit lcl_insertAnyAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel )
{}
void operator() ( vector< uno::Any >& rVector )
{
if( m_nLevel >= static_cast< sal_Int32 >(rVector.size()) )
{
rVector.resize( m_nLevel + 1 );
}
else
{
rVector.insert( rVector.begin() + m_nLevel, uno::Any() );
}
}
private:
sal_Int32 m_nLevel;
};
struct lcl_removeAnyAtLevel : public ::std::unary_function< vector< uno::Any >, void >
{
public:
explicit lcl_removeAnyAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel )
{}
void operator() ( vector< uno::Any >& rVector )
{
if( m_nLevel < static_cast<sal_Int32>(rVector.size()) )
{
rVector.erase(rVector.begin() + m_nLevel);
}
}
private:
sal_Int32 m_nLevel;
};
} // anonymous namespace
InternalDataProvider::InternalDataProvider( const Reference< uno::XComponentContext > & /*_xContext*/)
: m_bDataInColumns( true )
{}
InternalDataProvider::InternalDataProvider(
const Reference< chart2::XChartDocument > & xChartDoc,
bool bConnectToModel,
bool bDefaultDataInColumns)
: m_bDataInColumns( bDefaultDataInColumns )
{
try
{
Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartDoc ) );
if( xDiagram.is())
{
Reference< frame::XModel > xChartModel( xChartDoc, uno::UNO_QUERY );
//data in columns?
{
OUString aRangeString;
bool bFirstCellAsLabel = true;
bool bHasCategories = true;
uno::Sequence< sal_Int32 > aSequenceMapping;
const bool bSomethingDetected(
DataSourceHelper::detectRangeSegmentation(
xChartModel, aRangeString, aSequenceMapping, m_bDataInColumns, bFirstCellAsLabel, bHasCategories ));
// #i120559# if no data was available, restore default
if(!bSomethingDetected && m_bDataInColumns != bDefaultDataInColumns)
{
m_bDataInColumns = bDefaultDataInColumns;
}
}
// categories
{
vector< vector< uno::Any > > aNewCategories;//inner count is level
{
ChartModel& rModel = dynamic_cast<ChartModel&>(*xChartModel.get());
ExplicitCategoriesProvider aExplicitCategoriesProvider(ChartModelHelper::getFirstCoordinateSystem(xChartModel), rModel);
const Sequence< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList( aExplicitCategoriesProvider.getSplitCategoriesList() );
sal_Int32 nLevelCount = rSplitCategoriesList.getLength();
for( sal_Int32 nL = 0; nL<nLevelCount; nL++ )
{
Reference< chart2::data::XLabeledDataSequence > xLDS( rSplitCategoriesList[nL] );
if( !xLDS.is() )
continue;
Sequence< uno::Any > aDataSeq;
Reference< chart2::data::XDataSequence > xSeq( xLDS->getValues() );
if( xSeq.is() )
aDataSeq = xSeq->getData();
sal_Int32 nLength = aDataSeq.getLength();
sal_Int32 nCatLength = static_cast< sal_Int32 >(aNewCategories.size());
if( nCatLength < nLength )
aNewCategories.resize( nLength );
else if( nLength < nCatLength )
aDataSeq.realloc( nCatLength );
transform( aNewCategories.begin(), aNewCategories.end(), aDataSeq.getConstArray(),
aNewCategories.begin(), lcl_setAnyAtLevel(nL) );
}
if( !nLevelCount )
{
Sequence< OUString > aSimplecategories = aExplicitCategoriesProvider.getSimpleCategories();
sal_Int32 nLength = aSimplecategories.getLength();
aNewCategories.reserve( nLength );
for( sal_Int32 nN=0; nN<nLength; nN++)
{
vector< uno::Any > aVector(1);
aVector[0] = uno::makeAny( aSimplecategories[nN] );
aNewCategories.push_back( aVector );
}
}
}
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::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::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::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::increaseMapReferences(
sal_Int32 nBegin, sal_Int32 nEnd )
{
for( sal_Int32 nIndex = nEnd - 1; nIndex >= nBegin; --nIndex )
{
adaptMapReferences( OUString::number( nIndex ),
OUString::number( nIndex + 1 ));
adaptMapReferences( lcl_aLabelRangePrefix + OUString::number( nIndex ),
lcl_aLabelRangePrefix + OUString::number( nIndex + 1 ));
}
}
void InternalDataProvider::decreaseMapReferences(
sal_Int32 nBegin, sal_Int32 nEnd )
{
for( sal_Int32 nIndex = nBegin; nIndex < nEnd; ++nIndex )
{
adaptMapReferences( OUString::number( nIndex ),
OUString::number( nIndex - 1 ));
adaptMapReferences( lcl_aLabelRangePrefix + OUString::number( nIndex ),
lcl_aLabelRangePrefix + OUString::number( nIndex - 1 ));
}
}
Reference< chart2::data::XDataSequence > InternalDataProvider::createDataSequenceAndAddToMap(
const OUString & rRangeRepresentation )
{
Reference<chart2::data::XDataSequence> xSeq = createDataSequenceFromArray(rRangeRepresentation, OUString());
if (xSeq.is())
return xSeq;
xSeq.set(new UncachedDataSequence(this, rRangeRepresentation));
addDataSequenceToMap(rRangeRepresentation, xSeq);
return xSeq;
}
uno::Reference<chart2::data::XDataSequence>
InternalDataProvider::createDataSequenceFromArray( const OUString& rArrayStr, const OUString& rRole )
{
if (rArrayStr.indexOf('{') != 0 || rArrayStr[rArrayStr.getLength()-1] != '}')
{
// Not an array string.
return uno::Reference<chart2::data::XDataSequence>();
}
bool bAllNumeric = true;
uno::Reference<chart2::data::XDataSequence> xSeq;
const sal_Unicode* p = rArrayStr.getStr();
const sal_Unicode* pEnd = p + rArrayStr.getLength();
const sal_Unicode* pElem = NULL;
OUString aElem;
std::vector<OUString> aRawElems;
++p; // Skip the first '{'.
--pEnd; // Skip the last '}'.
bool bInQuote = false;
for (; p != pEnd; ++p)
{
if (*p == '"')
{
bInQuote = !bInQuote;
if (bInQuote)
{
// Opening quote.
bAllNumeric = false;
++p;
if (p == pEnd)
break;
pElem = p;
}
else
{
// Closing quote.
if (pElem)
aElem = OUString(pElem, p-pElem);
aRawElems.push_back(aElem);
pElem = NULL;
aElem = OUString();
++p; // Skip '"'.
if (p == pEnd)
break;
}
}
else if (bInQuote)
{
// Do nothing.
}
else if (*p == ';')
{
// element separator.
if (pElem)
aElem = OUString(pElem, p-pElem);
aRawElems.push_back(aElem);
pElem = NULL;
aElem = OUString();
}
else if (!pElem)
pElem = p;
}
if (pElem)
{
aElem = OUString(pElem, p-pElem);
aRawElems.push_back(aElem);
}
if (rRole == "values-y" || rRole == "values-first" || rRole == "values-last" ||
rRole == "values-min" || rRole == "values-max")
{
// Column values. Append a new data column and populate it.
std::vector<double> aValues;
aValues.reserve(aRawElems.size());
for (size_t i = 0; i < aRawElems.size(); ++i)
aValues.push_back(aRawElems[i].toDouble());
sal_Int32 n = m_aInternalData.appendColumn();
m_aInternalData.setColumnValues(n, aValues);
OUString aRangeRep = OUString::number(n);
xSeq.set(new UncachedDataSequence(this, aRangeRep));
addDataSequenceToMap(aRangeRep, xSeq);
}
else if (rRole == "values-x")
{
std::vector<double> aValues;
aValues.reserve(aRawElems.size());
if (bAllNumeric)
{
for (size_t i = 0; i < aRawElems.size(); ++i)
aValues.push_back(aRawElems[i].toDouble());
}
else
{
for (size_t i = 0; i < aRawElems.size(); ++i)
aValues.push_back(i+1);
}
sal_Int32 n = m_aInternalData.appendColumn();
m_aInternalData.setColumnValues(n, aValues);
OUString aRangeRep = OUString::number(n);
xSeq.set(new UncachedDataSequence(this, aRangeRep));
addDataSequenceToMap(aRangeRep, xSeq);
}
else if (rRole == "categories")
{
// Category labels.
for (size_t i = 0; i < aRawElems.size(); ++i)
{
std::vector<uno::Any> aLabels(1, uno::makeAny(aRawElems[i]));
m_aInternalData.setComplexRowLabel(i, aLabels);
}
xSeq.set(new UncachedDataSequence(this, lcl_aCategoriesRangeName));
addDataSequenceToMap(lcl_aCategoriesRangeName, xSeq);
}
else if (rRole == "label")
{
// Data series label. There should be only one element. This always
// goes to the last data column.
sal_Int32 nColSize = m_aInternalData.getColumnCount();
if (!aRawElems.empty() && nColSize)
{
std::vector<uno::Any> aLabels(1, uno::makeAny(aRawElems[0]));
m_aInternalData.setComplexColumnLabel(nColSize-1, aLabels);
OUString aRangeRep = lcl_aLabelRangePrefix + OUString::number(nColSize-1);
xSeq.set(new UncachedDataSequence(this, aRangeRep));
addDataSequenceToMap(aRangeRep, xSeq);
}
}
return xSeq;
}
Reference< chart2::data::XDataSequence > InternalDataProvider::createDataSequenceAndAddToMap(
const OUString & rRangeRepresentation,
const OUString & rRole )
{
Reference< chart2::data::XDataSequence > xSeq(
new UncachedDataSequence( this, rRangeRepresentation, rRole ));
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, std::exception)
{
return true;
}
namespace
{
sal_Int32 lcl_getInnerLevelCount( const vector< vector< uno::Any > >& rLabels )
{
sal_Int32 nCount = 1;//minimum is 1!
vector< vector< uno::Any > >::const_iterator aLevelIt( rLabels.begin() );
vector< vector< uno::Any > >::const_iterator aLevelEnd( rLabels.end() );
for( ;aLevelIt!=aLevelEnd; ++aLevelIt )
{
const vector< uno::Any >& rCurrentLevelLabels = *aLevelIt;
nCount = std::max<sal_Int32>( 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, std::exception)
{
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< uno::Any > > 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<nLevelCount; nL++ )
aComplexCategories.push_back( new LabeledDataSequence(
new UncachedDataSequence( this
, lcl_aCategoriesLevelRangeNamePrefix + OUString::number( nL )
, lcl_aCategoriesRoleName ) ) );
}
else
{
sal_Int32 nPointCount = m_bDataInColumns ? m_aInternalData.getRowCount() : m_aInternalData.getColumnCount();
for( sal_Int32 nP=0; nP<nPointCount; nP++ )
aComplexCategories.push_back( new LabeledDataSequence(
new UncachedDataSequence( this
, lcl_aCategoriesPointRangeNamePrefix + OUString::number( nP )
, lcl_aCategoriesRoleName ) ) );
}
//don't add the created sequences to the map as they are used temporarily only ...
return new DataSource( ContainerHelper::ContainerToSequence(aComplexCategories) );
}
OSL_ASSERT( aRangeRepresentation.equals( lcl_aCompleteRange ));
::std::vector< Reference< chart2::data::XLabeledDataSequence > > aResultLSeqVec;
// categories
if( bHasCategories )
aResultLSeqVec.push_back(
new LabeledDataSequence( 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<nCount; ++nIdx )
{
aDataVec.push_back(
new LabeledDataSequence(
createDataSequenceAndAddToMap( OUString::number( nIdx )),
createDataSequenceAndAddToMap( lcl_aLabelRangePrefix + OUString::number( nIdx ))));
}
// 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
m_bDataInColumns = bUseColumns;
//reorder labeled sequences according to aSequenceMapping; ignore categories
for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ )
{
std::vector< LabeledDataSequence* >::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, std::exception)
{
Sequence< beans::PropertyValue > aArguments( 4 );
aArguments[0] = beans::PropertyValue(
"CellRangeRepresentation", -1, uno::makeAny( lcl_aCompleteRange ),
beans::PropertyState_DIRECT_VALUE );
aArguments[1] = beans::PropertyValue(
"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(
"FirstCellAsLabel", -1, uno::makeAny( true ), beans::PropertyState_DIRECT_VALUE );
aArguments[3] = beans::PropertyValue(
"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, std::exception)
{
return true;
}
Reference< chart2::data::XDataSequence > SAL_CALL InternalDataProvider::createDataSequenceByRangeRepresentation(
const OUString& aRangeRepresentation )
throw (lang::IllegalArgumentException,
uno::RuntimeException, std::exception)
{
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 createDataSequenceAndAddToMap( lcl_aCategoriesRangeName, lcl_aCategoriesRoleName );
}
else if( aRangeRepresentation.match( lcl_aLabelRangePrefix ))
{
// label
sal_Int32 nIndex = aRangeRepresentation.copy( lcl_aLabelRangePrefix.getLength()).toInt32();
return createDataSequenceAndAddToMap( lcl_aLabelRangePrefix + OUString::number( nIndex ));
}
else if ( aRangeRepresentation == "last" )
{
sal_Int32 nIndex = (m_bDataInColumns
? m_aInternalData.getColumnCount()
: m_aInternalData.getRowCount()) - 1;
return createDataSequenceAndAddToMap( OUString::number( nIndex ));
}
else if( !aRangeRepresentation.isEmpty())
{
// data
return createDataSequenceAndAddToMap( aRangeRepresentation );
}
return Reference< chart2::data::XDataSequence >();
}
Reference<chart2::data::XDataSequence> SAL_CALL
InternalDataProvider::createDataSequenceByValueArray(
const OUString& aRole, const OUString& aRangeRepresentation )
throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
{
return createDataSequenceFromArray(aRangeRepresentation, aRole);
}
Reference< sheet::XRangeSelection > SAL_CALL InternalDataProvider::getRangeSelection()
throw (uno::RuntimeException, std::exception)
{
// there is no range selection component
return Reference< sheet::XRangeSelection >();
}
// ____ XInternalDataProvider ____
sal_Bool SAL_CALL InternalDataProvider::hasDataByRangeRepresentation( const OUString& aRange )
throw (uno::RuntimeException, std::exception)
{
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, std::exception)
{
Sequence< uno::Any > aResult;
if( aRange.match( lcl_aLabelRangePrefix ) )
{
sal_Int32 nIndex = aRange.copy( lcl_aLabelRangePrefix.getLength()).toInt32();
vector< uno::Any > aComplexLabel = m_bDataInColumns
? m_aInternalData.getComplexColumnLabel( nIndex )
: m_aInternalData.getComplexRowLabel( nIndex );
if( !aComplexLabel.empty() )
aResult = ContainerHelper::ContainerToSequence(aComplexLabel);
}
else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) )
{
sal_Int32 nPointIndex = aRange.copy( lcl_aCategoriesPointRangeNamePrefix.getLength() ).toInt32();
vector< uno::Any > aComplexCategory = m_bDataInColumns
? m_aInternalData.getComplexRowLabel( nPointIndex )
: m_aInternalData.getComplexColumnLabel( nPointIndex );
if( !aComplexCategory.empty() )
aResult = ContainerHelper::ContainerToSequence(aComplexCategory);
}
else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) )
{
sal_Int32 nLevel = aRange.copy( lcl_aCategoriesLevelRangeNamePrefix.getLength() ).toInt32();
vector< vector< uno::Any > > 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_copyFromLevel(nLevel) );
}
}
else if( aRange.equals( lcl_aCategoriesRangeName ) )
{
vector< vector< uno::Any > > aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels());
sal_Int32 nLevelCount = lcl_getInnerLevelCount( aCategories );
if( nLevelCount == 1 )
{
sal_Int32 nL=0;
aResult = this->getDataByRangeRepresentation( lcl_aCategoriesLevelRangeNamePrefix + OUString::number( nL ) );
}
else
{
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, std::exception)
{
vector< uno::Any > aNewVector( ContainerHelper::SequenceToVector(aNewData) );
if( aRange.match( lcl_aLabelRangePrefix ) )
{
sal_uInt32 nIndex = aRange.copy( lcl_aLabelRangePrefix.getLength()).toInt32();
if( m_bDataInColumns )
m_aInternalData.setComplexColumnLabel( nIndex, aNewVector );
else
m_aInternalData.setComplexRowLabel( nIndex, aNewVector );
}
else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) )
{
sal_Int32 nPointIndex = aRange.copy( lcl_aCategoriesLevelRangeNamePrefix.getLength()).toInt32();
if( m_bDataInColumns )
m_aInternalData.setComplexRowLabel( nPointIndex, aNewVector );
else
m_aInternalData.setComplexColumnLabel( nPointIndex, aNewVector );
}
else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) )
{
sal_Int32 nLevel = aRange.copy( lcl_aCategoriesLevelRangeNamePrefix.getLength()).toInt32();
vector< vector< uno::Any > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels();
//ensure equal length
if( aNewVector.size() > aComplexCategories.size() )
aComplexCategories.resize( aNewVector.size() );
else if( aNewVector.size() < aComplexCategories.size() )
aNewVector.resize( aComplexCategories.size() );
transform( aComplexCategories.begin(), aComplexCategories.end(), aNewVector.begin(),
aComplexCategories.begin(), lcl_setAnyAtLevel(nLevel) );
if( m_bDataInColumns )
m_aInternalData.setComplexRowLabels( aComplexCategories );
else
m_aInternalData.setComplexColumnLabels( aComplexCategories );
}
else if( aRange.equals( lcl_aCategoriesRangeName ) )
{
vector< vector< uno::Any > > aComplexCategories;
aComplexCategories.resize( aNewVector.size() );
transform( aComplexCategories.begin(), aComplexCategories.end(), aNewVector.begin(),
aComplexCategories.begin(), lcl_setAnyAtLevel(0) );
if( m_bDataInColumns )
m_aInternalData.setComplexRowLabels( aComplexCategories );
else
m_aInternalData.setComplexColumnLabels( aComplexCategories );
}
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, std::exception)
{
if( m_bDataInColumns )
{
increaseMapReferences( nAfterIndex + 1, m_aInternalData.getColumnCount());
m_aInternalData.insertColumn( nAfterIndex );
}
else
{
increaseMapReferences( nAfterIndex + 1, m_aInternalData.getRowCount());
m_aInternalData.insertRow( nAfterIndex );
}
}
void SAL_CALL InternalDataProvider::deleteSequence( ::sal_Int32 nAtIndex )
throw (uno::RuntimeException, std::exception)
{
deleteMapReferences( OUString::number( nAtIndex ));
deleteMapReferences( lcl_aLabelRangePrefix + OUString::number( nAtIndex ));
if( m_bDataInColumns )
{
decreaseMapReferences( nAtIndex + 1, m_aInternalData.getColumnCount());
m_aInternalData.deleteColumn( nAtIndex );
}
else
{
decreaseMapReferences( nAtIndex + 1, m_aInternalData.getRowCount());
m_aInternalData.deleteRow( nAtIndex );
}
}
void SAL_CALL InternalDataProvider::appendSequence()
throw (uno::RuntimeException, std::exception)
{
if( m_bDataInColumns )
m_aInternalData.appendColumn();
else
m_aInternalData.appendRow();
}
void SAL_CALL InternalDataProvider::insertComplexCategoryLevel( sal_Int32 nLevel )
throw (uno::RuntimeException, std::exception)
{
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< uno::Any > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels();
::std::for_each( aComplexCategories.begin(), aComplexCategories.end(), lcl_insertAnyAtLevel(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, std::exception)
{
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< uno::Any > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels();
::std::for_each( aComplexCategories.begin(), aComplexCategories.end(), lcl_removeAnyAtLevel(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, std::exception)
{
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( "0"));
tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::number( 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, std::exception)
{
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( "0"));
tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::number( 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, std::exception)
{
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( "0"));
tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::number( 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, std::exception)
{
if( xSeq.is())
addDataSequenceToMap( xSeq->getSourceRangeRepresentation(), xSeq );
}
// ____ XRangeXMLConversion ____
OUString SAL_CALL InternalDataProvider::convertRangeToXML( const OUString& aRangeRepresentation )
throw (lang::IllegalArgumentException,
uno::RuntimeException, std::exception)
{
XMLRangeHelper::CellRange aRange;
aRange.aTableName = "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, std::exception)
{
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::number( aRange.aUpperLeft.nColumn - 1 );
return OUString::number( aRange.aUpperLeft.nColumn - 1 );
}
// data in rows
if( aRange.aUpperLeft.nRow == 0 )
return lcl_aCategoriesRangeName;
if( aRange.aUpperLeft.nColumn == 0 )
return lcl_aLabelRangePrefix + OUString::number( aRange.aUpperLeft.nRow - 1 );
return OUString::number( aRange.aUpperLeft.nRow - 1 );
}
namespace
{
template< class Type >
Sequence< Sequence< Type > > lcl_convertVectorVectorToSequenceSequence( const vector< vector< Type > >& rIn )
{
Sequence< Sequence< Type > > aRet;
sal_Int32 nOuterCount = rIn.size();
if( nOuterCount )
{
aRet.realloc(nOuterCount);
for( sal_Int32 nN=0; nN<nOuterCount; nN++)
aRet[nN]= ContainerHelper::ContainerToSequence( rIn[nN] );
}
return aRet;
}
template< class Type >
vector< vector< Type > > lcl_convertSequenceSequenceToVectorVector( const Sequence< Sequence< Type > >& rIn )
{
vector< vector< Type > > aRet;
sal_Int32 nOuterCount = rIn.getLength();
if( nOuterCount )
{
aRet.resize(nOuterCount);
for( sal_Int32 nN=0; nN<nOuterCount; nN++)
aRet[nN]= ContainerHelper::SequenceToVector( rIn[nN] );
}
return aRet;
}
Sequence< Sequence< OUString > > lcl_convertComplexAnyVectorToStringSequence( const vector< vector< uno::Any > >& rIn )
{
Sequence< Sequence< OUString > > aRet;
sal_Int32 nOuterCount = rIn.size();
if( nOuterCount )
{
aRet.realloc(nOuterCount);
for( sal_Int32 nN=0; nN<nOuterCount; nN++)
aRet[nN]= lcl_AnyToStringSequence( ContainerHelper::ContainerToSequence( rIn[nN] ) );
}
return aRet;
}
vector< vector< uno::Any > > lcl_convertComplexStringSequenceToAnyVector( const Sequence< Sequence< OUString > >& rIn )
{
vector< vector< uno::Any > > aRet;
sal_Int32 nOuterCount = rIn.getLength();
for( sal_Int32 nN=0; nN<nOuterCount; nN++)
aRet.push_back( ContainerHelper::SequenceToVector( lcl_StringToAnySequence( rIn[nN] ) ) );
return aRet;
}
class SplitCategoriesProvider_ForComplexDescriptions : public SplitCategoriesProvider
{
public:
explicit SplitCategoriesProvider_ForComplexDescriptions( const ::std::vector< ::std::vector< uno::Any > >& rComplexDescriptions )
: m_rComplexDescriptions( rComplexDescriptions )
{}
virtual ~SplitCategoriesProvider_ForComplexDescriptions()
{}
virtual sal_Int32 getLevelCount() const SAL_OVERRIDE;
virtual uno::Sequence< OUString > getStringsForLevel( sal_Int32 nIndex ) const SAL_OVERRIDE;
private:
const ::std::vector< ::std::vector< uno::Any > >& m_rComplexDescriptions;
};
sal_Int32 SplitCategoriesProvider_ForComplexDescriptions::getLevelCount() const
{
return lcl_getInnerLevelCount( m_rComplexDescriptions );
}
uno::Sequence< OUString > SplitCategoriesProvider_ForComplexDescriptions::getStringsForLevel( sal_Int32 nLevel ) const
{
uno::Sequence< 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
// ____ XDateCategories ____
Sequence< double > SAL_CALL InternalDataProvider::getDateCategories() throw (uno::RuntimeException, std::exception)
{
double fNan = InternalDataProvider::getNotANumber();
double fValue = fNan;
vector< vector< uno::Any > > aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels());
sal_Int32 nCount = aCategories.size();
Sequence< double > aDoubles( nCount );
vector< vector< uno::Any > >::iterator aIt( aCategories.begin() );
vector< vector< uno::Any > >::const_iterator aEnd( aCategories.end() );
for(sal_Int32 nN=0; nN<nCount && aIt!=aEnd; ++nN, ++aIt )
{
if( !( !aIt->empty() && ((*aIt)[0]>>=fValue) ) )
fValue = fNan;
aDoubles[nN]=fValue;
}
return aDoubles;
}
void SAL_CALL InternalDataProvider::setDateCategories( const Sequence< double >& rDates ) throw (uno::RuntimeException, std::exception)
{
sal_Int32 nCount = rDates.getLength();
vector< vector< uno::Any > > aNewCategories;
aNewCategories.reserve(nCount);
vector< uno::Any > aSingleLabel(1);
for(sal_Int32 nN=0; nN<nCount; ++nN )
{
aSingleLabel[0]=uno::makeAny(rDates[nN]);
aNewCategories.push_back(aSingleLabel);
}
if( m_bDataInColumns )
m_aInternalData.setComplexRowLabels( aNewCategories );
else
m_aInternalData.setComplexColumnLabels( aNewCategories );
}
// ____ XAnyDescriptionAccess ____
Sequence< Sequence< uno::Any > > SAL_CALL InternalDataProvider::getAnyRowDescriptions() throw (uno::RuntimeException, std::exception)
{
return lcl_convertVectorVectorToSequenceSequence( m_aInternalData.getComplexRowLabels() );
}
void SAL_CALL InternalDataProvider::setAnyRowDescriptions( const Sequence< Sequence< uno::Any > >& aRowDescriptions ) throw (uno::RuntimeException, std::exception)
{
m_aInternalData.setComplexRowLabels( lcl_convertSequenceSequenceToVectorVector( aRowDescriptions ) );
}
Sequence< Sequence< uno::Any > > SAL_CALL InternalDataProvider::getAnyColumnDescriptions() throw (uno::RuntimeException, std::exception)
{
return lcl_convertVectorVectorToSequenceSequence( m_aInternalData.getComplexColumnLabels() );
}
void SAL_CALL InternalDataProvider::setAnyColumnDescriptions( const Sequence< Sequence< uno::Any > >& aColumnDescriptions ) throw (uno::RuntimeException, std::exception)
{
m_aInternalData.setComplexColumnLabels( lcl_convertSequenceSequenceToVectorVector( aColumnDescriptions ) );
}
// ____ XComplexDescriptionAccess ____
Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexRowDescriptions() throw (uno::RuntimeException, std::exception)
{
return lcl_convertComplexAnyVectorToStringSequence( m_aInternalData.getComplexRowLabels() );
}
void SAL_CALL InternalDataProvider::setComplexRowDescriptions( const Sequence< Sequence< OUString > >& aRowDescriptions ) throw (uno::RuntimeException, std::exception)
{
m_aInternalData.setComplexRowLabels( lcl_convertComplexStringSequenceToAnyVector(aRowDescriptions) );
}
Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexColumnDescriptions() throw (uno::RuntimeException, std::exception)
{
return lcl_convertComplexAnyVectorToStringSequence( m_aInternalData.getComplexColumnLabels() );
}
void SAL_CALL InternalDataProvider::setComplexColumnDescriptions( const Sequence< Sequence< OUString > >& aColumnDescriptions ) throw (uno::RuntimeException, std::exception)
{
m_aInternalData.setComplexColumnLabels( lcl_convertComplexStringSequenceToAnyVector(aColumnDescriptions) );
}
// ____ XChartDataArray ____
Sequence< Sequence< double > > SAL_CALL InternalDataProvider::getData()
throw (uno::RuntimeException, std::exception)
{
return m_aInternalData.getData();
}
void SAL_CALL InternalDataProvider::setData( const Sequence< Sequence< double > >& rDataInRows )
throw (uno::RuntimeException, std::exception)
{
return m_aInternalData.setData( rDataInRows );
}
void SAL_CALL InternalDataProvider::setRowDescriptions( const Sequence< OUString >& aRowDescriptions )
throw (uno::RuntimeException, std::exception)
{
vector< vector< uno::Any > > aComplexDescriptions( aRowDescriptions.getLength() );
transform( aComplexDescriptions.begin(), aComplexDescriptions.end(), aRowDescriptions.getConstArray(),
aComplexDescriptions.begin(), lcl_setAnyAtLevelFromStringSequence(0) );
m_aInternalData.setComplexRowLabels( aComplexDescriptions );
}
void SAL_CALL InternalDataProvider::setColumnDescriptions( const Sequence< OUString >& aColumnDescriptions )
throw (uno::RuntimeException, std::exception)
{
vector< vector< uno::Any > > aComplexDescriptions( aColumnDescriptions.getLength() );
transform( aComplexDescriptions.begin(), aComplexDescriptions.end(), aColumnDescriptions.getConstArray(),
aComplexDescriptions.begin(), lcl_setAnyAtLevelFromStringSequence(0) );
m_aInternalData.setComplexColumnLabels( aComplexDescriptions );
}
Sequence< OUString > SAL_CALL InternalDataProvider::getRowDescriptions()
throw (uno::RuntimeException, std::exception)
{
vector< vector< uno::Any > > aComplexLabels( m_aInternalData.getComplexRowLabels() );
SplitCategoriesProvider_ForComplexDescriptions aProvider( aComplexLabels );
return ExplicitCategoriesProvider::getExplicitSimpleCategories( aProvider );
}
Sequence< OUString > SAL_CALL InternalDataProvider::getColumnDescriptions()
throw (uno::RuntimeException, std::exception)
{
vector< vector< uno::Any > > 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, std::exception)
{
}
void SAL_CALL InternalDataProvider::removeChartDataChangeEventListener(
const Reference< ::com::sun::star::chart::XChartDataChangeEventListener >& )
throw (uno::RuntimeException, std::exception)
{
}
double SAL_CALL InternalDataProvider::getNotANumber()
throw (uno::RuntimeException, std::exception)
{
double fNan;
::rtl::math::setNan( & fNan );
return fNan;
}
sal_Bool SAL_CALL InternalDataProvider::isNotANumber( double nNumber )
throw (uno::RuntimeException, std::exception)
{
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, std::exception)
{
comphelper::SequenceAsHashMap aArgs(_aArguments);
if ( aArgs.getUnpackedValueOrDefault( "CreateDefaultData" ,sal_False) )
createDefaultData();
}
// ____ XCloneable ____
Reference< util::XCloneable > SAL_CALL InternalDataProvider::createClone()
throw (uno::RuntimeException, std::exception)
{
return Reference< util::XCloneable >( new InternalDataProvider( *this ));
}
Sequence< OUString > InternalDataProvider::getSupportedServiceNames_Static()
{
Sequence< OUString > aServices( 1 );
aServices[ 0 ] = "com.sun.star.chart2.data.DataProvider";
return aServices;
}
APPHELPER_XSERVICEINFO_IMPL( InternalDataProvider, lcl_aServiceName );
} // namespace chart
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */