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