1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
30 
31 #include "XYDataInterpreter.hxx"
32 #include "DataSeries.hxx"
33 #include "macros.hxx"
34 #include "DataSeriesHelper.hxx"
35 #include "CommonConverters.hxx"
36 #include "ContainerHelper.hxx"
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/chart2/data/XDataSink.hpp>
39 #include <com/sun/star/util/XCloneable.hpp>
40 
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::chart2;
43 using namespace ::std;
44 
45 using ::com::sun::star::uno::Reference;
46 using ::com::sun::star::uno::Sequence;
47 using ::rtl::OUString;
48 
49 namespace chart
50 {
51 
52 XYDataInterpreter::XYDataInterpreter(
53     const uno::Reference< uno::XComponentContext > & xContext ) :
54         DataInterpreter( xContext )
55 {
56 }
57 
58 XYDataInterpreter::~XYDataInterpreter()
59 {
60 }
61 
62 // ____ XDataInterpreter ____
63 chart2::InterpretedData SAL_CALL XYDataInterpreter::interpretDataSource(
64     const Reference< chart2::data::XDataSource >& xSource,
65     const Sequence< beans::PropertyValue >& aArguments,
66     const Sequence< Reference< XDataSeries > >& aSeriesToReUse )
67     throw (uno::RuntimeException)
68 {
69     if( ! xSource.is())
70         return InterpretedData();
71 
72     Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() );
73 
74     Reference< data::XLabeledDataSequence > xValuesX;
75     vector< Reference< data::XLabeledDataSequence > > aSequencesVec;
76 
77     Reference< data::XLabeledDataSequence > xCategories;
78     bool bHasCategories = HasCategories( aArguments, aData );
79     bool bUseCategoriesAsX = UseCategoriesAsX( aArguments );
80 
81     // parse data
82     bool bCategoriesUsed = false;
83     bool bSetXValues = aData.getLength()>(bCategoriesUsed?2:1);
84     for( sal_Int32 nDataIdx= 0; nDataIdx < aData.getLength(); ++nDataIdx )
85     {
86         try
87         {
88             if( bHasCategories && ! bCategoriesUsed )
89             {
90                 xCategories.set( aData[nDataIdx] );
91                 if( xCategories.is())
92                 {
93                     SetRole( xCategories->getValues(), C2U("categories"));
94                     if( bUseCategoriesAsX )
95                         bSetXValues = false;
96                 }
97                 bCategoriesUsed = true;
98             }
99             else if( !xValuesX.is() && bSetXValues )
100             {
101                 xValuesX.set( aData[nDataIdx] );
102                 if( xValuesX.is())
103                     SetRole( xValuesX->getValues(), C2U("values-x"));
104             }
105             else
106             {
107                 aSequencesVec.push_back( aData[nDataIdx] );
108                 if( aData[nDataIdx].is())
109                     SetRole( aData[nDataIdx]->getValues(), C2U("values-y"));
110             }
111         }
112         catch( uno::Exception & ex )
113         {
114             ASSERT_EXCEPTION( ex );
115         }
116     }
117 
118     // create DataSeries
119     vector< Reference< data::XLabeledDataSequence > >::const_iterator
120           aSequencesVecIt = aSequencesVec.begin();
121 
122     sal_Int32 nSeriesIndex = 0;
123     vector< Reference< XDataSeries > > aSeriesVec;
124     aSeriesVec.reserve( aSequencesVec.size());
125 
126     Reference< data::XLabeledDataSequence > xClonedXValues = xValuesX;
127     Reference< util::XCloneable > xCloneable( xValuesX, uno::UNO_QUERY );
128 
129     for( ;aSequencesVecIt != aSequencesVec.end(); ++aSequencesVecIt, ++nSeriesIndex )
130     {
131         vector< Reference< data::XLabeledDataSequence > > aNewData;
132 
133         if( aSequencesVecIt != aSequencesVec.begin() && xCloneable.is() )
134             xClonedXValues.set( xCloneable->createClone(), uno::UNO_QUERY );
135         if( xValuesX.is() )
136             aNewData.push_back( xClonedXValues );
137 
138         aNewData.push_back( *aSequencesVecIt );
139 
140         Reference< XDataSeries > xSeries;
141         if( nSeriesIndex < aSeriesToReUse.getLength())
142             xSeries.set( aSeriesToReUse[nSeriesIndex] );
143         else
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( ContainerHelper::ContainerToSequence( aNewData ) );
149 
150         aSeriesVec.push_back( xSeries );
151     }
152 
153     Sequence< Sequence< Reference< XDataSeries > > > aSeries(1);
154     aSeries[0] = ContainerHelper::ContainerToSequence( aSeriesVec );
155     return InterpretedData( aSeries, xCategories );
156 }
157 
158 chart2::InterpretedData SAL_CALL XYDataInterpreter::reinterpretDataSeries(
159     const chart2::InterpretedData& aInterpretedData )
160     throw (uno::RuntimeException)
161 {
162     InterpretedData aResult( aInterpretedData );
163 
164     sal_Int32 i=0;
165     Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
166     const sal_Int32 nCount = aSeries.getLength();
167     for( ; i<nCount; ++i )
168     {
169         try
170         {
171             Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW );
172             Sequence< Reference< data::XLabeledDataSequence > > aNewSequences;
173 
174             // values-y
175             Reference< data::XLabeledDataSequence > xValuesY(
176                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false ));
177             Reference< data::XLabeledDataSequence > xValuesX(
178                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-x"), false ));
179             // re-use values-... as values-x/values-y
180             if( ! xValuesX.is() ||
181                 ! xValuesY.is())
182             {
183                 vector< Reference< data::XLabeledDataSequence > > aValueSeqVec(
184                     DataSeriesHelper::getAllDataSequencesByRole(
185                         xSeriesSource->getDataSequences(), C2U("values"), true ));
186                 if( xValuesX.is())
187                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesX ));
188                 if( xValuesY.is())
189                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesY ));
190 
191                 size_t nIndex = 0;
192                 if( ! xValuesY.is() &&
193                     aValueSeqVec.size() > nIndex )
194                 {
195                     xValuesY.set( aValueSeqVec[nIndex++] );
196                     if( xValuesY.is())
197                         SetRole( xValuesY->getValues(), C2U("values-y"));
198                 }
199 
200                 if( ! xValuesX.is() &&
201                     aValueSeqVec.size() > nIndex )
202                 {
203                     xValuesX.set( aValueSeqVec[nIndex++] );
204                     if( xValuesX.is())
205                         SetRole( xValuesY->getValues(), C2U("values-x"));
206                 }
207             }
208             if( xValuesY.is())
209             {
210                 if( xValuesX.is())
211                 {
212                     aNewSequences.realloc(2);
213                     aNewSequences[0] = xValuesX;
214                     aNewSequences[1] = xValuesY;
215                 }
216                 else
217                 {
218                     aNewSequences.realloc(1);
219                     aNewSequences[0] = xValuesY;
220                 }
221             }
222 
223             Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences());
224             if( aSeqs.getLength() != aNewSequences.getLength() )
225             {
226 #if OSL_DEBUG_LEVEL > 1
227                 sal_Int32 j=0;
228                 for( ; j<aSeqs.getLength(); ++j )
229                 {
230                     OSL_ENSURE( aSeqs[j] == xValuesY || aSeqs[j] == xValuesX, "All sequences should be used" );
231                 }
232 #endif
233                 Reference< data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY_THROW );
234                 xSink->setData( aNewSequences );
235             }
236         }
237         catch( uno::Exception & ex )
238         {
239             ASSERT_EXCEPTION( ex );
240         }
241     }
242 
243     return aResult;
244 }
245 
246 // criterion: all series must have exactly two data::XLabeledDataSequences
247 sal_Bool SAL_CALL XYDataInterpreter::isDataCompatible(
248     const chart2::InterpretedData& aInterpretedData )
249     throw (uno::RuntimeException)
250 {
251     Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
252     for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
253     {
254         try
255         {
256             Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW );
257             Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
258             if( aSeq.getLength() != 2 )
259                 return sal_False;
260         }
261         catch( uno::Exception & ex )
262         {
263             ASSERT_EXCEPTION( ex );
264         }
265     }
266 
267     return sal_True;
268 }
269 
270 } // namespace chart
271