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 <ChartModel.hxx>
23 #include <ChartModelHelper.hxx>
24 #include <DataSourceHelper.hxx>
25 #include <ObjectIdentifier.hxx>
26 #include <DataSeries.hxx>
27 #include <DataSeriesHelper.hxx>
28 #include <Diagram.hxx>
30 #include <com/sun/star/chart2/ScaleData.hpp>
31 #include <com/sun/star/chart2/XAxis.hpp>
32 #include <com/sun/star/chart2/XDataSeries.hpp>
33 #include <com/sun/star/chart/ErrorBarStyle.hpp>
34 #include <com/sun/star/drawing/XShape.hpp>
35 #include <com/sun/star/view/XSelectionSupplier.hpp>
36 #include <comphelper/sequence.hxx>
37 #include <comphelper/diagnose_ex.hxx>
38 #include <tools/color.hxx>
40 using namespace ::com::sun::star
;
42 using ::com::sun::star::uno::Reference
;
43 using ::com::sun::star::uno::Sequence
;
48 const Color defaultPreferredColor
= COL_LIGHTBLUE
;
51 Sequence
< chart2::data::HighlightedRange
> & rOutRanges
,
52 const Sequence
< OUString
>& aRangeStrings
,
53 Color nPreferredColor
,
54 sal_Int32 nIndex
= -1 )
56 rOutRanges
.realloc( aRangeStrings
.getLength());
57 auto pOutRanges
= rOutRanges
.getArray();
58 for( sal_Int32 i
=0; i
<aRangeStrings
.getLength(); ++i
)
60 pOutRanges
[i
].RangeRepresentation
= aRangeStrings
[i
];
61 pOutRanges
[i
].PreferredColor
= sal_Int32(nPreferredColor
);
62 pOutRanges
[i
].AllowMerginigWithOtherRanges
= false;
63 pOutRanges
[i
].Index
= nIndex
;
67 } // anonymous namespace
72 RangeHighlighter::RangeHighlighter(
73 const rtl::Reference
< ChartModel
> & xChartModel
) :
74 m_xSelectionSupplier(xChartModel
->getCurrentController(), uno::UNO_QUERY
),
75 m_xChartModel( xChartModel
),
76 m_nAddedListenerCount( 0 ),
77 m_bIncludeHiddenCells(true)
81 RangeHighlighter::~RangeHighlighter()
84 // ____ XRangeHighlighter ____
85 Sequence
< chart2::data::HighlightedRange
> SAL_CALL
RangeHighlighter::getSelectedRanges()
87 return m_aSelectedRanges
;
90 void RangeHighlighter::determineRanges()
92 m_aSelectedRanges
.realloc( 0 );
93 if( !m_xChartModel
.is())
95 if( !m_xSelectionSupplier
.is())
100 m_bIncludeHiddenCells
= ChartModelHelper::isIncludeHiddenCells( m_xChartModel
);
102 uno::Any
aSelection( m_xSelectionSupplier
->getSelection());
104 if (aSelection
.getValueType() == cppu::UnoType
<OUString
>::get())
106 // @todo??: maybe getSelection() should return a model object rather than a CID
110 if ( !aCID
.isEmpty() )
112 ObjectType eObjectType
= ObjectIdentifier::getObjectType( aCID
);
113 sal_Int32 nIndex
= ObjectIdentifier::getIndexFromParticleOrCID( aCID
);
114 rtl::Reference
< DataSeries
> xDataSeries( ObjectIdentifier::getDataSeriesForCID( aCID
, m_xChartModel
) );
115 if( eObjectType
== OBJECTTYPE_LEGEND_ENTRY
)
117 OUString
aParentParticel( ObjectIdentifier::getFullParentParticle( aCID
) );
118 ObjectType eParentObjectType
= ObjectIdentifier::getObjectType( aParentParticel
);
119 eObjectType
= eParentObjectType
;
120 if( eObjectType
== OBJECTTYPE_DATA_POINT
)
121 nIndex
= ObjectIdentifier::getIndexFromParticleOrCID( aParentParticel
);
124 if( eObjectType
== OBJECTTYPE_DATA_POINT
|| eObjectType
== OBJECTTYPE_DATA_LABEL
)
127 fillRangesForDataPoint( xDataSeries
, nIndex
);
130 else if( eObjectType
== OBJECTTYPE_DATA_ERRORS_X
||
131 eObjectType
== OBJECTTYPE_DATA_ERRORS_Y
||
132 eObjectType
== OBJECTTYPE_DATA_ERRORS_Z
)
134 // select error bar ranges, or data series, if the style is
135 // not set to FROM_DATA
136 fillRangesForErrorBars( ObjectIdentifier::getObjectPropertySet( aCID
, m_xChartModel
), xDataSeries
);
139 else if( xDataSeries
.is() )
142 fillRangesForDataSeries( xDataSeries
);
145 else if( eObjectType
== OBJECTTYPE_AXIS
)
148 Reference
< chart2::XAxis
> xAxis( ObjectIdentifier::getObjectPropertySet( aCID
, m_xChartModel
), uno::UNO_QUERY
);
151 fillRangesForCategories( xAxis
);
155 else if( eObjectType
== OBJECTTYPE_PAGE
156 || eObjectType
== OBJECTTYPE_DIAGRAM
157 || eObjectType
== OBJECTTYPE_DIAGRAM_WALL
158 || eObjectType
== OBJECTTYPE_DIAGRAM_FLOOR
162 rtl::Reference
< ::chart::Diagram
> xDia( ObjectIdentifier::getDiagramForCID( aCID
, m_xChartModel
) );
165 fillRangesForDiagram( xDia
);
171 else if (Reference
<drawing::XShape
> xShape
; aSelection
>>= xShape
)
173 // #i12587# support for shapes in chart
181 //if nothing is selected select all ranges
182 fillRangesForDiagram( m_xChartModel
->getFirstChartDiagram() );
186 catch( const uno::Exception
& )
188 DBG_UNHANDLED_EXCEPTION("chart2");
192 void RangeHighlighter::fillRangesForDiagram( const rtl::Reference
< Diagram
> & xDiagram
)
194 Sequence
< OUString
> aSelectedRanges( DataSourceHelper::getUsedDataRanges( xDiagram
));
195 m_aSelectedRanges
.realloc( aSelectedRanges
.getLength());
196 auto pSelectedRanges
= m_aSelectedRanges
.getArray();
197 // @todo: merge ranges
198 for( sal_Int32 i
=0; i
<aSelectedRanges
.getLength(); ++i
)
200 pSelectedRanges
[i
].RangeRepresentation
= aSelectedRanges
[i
];
201 pSelectedRanges
[i
].Index
= -1;
202 pSelectedRanges
[i
].PreferredColor
= sal_Int32(defaultPreferredColor
);
203 pSelectedRanges
[i
].AllowMerginigWithOtherRanges
= true;
207 void RangeHighlighter::fillRangesForDataSeries( const uno::Reference
< chart2::XDataSeries
> & xSeries
)
209 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
212 lcl_fillRanges( m_aSelectedRanges
,
213 ::chart::DataSourceHelper::getRangesFromDataSource( xSource
),
214 defaultPreferredColor
);
218 void RangeHighlighter::fillRangesForErrorBars(
219 const uno::Reference
< beans::XPropertySet
> & xErrorBar
,
220 const uno::Reference
< chart2::XDataSeries
> & xSeries
)
222 // only show error bar ranges, if the style is set to FROM_DATA
223 bool bUsesRangesAsErrorBars
= false;
226 sal_Int32 nStyle
= css::chart::ErrorBarStyle::NONE
;
227 bUsesRangesAsErrorBars
=
229 (xErrorBar
->getPropertyValue( u
"ErrorBarStyle"_ustr
) >>= nStyle
) &&
230 nStyle
== css::chart::ErrorBarStyle::FROM_DATA
);
232 catch( const uno::Exception
& )
234 DBG_UNHANDLED_EXCEPTION("chart2");
237 if( bUsesRangesAsErrorBars
)
239 Reference
< chart2::data::XDataSource
> xSource( xErrorBar
, uno::UNO_QUERY
);
242 lcl_fillRanges( m_aSelectedRanges
,
243 ::chart::DataSourceHelper::getRangesFromDataSource( xSource
),
244 defaultPreferredColor
);
249 fillRangesForDataSeries( xSeries
);
253 void RangeHighlighter::fillRangesForCategories( const Reference
< chart2::XAxis
> & xAxis
)
257 chart2::ScaleData
aData( xAxis
->getScaleData());
258 lcl_fillRanges( m_aSelectedRanges
,
259 DataSourceHelper::getRangesFromLabeledDataSequence( aData
.Categories
),
260 defaultPreferredColor
);
263 void RangeHighlighter::fillRangesForDataPoint( const rtl::Reference
< DataSeries
> & xDataSeries
, sal_Int32 nIndex
)
265 if( !xDataSeries
.is())
268 Color nPreferredColor
= defaultPreferredColor
;
269 std::vector
< chart2::data::HighlightedRange
> aHilightedRanges
;
270 const std::vector
< uno::Reference
< chart2::data::XLabeledDataSequence
> > & aLSeqSeq( xDataSeries
->getDataSequences2());
271 for( uno::Reference
< chart2::data::XLabeledDataSequence
> const & labelDataSeq
: aLSeqSeq
)
273 Reference
< chart2::data::XDataSequence
> xLabel( labelDataSeq
->getLabel());
274 Reference
< chart2::data::XDataSequence
> xValues( labelDataSeq
->getValues());
277 aHilightedRanges
.emplace_back(
278 xLabel
->getSourceRangeRepresentation(),
280 sal_Int32(nPreferredColor
),
283 sal_Int32 nUnhiddenIndex
= DataSeriesHelper::translateIndexFromHiddenToFullSequence( nIndex
, xValues
, !m_bIncludeHiddenCells
);
285 aHilightedRanges
.emplace_back(
286 xValues
->getSourceRangeRepresentation(),
288 sal_Int32(nPreferredColor
),
291 m_aSelectedRanges
= comphelper::containerToSequence( aHilightedRanges
);
294 void SAL_CALL
RangeHighlighter::addSelectionChangeListener( const Reference
< view::XSelectionChangeListener
>& xListener
)
299 if( m_nAddedListenerCount
== 0 )
301 std::unique_lock
g(m_aMutex
);
302 maSelectionChangeListeners
.addInterface( g
, xListener
);
303 ++m_nAddedListenerCount
;
305 //bring the new listener up to the current state
306 lang::EventObject
aEvent( static_cast< lang::XComponent
* >( this ) );
307 xListener
->selectionChanged( aEvent
);
310 void SAL_CALL
RangeHighlighter::removeSelectionChangeListener( const Reference
< view::XSelectionChangeListener
>& xListener
)
312 std::unique_lock
g(m_aMutex
);
313 maSelectionChangeListeners
.removeInterface( g
, xListener
);
314 --m_nAddedListenerCount
;
315 if( m_nAddedListenerCount
== 0 )
319 // ____ XSelectionChangeListener ____
320 void SAL_CALL
RangeHighlighter::selectionChanged( const lang::EventObject
& /*aEvent*/ )
324 // determine ranges of selected view objects
325 // if changed, fire an event
326 fireSelectionEvent();
329 void RangeHighlighter::fireSelectionEvent()
331 std::unique_lock
g(m_aMutex
);
332 if( maSelectionChangeListeners
.getLength(g
) )
334 lang::EventObject
aEvent( static_cast< lang::XComponent
* >( this ) );
335 maSelectionChangeListeners
.forEach(g
,
336 [&aEvent
](const css::uno::Reference
<view::XSelectionChangeListener
>& xListener
)
338 xListener
->selectionChanged(aEvent
);
344 void SAL_CALL
RangeHighlighter::disposing( const lang::EventObject
& Source
)
346 if( Source
.Source
== m_xSelectionSupplier
)
348 m_xSelectionSupplier
.clear();
349 m_aSelectedRanges
.realloc( 0 );
350 fireSelectionEvent();
354 void RangeHighlighter::startListening()
356 if( m_xSelectionSupplier
.is())
358 if( ! m_xListener
.is())
360 m_xListener
.set( new WeakSelectionChangeListenerAdapter( this ));
363 m_xSelectionSupplier
->addSelectionChangeListener( m_xListener
);
367 void RangeHighlighter::stopListening()
369 if( m_xSelectionSupplier
.is() && m_xListener
.is())
371 m_xSelectionSupplier
->removeSelectionChangeListener( m_xListener
);
376 // ____ WeakComponentImplHelperBase ____
377 // is called when dispose() is called at this component
378 void RangeHighlighter::disposing(std::unique_lock
<std::mutex
>&)
380 // @todo: remove listener. Currently the controller shows an assertion
381 // because it is already disposed
384 m_xSelectionSupplier
.clear();
385 m_nAddedListenerCount
= 0;
386 m_aSelectedRanges
.realloc( 0 );
391 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */