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