LibreOffice Module chart2 (master) 1
RangeHighlighter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <RangeHighlighter.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>
29
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>
38#include <tools/color.hxx>
39
40using namespace ::com::sun::star;
41
42using ::com::sun::star::uno::Reference;
43using ::com::sun::star::uno::Sequence;
44
45namespace
46{
47
48const Color defaultPreferredColor = COL_LIGHTBLUE;
49
50void lcl_fillRanges(
51 Sequence< chart2::data::HighlightedRange > & rOutRanges,
52 const Sequence< OUString >& aRangeStrings,
53 Color nPreferredColor,
54 sal_Int32 nIndex = -1 )
55{
56 rOutRanges.realloc( aRangeStrings.getLength());
57 auto pOutRanges = rOutRanges.getArray();
58 for( sal_Int32 i=0; i<aRangeStrings.getLength(); ++i )
59 {
60 pOutRanges[i].RangeRepresentation = aRangeStrings[i];
61 pOutRanges[i].PreferredColor = sal_Int32(nPreferredColor);
62 pOutRanges[i].AllowMerginigWithOtherRanges = false;
63 pOutRanges[i].Index = nIndex;
64 }
65}
66
67} // anonymous namespace
68
69namespace chart
70{
71
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)
78{
79}
80
82{}
83
84// ____ XRangeHighlighter ____
86{
87 return m_aSelectedRanges;
88}
89
91{
92 m_aSelectedRanges.realloc( 0 );
93 if( !m_xChartModel.is())
94 return;
95 if( !m_xSelectionSupplier.is())
96 return;
97
98 try
99 {
101
102 uno::Any aSelection( m_xSelectionSupplier->getSelection());
103 const uno::Type& rType = aSelection.getValueType();
104
105 if ( rType == cppu::UnoType<OUString>::get() )
106 {
107 // @todo??: maybe getSelection() should return a model object rather than a CID
108
109 OUString aCID;
110 aSelection >>= aCID;
111 if ( !aCID.isEmpty() )
112 {
113 ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID );
116 if( eObjectType == OBJECTTYPE_LEGEND_ENTRY )
117 {
118 OUString aParentParticel( ObjectIdentifier::getFullParentParticle( aCID ) );
119 ObjectType eParentObjectType = ObjectIdentifier::getObjectType( aParentParticel );
120 eObjectType = eParentObjectType;
121 if( eObjectType == OBJECTTYPE_DATA_POINT )
123 }
124
125 if( eObjectType == OBJECTTYPE_DATA_POINT || eObjectType == OBJECTTYPE_DATA_LABEL )
126 {
127 // Data Point
128 fillRangesForDataPoint( xDataSeries, nIndex );
129 return;
130 }
131 else if( eObjectType == OBJECTTYPE_DATA_ERRORS_X ||
132 eObjectType == OBJECTTYPE_DATA_ERRORS_Y ||
133 eObjectType == OBJECTTYPE_DATA_ERRORS_Z )
134 {
135 // select error bar ranges, or data series, if the style is
136 // not set to FROM_DATA
138 return;
139 }
140 else if( xDataSeries.is() )
141 {
142 // Data Series
143 fillRangesForDataSeries( xDataSeries );
144 return;
145 }
146 else if( eObjectType == OBJECTTYPE_AXIS )
147 {
148 // Axis (Categories)
150 if( xAxis.is())
151 {
153 return;
154 }
155 }
156 else if( eObjectType == OBJECTTYPE_PAGE
157 || eObjectType == OBJECTTYPE_DIAGRAM
158 || eObjectType == OBJECTTYPE_DIAGRAM_WALL
159 || eObjectType == OBJECTTYPE_DIAGRAM_FLOOR
160 )
161 {
162 // Diagram
164 if( xDia.is())
165 {
166 fillRangesForDiagram( xDia );
167 return;
168 }
169 }
170 }
171 }
172 else if ( rType == cppu::UnoType< drawing::XShape >::get() )
173 {
174 // #i12587# support for shapes in chart
176 aSelection >>= xShape;
177 if ( xShape.is() )
178 {
179 return;
180 }
181 }
182 else
183 {
184 //if nothing is selected select all ranges
185 fillRangesForDiagram( m_xChartModel->getFirstChartDiagram() );
186 return;
187 }
188 }
189 catch( const uno::Exception & )
190 {
191 DBG_UNHANDLED_EXCEPTION("chart2");
192 }
193}
194
196{
197 Sequence< OUString > aSelectedRanges( DataSourceHelper::getUsedDataRanges( xDiagram ));
198 m_aSelectedRanges.realloc( aSelectedRanges.getLength());
199 auto pSelectedRanges = m_aSelectedRanges.getArray();
200 // @todo: merge ranges
201 for( sal_Int32 i=0; i<aSelectedRanges.getLength(); ++i )
202 {
203 pSelectedRanges[i].RangeRepresentation = aSelectedRanges[i];
204 pSelectedRanges[i].Index = -1;
205 pSelectedRanges[i].PreferredColor = sal_Int32(defaultPreferredColor);
206 pSelectedRanges[i].AllowMerginigWithOtherRanges = true;
207 }
208}
209
211{
212 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
213 if( xSource.is())
214 {
215 lcl_fillRanges( m_aSelectedRanges,
217 defaultPreferredColor );
218 }
219}
220
224{
225 // only show error bar ranges, if the style is set to FROM_DATA
226 bool bUsesRangesAsErrorBars = false;
227 try
228 {
229 sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE;
230 bUsesRangesAsErrorBars =
231 ( xErrorBar.is() &&
232 (xErrorBar->getPropertyValue( "ErrorBarStyle") >>= nStyle) &&
233 nStyle == css::chart::ErrorBarStyle::FROM_DATA );
234 }
235 catch( const uno::Exception & )
236 {
237 DBG_UNHANDLED_EXCEPTION("chart2");
238 }
239
240 if( bUsesRangesAsErrorBars )
241 {
242 Reference< chart2::data::XDataSource > xSource( xErrorBar, uno::UNO_QUERY );
243 if( xSource.is())
244 {
245 lcl_fillRanges( m_aSelectedRanges,
247 defaultPreferredColor );
248 }
249 }
250 else
251 {
252 fillRangesForDataSeries( xSeries );
253 }
254}
255
257{
258 if( ! xAxis.is())
259 return;
260 chart2::ScaleData aData( xAxis->getScaleData());
261 lcl_fillRanges( m_aSelectedRanges,
263 defaultPreferredColor );
264}
265
267{
268 if( !xDataSeries.is())
269 return;
270
271 Color nPreferredColor = defaultPreferredColor;
272 std::vector< chart2::data::HighlightedRange > aHilightedRanges;
273 const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aLSeqSeq( xDataSeries->getDataSequences2());
274 for( uno::Reference< chart2::data::XLabeledDataSequence > const & labelDataSeq : aLSeqSeq )
275 {
276 Reference< chart2::data::XDataSequence > xLabel( labelDataSeq->getLabel());
277 Reference< chart2::data::XDataSequence > xValues( labelDataSeq->getValues());
278
279 if( xLabel.is())
280 aHilightedRanges.emplace_back(
281 xLabel->getSourceRangeRepresentation(),
282 -1,
283 sal_Int32(nPreferredColor),
284 false );
285
287 if( xValues.is())
288 aHilightedRanges.emplace_back(
289 xValues->getSourceRangeRepresentation(),
290 nUnhiddenIndex,
291 sal_Int32(nPreferredColor),
292 false );
293 }
295}
296
298{
299 if(!xListener.is())
300 return;
301
302 if( m_nAddedListenerCount == 0 )
304 std::unique_lock g(m_aMutex);
307
308 //bring the new listener up to the current state
309 lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) );
310 xListener->selectionChanged( aEvent );
311}
312
314{
315 std::unique_lock g(m_aMutex);
318 if( m_nAddedListenerCount == 0 )
320}
321
322// ____ XSelectionChangeListener ____
323void SAL_CALL RangeHighlighter::selectionChanged( const lang::EventObject& /*aEvent*/ )
324{
326
327 // determine ranges of selected view objects
328 // if changed, fire an event
330}
331
333{
334 std::unique_lock g(m_aMutex);
336 {
337 lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) );
339 [&aEvent](const css::uno::Reference<view::XSelectionChangeListener>& xListener)
340 {
341 xListener->selectionChanged(aEvent);
342 }
343 );
344 }
345}
346
347void SAL_CALL RangeHighlighter::disposing( const lang::EventObject& Source )
348{
349 if( Source.Source == m_xSelectionSupplier )
350 {
351 m_xSelectionSupplier.clear();
352 m_aSelectedRanges.realloc( 0 );
354 }
355}
356
358{
359 if( m_xSelectionSupplier.is())
360 {
361 if( ! m_xListener.is())
362 {
365 }
366 m_xSelectionSupplier->addSelectionChangeListener( m_xListener );
367 }
368}
369
371{
372 if( m_xSelectionSupplier.is() && m_xListener.is())
373 {
374 m_xSelectionSupplier->removeSelectionChangeListener( m_xListener );
375 m_xListener.clear();
376 }
377}
378
379// ____ WeakComponentImplHelperBase ____
380// is called when dispose() is called at this component
381void RangeHighlighter::disposing(std::unique_lock<std::mutex>&)
382{
383 // @todo: remove listener. Currently the controller shows an assertion
384 // because it is already disposed
385// stopListening();
386 m_xListener.clear();
387 m_xSelectionSupplier.clear();
389 m_aSelectedRanges.realloc( 0 );
390}
391
392} // namespace chart
393
394/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AnyEventRef aEvent
static bool isIncludeHiddenCells(const rtl::Reference<::chart::ChartModel > &xChartModel)
static SAL_DLLPRIVATE css::uno::Sequence< OUString > getUsedDataRanges(const rtl::Reference< ::chart::Diagram > &xDiagram)
static SAL_DLLPRIVATE css::uno::Sequence< OUString > getRangesFromLabeledDataSequence(const css::uno::Reference< css::chart2::data::XLabeledDataSequence > &xLSeq)
static SAL_DLLPRIVATE css::uno::Sequence< OUString > getRangesFromDataSource(const css::uno::Reference< css::chart2::data::XDataSource > &xSource)
static rtl::Reference< ::chart::DataSeries > getDataSeriesForCID(std::u16string_view rObjectCID, const rtl::Reference<::chart::ChartModel > &xChartModel)
static css::uno::Reference< css::beans::XPropertySet > getObjectPropertySet(std::u16string_view rObjectCID, const rtl::Reference< ::chart::ChartModel > &xChartDocument)
static sal_Int32 getIndexFromParticleOrCID(std::u16string_view rParticleOrCID)
static rtl::Reference< ::chart::Diagram > getDiagramForCID(std::u16string_view rObjectCID, const rtl::Reference<::chart::ChartModel > &xChartModel)
static std::u16string_view getFullParentParticle(std::u16string_view rCID)
ObjectType getObjectType() const
css::uno::Sequence< css::chart2::data::HighlightedRange > m_aSelectedRanges
virtual void SAL_CALL selectionChanged(const css::lang::EventObject &aEvent) override
virtual css::uno::Sequence< css::chart2::data::HighlightedRange > SAL_CALL getSelectedRanges() override
virtual ~RangeHighlighter() override
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
void fillRangesForCategories(const css::uno::Reference< css::chart2::XAxis > &xAxis)
void fillRangesForDataPoint(const rtl::Reference< ::chart::DataSeries > &xDataSeries, sal_Int32 nIndex)
RangeHighlighter(const rtl::Reference< ::chart::ChartModel > &xSelectionSupplier)
void fillRangesForDiagram(const rtl::Reference< ::chart::Diagram > &xDiagram)
comphelper::OInterfaceContainerHelper4< css::view::XSelectionChangeListener > maSelectionChangeListeners
css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier
void fillRangesForDataSeries(const css::uno::Reference< css::chart2::XDataSeries > &xSeries)
css::uno::Reference< css::view::XSelectionChangeListener > m_xListener
void fillRangesForErrorBars(const css::uno::Reference< css::beans::XPropertySet > &xErrorBar, const css::uno::Reference< css::chart2::XDataSeries > &xDataSeries)
virtual void SAL_CALL removeSelectionChangeListener(const css::uno::Reference< css::view::XSelectionChangeListener > &xListener) override
rtl::Reference< ::chart::ChartModel > m_xChartModel
virtual void SAL_CALL addSelectionChangeListener(const css::uno::Reference< css::view::XSelectionChangeListener > &xListener) override
void forEach(std::unique_lock< std::mutex > &rGuard, FuncT const &func) const
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
sal_Int32 getLength(std::unique_lock< std::mutex > &rGuard) const
sal_Int32 removeInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
constexpr ::Color COL_LIGHTBLUE(0x00, 0x00, 0xFF)
#define DBG_UNHANDLED_EXCEPTION(...)
sal_Int32 nIndex
constexpr OUStringLiteral aData
OOO_DLLPUBLIC_CHARTTOOLS sal_Int32 translateIndexFromHiddenToFullSequence(sal_Int32 nClippedIndex, const css::uno::Reference< css::chart2::data::XDataSequence > &xDataSequence, bool bTranslate)
@ OBJECTTYPE_DIAGRAM
@ OBJECTTYPE_LEGEND_ENTRY
@ OBJECTTYPE_DATA_ERRORS_X
@ OBJECTTYPE_DIAGRAM_FLOOR
@ OBJECTTYPE_DATA_POINT
@ OBJECTTYPE_DATA_ERRORS_Y
@ OBJECTTYPE_DATA_ERRORS_Z
@ OBJECTTYPE_DATA_LABEL
@ OBJECTTYPE_DIAGRAM_WALL
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
int i