Files
libreoffice/chart2/source/tools/InternalDataProvider.cxx
Stephan Bergmann 0cdcb21c90 Upcoming improved loplugin:staticanonymous -> redundantstatic: chart2
Change-Id: If4e61fdcf1749b2900512ae788422c435ae6af0d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97541
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2020-06-30 22:57:53 +02:00

1529 lines
56 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 <iterator>
#include <InternalDataProvider.hxx>
#include <LabeledDataSequence.hxx>
#include <DataSource.hxx>
#include <XMLRangeHelper.hxx>
#include <CommonFunctors.hxx>
#include <UncachedDataSequence.hxx>
#include <DataSourceHelper.hxx>
#include <ChartModel.hxx>
#include <ChartModelHelper.hxx>
#include <DiagramHelper.hxx>
#include <ExplicitCategoriesProvider.hxx>
#include <com/sun/star/chart2/data/XDataSequence.hpp>
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <comphelper/property.hxx>
#include <tools/diagnose_ex.h>
#include <vector>
#include <algorithm>
namespace com::sun::star::chart2 { class XChartDocument; }
using namespace ::com::sun::star;
using namespace ::std;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
namespace chart
{
namespace
{
const char lcl_aCategoriesRangeName[] = "categories";
const char lcl_aCategoriesLevelRangeNamePrefix[] = "categoriesL "; //L <-> level
const char lcl_aCategoriesPointRangeNamePrefix[] = "categoriesP "; //P <-> point
const char lcl_aCategoriesRoleName[] = "categories";
const char lcl_aLabelRangePrefix[] = "label ";
const char lcl_aCompleteRange[] = "all";
typedef std::multimap< OUString, uno::WeakReference< chart2::data::XDataSequence > >
lcl_tSequenceMap;
std::vector< OUString > lcl_AnyToStringSequence( const std::vector< uno::Any >& aAnySeq )
{
std::vector< OUString > aResult;
aResult.resize( aAnySeq.size() );
int i = 0;
for (const uno::Any& aAny : aAnySeq)
aResult[i++] = CommonFunctors::AnyToString()(aAny);
return aResult;
}
std::vector< uno::Any > lcl_StringToAnyVector( const css::uno::Sequence< OUString >& aStringSeq )
{
std::vector< uno::Any > aResult;
aResult.resize( aStringSeq.getLength() );
int i = 0;
for (const OUString& aStr : aStringSeq)
aResult[i++] = CommonFunctors::makeAny<OUString>()(aStr);
return aResult;
}
struct lcl_setModified
{
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( true );
}
}
};
struct lcl_internalizeSeries
{
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()) )
return;
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() )
{
auto aValues( comphelper::sequenceToContainer<std::vector< double >>( 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, lcl_StringToAnyVector( xLabel->getTextualData() ) );
else
m_rInternalData.setComplexRowLabel( nNewIndex, lcl_StringToAnyVector( 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].set( new LabeledDataSequence( xNewValues, xNewLabel ) );
}
}
else
{
if( m_bConnectToModel )
aNewSeriesData[i].set( 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:
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:
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:
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:
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 ] <<= rNewValue;
return aRet;
}
private:
sal_Int32 m_nLevel;
};
struct lcl_insertAnyAtLevel
{
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:
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()
: 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;
//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);
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] <<= 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 ));
lcl_internalizeSeries ftor( m_aInternalData, *this, bConnectToModel, m_bDataInColumns );
for( const auto& rxScreen : aSeriesVector )
ftor( rxScreen );
}
}
catch( const uno::Exception & )
{
DBG_UNHANDLED_EXCEPTION("chart2");
}
}
// copy-CTOR
InternalDataProvider::InternalDataProvider( const InternalDataProvider & rOther ) :
impl::InternalDataProvider_Base(rOther),
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.emplace(
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.emplace( rNewRangeRepresentation, aIt->second );
}
// erase map values for old index
m_aSequenceMap.erase( aRange.first, aRange.second );
// add new entries for values with new index
m_aSequenceMap.insert( aNewElements.begin(), aNewElements.end() );
}
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 = nullptr;
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.
pElem = nullptr;
}
else
{
// Closing quote.
if (pElem)
aElem = OUString(pElem, p-pElem);
// Non empty string
if (!aElem.isEmpty())
bAllNumeric = false;
aRawElems.push_back(aElem);
pElem = nullptr;
aElem.clear();
++p; // Skip '"'.
if (p == pEnd)
break;
}
}
else if (*p == ';' && !bInQuote)
{
// element separator.
if (pElem)
aElem = OUString(pElem, p-pElem);
aRawElems.push_back(aElem);
pElem = nullptr;
aElem.clear();
}
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" || rRole == "values-size")
{
// Column values. Append a new data column and populate it.
std::vector<double> aValues;
aValues.reserve(aRawElems.size());
for (const OUString & aRawElem : aRawElems)
{
if (aRawElem.isEmpty())
aValues.push_back(NAN);
else
aValues.push_back(aRawElem.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 (const OUString & aRawElem : aRawElems)
{
if (!aRawElem.isEmpty())
aValues.push_back(aRawElem.toDouble());
else
aValues.push_back(NAN);
}
}
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::Any(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::Any(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;
}
// ____ XDataProvider ____
sal_Bool SAL_CALL InternalDataProvider::createDataSourcePossible( const Sequence< beans::PropertyValue >& /* aArguments */ )
{
return true;
}
namespace
{
sal_Int32 lcl_getInnerLevelCount( const vector< vector< uno::Any > >& rLabels )
{
sal_Int32 nCount = 1;//minimum is 1!
for (auto const& elemLabel : rLabels)
{
nCount = std::max<sal_Int32>( elemLabel.size(), nCount );
}
return nCount;
}
}//end anonymous namespace
Reference< chart2::data::XDataSource > SAL_CALL InternalDataProvider::createDataSource(
const Sequence< beans::PropertyValue >& aArguments )
{
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 == 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( comphelper::containerToSequence(aComplexCategories) );
}
OSL_ASSERT( aRangeRepresentation == 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());
aDataVec.reserve(nCount);
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] = nullptr;
}
}
}
//add left over data sequences to result
for (auto const& elem : aDataVec)
{
if( elem.is() )
aResultLSeqVec.push_back(elem);
}
return new DataSource( comphelper::containerToSequence(aResultLSeqVec) );
}
Sequence< beans::PropertyValue > SAL_CALL InternalDataProvider::detectArguments(
const Reference< chart2::data::XDataSource >& /* xDataSource */ )
{
Sequence< beans::PropertyValue > aArguments( 4 );
aArguments[0] = beans::PropertyValue(
"CellRangeRepresentation", -1, uno::Any( OUString(lcl_aCompleteRange) ),
beans::PropertyState_DIRECT_VALUE );
aArguments[1] = beans::PropertyValue(
"DataRowSource", -1, uno::Any(
m_bDataInColumns
? css::chart::ChartDataRowSource_COLUMNS
: css::chart::ChartDataRowSource_ROWS ),
beans::PropertyState_DIRECT_VALUE );
// internal data always contains labels and categories
aArguments[2] = beans::PropertyValue(
"FirstCellAsLabel", -1, uno::Any( true ), beans::PropertyState_DIRECT_VALUE );
aArguments[3] = beans::PropertyValue(
"HasCategories", -1, uno::Any( 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 */ )
{
return true;
}
Reference< chart2::data::XDataSequence > SAL_CALL InternalDataProvider::createDataSequenceByRangeRepresentation(
const OUString& aRangeRepresentation )
{
if( aRangeRepresentation.match( lcl_aCategoriesRangeName ))
{
OSL_ASSERT( aRangeRepresentation == lcl_aCategoriesRangeName );//it is not expected nor implemented 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( strlen(lcl_aLabelRangePrefix)).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 )
{
return createDataSequenceFromArray(aRangeRepresentation, aRole);
}
Reference< sheet::XRangeSelection > SAL_CALL InternalDataProvider::getRangeSelection()
{
// there is no range selection component
return Reference< sheet::XRangeSelection >();
}
// ____ XInternalDataProvider ____
sal_Bool SAL_CALL InternalDataProvider::hasDataByRangeRepresentation( const OUString& aRange )
{
bool bResult = false;
if( aRange.match( lcl_aCategoriesRangeName ))
{
OSL_ASSERT( aRange == lcl_aCategoriesRangeName );//it is not expected nor implemented that only parts of the categories are really requested
bResult = true;
}
else if( aRange.match( lcl_aLabelRangePrefix ))
{
sal_Int32 nIndex = aRange.copy( strlen(lcl_aLabelRangePrefix)).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 )
{
Sequence< uno::Any > aResult;
if( aRange.match( lcl_aLabelRangePrefix ) )
{
auto nIndex = aRange.copy( strlen(lcl_aLabelRangePrefix)).toUInt32();
vector< uno::Any > aComplexLabel = m_bDataInColumns
? m_aInternalData.getComplexColumnLabel( nIndex )
: m_aInternalData.getComplexRowLabel( nIndex );
if( !aComplexLabel.empty() )
aResult = comphelper::containerToSequence(aComplexLabel);
}
else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) )
{
auto nPointIndex = aRange.copy( strlen(lcl_aCategoriesPointRangeNamePrefix) ).toUInt32();
vector< uno::Any > aComplexCategory = m_bDataInColumns
? m_aInternalData.getComplexRowLabel( nPointIndex )
: m_aInternalData.getComplexColumnLabel( nPointIndex );
if( !aComplexCategory.empty() )
aResult = comphelper::containerToSequence(aComplexCategory);
}
else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) )
{
sal_Int32 nLevel = aRange.copy( strlen(lcl_aCategoriesLevelRangeNamePrefix) ).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 == lcl_aCategoriesRangeName )
{
vector< vector< uno::Any > > aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels());
sal_Int32 nLevelCount = lcl_getInnerLevelCount( aCategories );
if( nLevelCount == 1 )
{
aResult = getDataByRangeRepresentation( lcl_aCategoriesLevelRangeNamePrefix + OUString::number( 0 ) );
}
else
{
// Maybe this 'else' part and the functions is not necessary anymore.
Sequence< OUString > aLabels = m_bDataInColumns ? getRowDescriptions() : getColumnDescriptions();
aResult.realloc( aLabels.getLength() );
transform( aLabels.begin(), aLabels.end(),
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.hasElements() )
{
aResult.realloc( aData.getLength());
transform( aData.begin(), aData.end(),
aResult.getArray(), CommonFunctors::makeAny< double >());
}
}
}
return aResult;
}
void SAL_CALL InternalDataProvider::setDataByRangeRepresentation(
const OUString& aRange, const Sequence< uno::Any >& aNewData )
{
auto aNewVector( comphelper::sequenceToContainer<vector< uno::Any >>(aNewData) );
if( aRange.match( lcl_aLabelRangePrefix ) )
{
sal_uInt32 nIndex = aRange.copy( strlen(lcl_aLabelRangePrefix)).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( strlen(lcl_aCategoriesLevelRangeNamePrefix)).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( strlen(lcl_aCategoriesLevelRangeNamePrefix)).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 == 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.begin(), aNewData.end(),
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 )
{
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 )
{
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()
{
if( m_bDataInColumns )
m_aInternalData.appendColumn();
else
m_aInternalData.appendRow();
}
void SAL_CALL InternalDataProvider::insertComplexCategoryLevel( sal_Int32 nLevel )
{
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 )
{
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 )
{
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 )
{
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 )
{
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 )
{
if( xSeq.is())
addDataSequenceToMap( xSeq->getSourceRangeRepresentation(), xSeq );
}
// ____ XRangeXMLConversion ____
OUString SAL_CALL InternalDataProvider::convertRangeToXML( const OUString& aRangeRepresentation )
{
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 == lcl_aCategoriesRangeName );//it is not expected nor implemented 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( strlen(lcl_aLabelRangePrefix)).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 == 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 )
{
const OUString aPivotTableID("PT@");
if (aXMLRange.startsWith(aPivotTableID))
return aXMLRange.copy(aPivotTableID.getLength());
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]= comphelper::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]= comphelper::sequenceToContainer<vector< Type >>( rIn[nN] );
}
return aRet;
}
std::vector< Sequence< OUString > > lcl_convertComplexAnyVectorToStringSequence( const vector< vector< uno::Any > >& rIn )
{
std::vector< Sequence< OUString > > aRet;
sal_Int32 nOuterCount = rIn.size();
if( nOuterCount )
{
aRet.resize(nOuterCount);
for( sal_Int32 nN=0; nN<nOuterCount; nN++)
aRet[nN] = comphelper::containerToSequence(lcl_AnyToStringSequence( 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();
aRet.reserve(nOuterCount);
for (sal_Int32 nN = 0; nN < nOuterCount; nN++)
aRet.push_back( lcl_StringToAnyVector( 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 sal_Int32 getLevelCount() const override;
virtual uno::Sequence< OUString > getStringsForLevel( sal_Int32 nIndex ) const 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()
{
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 );
sal_Int32 nN=0;
for (auto const& category : aCategories)
{
if( !( !category.empty() && (category[0]>>=fValue) ) )
fValue = fNan;
aDoubles[nN++]=fValue;
}
return aDoubles;
}
void SAL_CALL InternalDataProvider::setDateCategories( const Sequence< double >& rDates )
{
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] <<= 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()
{
return lcl_convertVectorVectorToSequenceSequence( m_aInternalData.getComplexRowLabels() );
}
void SAL_CALL InternalDataProvider::setAnyRowDescriptions( const Sequence< Sequence< uno::Any > >& aRowDescriptions )
{
m_aInternalData.setComplexRowLabels( lcl_convertSequenceSequenceToVectorVector( aRowDescriptions ) );
}
Sequence< Sequence< uno::Any > > SAL_CALL InternalDataProvider::getAnyColumnDescriptions()
{
return lcl_convertVectorVectorToSequenceSequence( m_aInternalData.getComplexColumnLabels() );
}
void SAL_CALL InternalDataProvider::setAnyColumnDescriptions( const Sequence< Sequence< uno::Any > >& aColumnDescriptions )
{
m_aInternalData.setComplexColumnLabels( lcl_convertSequenceSequenceToVectorVector( aColumnDescriptions ) );
}
// ____ XComplexDescriptionAccess ____
Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexRowDescriptions()
{
return comphelper::containerToSequence(lcl_convertComplexAnyVectorToStringSequence( m_aInternalData.getComplexRowLabels() ));
}
void SAL_CALL InternalDataProvider::setComplexRowDescriptions( const Sequence< Sequence< OUString > >& aRowDescriptions )
{
m_aInternalData.setComplexRowLabels( lcl_convertComplexStringSequenceToAnyVector(aRowDescriptions) );
}
Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexColumnDescriptions()
{
return comphelper::containerToSequence(lcl_convertComplexAnyVectorToStringSequence( m_aInternalData.getComplexColumnLabels() ));
}
void SAL_CALL InternalDataProvider::setComplexColumnDescriptions( const Sequence< Sequence< OUString > >& aColumnDescriptions )
{
m_aInternalData.setComplexColumnLabels( lcl_convertComplexStringSequenceToAnyVector(aColumnDescriptions) );
}
// ____ XChartDataArray ____
Sequence< Sequence< double > > SAL_CALL InternalDataProvider::getData()
{
return m_aInternalData.getData();
}
void SAL_CALL InternalDataProvider::setData( const Sequence< Sequence< double > >& rDataInRows )
{
return m_aInternalData.setData( rDataInRows );
}
void SAL_CALL InternalDataProvider::setRowDescriptions( const Sequence< OUString >& aRowDescriptions )
{
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 )
{
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()
{
vector< vector< uno::Any > > aComplexLabels( m_aInternalData.getComplexRowLabels() );
SplitCategoriesProvider_ForComplexDescriptions aProvider( aComplexLabels );
return ExplicitCategoriesProvider::getExplicitSimpleCategories( aProvider );
}
Sequence< OUString > SAL_CALL InternalDataProvider::getColumnDescriptions()
{
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< css::chart::XChartDataChangeEventListener >& )
{
}
void SAL_CALL InternalDataProvider::removeChartDataChangeEventListener(
const Reference< css::chart::XChartDataChangeEventListener >& )
{
}
double SAL_CALL InternalDataProvider::getNotANumber()
{
double fNan;
::rtl::math::setNan( & fNan );
return fNan;
}
sal_Bool SAL_CALL InternalDataProvider::isNotANumber( double nNumber )
{
return std::isnan( nNumber )
|| std::isinf( nNumber );
}
// lang::XInitialization:
void SAL_CALL InternalDataProvider::initialize(const uno::Sequence< uno::Any > & _aArguments)
{
comphelper::SequenceAsHashMap aArgs(_aArguments);
if ( aArgs.getUnpackedValueOrDefault( "CreateDefaultData", false ) )
m_aInternalData.createDefaultData();
}
// ____ XCloneable ____
Reference< util::XCloneable > SAL_CALL InternalDataProvider::createClone()
{
return Reference< util::XCloneable >( new InternalDataProvider( *this ));
}
OUString SAL_CALL InternalDataProvider::getImplementationName()
{
// note: in xmloff this name is used to indicate usage of own data
return "com.sun.star.comp.chart.InternalDataProvider";
}
sal_Bool SAL_CALL InternalDataProvider::supportsService( const OUString& rServiceName )
{
return cppu::supportsService(this, rServiceName);
}
css::uno::Sequence< OUString > SAL_CALL InternalDataProvider::getSupportedServiceNames()
{
return { "com.sun.star.chart2.data.DataProvider" };
}
} // namespace chart
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_chart_InternalDataProvider_get_implementation(css::uno::XComponentContext *,
css::uno::Sequence<css::uno::Any> const &)
{
return cppu::acquire(new ::chart::InternalDataProvider);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */