xref: /trunk/main/chart2/source/model/template/DataInterpreter.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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