1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 
31 #include "SchXMLTableContext.hxx"
32 #include "SchXMLParagraphContext.hxx"
33 #include "SchXMLTextListContext.hxx"
34 #include "SchXMLImport.hxx"
35 #include "SchXMLTools.hxx"
36 #include "transporttypes.hxx"
37 #include "XMLStringBufferImportContext.hxx"
38 #include <tools/debug.hxx>
39 #include <rtl/math.hxx>
40 #include "xmloff/xmlnmspe.hxx"
41 #include <xmloff/xmltoken.hxx>
42 #include <xmloff/nmspmap.hxx>
43 #include <xmloff/xmluconv.hxx>
44 #include <com/sun/star/frame/XModel.hpp>
45 #include <com/sun/star/chart2/XAnyDescriptionAccess.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/ChartSeriesAddress.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/beans/XPropertySetInfo.hpp>
53 #include <com/sun/star/beans/PropertyAttribute.hpp>
54 
55 #include <com/sun/star/chart2/XDiagram.hpp>
56 #include <com/sun/star/chart2/XAxis.hpp>
57 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
58 #include <com/sun/star/chart2/AxisType.hpp>
59 
60 #include <vector>
61 #include <algorithm>
62 
63 using namespace com::sun::star;
64 using namespace ::xmloff::token;
65 using ::com::sun::star::uno::Sequence;
66 using ::com::sun::star::uno::Reference;
67 using ::rtl::OUString;
68 
69 namespace
70 {
71 
72 const OUString lcl_aLabelPrefix( RTL_CONSTASCII_USTRINGPARAM("label "));
73 const OUString lcl_aCategoriesRange( RTL_CONSTASCII_USTRINGPARAM("categories"));
74 
75 typedef ::std::multimap< ::rtl::OUString, ::rtl::OUString >
76     lcl_tOriginalRangeToInternalRangeMap;
77 
78 Sequence< OUString > lcl_getCategoriesFromTable( const SchXMLTable & rTable, bool bHasLabels )
79 {
80     sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size()));
81     OSL_ENSURE( static_cast< size_t >( nNumRows ) == rTable.aData.size(), "Table too big" );
82 
83     sal_Int32 nOffset(bHasLabels ? 1 : 0);
84     Sequence< OUString > aResult( nNumRows - nOffset );
85     sal_Int32 i=nOffset;
86     for( ; i<nNumRows; ++i )
87     {
88         if( !rTable.aData[i].empty() && (rTable.aData[i].front().eType == SCH_CELL_TYPE_STRING ))
89             aResult[i - nOffset] = rTable.aData[i].front().aString;
90     }
91     return aResult;
92 }
93 
94 std::vector< Reference< chart2::XAxis > > lcl_getAxesHoldingCategoriesFromDiagram(
95     const Reference< chart2::XDiagram > & xDiagram )
96 {
97     std::vector< Reference< chart2::XAxis > > aRet;
98 
99     Reference< chart2::XAxis > xResult;
100     // return first x-axis as fall-back
101     Reference< chart2::XAxis > xFallBack;
102     try
103     {
104         Reference< chart2::XCoordinateSystemContainer > xCooSysCnt(
105             xDiagram, uno::UNO_QUERY_THROW );
106         Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq(
107             xCooSysCnt->getCoordinateSystems());
108         for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
109         {
110             Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[i] );
111             OSL_ASSERT( xCooSys.is());
112             for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
113             {
114                 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
115                 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
116                 {
117                     Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI );
118                     OSL_ASSERT( xAxis.is());
119                     if( xAxis.is())
120                     {
121                         chart2::ScaleData aScaleData = xAxis->getScaleData();
122                         if( aScaleData.Categories.is() || (aScaleData.AxisType == chart2::AxisType::CATEGORY) )
123                         {
124                             aRet.push_back(xAxis);
125                         }
126                         if( (nN == 0) && !xFallBack.is())
127                             xFallBack.set( xAxis );
128                     }
129                 }
130             }
131         }
132     }
133     catch( uno::Exception & )
134     {
135     }
136 
137     if( aRet.empty())
138         aRet.push_back(xFallBack);
139 
140     return aRet;
141 }
142 
143 struct lcl_ApplyCellToData : public ::std::unary_function< SchXMLCell, void >
144 {
145     lcl_ApplyCellToData( Sequence< double > & rOutData ) :
146             m_rData( rOutData ),
147             m_nIndex( 0 ),
148             m_nSize( rOutData.getLength())
149     {
150         ::rtl::math::setNan( &m_fNaN );
151     }
152 
153     void operator() ( const SchXMLCell & rCell )
154     {
155         if( m_nIndex < m_nSize )
156         {
157             if( rCell.eType == SCH_CELL_TYPE_FLOAT )
158                 m_rData[m_nIndex] = rCell.fValue;
159             else
160                 m_rData[m_nIndex] = m_fNaN;
161         }
162         ++m_nIndex;
163     }
164 
165     sal_Int32 getCurrentIndex() const
166     {
167         return m_nIndex;
168     }
169 
170 private:
171     Sequence< double > & m_rData;
172     sal_Int32 m_nIndex;
173     sal_Int32 m_nSize;
174     double m_fNaN;
175 };
176 
177 Sequence< Sequence< double > > lcl_getSwappedArray( const Sequence< Sequence< double > > & rData )
178 {
179     sal_Int32 nOldOuterSize = rData.getLength();
180     sal_Int32 nOldInnerSize = (nOldOuterSize == 0 ? 0 : rData[0].getLength());
181     Sequence< Sequence< double > > aResult( nOldInnerSize );
182 
183     for( sal_Int32 i=0; i<nOldInnerSize; ++i )
184         aResult[i].realloc( nOldOuterSize );
185 
186     for( sal_Int32 nOuter=0; nOuter<nOldOuterSize; ++nOuter )
187         for( sal_Int32 nInner=0; nInner<nOldInnerSize; ++nInner )
188             aResult[nInner][nOuter] = rData[nOuter][nInner];
189 
190     return aResult;
191 }
192 
193 void lcl_fillRangeMapping(
194     const SchXMLTable & rTable,
195     lcl_tOriginalRangeToInternalRangeMap & rOutRangeMap,
196     chart::ChartDataRowSource eDataRowSource )
197 {
198     sal_Int32 nRowOffset = ( rTable.bHasHeaderRow ? 1 : 0 );
199     sal_Int32 nColOffset = ( rTable.bHasHeaderColumn ? 1 : 0 );
200 
201     // Fill range mapping
202     const size_t nTableRowCount( rTable.aData.size());
203     for( size_t nRow = 0; nRow < nTableRowCount; ++nRow )
204     {
205         const ::std::vector< SchXMLCell > & rRow( rTable.aData[nRow] );
206         const size_t nTableColCount( rRow.size());
207         for( size_t nCol = 0; nCol < nTableColCount; ++nCol )
208         {
209             OUString aRangeId( rRow[nCol].aRangeId );
210             if( aRangeId.getLength())
211             {
212                 if( eDataRowSource == chart::ChartDataRowSource_COLUMNS )
213                 {
214                     if( nCol == 0 && rTable.bHasHeaderColumn )
215                     {
216                         OSL_ASSERT( static_cast< sal_Int32 >( nRow ) == nRowOffset );
217                         rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
218                                                  aRangeId, lcl_aCategoriesRange ));
219                     }
220                     else
221                     {
222                         OUString aColNumStr = OUString::valueOf( static_cast< sal_Int32 >( nCol - nColOffset ));
223                         if( nRow == 0 && rTable.bHasHeaderRow )
224                             rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
225                                                      aRangeId, lcl_aLabelPrefix + aColNumStr ));
226                         else
227                             rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
228                                                      aRangeId, aColNumStr ));
229                     }
230                 }
231                 else // eDataRowSource == chart::ChartDataRowSource_ROWS
232                 {
233                     if( nRow == 0 && rTable.bHasHeaderRow )
234                     {
235                         OSL_ASSERT( static_cast< sal_Int32 >( nCol ) == nColOffset );
236                         rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
237                                                  aRangeId, lcl_aCategoriesRange ));
238                     }
239                     else
240                     {
241                         OUString aRowNumStr = OUString::valueOf( static_cast< sal_Int32 >( nRow - nRowOffset ));
242                         if( nCol == 0 && rTable.bHasHeaderColumn )
243                             rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
244                                                      aRangeId, lcl_aLabelPrefix + aRowNumStr ));
245                         else
246                             rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type(
247                                                      aRangeId, aRowNumStr ));
248                     }
249                 }
250             }
251         }
252     }
253 }
254 
255 Reference< chart2::data::XDataSequence >
256     lcl_reassignDataSequence(
257         const Reference< chart2::data::XDataSequence > & xSequence,
258         const Reference< chart2::data::XDataProvider > & xDataProvider,
259         lcl_tOriginalRangeToInternalRangeMap & rRangeMap,
260         const OUString & rRange )
261 {
262     Reference< chart2::data::XDataSequence > xResult( xSequence );
263     lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange ));
264     if( aIt != rRangeMap.end())
265     {
266         // set sequence with correct data
267         xResult.set( xDataProvider->createDataSequenceByRangeRepresentation( aIt->second ));
268         // remove translation, because it was used
269         rRangeMap.erase( aIt );
270     }
271 
272     return xResult;
273 }
274 
275 bool lcl_mapContainsRange(
276     lcl_tOriginalRangeToInternalRangeMap & rRangeMap,
277     const OUString & rRange )
278 {
279     lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange ));
280     return ( aIt != rRangeMap.end());
281 }
282 
283 bool lcl_tableOfRangeMatches(
284     const ::rtl::OUString & rRange,
285     const ::rtl::OUString & rTableName )
286 {
287     // both strings are non-empty and the table name is part of the range
288     return ( (rRange.getLength() > 0) &&
289              (rTableName.getLength() > 0) &&
290              (rRange.indexOf( rTableName ) != -1 ));
291 }
292 
293 template< typename T >
294 ::std::vector< T > lcl_SequenceToVector( const uno::Sequence< T > & rSequence )
295 {
296     ::std::vector< T > aResult( rSequence.getLength());
297     ::std::copy( rSequence.getConstArray(), rSequence.getConstArray() + rSequence.getLength(),
298                  aResult.begin());
299     return aResult;
300 }
301 
302 } // anonymous namespace
303 
304 
305 // ----------------------------------------
306 // class SchXMLTableContext
307 // ----------------------------------------
308 
309 SchXMLTableContext::SchXMLTableContext( SchXMLImportHelper& rImpHelper,
310 										SvXMLImport& rImport,
311 										const rtl::OUString& rLName,
312 										SchXMLTable& aTable ) :
313 		SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLName ),
314 		mrImportHelper( rImpHelper ),
315 		mrTable( aTable ),
316         mbHasRowPermutation( false ),
317         mbHasColumnPermutation( false )
318 {
319 	mrTable.nColumnIndex = -1;
320 	mrTable.nMaxColumnIndex = -1;
321 	mrTable.nRowIndex = -1;
322 	mrTable.aData.clear();
323 }
324 
325 SchXMLTableContext::~SchXMLTableContext()
326 {
327 }
328 
329 SvXMLImportContext *SchXMLTableContext::CreateChildContext(
330 	sal_uInt16 nPrefix,
331 	const rtl::OUString& rLocalName,
332 	const uno::Reference< xml::sax::XAttributeList >& )
333 {
334 	SvXMLImportContext* pContext = 0;
335 	const SvXMLTokenMap& rTokenMap = mrImportHelper.GetTableElemTokenMap();
336 
337 	switch( rTokenMap.Get( nPrefix, rLocalName ))
338 	{
339 		case XML_TOK_TABLE_HEADER_COLS:
340             mrTable.bHasHeaderColumn = true;
341             // fall through intended
342 		case XML_TOK_TABLE_COLUMNS:
343 			pContext = new SchXMLTableColumnsContext( mrImportHelper, GetImport(), rLocalName, mrTable );
344 			break;
345 
346 		case XML_TOK_TABLE_COLUMN:
347 			pContext = new SchXMLTableColumnContext( mrImportHelper, GetImport(), rLocalName, mrTable );
348 			break;
349 
350 		case XML_TOK_TABLE_HEADER_ROWS:
351             mrTable.bHasHeaderRow = true;
352             // fall through intended
353 		case XML_TOK_TABLE_ROWS:
354 			pContext = new SchXMLTableRowsContext( mrImportHelper, GetImport(), rLocalName, mrTable );
355 			break;
356 
357 		case XML_TOK_TABLE_ROW:
358 			pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable );
359 			break;
360 
361 		default:
362 			pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
363 	}
364 
365 	return pContext;
366 }
367 
368 void SchXMLTableContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
369 {
370     // get table-name
371 	sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
372 
373 	for( sal_Int16 i = 0; i < nAttrCount; i++ )
374 	{
375 		rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
376 		rtl::OUString aLocalName;
377 		sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
378         if ( nPrefix == XML_NAMESPACE_TABLE )
379         {
380             if ( IsXMLToken( aLocalName, XML_NAME ) )
381             {
382                 mrTable.aTableNameOfFile = xAttrList->getValueByIndex( i );
383             }
384             else if ( IsXMLToken( aLocalName, XML_PROTECTED ) )
385             {
386                 if ( IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) )
387                 {
388                     mrTable.bProtected = true;
389                 }
390             }
391         }
392 	}
393 }
394 
395 void SchXMLTableContext::EndElement()
396 {
397     if( mbHasColumnPermutation )
398     {
399         OSL_ASSERT( !mbHasRowPermutation );
400         ::std::vector< sal_Int32 > aPermutation( lcl_SequenceToVector( maColumnPermutation ));
401         OSL_ASSERT( !aPermutation.empty());
402         if( aPermutation.empty())
403             return;
404 
405         // permute the values of all rows according to aPermutation
406         for( ::std::vector< ::std::vector< SchXMLCell > >::iterator aRowIt( mrTable.aData.begin());
407              aRowIt != mrTable.aData.end(); ++aRowIt )
408         {
409             bool bModified = false;
410             ::std::vector< SchXMLCell > aModifiedRow;
411             const size_t nPermSize = aPermutation.size();
412             OSL_ASSERT( static_cast< sal_Int32 >( nPermSize ) - 1 == *(::std::max_element( aPermutation.begin(), aPermutation.end())));
413             const size_t nRowSize = aRowIt->size();
414             const size_t nDestSize = ::std::min( nPermSize, nRowSize );
415             for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex )
416             {
417                 const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] );
418                 if( nSourceIndex != nDestinationIndex &&
419                     nSourceIndex < nRowSize )
420                 {
421                     // copy original on first real permutation
422                     if( !bModified )
423                     {
424                         OSL_ASSERT( aModifiedRow.empty());
425                         aModifiedRow.reserve( aRowIt->size());
426                         ::std::copy( aRowIt->begin(), aRowIt->end(), ::std::back_inserter( aModifiedRow ));
427                         OSL_ASSERT( !aModifiedRow.empty());
428                     }
429                     OSL_ASSERT( nDestinationIndex < aModifiedRow.size());
430                     aModifiedRow[ nDestinationIndex ] = (*aRowIt)[ nSourceIndex ];
431                     bModified = true;
432                 }
433             }
434             // copy back
435             if( bModified )
436                 ::std::copy( aModifiedRow.begin(), aModifiedRow.end(), aRowIt->begin());
437         }
438     }
439     else if( mbHasRowPermutation )
440     {
441         ::std::vector< sal_Int32 > aPermutation( lcl_SequenceToVector( maRowPermutation ));
442         OSL_ASSERT( !aPermutation.empty());
443         if( aPermutation.empty())
444             return;
445 
446         bool bModified = false;
447         const size_t nPermSize = aPermutation.size();
448         OSL_ASSERT( static_cast< sal_Int32 >( nPermSize ) - 1 == *(::std::max_element( aPermutation.begin(), aPermutation.end())));
449         const size_t nTableRowCount = mrTable.aData.size();
450         const size_t nDestSize = ::std::min( nPermSize, nTableRowCount );
451         ::std::vector< ::std::vector< SchXMLCell > > aDestination;
452         for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex )
453         {
454             const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] );
455             if( nSourceIndex != nDestinationIndex &&
456                 nSourceIndex < nTableRowCount )
457             {
458                 // copy original on first real permutation
459                 if( !bModified )
460                 {
461                     OSL_ASSERT( aDestination.empty());
462                     aDestination.reserve( mrTable.aData.size());
463                     ::std::copy( mrTable.aData.begin(), mrTable.aData.end(), ::std::back_inserter( aDestination ));
464                     OSL_ASSERT( !aDestination.empty());
465                 }
466                 OSL_ASSERT( nDestinationIndex < aDestination.size());
467                 aDestination[ nDestinationIndex ] = mrTable.aData[ nSourceIndex ];
468                 bModified = true;
469             }
470         }
471         if( bModified )
472         {
473             // copy back
474             ::std::copy( aDestination.begin(), aDestination.end(), mrTable.aData.begin());
475         }
476     }
477 }
478 
479 void SchXMLTableContext::setRowPermutation( const uno::Sequence< sal_Int32 > & rPermutation )
480 {
481     maRowPermutation = rPermutation;
482     mbHasRowPermutation = ( rPermutation.getLength() > 0 );
483 
484     if( mbHasRowPermutation && mbHasColumnPermutation )
485     {
486         mbHasColumnPermutation = false;
487         maColumnPermutation.realloc( 0 );
488     }
489 }
490 
491 void SchXMLTableContext::setColumnPermutation( const uno::Sequence< sal_Int32 > & rPermutation )
492 {
493     maColumnPermutation = rPermutation;
494     mbHasColumnPermutation = ( rPermutation.getLength() > 0 );
495 
496     if( mbHasColumnPermutation && mbHasRowPermutation )
497     {
498         mbHasRowPermutation = false;
499         maRowPermutation.realloc( 0 );
500     }
501 }
502 
503 // ========================================
504 // classes for columns
505 // ========================================
506 
507 // ----------------------------------------
508 // class SchXMLTableColumnsContext
509 // ----------------------------------------
510 
511 SchXMLTableColumnsContext::SchXMLTableColumnsContext(
512 	SchXMLImportHelper& rImpHelper,
513 	SvXMLImport& rImport,
514 	const rtl::OUString& rLocalName,
515 	SchXMLTable& aTable ) :
516 		SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
517 		mrImportHelper( rImpHelper ),
518 		mrTable( aTable )
519 {
520 }
521 
522 SchXMLTableColumnsContext::~SchXMLTableColumnsContext()
523 {
524 }
525 
526 SvXMLImportContext* SchXMLTableColumnsContext::CreateChildContext(
527 	sal_uInt16 nPrefix,
528 	const rtl::OUString& rLocalName,
529 	const uno::Reference< xml::sax::XAttributeList >& )
530 {
531 	SvXMLImportContext* pContext = 0;
532 
533 	if( nPrefix == XML_NAMESPACE_TABLE &&
534 		IsXMLToken( rLocalName, XML_TABLE_COLUMN ) )
535 	{
536 		pContext = new SchXMLTableColumnContext( mrImportHelper, GetImport(), rLocalName, mrTable );
537 	}
538 	else
539 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
540 
541 	return pContext;
542 }
543 
544 // ----------------------------------------
545 // class SchXMLTableColumnContext
546 // ----------------------------------------
547 
548 SchXMLTableColumnContext::SchXMLTableColumnContext(
549 	SchXMLImportHelper& rImpHelper,
550 	SvXMLImport& rImport,
551 	const rtl::OUString& rLocalName,
552 	SchXMLTable& aTable ) :
553 		SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
554 		mrImportHelper( rImpHelper ),
555 		mrTable( aTable )
556 {
557 }
558 
559 void SchXMLTableColumnContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
560 {
561 	// get number-columns-repeated attribute
562 	sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
563 	sal_Int32 nRepeated = 1;
564     bool bHidden = false;
565 
566 	for( sal_Int16 i = 0; i < nAttrCount; i++ )
567 	{
568 		rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
569 		rtl::OUString aLocalName;
570 		sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
571 
572 		if( nPrefix == XML_NAMESPACE_TABLE &&
573 			IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) )
574 		{
575 			rtl::OUString aValue = xAttrList->getValueByIndex( i );
576             if( aValue.getLength())
577                 nRepeated = aValue.toInt32();
578 		}
579         else if( nPrefix == XML_NAMESPACE_TABLE &&
580 			IsXMLToken( aLocalName, XML_VISIBILITY ) )
581 		{
582 			rtl::OUString aVisibility = xAttrList->getValueByIndex( i );
583             bHidden = aVisibility.equals( GetXMLToken( XML_COLLAPSE ) );
584 		}
585 	}
586 
587     sal_Int32 nOldCount = mrTable.nNumberOfColsEstimate;
588     sal_Int32 nNewCount = nOldCount + nRepeated;
589     mrTable.nNumberOfColsEstimate = nNewCount;
590 
591     if( bHidden )
592     {
593         //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste )
594         sal_Int32 nColOffset = ( mrTable.bHasHeaderColumn ? 1 : 0 );
595         for( sal_Int32 nN = nOldCount; nN<nNewCount; nN++ )
596         {
597             sal_Int32 nHiddenColumnIndex = nN-nColOffset;
598             if( nHiddenColumnIndex>=0 )
599                 mrTable.aHiddenColumns.push_back(nHiddenColumnIndex);
600         }
601     }
602 }
603 
604 SchXMLTableColumnContext::~SchXMLTableColumnContext()
605 {
606 }
607 
608 // ========================================
609 // classes for rows
610 // ========================================
611 
612 // ----------------------------------------
613 // class SchXMLTableRowsContext
614 // ----------------------------------------
615 
616 SchXMLTableRowsContext::SchXMLTableRowsContext(
617 	SchXMLImportHelper& rImpHelper,
618 	SvXMLImport& rImport,
619 	const rtl::OUString& rLocalName,
620 	SchXMLTable& aTable ) :
621 		SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
622 		mrImportHelper( rImpHelper ),
623 		mrTable( aTable )
624 {
625 }
626 
627 SchXMLTableRowsContext::~SchXMLTableRowsContext()
628 {
629 }
630 
631 SvXMLImportContext* SchXMLTableRowsContext::CreateChildContext(
632 	sal_uInt16 nPrefix,
633 	const rtl::OUString& rLocalName,
634 	const uno::Reference< xml::sax::XAttributeList >& )
635 {
636 	SvXMLImportContext* pContext = 0;
637 
638 	if( nPrefix == XML_NAMESPACE_TABLE &&
639         IsXMLToken( rLocalName, XML_TABLE_ROW ) )
640 	{
641 		pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable );
642 	}
643 	else
644 	{
645 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
646 	}
647 
648 	return pContext;
649 }
650 
651 // ----------------------------------------
652 // class SchXMLTableRowContext
653 // ----------------------------------------
654 
655 SchXMLTableRowContext::SchXMLTableRowContext(
656 	SchXMLImportHelper& rImpHelper,
657 	SvXMLImport& rImport,
658 	const rtl::OUString& rLocalName,
659 	SchXMLTable& aTable ) :
660 		SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
661 		mrImportHelper( rImpHelper ),
662 		mrTable( aTable )
663 {
664 	mrTable.nColumnIndex = -1;
665 	mrTable.nRowIndex++;
666 
667 	std::vector< SchXMLCell > aNewRow;
668 	aNewRow.reserve( mrTable.nNumberOfColsEstimate );
669 	while( mrTable.aData.size() <= (unsigned long)mrTable.nRowIndex )
670 		mrTable.aData.push_back( aNewRow );
671 }
672 
673 SchXMLTableRowContext::~SchXMLTableRowContext()
674 {
675 }
676 
677 SvXMLImportContext* SchXMLTableRowContext::CreateChildContext(
678 	sal_uInt16 nPrefix,
679 	const rtl::OUString& rLocalName,
680 	const uno::Reference< xml::sax::XAttributeList >& )
681 {
682 	SvXMLImportContext* pContext = 0;
683 
684 	// <table:table-cell> element
685 	if( nPrefix == XML_NAMESPACE_TABLE &&
686         IsXMLToken(rLocalName, XML_TABLE_CELL ) )
687 	{
688 		pContext = new SchXMLTableCellContext( mrImportHelper, GetImport(), rLocalName, mrTable );
689 	}
690 	else
691 	{
692 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
693 	}
694 
695 	return pContext;
696 }
697 
698 //---------------------------------------------------------------------------------------------------
699 //---------------------------------------------------------------------------------------------------
700 
701 class SchXMLRangeSomewhereContext : public SvXMLImportContext
702 {
703 //#i113950# previously the range was exported to attribute text:id,
704 //but that attribute does not allow arbitrary strings anymore
705 //so we need to find an alternative to save that range info for copy/paste scenario ...
706 //-> use description at an empty group element for now
707 
708 private:
709 	::rtl::OUString& mrRangeString;
710     ::rtl::OUStringBuffer maRangeStringBuffer;
711 
712 public:
713 	SchXMLRangeSomewhereContext( SvXMLImport& rImport,
714                             sal_uInt16 nPrefix,
715 							const ::rtl::OUString& rLocalName,
716 							::rtl::OUString& rRangeString );
717 	virtual ~SchXMLRangeSomewhereContext();
718 
719 	virtual SvXMLImportContext* CreateChildContext(
720 		sal_uInt16 nPrefix,
721 		const ::rtl::OUString& rLocalName,
722 		const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttrList );
723     virtual void EndElement();
724 };
725 
726 //---------------------------------------------------------------------------------------------------
727 //---------------------------------------------------------------------------------------------------
728 
729 // ========================================
730 // classes for cells and their content
731 // ========================================
732 
733 // ----------------------------------------
734 // class SchXMLTableCellContext
735 // ----------------------------------------
736 
737 SchXMLTableCellContext::SchXMLTableCellContext(
738 	SchXMLImportHelper& rImpHelper,
739 	SvXMLImport& rImport,
740 	const rtl::OUString& rLocalName,
741 	SchXMLTable& aTable ) :
742 		SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ),
743 		mrImportHelper( rImpHelper ),
744 		mrTable( aTable )
745 {
746 }
747 
748 SchXMLTableCellContext::~SchXMLTableCellContext()
749 {
750 }
751 
752 void SchXMLTableCellContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
753 {
754 	sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
755 	rtl::OUString aValue;
756 	rtl::OUString aLocalName;
757 	rtl::OUString aCellContent;
758 	SchXMLCellType eValueType  = SCH_CELL_TYPE_UNKNOWN;
759 	const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetCellAttrTokenMap();
760 
761 	for( sal_Int16 i = 0; i < nAttrCount; i++ )
762 	{
763 		rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
764 		sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
765 
766 		switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
767 		{
768 			case XML_TOK_CELL_VAL_TYPE:
769 				aValue = xAttrList->getValueByIndex( i );
770 				if( IsXMLToken( aValue, XML_FLOAT ) )
771 					eValueType = SCH_CELL_TYPE_FLOAT;
772 				else if( IsXMLToken( aValue, XML_STRING ) )
773 					eValueType = SCH_CELL_TYPE_STRING;
774 				break;
775 
776 			case XML_TOK_CELL_VALUE:
777 				aCellContent = xAttrList->getValueByIndex( i );
778 				break;
779 		}
780 	}
781 
782 	mbReadText = sal_True;
783 	SchXMLCell aCell;
784 	aCell.eType = eValueType;
785 
786 	if( eValueType == SCH_CELL_TYPE_FLOAT )
787 	{
788 		double fData;
789 		// the result may be false if a NaN is read, but that's ok
790 		SvXMLUnitConverter::convertDouble( fData, aCellContent );
791 
792 		aCell.fValue = fData;
793 		// dont read text from following <text:p> or <text:list> element
794 		mbReadText = sal_False;
795 	}
796 
797 	mrTable.aData[ mrTable.nRowIndex ].push_back( aCell );
798 	mrTable.nColumnIndex++;
799 	if( mrTable.nMaxColumnIndex < mrTable.nColumnIndex )
800 		mrTable.nMaxColumnIndex = mrTable.nColumnIndex;
801 }
802 
803 SvXMLImportContext* SchXMLTableCellContext::CreateChildContext(
804 	sal_uInt16 nPrefix,
805 	const rtl::OUString& rLocalName,
806 	const uno::Reference< xml::sax::XAttributeList >& )
807 {
808 	SvXMLImportContext* pContext = 0;
809 
810     // <text:list> element
811     if( nPrefix == XML_NAMESPACE_TEXT && IsXMLToken( rLocalName, XML_LIST ) && mbReadText )
812 	{
813         SchXMLCell& rCell = mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ];
814         rCell.pComplexString = new Sequence< OUString >();
815         rCell.eType = SCH_CELL_TYPE_COMPLEX_STRING;
816         pContext = new SchXMLTextListContext( GetImport(), rLocalName, *rCell.pComplexString );
817         mbReadText = sal_False;//don't apply text from <text:p>
818 	}
819 	// <text:p> element - read text (and range from text:id old version)
820 	else if( nPrefix == XML_NAMESPACE_TEXT && IsXMLToken( rLocalName, XML_P ) )
821 	{
822         pContext = new SchXMLParagraphContext( GetImport(), rLocalName, maCellContent, &maRangeId );
823 	}
824     // <draw:g> element - read range
825     else if( nPrefix == XML_NAMESPACE_DRAW && IsXMLToken( rLocalName, XML_G ) )
826 	{
827         //#i113950# previously the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore
828         //so we need to find an alternative to save that range info for copy/paste scenario ... -> use description at an empty group element for now
829         pContext = new SchXMLRangeSomewhereContext( GetImport(), nPrefix, rLocalName, maRangeId );
830 	}
831 	else
832 	{
833 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
834 	}
835 
836 	return pContext;
837 }
838 
839 void SchXMLTableCellContext::EndElement()
840 {
841 	if( mbReadText && maCellContent.getLength() ) //apply text from <text:p> element
842         mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aString = maCellContent;
843     if( maRangeId.getLength())
844         mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aRangeId = maRangeId;
845 }
846 
847 // ========================================
848 
849 void lcl_ApplyCellToComplexLabel( const SchXMLCell& rCell, Sequence< uno::Any >& rComplexLabel )
850 {
851     if( rCell.eType == SCH_CELL_TYPE_STRING )
852     {
853         rComplexLabel.realloc(1);
854         rComplexLabel[0] = uno::makeAny( rCell.aString );
855     }
856     else if( rCell.pComplexString && rCell.eType == SCH_CELL_TYPE_COMPLEX_STRING )
857     {
858         sal_Int32 nCount = rCell.pComplexString->getLength();
859         rComplexLabel.realloc( nCount );
860         for( sal_Int32 nN=0; nN<nCount; nN++)
861             rComplexLabel[nN] = uno::makeAny((*rCell.pComplexString)[nN]);
862     }
863     else if( rCell.eType == SCH_CELL_TYPE_FLOAT )
864     {
865         rComplexLabel.realloc(1);
866         rComplexLabel[0] = uno::makeAny( rCell.fValue );
867     }
868 }
869 
870 void SchXMLTableHelper::applyTableToInternalDataProvider(
871 	const SchXMLTable& rTable,
872 	uno::Reference< chart2::XChartDocument > xChartDoc )
873 {
874     // apply all data read from the local table to the internal data provider
875     if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() )
876         return;
877     Reference< chart2::data::XDataProvider >  xDataProv( xChartDoc->getDataProvider() );
878     if( !xDataProv.is() )
879         return;
880 
881     //prepare the read local table data
882     sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size()));
883     sal_Int32 nRowOffset = 0;
884     if( rTable.bHasHeaderRow )
885     {
886         --nNumRows;
887         nRowOffset = 1;
888     }
889     sal_Int32 nNumColumns( rTable.nMaxColumnIndex + 1 );
890     sal_Int32 nColOffset = 0;
891     if( rTable.bHasHeaderColumn )
892     {
893         --nNumColumns;
894         nColOffset = 1;
895     }
896 
897     Sequence< Sequence< double > > aDataInRows( nNumRows );
898     Sequence< Sequence< uno::Any > > aComplexRowDescriptions( nNumRows );
899     Sequence< Sequence< uno::Any > > aComplexColumnDescriptions( nNumColumns );
900     for( sal_Int32 i=0; i<nNumRows; ++i )
901         aDataInRows[i].realloc( nNumColumns );
902 
903     if( rTable.aData.begin() != rTable.aData.end())
904     {
905         //apply column labels
906         if( rTable.bHasHeaderRow )
907         {
908             const ::std::vector< SchXMLCell >& rFirstRow = rTable.aData.front();
909             const sal_Int32 nColumnLabelsSize = aComplexColumnDescriptions.getLength();
910             const sal_Int32 nMax = ::std::min< sal_Int32 >( nColumnLabelsSize, static_cast< sal_Int32 >( rFirstRow.size()) - nColOffset );
911             OSL_ASSERT( nMax == nColumnLabelsSize );
912             for( sal_Int32 i=0; i<nMax; ++i )
913                 lcl_ApplyCellToComplexLabel( rFirstRow[i+nColOffset], aComplexColumnDescriptions[i] );
914         }
915 
916         std::vector< ::std::vector< SchXMLCell > >::const_iterator aRowIter( rTable.aData.begin() + nRowOffset );
917         std::vector< ::std::vector< SchXMLCell > >::const_iterator aEnd( rTable.aData.end() );
918         for( sal_Int32 nRow = 0; aRowIter != aEnd && nRow < nNumRows; ++aRowIter, ++nRow )
919         {
920             const ::std::vector< SchXMLCell >& rRow = *aRowIter;
921             if( !rRow.empty() )
922             {
923                 // row label
924                 if( rTable.bHasHeaderColumn )
925                     lcl_ApplyCellToComplexLabel( rRow.front(), aComplexRowDescriptions[nRow] );
926 
927                 // values
928                 Sequence< double >& rTargetRow = aDataInRows[nRow];
929                 lcl_ApplyCellToData aApplyCellToData = ::std::for_each( rRow.begin() + nColOffset, rRow.end(), lcl_ApplyCellToData( rTargetRow ) );
930                 double fNaN = 0.0;
931                 ::rtl::math::setNan( &fNaN );
932                 for( sal_Int32 nCurrentIndex = aApplyCellToData.getCurrentIndex(); nCurrentIndex<nNumColumns; nCurrentIndex++ )
933                     rTargetRow[nCurrentIndex] = fNaN;//#i110615#
934             }
935         }
936     }
937 
938     //apply the collected data to the chart
939     Reference< chart2::XAnyDescriptionAccess > xDataAccess( xDataProv, uno::UNO_QUERY );
940     if( !xDataAccess.is() )
941         return;
942 
943     xDataAccess->setData( aDataInRows );
944     if( rTable.bHasHeaderColumn )
945         xDataAccess->setAnyRowDescriptions( aComplexRowDescriptions );
946     if( rTable.bHasHeaderRow )
947         xDataAccess->setAnyColumnDescriptions( aComplexColumnDescriptions );
948 
949     if ( rTable.bProtected )
950     {
951         try
952         {
953             Reference< beans::XPropertySet > xProps( xChartDoc, uno::UNO_QUERY_THROW );
954             xProps->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ), uno::makeAny( sal_True ) );
955             xProps->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableComplexChartTypes" ) ), uno::makeAny( sal_True ) );
956         }
957         catch ( uno::Exception& )
958         {
959         }
960     }
961 }
962 
963 void SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary(
964 	const SchXMLTable& rTable,
965     const tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
966 	uno::Reference< chart2::XChartDocument > xChartDoc,
967     chart::ChartDataRowSource eDataRowSource )
968 {
969     if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider()))
970         return;
971 
972     // If the range-strings are valid (starting with "local-table") they should
973     // be interpreted like given, otherwise (when the ranges refer to Calc- or
974     // Writer-ranges, but the container is not available like when pasting a
975     // chart from Calc to Impress) the range is ignored, and every object gets
976     // one table column in the order of appearance, which is: 1. categories,
977     // 2. data series: 2.a) domains, 2.b) values (main-role, usually y-values)
978 
979     Reference< chart2::data::XDataProvider >  xDataProv( xChartDoc->getDataProvider());
980 
981     // create a mapping from original ranges to new ranges
982     lcl_tOriginalRangeToInternalRangeMap aRangeMap;
983 
984     lcl_fillRangeMapping( rTable, aRangeMap, eDataRowSource );
985 
986     bool bCategoriesApplied = false;
987     // translate ranges (using the map created before)
988     for( tSchXMLLSequencesPerIndex::const_iterator aLSeqIt( rLSequencesPerIndex.begin());
989          aLSeqIt != rLSequencesPerIndex.end(); ++aLSeqIt )
990     {
991         if( aLSeqIt->second.is())
992         {
993             // values/error bars/categories
994             if( aLSeqIt->first.second == SCH_XML_PART_VALUES ||
995                 aLSeqIt->first.second == SCH_XML_PART_ERROR_BARS )
996             {
997                 Reference< chart2::data::XDataSequence > xSeq( aLSeqIt->second->getValues());
998                 OUString aRange;
999                 if( xSeq.is() &&
1000                     SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) &&
1001                     lcl_mapContainsRange( aRangeMap, aRange ))
1002                 {
1003                     Reference< chart2::data::XDataSequence > xNewSeq(
1004                         lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange ));
1005                     if( xNewSeq != xSeq )
1006                     {
1007                         SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
1008                                             Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY ));
1009                         aLSeqIt->second->setValues( xNewSeq );
1010                     }
1011                 }
1012                 else
1013                 {
1014                     if( lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile ))
1015                     {
1016                         if( aLSeqIt->first.first == SCH_XML_CATEGORIES_INDEX )
1017                             bCategoriesApplied = true;
1018                     }
1019                     else
1020                     {
1021                         if( aLSeqIt->first.first == SCH_XML_CATEGORIES_INDEX )
1022                         {
1023                             Reference< beans::XPropertySet > xOldSequenceProp( aLSeqIt->second->getValues(), uno::UNO_QUERY );
1024                             Reference< chart2::data::XDataSequence > xNewSequence(
1025                                 xDataProv->createDataSequenceByRangeRepresentation(
1026                                     OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
1027                             SchXMLTools::copyProperties(
1028                                 xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
1029                             aLSeqIt->second->setValues( xNewSequence );
1030                             bCategoriesApplied = true;
1031                         }
1032                         else
1033                         {
1034                             Reference< beans::XPropertySet > xOldSequenceProp( aLSeqIt->second->getValues(), uno::UNO_QUERY );
1035                             OUString aRep( OUString::valueOf( aLSeqIt->first.first ));
1036                             Reference< chart2::data::XDataSequence > xNewSequence(
1037                                 xDataProv->createDataSequenceByRangeRepresentation( aRep ));
1038                             SchXMLTools::copyProperties(
1039                                 xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY ));
1040                             aLSeqIt->second->setValues( xNewSequence );
1041                         }
1042                     }
1043                 }
1044             }
1045             else // labels
1046             {
1047                 OSL_ASSERT( aLSeqIt->first.second == SCH_XML_PART_LABEL );
1048                 // labels
1049                 Reference< chart2::data::XDataSequence > xSeq( aLSeqIt->second->getLabel());
1050                 OUString aRange;
1051                 if( xSeq.is() &&
1052                     SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) &&
1053                     lcl_mapContainsRange( aRangeMap, aRange ))
1054                 {
1055                     Reference< chart2::data::XDataSequence > xNewSeq(
1056                         lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange ));
1057                     if( xNewSeq != xSeq )
1058                     {
1059                         SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
1060                                             Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY ));
1061                         aLSeqIt->second->setLabel( xNewSeq );
1062                     }
1063                 }
1064                 else if( ! lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile ))
1065                 {
1066                     OUString aRep( RTL_CONSTASCII_USTRINGPARAM("label "));
1067                     aRep += OUString::valueOf( aLSeqIt->first.first );
1068 
1069                     Reference< chart2::data::XDataSequence > xNewSeq(
1070                         xDataProv->createDataSequenceByRangeRepresentation( aRep ));
1071                     SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
1072                                         Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY ));
1073                     aLSeqIt->second->setLabel( xNewSeq );
1074                 }
1075             }
1076         }
1077     }
1078 
1079     // there exist files with own data without a categories element but with row
1080     // descriptions.  The row descriptions were used as categories even without
1081     // the categories element
1082     if( ! bCategoriesApplied )
1083     {
1084         SchXMLTools::CreateCategories(
1085             xDataProv, xChartDoc, OUString(RTL_CONSTASCII_USTRINGPARAM("categories")),
1086             0 /* nCooSysIndex */, 0 /* nDimension */ );
1087     }
1088 
1089     //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste )
1090     //remove series that consist only of hidden columns
1091     Reference< chart2::XInternalDataProvider > xInternalDataProvider( xDataProv, uno::UNO_QUERY );
1092     if( xInternalDataProvider.is() && !rTable.aHiddenColumns.empty() )
1093     {
1094         try
1095         {
1096             Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChartDoc->getFirstDiagram(), uno::UNO_QUERY_THROW );
1097             Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
1098             for( sal_Int32 nC=0; nC<aCooSysSeq.getLength(); ++nC )
1099             {
1100                 Reference< chart2::XChartTypeContainer > xCooSysContainer( aCooSysSeq[nC], uno::UNO_QUERY_THROW );
1101                 Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCooSysContainer->getChartTypes());
1102                 for( sal_Int32 nT=0; nT<aChartTypeSeq.getLength(); ++nT )
1103                 {
1104                     Reference< chart2::XDataSeriesContainer > xSeriesContainer( aChartTypeSeq[nT], uno::UNO_QUERY );
1105                     if(!xSeriesContainer.is())
1106                         continue;
1107                     Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesContainer->getDataSeries() );
1108                     std::vector< Reference< chart2::XDataSeries > > aRemainingSeries;
1109 
1110                     for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ )
1111                     {
1112                         Reference< chart2::data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY );
1113                         if( xDataSource.is() )
1114                         {
1115                             bool bHasUnhiddenColumns = false;
1116                             rtl::OUString aRange;
1117                             uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences() );
1118                             for( sal_Int32 nN=0; nN< aSequences.getLength(); ++nN )
1119                             {
1120                                 Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aSequences[nN] );
1121                                 if(!xLabeledSequence.is())
1122                                     continue;
1123                                 Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() );
1124                                 if( xValues.is() )
1125                                 {
1126                                     aRange = xValues->getSourceRangeRepresentation();
1127                                     if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aRange.toInt32() ) == rTable.aHiddenColumns.end() )
1128                                         bHasUnhiddenColumns = true;
1129                                 }
1130                                 if( !bHasUnhiddenColumns )
1131                                 {
1132                                     Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() );
1133                                     if( xLabel.is() )
1134                                     {
1135                                         aRange = xLabel->getSourceRangeRepresentation();
1136                                         sal_Int32 nSearchIndex = 0;
1137                                         OUString aSecondToken = aRange.getToken( 1, ' ', nSearchIndex );
1138                                         if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aSecondToken.toInt32() ) == rTable.aHiddenColumns.end() )
1139                                             bHasUnhiddenColumns = true;
1140                                     }
1141                                 }
1142                             }
1143                             if( bHasUnhiddenColumns )
1144                                 aRemainingSeries.push_back( aSeriesSeq[nS] );
1145                         }
1146                     }
1147 
1148                     if( static_cast<sal_Int32>(aRemainingSeries.size()) != aSeriesSeq.getLength() )
1149                     {
1150                         //remove the series that have only hidden data
1151                         Sequence< Reference< chart2::XDataSeries > > aRemainingSeriesSeq( aRemainingSeries.size());
1152                         ::std::copy( aRemainingSeries.begin(), aRemainingSeries.end(), aRemainingSeriesSeq.getArray());
1153                         xSeriesContainer->setDataSeries( aRemainingSeriesSeq );
1154 
1155                         //remove unused sequences
1156                         Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
1157                         if( xDataSource.is() )
1158                         {
1159                             //first detect which collumns are really used
1160                             std::map< sal_Int32, bool > aUsageMap;
1161                             rtl::OUString aRange;
1162                             Sequence< Reference< chart2::data::XLabeledDataSequence > > aUsedSequences( xDataSource->getDataSequences() );
1163                             for( sal_Int32 nN=0; nN< aUsedSequences.getLength(); ++nN )
1164                             {
1165                                 Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aUsedSequences[nN] );
1166                                 if(!xLabeledSequence.is())
1167                                     continue;
1168                                 Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() );
1169                                 if( xValues.is() )
1170                                 {
1171                                     aRange = xValues->getSourceRangeRepresentation();
1172                                     sal_Int32 nIndex = aRange.toInt32();
1173                                     if( nIndex!=0 || !aRange.equals(lcl_aCategoriesRange) )
1174                                         aUsageMap[nIndex] = true;
1175                                 }
1176                                 Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() );
1177                                 if( xLabel.is() )
1178                                 {
1179                                     aRange = xLabel->getSourceRangeRepresentation();
1180                                     sal_Int32 nSearchIndex = 0;
1181                                     OUString aSecondToken = aRange.getToken( 1, ' ', nSearchIndex );
1182                                     if( aSecondToken.getLength() )
1183                                         aUsageMap[aSecondToken.toInt32()] = true;
1184                                 }
1185                             }
1186 
1187                             ::std::vector< sal_Int32 > aSequenceIndexesToDelete;
1188                             for( ::std::vector< sal_Int32 >::const_iterator aIt(
1189                                      rTable.aHiddenColumns.begin()); aIt != rTable.aHiddenColumns.end(); ++aIt )
1190                             {
1191                                 sal_Int32 nSequenceIndex = *aIt;
1192                                 if( aUsageMap.find(nSequenceIndex) != aUsageMap.end() )
1193                                     continue;
1194                                 aSequenceIndexesToDelete.push_back(nSequenceIndex);
1195                             }
1196 
1197                             // delete unnecessary sequences of the internal data
1198                             // iterate using greatest index first, so that deletion does not
1199                             // shift other sequences that will be deleted later
1200                             ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end());
1201                             for( ::std::vector< sal_Int32 >::reverse_iterator aIt(
1202                                      aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt )
1203                             {
1204                                 if( *aIt != -1 )
1205                                     xInternalDataProvider->deleteSequence( *aIt );
1206                             }
1207                         }
1208                     }
1209                 }
1210             }
1211         }
1212         catch( uno::Exception & ex )
1213         {
1214             (void)ex; // avoid warning for pro build
1215         }
1216     }
1217 }
1218 
1219 //---------------------------------------------------------------------------------------------------
1220 
1221 SchXMLRangeSomewhereContext::SchXMLRangeSomewhereContext( SvXMLImport& rImport,
1222                                                 sal_uInt16 nPrefix,
1223 												const OUString& rLocalName,
1224 												OUString& rRangeString ) :
1225 		SvXMLImportContext( rImport, nPrefix, rLocalName ),
1226 		mrRangeString( rRangeString )
1227 {
1228 }
1229 
1230 SchXMLRangeSomewhereContext::~SchXMLRangeSomewhereContext()
1231 {
1232 }
1233 
1234 SvXMLImportContext* SchXMLRangeSomewhereContext::CreateChildContext(
1235     sal_uInt16 nPrefix,
1236     const OUString& rLocalName,
1237     const uno::Reference< xml::sax::XAttributeList >& )
1238 {
1239     if( XML_NAMESPACE_SVG == nPrefix && IsXMLToken( rLocalName, XML_DESC ) )
1240 	{
1241 		return new XMLStringBufferImportContext(
1242 			GetImport(), nPrefix, rLocalName, maRangeStringBuffer );
1243 	}
1244 	return new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1245 }
1246 
1247 void SchXMLRangeSomewhereContext::EndElement()
1248 {
1249     mrRangeString = maRangeStringBuffer.makeStringAndClear();
1250 }
1251