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 41 : DataInterpreter::DataInterpreter(
55 : const Reference< uno::XComponentContext > & xContext ) :
56 41 : m_xContext( xContext )
57 41 : {}
58 :
59 82 : DataInterpreter::~DataInterpreter()
60 82 : {}
61 :
62 123 : Reference< uno::XComponentContext > DataInterpreter::GetComponentContext() const
63 : {
64 123 : return m_xContext;
65 : }
66 :
67 : // ____ XDataInterpreter ____
68 41 : 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 41 : if( ! xSource.is())
75 0 : return InterpretedData();
76 :
77 : #if OSL_DEBUG_LEVEL > 1
78 : lcl_ShowDataSource( xSource );
79 : #endif
80 :
81 41 : Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() );
82 :
83 41 : Reference< data::XLabeledDataSequence > xCategories;
84 41 : vector< Reference< data::XLabeledDataSequence > > aSequencesVec;
85 :
86 : // check if we should use categories
87 :
88 41 : bool bHasCategories( HasCategories( aArguments, aData ));
89 :
90 : // parse data
91 41 : bool bCategoriesUsed = false;
92 205 : for( sal_Int32 i=0; i < aData.getLength(); ++i )
93 : {
94 : try
95 : {
96 164 : if( bHasCategories && ! bCategoriesUsed )
97 : {
98 41 : xCategories.set( aData[i] );
99 41 : if( xCategories.is())
100 41 : SetRole( xCategories->getValues(), C2U("categories"));
101 41 : bCategoriesUsed = true;
102 : }
103 : else
104 : {
105 123 : aSequencesVec.push_back( aData[i] );
106 123 : if( aData[i].is())
107 123 : 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 41 : aSequencesVecIt = aSequencesVec.begin();
119 :
120 41 : sal_Int32 nSeriesIndex = 0;
121 41 : vector< Reference< XDataSeries > > aSeriesVec;
122 41 : aSeriesVec.reserve( aSequencesVec.size());
123 :
124 164 : for( ;aSequencesVecIt != aSequencesVec.end(); ++aSequencesVecIt, ++nSeriesIndex )
125 : {
126 123 : Sequence< Reference< data::XLabeledDataSequence > > aNewData( & (*aSequencesVecIt), 1 );
127 123 : Reference< XDataSeries > xSeries;
128 123 : if( nSeriesIndex < aSeriesToReUse.getLength())
129 0 : xSeries.set( aSeriesToReUse[nSeriesIndex] );
130 : else
131 123 : xSeries.set( new DataSeries( GetComponentContext() ));
132 : OSL_ASSERT( xSeries.is() );
133 123 : Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY );
134 : OSL_ASSERT( xSink.is() );
135 123 : xSink->setData( aNewData );
136 :
137 123 : aSeriesVec.push_back( xSeries );
138 123 : }
139 :
140 41 : Sequence< Sequence< Reference< XDataSeries > > > aSeries(1);
141 41 : aSeries[0] = ContainerToSequence( aSeriesVec );
142 41 : return InterpretedData( aSeries, xCategories );
143 : }
144 :
145 0 : InterpretedData SAL_CALL DataInterpreter::reinterpretDataSeries(
146 : const InterpretedData& aInterpretedData )
147 : throw (uno::RuntimeException)
148 : {
149 0 : InterpretedData aResult( aInterpretedData );
150 :
151 0 : sal_Int32 i=0;
152 0 : Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
153 0 : const sal_Int32 nCount = aSeries.getLength();
154 0 : for( ; i<nCount; ++i )
155 : {
156 : try
157 : {
158 0 : Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW );
159 0 : Sequence< Reference< data::XLabeledDataSequence > > aNewSequences;
160 :
161 : // values-y
162 : Reference< data::XLabeledDataSequence > xValuesY(
163 0 : DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false ));
164 : // re-use values-... as values-y
165 0 : 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 0 : if( xValuesY.is())
173 : {
174 0 : aNewSequences.realloc(1);
175 0 : aNewSequences[0] = xValuesY;
176 : }
177 :
178 0 : Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences());
179 0 : 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 0 : }
191 : }
192 0 : catch( const uno::Exception & ex )
193 : {
194 : ASSERT_EXCEPTION( ex );
195 : }
196 : }
197 :
198 0 : return aResult;
199 : }
200 :
201 : // criterion: all series must have exactly one data::XLabeledDataSequence
202 0 : sal_Bool SAL_CALL DataInterpreter::isDataCompatible(
203 : const chart2::InterpretedData& aInterpretedData )
204 : throw (uno::RuntimeException)
205 : {
206 0 : Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
207 0 : for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
208 : {
209 : try
210 : {
211 0 : Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW );
212 0 : Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
213 0 : if( aSeq.getLength() != 1 )
214 0 : return sal_False;
215 : }
216 0 : catch( const uno::Exception & ex )
217 : {
218 : ASSERT_EXCEPTION( ex );
219 : }
220 : }
221 :
222 0 : return sal_True;
223 : }
224 :
225 : namespace
226 : {
227 :
228 0 : struct lcl_LabeledSequenceEquals : public std::unary_function< Reference< data::XLabeledDataSequence >, bool >
229 : {
230 0 : lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) :
231 : m_bHasLabels ( false ),
232 0 : m_bHasValues ( false )
233 : {
234 0 : if( xLSeqToCmp.is())
235 : {
236 0 : Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues());
237 0 : if( xSeq.is())
238 : {
239 0 : m_bHasValues = true;
240 0 : m_aValuesRangeRep = xSeq->getSourceRangeRepresentation();
241 : }
242 :
243 0 : xSeq.set( xLSeqToCmp->getLabel());
244 0 : if( xSeq.is())
245 : {
246 0 : m_bHasLabels = true;
247 0 : m_aLabelRangeRep = xSeq->getSourceRangeRepresentation();
248 0 : }
249 : }
250 0 : }
251 :
252 0 : bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq )
253 : {
254 0 : if( ! xSeq.is())
255 0 : return false;
256 :
257 0 : Reference< data::XDataSequence > xSeqValues( xSeq->getValues() );
258 0 : Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() );
259 0 : bool bHasValues = xSeqValues.is();
260 0 : bool bHasLabels = xSeqLabels.is();
261 :
262 : return ( ( (m_bHasValues == bHasValues) &&
263 0 : (!bHasValues || m_aValuesRangeRep.equals( xSeqValues->getSourceRangeRepresentation())) ) &&
264 : ( (m_bHasLabels == bHasLabels) &&
265 0 : (!bHasLabels || m_aLabelRangeRep.equals( xSeqLabels->getSourceRangeRepresentation())) )
266 0 : );
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 0 : Reference< data::XDataSource > SAL_CALL DataInterpreter::mergeInterpretedData(
279 : const InterpretedData& aInterpretedData )
280 : throw (uno::RuntimeException)
281 : {
282 0 : vector< Reference< data::XLabeledDataSequence > > aResultVec;
283 0 : aResultVec.reserve( aInterpretedData.Series.getLength() +
284 : 1 // categories
285 0 : );
286 :
287 0 : if( aInterpretedData.Categories.is())
288 0 : aResultVec.push_back( aInterpretedData.Categories );
289 :
290 0 : Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
291 0 : for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx )
292 : {
293 : try
294 : {
295 0 : Reference< data::XDataSource > xSrc( aSeries[nSeriesIdx], uno::UNO_QUERY_THROW );
296 0 : Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
297 :
298 : // add all sequences of data series
299 0 : for( sal_Int32 nSeqIdx=0; nSeqIdx<aSeq.getLength(); ++nSeqIdx )
300 : {
301 0 : Reference< data::XLabeledDataSequence > xAdd( aSeq[nSeqIdx] );
302 :
303 : // only add if sequence is not yet in the result
304 0 : if( find_if( aResultVec.begin(), aResultVec.end(),
305 0 : lcl_LabeledSequenceEquals( xAdd )) == aResultVec.end())
306 : {
307 0 : aResultVec.push_back( xAdd );
308 : }
309 0 : }
310 : }
311 0 : catch( const uno::Exception & ex )
312 : {
313 : ASSERT_EXCEPTION( ex );
314 : }
315 : }
316 :
317 0 : return Reference< data::XDataSource >( DataSourceHelper::createDataSource( ContainerToSequence( aResultVec ) ) );
318 : }
319 :
320 : // convenience methods
321 :
322 0 : OUString DataInterpreter::GetRole( const Reference< data::XDataSequence > & xSeq )
323 : {
324 0 : OUString aResult;
325 0 : if( ! xSeq.is())
326 0 : return aResult;
327 :
328 : try
329 : {
330 0 : Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
331 0 : xProp->getPropertyValue( C2U("Role")) >>= aResult;
332 : }
333 0 : catch( const uno::Exception & ex )
334 : {
335 : ASSERT_EXCEPTION( ex );
336 : }
337 0 : return aResult;
338 : }
339 :
340 164 : void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole )
341 : {
342 164 : if( ! xSeq.is())
343 164 : return;
344 : try
345 : {
346 164 : Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
347 164 : xProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole ));
348 : }
349 0 : catch( const uno::Exception & ex )
350 : {
351 : ASSERT_EXCEPTION( ex );
352 : }
353 : }
354 :
355 41 : uno::Any DataInterpreter::GetProperty(
356 : const Sequence< beans::PropertyValue > & aArguments,
357 : const OUString & rName )
358 : {
359 82 : for( sal_Int32 i=aArguments.getLength(); i--; )
360 : {
361 41 : if( aArguments[i].Name.equals( rName ))
362 41 : return aArguments[i].Value;
363 : }
364 0 : return uno::Any();
365 : }
366 :
367 41 : bool DataInterpreter::HasCategories(
368 : const Sequence< beans::PropertyValue > & rArguments,
369 : const Sequence< Reference< data::XLabeledDataSequence > > & rData )
370 : {
371 41 : bool bHasCategories = false;
372 :
373 41 : if( rArguments.getLength() > 0 )
374 41 : GetProperty( rArguments, C2U(("HasCategories"))) >>= bHasCategories;
375 :
376 41 : for( sal_Int32 nLSeqIdx=0; ! bHasCategories && nLSeqIdx<rData.getLength(); ++nLSeqIdx )
377 0 : bHasCategories = ( rData[nLSeqIdx].is() && GetRole( rData[nLSeqIdx]->getValues() ) == "categories");
378 :
379 41 : return bHasCategories;
380 : }
381 :
382 0 : bool DataInterpreter::UseCategoriesAsX( const Sequence< beans::PropertyValue > & rArguments )
383 : {
384 0 : bool bUseCategoriesAsX = true;
385 0 : if( rArguments.getLength() > 0 )
386 0 : GetProperty( rArguments, C2U(("UseCategoriesAsX"))) >>= bUseCategoriesAsX;
387 0 : 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: */
|