| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_chart2.hxx" |
| |
| #include "RangeHighlighter.hxx" |
| #include "WeakListenerAdapter.hxx" |
| #include "ChartModelHelper.hxx" |
| #include "DataSourceHelper.hxx" |
| #include "ContainerHelper.hxx" |
| #include "macros.hxx" |
| #include "ObjectIdentifier.hxx" |
| #include "DataSeriesHelper.hxx" |
| |
| #include <com/sun/star/chart2/XDataSeries.hpp> |
| #include <com/sun/star/chart/ErrorBarStyle.hpp> |
| #include <com/sun/star/drawing/XShape.hpp> |
| |
| #define PREFERED_DEFAULT_COLOR 0x0000ff |
| |
| using namespace ::com::sun::star; |
| |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::uno::Sequence; |
| using ::rtl::OUString; |
| |
| namespace |
| { |
| |
| void lcl_fillRanges( |
| Sequence< chart2::data::HighlightedRange > & rOutRanges, |
| Sequence< OUString > aRangeStrings, |
| sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR, |
| sal_Int32 nIndex = -1 ) |
| { |
| rOutRanges.realloc( aRangeStrings.getLength()); |
| for( sal_Int32 i=0; i<aRangeStrings.getLength(); ++i ) |
| { |
| rOutRanges[i].RangeRepresentation = aRangeStrings[i]; |
| rOutRanges[i].PreferredColor = nPreferredColor; |
| rOutRanges[i].AllowMerginigWithOtherRanges = sal_False; |
| rOutRanges[i].Index = nIndex; |
| } |
| } |
| |
| } // anonymous namespace |
| |
| namespace chart |
| { |
| |
| RangeHighlighter::RangeHighlighter( |
| const Reference< view::XSelectionSupplier > & xSelectionSupplier ) : |
| impl::RangeHighlighter_Base( m_aMutex ), |
| m_xSelectionSupplier( xSelectionSupplier ), |
| m_nAddedListenerCount( 0 ), |
| m_bIncludeHiddenCells(true) |
| { |
| } |
| |
| RangeHighlighter::~RangeHighlighter() |
| {} |
| |
| // ____ XRangeHighlighter ____ |
| Sequence< chart2::data::HighlightedRange > SAL_CALL RangeHighlighter::getSelectedRanges() |
| throw (uno::RuntimeException) |
| { |
| return m_aSelectedRanges; |
| } |
| |
| void RangeHighlighter::determineRanges() |
| { |
| m_aSelectedRanges.realloc( 0 ); |
| if( m_xSelectionSupplier.is()) |
| { |
| try |
| { |
| Reference< frame::XController > xController( m_xSelectionSupplier, uno::UNO_QUERY ); |
| Reference< frame::XModel > xChartModel; |
| if( xController.is()) |
| xChartModel.set( xController->getModel()); |
| |
| m_bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( xChartModel ); |
| |
| uno::Any aSelection( m_xSelectionSupplier->getSelection()); |
| const uno::Type& rType = aSelection.getValueType(); |
| |
| if ( rType == ::getCppuType( static_cast< const OUString* >( 0 ) ) ) |
| { |
| // @todo??: maybe getSelection() should return a model object rather than a CID |
| |
| OUString aCID; |
| aSelection >>= aCID; |
| if ( !aCID.isEmpty() ) |
| { |
| ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); |
| sal_Int32 nIndex = ObjectIdentifier::getIndexFromParticleOrCID( aCID ); |
| Reference< chart2::XDataSeries > xDataSeries( ObjectIdentifier::getDataSeriesForCID( aCID, xChartModel ) ); |
| if( OBJECTTYPE_LEGEND_ENTRY == eObjectType ) |
| { |
| OUString aParentParticel( ObjectIdentifier::getFullParentParticle( aCID ) ); |
| ObjectType eParentObjectType = ObjectIdentifier::getObjectType( aParentParticel ); |
| eObjectType = eParentObjectType; |
| if( OBJECTTYPE_DATA_POINT == eObjectType ) |
| nIndex = ObjectIdentifier::getIndexFromParticleOrCID( aParentParticel ); |
| } |
| |
| if( OBJECTTYPE_DATA_POINT == eObjectType || OBJECTTYPE_DATA_LABEL == eObjectType ) |
| { |
| // Data Point |
| fillRangesForDataPoint( xDataSeries, nIndex ); |
| return; |
| } |
| else if( OBJECTTYPE_DATA_ERRORS == eObjectType ) |
| { |
| // select error bar ranges, or data series, if the style is |
| // not set to FROM_DATA |
| fillRangesForErrorBars( ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ), xDataSeries ); |
| return; |
| } |
| else if( xDataSeries.is() ) |
| { |
| // Data Series |
| fillRangesForDataSeries( xDataSeries ); |
| return; |
| } |
| else if( OBJECTTYPE_AXIS == eObjectType ) |
| { |
| // Axis (Categories) |
| Reference< chart2::XAxis > xAxis( ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ), uno::UNO_QUERY ); |
| if( xAxis.is()) |
| { |
| fillRangesForCategories( xAxis ); |
| return; |
| } |
| } |
| else if( OBJECTTYPE_PAGE == eObjectType |
| || OBJECTTYPE_DIAGRAM == eObjectType |
| || OBJECTTYPE_DIAGRAM_WALL == eObjectType |
| || OBJECTTYPE_DIAGRAM_FLOOR == eObjectType |
| ) |
| { |
| // Diagram |
| Reference< chart2::XDiagram > xDia( ObjectIdentifier::getDiagramForCID( aCID, xChartModel ) ); |
| if( xDia.is()) |
| { |
| fillRangesForDiagram( xDia ); |
| return; |
| } |
| } |
| } |
| } |
| else if ( rType == ::getCppuType( static_cast< const Reference< drawing::XShape >* >( 0 ) ) ) |
| { |
| // #i12587# support for shapes in chart |
| Reference< drawing::XShape > xShape; |
| aSelection >>= xShape; |
| if ( xShape.is() ) |
| { |
| return; |
| } |
| } |
| else |
| { |
| //if nothing is selected select all ranges |
| Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY_THROW ); |
| fillRangesForDiagram( xChartDoc->getFirstDiagram() ); |
| return; |
| } |
| } |
| catch( const uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| } |
| } |
| |
| void RangeHighlighter::fillRangesForDiagram( const Reference< chart2::XDiagram > & xDiagram ) |
| { |
| Sequence< OUString > aSelectedRanges( DataSourceHelper::getUsedDataRanges( xDiagram )); |
| m_aSelectedRanges.realloc( aSelectedRanges.getLength()); |
| // @todo: merge ranges |
| for( sal_Int32 i=0; i<aSelectedRanges.getLength(); ++i ) |
| { |
| m_aSelectedRanges[i].RangeRepresentation = aSelectedRanges[i]; |
| m_aSelectedRanges[i].Index = -1; |
| m_aSelectedRanges[i].PreferredColor = PREFERED_DEFAULT_COLOR; |
| m_aSelectedRanges[i].AllowMerginigWithOtherRanges = sal_True; |
| } |
| } |
| |
| void RangeHighlighter::fillRangesForDataSeries( const uno::Reference< chart2::XDataSeries > & xSeries ) |
| { |
| sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR; |
| Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); |
| if( xSource.is()) |
| lcl_fillRanges( m_aSelectedRanges, |
| ::chart::DataSourceHelper::getRangesFromDataSource( xSource ), |
| nPreferredColor ); |
| } |
| |
| void RangeHighlighter::fillRangesForErrorBars( |
| const uno::Reference< beans::XPropertySet > & xErrorBar, |
| const uno::Reference< chart2::XDataSeries > & xSeries ) |
| { |
| // only show error bar ranges, if the style is set to FROM_DATA |
| bool bUsesRangesAsErrorBars = false; |
| try |
| { |
| sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; |
| bUsesRangesAsErrorBars = |
| ( xErrorBar.is() && |
| (xErrorBar->getPropertyValue( C2U("ErrorBarStyle")) >>= nStyle) && |
| nStyle == ::com::sun::star::chart::ErrorBarStyle::FROM_DATA ); |
| } |
| catch( const uno::Exception & ex ) |
| { |
| ASSERT_EXCEPTION( ex ); |
| } |
| |
| if( bUsesRangesAsErrorBars ) |
| { |
| sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR; |
| Reference< chart2::data::XDataSource > xSource( xErrorBar, uno::UNO_QUERY ); |
| if( xSource.is()) |
| lcl_fillRanges( m_aSelectedRanges, |
| ::chart::DataSourceHelper::getRangesFromDataSource( xSource ), |
| nPreferredColor ); |
| } |
| else |
| { |
| fillRangesForDataSeries( xSeries ); |
| } |
| } |
| |
| void RangeHighlighter::fillRangesForCategories( const Reference< chart2::XAxis > & xAxis ) |
| { |
| if( ! xAxis.is()) |
| return; |
| chart2::ScaleData aData( xAxis->getScaleData()); |
| lcl_fillRanges( m_aSelectedRanges, |
| DataSourceHelper::getRangesFromLabeledDataSequence( aData.Categories )); |
| } |
| |
| void RangeHighlighter::fillRangesForDataPoint( const Reference< uno::XInterface > & xDataSeries, sal_Int32 nIndex ) |
| { |
| sal_Int32 nPreferredColor = PREFERED_DEFAULT_COLOR; |
| if( xDataSeries.is()) |
| { |
| Reference< chart2::data::XDataSource > xSource( xDataSeries, uno::UNO_QUERY ); |
| if( xSource.is() ) |
| { |
| ::std::vector< chart2::data::HighlightedRange > aHilightedRanges; |
| Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeqSeq( xSource->getDataSequences()); |
| for( sal_Int32 i=0; i<aLSeqSeq.getLength(); ++i ) |
| { |
| Reference< chart2::data::XDataSequence > xLabel( aLSeqSeq[i]->getLabel()); |
| Reference< chart2::data::XDataSequence > xValues( aLSeqSeq[i]->getValues()); |
| |
| if( xLabel.is()) |
| aHilightedRanges.push_back( |
| chart2::data::HighlightedRange( |
| xLabel->getSourceRangeRepresentation(), |
| -1, |
| nPreferredColor, |
| sal_False )); |
| |
| sal_Int32 nUnhiddenIndex = DataSeriesHelper::translateIndexFromHiddenToFullSequence( nIndex, xValues, !m_bIncludeHiddenCells ); |
| if( xValues.is()) |
| aHilightedRanges.push_back( |
| chart2::data::HighlightedRange( |
| xValues->getSourceRangeRepresentation(), |
| nUnhiddenIndex, |
| nPreferredColor, |
| sal_False )); |
| } |
| m_aSelectedRanges = ContainerHelper::ContainerToSequence( aHilightedRanges ); |
| } |
| } |
| } |
| |
| void SAL_CALL RangeHighlighter::addSelectionChangeListener( const Reference< view::XSelectionChangeListener >& xListener ) |
| throw (uno::RuntimeException) |
| { |
| if(!xListener.is()) |
| return; |
| |
| if( m_nAddedListenerCount == 0 ) |
| startListening(); |
| rBHelper.addListener( ::getCppuType( & xListener ), xListener); |
| ++m_nAddedListenerCount; |
| |
| //bring the new listener up to the current state |
| lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) ); |
| xListener->selectionChanged( aEvent ); |
| } |
| |
| void SAL_CALL RangeHighlighter::removeSelectionChangeListener( const Reference< view::XSelectionChangeListener >& xListener ) |
| throw (uno::RuntimeException) |
| { |
| rBHelper.removeListener( ::getCppuType( & xListener ), xListener ); |
| --m_nAddedListenerCount; |
| if( m_nAddedListenerCount == 0 ) |
| stopListening(); |
| } |
| |
| // ____ XSelectionChangeListener ____ |
| void SAL_CALL RangeHighlighter::selectionChanged( const lang::EventObject& /*aEvent*/ ) |
| throw (uno::RuntimeException) |
| { |
| determineRanges(); |
| |
| // determine ranges of selected view objects |
| // if changed, fire an event |
| fireSelectionEvent(); |
| } |
| |
| void RangeHighlighter::fireSelectionEvent() |
| { |
| ::cppu::OInterfaceContainerHelper* pIC = rBHelper.getContainer( |
| ::getCppuType((const uno::Reference< view::XSelectionChangeListener >*)0) ); |
| if( pIC ) |
| { |
| lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) ); |
| ::cppu::OInterfaceIteratorHelper aIt( *pIC ); |
| while( aIt.hasMoreElements() ) |
| { |
| uno::Reference< view::XSelectionChangeListener > xListener( aIt.next(), uno::UNO_QUERY ); |
| if( xListener.is() ) |
| xListener->selectionChanged( aEvent ); |
| } |
| } |
| } |
| |
| void SAL_CALL RangeHighlighter::disposing( const lang::EventObject& Source ) |
| throw (uno::RuntimeException) |
| { |
| if( Source.Source == m_xSelectionSupplier ) |
| { |
| m_xSelectionSupplier.clear(); |
| m_aSelectedRanges.realloc( 0 ); |
| fireSelectionEvent(); |
| } |
| } |
| |
| void RangeHighlighter::startListening() |
| { |
| if( m_xSelectionSupplier.is()) |
| { |
| if( ! m_xListener.is()) |
| { |
| m_xListener.set( new WeakSelectionChangeListenerAdapter( this )); |
| determineRanges(); |
| } |
| m_xSelectionSupplier->addSelectionChangeListener( m_xListener ); |
| } |
| } |
| |
| void RangeHighlighter::stopListening() |
| { |
| if( m_xSelectionSupplier.is() && m_xListener.is()) |
| { |
| m_xSelectionSupplier->removeSelectionChangeListener( m_xListener ); |
| m_xListener.clear(); |
| } |
| } |
| |
| |
| // ____ WeakComponentImplHelperBase ____ |
| // is called when dispose() is called at this component |
| void SAL_CALL RangeHighlighter::disposing() |
| { |
| // @todo: remove listener. Currently the controller shows an assertion |
| // because it is already disposed |
| // stopListening(); |
| m_xListener.clear(); |
| m_xSelectionSupplier.clear(); |
| m_nAddedListenerCount = 0; |
| m_aSelectedRanges.realloc( 0 ); |
| } |
| |
| } // namespace chart |