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