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