summaryrefslogtreecommitdiff
path: root/chart2
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-07-02 09:53:54 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-07-02 22:50:37 -0400
commit7554f619f03e1fcadd333f2792913f412c0a7031 (patch)
tree05e27cff79361271474bfa5b93d024a6d0f95755 /chart2
parent732076e974291a07f29cddfbb4e0763ddce5fc8c (diff)
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. (cherry picked from commit 6c4e21a234f12e1310ba06f9859e08b424acf8bf) Conflicts: chart2/source/inc/InternalDataProvider.hxx chart2/source/tools/InternalDataProvider.cxx Conflicts: chart2/source/inc/InternalDataProvider.hxx dbaccess/source/core/inc/DatabaseDataProvider.hxx dbaccess/source/core/misc/DatabaseDataProvider.cxx sc/source/filter/inc/excelchartconverter.hxx Change-Id: If4bc1f650bb024dcd1b1b36537f457fb38404a78
Diffstat (limited to 'chart2')
-rw-r--r--chart2/source/inc/InternalDataProvider.hxx8
-rw-r--r--chart2/source/tools/InternalDataProvider.cxx200
2 files changed, 150 insertions, 58 deletions
diff --git a/chart2/source/inc/InternalDataProvider.hxx b/chart2/source/inc/InternalDataProvider.hxx
index 9c03b23b8afb..6ddcded338bc 100644
--- a/chart2/source/inc/InternalDataProvider.hxx
+++ b/chart2/source/inc/InternalDataProvider.hxx
@@ -135,6 +135,11 @@ public:
const OUString& aRangeRepresentation )
throw (::com::sun::star::lang::IllegalArgumentException,
::com::sun::star::uno::RuntimeException);
+
+ virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
+ createDataSequenceByValueArray( const OUString& aRole, const OUString& aRangeRepresentation )
+ throw (css::lang::IllegalArgumentException, css::uno::RuntimeException);
+
virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XRangeSelection > SAL_CALL getRangeSelection()
throw (::com::sun::star::uno::RuntimeException);
@@ -233,6 +238,9 @@ private:
void lcl_deleteMapReferences( const OUString & rRangeRepresentation );
+ css::uno::Reference<css::chart2::data::XDataSequence>
+ createDataSequenceFromArray( const OUString& rArrayStr, const OUString& rRole );
+
void lcl_adaptMapReferences(
const OUString & rOldRangeRepresentation,
const OUString & rNewRangeRepresentation );
diff --git a/chart2/source/tools/InternalDataProvider.cxx b/chart2/source/tools/InternalDataProvider.cxx
index fe70d7c59066..842dd632506a 100644
--- a/chart2/source/tools/InternalDataProvider.cxx
+++ b/chart2/source/tools/InternalDataProvider.cxx
@@ -492,79 +492,155 @@ void InternalDataProvider::lcl_decreaseMapReferences(
Reference< chart2::data::XDataSequence > InternalDataProvider::lcl_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
+ Reference<chart2::data::XDataSequence> xSeq = createDataSequenceFromArray(rRangeRepresentation, OUString());
+ if (xSeq.is())
+ return xSeq;
+
+ xSeq.set(new UncachedDataSequence(this, rRangeRepresentation));
+ lcl_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 == '"')
{
- // 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 )
+ bInQuote = !bInQuote;
+ if (bInQuote)
{
- aNewData.push_back( aToken.toDouble() );
+ // Opening quote.
+ bAllNumeric = false;
+ ++p;
+ if (p == pEnd)
+ break;
+ pElem = p;
}
else
{
- aNewLabels.push_back( uno::makeAny(aToken.replace('"', ' ').trim()) );
- if( !nCategories &&
- ( !m_aInternalData.getComplexColumnLabel(n).size() ||
- !m_aInternalData.getComplexColumnLabel(n).front().hasValue() ) )
- {
- m_aInternalData.setComplexColumnLabel( n, aNewLabels );
- bLabelSet = true;
- }
- else
- {
- m_aInternalData.setComplexRowLabel(nCategories, aNewLabels);
- if(nCategories==1 && bLabelSet)
- {
- ::std::vector< uno::Any > aLabels;
- m_aInternalData.setComplexRowLabel( 0, m_aInternalData.getComplexColumnLabel( n ) );
- m_aInternalData.setComplexColumnLabel( n, aLabels );
- }
- }
- aNewLabels.pop_back();
- nCategories++;
- bValues = false;
+ // Closing quote.
+ if (pElem)
+ aElem = OUString(pElem, p-pElem);
+ aRawElems.push_back(aElem);
+ pElem = NULL;
+ aElem = OUString();
+
+ ++p; // Skip '"'.
+ if (p == pEnd)
+ break;
}
- } while( nIndex >= 0 );
-
- if( bValues )
+ }
+ else if (bInQuote)
+ {
+ // Do nothing.
+ }
+ else if (*p == ';')
{
- m_aInternalData.insertColumn( n );
- m_aInternalData.setColumnValues( n, aNewData );
- aRangeRepresentation = OUString::number( n );
+ // element separator.
+ if (pElem)
+ aElem = OUString(pElem, p-pElem);
+ aRawElems.push_back(aElem);
+ pElem = NULL;
+ aElem = OUString();
}
- else if( nCategories > 1 )
+ 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));
+ lcl_addDataSequenceToMap(aRangeRep, xSeq);
+ }
+ else if (rRole == "values-x")
+ {
+ std::vector<double> aValues;
+ aValues.reserve(aRawElems.size());
+ if (bAllNumeric)
{
- aRangeRepresentation = lcl_aCategoriesRangeName;
+ 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));
+ lcl_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));
+ lcl_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));
+ lcl_addDataSequenceToMap(aRangeRep, xSeq);
}
}
- Reference< chart2::data::XDataSequence > xSeq(
- new UncachedDataSequence( this, aRangeRepresentation ));
- lcl_addDataSequenceToMap( aRangeRepresentation, xSeq );
return xSeq;
}
@@ -765,6 +841,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)
+{
+ return createDataSequenceFromArray(aRangeRepresentation, aRole);
+}
+
Reference< sheet::XRangeSelection > SAL_CALL InternalDataProvider::getRangeSelection()
throw (uno::RuntimeException)
{