Branch data Line data Source code
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 : :
21 : : #include "DataInterpreter.hxx"
22 : : #include "DataSeries.hxx"
23 : : #include "DataSourceHelper.hxx"
24 : : #include "DataSeriesHelper.hxx"
25 : : #include "macros.hxx"
26 : : #include "CommonConverters.hxx"
27 : : #include "ContainerHelper.hxx"
28 : : #include <com/sun/star/beans/XPropertySet.hpp>
29 : : #include <com/sun/star/chart2/data/XDataSink.hpp>
30 : :
31 : : #include <vector>
32 : : #include <algorithm>
33 : : #include <iterator>
34 : :
35 : : using namespace ::com::sun::star;
36 : : using namespace ::com::sun::star::chart2;
37 : : using namespace ::std;
38 : : using namespace ::chart::ContainerHelper;
39 : :
40 : : using ::com::sun::star::uno::Reference;
41 : : using ::com::sun::star::uno::Sequence;
42 : : using ::rtl::OUString;
43 : :
44 : : #if OSL_DEBUG_LEVEL > 1
45 : : namespace
46 : : {
47 : : void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource );
48 : : }
49 : : #endif
50 : :
51 : : namespace chart
52 : : {
53 : :
54 : 120 : DataInterpreter::DataInterpreter(
55 : : const Reference< uno::XComponentContext > & xContext ) :
56 : 120 : m_xContext( xContext )
57 : 120 : {}
58 : :
59 : 120 : DataInterpreter::~DataInterpreter()
60 [ - + ]: 230 : {}
61 : :
62 : 263 : Reference< uno::XComponentContext > DataInterpreter::GetComponentContext() const
63 : : {
64 : 263 : return m_xContext;
65 : : }
66 : :
67 : : // ____ XDataInterpreter ____
68 : 98 : InterpretedData SAL_CALL DataInterpreter::interpretDataSource(
69 : : const Reference< data::XDataSource >& xSource,
70 : : const Sequence< beans::PropertyValue >& aArguments,
71 : : const Sequence< Reference< XDataSeries > >& aSeriesToReUse )
72 : : throw (uno::RuntimeException)
73 : : {
74 [ + + ]: 98 : if( ! xSource.is())
75 [ + - ]: 6 : return InterpretedData();
76 : :
77 : : #if OSL_DEBUG_LEVEL > 1
78 : : lcl_ShowDataSource( xSource );
79 : : #endif
80 : :
81 [ + - ][ + - ]: 92 : Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() );
82 : :
83 : 92 : Reference< data::XLabeledDataSequence > xCategories;
84 [ + - ]: 92 : vector< Reference< data::XLabeledDataSequence > > aSequencesVec;
85 : :
86 : : // check if we should use categories
87 : :
88 [ + - ]: 92 : bool bHasCategories( HasCategories( aArguments, aData ));
89 : :
90 : : // parse data
91 : 92 : bool bCategoriesUsed = false;
92 [ + + ]: 630 : for( sal_Int32 i=0; i < aData.getLength(); ++i )
93 : : {
94 : : try
95 : : {
96 [ + + ][ + + ]: 538 : if( bHasCategories && ! bCategoriesUsed )
97 : : {
98 [ + - ][ + - ]: 87 : xCategories.set( aData[i] );
99 [ + - ]: 87 : if( xCategories.is())
100 [ + - ][ + - ]: 87 : SetRole( xCategories->getValues(), C2U("categories"));
[ + - ][ + - ]
101 : 87 : bCategoriesUsed = true;
102 : : }
103 : : else
104 : : {
105 [ + - ][ + - ]: 451 : aSequencesVec.push_back( aData[i] );
106 [ + - ][ + - ]: 451 : if( aData[i].is())
107 [ + - ][ + - ]: 451 : SetRole( aData[i]->getValues(), C2U("values-y"));
[ + - ][ + - ]
[ + - ][ # # ]
108 : : }
109 : : }
110 [ # # ]: 0 : catch( const uno::Exception & ex )
111 : : {
112 : : ASSERT_EXCEPTION( ex );
113 : : }
114 : : }
115 : :
116 : : // create DataSeries
117 : : vector< Reference< data::XLabeledDataSequence > >::const_iterator
118 [ + - ]: 92 : aSequencesVecIt = aSequencesVec.begin();
119 : :
120 : 92 : sal_Int32 nSeriesIndex = 0;
121 [ + - ]: 92 : vector< Reference< XDataSeries > > aSeriesVec;
122 [ + - ]: 92 : aSeriesVec.reserve( aSequencesVec.size());
123 : :
124 [ + - ][ + + ]: 543 : for( ;aSequencesVecIt != aSequencesVec.end(); ++aSequencesVecIt, ++nSeriesIndex )
125 : : {
126 [ + - ]: 451 : Sequence< Reference< data::XLabeledDataSequence > > aNewData( & (*aSequencesVecIt), 1 );
127 : 451 : Reference< XDataSeries > xSeries;
128 [ + + ]: 451 : if( nSeriesIndex < aSeriesToReUse.getLength())
129 [ + - ]: 188 : xSeries.set( aSeriesToReUse[nSeriesIndex] );
130 : : else
131 [ + - ][ + - ]: 263 : xSeries.set( new DataSeries( GetComponentContext() ));
[ + - ][ + - ]
132 : : OSL_ASSERT( xSeries.is() );
133 [ + - ]: 451 : Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY );
134 : : OSL_ASSERT( xSink.is() );
135 [ + - ][ + - ]: 451 : xSink->setData( aNewData );
136 : :
137 [ + - ]: 451 : aSeriesVec.push_back( xSeries );
138 [ + - ]: 451 : }
139 : :
140 [ + - ]: 92 : Sequence< Sequence< Reference< XDataSeries > > > aSeries(1);
141 [ + - ][ + - ]: 92 : aSeries[0] = ContainerToSequence( aSeriesVec );
[ + - ][ + - ]
142 [ + - ][ + - ]: 98 : return InterpretedData( aSeries, xCategories );
[ + - ]
143 : : }
144 : :
145 : 12 : InterpretedData SAL_CALL DataInterpreter::reinterpretDataSeries(
146 : : const InterpretedData& aInterpretedData )
147 : : throw (uno::RuntimeException)
148 : : {
149 [ + - ]: 12 : InterpretedData aResult( aInterpretedData );
150 : :
151 : 12 : sal_Int32 i=0;
152 [ + - ]: 12 : Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
153 : 12 : const sal_Int32 nCount = aSeries.getLength();
154 [ + + ]: 88 : for( ; i<nCount; ++i )
155 : : {
156 : : try
157 : : {
158 [ + - ][ + - ]: 76 : Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW );
159 [ + - ]: 76 : Sequence< Reference< data::XLabeledDataSequence > > aNewSequences;
160 : :
161 : : // values-y
162 : : Reference< data::XLabeledDataSequence > xValuesY(
163 [ + - ][ + - ]: 76 : DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false ));
164 : : // re-use values-... as values-y
165 [ - + ]: 76 : if( ! xValuesY.is())
166 : : {
167 : : xValuesY.set(
168 [ # # ][ # # ]: 0 : DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values"), true ));
[ # # ]
169 [ # # ]: 0 : if( xValuesY.is())
170 [ # # ][ # # ]: 0 : SetRole( xValuesY->getValues(), C2U("values-y"));
[ # # ][ # # ]
171 : : }
172 [ + - ]: 76 : if( xValuesY.is())
173 : : {
174 [ + - ]: 76 : aNewSequences.realloc(1);
175 [ + - ][ + - ]: 76 : aNewSequences[0] = xValuesY;
176 : : }
177 : :
178 [ + - ][ + - ]: 76 : Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences());
179 [ - + ]: 76 : if( aSeqs.getLength() != aNewSequences.getLength() )
180 : : {
181 : : #if OSL_DEBUG_LEVEL > 1
182 : : sal_Int32 j=0;
183 : : for( ; j<aSeqs.getLength(); ++j )
184 : : {
185 : : OSL_ENSURE( aSeqs[j] == xValuesY, "All sequences should be used" );
186 : : }
187 : : #endif
188 [ # # ]: 0 : Reference< data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY_THROW );
189 [ # # ][ # # ]: 0 : xSink->setData( aNewSequences );
190 [ + - ][ + - ]: 76 : }
[ # # ]
191 : : }
192 [ # # ]: 0 : catch( const uno::Exception & ex )
193 : : {
194 : : ASSERT_EXCEPTION( ex );
195 : : }
196 : : }
197 : :
198 [ + - ]: 12 : return aResult;
199 : : }
200 : :
201 : : // criterion: all series must have exactly one data::XLabeledDataSequence
202 : 16 : sal_Bool SAL_CALL DataInterpreter::isDataCompatible(
203 : : const chart2::InterpretedData& aInterpretedData )
204 : : throw (uno::RuntimeException)
205 : : {
206 [ + - ]: 16 : Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
207 [ + + ]: 92 : for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
208 : : {
209 : : try
210 : : {
211 [ + - ][ + - ]: 80 : Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW );
212 [ + - ][ + - ]: 80 : Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
213 [ + + ]: 80 : if( aSeq.getLength() != 1 )
214 [ + - ][ + + ]: 80 : return sal_False;
[ + + ][ # # ]
215 : : }
216 [ # # ]: 0 : catch( const uno::Exception & ex )
217 : : {
218 : : ASSERT_EXCEPTION( ex );
219 : : }
220 : : }
221 : :
222 [ + - ]: 16 : return sal_True;
223 : : }
224 : :
225 : : namespace
226 : : {
227 : :
228 : 486 : struct lcl_LabeledSequenceEquals : public std::unary_function< Reference< data::XLabeledDataSequence >, bool >
229 : : {
230 : 162 : lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) :
231 : : m_bHasLabels ( false ),
232 : 162 : m_bHasValues ( false )
233 : : {
234 [ + - ]: 162 : if( xLSeqToCmp.is())
235 : : {
236 [ + - ][ + - ]: 162 : Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues());
237 [ + - ]: 162 : if( xSeq.is())
238 : : {
239 : 162 : m_bHasValues = true;
240 [ + - ][ + - ]: 162 : m_aValuesRangeRep = xSeq->getSourceRangeRepresentation();
241 : : }
242 : :
243 [ + - ][ + - ]: 162 : xSeq.set( xLSeqToCmp->getLabel());
[ + - ]
244 [ + - ]: 162 : if( xSeq.is())
245 : : {
246 : 162 : m_bHasLabels = true;
247 [ + - ][ + - ]: 162 : m_aLabelRangeRep = xSeq->getSourceRangeRepresentation();
248 : 162 : }
249 : : }
250 : 162 : }
251 : :
252 : 1104 : bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq )
253 : : {
254 [ - + ]: 1104 : if( ! xSeq.is())
255 : 0 : return false;
256 : :
257 [ + - ][ + - ]: 1104 : Reference< data::XDataSequence > xSeqValues( xSeq->getValues() );
258 [ + - ][ + - ]: 1104 : Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() );
259 : 1104 : bool bHasValues = xSeqValues.is();
260 : 1104 : bool bHasLabels = xSeqLabels.is();
261 : :
262 : : return ( ( (m_bHasValues == bHasValues) &&
263 [ + - ][ + - ]: 2208 : (!bHasValues || m_aValuesRangeRep.equals( xSeqValues->getSourceRangeRepresentation())) ) &&
[ + - ][ # # ]
264 : : ( (m_bHasLabels == bHasLabels) &&
265 [ # # ][ # # ]: 1104 : (!bHasLabels || m_aLabelRangeRep.equals( xSeqLabels->getSourceRangeRepresentation())) )
[ - + ][ # # ]
266 [ + - - + ]: 3312 : );
[ # # ]
[ # # # # ]
[ + - ]
267 : : }
268 : :
269 : : private:
270 : : bool m_bHasLabels;
271 : : bool m_bHasValues;
272 : : OUString m_aValuesRangeRep;
273 : : OUString m_aLabelRangeRep;
274 : : };
275 : :
276 : : } // anonymous namespace
277 : :
278 : 14 : Reference< data::XDataSource > SAL_CALL DataInterpreter::mergeInterpretedData(
279 : : const InterpretedData& aInterpretedData )
280 : : throw (uno::RuntimeException)
281 : : {
282 [ + - ]: 14 : vector< Reference< data::XLabeledDataSequence > > aResultVec;
283 : 14 : aResultVec.reserve( aInterpretedData.Series.getLength() +
284 : : 1 // categories
285 [ + - ]: 14 : );
286 : :
287 [ + - ]: 14 : if( aInterpretedData.Categories.is())
288 [ + - ]: 14 : aResultVec.push_back( aInterpretedData.Categories );
289 : :
290 [ + - ]: 14 : Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
291 [ + + ]: 144 : for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx )
292 : : {
293 : : try
294 : : {
295 [ + - ][ + - ]: 130 : Reference< data::XDataSource > xSrc( aSeries[nSeriesIdx], uno::UNO_QUERY_THROW );
296 [ + - ][ + - ]: 130 : Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
297 : :
298 : : // add all sequences of data series
299 [ + + ]: 292 : for( sal_Int32 nSeqIdx=0; nSeqIdx<aSeq.getLength(); ++nSeqIdx )
300 : : {
301 [ + - ]: 162 : Reference< data::XLabeledDataSequence > xAdd( aSeq[nSeqIdx] );
302 : :
303 : : // only add if sequence is not yet in the result
304 [ + - + - ]: 324 : if( find_if( aResultVec.begin(), aResultVec.end(),
305 [ + - ][ + - ]: 324 : lcl_LabeledSequenceEquals( xAdd )) == aResultVec.end())
306 : : {
307 [ + - ]: 162 : aResultVec.push_back( xAdd );
308 : : }
309 [ + - ][ # # ]: 292 : }
310 : : }
311 [ # # ]: 0 : catch( const uno::Exception & ex )
312 : : {
313 : : ASSERT_EXCEPTION( ex );
314 : : }
315 : : }
316 : :
317 [ + - ][ + - ]: 14 : return Reference< data::XDataSource >( DataSourceHelper::createDataSource( ContainerToSequence( aResultVec ) ) );
[ + - ][ + - ]
318 : : }
319 : :
320 : : // convenience methods
321 : :
322 : 26 : OUString DataInterpreter::GetRole( const Reference< data::XDataSequence > & xSeq )
323 : : {
324 : 26 : OUString aResult;
325 [ - + ]: 26 : if( ! xSeq.is())
326 : 0 : return aResult;
327 : :
328 : : try
329 : : {
330 [ + - ]: 26 : Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
331 [ + - ][ + - ]: 26 : xProp->getPropertyValue( C2U("Role")) >>= aResult;
[ + - ][ # # ]
332 : : }
333 [ # # ]: 0 : catch( const uno::Exception & ex )
334 : : {
335 : : ASSERT_EXCEPTION( ex );
336 : : }
337 : 26 : return aResult;
338 : : }
339 : :
340 : 654 : void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole )
341 : : {
342 [ + + ]: 654 : if( ! xSeq.is())
343 : 654 : return;
344 : : try
345 : : {
346 [ + - ]: 652 : Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
347 [ + - ][ + - ]: 652 : xProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole ));
[ + - ][ + - ]
[ # # ]
348 : : }
349 : 0 : catch( const uno::Exception & ex )
350 : : {
351 : : ASSERT_EXCEPTION( ex );
352 : : }
353 : : }
354 : :
355 : 108 : uno::Any DataInterpreter::GetProperty(
356 : : const Sequence< beans::PropertyValue > & aArguments,
357 : : const OUString & rName )
358 : : {
359 [ + + ]: 168 : for( sal_Int32 i=aArguments.getLength(); i--; )
360 : : {
361 [ + + ]: 162 : if( aArguments[i].Name.equals( rName ))
362 : 102 : return aArguments[i].Value;
363 : : }
364 : 108 : return uno::Any();
365 : : }
366 : :
367 : 102 : bool DataInterpreter::HasCategories(
368 : : const Sequence< beans::PropertyValue > & rArguments,
369 : : const Sequence< Reference< data::XLabeledDataSequence > > & rData )
370 : : {
371 : 102 : bool bHasCategories = false;
372 : :
373 [ + - ]: 102 : if( rArguments.getLength() > 0 )
374 [ + - ][ + - ]: 102 : GetProperty( rArguments, C2U(("HasCategories"))) >>= bHasCategories;
375 : :
376 [ + + ][ + + ]: 128 : for( sal_Int32 nLSeqIdx=0; ! bHasCategories && nLSeqIdx<rData.getLength(); ++nLSeqIdx )
[ + + ]
377 [ + - ][ + - ]: 26 : bHasCategories = ( rData[nLSeqIdx].is() && GetRole( rData[nLSeqIdx]->getValues() ) == "categories");
[ + - ][ + - ]
[ - + ][ + - ]
[ + - ]
[ # # # # ]
378 : :
379 : 102 : return bHasCategories;
380 : : }
381 : :
382 : 6 : bool DataInterpreter::UseCategoriesAsX( const Sequence< beans::PropertyValue > & rArguments )
383 : : {
384 : 6 : bool bUseCategoriesAsX = true;
385 [ + - ]: 6 : if( rArguments.getLength() > 0 )
386 [ + - ][ + - ]: 6 : GetProperty( rArguments, C2U(("UseCategoriesAsX"))) >>= bUseCategoriesAsX;
387 : 6 : return bUseCategoriesAsX;
388 : : }
389 : :
390 : : // ------------------------------------------------------------
391 : :
392 : 0 : Sequence< OUString > DataInterpreter::getSupportedServiceNames_Static()
393 : : {
394 : 0 : Sequence< OUString > aServices( 1 );
395 [ # # ][ # # ]: 0 : aServices[0] = C2U( "com.sun.star.chart2.DataInterpreter" );
396 : 0 : return aServices;
397 : : }
398 : :
399 : : // implement XServiceInfo methods basing upon getSupportedServiceNames_Static
400 [ # # ][ # # ]: 0 : APPHELPER_XSERVICEINFO_IMPL( DataInterpreter, C2U("com.sun.star.comp.chart2.DataInterpreter"));
[ # # ][ # # ]
[ # # ]
401 : :
402 : : } // namespace chart
403 : :
404 : : #if OSL_DEBUG_LEVEL > 1
405 : : namespace
406 : : {
407 : :
408 : : void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource )
409 : : {
410 : : if( ! xSource.is())
411 : : return;
412 : :
413 : : OSL_TRACE( "DataSource in DataInterpreter:" );
414 : : Sequence< Reference< data::XLabeledDataSequence > > aSequences( xSource->getDataSequences());
415 : : Reference< beans::XPropertySet > xProp;
416 : : OUString aId;
417 : : const sal_Int32 nMax = aSequences.getLength();
418 : : for( sal_Int32 k = 0; k < nMax; ++k )
419 : : {
420 : : if( aSequences[k].is())
421 : : {
422 : : OUString aSourceRepr(C2U("<none>"));
423 : : if( aSequences[k]->getValues().is())
424 : : aSourceRepr = aSequences[k]->getValues()->getSourceRangeRepresentation();
425 : : xProp.set( aSequences[k]->getValues(), uno::UNO_QUERY );
426 : : if( xProp.is() &&
427 : : ( xProp->getPropertyValue( C2U( "Role" )) >>= aId ))
428 : : {
429 : : OSL_TRACE( " <data sequence %d> Role: %s, Source: %s", k, U2C( aId ), U2C( aSourceRepr ));
430 : : }
431 : : else
432 : : {
433 : : OSL_TRACE( " <data sequence %d> unknown Role, Source: %s", k, U2C( aSourceRepr ) );
434 : : }
435 : :
436 : : aSourceRepr = C2U("<none>");
437 : : if( aSequences[k]->getLabel().is())
438 : : aSourceRepr = OUString( aSequences[k]->getLabel()->getSourceRangeRepresentation());
439 : : xProp.set( aSequences[k]->getLabel(), uno::UNO_QUERY );
440 : : if( xProp.is() &&
441 : : ( xProp->getPropertyValue( C2U( "Role" )) >>= aId ))
442 : : {
443 : : OSL_TRACE( " <data sequence label %d> Role: %s, Source: %s", k, U2C( aId ), U2C( aSourceRepr ));
444 : : }
445 : : else
446 : : {
447 : : OSL_TRACE( " <data sequence label %d> unknown Role, Source: %s", k, U2C( aSourceRepr ) );
448 : : }
449 : : }
450 : : }
451 : : }
452 : :
453 : : }
454 : : #endif
455 : :
456 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|