merge the formfield patch from ooo-build
[ooovba.git] / xmloff / source / chart / SchXMLTableContext.cxx
blob2e0aad2997eec94e009c16b1eb4f82d8d46515da
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SchXMLTableContext.cxx,v $
10 * $Revision: 1.22 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmloff.hxx"
34 #include "SchXMLTableContext.hxx"
35 #include "SchXMLParagraphContext.hxx"
36 #include "SchXMLImport.hxx"
37 #include "SchXMLTools.hxx"
38 #include "transporttypes.hxx"
39 #include <tools/debug.hxx>
40 #include <rtl/math.hxx>
41 #include "xmlnmspe.hxx"
42 #include <xmloff/xmltoken.hxx>
43 #include <xmloff/nmspmap.hxx>
44 #include <xmloff/xmluconv.hxx>
45 #include <com/sun/star/frame/XModel.hpp>
46 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
47 #include <com/sun/star/chart2/XChartDocument.hpp>
48 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
49 #include <com/sun/star/chart2/XInternalDataProvider.hpp>
50 #include <com/sun/star/chart/XChartDataArray.hpp>
51 #include <com/sun/star/chart/ChartSeriesAddress.hpp>
52 #include <com/sun/star/beans/XPropertySet.hpp>
53 #include <com/sun/star/beans/XPropertySetInfo.hpp>
54 #include <com/sun/star/beans/PropertyAttribute.hpp>
56 #include <com/sun/star/chart2/XDiagram.hpp>
57 #include <com/sun/star/chart2/XAxis.hpp>
58 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
59 #include <com/sun/star/chart2/AxisType.hpp>
61 #include <vector>
62 #include <algorithm>
64 using namespace com::sun::star;
65 using namespace ::xmloff::token;
66 using ::com::sun::star::uno::Sequence;
67 using ::com::sun::star::uno::Reference;
68 using ::rtl::OUString;
70 namespace
73 const OUString lcl_aLabelPrefix( RTL_CONSTASCII_USTRINGPARAM("label "));
74 const OUString lcl_aCategoriesRange( RTL_CONSTASCII_USTRINGPARAM("categories"));
76 typedef ::std::multimap< ::rtl::OUString, ::rtl::OUString >
77 lcl_tOriginalRangeToInternalRangeMap;
79 Sequence< OUString > lcl_getCategoriesFromTable( const SchXMLTable & rTable, bool bHasLabels )
81 sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size()));
82 OSL_ENSURE( static_cast< size_t >( nNumRows ) == rTable.aData.size(), "Table too big" );
84 sal_Int32 nOffset(bHasLabels ? 1 : 0);
85 Sequence< OUString > aResult( nNumRows - nOffset );
86 sal_Int32 i=nOffset;
87 for( ; i<nNumRows; ++i )
89 if( !rTable.aData[i].empty() && (rTable.aData[i].front().eType == SCH_CELL_TYPE_STRING ))
90 aResult[i - nOffset] = rTable.aData[i].front().aString;
92 return aResult;
95 std::vector< Reference< chart2::XAxis > > lcl_getAxesHoldingCategoriesFromDiagram(
96 const Reference< chart2::XDiagram > & xDiagram )
98 std::vector< Reference< chart2::XAxis > > aRet;
100 Reference< chart2::XAxis > xResult;
101 // return first x-axis as fall-back
102 Reference< chart2::XAxis > xFallBack;
105 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
106 xDiagram, uno::UNO_QUERY_THROW );
107 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
108 xCooSysCnt->getCoordinateSystems());
109 for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
111 Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[i] );
112 OSL_ASSERT( xCooSys.is());
113 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
115 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
116 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
118 Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
119 OSL_ASSERT( xAxis.is());
120 if( xAxis.is())
122 chart2::ScaleData aScaleData = xAxis->getScaleData();
123 if( aScaleData.Categories.is() || (aScaleData.AxisType == chart2::AxisType::CATEGORY) )
125 aRet.push_back(xAxis);
127 if( (nN == 0) && !xFallBack.is())
128 xFallBack.set( xAxis );
134 catch( uno::Exception & )
138 if( aRet.empty())
139 aRet.push_back(xFallBack);
141 return aRet;
144 void lcl_ApplyColumnLabels(
145 const ::std::vector< SchXMLCell > & rFirstRow,
146 Sequence< OUString > & rOutColumnLabels,
147 sal_Int32 nOffset )
149 const sal_Int32 nColumnLabelsSize = rOutColumnLabels.getLength();
150 const sal_Int32 nMax = ::std::min< sal_Int32 >( nColumnLabelsSize,
151 static_cast< sal_Int32 >( rFirstRow.size()) - nOffset );
152 OSL_ASSERT( nMax == nColumnLabelsSize );
153 for( sal_Int32 i=0; i<nMax; ++i )
154 if( rFirstRow[i+nOffset].eType == SCH_CELL_TYPE_STRING )
155 rOutColumnLabels[i] = rFirstRow[i+nOffset].aString;
158 struct lcl_ApplyCellToData : public ::std::unary_function< SchXMLCell, void >
160 lcl_ApplyCellToData( Sequence< double > & rOutData,
161 Sequence< OUString > & rOutRowLabels ) :
162 m_rData( rOutData ),
163 m_rRowLabels( rOutRowLabels ),
164 m_nIndex( 0 ),
165 m_nSize( rOutData.getLength())
167 ::rtl::math::setNan( &m_fNaN );
170 void operator() ( const SchXMLCell & rCell )
172 if( m_nIndex < m_nSize )
174 if( rCell.eType == SCH_CELL_TYPE_FLOAT )
175 m_rData[m_nIndex] = rCell.fValue;
176 else
177 m_rData[m_nIndex] = m_fNaN;
179 ++m_nIndex;
182 private:
183 Sequence< double > & m_rData;
184 Sequence< OUString > & m_rRowLabels;
185 sal_Int32 m_nIndex;
186 sal_Int32 m_nSize;
187 double m_fNaN;
190 struct lcl_ApplyRowsToData : public ::std::unary_function< ::std::vector< SchXMLCell >, void >
192 lcl_ApplyRowsToData( Sequence< Sequence< double > > & rOutData,
193 Sequence< OUString > & rOutRowLabels,
194 sal_Int32 nOffset,
195 bool bHasHeader ) :
196 m_rData( rOutData ),
197 m_rRowLabels( rOutRowLabels ),
198 m_nIndex( 0 ),
199 m_nOuterSize( rOutData.getLength()),
200 m_nOffset( nOffset ),
201 m_bHasHeader( bHasHeader )
203 void operator() ( const ::std::vector< SchXMLCell > & rRow )
205 if( ! rRow.empty())
207 // label
208 if( m_bHasHeader && m_nIndex < m_rRowLabels.getLength() && rRow.front().eType == SCH_CELL_TYPE_STRING )
209 m_rRowLabels[m_nIndex] = rRow.front().aString;
211 // values
212 if( m_nIndex < m_nOuterSize )
213 ::std::for_each( rRow.begin() + m_nOffset, rRow.end(), lcl_ApplyCellToData( m_rData[m_nIndex], m_rRowLabels ));
215 ++m_nIndex;
218 private:
219 Sequence< Sequence< double > > & m_rData;
220 Sequence< OUString > & m_rRowLabels;
221 sal_Int32 m_nIndex;
222 sal_Int32 m_nOuterSize;
223 sal_Int32 m_nOffset;
224 bool m_bHasHeader;
227 Sequence< Sequence< double > > lcl_getSwappedArray( const Sequence< Sequence< double > > & rData )
229 sal_Int32 nOldOuterSize = rData.getLength();
230 sal_Int32 nOldInnerSize = (nOldOuterSize == 0 ? 0 : rData[0].getLength());
231 Sequence< Sequence< double > > aResult( nOldInnerSize );
233 for( sal_Int32 i=0; i<nOldInnerSize; ++i )
234 aResult[i].realloc( nOldOuterSize );
236 for( sal_Int32 nOuter=0; nOuter<nOldOuterSize; ++nOuter )
237 for( sal_Int32 nInner=0; nInner<nOldInnerSize; ++nInner )
238 aResult[nInner][nOuter] = rData[nOuter][nInner];
240 return aResult;
243 void lcl_applyXMLTableToInternalDataprovider(
244 const SchXMLTable & rTable,
245 const Reference< chart::XChartDataArray > & xDataArray )
247 sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size()));
248 sal_Int32 nRowOffset = 0;
249 if( rTable.bHasHeaderRow )
251 --nNumRows;
252 nRowOffset = 1;
254 sal_Int32 nNumColumns( rTable.nMaxColumnIndex + 1 );
255 sal_Int32 nColOffset = 0;
256 if( rTable.bHasHeaderColumn )
258 --nNumColumns;
259 nColOffset = 1;
262 Sequence< Sequence< double > > aData( nNumRows );
263 Sequence< OUString > aRowLabels( nNumRows );
264 Sequence< OUString > aColumnLabels( nNumColumns );
265 for( sal_Int32 i=0; i<nNumRows; ++i )
266 aData[i].realloc( nNumColumns );
268 if( rTable.aData.begin() != rTable.aData.end())
270 if( rTable.bHasHeaderRow )
271 lcl_ApplyColumnLabels( rTable.aData.front(), aColumnLabels, nColOffset );
272 ::std::for_each( rTable.aData.begin() + nRowOffset, rTable.aData.end(),
273 lcl_ApplyRowsToData( aData, aRowLabels, nColOffset, rTable.bHasHeaderColumn ));
276 xDataArray->setData( aData );
278 if( rTable.bHasHeaderColumn )
279 xDataArray->setRowDescriptions( aRowLabels );
280 if( rTable.bHasHeaderRow )
281 xDataArray->setColumnDescriptions( aColumnLabels );
284 void lcl_fillRangeMapping(
285 const SchXMLTable & rTable,
286 lcl_tOriginalRangeToInternalRangeMap & rOutRangeMap,
287 chart::ChartDataRowSource eDataRowSource )
289 sal_Int32 nRowOffset = ( rTable.bHasHeaderRow ? 1 : 0 );
290 sal_Int32 nColOffset = ( rTable.bHasHeaderColumn ? 1 : 0 );
292 // Fill range mapping
293 const size_t nTableRowCount( rTable.aData.size());
294 for( size_t nRow = 0; nRow < nTableRowCount; ++nRow )
296 const ::std::vector< SchXMLCell > & rRow( rTable.aData[nRow] );
297 const size_t nTableColCount( rRow.size());
298 for( size_t nCol = 0; nCol < nTableColCount; ++nCol )
300 OUString aRangeId( rRow[nCol].aRangeId );
301 if( aRangeId.getLength())
303 if( eDataRowSource == chart::ChartDataRowSource_COLUMNS )
305 if( nCol == 0 && rTable.bHasHeaderColumn )
307 OSL_ASSERT( static_cast< sal_Int32 >( nRow ) == nRowOffset );
308 rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
309 aRangeId, lcl_aCategoriesRange ));
311 else
313 OUString aColNumStr = OUString::valueOf( static_cast< sal_Int32 >( nCol - nColOffset ));
314 if( nRow == 0 && rTable.bHasHeaderRow )
315 rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
316 aRangeId, lcl_aLabelPrefix + aColNumStr ));
317 else
318 rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
319 aRangeId, aColNumStr ));
322 else // eDataRowSource == chart::ChartDataRowSource_ROWS
324 if( nRow == 0 && rTable.bHasHeaderRow )
326 OSL_ASSERT( static_cast< sal_Int32 >( nCol ) == nColOffset );
327 rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
328 aRangeId, lcl_aCategoriesRange ));
330 else
332 OUString aRowNumStr = OUString::valueOf( static_cast< sal_Int32 >( nRow - nRowOffset ));
333 if( nCol == 0 && rTable.bHasHeaderColumn )
334 rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
335 aRangeId, lcl_aLabelPrefix + aRowNumStr ));
336 else
337 rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
338 aRangeId, aRowNumStr ));
346 Reference< chart2::data::XDataSequence >
347 lcl_reassignDataSequence(
348 const Reference< chart2::data::XDataSequence > & xSequence,
349 const Reference< chart2::data::XDataProvider > & xDataProvider,
350 lcl_tOriginalRangeToInternalRangeMap & rRangeMap,
351 const OUString & rRange )
353 Reference< chart2::data::XDataSequence > xResult( xSequence );
354 lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange ));
355 if( aIt != rRangeMap.end())
357 // set sequence with correct data
358 xResult.set( xDataProvider->createDataSequenceByRangeRepresentation( aIt->second ));
359 // remove translation, because it was used
360 rRangeMap.erase( aIt );
363 return xResult;
366 bool lcl_mapContainsRange(
367 lcl_tOriginalRangeToInternalRangeMap & rRangeMap,
368 const OUString & rRange )
370 lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange ));
371 return ( aIt != rRangeMap.end());
374 bool lcl_tableOfRangeMatches(
375 const ::rtl::OUString & rRange,
376 const ::rtl::OUString & rTableName )
378 // both strings are non-empty and the table name is part of the range
379 return ( (rRange.getLength() > 0) &&
380 (rTableName.getLength() > 0) &&
381 (rRange.indexOf( rTableName ) != -1 ));
384 template< typename T >
385 ::std::vector< T > lcl_SequenceToVector( const uno::Sequence< T > & rSequence )
387 ::std::vector< T > aResult( rSequence.getLength());
388 ::std::copy( rSequence.getConstArray(), rSequence.getConstArray() + rSequence.getLength(),
389 aResult.begin());
390 return aResult;
393 } // anonymous namespace
396 // ----------------------------------------
397 // class SchXMLTableContext
398 // ----------------------------------------
400 SchXMLTableContext::SchXMLTableContext( SchXMLImportHelper& rImpHelper,
401 SvXMLImport& rImport,
402 const rtl::OUString& rLName,
403 SchXMLTable& aTable ) :
404 SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLName ),
405 mrImportHelper( rImpHelper ),
406 mrTable( aTable ),
407 mbHasRowPermutation( false ),
408 mbHasColumnPermutation( false )
410 mrTable.nColumnIndex = -1;
411 mrTable.nMaxColumnIndex = -1;
412 mrTable.nRowIndex = -1;
413 mrTable.aData.clear();
416 SchXMLTableContext::~SchXMLTableContext()
420 SvXMLImportContext *SchXMLTableContext::CreateChildContext(
421 USHORT nPrefix,
422 const rtl::OUString& rLocalName,
423 const uno::Reference< xml::sax::XAttributeList >& )
425 SvXMLImportContext* pContext = 0;
426 const SvXMLTokenMap& rTokenMap = mrImportHelper.GetTableElemTokenMap();
428 switch( rTokenMap.Get( nPrefix, rLocalName ))
430 case XML_TOK_TABLE_HEADER_COLS:
431 mrTable.bHasHeaderColumn = true;
432 // fall through intended
433 case XML_TOK_TABLE_COLUMNS:
434 pContext = new SchXMLTableColumnsContext( mrImportHelper, GetImport(), rLocalName, mrTable );
435 break;
437 case XML_TOK_TABLE_COLUMN:
438 pContext = new SchXMLTableColumnContext( mrImportHelper, GetImport(), rLocalName, mrTable );
439 break;
441 case XML_TOK_TABLE_HEADER_ROWS:
442 mrTable.bHasHeaderRow = true;
443 // fall through intended
444 case XML_TOK_TABLE_ROWS:
445 pContext = new SchXMLTableRowsContext( mrImportHelper, GetImport(), rLocalName, mrTable );
446 break;
448 case XML_TOK_TABLE_ROW:
449 pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable );
450 break;
452 default:
453 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
456 return pContext;
459 void SchXMLTableContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
461 // get table-name
462 sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
464 for( sal_Int16 i = 0; i < nAttrCount; i++ )
466 rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
467 rtl::OUString aLocalName;
468 USHORT nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
470 if( nPrefix == XML_NAMESPACE_TABLE &&
471 IsXMLToken( aLocalName, XML_NAME ) )
473 mrTable.aTableNameOfFile = xAttrList->getValueByIndex( i );
474 break; // we only need this attribute
479 void SchXMLTableContext::EndElement()
481 if( mbHasColumnPermutation )
483 OSL_ASSERT( !mbHasRowPermutation );
484 ::std::vector< sal_Int32 > aPermutation( lcl_SequenceToVector( maColumnPermutation ));
485 OSL_ASSERT( !aPermutation.empty());
486 if( aPermutation.empty())
487 return;
489 // permute the values of all rows according to aPermutation
490 for( ::std::vector< ::std::vector< SchXMLCell > >::iterator aRowIt( mrTable.aData.begin());
491 aRowIt != mrTable.aData.end(); ++aRowIt )
493 bool bModified = false;
494 ::std::vector< SchXMLCell > aModifiedRow;
495 const size_t nPermSize = aPermutation.size();
496 OSL_ASSERT( static_cast< sal_Int32 >( nPermSize ) - 1 == *(::std::max_element( aPermutation.begin(), aPermutation.end())));
497 const size_t nRowSize = aRowIt->size();
498 const size_t nDestSize = ::std::min( nPermSize, nRowSize );
499 for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex )
501 const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] );
502 if( nSourceIndex != nDestinationIndex &&
503 nSourceIndex < nRowSize )
505 // copy original on first real permutation
506 if( !bModified )
508 OSL_ASSERT( aModifiedRow.empty());
509 aModifiedRow.reserve( aRowIt->size());
510 ::std::copy( aRowIt->begin(), aRowIt->end(), ::std::back_inserter( aModifiedRow ));
511 OSL_ASSERT( !aModifiedRow.empty());
513 OSL_ASSERT( nDestinationIndex < aModifiedRow.size());
514 aModifiedRow[ nDestinationIndex ] = (*aRowIt)[ nSourceIndex ];
515 bModified = true;
518 // copy back
519 if( bModified )
520 ::std::copy( aModifiedRow.begin(), aModifiedRow.end(), aRowIt->begin());
523 else if( mbHasRowPermutation )
525 ::std::vector< sal_Int32 > aPermutation( lcl_SequenceToVector( maRowPermutation ));
526 OSL_ASSERT( !aPermutation.empty());
527 if( aPermutation.empty())
528 return;
530 bool bModified = false;
531 const size_t nPermSize = aPermutation.size();
532 OSL_ASSERT( static_cast< sal_Int32 >( nPermSize ) - 1 == *(::std::max_element( aPermutation.begin(), aPermutation.end())));
533 const size_t nTableRowCount = mrTable.aData.size();
534 const size_t nDestSize = ::std::min( nPermSize, nTableRowCount );
535 ::std::vector< ::std::vector< SchXMLCell > > aDestination;
536 for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex )
538 const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] );
539 if( nSourceIndex != nDestinationIndex &&
540 nSourceIndex < nTableRowCount )
542 // copy original on first real permutation
543 if( !bModified )
545 OSL_ASSERT( aDestination.empty());
546 aDestination.reserve( mrTable.aData.size());
547 ::std::copy( mrTable.aData.begin(), mrTable.aData.end(), ::std::back_inserter( aDestination ));
548 OSL_ASSERT( !aDestination.empty());
550 OSL_ASSERT( nDestinationIndex < aDestination.size());
551 aDestination[ nDestinationIndex ] = mrTable.aData[ nSourceIndex ];
552 bModified = true;
555 if( bModified )
557 // copy back
558 ::std::copy( aDestination.begin(), aDestination.end(), mrTable.aData.begin());
563 void SchXMLTableContext::setRowPermutation( const uno::Sequence< sal_Int32 > & rPermutation )
565 maRowPermutation = rPermutation;
566 mbHasRowPermutation = ( rPermutation.getLength() > 0 );
568 if( mbHasRowPermutation && mbHasColumnPermutation )
570 mbHasColumnPermutation = false;
571 maColumnPermutation.realloc( 0 );
575 void SchXMLTableContext::setColumnPermutation( const uno::Sequence< sal_Int32 > & rPermutation )
577 maColumnPermutation = rPermutation;
578 mbHasColumnPermutation = ( rPermutation.getLength() > 0 );
580 if( mbHasColumnPermutation && mbHasRowPermutation )
582 mbHasRowPermutation = false;
583 maRowPermutation.realloc( 0 );
587 // ========================================
588 // classes for columns
589 // ========================================
591 // ----------------------------------------
592 // class SchXMLTableColumnsContext
593 // ----------------------------------------
595 SchXMLTableColumnsContext::SchXMLTableColumnsContext(
596 SchXMLImportHelper& rImpHelper,
597 SvXMLImport& rImport,
598 const rtl::OUString& rLocalName,
599 SchXMLTable& aTable ) :
600 SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
601 mrImportHelper( rImpHelper ),
602 mrTable( aTable )
606 SchXMLTableColumnsContext::~SchXMLTableColumnsContext()
610 SvXMLImportContext* SchXMLTableColumnsContext::CreateChildContext(
611 USHORT nPrefix,
612 const rtl::OUString& rLocalName,
613 const uno::Reference< xml::sax::XAttributeList >& )
615 SvXMLImportContext* pContext = 0;
617 if( nPrefix == XML_NAMESPACE_TABLE &&
618 IsXMLToken( rLocalName, XML_TABLE_COLUMN ) )
620 pContext = new SchXMLTableColumnContext( mrImportHelper, GetImport(), rLocalName, mrTable );
622 else
623 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
625 return pContext;
628 // ----------------------------------------
629 // class SchXMLTableColumnContext
630 // ----------------------------------------
632 SchXMLTableColumnContext::SchXMLTableColumnContext(
633 SchXMLImportHelper& rImpHelper,
634 SvXMLImport& rImport,
635 const rtl::OUString& rLocalName,
636 SchXMLTable& aTable ) :
637 SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
638 mrImportHelper( rImpHelper ),
639 mrTable( aTable )
643 void SchXMLTableColumnContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
645 // get number-columns-repeated attribute
646 sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
647 sal_Int32 nRepeated = 1;
648 bool bHidden = false;
650 for( sal_Int16 i = 0; i < nAttrCount; i++ )
652 rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
653 rtl::OUString aLocalName;
654 USHORT nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
656 if( nPrefix == XML_NAMESPACE_TABLE &&
657 IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) )
659 rtl::OUString aValue = xAttrList->getValueByIndex( i );
660 if( aValue.getLength())
661 nRepeated = aValue.toInt32();
663 else if( nPrefix == XML_NAMESPACE_TABLE &&
664 IsXMLToken( aLocalName, XML_VISIBILITY ) )
666 rtl::OUString aVisibility = xAttrList->getValueByIndex( i );
667 bHidden = aVisibility.equals( GetXMLToken( XML_COLLAPSE ) );
671 sal_Int32 nOldCount = mrTable.nNumberOfColsEstimate;
672 sal_Int32 nNewCount = nOldCount + nRepeated;
673 mrTable.nNumberOfColsEstimate = nNewCount;
675 if( bHidden )
677 //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste )
678 sal_Int32 nColOffset = ( mrTable.bHasHeaderColumn ? 1 : 0 );
679 for( sal_Int32 nN = nOldCount; nN<nNewCount; nN++ )
681 sal_Int32 nHiddenColumnIndex = nN-nColOffset;
682 if( nHiddenColumnIndex>=0 )
683 mrTable.aHiddenColumns.push_back(nHiddenColumnIndex);
688 SchXMLTableColumnContext::~SchXMLTableColumnContext()
692 // ========================================
693 // classes for rows
694 // ========================================
696 // ----------------------------------------
697 // class SchXMLTableRowsContext
698 // ----------------------------------------
700 SchXMLTableRowsContext::SchXMLTableRowsContext(
701 SchXMLImportHelper& rImpHelper,
702 SvXMLImport& rImport,
703 const rtl::OUString& rLocalName,
704 SchXMLTable& aTable ) :
705 SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
706 mrImportHelper( rImpHelper ),
707 mrTable( aTable )
711 SchXMLTableRowsContext::~SchXMLTableRowsContext()
715 SvXMLImportContext* SchXMLTableRowsContext::CreateChildContext(
716 USHORT nPrefix,
717 const rtl::OUString& rLocalName,
718 const uno::Reference< xml::sax::XAttributeList >& )
720 SvXMLImportContext* pContext = 0;
722 if( nPrefix == XML_NAMESPACE_TABLE &&
723 IsXMLToken( rLocalName, XML_TABLE_ROW ) )
725 pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable );
727 else
729 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
732 return pContext;
735 // ----------------------------------------
736 // class SchXMLTableRowContext
737 // ----------------------------------------
739 SchXMLTableRowContext::SchXMLTableRowContext(
740 SchXMLImportHelper& rImpHelper,
741 SvXMLImport& rImport,
742 const rtl::OUString& rLocalName,
743 SchXMLTable& aTable ) :
744 SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
745 mrImportHelper( rImpHelper ),
746 mrTable( aTable )
748 mrTable.nColumnIndex = -1;
749 mrTable.nRowIndex++;
751 std::vector< SchXMLCell > aNewRow;
752 aNewRow.reserve( mrTable.nNumberOfColsEstimate );
753 while( mrTable.aData.size() <= (unsigned long)mrTable.nRowIndex )
754 mrTable.aData.push_back( aNewRow );
757 SchXMLTableRowContext::~SchXMLTableRowContext()
761 SvXMLImportContext* SchXMLTableRowContext::CreateChildContext(
762 USHORT nPrefix,
763 const rtl::OUString& rLocalName,
764 const uno::Reference< xml::sax::XAttributeList >& )
766 SvXMLImportContext* pContext = 0;
768 // <table:table-cell> element
769 if( nPrefix == XML_NAMESPACE_TABLE &&
770 IsXMLToken(rLocalName, XML_TABLE_CELL ) )
772 pContext = new SchXMLTableCellContext( mrImportHelper, GetImport(), rLocalName, mrTable );
774 else
776 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
779 return pContext;
783 // ========================================
784 // classes for cells and their content
785 // ========================================
787 // ----------------------------------------
788 // class SchXMLTableCellContext
789 // ----------------------------------------
791 SchXMLTableCellContext::SchXMLTableCellContext(
792 SchXMLImportHelper& rImpHelper,
793 SvXMLImport& rImport,
794 const rtl::OUString& rLocalName,
795 SchXMLTable& aTable ) :
796 SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
797 mrImportHelper( rImpHelper ),
798 mrTable( aTable )
802 SchXMLTableCellContext::~SchXMLTableCellContext()
806 void SchXMLTableCellContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
808 sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
809 rtl::OUString aValue;
810 rtl::OUString aLocalName;
811 rtl::OUString aCellContent;
812 SchXMLCellType eValueType = SCH_CELL_TYPE_UNKNOWN;
813 const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetCellAttrTokenMap();
815 for( sal_Int16 i = 0; i < nAttrCount; i++ )
817 rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
818 USHORT nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
820 switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
822 case XML_TOK_CELL_VAL_TYPE:
823 aValue = xAttrList->getValueByIndex( i );
824 if( IsXMLToken( aValue, XML_FLOAT ) )
825 eValueType = SCH_CELL_TYPE_FLOAT;
826 else if( IsXMLToken( aValue, XML_STRING ) )
827 eValueType = SCH_CELL_TYPE_STRING;
828 break;
830 case XML_TOK_CELL_VALUE:
831 aCellContent = xAttrList->getValueByIndex( i );
832 break;
836 mbReadPara = sal_True;
837 SchXMLCell aCell;
838 aCell.eType = eValueType;
840 if( eValueType == SCH_CELL_TYPE_FLOAT )
842 double fData;
843 // the result may be false if a NaN is read, but that's ok
844 SvXMLUnitConverter::convertDouble( fData, aCellContent );
846 aCell.fValue = fData;
847 // dont read following <text:p> element
848 mbReadPara = sal_False;
851 mrTable.aData[ mrTable.nRowIndex ].push_back( aCell );
852 mrTable.nColumnIndex++;
853 if( mrTable.nMaxColumnIndex < mrTable.nColumnIndex )
854 mrTable.nMaxColumnIndex = mrTable.nColumnIndex;
857 SvXMLImportContext* SchXMLTableCellContext::CreateChildContext(
858 USHORT nPrefix,
859 const rtl::OUString& rLocalName,
860 const uno::Reference< xml::sax::XAttributeList >& )
862 SvXMLImportContext* pContext = 0;
864 // <text:p> element
865 if( nPrefix == XML_NAMESPACE_TEXT &&
866 IsXMLToken( rLocalName, XML_P ) )
868 pContext = new SchXMLParagraphContext( GetImport(), rLocalName, maCellContent, &maRangeId );
870 else
872 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
875 return pContext;
878 void SchXMLTableCellContext::EndElement()
880 if( mbReadPara && maCellContent.getLength())
881 mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aString = maCellContent;
882 if( maRangeId.getLength())
883 mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aRangeId = maRangeId;
886 // ========================================
888 // just interpret the table in a linear way with no references used
889 // (this is just a workaround for clipboard handling in EA2)
890 void SchXMLTableHelper::applyTableSimple(
891 const SchXMLTable& rTable,
892 const uno::Reference< chart::XChartDataArray > & xData )
894 // interpret table like this:
896 // series ----+---+
897 // | |
898 // categories | |
899 // | | |
900 // V V V
901 // A B C ...
902 // 1 x x <--- labels
903 // 2 x 0 0
904 // 3 x 0 0
905 // ...
907 // Standard Role-interpretation:
909 // Column 1 contains the Categories
911 // Chart Type/Class | Col 2 Col 3 Col 4 Col 5 Col 6 | Series | Domain
912 // -----------------+-----------------------------------+--------+-------
913 // Category Charts | Y 1 Y 2 Y 3 Y 4 ... | Y | -
914 // XY Chart | X all Y 1 Y 2 Y 3 ... | Y | X
915 // Stock Chart 1 | Min Max Close - - | Close | -
916 // Stock Chart 2 | Open Min Max Close - | Close | -
917 // Stock Chart 3 | Volume Min Max Close - | Close | -
918 // Stock Chart 4 | Volume Open Min Max Close | Close | -
920 if( xData.is())
922 // get NaN
923 double fSolarNaN;
924 ::rtl::math::setNan( &fSolarNaN );
925 double fNaN = fSolarNaN;
926 sal_Bool bConvertNaN = sal_False;
928 uno::Reference< chart::XChartData > xChartData( xData, uno::UNO_QUERY );
929 if( xChartData.is())
931 fNaN = xChartData->getNotANumber();
932 bConvertNaN = ( ! ::rtl::math::isNan( fNaN ));
935 sal_Int32 nRowCount = rTable.aData.size();
936 sal_Int32 nColumnCount = 0;
937 sal_Int32 nCol = 0, nRow = 0;
938 if( nRowCount )
940 nColumnCount = rTable.aData[ 0 ].size();
941 ::std::vector< ::std::vector< SchXMLCell > >::const_iterator iRow = rTable.aData.begin();
942 while( iRow != rTable.aData.end() )
944 nColumnCount = ::std::max( nColumnCount, static_cast<sal_Int32>(iRow->size()) );
945 iRow++;
949 // #i27909# avoid illegal index access for empty tables
950 if( nColumnCount == 0 || nRowCount == 0 )
951 return;
953 uno::Sequence< ::rtl::OUString > aCategories( nRowCount - 1 );
954 uno::Sequence< ::rtl::OUString > aLabels( nColumnCount - 1 );
955 uno::Sequence< uno::Sequence< double > > aData( nRowCount - 1 );
956 for( nRow = 0; nRow < nRowCount - 1; nRow++ )
957 aData[ nRow ].realloc( nColumnCount - 1 );
959 // set labels
960 ::std::vector< ::std::vector< SchXMLCell > >::const_iterator iRow = rTable.aData.begin();
961 sal_Int32 nColumnCountOnFirstRow = iRow->size();
962 for( nCol = 1; nCol < nColumnCountOnFirstRow; nCol++ )
964 aLabels[ nCol - 1 ] = (*iRow)[ nCol ].aString;
966 xData->setColumnDescriptions( aLabels );
968 double fVal;
969 const sal_Bool bConstConvertNan = bConvertNaN;
970 for( ++iRow, nRow = 0; iRow != rTable.aData.end(); iRow++, nRow++ )
972 aCategories[ nRow ] = (*iRow)[ 0 ].aString;
973 sal_Int32 nTableColCount( static_cast< sal_Int32 >((*iRow).size()));
974 for( nCol = 1; nCol < nTableColCount; nCol++ )
976 fVal = (*iRow)[ nCol ].fValue;
977 if( bConstConvertNan &&
978 ::rtl::math::isNan( fVal ))
979 aData[ nRow ][ nCol - 1 ] = fNaN;
980 else
981 aData[ nRow ][ nCol - 1 ] = fVal;
983 // set remaining cells to NaN
984 for( ; nCol < nColumnCount; ++nCol )
985 if( bConstConvertNan )
986 aData[ nRow ][nCol - 1 ] = fNaN;
987 else
988 ::rtl::math::setNan( &(aData[ nRow ][nCol - 1 ]));
990 xData->setRowDescriptions( aCategories );
991 xData->setData( aData );
995 // ----------------------------------------
997 void SchXMLTableHelper::applyTableToInternalDataProvider(
998 const SchXMLTable& rTable,
999 uno::Reference< chart2::XChartDocument > xChartDoc )
1001 if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider()))
1002 return;
1003 Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider());
1004 Reference< chart::XChartDataArray > xDataArray( xDataProv, uno::UNO_QUERY );
1005 if( ! xDataArray.is())
1006 return;
1007 OSL_ASSERT( xDataProv.is());
1009 // prerequisite for this method: all objects (data series, domains, etc.)
1010 // need their own range string.
1012 // apply all data read in the table to the chart data-array of the internal
1013 // data provider
1014 lcl_applyXMLTableToInternalDataprovider( rTable, xDataArray );
1017 void SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary(
1018 const SchXMLTable& rTable,
1019 const tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
1020 uno::Reference< chart2::XChartDocument > xChartDoc,
1021 chart::ChartDataRowSource eDataRowSource )
1023 if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider()))
1024 return;
1026 // If the range-strings are valid (starting with "local-table") they should
1027 // be interpreted like given, otherwise (when the ranges refer to Calc- or
1028 // Writer-ranges, but the container is not available like when pasting a
1029 // chart from Calc to Impress) the range is ignored, and every object gets
1030 // one table column in the order of appearance, which is: 1. categories,
1031 // 2. data series: 2.a) domains, 2.b) values (main-role, usually y-values)
1033 Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider());
1035 // create a mapping from original ranges to new ranges
1036 lcl_tOriginalRangeToInternalRangeMap aRangeMap;
1038 lcl_fillRangeMapping( rTable, aRangeMap, eDataRowSource );
1040 bool bCategoriesApplied = false;
1041 // translate ranges (using the map created before)
1042 for( tSchXMLLSequencesPerIndex::const_iterator aLSeqIt( rLSequencesPerIndex.begin());
1043 aLSeqIt != rLSequencesPerIndex.end(); ++aLSeqIt )
1045 if( aLSeqIt->second.is())
1047 // values/error bars/categories
1048 if( aLSeqIt->first.second == SCH_XML_PART_VALUES ||
1049 aLSeqIt->first.second == SCH_XML_PART_ERROR_BARS )
1051 Reference< chart2::data::XDataSequence > xSeq( aLSeqIt->second->getValues());
1052 OUString aRange;
1053 if( xSeq.is() &&
1054 SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) &&
1055 lcl_mapContainsRange( aRangeMap, aRange ))
1057 Reference< chart2::data::XDataSequence > xNewSeq(
1058 lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange ));
1059 if( xNewSeq != xSeq )
1061 SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
1062 Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY ));
1063 aLSeqIt->second->setValues( xNewSeq );
1066 else
1068 if( lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile ))
1070 if( aLSeqIt->first.first == SCH_XML_CATEGORIES_INDEX )
1071 bCategoriesApplied = true;
1073 else
1075 if( aLSeqIt->first.first == SCH_XML_CATEGORIES_INDEX )
1077 Reference< beans::XPropertySet > xOldSequenceProp( aLSeqIt->second->getValues(), uno::UNO_QUERY );
1078 Reference< chart2::data::XDataSequence > xNewSequence(
1079 xDataProv->createDataSequenceByRangeRepresentation(
1080 OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
1081 SchXMLTools::copyProperties(
1082 xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
1083 aLSeqIt->second->setValues( xNewSequence );
1084 bCategoriesApplied = true;
1086 else
1088 Reference< beans::XPropertySet > xOldSequenceProp( aLSeqIt->second->getValues(), uno::UNO_QUERY );
1089 OUString aRep( OUString::valueOf( aLSeqIt->first.first ));
1090 Reference< chart2::data::XDataSequence > xNewSequence(
1091 xDataProv->createDataSequenceByRangeRepresentation( aRep ));
1092 SchXMLTools::copyProperties(
1093 xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
1094 aLSeqIt->second->setValues( xNewSequence );
1099 else // labels
1101 OSL_ASSERT( aLSeqIt->first.second == SCH_XML_PART_LABEL );
1102 // labels
1103 Reference< chart2::data::XDataSequence > xSeq( aLSeqIt->second->getLabel());
1104 OUString aRange;
1105 if( xSeq.is() &&
1106 SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) &&
1107 lcl_mapContainsRange( aRangeMap, aRange ))
1109 Reference< chart2::data::XDataSequence > xNewSeq(
1110 lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange ));
1111 if( xNewSeq != xSeq )
1113 SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
1114 Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY ));
1115 aLSeqIt->second->setLabel( xNewSeq );
1118 else if( ! lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile ))
1120 OUString aRep( RTL_CONSTASCII_USTRINGPARAM("label "));
1121 aRep += OUString::valueOf( aLSeqIt->first.first );
1123 Reference< chart2::data::XDataSequence > xNewSeq(
1124 xDataProv->createDataSequenceByRangeRepresentation( aRep ));
1125 SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
1126 Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY ));
1127 aLSeqIt->second->setLabel( xNewSeq );
1133 // there exist files with own data without a categories element but with row
1134 // descriptions. The row descriptions were used as categories even without
1135 // the categories element
1136 if( ! bCategoriesApplied )
1138 SchXMLTools::CreateCategories(
1139 xDataProv, xChartDoc, OUString(RTL_CONSTASCII_USTRINGPARAM("categories")),
1140 0 /* nCooSysIndex */, 0 /* nDimension */ );
1143 //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste )
1144 //remove series that consist only of hidden columns
1145 Reference< chart2::XInternalDataProvider > xInternalDataProvider( xDataProv, uno::UNO_QUERY );
1146 if( xInternalDataProvider.is() && !rTable.aHiddenColumns.empty() )
1150 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChartDoc->getFirstDiagram(), uno::UNO_QUERY_THROW );
1151 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
1152 for( sal_Int32 nC=0; nC<aCooSysSeq.getLength(); ++nC )
1154 Reference< chart2::XChartTypeContainer > xCooSysContainer( aCooSysSeq[nC], uno::UNO_QUERY_THROW );
1155 Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCooSysContainer->getChartTypes());
1156 for( sal_Int32 nT=0; nT<aChartTypeSeq.getLength(); ++nT )
1158 Reference< chart2::XDataSeriesContainer > xSeriesContainer( aChartTypeSeq[nT], uno::UNO_QUERY );
1159 if(!xSeriesContainer.is())
1160 continue;
1161 Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesContainer->getDataSeries() );
1162 std::vector< Reference< chart2::XDataSeries > > aRemainingSeries;
1164 for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
1166 Reference< chart2::data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
1167 if( xDataSource.is() )
1169 bool bHasUnhiddenColumns = false;
1170 rtl::OUString aRange;
1171 uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences() );
1172 for( sal_Int32 nN=0; nN< aSequences.getLength(); ++nN )
1174 Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aSequences[nN] );
1175 if(!xLabeledSequence.is())
1176 continue;
1177 Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() );
1178 if( xValues.is() )
1180 aRange = xValues->getSourceRangeRepresentation();
1181 if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aRange.toInt32() ) == rTable.aHiddenColumns.end() )
1182 bHasUnhiddenColumns = true;
1184 if( !bHasUnhiddenColumns )
1186 Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() );
1187 if( xLabel.is() )
1189 aRange = xLabel->getSourceRangeRepresentation();
1190 sal_Int32 nSearchIndex = 0;
1191 OUString aSecondToken = aRange.getToken( 1, ' ', nSearchIndex );
1192 if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aSecondToken.toInt32() ) == rTable.aHiddenColumns.end() )
1193 bHasUnhiddenColumns = true;
1197 if( bHasUnhiddenColumns )
1198 aRemainingSeries.push_back( aSeriesSeq[nS] );
1202 if( static_cast<sal_Int32>(aRemainingSeries.size()) != aSeriesSeq.getLength() )
1204 //remove the series that have only hidden data
1205 Sequence< Reference< chart2::XDataSeries > > aRemainingSeriesSeq( aRemainingSeries.size());
1206 ::std::copy( aRemainingSeries.begin(), aRemainingSeries.end(), aRemainingSeriesSeq.getArray());
1207 xSeriesContainer->setDataSeries( aRemainingSeriesSeq );
1209 //remove unused sequences
1210 Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
1211 if( xDataSource.is() )
1213 //first detect which collumns are really used
1214 std::map< sal_Int32, bool > aUsageMap;
1215 rtl::OUString aRange;
1216 Sequence< Reference< chart2::data::XLabeledDataSequence > > aUsedSequences( xDataSource->getDataSequences() );
1217 for( sal_Int32 nN=0; nN< aUsedSequences.getLength(); ++nN )
1219 Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aUsedSequences[nN] );
1220 if(!xLabeledSequence.is())
1221 continue;
1222 Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() );
1223 if( xValues.is() )
1225 aRange = xValues->getSourceRangeRepresentation();
1226 sal_Int32 nIndex = aRange.toInt32();
1227 if( nIndex!=0 || !aRange.equals(lcl_aCategoriesRange) )
1228 aUsageMap[nIndex] = true;
1230 Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() );
1231 if( xLabel.is() )
1233 aRange = xLabel->getSourceRangeRepresentation();
1234 sal_Int32 nSearchIndex = 0;
1235 OUString aSecondToken = aRange.getToken( 1, ' ', nSearchIndex );
1236 if( aSecondToken.getLength() )
1237 aUsageMap[aSecondToken.toInt32()] = true;
1241 ::std::vector< sal_Int32 > aSequenceIndexesToDelete;
1242 for( ::std::vector< sal_Int32 >::const_iterator aIt(
1243 rTable.aHiddenColumns.begin()); aIt != rTable.aHiddenColumns.end(); ++aIt )
1245 sal_Int32 nSequenceIndex = *aIt;
1246 if( aUsageMap.find(nSequenceIndex) != aUsageMap.end() )
1247 continue;
1248 aSequenceIndexesToDelete.push_back(nSequenceIndex);
1251 // delete unnecessary sequences of the internal data
1252 // iterate using greatest index first, so that deletion does not
1253 // shift other sequences that will be deleted later
1254 ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end());
1255 for( ::std::vector< sal_Int32 >::reverse_iterator aIt(
1256 aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt )
1258 if( *aIt != -1 )
1259 xInternalDataProvider->deleteSequence( *aIt );
1266 catch( uno::Exception & ex )
1268 (void)ex; // avoid warning for pro build