Kaydet (Commit) 6c4e21a2 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

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
üst 5e2b7e37
......@@ -134,6 +134,11 @@ public:
const OUString& aRangeRepresentation )
throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
createDataSequenceByValueArray( const OUString& aRole, const OUString& aRangeRepresentation )
throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XRangeSelection > SAL_CALL getRangeSelection()
throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
......@@ -230,6 +235,9 @@ private:
::com::sun::star::chart2::data::XDataSequence >
createDataSequenceAndAddToMap( const OUString & rRangeRepresentation );
css::uno::Reference<css::chart2::data::XDataSequence>
createDataSequenceFromArray( const OUString& rArrayStr, const OUString& rRole );
void deleteMapReferences( const OUString & rRangeRepresentation );
void adaptMapReferences(
......
......@@ -491,79 +491,155 @@ void InternalDataProvider::decreaseMapReferences(
Reference< chart2::data::XDataSequence > InternalDataProvider::createDataSequenceAndAddToMap(
const OUString & rRangeRepresentation )
{
OUString aRangeRepresentation = rRangeRepresentation;
if( aRangeRepresentation.indexOf('{') >= 0 )
{
::std::vector< double > aNewData;
::std::vector< uno::Any > aNewLabels;
OUString aToken;
sal_Int32 nCategories = 0;
sal_Int32 nIndex = 0;
bool bValues = true;
bool bLabelSet = false;
OUString str = aRangeRepresentation.replace('{',' ').replace('}',' ');
m_aInternalData.clearDefaultData();
sal_Int32 n = m_aInternalData.getColumnCount();
if( n )
n = n - 1;
do
{
// TODO: This will be problematic if ';' is used in label names
// '"' character also needs to be considered in such cases
aToken = str.getToken(0,';',nIndex);
if( aToken.isEmpty() )
break;
if( aToken.indexOf('"') < 0 )
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] != '}')
{
aNewData.push_back( aToken.toDouble() );
// Not an array string.
return uno::Reference<chart2::data::XDataSequence>();
}
else
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)
{
aNewLabels.push_back( uno::makeAny(aToken.replace('"', ' ').trim()) );
if( !nCategories &&
( !m_aInternalData.getComplexColumnLabel(n).size() ||
!m_aInternalData.getComplexColumnLabel(n).front().hasValue() ) )
if (*p == '"')
{
m_aInternalData.setComplexColumnLabel( n, aNewLabels );
bLabelSet = true;
bInQuote = !bInQuote;
if (bInQuote)
{
// Opening quote.
bAllNumeric = false;
++p;
if (p == pEnd)
break;
pElem = p;
}
else
{
m_aInternalData.setComplexRowLabel(nCategories, aNewLabels);
if(nCategories==1 && bLabelSet)
// 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 == ';')
{
::std::vector< uno::Any > aLabels;
m_aInternalData.setComplexRowLabel( 0, m_aInternalData.getComplexColumnLabel( n ) );
m_aInternalData.setComplexColumnLabel( n, aLabels );
// element separator.
if (pElem)
aElem = OUString(pElem, p-pElem);
aRawElems.push_back(aElem);
pElem = NULL;
aElem = OUString();
}
else if (!pElem)
pElem = p;
}
aNewLabels.pop_back();
nCategories++;
bValues = false;
if (pElem)
{
aElem = OUString(pElem, p-pElem);
aRawElems.push_back(aElem);
}
} while( nIndex >= 0 );
if( bValues )
if (rRole == "values-y" || rRole == "values-first" || rRole == "values-last" ||
rRole == "values-min" || rRole == "values-max")
{
m_aInternalData.insertColumn( n );
m_aInternalData.setColumnValues( n, aNewData );
aRangeRepresentation = OUString::number( n );
// 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( nCategories > 1 )
else if (rRole == "values-x")
{
aRangeRepresentation = lcl_aCategoriesRangeName;
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
{
aRangeRepresentation = lcl_aLabelRangePrefix+OUString::number( n );
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);
}
}
Reference< chart2::data::XDataSequence > xSeq(
new UncachedDataSequence( this, aRangeRepresentation ));
addDataSequenceToMap( aRangeRepresentation, xSeq );
return xSeq;
}
......@@ -764,6 +840,14 @@ Reference< chart2::data::XDataSequence > SAL_CALL InternalDataProvider::createDa
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)
{
......
......@@ -81,6 +81,12 @@ private:
virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL detectArguments(const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSource > & xDataSource) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString & aRangeRepresentation) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString & aRangeRepresentation) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
createDataSequenceByValueArray(
const OUString& aRole, const OUString & aRangeRepresentation)
throw (css::uno::RuntimeException, css::lang::IllegalArgumentException, std::exception) SAL_OVERRIDE;
virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XRangeSelection > SAL_CALL getRangeSelection() throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
// ::com::sun::star::chart2::data::XRangeXMLConversion:
......
......@@ -301,6 +301,14 @@ uno::Reference< chart2::data::XDataSequence > SAL_CALL DatabaseDataProvider::cre
return xData;
}
uno::Reference<chart2::data::XDataSequence>
SAL_CALL DatabaseDataProvider::createDataSequenceByValueArray(
const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/ )
throw (uno::RuntimeException, lang::IllegalArgumentException, std::exception)
{
return uno::Reference<chart2::data::XDataSequence>();
}
uno::Sequence< uno::Sequence< OUString > > SAL_CALL DatabaseDataProvider::getComplexRowDescriptions() throw (uno::RuntimeException, std::exception)
{
return m_xComplexDescriptionAccess->getComplexRowDescriptions();
......
......@@ -83,10 +83,10 @@ public:
/** Creates a data sequence from a formula. Dummy implementation. Derived
classes have to override this function to actually parse the formula. */
virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence >
virtual css::uno::Reference<css::chart2::data::XDataSequence>
createDataSequence(
const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataProvider >& rxDataProvider,
const DataSequenceModel& rDataSeq );
const css::uno::Reference<css::chart2::data::XDataProvider>& rxDataProvider,
const DataSequenceModel& rDataSeq, const OUString& rRole );
private:
ChartConverter( const ChartConverter& );
......
......@@ -126,6 +126,9 @@ interface XDataProvider : ::com::sun::star::uno::XInterface
[in] string aRangeRepresentation )
raises( com::sun::star::lang::IllegalArgumentException );
XDataSequence createDataSequenceByValueArray( [in] string aRole, [in] string aValueArray )
raises( com::sun::star::lang::IllegalArgumentException );
/** Returns a component that is able to change a given range
representation to another one. This usually is a
controller-component that uses the GUI to allow a user to
......
......@@ -114,7 +114,9 @@ void ChartConverter::createDataProvider( const Reference< XChartDocument >& rxCh
}
}
Reference< XDataSequence > ChartConverter::createDataSequence( const Reference< XDataProvider >& rxDataProvider, const DataSequenceModel& rDataSeq )
Reference< XDataSequence > ChartConverter::createDataSequence(
const Reference< XDataProvider >& rxDataProvider, const DataSequenceModel& rDataSeq,
const OUString& rRole )
{
Reference< XDataSequence > xDataSeq;
if( rxDataProvider.is() )
......@@ -134,7 +136,7 @@ Reference< XDataSequence > ChartConverter::createDataSequence( const Reference<
if( !aRangeRep.isEmpty() ) try
{
// create the data sequence
xDataSeq = rxDataProvider->createDataSequenceByRangeRepresentation( aRangeRep );
xDataSeq = rxDataProvider->createDataSequenceByValueArray(rRole, aRangeRep);
return xDataSeq;
}
catch( Exception& )
......
......@@ -74,9 +74,9 @@ Reference< XDataSequence > DataSequenceConverter::createDataSequence( const OUSt
mrModel.maData.insert(std::make_pair<sal_Int32, Any>(1, Any(aTitle.makeStringAndClear())));
}
}
xDataSeq = getChartConverter()->createDataSequence( getChartDocument()->getDataProvider(), mrModel );
xDataSeq = getChartConverter()->createDataSequence(getChartDocument()->getDataProvider(), mrModel, rRole);
// set sequen ce role
// set sequence role
PropertySet aSeqProp( xDataSeq );
aSeqProp.setProperty( PROP_Role, rRole );
}
......
......@@ -513,7 +513,7 @@ SeriesConverter::~SeriesConverter()
Reference< XLabeledDataSequence > SeriesConverter::createCategorySequence( const OUString& rRole )
{
return createLabeledDataSequence( SeriesModel::CATEGORIES, rRole, false );
return createLabeledDataSequence(SeriesModel::CATEGORIES, rRole, false);
}
Reference< XLabeledDataSequence > SeriesConverter::createValueSequence( const OUString& rRole )
......
......@@ -97,6 +97,10 @@ public:
const OUString& aRangeRepresentation )
throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
createDataSequenceByValueArray( const OUString& aRole, const OUString& aRangeRepresentation )
throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XRangeSelection > SAL_CALL getRangeSelection()
throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
......
......@@ -37,10 +37,10 @@ public:
const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XChartDocument >& rxChartDoc ) SAL_OVERRIDE;
/** Creates a data sequence from the passed formula. */
virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence >
virtual css::uno::Reference<css::chart2::data::XDataSequence>
createDataSequence(
const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataProvider >& rxDataProvider,
const ::oox::drawingml::chart::DataSequenceModel& rDataSeq ) SAL_OVERRIDE;
const css::uno::Reference<css::chart2::data::XDataProvider>& rxDataProvider,
const oox::drawingml::chart::DataSequenceModel& rDataSeq, const OUString& rRole ) SAL_OVERRIDE;
};
} // namespace xls
......
......@@ -64,7 +64,8 @@ void ExcelChartConverter::createDataProvider( const Reference< XChartDocument >&
}
Reference< XDataSequence > ExcelChartConverter::createDataSequence(
const Reference< XDataProvider >& rxDataProvider, const DataSequenceModel& rDataSeq )
const Reference< XDataProvider >& rxDataProvider, const DataSequenceModel& rDataSeq,
const OUString& /*rRole*/ )
{
Reference< XDataSequence > xDataSeq;
if (!rxDataProvider.is())
......
......@@ -2098,6 +2098,14 @@ uno::Reference< chart2::data::XDataSequence > SAL_CALL
return xResult;
}
uno::Reference<chart2::data::XDataSequence> SAL_CALL
ScChart2DataProvider::createDataSequenceByValueArray(
const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/ )
throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception)
{
return uno::Reference<chart2::data::XDataSequence>();
}
uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
throw (uno::RuntimeException, std::exception)
{
......
......@@ -172,6 +172,11 @@ public:
virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation( const OUString& aRangeRepresentation ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XRangeSelection > SAL_CALL getRangeSelection( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
virtual css::uno::Reference<css::chart2::data::XDataSequence>
SAL_CALL createDataSequenceByValueArray(
const OUString& aRole, const OUString& aRangeRepresentation )
throw (css::lang::IllegalArgumentException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
// XRangeXMLConversion
virtual OUString SAL_CALL convertRangeToXML( const OUString& aRangeRepresentation )
throw (::com::sun::star::lang::IllegalArgumentException,
......
......@@ -1432,6 +1432,14 @@ uno::Reference< sheet::XRangeSelection > SAL_CALL SwChartDataProvider::getRangeS
return uno::Reference< sheet::XRangeSelection >();
}
uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
SwChartDataProvider::createDataSequenceByValueArray(
const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/ )
throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
{
return uno::Reference<css::chart2::data::XDataSequence>();
}
void SAL_CALL SwChartDataProvider::dispose( )
throw (uno::RuntimeException, std::exception)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment