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_chart2.hxx" 30 31 #include "DataBrowserModel.hxx" 32 #include "DialogModel.hxx" 33 #include "ChartModelHelper.hxx" 34 #include "DiagramHelper.hxx" 35 #include "DataSeriesHelper.hxx" 36 #include "PropertyHelper.hxx" 37 #include "ControllerLockGuard.hxx" 38 #include "macros.hxx" 39 #include "StatisticsHelper.hxx" 40 #include "ContainerHelper.hxx" 41 #include "ChartTypeHelper.hxx" 42 #include "chartview/ExplicitValueProvider.hxx" 43 #include "ExplicitCategoriesProvider.hxx" 44 45 #include <com/sun/star/container/XIndexReplace.hpp> 46 #include <com/sun/star/chart2/XAxis.hpp> 47 #include <com/sun/star/chart2/XDataSeriesContainer.hpp> 48 #include <com/sun/star/chart2/XInternalDataProvider.hpp> 49 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> 50 #include <com/sun/star/chart2/XChartTypeContainer.hpp> 51 #include <com/sun/star/chart2/data/XDataSource.hpp> 52 #include <com/sun/star/chart2/data/XDataSink.hpp> 53 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp> 54 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp> 55 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp> 56 #include <com/sun/star/util/XModifiable.hpp> 57 58 #include <rtl/math.hxx> 59 60 #include <algorithm> 61 62 #if OSL_DEBUG_LEVEL > 1 63 #include <cstdio> 64 #endif 65 66 using namespace ::com::sun::star; 67 68 using ::com::sun::star::uno::Reference; 69 using ::com::sun::star::uno::Sequence; 70 using ::rtl::OUString; 71 72 namespace 73 { 74 OUString lcl_getRole( 75 const Reference< chart2::data::XDataSequence > & xSeq ) 76 { 77 OUString aResult; 78 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); 79 if( xProp.is()) 80 { 81 try 82 { 83 xProp->getPropertyValue( C2U("Role")) >>= aResult; 84 } 85 catch( const uno::Exception & ex ) 86 { 87 ASSERT_EXCEPTION( ex ); 88 } 89 } 90 return aResult; 91 } 92 93 94 OUString lcl_getRole( 95 const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) 96 { 97 OUString aResult; 98 if( xLSeq.is()) 99 aResult = lcl_getRole( xLSeq->getValues()); 100 return aResult; 101 } 102 103 OUString lcl_getUIRoleName( 104 const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) 105 { 106 OUString aResult( lcl_getRole( xLSeq )); 107 if( aResult.getLength()) 108 aResult = ::chart::DialogModel::ConvertRoleFromInternalToUI( aResult ); 109 return aResult; 110 } 111 112 void lcl_copyDataSequenceProperties( 113 const Reference< chart2::data::XDataSequence > & xOldSequence, 114 const Reference< chart2::data::XDataSequence > & xNewSequence ) 115 { 116 Reference< beans::XPropertySet > xOldSeqProp( xOldSequence, uno::UNO_QUERY ); 117 Reference< beans::XPropertySet > xNewSeqProp( xNewSequence, uno::UNO_QUERY ); 118 comphelper::copyProperties( xOldSeqProp, xNewSeqProp ); 119 } 120 121 bool lcl_SequenceOfSeriesIsShared( 122 const Reference< chart2::XDataSeries > & xSeries, 123 const Reference< chart2::data::XDataSequence > & xValues ) 124 { 125 bool bResult = false; 126 if( !xValues.is()) 127 return bResult; 128 try 129 { 130 OUString aValuesRole( lcl_getRole( xValues )); 131 OUString aValuesRep( xValues->getSourceRangeRepresentation()); 132 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY_THROW ); 133 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeq( xSource->getDataSequences()); 134 for( sal_Int32 i=0; i<aLSeq.getLength(); ++i ) 135 if( aLSeq[i].is() && 136 lcl_getRole( aLSeq[i] ).equals( aValuesRole )) 137 { 138 // getValues().is(), because lcl_getRole checked that already 139 bResult = (aValuesRep == aLSeq[i]->getValues()->getSourceRangeRepresentation()); 140 // assumption: a role appears only once in a series 141 break; 142 } 143 } 144 catch( const uno::Exception & ex ) 145 { 146 ASSERT_EXCEPTION( ex ); 147 } 148 return bResult; 149 } 150 151 typedef ::std::vector< Reference< chart2::data::XLabeledDataSequence > > lcl_tSharedSeqVec; 152 153 lcl_tSharedSeqVec lcl_getSharedSequences( const Sequence< Reference< chart2::XDataSeries > > & rSeries ) 154 { 155 // @todo: if only some series share a sequence, those have to be duplicated 156 // and made unshared for all series 157 lcl_tSharedSeqVec aResult; 158 // if we have only one series, we don't want any shared sequences 159 if( rSeries.getLength() <= 1 ) 160 return aResult; 161 162 Reference< chart2::data::XDataSource > xSource( rSeries[0], uno::UNO_QUERY ); 163 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeq( xSource->getDataSequences()); 164 for( sal_Int32 nIdx=0; nIdx<aLSeq.getLength(); ++nIdx ) 165 { 166 Reference< chart2::data::XDataSequence > xValues( aLSeq[nIdx]->getValues()); 167 bool bShared = true; 168 for( sal_Int32 nSeriesIdx=1; nSeriesIdx<rSeries.getLength(); ++nSeriesIdx ) 169 { 170 bShared = lcl_SequenceOfSeriesIsShared( rSeries[nSeriesIdx], xValues ); 171 if( !bShared ) 172 break; 173 } 174 if( bShared ) 175 aResult.push_back( aLSeq[nIdx] ); 176 } 177 178 return aResult; 179 } 180 181 sal_Int32 lcl_getValuesRepresentationIndex( 182 const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) 183 { 184 sal_Int32 nResult = -1; 185 if( xLSeq.is()) 186 { 187 Reference< chart2::data::XDataSequence > xSeq( xLSeq->getValues()); 188 if( xSeq.is()) 189 { 190 OUString aRep( xSeq->getSourceRangeRepresentation()); 191 nResult = aRep.toInt32(); 192 } 193 } 194 return nResult; 195 } 196 197 struct lcl_RepresentationsOfLSeqMatch : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool > 198 { 199 lcl_RepresentationsOfLSeqMatch( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) : 200 m_aValuesRep( xLSeq.is() ? 201 (xLSeq->getValues().is() ? xLSeq->getValues()->getSourceRangeRepresentation() : OUString()) 202 : OUString() ) 203 {} 204 bool operator() ( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) 205 { 206 return (xLSeq.is() && 207 xLSeq->getValues().is() && 208 (xLSeq->getValues()->getSourceRangeRepresentation() == m_aValuesRep )); 209 } 210 private: 211 OUString m_aValuesRep; 212 }; 213 214 struct lcl_RolesOfLSeqMatch : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool > 215 { 216 lcl_RolesOfLSeqMatch( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) : 217 m_aRole( lcl_getRole( xLSeq )) 218 {} 219 bool operator() ( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) 220 { 221 return lcl_getRole( xLSeq ).equals( m_aRole ); 222 } 223 private: 224 OUString m_aRole; 225 }; 226 227 bool lcl_ShowCategories( const Reference< chart2::XDiagram > & /* xDiagram */ ) 228 { 229 // show categories for all charts 230 return true; 231 // return DiagramHelper::isCategoryDiagram( xDiagram ); 232 } 233 234 bool lcl_ShowCategoriesAsDataLabel( const Reference< chart2::XDiagram > & xDiagram ) 235 { 236 return ! ::chart::DiagramHelper::isCategoryDiagram( xDiagram ); 237 } 238 239 } // anonymous namespace 240 241 namespace chart 242 { 243 244 245 struct DataBrowserModel::tDataColumn 246 { 247 ::com::sun::star::uno::Reference< 248 ::com::sun::star::chart2::XDataSeries > m_xDataSeries; 249 sal_Int32 m_nIndexInDataSeries; 250 ::rtl::OUString m_aUIRoleName; 251 ::com::sun::star::uno::Reference< 252 ::com::sun::star::chart2::data::XLabeledDataSequence > m_xLabeledDataSequence; 253 eCellType m_eCellType; 254 sal_Int32 m_nNumberFormatKey; 255 256 // default CTOR 257 tDataColumn() : m_nIndexInDataSeries( -1 ), m_eCellType( TEXT ), m_nNumberFormatKey( 0 ) {} 258 // "full" CTOR 259 tDataColumn( 260 const ::com::sun::star::uno::Reference< 261 ::com::sun::star::chart2::XDataSeries > & xDataSeries, 262 sal_Int32 nIndexInDataSeries, 263 ::rtl::OUString aUIRoleName, 264 ::com::sun::star::uno::Reference< 265 ::com::sun::star::chart2::data::XLabeledDataSequence > xLabeledDataSequence, 266 eCellType aCellType, 267 sal_Int32 nNumberFormatKey ) : 268 m_xDataSeries( xDataSeries ), 269 m_nIndexInDataSeries( nIndexInDataSeries ), 270 m_aUIRoleName( aUIRoleName ), 271 m_xLabeledDataSequence( xLabeledDataSequence ), 272 m_eCellType( aCellType ), 273 m_nNumberFormatKey( nNumberFormatKey ) 274 {} 275 }; 276 277 struct DataBrowserModel::implColumnLess : public ::std::binary_function< 278 DataBrowserModel::tDataColumn, DataBrowserModel::tDataColumn, bool > 279 { 280 bool operator() ( const first_argument_type & rLeft, const second_argument_type & rRight ) 281 { 282 if( rLeft.m_xLabeledDataSequence.is() && rRight.m_xLabeledDataSequence.is()) 283 { 284 return DialogModel::GetRoleIndexForSorting( lcl_getRole( rLeft.m_xLabeledDataSequence )) < 285 DialogModel::GetRoleIndexForSorting( lcl_getRole( rRight.m_xLabeledDataSequence )); 286 } 287 return true; 288 } 289 }; 290 291 DataBrowserModel::DataBrowserModel( 292 const Reference< chart2::XChartDocument > & xChartDoc, 293 const Reference< uno::XComponentContext > & xContext ) : 294 m_xChartDocument( xChartDoc ), 295 m_xContext( xContext ), 296 m_apDialogModel( new DialogModel( xChartDoc, xContext )) 297 { 298 updateFromModel(); 299 } 300 301 DataBrowserModel::~DataBrowserModel() 302 {} 303 304 namespace 305 { 306 struct lcl_DataSeriesOfHeaderMatches : public ::std::unary_function< ::chart::DataBrowserModel::tDataHeader, bool > 307 { 308 lcl_DataSeriesOfHeaderMatches( 309 const Reference< chart2::XDataSeries > & xSeriesToCompareWith ) : 310 m_xSeries( xSeriesToCompareWith ) 311 {} 312 bool operator() ( const ::chart::DataBrowserModel::tDataHeader & rHeader ) 313 { 314 return (m_xSeries == rHeader.m_xDataSeries); 315 } 316 private: 317 Reference< chart2::XDataSeries > m_xSeries; 318 }; 319 } 320 321 void DataBrowserModel::insertDataSeries( sal_Int32 nAfterColumnIndex ) 322 { 323 OSL_ASSERT( m_apDialogModel.get()); 324 Reference< chart2::XInternalDataProvider > xDataProvider( 325 m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 326 if( xDataProvider.is()) 327 { 328 if( isCategoriesColumn(nAfterColumnIndex) ) 329 nAfterColumnIndex = getCategoryColumnCount()-1; 330 331 sal_Int32 nStartCol = 0; 332 Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartDocument )); 333 Reference< chart2::XChartType > xChartType; 334 Reference< chart2::XDataSeries > xSeries; 335 if( static_cast< tDataColumnVector::size_type >( nAfterColumnIndex ) <= m_aColumns.size()) 336 xSeries.set( m_aColumns[nAfterColumnIndex].m_xDataSeries ); 337 338 sal_Int32 nSeriesNumberFormat = 0; 339 if( xSeries.is()) 340 { 341 xChartType.set( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries )); 342 tDataHeaderVector::const_iterator aIt( 343 ::std::find_if( m_aHeaders.begin(), m_aHeaders.end(), 344 lcl_DataSeriesOfHeaderMatches( xSeries ))); 345 if( aIt != m_aHeaders.end()) 346 nStartCol = aIt->m_nEndColumn; 347 348 Reference< beans::XPropertySet > xSeriesProps( xSeries, uno::UNO_QUERY ); 349 if( xSeriesProps.is() ) 350 xSeriesProps->getPropertyValue( C2U( "NumberFormat" )) >>= nSeriesNumberFormat; 351 } 352 else 353 { 354 xChartType.set( DiagramHelper::getChartTypeByIndex( xDiagram, 0 )); 355 nStartCol = nAfterColumnIndex; 356 } 357 358 if( xChartType.is()) 359 { 360 sal_Int32 nOffset = 0; 361 if( xDiagram.is() && lcl_ShowCategories( xDiagram )) 362 nOffset=getCategoryColumnCount(); 363 // get shared sequences of current series 364 Reference< chart2::XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY ); 365 lcl_tSharedSeqVec aSharedSequences; 366 if( xSeriesCnt.is()) 367 aSharedSequences = lcl_getSharedSequences( xSeriesCnt->getDataSeries()); 368 Reference< chart2::XDataSeries > xNewSeries( 369 m_apDialogModel->insertSeriesAfter( xSeries, xChartType, true /* bCreateDataCachedSequences */ )); 370 if( xNewSeries.is()) 371 { 372 { 373 Reference< chart2::data::XDataSource > xSource( xNewSeries, uno::UNO_QUERY ); 374 if( xSource.is()) 375 { 376 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences( 377 xSource->getDataSequences()); 378 sal_Int32 nSeqIdx = 0; 379 sal_Int32 nSeqSize = aLSequences.getLength(); 380 nStartCol -= (nOffset - 1); 381 for( sal_Int32 nIndex = nStartCol; 382 (nSeqIdx < nSeqSize); 383 ++nSeqIdx ) 384 { 385 lcl_tSharedSeqVec::const_iterator aSharedIt( 386 ::std::find_if( aSharedSequences.begin(), aSharedSequences.end(), 387 lcl_RolesOfLSeqMatch( aLSequences[nSeqIdx] ))); 388 if( aSharedIt != aSharedSequences.end()) 389 { 390 aLSequences[nSeqIdx]->setValues( (*aSharedIt)->getValues()); 391 aLSequences[nSeqIdx]->setLabel( (*aSharedIt)->getLabel()); 392 } 393 else 394 { 395 xDataProvider->insertSequence( nIndex - 1 ); 396 397 // values 398 Reference< chart2::data::XDataSequence > xNewSeq( 399 xDataProvider->createDataSequenceByRangeRepresentation( 400 OUString::valueOf( nIndex ))); 401 lcl_copyDataSequenceProperties( 402 aLSequences[nSeqIdx]->getValues(), xNewSeq ); 403 aLSequences[nSeqIdx]->setValues( xNewSeq ); 404 405 // labels 406 Reference< chart2::data::XDataSequence > xNewLabelSeq( 407 xDataProvider->createDataSequenceByRangeRepresentation( 408 OUString( RTL_CONSTASCII_USTRINGPARAM( "label " )) + 409 OUString::valueOf( nIndex ))); 410 lcl_copyDataSequenceProperties( 411 aLSequences[nSeqIdx]->getLabel(), xNewLabelSeq ); 412 aLSequences[nSeqIdx]->setLabel( xNewLabelSeq ); 413 ++nIndex; 414 } 415 } 416 } 417 } 418 if( nSeriesNumberFormat != 0 ) 419 { 420 //give the new series the same number format as the former series especially for bubble charts thus the bubble size values can be edited with same format immidiately 421 Reference< beans::XPropertySet > xNewSeriesProps( xNewSeries, uno::UNO_QUERY ); 422 if( xNewSeriesProps.is() ) 423 xNewSeriesProps->setPropertyValue( C2U( "NumberFormat" ), uno::makeAny( nSeriesNumberFormat ) ); 424 } 425 426 updateFromModel(); 427 } 428 } 429 } 430 } 431 432 void DataBrowserModel::insertComplexCategoryLevel( sal_Int32 nAfterColumnIndex ) 433 { 434 //create a new text column for complex categories 435 436 OSL_ASSERT( m_apDialogModel.get()); 437 Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 438 if( xDataProvider.is() ) 439 { 440 if( !isCategoriesColumn(nAfterColumnIndex) ) 441 nAfterColumnIndex = getCategoryColumnCount()-1; 442 443 if(nAfterColumnIndex<0) 444 { 445 OSL_ENSURE( false, "wrong index for category level insertion" ); 446 return; 447 } 448 449 m_apDialogModel->startControllerLockTimer(); 450 ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) ); 451 xDataProvider->insertComplexCategoryLevel( nAfterColumnIndex+1 ); 452 updateFromModel(); 453 } 454 } 455 456 void DataBrowserModel::removeDataSeriesOrComplexCategoryLevel( sal_Int32 nAtColumnIndex ) 457 { 458 OSL_ASSERT( m_apDialogModel.get()); 459 if( static_cast< tDataColumnVector::size_type >( nAtColumnIndex ) < m_aColumns.size()) 460 { 461 Reference< chart2::XDataSeries > xSeries( m_aColumns[nAtColumnIndex].m_xDataSeries ); 462 if( xSeries.is()) 463 { 464 m_apDialogModel->deleteSeries( 465 xSeries, getHeaderForSeries( xSeries ).m_xChartType ); 466 467 //delete sequences from internal data provider that are not used anymore 468 //but do not delete sequences that are still in use by the remaining series 469 Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 470 Reference< chart2::data::XDataSource > xSourceOfDeletedSeries( xSeries, uno::UNO_QUERY ); 471 if( xDataProvider.is() && xSourceOfDeletedSeries.is()) 472 { 473 ::std::vector< sal_Int32 > aSequenceIndexesToDelete; 474 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequencesOfDeletedSeries( xSourceOfDeletedSeries->getDataSequences() ); 475 Reference< chart2::XDataSeriesContainer > xSeriesCnt( getHeaderForSeries( xSeries ).m_xChartType, uno::UNO_QUERY ); 476 if( xSeriesCnt.is()) 477 { 478 Reference< chart2::data::XDataSource > xRemainingDataSource( DataSeriesHelper::getDataSource( xSeriesCnt->getDataSeries() ) ); 479 if( xRemainingDataSource.is() ) 480 { 481 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aRemainingSeq( ContainerHelper::SequenceToVector( xRemainingDataSource->getDataSequences() ) ); 482 for( sal_Int32 i=0; i<aSequencesOfDeletedSeries.getLength(); ++i ) 483 { 484 ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::const_iterator aHitIt( 485 ::std::find_if( aRemainingSeq.begin(), aRemainingSeq.end(), 486 lcl_RepresentationsOfLSeqMatch( aSequencesOfDeletedSeries[i] ))); 487 // if not used by the remaining series this sequence can be deleted 488 if( aHitIt == aRemainingSeq.end() ) 489 aSequenceIndexesToDelete.push_back( lcl_getValuesRepresentationIndex( aSequencesOfDeletedSeries[i] ) ); 490 } 491 } 492 } 493 494 // delete unnecessary sequences of the internal data 495 // iterate using greatest index first, so that deletion does not 496 // shift other sequences that will be deleted later 497 ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end()); 498 for( ::std::vector< sal_Int32 >::reverse_iterator aIt( 499 aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt ) 500 { 501 if( *aIt != -1 ) 502 xDataProvider->deleteSequence( *aIt ); 503 } 504 } 505 updateFromModel(); 506 } 507 else 508 { 509 //delete a category column if there is more than one level (in case of a single column we do not get here) 510 OSL_ENSURE(nAtColumnIndex>0, "wrong index for categories deletion" ); 511 512 Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 513 if( xDataProvider.is() ) 514 { 515 m_apDialogModel->startControllerLockTimer(); 516 ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) ); 517 xDataProvider->deleteComplexCategoryLevel( nAtColumnIndex ); 518 updateFromModel(); 519 } 520 } 521 } 522 } 523 524 void DataBrowserModel::swapDataSeries( sal_Int32 nFirstColumnIndex ) 525 { 526 OSL_ASSERT( m_apDialogModel.get()); 527 if( static_cast< tDataColumnVector::size_type >( nFirstColumnIndex ) < m_aColumns.size() - 1 ) 528 { 529 Reference< chart2::XDataSeries > xSeries( m_aColumns[nFirstColumnIndex].m_xDataSeries ); 530 if( xSeries.is()) 531 { 532 m_apDialogModel->moveSeries( xSeries, DialogModel::MOVE_DOWN ); 533 updateFromModel(); 534 } 535 } 536 } 537 538 void DataBrowserModel::swapDataPointForAllSeries( sal_Int32 nFirstIndex ) 539 { 540 OSL_ASSERT( m_apDialogModel.get()); 541 Reference< chart2::XInternalDataProvider > xDataProvider( 542 m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 543 // lockControllers 544 ControllerLockGuard aGuard( m_apDialogModel->getChartModel()); 545 if( xDataProvider.is()) 546 xDataProvider->swapDataPointWithNextOneForAllSequences( nFirstIndex ); 547 // unlockControllers 548 } 549 550 void DataBrowserModel::insertDataPointForAllSeries( sal_Int32 nAfterIndex ) 551 { 552 Reference< chart2::XInternalDataProvider > xDataProvider( 553 m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 554 // lockControllers 555 ControllerLockGuard aGuard( m_apDialogModel->getChartModel()); 556 if( xDataProvider.is()) 557 xDataProvider->insertDataPointForAllSequences( nAfterIndex ); 558 // unlockControllers 559 } 560 561 void DataBrowserModel::removeDataPointForAllSeries( sal_Int32 nAtIndex ) 562 { 563 Reference< chart2::XInternalDataProvider > xDataProvider( 564 m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); 565 // lockControllers 566 ControllerLockGuard aGuard( m_apDialogModel->getChartModel()); 567 if( xDataProvider.is()) 568 xDataProvider->deleteDataPointForAllSequences( nAtIndex ); 569 // unlockControllers 570 } 571 572 DataBrowserModel::tDataHeader DataBrowserModel::getHeaderForSeries( 573 const Reference< chart2::XDataSeries > & xSeries ) const 574 { 575 for( tDataHeaderVector::const_iterator aIt( m_aHeaders.begin()); 576 aIt != m_aHeaders.end(); ++aIt ) 577 { 578 if( aIt->m_xDataSeries == xSeries ) 579 return (*aIt); 580 } 581 return tDataHeader(); 582 } 583 584 Reference< chart2::XDataSeries > 585 DataBrowserModel::getDataSeriesByColumn( sal_Int32 nColumn ) const 586 { 587 tDataColumnVector::size_type nIndex( nColumn ); 588 if( nIndex < m_aColumns.size()) 589 return m_aColumns[nIndex].m_xDataSeries; 590 return 0; 591 } 592 593 DataBrowserModel::eCellType DataBrowserModel::getCellType( sal_Int32 nAtColumn, sal_Int32 /* nAtRow */ ) const 594 { 595 eCellType eResult = TEXT; 596 tDataColumnVector::size_type nIndex( nAtColumn ); 597 if( nIndex < m_aColumns.size()) 598 eResult = m_aColumns[nIndex].m_eCellType; 599 return eResult; 600 } 601 602 double DataBrowserModel::getCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow ) 603 { 604 double fResult; 605 ::rtl::math::setNan( & fResult ); 606 607 tDataColumnVector::size_type nIndex( nAtColumn ); 608 if( nIndex < m_aColumns.size() && 609 m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) 610 { 611 Reference< chart2::data::XNumericalDataSequence > xData( 612 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY ); 613 if( xData.is()) 614 { 615 Sequence< double > aValues( xData->getNumericalData()); 616 if( nAtRow < aValues.getLength()) 617 fResult = aValues[nAtRow]; 618 } 619 } 620 return fResult; 621 } 622 623 uno::Any DataBrowserModel::getCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow ) 624 { 625 uno::Any aResult; 626 627 tDataColumnVector::size_type nIndex( nAtColumn ); 628 if( nIndex < m_aColumns.size() && 629 m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) 630 { 631 Reference< chart2::data::XDataSequence > xData( 632 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues() ); 633 if( xData.is() ) 634 { 635 Sequence< uno::Any > aValues( xData->getData()); 636 if( nAtRow < aValues.getLength()) 637 aResult = aValues[nAtRow]; 638 } 639 } 640 return aResult; 641 } 642 643 OUString DataBrowserModel::getCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow ) 644 { 645 OUString aResult; 646 647 tDataColumnVector::size_type nIndex( nAtColumn ); 648 if( nIndex < m_aColumns.size() && 649 m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) 650 { 651 Reference< chart2::data::XTextualDataSequence > xData( 652 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY ); 653 if( xData.is()) 654 { 655 Sequence< OUString > aValues( xData->getTextualData()); 656 if( nAtRow < aValues.getLength()) 657 aResult = aValues[nAtRow]; 658 } 659 } 660 return aResult; 661 } 662 663 sal_uInt32 DataBrowserModel::getNumberFormatKey( sal_Int32 nAtColumn, sal_Int32 /* nAtRow */ ) 664 { 665 tDataColumnVector::size_type nIndex( nAtColumn ); 666 if( nIndex < m_aColumns.size()) 667 return m_aColumns[ nIndex ].m_nNumberFormatKey; 668 return 0; 669 } 670 671 bool DataBrowserModel::setCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow, const uno::Any & rValue ) 672 { 673 bool bResult = false; 674 tDataColumnVector::size_type nIndex( nAtColumn ); 675 if( nIndex < m_aColumns.size() && 676 m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) 677 { 678 bResult = true; 679 try 680 { 681 ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) ); 682 683 // label 684 if( nAtRow == -1 ) 685 { 686 Reference< container::XIndexReplace > xIndexReplace( 687 m_aColumns[ nIndex ].m_xLabeledDataSequence->getLabel(), uno::UNO_QUERY_THROW ); 688 xIndexReplace->replaceByIndex( 0, rValue ); 689 } 690 else 691 { 692 Reference< container::XIndexReplace > xIndexReplace( 693 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY_THROW ); 694 xIndexReplace->replaceByIndex( nAtRow, rValue ); 695 } 696 697 m_apDialogModel->startControllerLockTimer(); 698 //notify change directly to the model (this is necessary here as sequences for complex categories not known directly to the chart model so they do not notify their changes) (for complex categories see issue #i82971#) 699 Reference< util::XModifiable > xModifiable( m_xChartDocument, uno::UNO_QUERY ); 700 if( xModifiable.is() ) 701 xModifiable->setModified(true); 702 } 703 catch( const uno::Exception & ex ) 704 { 705 (void)(ex); 706 bResult = false; 707 } 708 } 709 return bResult; 710 } 711 712 bool DataBrowserModel::setCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow, double fValue ) 713 { 714 return (getCellType( nAtColumn, nAtRow ) == NUMBER) && 715 setCellAny( nAtColumn, nAtRow, uno::makeAny( fValue )); 716 } 717 718 bool DataBrowserModel::setCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow, const ::rtl::OUString & rText ) 719 { 720 return (getCellType( nAtColumn, nAtRow ) == TEXT) && 721 setCellAny( nAtColumn, nAtRow, uno::makeAny( rText )); 722 } 723 724 sal_Int32 DataBrowserModel::getColumnCount() const 725 { 726 return static_cast< sal_Int32 >( m_aColumns.size()); 727 } 728 729 sal_Int32 DataBrowserModel::getMaxRowCount() const 730 { 731 sal_Int32 nResult = 0; 732 tDataColumnVector::const_iterator aIt( m_aColumns.begin()); 733 for( ; aIt != m_aColumns.end(); ++aIt ) 734 { 735 if( aIt->m_xLabeledDataSequence.is()) 736 { 737 Reference< chart2::data::XDataSequence > xSeq( 738 aIt->m_xLabeledDataSequence->getValues()); 739 if( !xSeq.is()) 740 continue; 741 sal_Int32 nLength( xSeq->getData().getLength()); 742 if( nLength > nResult ) 743 nResult = nLength; 744 } 745 } 746 747 return nResult; 748 } 749 750 OUString DataBrowserModel::getRoleOfColumn( sal_Int32 nColumnIndex ) const 751 { 752 if( nColumnIndex != -1 && 753 static_cast< sal_uInt32 >( nColumnIndex ) < m_aColumns.size()) 754 return m_aColumns[ nColumnIndex ].m_aUIRoleName; 755 return OUString(); 756 } 757 758 bool DataBrowserModel::isCategoriesColumn( sal_Int32 nColumnIndex ) const 759 { 760 bool bIsCategories = false; 761 if( nColumnIndex>=0 && nColumnIndex<static_cast< sal_Int32 >(m_aColumns.size()) ) 762 bIsCategories = !m_aColumns[ nColumnIndex ].m_xDataSeries.is(); 763 return bIsCategories; 764 } 765 766 sal_Int32 DataBrowserModel::getCategoryColumnCount() 767 { 768 sal_Int32 nLastTextColumnIndex = -1; 769 tDataColumnVector::const_iterator aIt = m_aColumns.begin(); 770 for( ; aIt != m_aColumns.end(); ++aIt ) 771 { 772 if( !aIt->m_xDataSeries.is() ) 773 nLastTextColumnIndex++; 774 else 775 break; 776 } 777 return nLastTextColumnIndex+1; 778 } 779 780 const DataBrowserModel::tDataHeaderVector& DataBrowserModel::getDataHeaders() const 781 { 782 return m_aHeaders; 783 } 784 785 void DataBrowserModel::updateFromModel() 786 { 787 if( !m_xChartDocument.is()) 788 return; 789 m_aColumns.clear(); 790 m_aHeaders.clear(); 791 792 Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartDocument )); 793 if( !xDiagram.is()) 794 return; 795 796 // set template at DialogModel 797 uno::Reference< lang::XMultiServiceFactory > xFact( m_xChartDocument->getChartTypeManager(), uno::UNO_QUERY ); 798 DiagramHelper::tTemplateWithServiceName aTemplateAndService = 799 DiagramHelper::getTemplateForDiagram( xDiagram, xFact ); 800 if( aTemplateAndService.first.is()) 801 m_apDialogModel->setTemplate( aTemplateAndService.first ); 802 803 sal_Int32 nHeaderStart = 0; 804 sal_Int32 nHeaderEnd = 0; 805 if( lcl_ShowCategories( xDiagram )) 806 { 807 Reference< frame::XModel > xChartModel( m_xChartDocument, uno::UNO_QUERY ); 808 ExplicitCategoriesProvider aExplicitCategoriesProvider( ChartModelHelper::getFirstCoordinateSystem(xChartModel), xChartModel ); 809 810 const Sequence< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList( aExplicitCategoriesProvider.getSplitCategoriesList() ); 811 sal_Int32 nLevelCount = rSplitCategoriesList.getLength(); 812 for( sal_Int32 nL = 0; nL<nLevelCount; nL++ ) 813 { 814 Reference< chart2::data::XLabeledDataSequence > xCategories( rSplitCategoriesList[nL] ); 815 if( !xCategories.is() ) 816 continue; 817 818 tDataColumn aCategories; 819 aCategories.m_xLabeledDataSequence.set( xCategories ); 820 if( lcl_ShowCategoriesAsDataLabel( xDiagram )) 821 aCategories.m_aUIRoleName = DialogModel::GetRoleDataLabel(); 822 else 823 aCategories.m_aUIRoleName = lcl_getUIRoleName( xCategories ); 824 aCategories.m_eCellType = TEXTORDATE; 825 m_aColumns.push_back( aCategories ); 826 ++nHeaderStart; 827 } 828 } 829 830 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY ); 831 if( !xCooSysCnt.is()) 832 return; 833 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); 834 for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx ) 835 { 836 Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW ); 837 Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); 838 sal_Int32 nXAxisNumberFormat = DataSeriesHelper::getNumberFormatKeyFromAxis( 0, aCooSysSeq[nCooSysIdx], 0, 0 ); 839 840 for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx ) 841 { 842 Reference< chart2::XDataSeriesContainer > xSeriesCnt( aChartTypes[nCTIdx], uno::UNO_QUERY ); 843 if( xSeriesCnt.is()) 844 { 845 rtl::OUString aRoleForDataLabelNumberFormat = ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( aChartTypes[nCTIdx] ); 846 847 Sequence< Reference< chart2::XDataSeries > > aSeries( xSeriesCnt->getDataSeries()); 848 lcl_tSharedSeqVec aSharedSequences( lcl_getSharedSequences( aSeries )); 849 for( lcl_tSharedSeqVec::const_iterator aIt( aSharedSequences.begin()); 850 aIt != aSharedSequences.end(); ++aIt ) 851 { 852 tDataColumn aSharedSequence; 853 aSharedSequence.m_xLabeledDataSequence = *aIt; 854 aSharedSequence.m_aUIRoleName = lcl_getUIRoleName( *aIt ); 855 aSharedSequence.m_eCellType = NUMBER; 856 // as the sequences are shared it should be ok to take the first series 857 // @todo: dimension index 0 for x-values used here. This is just a guess. 858 // Also, the axis index is 0, as there is usually only one x-axis 859 aSharedSequence.m_nNumberFormatKey = nXAxisNumberFormat; 860 m_aColumns.push_back( aSharedSequence ); 861 ++nHeaderStart; 862 } 863 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx ) 864 { 865 tDataColumnVector::size_type nStartColIndex = m_aColumns.size(); 866 Reference< chart2::XDataSeries > xSeries( aSeries[nSeriesIdx] ); 867 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); 868 if( xSource.is()) 869 { 870 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeqs( xSource->getDataSequences()); 871 if( aLSeqs.getLength() == 0 ) 872 continue; 873 nHeaderEnd = nHeaderStart; 874 875 // @todo: dimension index 1 for y-values used here. This is just a guess 876 sal_Int32 nYAxisNumberFormatKey = 877 DataSeriesHelper::getNumberFormatKeyFromAxis( 878 aSeries[nSeriesIdx], aCooSysSeq[nCooSysIdx], 1 ); 879 880 sal_Int32 nSeqIdx=0; 881 for( ; nSeqIdx<aLSeqs.getLength(); ++nSeqIdx ) 882 { 883 sal_Int32 nSequenceNumberFormatKey = nYAxisNumberFormatKey; 884 OUString aRole = lcl_getRole( aLSeqs[nSeqIdx] ); 885 886 if( aRole.equals( aRoleForDataLabelNumberFormat ) ) 887 { 888 nSequenceNumberFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( 889 Reference< beans::XPropertySet >( xSeries, uno::UNO_QUERY ), xSeries, -1, xDiagram ); 890 } 891 else if( aRole.equals( C2U( "values-x" ) ) ) 892 nSequenceNumberFormatKey = nXAxisNumberFormat; 893 894 if( ::std::find_if( aSharedSequences.begin(), aSharedSequences.end(), 895 lcl_RepresentationsOfLSeqMatch( aLSeqs[nSeqIdx] )) == aSharedSequences.end()) 896 { 897 // no shared sequence 898 m_aColumns.push_back( 899 tDataColumn( 900 aSeries[nSeriesIdx], 901 nSeqIdx, 902 lcl_getUIRoleName( aLSeqs[nSeqIdx] ), 903 aLSeqs[nSeqIdx], 904 NUMBER, 905 nSequenceNumberFormatKey )); 906 ++nHeaderEnd; 907 } 908 // else skip 909 } 910 bool bSwapXAndYAxis = false; 911 try 912 { 913 Reference< beans::XPropertySet > xProp( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY ); 914 xProp->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("SwapXAndYAxis"))) >>= bSwapXAndYAxis; 915 } 916 catch( const beans::UnknownPropertyException & ex ) 917 { 918 (void)ex; 919 } 920 921 // add ranges for error bars if present for a series 922 if( StatisticsHelper::usesErrorBarRanges( aSeries[nSeriesIdx], /* bYError = */ true )) 923 addErrorBarRanges( aSeries[nSeriesIdx], nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd ); 924 925 m_aHeaders.push_back( 926 tDataHeader( 927 aSeries[nSeriesIdx], 928 aChartTypes[nCTIdx], 929 bSwapXAndYAxis, 930 nHeaderStart, 931 nHeaderEnd - 1 )); 932 933 nHeaderStart = nHeaderEnd; 934 935 ::std::sort( m_aColumns.begin() + nStartColIndex, m_aColumns.end(), implColumnLess() ); 936 } 937 } 938 } 939 } 940 } 941 } 942 943 void DataBrowserModel::addErrorBarRanges( 944 const Reference< chart2::XDataSeries > & xDataSeries, 945 sal_Int32 nNumberFormatKey, 946 sal_Int32 & rInOutSequenceIndex, 947 sal_Int32 & rInOutHeaderEnd ) 948 { 949 try 950 { 951 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSequences; 952 953 // x error bars 954 // ------------ 955 Reference< chart2::data::XDataSource > xErrorSource( 956 StatisticsHelper::getErrorBars( xDataSeries, /* bYError = */ false ), uno::UNO_QUERY ); 957 958 // positive x error bars 959 Reference< chart2::data::XLabeledDataSequence > xErrorLSequence( 960 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( 961 xErrorSource, 962 /* bPositiveValue = */ true, 963 /* bYError = */ false )); 964 if( xErrorLSequence.is()) 965 aSequences.push_back( xErrorLSequence ); 966 967 // negative x error bars 968 xErrorLSequence.set( 969 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( 970 xErrorSource, 971 /* bPositiveValue = */ false, 972 /* bYError = */ false )); 973 if( xErrorLSequence.is()) 974 aSequences.push_back( xErrorLSequence ); 975 976 // y error bars 977 // ------------ 978 xErrorSource.set( 979 StatisticsHelper::getErrorBars( xDataSeries, /* bYError = */ true ), uno::UNO_QUERY ); 980 981 // positive y error bars 982 xErrorLSequence.set( 983 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( 984 xErrorSource, 985 /* bPositiveValue = */ true, 986 /* bYError = */ true )); 987 if( xErrorLSequence.is()) 988 aSequences.push_back( xErrorLSequence ); 989 990 // negative y error bars 991 xErrorLSequence.set( 992 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( 993 xErrorSource, 994 /* bPositiveValue = */ false, 995 /* bYError = */ true )); 996 if( xErrorLSequence.is()) 997 aSequences.push_back( xErrorLSequence ); 998 999 1000 for( ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::const_iterator aIt( aSequences.begin()); 1001 aIt != aSequences.end(); ++aIt ) 1002 { 1003 m_aColumns.push_back( 1004 tDataColumn( 1005 xDataSeries, 1006 rInOutSequenceIndex, 1007 lcl_getUIRoleName( *aIt ), 1008 *aIt, 1009 NUMBER, 1010 nNumberFormatKey )); 1011 ++rInOutSequenceIndex; 1012 ++rInOutHeaderEnd; 1013 } 1014 } 1015 catch( const uno::Exception & ex ) 1016 { 1017 ASSERT_EXCEPTION( ex ); 1018 } 1019 } 1020 1021 } // namespace chart 1022