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