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::__anon296167bb0211::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::__anon296167bb0211::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