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 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 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 { 141 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 149 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 161 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 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 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 > 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 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 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 > 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 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 321 SchXMLTableContext::~SchXMLTableContext() 322 { 323 } 324 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 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 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 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 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 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 518 SchXMLTableColumnsContext::~SchXMLTableColumnsContext() 519 { 520 } 521 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 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 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 600 SchXMLTableColumnContext::~SchXMLTableColumnContext() 601 { 602 } 603 604 // ======================================== 605 // classes for rows 606 // ======================================== 607 608 // ---------------------------------------- 609 // class SchXMLTableRowsContext 610 // ---------------------------------------- 611 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 623 SchXMLTableRowsContext::~SchXMLTableRowsContext() 624 { 625 } 626 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 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 669 SchXMLTableRowContext::~SchXMLTableRowContext() 670 { 671 } 672 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 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 744 SchXMLTableCellContext::~SchXMLTableCellContext() 745 { 746 } 747 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 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 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 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 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 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 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 1226 SchXMLRangeSomewhereContext::~SchXMLRangeSomewhereContext() 1227 { 1228 } 1229 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 1243 void SchXMLRangeSomewhereContext::EndElement() 1244 { 1245 mrRangeString = maRangeStringBuffer.makeStringAndClear(); 1246 } 1247