summaryrefslogtreecommitdiff
path: root/xmloff/source/chart/SchXMLTableContext.cxx
diff options
context:
space:
mode:
authorVladimir Glazounov <vg@openoffice.org>2007-05-22 15:07:45 +0000
committerVladimir Glazounov <vg@openoffice.org>2007-05-22 15:07:45 +0000
commit975608a78c3e70adca36e5fd956c3846b0951323 (patch)
tree8755b47a464bccc360808a010010d0c98b2fd56a /xmloff/source/chart/SchXMLTableContext.cxx
parentce5e96e5e289e54cd12588a707df1460dd862bf4 (diff)
INTEGRATION: CWS chart2mst3 (1.13.26); FILE MERGED
2006/12/12 16:55:12 bm 1.13.26.9: own data with no categories element: apply categories in applyTable() 2006/12/07 16:32:07 bm 1.13.26.8: #i64497# some more fixes for clipboard 2006/12/06 18:57:10 bm 1.13.26.7: build breaks on Linux 2006/12/06 18:50:46 bm 1.13.26.6: #i64497# allow import and export to deal with flexible source ranges also with own data. This is needed for the clipboard between Calc and Impress 2006/10/19 09:59:48 bm 1.13.26.5: RESYNC: (1.14-1.16); FILE MERGED 2006/08/09 15:47:09 bm 1.13.26.4: robustness in applyTableSimple 2005/10/09 08:07:15 bm 1.13.26.3: RESYNC: (1.13-1.14); FILE MERGED 2005/08/15 13:09:12 bm 1.13.26.2: applyTableSimple: gets the data directly. This eases filling the internal data provider 2004/09/08 15:33:52 bm 1.13.26.1: call attachData() after changing data of ChartDocument
Diffstat (limited to 'xmloff/source/chart/SchXMLTableContext.cxx')
-rw-r--r--xmloff/source/chart/SchXMLTableContext.cxx738
1 files changed, 434 insertions, 304 deletions
diff --git a/xmloff/source/chart/SchXMLTableContext.cxx b/xmloff/source/chart/SchXMLTableContext.cxx
index 962d9ef9f8..19d599c847 100644
--- a/xmloff/source/chart/SchXMLTableContext.cxx
+++ b/xmloff/source/chart/SchXMLTableContext.cxx
@@ -4,9 +4,9 @@
*
* $RCSfile: SchXMLTableContext.cxx,v $
*
- * $Revision: 1.16 $
+ * $Revision: 1.17 $
*
- * last change: $Author: obo $ $Date: 2006-09-17 10:16:07 $
+ * last change: $Author: vg $ $Date: 2007-05-22 16:07:45 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
@@ -39,6 +39,7 @@
#include "SchXMLTableContext.hxx"
#include "SchXMLParagraphContext.hxx"
#include "SchXMLImport.hxx"
+#include "SchXMLTools.hxx"
#include "transporttypes.hxx"
#ifndef _TOOLS_DEBUG_HXX
@@ -64,21 +65,301 @@
#ifndef _COM_SUN_STAR_FRAME_XMODEL_HPP_
#include <com/sun/star/frame/XModel.hpp>
#endif
-#ifndef _COM_SUN_STAR_CHART_XCHARTDOCUMENT_HPP_
-#include <com/sun/star/chart/XChartDocument.hpp>
+#ifndef _COM_SUN_STAR_CHART2_XCHARTDOCUMENT_HPP_
+#include <com/sun/star/chart2/XChartDocument.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART_XCHARTDATAARRAY_HPP_
#include <com/sun/star/chart/XChartDataArray.hpp>
#endif
-#ifndef _COM_SUN_STAR_CHART_CHARTDATAROWSOURCE_HPP_
-#include <com/sun/star/chart/ChartDataRowSource.hpp>
-#endif
#ifndef _COM_SUN_STAR_CHART_CHARTSERIESADDRESS_HPP_
#include <com/sun/star/chart/ChartSeriesAddress.hpp>
#endif
+#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
+#include <com/sun/star/beans/XPropertySet.hpp>
+#endif
+#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSETINFO_HPP_
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#endif
+#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#endif
+
+#include <com/sun/star/chart2/XDiagram.hpp>
+#include <com/sun/star/chart2/XAxis.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/AxisType.hpp>
+
+#include <algorithm>
using namespace com::sun::star;
using namespace ::xmloff::token;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::rtl::OUString;
+
+namespace
+{
+Sequence< OUString > lcl_getCategoriesFromTable( const SchXMLTable & rTable, bool bHasLabels )
+{
+ sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size()));
+ OSL_ENSURE( static_cast< size_t >( nNumRows ) == rTable.aData.size(), "Table too big" );
+
+ sal_Int32 nOffset(bHasLabels ? 1 : 0);
+ Sequence< OUString > aResult( nNumRows - nOffset );
+ sal_Int32 i=nOffset;
+ for( ; i<nNumRows; ++i )
+ {
+ if( !rTable.aData[i].empty() && (rTable.aData[i].front().eType == SCH_CELL_TYPE_STRING ))
+ aResult[i - nOffset] = rTable.aData[i].front().aString;
+ }
+ return aResult;
+}
+
+std::vector< Reference< chart2::XAxis > > lcl_getAxesHoldingCategoriesFromDiagram(
+ const Reference< chart2::XDiagram > & xDiagram )
+{
+ std::vector< Reference< chart2::XAxis > > aRet;
+
+ Reference< chart2::XAxis > xResult;
+ // return first x-axis as fall-back
+ Reference< chart2::XAxis > xFallBack;
+ try
+ {
+ Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
+ xDiagram, uno::UNO_QUERY_THROW );
+ Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
+ xCooSysCnt->getCoordinateSystems());
+ for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
+ {
+ Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[i] );
+ OSL_ASSERT( xCooSys.is());
+ for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
+ {
+ const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
+ for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
+ {
+ Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
+ OSL_ASSERT( xAxis.is());
+ if( xAxis.is())
+ {
+ chart2::ScaleData aScaleData = xAxis->getScaleData();
+ if( aScaleData.Categories.is() || (aScaleData.AxisType == chart2::AxisType::CATEGORY) )
+ {
+ aRet.push_back(xAxis);
+ }
+ if( (nN == 0) && !xFallBack.is())
+ xFallBack.set( xAxis );
+ }
+ }
+ }
+ }
+ }
+ catch( uno::Exception & )
+ {
+ }
+
+ if( aRet.empty())
+ aRet.push_back(xFallBack);
+
+ return aRet;
+}
+
+struct lcl_setCategories : public ::std::unary_function< Reference< chart2::XAxis >, void >
+{
+ lcl_setCategories( const Reference< chart2::data::XDataProvider > & xProvider ) :
+ m_xProvider( xProvider )
+ {}
+ void operator() ( const Reference< chart2::XAxis > & xAxis )
+ {
+ if( xAxis.is() && m_xProvider.is())
+ {
+ chart2::ScaleData aSData( xAxis->getScaleData());
+ if( aSData.Categories.is())
+ {
+ aSData.Categories->setValues(
+ m_xProvider->createDataSequenceByRangeRepresentation(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
+ xAxis->setScaleData( aSData );
+ }
+ }
+ }
+
+private:
+ Reference< chart2::data::XDataProvider > m_xProvider;
+};
+
+void lcl_ApplyColumnLabels(
+ const ::std::vector< SchXMLCell > & rFirstRow,
+ Sequence< OUString > & rOutColumnLabels,
+ sal_Int32 nOffset )
+{
+ const sal_Int32 nColumnLabelsSize = rOutColumnLabels.getLength();
+ const sal_Int32 nMax = ::std::min< sal_Int32 >( nColumnLabelsSize,
+ static_cast< sal_Int32 >( rFirstRow.size()) - nOffset );
+ OSL_ASSERT( nMax == nColumnLabelsSize );
+ for( sal_Int32 i=0; i<nMax; ++i )
+ if( rFirstRow[i+nOffset].eType == SCH_CELL_TYPE_STRING )
+ rOutColumnLabels[i] = rFirstRow[i+nOffset].aString;
+}
+
+struct lcl_ApplyCellToData : public ::std::unary_function< SchXMLCell, void >
+{
+ lcl_ApplyCellToData( Sequence< double > & rOutData,
+ Sequence< OUString > & rOutRowLabels ) :
+ m_rData( rOutData ),
+ m_rRowLabels( rOutRowLabels ),
+ m_nIndex( 0 ),
+ m_nSize( rOutData.getLength())
+ {
+ ::rtl::math::setNan( &m_fNaN );
+ }
+
+ void operator() ( const SchXMLCell & rCell )
+ {
+ if( m_nIndex < m_nSize )
+ {
+ if( rCell.eType == SCH_CELL_TYPE_FLOAT )
+ m_rData[m_nIndex] = rCell.fValue;
+ else
+ m_rData[m_nIndex] = m_fNaN;
+ }
+ ++m_nIndex;
+ }
+
+private:
+ Sequence< double > & m_rData;
+ Sequence< OUString > & m_rRowLabels;
+ sal_Int32 m_nIndex;
+ sal_Int32 m_nSize;
+ double m_fNaN;
+};
+
+struct lcl_ApplyRowsToData : public ::std::unary_function< ::std::vector< SchXMLCell >, void >
+{
+ lcl_ApplyRowsToData( Sequence< Sequence< double > > & rOutData,
+ Sequence< OUString > & rOutRowLabels,
+ sal_Int32 nOffset,
+ bool bHasHeader ) :
+ m_rData( rOutData ),
+ m_rRowLabels( rOutRowLabels ),
+ m_nIndex( 0 ),
+ m_nOuterSize( rOutData.getLength()),
+ m_nOffset( nOffset ),
+ m_bHasHeader( bHasHeader )
+ {}
+ void operator() ( const ::std::vector< SchXMLCell > & rRow )
+ {
+ if( ! rRow.empty())
+ {
+ // label
+ if( m_bHasHeader && m_nIndex < m_rRowLabels.getLength() && rRow.front().eType == SCH_CELL_TYPE_STRING )
+ m_rRowLabels[m_nIndex] = rRow.front().aString;
+ // values
+ if( m_nIndex < m_nOuterSize )
+ ::std::for_each( rRow.begin() + m_nOffset, rRow.end(), lcl_ApplyCellToData( m_rData[m_nIndex], m_rRowLabels ));
+ }
+ ++m_nIndex;
+ }
+
+private:
+ Sequence< Sequence< double > > & m_rData;
+ Sequence< OUString > & m_rRowLabels;
+ sal_Int32 m_nIndex;
+ sal_Int32 m_nOuterSize;
+ sal_Int32 m_nOffset;
+ bool m_bHasHeader;
+};
+
+Sequence< Sequence< double > > lcl_getSwappedArray( const Sequence< Sequence< double > > & rData )
+{
+ sal_Int32 nOldOuterSize = rData.getLength();
+ sal_Int32 nOldInnerSize = (nOldOuterSize == 0 ? 0 : rData[0].getLength());
+ Sequence< Sequence< double > > aResult( nOldInnerSize );
+
+ for( sal_Int32 i=0; i<nOldInnerSize; ++i )
+ aResult[i].realloc( nOldOuterSize );
+
+ for( sal_Int32 nOuter=0; nOuter<nOldOuterSize; ++nOuter )
+ for( sal_Int32 nInner=0; nInner<nOldInnerSize; ++nInner )
+ aResult[nInner][nOuter] = rData[nOuter][nInner];
+
+ return aResult;
+}
+
+void lcl_applyXMLTableToInternalDataprovider(
+ const SchXMLTable & rTable,
+ const Reference< chart::XChartDataArray > & xDataArray )
+{
+ sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size()));
+ sal_Int32 nRowOffset = 0;
+ if( rTable.bHasHeaderRow )
+ {
+ --nNumRows;
+ nRowOffset = 1;
+ }
+ sal_Int32 nNumColumns( rTable.nMaxColumnIndex + 1 );
+ sal_Int32 nColOffset = 0;
+ if( rTable.bHasHeaderColumn )
+ {
+ --nNumColumns;
+ nColOffset = 1;
+ }
+
+ Sequence< Sequence< double > > aData( nNumRows );
+ Sequence< OUString > aRowLabels( nNumRows );
+ Sequence< OUString > aColumnLabels( nNumColumns );
+ for( sal_Int32 i=0; i<nNumRows; ++i )
+ aData[i].realloc( nNumColumns );
+
+ if( rTable.aData.begin() != rTable.aData.end())
+ {
+ if( rTable.bHasHeaderRow )
+ lcl_ApplyColumnLabels( rTable.aData.front(), aColumnLabels, nColOffset );
+ ::for_each( rTable.aData.begin() + nRowOffset, rTable.aData.end(),
+ lcl_ApplyRowsToData( aData, aRowLabels, nColOffset, rTable.bHasHeaderColumn ));
+ }
+
+ xDataArray->setData( aData );
+
+ if( rTable.bHasHeaderColumn )
+ xDataArray->setRowDescriptions( aRowLabels );
+ if( rTable.bHasHeaderRow )
+ xDataArray->setColumnDescriptions( aColumnLabels );
+}
+
+void lcl_copyProperties(
+ const Reference< beans::XPropertySet > & xSource,
+ const Reference< beans::XPropertySet > & xDestination )
+{
+ if( ! (xSource.is() && xDestination.is()))
+ return;
+
+ try
+ {
+ Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_QUERY_THROW );
+ Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_QUERY_THROW );
+ Sequence< beans::Property > aProperties( xSrcInfo->getProperties());
+ const sal_Int32 nLength = aProperties.getLength();
+ for( sal_Int32 i = 0; i < nLength; ++i )
+ {
+ OUString aName( aProperties[i].Name);
+ if( xDestInfo->hasPropertyByName( aName ))
+ {
+ beans::Property aProp( xDestInfo->getPropertyByName( aName ));
+ if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 )
+ xDestination->setPropertyValue(
+ aName, xSource->getPropertyValue( aName ));
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ OSL_ENSURE( false, "Copying property sets failed!" );
+ }
+}
+
+} // anonymous namespace
+
// ----------------------------------------
// class SchXMLTableContext
@@ -113,6 +394,8 @@ SvXMLImportContext *SchXMLTableContext::CreateChildContext(
switch( rTokenMap.Get( nPrefix, rLocalName ))
{
case XML_TOK_TABLE_HEADER_COLS:
+ mrTable.bHasHeaderColumn = true;
+ // fall through intended
case XML_TOK_TABLE_COLUMNS:
pContext = new SchXMLTableColumnsContext( mrImportHelper, GetImport(), rLocalName, mrTable );
break;
@@ -122,6 +405,8 @@ SvXMLImportContext *SchXMLTableContext::CreateChildContext(
break;
case XML_TOK_TABLE_HEADER_ROWS:
+ mrTable.bHasHeaderRow = true;
+ // fall through intended
case XML_TOK_TABLE_ROWS:
pContext = new SchXMLTableRowsContext( mrImportHelper, GetImport(), rLocalName, mrTable );
break;
@@ -428,7 +713,7 @@ void SchXMLTableCellContext::EndElement()
// (this is just a workaround for clipboard handling in EA2)
void SchXMLTableHelper::applyTableSimple(
const SchXMLTable& rTable,
- uno::Reference< chart::XChartDocument > xChartDoc )
+ uno::Reference< chart::XChartDataArray > xData )
{
// interpret table like this:
//
@@ -442,66 +727,83 @@ void SchXMLTableHelper::applyTableSimple(
// 2 x 0 0
// 3 x 0 0
// ...
- if( xChartDoc.is())
+
+ // Standard Role-interpretation:
+
+ // Column 1 contains the Categories
+
+ // Chart Type/Class | Col 2 Col 3 Col 4 Col 5 Col 6 | Series | Domain
+ // -----------------+-----------------------------------+--------+-------
+ // Category Charts | Y 1 Y 2 Y 3 Y 4 ... | Y | -
+ // XY Chart | X all Y 1 Y 2 Y 3 ... | Y | X
+ // Stock Chart 1 | Min Max Close - - | Close | -
+ // Stock Chart 2 | Open Min Max Close - | Close | -
+ // Stock Chart 3 | Volume Min Max Close - | Close | -
+ // Stock Chart 4 | Volume Open Min Max Close | Close | -
+
+ if( xData.is())
{
- uno::Reference< chart::XChartDataArray > xData( xChartDoc->getData(), uno::UNO_QUERY );
- if( xData.is())
+ // get NaN
+ double fSolarNaN;
+ ::rtl::math::setNan( &fSolarNaN );
+ double fNaN = fSolarNaN;
+ sal_Bool bConvertNaN = sal_False;
+
+ uno::Reference< chart::XChartData > xChartData( xData, uno::UNO_QUERY );
+ if( xChartData.is())
{
- // get NaN
- double fSolarNaN;
- ::rtl::math::setNan( &fSolarNaN );
- double fNaN = fSolarNaN;
- sal_Bool bConvertNaN = sal_False;
-
- uno::Reference< chart::XChartData > xChartData( xData, uno::UNO_QUERY );
- if( xChartData.is())
- {
- fNaN = xChartData->getNotANumber();
- bConvertNaN = ( ! ::rtl::math::isNan( fNaN ));
- }
+ fNaN = xChartData->getNotANumber();
+ bConvertNaN = ( ! ::rtl::math::isNan( fNaN ));
+ }
- sal_Int32 nRowCount = rTable.aData.size();
- sal_Int32 nColumnCount = 0;
- sal_Int32 nCol = 0, nRow = 0;
- if( nRowCount )
- nColumnCount = rTable.aData[ 0 ].size();
-
- // #i27909# avoid illegal index access for empty tables
- if( nColumnCount == 0 || nRowCount == 0 )
- return;
-
- uno::Sequence< ::rtl::OUString > aCategories( nRowCount - 1 );
- uno::Sequence< ::rtl::OUString > aLabels( nColumnCount - 1 );
- uno::Sequence< uno::Sequence< double > > aData( nRowCount - 1 );
- for( nRow = 0; nRow < nRowCount - 1; nRow++ )
- aData[ nRow ].realloc( nColumnCount - 1 );
-
- // set labels
- ::std::vector< ::std::vector< SchXMLCell > >::const_iterator iRow = rTable.aData.begin();
- for( nCol = 1; nCol < nColumnCount; nCol++ )
- {
- aLabels[ nCol - 1 ] = (*iRow)[ nCol ].aString;
- }
- xData->setColumnDescriptions( aLabels );
+ sal_Int32 nRowCount = rTable.aData.size();
+ sal_Int32 nColumnCount = 0;
+ sal_Int32 nCol = 0, nRow = 0;
+ if( nRowCount )
+ nColumnCount = rTable.aData[ 0 ].size();
+
+ // #i27909# avoid illegal index access for empty tables
+ if( nColumnCount == 0 || nRowCount == 0 )
+ return;
+
+ uno::Sequence< ::rtl::OUString > aCategories( nRowCount - 1 );
+ uno::Sequence< ::rtl::OUString > aLabels( nColumnCount - 1 );
+ uno::Sequence< uno::Sequence< double > > aData( nRowCount - 1 );
+ for( nRow = 0; nRow < nRowCount - 1; nRow++ )
+ aData[ nRow ].realloc( nColumnCount - 1 );
+
+ // set labels
+ ::std::vector< ::std::vector< SchXMLCell > >::const_iterator iRow = rTable.aData.begin();
+ for( nCol = 1; nCol < nColumnCount; nCol++ )
+ {
+ aLabels[ nCol - 1 ] = (*iRow)[ nCol ].aString;
+ }
+ xData->setColumnDescriptions( aLabels );
- double fVal;
- const sal_Bool bConstConvertNan = bConvertNaN;
- for( ++iRow, nRow = 0; iRow != rTable.aData.end(); iRow++, nRow++ )
+ double fVal;
+ const sal_Bool bConstConvertNan = bConvertNaN;
+ for( ++iRow, nRow = 0; iRow != rTable.aData.end(); iRow++, nRow++ )
+ {
+ aCategories[ nRow ] = (*iRow)[ 0 ].aString;
+ sal_Int32 nTableColCount( static_cast< sal_Int32 >((*iRow).size()));
+ for( nCol = 1; nCol < nTableColCount; nCol++ )
{
- aCategories[ nRow ] = (*iRow)[ 0 ].aString;
- for( nCol = 1; nCol < nColumnCount; nCol++ )
- {
- fVal = (*iRow)[ nCol ].fValue;
- if( bConstConvertNan &&
- ::rtl::math::isNan( fVal ))
- aData[ nRow ][ nCol - 1 ] = fNaN;
- else
- aData[ nRow ][ nCol - 1 ] = fVal;
- }
+ fVal = (*iRow)[ nCol ].fValue;
+ if( bConstConvertNan &&
+ ::rtl::math::isNan( fVal ))
+ aData[ nRow ][ nCol - 1 ] = fNaN;
+ else
+ aData[ nRow ][ nCol - 1 ] = fVal;
}
- xData->setRowDescriptions( aCategories );
- xData->setData( aData );
+ // set remaining cells to NaN
+ for( ; nCol < nColumnCount; ++nCol )
+ if( bConstConvertNan )
+ aData[ nRow ][nCol - 1 ] = fNaN;
+ else
+ ::rtl::math::setNan( &(aData[ nRow ][nCol - 1 ]));
}
+ xData->setRowDescriptions( aCategories );
+ xData->setData( aData );
}
}
@@ -509,264 +811,92 @@ void SchXMLTableHelper::applyTableSimple(
void SchXMLTableHelper::applyTable(
const SchXMLTable& rTable,
- uno::Sequence< chart::ChartSeriesAddress >& rSeriesAddresses,
- rtl::OUString& rCategoriesAddress,
- uno::Reference< chart::XChartDocument > xChartDoc )
+ const tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
+ uno::Reference< chart2::XChartDocument > xChartDoc )
{
- // general note: series are always interpreted as columns in import
+ if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider()))
+ return;
+ Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider());
+ Reference< chart::XChartDataArray > xDataArray( xDataProv, uno::UNO_QUERY );
+ if( ! xDataArray.is())
+ return;
+ OSL_ASSERT( xDataProv.is());
+ Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
+ if( ! xDiagram.is())
+ return;
- // first check if data can be attached to an appropriate object
- if( rTable.nRowIndex > -1 &&
- xChartDoc.is())
+ // prerequisite for this method: all objects (data series, domains, etc.)
+ // need their own range string.
+
+ // If the range-strings are valid (starting with "local-table") they should
+ // be interpreted like given, otherwise (when the ranges refer to Calc- or
+ // Writer-ranges, but the container is not available like when pasting a
+ // chart from Calc to Impress) the range is ignored, and every object gets
+ // one table column in the order of appearance, which is: 1. categories,
+ // 2. data series: 2.a) domains, 2.b) values (main-role, usually y-values)
+
+ // apply all data read in the table to the chart data-array of the internal
+ // data provider
+ lcl_applyXMLTableToInternalDataprovider( rTable, xDataArray );
+
+ bool bCategoriesApplied = false;
+ // apply the data to the objects that have been parsed and marked for
+ // getting the new data in ther rLSequencesPerIndex map.
+ for( tSchXMLLSequencesPerIndex::const_iterator aIt( rLSequencesPerIndex.begin());
+ aIt != rLSequencesPerIndex.end(); ++aIt )
{
- uno::Reference< chart::XChartDataArray > xData( xChartDoc->getData(), uno::UNO_QUERY );
- if( xData.is())
+ if( aIt->second.is())
{
- sal_Int32 nNumSeriesAddresses = rSeriesAddresses.getLength();
- sal_Int32 nDomainOffset = 0;
- sal_Int32 nNumAddrSize = nNumSeriesAddresses;
-
- uno::Reference< chart::XChartData > xChartData( xData, uno::UNO_QUERY );
- if( xChartData.is())
+ if( aIt->first.second == SCH_XML_PART_VALUES )
{
- sal_Int32 nColumns = 0;
- sal_Int32 nRows = 0;
- sal_Int32 i, j;
-
- // set data
- if( nNumSeriesAddresses )
+ if( aIt->first.first == SCH_XML_CATEGORIES_INDEX )
{
- // get NaN
- double fSolarNaN;
- ::rtl::math::setNan( &fSolarNaN );
- double fNaN = fSolarNaN;
- fNaN = xChartData->getNotANumber();
-
- // convert data from std::vector to uno::Sequence
- // ----------------------------------------------
-
- // determine size of data
- std::vector< SchNumericCellRangeAddress > aNumericAddresses( nNumSeriesAddresses );
-
- for( i = 0; i < nNumSeriesAddresses; i++ )
- {
- if( rSeriesAddresses[ i ].DomainRangeAddresses.getLength())
- {
- GetCellRangeAddress( rSeriesAddresses[ i ].DomainRangeAddresses[ 0 ],
- aNumericAddresses[ i + nDomainOffset ] );
- AdjustMax( aNumericAddresses[ i + nDomainOffset ], nRows, nColumns );
- nDomainOffset++;
- aNumericAddresses.reserve( nNumSeriesAddresses + nDomainOffset );
- }
-
- GetCellRangeAddress( rSeriesAddresses[ i ].DataRangeAddress,
- aNumericAddresses[ i + nDomainOffset ] );
- AdjustMax( aNumericAddresses[ i + nDomainOffset ], nRows, nColumns );
- }
- nNumAddrSize += nDomainOffset;
-
- // allocate memory for sequence
- uno::Sequence< uno::Sequence< double > > aSequence( nRows );
- for( i = 0; i < nRows; i++ )
- {
- aSequence[ i ].realloc( nColumns );
-
- // initialize values with NaN
- for( j = 0; j < nColumns; j++ )
- aSequence[ i ][ j ] = fNaN;
- }
-
- // copy data
- for( i = 0; i < nNumAddrSize; i++ )
- PutTableContentIntoSequence( rTable, aNumericAddresses[ i ], i, aSequence );
-
- // set data to XChartDataArray
- xData->setData( aSequence );
- }
-
- // set labels
- uno::Sequence< rtl::OUString > aColumnLabels( nNumAddrSize );
-
- sal_Int32 nRow, nCol;
- for( i = 0; i < nNumSeriesAddresses; i++ )
- {
- if( rSeriesAddresses[ i ].LabelAddress.getLength())
- {
- GetCellAddress( rSeriesAddresses[ i ].LabelAddress, nCol, nRow );
- aColumnLabels[ i + nDomainOffset ] = rTable.aData[ nRow ][ nCol ].aString;
- }
+ Reference< beans::XPropertySet > xOldSequenceProp( aIt->second->getValues(), uno::UNO_QUERY );
+ Reference< chart2::data::XDataSequence > xNewSequence(
+ xDataProv->createDataSequenceByRangeRepresentation(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
+ lcl_copyProperties(
+ xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
+ aIt->second->setValues( xNewSequence );
+ bCategoriesApplied = true;
}
- xData->setColumnDescriptions( aColumnLabels );
-
- if( rCategoriesAddress.getLength())
+ else
{
- SchNumericCellRangeAddress aAddress;
- if( GetCellRangeAddress( rCategoriesAddress, aAddress ))
- {
- uno::Sequence< rtl::OUString > aLabels;
-
- if( aAddress.nCol1 == aAddress.nCol2 )
- {
- sal_Int32 nWidth = aAddress.nRow2 - aAddress.nRow1 + 1;
- aLabels.realloc( nWidth );
-
- for( i = 0; i < nWidth; i++ )
- {
- DBG_ASSERT( rTable.aData[ aAddress.nRow1 + i ][ aAddress.nCol1 ].eType == SCH_CELL_TYPE_STRING, "expecting string" );
- aLabels[ i ] = rTable.aData[ aAddress.nRow1 + i ][ aAddress.nCol1 ].aString;
- }
- }
- else
- {
- DBG_ASSERT( aAddress.nRow1 == aAddress.nRow2, "range must be in one row or one column" );
-
- sal_Int32 nWidth = aAddress.nCol2 - aAddress.nCol1 + 1;
- aLabels.realloc( nWidth );
-
- for( i = 0; i < nWidth; i++ )
- {
- DBG_ASSERT( rTable.aData[ aAddress.nRow1 ][ aAddress.nCol1 + i ].eType == SCH_CELL_TYPE_STRING, "expecting string" );
- aLabels[ i ] = rTable.aData[ aAddress.nRow1 ][ aAddress.nCol1 + i ].aString;
- }
- }
-
- xData->setRowDescriptions( aLabels );
- }
+ Reference< beans::XPropertySet > xOldSequenceProp( aIt->second->getValues(), uno::UNO_QUERY );
+ OUString aRep( OUString::valueOf( aIt->first.first ));
+ Reference< chart2::data::XDataSequence > xNewSequence(
+ xDataProv->createDataSequenceByRangeRepresentation( aRep ));
+ lcl_copyProperties(
+ xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
+ aIt->second->setValues( xNewSequence );
}
}
- }
- }
-}
-
-void SchXMLTableHelper::AdjustMax( const SchNumericCellRangeAddress& rAddr,
- sal_Int32& nRows, sal_Int32& nColumns )
-{
- // rows and columns are both mapped to columns ( == series )
- if( rAddr.nCol1 == rAddr.nCol2 )
- {
- if( rAddr.nRow1 > nRows )
- nRows = rAddr.nRow1;
- if( rAddr.nRow2 > nRows )
- nRows = rAddr.nRow2;
- if( rAddr.nCol1 > nColumns )
- nColumns = rAddr.nCol1;
- if( rAddr.nCol2 > nColumns )
- nColumns = rAddr.nCol2;
- }
- else
- {
- DBG_ASSERT( rAddr.nRow1 == rAddr.nRow2, "row indexes should be equal" );
- if( rAddr.nRow1 > nColumns )
- nColumns = rAddr.nRow1;
- if( rAddr.nRow2 > nColumns )
- nColumns = rAddr.nRow2;
- if( rAddr.nCol1 > nRows )
- nRows = rAddr.nCol1;
- if( rAddr.nCol2 > nRows )
- nRows = rAddr.nCol2;
- }
-}
-
-void SchXMLTableHelper::GetCellAddress( const rtl::OUString& rStr, sal_Int32& rCol, sal_Int32& rRow )
-{
- sal_Int32 nPos = rStr.indexOf( sal_Unicode( '.' ));
- if( nPos != -1 )
- {
- // currently just one letter is accepted
- sal_Unicode aLetter = rStr.getStr()[ nPos + 1 ];
- if( 'a' <= aLetter && aLetter <= 'z' )
- rCol = aLetter - 'a';
- else
- rCol = aLetter - 'A';
-
- rRow = (rStr.copy( nPos + 2 )).toInt32() - 1;
- }
-}
-
-sal_Bool SchXMLTableHelper::GetCellRangeAddress(
- const rtl::OUString& rStr, SchNumericCellRangeAddress& rResult )
-{
- sal_Int32 nBreakAt = rStr.indexOf( sal_Unicode( ':' ));
- if( nBreakAt != -1 )
- {
- GetCellAddress( rStr.copy( 0, nBreakAt ), rResult.nCol1, rResult.nRow1 );
- GetCellAddress( rStr.copy( nBreakAt + 1 ), rResult.nCol2, rResult.nRow2 );
- return sal_True;
- }
-
- return sal_False;
-}
-
-
-// returns true if datarange was inside one column
-void SchXMLTableHelper::PutTableContentIntoSequence(
- const SchXMLTable& rTable,
- SchNumericCellRangeAddress& rAddress,
- sal_Int32 nSeriesIndex,
- uno::Sequence< uno::Sequence< double > >& aSequence )
-{
- if( rAddress.nCol2 > rTable.nMaxColumnIndex + 1 ||
- rAddress.nRow2 > rTable.nRowIndex + 1 )
- {
- DBG_ERROR( "Invalid references" );
- //ToDo: strip the range
- return;
- }
-
- // currently only ranges that span one row or one column are supported
-
- sal_Int32 nSeqPos = 0;
- uno::Sequence< double >* pSeqArray = aSequence.getArray();
- double fValue;
-
- // same column
- if( rAddress.nCol1 == rAddress.nCol2 )
- {
- if( rAddress.nRow1 <= rAddress.nRow2 )
- {
- for( sal_Int32 nRow = rAddress.nRow1; nRow <= rAddress.nRow2; nRow++, nSeqPos++ )
- {
- DBG_ASSERT( rTable.aData[ nRow ][ rAddress.nCol1 ].eType != SCH_CELL_TYPE_UNKNOWN, "trying to refer to unknown cell" );
- fValue = rTable.aData[ nRow ][ rAddress.nCol1 ].fValue;
- if( ! ::rtl::math::isNan( fValue ))
- pSeqArray[ nSeqPos ][ nSeriesIndex ] = fValue;
- }
- }
- else // reverse
- {
- for( sal_Int32 nRow = rAddress.nRow1; nRow >= rAddress.nRow2; nRow--, nSeqPos++ )
+ else
{
- DBG_ASSERT( rTable.aData[ nRow ][ rAddress.nCol1 ].eType != SCH_CELL_TYPE_UNKNOWN, "trying to refer to unknown cell" );
- fValue = rTable.aData[ nRow ][ rAddress.nCol1 ].fValue;
- if( ! ::rtl::math::isNan( fValue ))
- pSeqArray[ nSeqPos ][ nSeriesIndex ] = fValue;
+ Reference< beans::XPropertySet > xOldSequenceProp( aIt->second->getLabel(), uno::UNO_QUERY );
+ OSL_ASSERT( aIt->first.second == SCH_XML_PART_LABEL );
+ // index -1 is for categories => shouldn't have a label
+ OSL_ASSERT( aIt->first.first >= 0 );
+ OUString aRep( RTL_CONSTASCII_USTRINGPARAM("label "));
+ aRep += OUString::valueOf( aIt->first.first );
+
+ Reference< chart2::data::XDataSequence > xNewSequence(
+ xDataProv->createDataSequenceByRangeRepresentation( aRep ));
+ lcl_copyProperties(
+ xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
+ aIt->second->setLabel( xNewSequence );
}
}
}
- else // same row
- {
- DBG_ASSERT( rAddress.nRow1 == rAddress.nRow2, "range must be in one row or one column" );
- if( rAddress.nCol1 <= rAddress.nCol2 )
- {
- for( sal_Int32 nCol = rAddress.nCol1; nCol <= rAddress.nCol2; nCol++, nSeqPos++ )
- {
- DBG_ASSERT( rTable.aData[ rAddress.nRow1 ][ nCol ].eType != SCH_CELL_TYPE_UNKNOWN, "trying to refer to unknown cell" );
- fValue = rTable.aData[ rAddress.nRow1 ][ nCol ].fValue;
- if( ! ::rtl::math::isNan( fValue ))
- pSeqArray[ nSeqPos ][ nSeriesIndex ] = fValue;
- }
- }
- else // reverse
- {
- for( sal_Int32 nCol = rAddress.nCol1; nCol >= rAddress.nCol2; nCol--, nSeqPos++ )
- {
- DBG_ASSERT( rTable.aData[ rAddress.nRow1 ][ nCol ].eType != SCH_CELL_TYPE_UNKNOWN, "trying to refer to unknown cell" );
- fValue = rTable.aData[ rAddress.nRow1 ][ nCol ].fValue;
- if( ! ::rtl::math::isNan( fValue ))
- pSeqArray[ nSeqPos ][ nSeriesIndex ] = fValue;
- }
- }
+ // there exist files with own data without a categories element but with row
+ // descriptions. The row descriptions were used as categories even without
+ // the categories element
+ if( ! bCategoriesApplied )
+ {
+ SchXMLTools::CreateCategories(
+ xDataProv, xChartDoc, OUString(RTL_CONSTASCII_USTRINGPARAM("categories")),
+ 0 /* nCooSysIndex */, 0 /* nDimension */ );
}
}