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