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__anonb105b5900111::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 ()__anonb105b5900111::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__anonb105b5900111::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