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 "RangeHighlighter.hxx" 32 #include "WeakListenerAdapter.hxx" 33 #include "ChartModelHelper.hxx" 34 #include "DataSourceHelper.hxx" 35 #include "ContainerHelper.hxx" 36 #include "macros.hxx" 37 #include "ObjectIdentifier.hxx" 38 #include "DataSeriesHelper.hxx" 39 40 #include <com/sun/star/chart2/XDataSeries.hpp> 41 #include <com/sun/star/chart/ErrorBarStyle.hpp> 42 #include <com/sun/star/drawing/XShape.hpp> 43 44 #define PREFERED_DEFAULT_COLOR 0x0000ff 45 46 using namespace ::com::sun::star; 47 48 using ::com::sun::star::uno::Reference; 49 using ::com::sun::star::uno::Sequence; 50 using ::rtl::OUString; 51 52 namespace 53 { 54 55 void lcl_fillRanges( 56 Sequence< chart2::data::HighlightedRange > & rOutRanges, 57 Sequence< OUString > aRangeStrings, 58 sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR, 59 sal_Int32 nIndex = -1 ) 60 { 61 rOutRanges.realloc( aRangeStrings.getLength()); 62 for( sal_Int32 i=0; i<aRangeStrings.getLength(); ++i ) 63 { 64 rOutRanges[i].RangeRepresentation = aRangeStrings[i]; 65 rOutRanges[i].PreferredColor = nPreferredColor; 66 rOutRanges[i].AllowMerginigWithOtherRanges = sal_False; 67 rOutRanges[i].Index = nIndex; 68 } 69 } 70 71 } // anonymous namespace 72 73 namespace chart 74 { 75 76 RangeHighlighter::RangeHighlighter( 77 const Reference< view::XSelectionSupplier > & xSelectionSupplier ) : 78 impl::RangeHighlighter_Base( m_aMutex ), 79 m_xSelectionSupplier( xSelectionSupplier ), 80 m_nAddedListenerCount( 0 ), 81 m_bIncludeHiddenCells(true) 82 { 83 } 84 85 RangeHighlighter::~RangeHighlighter() 86 {} 87 88 // ____ XRangeHighlighter ____ 89 Sequence< chart2::data::HighlightedRange > SAL_CALL RangeHighlighter::getSelectedRanges() 90 throw (uno::RuntimeException) 91 { 92 return m_aSelectedRanges; 93 } 94 95 void RangeHighlighter::determineRanges() 96 { 97 m_aSelectedRanges.realloc( 0 ); 98 if( m_xSelectionSupplier.is()) 99 { 100 try 101 { 102 Reference< frame::XController > xController( m_xSelectionSupplier, uno::UNO_QUERY ); 103 Reference< frame::XModel > xChartModel; 104 if( xController.is()) 105 xChartModel.set( xController->getModel()); 106 107 m_bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( xChartModel ); 108 109 uno::Any aSelection( m_xSelectionSupplier->getSelection()); 110 const uno::Type& rType = aSelection.getValueType(); 111 112 if ( rType == ::getCppuType( static_cast< const OUString* >( 0 ) ) ) 113 { 114 // @todo??: maybe getSelection() should return a model object rather than a CID 115 116 OUString aCID; 117 aSelection >>= aCID; 118 if ( aCID.getLength() > 0 ) 119 { 120 ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); 121 sal_Int32 nIndex = ObjectIdentifier::getIndexFromParticleOrCID( aCID ); 122 Reference< chart2::XDataSeries > xDataSeries( ObjectIdentifier::getDataSeriesForCID( aCID, xChartModel ) ); 123 if( OBJECTTYPE_LEGEND_ENTRY == eObjectType ) 124 { 125 OUString aParentParticel( ObjectIdentifier::getFullParentParticle( aCID ) ); 126 ObjectType eParentObjectType = ObjectIdentifier::getObjectType( aParentParticel ); 127 eObjectType = eParentObjectType; 128 if( OBJECTTYPE_DATA_POINT == eObjectType ) 129 nIndex = ObjectIdentifier::getIndexFromParticleOrCID( aParentParticel ); 130 } 131 132 if( OBJECTTYPE_DATA_POINT == eObjectType || OBJECTTYPE_DATA_LABEL == eObjectType ) 133 { 134 // Data Point 135 fillRangesForDataPoint( xDataSeries, nIndex ); 136 return; 137 } 138 else if( OBJECTTYPE_DATA_ERRORS == eObjectType ) 139 { 140 // select error bar ranges, or data series, if the style is 141 // not set to FROM_DATA 142 fillRangesForErrorBars( ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ), xDataSeries ); 143 return; 144 } 145 else if( xDataSeries.is() ) 146 { 147 // Data Series 148 fillRangesForDataSeries( xDataSeries ); 149 return; 150 } 151 else if( OBJECTTYPE_AXIS == eObjectType ) 152 { 153 // Axis (Categories) 154 Reference< chart2::XAxis > xAxis( ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ), uno::UNO_QUERY ); 155 if( xAxis.is()) 156 { 157 fillRangesForCategories( xAxis ); 158 return; 159 } 160 } 161 else if( OBJECTTYPE_PAGE == eObjectType 162 || OBJECTTYPE_DIAGRAM == eObjectType 163 || OBJECTTYPE_DIAGRAM_WALL == eObjectType 164 || OBJECTTYPE_DIAGRAM_FLOOR == eObjectType 165 ) 166 { 167 // Diagram 168 Reference< chart2::XDiagram > xDia( ObjectIdentifier::getDiagramForCID( aCID, xChartModel ) ); 169 if( xDia.is()) 170 { 171 fillRangesForDiagram( xDia ); 172 return; 173 } 174 } 175 } 176 } 177 else if ( rType == ::getCppuType( static_cast< const Reference< drawing::XShape >* >( 0 ) ) ) 178 { 179 // #i12587# support for shapes in chart 180 Reference< drawing::XShape > xShape; 181 aSelection >>= xShape; 182 if ( xShape.is() ) 183 { 184 return; 185 } 186 } 187 else 188 { 189 //if nothing is selected select all ranges 190 Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY_THROW ); 191 fillRangesForDiagram( xChartDoc->getFirstDiagram() ); 192 return; 193 } 194 } 195 catch( const uno::Exception & ex ) 196 { 197 ASSERT_EXCEPTION( ex ); 198 } 199 } 200 } 201 202 void RangeHighlighter::fillRangesForDiagram( const Reference< chart2::XDiagram > & xDiagram ) 203 { 204 Sequence< OUString > aSelectedRanges( DataSourceHelper::getUsedDataRanges( xDiagram )); 205 m_aSelectedRanges.realloc( aSelectedRanges.getLength()); 206 // @todo: merge ranges 207 for( sal_Int32 i=0; i<aSelectedRanges.getLength(); ++i ) 208 { 209 m_aSelectedRanges[i].RangeRepresentation = aSelectedRanges[i]; 210 m_aSelectedRanges[i].Index = -1; 211 m_aSelectedRanges[i].PreferredColor = PREFERED_DEFAULT_COLOR; 212 m_aSelectedRanges[i].AllowMerginigWithOtherRanges = sal_True; 213 } 214 } 215 216 void RangeHighlighter::fillRangesForDataSeries( const uno::Reference< chart2::XDataSeries > & xSeries ) 217 { 218 sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR; 219 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); 220 if( xSource.is()) 221 lcl_fillRanges( m_aSelectedRanges, 222 ::chart::DataSourceHelper::getRangesFromDataSource( xSource ), 223 nPreferredColor ); 224 } 225 226 void RangeHighlighter::fillRangesForErrorBars( 227 const uno::Reference< beans::XPropertySet > & xErrorBar, 228 const uno::Reference< chart2::XDataSeries > & xSeries ) 229 { 230 // only show error bar ranges, if the style is set to FROM_DATA 231 bool bUsesRangesAsErrorBars = false; 232 try 233 { 234 sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; 235 bUsesRangesAsErrorBars = 236 ( xErrorBar.is() && 237 (xErrorBar->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle) && 238 nStyle == ::com::sun::star::chart::ErrorBarStyle::FROM_DATA ); 239 } 240 catch( const uno::Exception & ex ) 241 { 242 ASSERT_EXCEPTION( ex ); 243 } 244 245 if( bUsesRangesAsErrorBars ) 246 { 247 sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR; 248 Reference< chart2::data::XDataSource > xSource( xErrorBar, uno::UNO_QUERY ); 249 if( xSource.is()) 250 lcl_fillRanges( m_aSelectedRanges, 251 ::chart::DataSourceHelper::getRangesFromDataSource( xSource ), 252 nPreferredColor ); 253 } 254 else 255 { 256 fillRangesForDataSeries( xSeries ); 257 } 258 } 259 260 void RangeHighlighter::fillRangesForCategories( const Reference< chart2::XAxis > & xAxis ) 261 { 262 if( ! xAxis.is()) 263 return; 264 chart2::ScaleData aData( xAxis->getScaleData()); 265 lcl_fillRanges( m_aSelectedRanges, 266 DataSourceHelper::getRangesFromLabeledDataSequence( aData.Categories )); 267 } 268 269 void RangeHighlighter::fillRangesForDataPoint( const Reference< uno::XInterface > & xDataSeries, sal_Int32 nIndex ) 270 { 271 sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR; 272 if( xDataSeries.is()) 273 { 274 Reference< chart2::data::XDataSource > xSource( xDataSeries, uno::UNO_QUERY ); 275 if( xSource.is() ) 276 { 277 ::std::vector< chart2::data::HighlightedRange > aHilightedRanges; 278 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeqSeq( xSource->getDataSequences()); 279 for( sal_Int32 i=0; i<aLSeqSeq.getLength(); ++i ) 280 { 281 Reference< chart2::data::XDataSequence > xLabel( aLSeqSeq[i]->getLabel()); 282 Reference< chart2::data::XDataSequence > xValues( aLSeqSeq[i]->getValues()); 283 284 if( xLabel.is()) 285 aHilightedRanges.push_back( 286 chart2::data::HighlightedRange( 287 xLabel->getSourceRangeRepresentation(), 288 -1, 289 nPreferredColor, 290 sal_False )); 291 292 sal_Int32 nUnhiddenIndex = DataSeriesHelper::translateIndexFromHiddenToFullSequence( nIndex, xValues, !m_bIncludeHiddenCells ); 293 if( xValues.is()) 294 aHilightedRanges.push_back( 295 chart2::data::HighlightedRange( 296 xValues->getSourceRangeRepresentation(), 297 nUnhiddenIndex, 298 nPreferredColor, 299 sal_False )); 300 } 301 m_aSelectedRanges = ContainerHelper::ContainerToSequence( aHilightedRanges ); 302 } 303 } 304 } 305 306 void SAL_CALL RangeHighlighter::addSelectionChangeListener( const Reference< view::XSelectionChangeListener >& xListener ) 307 throw (uno::RuntimeException) 308 { 309 if(!xListener.is()) 310 return; 311 312 if( m_nAddedListenerCount == 0 ) 313 startListening(); 314 rBHelper.addListener( ::getCppuType( & xListener ), xListener); 315 ++m_nAddedListenerCount; 316 317 //bring the new listener up to the current state 318 lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) ); 319 xListener->selectionChanged( aEvent ); 320 } 321 322 void SAL_CALL RangeHighlighter::removeSelectionChangeListener( const Reference< view::XSelectionChangeListener >& xListener ) 323 throw (uno::RuntimeException) 324 { 325 rBHelper.removeListener( ::getCppuType( & xListener ), xListener ); 326 --m_nAddedListenerCount; 327 if( m_nAddedListenerCount == 0 ) 328 stopListening(); 329 } 330 331 // ____ XSelectionChangeListener ____ 332 void SAL_CALL RangeHighlighter::selectionChanged( const lang::EventObject& /*aEvent*/ ) 333 throw (uno::RuntimeException) 334 { 335 determineRanges(); 336 337 // determine ranges of selected view objects 338 // if changed, fire an event 339 fireSelectionEvent(); 340 } 341 342 void RangeHighlighter::fireSelectionEvent() 343 { 344 ::cppu::OInterfaceContainerHelper* pIC = rBHelper.getContainer( 345 ::getCppuType((const uno::Reference< view::XSelectionChangeListener >*)0) ); 346 if( pIC ) 347 { 348 lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) ); 349 ::cppu::OInterfaceIteratorHelper aIt( *pIC ); 350 while( aIt.hasMoreElements() ) 351 { 352 uno::Reference< view::XSelectionChangeListener > xListener( aIt.next(), uno::UNO_QUERY ); 353 if( xListener.is() ) 354 xListener->selectionChanged( aEvent ); 355 } 356 } 357 } 358 359 void SAL_CALL RangeHighlighter::disposing( const lang::EventObject& Source ) 360 throw (uno::RuntimeException) 361 { 362 if( Source.Source == m_xSelectionSupplier ) 363 { 364 m_xSelectionSupplier.clear(); 365 m_aSelectedRanges.realloc( 0 ); 366 fireSelectionEvent(); 367 } 368 } 369 370 void RangeHighlighter::startListening() 371 { 372 if( m_xSelectionSupplier.is()) 373 { 374 if( ! m_xListener.is()) 375 { 376 m_xListener.set( new WeakSelectionChangeListenerAdapter( this )); 377 determineRanges(); 378 } 379 m_xSelectionSupplier->addSelectionChangeListener( m_xListener ); 380 } 381 } 382 383 void RangeHighlighter::stopListening() 384 { 385 if( m_xSelectionSupplier.is() && m_xListener.is()) 386 { 387 m_xSelectionSupplier->removeSelectionChangeListener( m_xListener ); 388 m_xListener.clear(); 389 } 390 } 391 392 393 // ____ WeakComponentImplHelperBase ____ 394 // is called when dispose() is called at this component 395 void SAL_CALL RangeHighlighter::disposing() 396 { 397 // @todo: remove listener. Currently the controller shows an assertion 398 // because it is already disposed 399 // stopListening(); 400 m_xListener.clear(); 401 m_xSelectionSupplier.clear(); 402 m_nAddedListenerCount = 0; 403 m_aSelectedRanges.realloc( 0 ); 404 } 405 406 } // namespace chart 407