1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: DataInterpreter.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
34 #include "DataInterpreter.hxx"
35 #include "DataSeries.hxx"
36 #include "DataSourceHelper.hxx"
37 #include "DataSeriesHelper.hxx"
39 #include "CommonConverters.hxx"
40 #include "ContainerHelper.hxx"
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/chart2/data/XDataSink.hpp>
48 using namespace ::com::sun::star
;
49 using namespace ::com::sun::star::chart2
;
50 using namespace ::std
;
51 using namespace ::chart::ContainerHelper
;
53 using ::com::sun::star::uno::Reference
;
54 using ::com::sun::star::uno::Sequence
;
55 using ::rtl::OUString
;
57 #if OSL_DEBUG_LEVEL > 1
60 void lcl_ShowDataSource( const Reference
< data::XDataSource
> & xSource
);
67 DataInterpreter::DataInterpreter(
68 const Reference
< uno::XComponentContext
> & xContext
) :
69 m_xContext( xContext
)
72 DataInterpreter::~DataInterpreter()
75 Reference
< uno::XComponentContext
> DataInterpreter::GetComponentContext() const
80 // ____ XDataInterpreter ____
81 InterpretedData SAL_CALL
DataInterpreter::interpretDataSource(
82 const Reference
< data::XDataSource
>& xSource
,
83 const Sequence
< beans::PropertyValue
>& aArguments
,
84 const Sequence
< Reference
< XDataSeries
> >& aSeriesToReUse
)
85 throw (uno::RuntimeException
)
88 return InterpretedData();
90 #if OSL_DEBUG_LEVEL > 2
91 lcl_ShowDataSource( xSource
);
94 Sequence
< Reference
< data::XLabeledDataSequence
> > aData( xSource
->getDataSequences() );
96 Reference
< data::XLabeledDataSequence
> xCategories
;
97 vector
< Reference
< data::XLabeledDataSequence
> > aSequencesVec
;
99 // check if we should use categories
101 bool bHasCategories( HasCategories( aArguments
, aData
));
104 bool bCategoriesUsed
= false;
105 for( sal_Int32 i
=0; i
< aData
.getLength(); ++i
)
109 if( bHasCategories
&& ! bCategoriesUsed
)
111 xCategories
.set( aData
[i
] );
112 if( xCategories
.is())
113 SetRole( xCategories
->getValues(), C2U("categories"));
114 bCategoriesUsed
= true;
118 aSequencesVec
.push_back( aData
[i
] );
120 SetRole( aData
[i
]->getValues(), C2U("values-y"));
123 catch( uno::Exception
& ex
)
125 ASSERT_EXCEPTION( ex
);
130 vector
< Reference
< data::XLabeledDataSequence
> >::const_iterator
131 aSequencesVecIt
= aSequencesVec
.begin();
133 sal_Int32 nSeriesIndex
= 0;
134 vector
< Reference
< XDataSeries
> > aSeriesVec
;
135 aSeriesVec
.reserve( aSequencesVec
.size());
137 for( ;aSequencesVecIt
!= aSequencesVec
.end(); ++aSequencesVecIt
, ++nSeriesIndex
)
139 Sequence
< Reference
< data::XLabeledDataSequence
> > aNewData( & (*aSequencesVecIt
), 1 );
140 Reference
< XDataSeries
> xSeries
;
141 if( nSeriesIndex
< aSeriesToReUse
.getLength())
142 xSeries
.set( aSeriesToReUse
[nSeriesIndex
] );
144 xSeries
.set( new DataSeries( GetComponentContext() ));
145 OSL_ASSERT( xSeries
.is() );
146 Reference
< data::XDataSink
> xSink( xSeries
, uno::UNO_QUERY
);
147 OSL_ASSERT( xSink
.is() );
148 xSink
->setData( aNewData
);
150 aSeriesVec
.push_back( xSeries
);
153 Sequence
< Sequence
< Reference
< XDataSeries
> > > aSeries(1);
154 aSeries
[0] = ContainerToSequence( aSeriesVec
);
155 return InterpretedData( aSeries
, xCategories
, Sequence
< Reference
< data::XLabeledDataSequence
> >() );
158 InterpretedData SAL_CALL
DataInterpreter::reinterpretDataSeries(
159 const InterpretedData
& aInterpretedData
)
160 throw (uno::RuntimeException
)
162 InterpretedData
aResult( aInterpretedData
);
163 vector
< Reference
< data::XLabeledDataSequence
> > aUnused(
164 SequenceToVector( aInterpretedData
.UnusedData
));
167 Sequence
< Reference
< XDataSeries
> > aSeries( FlattenSequence( aInterpretedData
.Series
));
168 const sal_Int32 nCount
= aSeries
.getLength();
169 for( ; i
<nCount
; ++i
)
173 Reference
< data::XDataSource
> xSeriesSource( aSeries
[i
], uno::UNO_QUERY_THROW
);
174 Sequence
< Reference
< data::XLabeledDataSequence
> > aNewSequences
;
177 Reference
< data::XLabeledDataSequence
> xValuesY(
178 DataSeriesHelper::getDataSequenceByRole( xSeriesSource
, C2U("values-y"), false ));
179 // re-use values-... as values-y
183 DataSeriesHelper::getDataSequenceByRole( xSeriesSource
, C2U("values"), true ));
185 SetRole( xValuesY
->getValues(), C2U("values-y"));
189 aNewSequences
.realloc(1);
190 aNewSequences
[0] = xValuesY
;
193 Sequence
< Reference
< data::XLabeledDataSequence
> > aSeqs( xSeriesSource
->getDataSequences());
194 if( aSeqs
.getLength() != aNewSequences
.getLength() )
197 for( ; j
<aSeqs
.getLength(); ++j
)
199 if( aSeqs
[j
] != xValuesY
)
200 aUnused
.push_back( aSeqs
[j
] );
202 Reference
< data::XDataSink
> xSink( xSeriesSource
, uno::UNO_QUERY_THROW
);
204 xSink
->setData( aNewSequences
);
207 catch( uno::Exception
& ex
)
209 ASSERT_EXCEPTION( ex
);
213 aResult
.UnusedData
= ContainerToSequence( aUnused
);
218 // criterion: all series must have exactly one data::XLabeledDataSequence
219 sal_Bool SAL_CALL
DataInterpreter::isDataCompatible(
220 const chart2::InterpretedData
& aInterpretedData
)
221 throw (uno::RuntimeException
)
223 Sequence
< Reference
< XDataSeries
> > aSeries( FlattenSequence( aInterpretedData
.Series
));
224 for( sal_Int32 i
=0; i
<aSeries
.getLength(); ++i
)
228 Reference
< data::XDataSource
> xSrc( aSeries
[i
], uno::UNO_QUERY_THROW
);
229 Sequence
< Reference
< data::XLabeledDataSequence
> > aSeq( xSrc
->getDataSequences());
230 if( aSeq
.getLength() != 1 )
233 catch( uno::Exception
& ex
)
235 ASSERT_EXCEPTION( ex
);
245 struct lcl_LabeledSequenceEquals
: public unary_function
< Reference
< data::XLabeledDataSequence
>, bool >
247 lcl_LabeledSequenceEquals( const Reference
< data::XLabeledDataSequence
> & xLSeqToCmp
) :
248 m_bHasLabels ( false ),
249 m_bHasValues ( false )
253 Reference
< data::XDataSequence
> xSeq( xLSeqToCmp
->getValues());
257 m_aValuesRangeRep
= xSeq
->getSourceRangeRepresentation();
260 xSeq
.set( xLSeqToCmp
->getLabel());
264 m_aLabelRangeRep
= xSeq
->getSourceRangeRepresentation();
269 bool operator() ( const Reference
< data::XLabeledDataSequence
> & xSeq
)
274 Reference
< data::XDataSequence
> xSeqValues( xSeq
->getValues() );
275 Reference
< data::XDataSequence
> xSeqLabels( xSeq
->getLabel() );
276 bool bHasValues
= xSeqValues
.is();
277 bool bHasLabels
= xSeqLabels
.is();
279 return ( ( (m_bHasValues
== bHasValues
) &&
280 (!bHasValues
|| m_aValuesRangeRep
.equals( xSeqValues
->getSourceRangeRepresentation())) ) &&
281 ( (m_bHasLabels
== bHasLabels
) &&
282 (!bHasLabels
|| m_aLabelRangeRep
.equals( xSeqLabels
->getSourceRangeRepresentation())) )
289 OUString m_aValuesRangeRep
;
290 OUString m_aLabelRangeRep
;
293 } // anonymous namespace
295 Reference
< data::XDataSource
> SAL_CALL
DataInterpreter::mergeInterpretedData(
296 const InterpretedData
& aInterpretedData
)
297 throw (uno::RuntimeException
)
299 vector
< Reference
< data::XLabeledDataSequence
> > aResultVec
;
300 vector
< Reference
< data::XLabeledDataSequence
> > aUnusedDataVec
;
301 aResultVec
.reserve( aInterpretedData
.Series
.getLength() +
302 aInterpretedData
.UnusedData
.getLength() +
306 if( aInterpretedData
.Categories
.is())
307 aResultVec
.push_back( aInterpretedData
.Categories
);
309 // add unused data that has the Role categories at front
310 if( aInterpretedData
.UnusedData
.getLength())
312 sal_Int32 nSize
= aInterpretedData
.UnusedData
.getLength();
313 for( sal_Int32 i
=0; i
<nSize
; ++i
)
315 Reference
< data::XLabeledDataSequence
> xPotentialCategories( aInterpretedData
.UnusedData
[i
] );
316 if( xPotentialCategories
.is() )
318 if( GetRole( xPotentialCategories
->getValues()).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("categories")))
319 aResultVec
.push_back( xPotentialCategories
);
321 aUnusedDataVec
.push_back( xPotentialCategories
);
326 aUnusedDataVec
= SequenceToVector( aInterpretedData
.UnusedData
);
328 Sequence
< Reference
< XDataSeries
> > aSeries( FlattenSequence( aInterpretedData
.Series
));
329 for( sal_Int32 nSeriesIdx
=0; nSeriesIdx
<aSeries
.getLength(); ++nSeriesIdx
)
333 Reference
< data::XDataSource
> xSrc( aSeries
[nSeriesIdx
], uno::UNO_QUERY_THROW
);
334 Sequence
< Reference
< data::XLabeledDataSequence
> > aSeq( xSrc
->getDataSequences());
336 // add all sequences of data series
337 for( sal_Int32 nSeqIdx
=0; nSeqIdx
<aSeq
.getLength(); ++nSeqIdx
)
339 Reference
< data::XLabeledDataSequence
> xAdd( aSeq
[nSeqIdx
] );
341 // only add if sequence is not yet in the result
342 if( find_if( aResultVec
.begin(), aResultVec
.end(),
343 lcl_LabeledSequenceEquals( xAdd
)) == aResultVec
.end())
345 aResultVec
.push_back( xAdd
);
349 catch( uno::Exception
& ex
)
351 ASSERT_EXCEPTION( ex
);
355 // add unused data at end
356 copy( aUnusedDataVec
.begin(), aUnusedDataVec
.end(), back_inserter( aResultVec
));
358 return Reference
< data::XDataSource
>( DataSourceHelper::createDataSource( ContainerToSequence( aResultVec
) ) );
361 // convenience methods
364 OUString
DataInterpreter::GetRole( const Reference
< data::XDataSequence
> & xSeq
)
372 Reference
< beans::XPropertySet
> xProp( xSeq
, uno::UNO_QUERY_THROW
);
373 xProp
->getPropertyValue( C2U("Role")) >>= aResult
;
375 catch( uno::Exception
& ex
)
377 ASSERT_EXCEPTION( ex
);
383 void DataInterpreter::SetRole( const Reference
< data::XDataSequence
> & xSeq
, const OUString
& rRole
)
389 Reference
< beans::XPropertySet
> xProp( xSeq
, uno::UNO_QUERY_THROW
);
390 xProp
->setPropertyValue( C2U("Role"), uno::makeAny( rRole
));
392 catch( uno::Exception
& ex
)
394 ASSERT_EXCEPTION( ex
);
399 uno::Any
DataInterpreter::GetProperty(
400 const Sequence
< beans::PropertyValue
> & aArguments
,
401 const OUString
& rName
)
403 for( sal_Int32 i
=aArguments
.getLength(); i
--; )
405 if( aArguments
[i
].Name
.equals( rName
))
406 return aArguments
[i
].Value
;
412 bool DataInterpreter::HasCategories(
413 const Sequence
< beans::PropertyValue
> & rArguments
,
414 const Sequence
< Reference
< data::XLabeledDataSequence
> > & rData
)
416 bool bHasCategories
= false;
418 if( rArguments
.getLength() > 0 )
419 GetProperty( rArguments
, C2U(("HasCategories"))) >>= bHasCategories
;
421 for( sal_Int32 nLSeqIdx
=0; ! bHasCategories
&& nLSeqIdx
<rData
.getLength(); ++nLSeqIdx
)
422 bHasCategories
= ( rData
[nLSeqIdx
].is() &&
423 GetRole( rData
[nLSeqIdx
]->getValues()).equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("categories")));
425 return bHasCategories
;
428 // ------------------------------------------------------------
430 Sequence
< OUString
> DataInterpreter::getSupportedServiceNames_Static()
432 Sequence
< OUString
> aServices( 1 );
433 aServices
[0] = C2U( "com.sun.star.chart2.DataInterpreter" );
437 // implement XServiceInfo methods basing upon getSupportedServiceNames_Static
438 APPHELPER_XSERVICEINFO_IMPL( DataInterpreter
, C2U("com.sun.star.comp.chart2.DataInterpreter"));
442 #if OSL_DEBUG_LEVEL > 1
446 void lcl_ShowDataSource( const Reference
< data::XDataSource
> & xSource
)
451 OSL_TRACE( "DataSource in DataInterpreter:" );
452 Sequence
< Reference
< data::XLabeledDataSequence
> > aSequences( xSource
->getDataSequences());
453 Reference
< beans::XPropertySet
> xProp
;
455 const sal_Int32 nMax
= aSequences
.getLength();
456 for( sal_Int32 k
= 0; k
< nMax
; ++k
)
458 if( aSequences
[k
].is())
460 OUString
aSourceRepr(C2U("<none>"));
461 if( aSequences
[k
]->getValues().is())
462 aSourceRepr
= aSequences
[k
]->getValues()->getSourceRangeRepresentation();
463 xProp
.set( aSequences
[k
]->getValues(), uno::UNO_QUERY
);
465 ( xProp
->getPropertyValue( C2U( "Role" )) >>= aId
))
467 OSL_TRACE( " <data sequence %d> Role: %s, Source: %s", k
, U2C( aId
), U2C( aSourceRepr
));
471 OSL_TRACE( " <data sequence %d> unknown Role, Source: %s", k
, U2C( aSourceRepr
) );
474 aSourceRepr
= C2U("<none>");
475 if( aSequences
[k
]->getLabel().is())
476 aSourceRepr
= OUString( aSequences
[k
]->getLabel()->getSourceRangeRepresentation());
477 xProp
.set( aSequences
[k
]->getLabel(), uno::UNO_QUERY
);
479 ( xProp
->getPropertyValue( C2U( "Role" )) >>= aId
))
481 OSL_TRACE( " <data sequence label %d> Role: %s, Source: %s", k
, U2C( aId
), U2C( aSourceRepr
));
485 OSL_TRACE( " <data sequence label %d> unknown Role, Source: %s", k
, U2C( aSourceRepr
) );