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