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