1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <RangeHighlighter.hxx>
21 #include <WeakListenerAdapter.hxx>
22 #include <ChartModelHelper.hxx>
23 #include <DataSourceHelper.hxx>
24 #include <ObjectIdentifier.hxx>
25 #include <DataSeriesHelper.hxx>
27 #include <com/sun/star/chart2/ScaleData.hpp>
28 #include <com/sun/star/chart2/XAxis.hpp>
29 #include <com/sun/star/chart2/XDataSeries.hpp>
30 #include <com/sun/star/chart/ErrorBarStyle.hpp>
31 #include <com/sun/star/chart2/XChartDocument.hpp>
32 #include <com/sun/star/drawing/XShape.hpp>
33 #include <com/sun/star/view/XSelectionSupplier.hpp>
34 #include <comphelper/sequence.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <tools/color.hxx>
38 using namespace ::com::sun::star
;
40 using ::com::sun::star::uno::Reference
;
41 using ::com::sun::star::uno::Sequence
;
46 const Color defaultPreferredColor
= COL_LIGHTBLUE
;
49 Sequence
< chart2::data::HighlightedRange
> & rOutRanges
,
50 const Sequence
< OUString
>& aRangeStrings
,
51 Color nPreferredColor
,
52 sal_Int32 nIndex
= -1 )
54 rOutRanges
.realloc( aRangeStrings
.getLength());
55 for( sal_Int32 i
=0; i
<aRangeStrings
.getLength(); ++i
)
57 rOutRanges
[i
].RangeRepresentation
= aRangeStrings
[i
];
58 rOutRanges
[i
].PreferredColor
= sal_Int32(nPreferredColor
);
59 rOutRanges
[i
].AllowMerginigWithOtherRanges
= false;
60 rOutRanges
[i
].Index
= nIndex
;
64 } // anonymous namespace
69 RangeHighlighter::RangeHighlighter(
70 const Reference
< view::XSelectionSupplier
> & xSelectionSupplier
) :
71 impl::RangeHighlighter_Base( m_aMutex
),
72 m_xSelectionSupplier( xSelectionSupplier
),
73 m_nAddedListenerCount( 0 ),
74 m_bIncludeHiddenCells(true)
78 RangeHighlighter::~RangeHighlighter()
81 // ____ XRangeHighlighter ____
82 Sequence
< chart2::data::HighlightedRange
> SAL_CALL
RangeHighlighter::getSelectedRanges()
84 return m_aSelectedRanges
;
87 void RangeHighlighter::determineRanges()
89 m_aSelectedRanges
.realloc( 0 );
90 if( !m_xSelectionSupplier
.is())
95 Reference
< frame::XController
> xController( m_xSelectionSupplier
, uno::UNO_QUERY
);
96 Reference
< frame::XModel
> xChartModel
;
98 xChartModel
.set( xController
->getModel());
100 m_bIncludeHiddenCells
= ChartModelHelper::isIncludeHiddenCells( xChartModel
);
102 uno::Any
aSelection( m_xSelectionSupplier
->getSelection());
103 const uno::Type
& rType
= aSelection
.getValueType();
105 if ( rType
== cppu::UnoType
<OUString
>::get() )
107 // @todo??: maybe getSelection() should return a model object rather than a CID
111 if ( !aCID
.isEmpty() )
113 ObjectType eObjectType
= ObjectIdentifier::getObjectType( aCID
);
114 sal_Int32 nIndex
= ObjectIdentifier::getIndexFromParticleOrCID( aCID
);
115 Reference
< chart2::XDataSeries
> xDataSeries( ObjectIdentifier::getDataSeriesForCID( aCID
, xChartModel
) );
116 if( eObjectType
== OBJECTTYPE_LEGEND_ENTRY
)
118 OUString
aParentParticel( ObjectIdentifier::getFullParentParticle( aCID
) );
119 ObjectType eParentObjectType
= ObjectIdentifier::getObjectType( aParentParticel
);
120 eObjectType
= eParentObjectType
;
121 if( eObjectType
== OBJECTTYPE_DATA_POINT
)
122 nIndex
= ObjectIdentifier::getIndexFromParticleOrCID( aParentParticel
);
125 if( eObjectType
== OBJECTTYPE_DATA_POINT
|| eObjectType
== OBJECTTYPE_DATA_LABEL
)
128 fillRangesForDataPoint( xDataSeries
, nIndex
);
131 else if( eObjectType
== OBJECTTYPE_DATA_ERRORS_X
||
132 eObjectType
== OBJECTTYPE_DATA_ERRORS_Y
||
133 eObjectType
== OBJECTTYPE_DATA_ERRORS_Z
)
135 // select error bar ranges, or data series, if the style is
136 // not set to FROM_DATA
137 fillRangesForErrorBars( ObjectIdentifier::getObjectPropertySet( aCID
, xChartModel
), xDataSeries
);
140 else if( xDataSeries
.is() )
143 fillRangesForDataSeries( xDataSeries
);
146 else if( eObjectType
== OBJECTTYPE_AXIS
)
149 Reference
< chart2::XAxis
> xAxis( ObjectIdentifier::getObjectPropertySet( aCID
, xChartModel
), uno::UNO_QUERY
);
152 fillRangesForCategories( xAxis
);
156 else if( eObjectType
== OBJECTTYPE_PAGE
157 || eObjectType
== OBJECTTYPE_DIAGRAM
158 || eObjectType
== OBJECTTYPE_DIAGRAM_WALL
159 || eObjectType
== OBJECTTYPE_DIAGRAM_FLOOR
163 Reference
< chart2::XDiagram
> xDia( ObjectIdentifier::getDiagramForCID( aCID
, xChartModel
) );
166 fillRangesForDiagram( xDia
);
172 else if ( rType
== cppu::UnoType
< drawing::XShape
>::get() )
174 // #i12587# support for shapes in chart
175 Reference
< drawing::XShape
> xShape
;
176 aSelection
>>= xShape
;
184 //if nothing is selected select all ranges
185 Reference
< chart2::XChartDocument
> xChartDoc( xChartModel
, uno::UNO_QUERY_THROW
);
186 fillRangesForDiagram( xChartDoc
->getFirstDiagram() );
190 catch( const uno::Exception
& )
192 DBG_UNHANDLED_EXCEPTION("chart2");
196 void RangeHighlighter::fillRangesForDiagram( const Reference
< chart2::XDiagram
> & xDiagram
)
198 Sequence
< OUString
> aSelectedRanges( DataSourceHelper::getUsedDataRanges( xDiagram
));
199 m_aSelectedRanges
.realloc( aSelectedRanges
.getLength());
200 // @todo: merge ranges
201 for( sal_Int32 i
=0; i
<aSelectedRanges
.getLength(); ++i
)
203 m_aSelectedRanges
[i
].RangeRepresentation
= aSelectedRanges
[i
];
204 m_aSelectedRanges
[i
].Index
= -1;
205 m_aSelectedRanges
[i
].PreferredColor
= sal_Int32(defaultPreferredColor
);
206 m_aSelectedRanges
[i
].AllowMerginigWithOtherRanges
= true;
210 void RangeHighlighter::fillRangesForDataSeries( const uno::Reference
< chart2::XDataSeries
> & xSeries
)
212 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
215 lcl_fillRanges( m_aSelectedRanges
,
216 ::chart::DataSourceHelper::getRangesFromDataSource( xSource
),
217 defaultPreferredColor
);
221 void RangeHighlighter::fillRangesForErrorBars(
222 const uno::Reference
< beans::XPropertySet
> & xErrorBar
,
223 const uno::Reference
< chart2::XDataSeries
> & xSeries
)
225 // only show error bar ranges, if the style is set to FROM_DATA
226 bool bUsesRangesAsErrorBars
= false;
229 sal_Int32 nStyle
= css::chart::ErrorBarStyle::NONE
;
230 bUsesRangesAsErrorBars
=
232 (xErrorBar
->getPropertyValue( "ErrorBarStyle") >>= nStyle
) &&
233 nStyle
== css::chart::ErrorBarStyle::FROM_DATA
);
235 catch( const uno::Exception
& )
237 DBG_UNHANDLED_EXCEPTION("chart2");
240 if( bUsesRangesAsErrorBars
)
242 Reference
< chart2::data::XDataSource
> xSource( xErrorBar
, uno::UNO_QUERY
);
245 lcl_fillRanges( m_aSelectedRanges
,
246 ::chart::DataSourceHelper::getRangesFromDataSource( xSource
),
247 defaultPreferredColor
);
252 fillRangesForDataSeries( xSeries
);
256 void RangeHighlighter::fillRangesForCategories( const Reference
< chart2::XAxis
> & xAxis
)
260 chart2::ScaleData
aData( xAxis
->getScaleData());
261 lcl_fillRanges( m_aSelectedRanges
,
262 DataSourceHelper::getRangesFromLabeledDataSequence( aData
.Categories
),
263 defaultPreferredColor
);
266 void RangeHighlighter::fillRangesForDataPoint( const Reference
< uno::XInterface
> & xDataSeries
, sal_Int32 nIndex
)
268 if( !xDataSeries
.is())
271 Reference
< chart2::data::XDataSource
> xSource( xDataSeries
, uno::UNO_QUERY
);
275 Color nPreferredColor
= defaultPreferredColor
;
276 std::vector
< chart2::data::HighlightedRange
> aHilightedRanges
;
277 const Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aLSeqSeq( xSource
->getDataSequences());
278 for( Reference
< chart2::data::XLabeledDataSequence
> const & labelDataSeq
: aLSeqSeq
)
280 Reference
< chart2::data::XDataSequence
> xLabel( labelDataSeq
->getLabel());
281 Reference
< chart2::data::XDataSequence
> xValues( labelDataSeq
->getValues());
284 aHilightedRanges
.emplace_back(
285 xLabel
->getSourceRangeRepresentation(),
287 sal_Int32(nPreferredColor
),
290 sal_Int32 nUnhiddenIndex
= DataSeriesHelper::translateIndexFromHiddenToFullSequence( nIndex
, xValues
, !m_bIncludeHiddenCells
);
292 aHilightedRanges
.emplace_back(
293 xValues
->getSourceRangeRepresentation(),
295 sal_Int32(nPreferredColor
),
298 m_aSelectedRanges
= comphelper::containerToSequence( aHilightedRanges
);
301 void SAL_CALL
RangeHighlighter::addSelectionChangeListener( const Reference
< view::XSelectionChangeListener
>& xListener
)
306 if( m_nAddedListenerCount
== 0 )
308 rBHelper
.addListener( cppu::UnoType
<decltype(xListener
)>::get(), xListener
);
309 ++m_nAddedListenerCount
;
311 //bring the new listener up to the current state
312 lang::EventObject
aEvent( static_cast< lang::XComponent
* >( this ) );
313 xListener
->selectionChanged( aEvent
);
316 void SAL_CALL
RangeHighlighter::removeSelectionChangeListener( const Reference
< view::XSelectionChangeListener
>& xListener
)
318 rBHelper
.removeListener( cppu::UnoType
<decltype(xListener
)>::get(), xListener
);
319 --m_nAddedListenerCount
;
320 if( m_nAddedListenerCount
== 0 )
324 // ____ XSelectionChangeListener ____
325 void SAL_CALL
RangeHighlighter::selectionChanged( const lang::EventObject
& /*aEvent*/ )
329 // determine ranges of selected view objects
330 // if changed, fire an event
331 fireSelectionEvent();
334 void RangeHighlighter::fireSelectionEvent()
336 ::cppu::OInterfaceContainerHelper
* pIC
= rBHelper
.getContainer(
337 cppu::UnoType
< view::XSelectionChangeListener
>::get() );
340 lang::EventObject
aEvent( static_cast< lang::XComponent
* >( this ) );
341 ::cppu::OInterfaceIteratorHelper
aIt( *pIC
);
342 while( aIt
.hasMoreElements() )
344 uno::Reference
< view::XSelectionChangeListener
> xListener( aIt
.next(), uno::UNO_QUERY
);
346 xListener
->selectionChanged( aEvent
);
351 void SAL_CALL
RangeHighlighter::disposing( const lang::EventObject
& Source
)
353 if( Source
.Source
== m_xSelectionSupplier
)
355 m_xSelectionSupplier
.clear();
356 m_aSelectedRanges
.realloc( 0 );
357 fireSelectionEvent();
361 void RangeHighlighter::startListening()
363 if( m_xSelectionSupplier
.is())
365 if( ! m_xListener
.is())
367 m_xListener
.set( new WeakSelectionChangeListenerAdapter( this ));
370 m_xSelectionSupplier
->addSelectionChangeListener( m_xListener
);
374 void RangeHighlighter::stopListening()
376 if( m_xSelectionSupplier
.is() && m_xListener
.is())
378 m_xSelectionSupplier
->removeSelectionChangeListener( m_xListener
);
383 // ____ WeakComponentImplHelperBase ____
384 // is called when dispose() is called at this component
385 void SAL_CALL
RangeHighlighter::disposing()
387 // @todo: remove listener. Currently the controller shows an assertion
388 // because it is already disposed
391 m_xSelectionSupplier
.clear();
392 m_nAddedListenerCount
= 0;
393 m_aSelectedRanges
.realloc( 0 );
398 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */