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