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