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