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