xref: /trunk/main/chart2/source/model/template/XYDataInterpreter.cxx (revision 9c15e1abd703a7953928d7a80655ae1a76a41f6d)
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 "XYDataInterpreter.hxx"
28 #include "DataSeries.hxx"
29 #include "macros.hxx"
30 #include "DataSeriesHelper.hxx"
31 #include "CommonConverters.hxx"
32 #include "ContainerHelper.hxx"
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/chart2/data/XDataSink.hpp>
35 #include <com/sun/star/util/XCloneable.hpp>
36 
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::chart2;
39 using namespace ::std;
40 
41 using ::com::sun::star::uno::Reference;
42 using ::com::sun::star::uno::Sequence;
43 using ::rtl::OUString;
44 
45 namespace chart
46 {
47 
48 XYDataInterpreter::XYDataInterpreter(
49     const uno::Reference< uno::XComponentContext > & xContext ) :
50         DataInterpreter( xContext )
51 {
52 }
53 
54 XYDataInterpreter::~XYDataInterpreter()
55 {
56 }
57 
58 // ____ XDataInterpreter ____
59 chart2::InterpretedData SAL_CALL XYDataInterpreter::interpretDataSource(
60     const Reference< chart2::data::XDataSource >& xSource,
61     const Sequence< beans::PropertyValue >& aArguments,
62     const Sequence< Reference< XDataSeries > >& aSeriesToReUse )
63 {
64     if( ! xSource.is())
65         return InterpretedData();
66 
67     Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() );
68 
69     Reference< data::XLabeledDataSequence > xValuesX;
70     vector< Reference< data::XLabeledDataSequence > > aSequencesVec;
71 
72     Reference< data::XLabeledDataSequence > xCategories;
73     bool bHasCategories = HasCategories( aArguments, aData );
74     bool bUseCategoriesAsX = UseCategoriesAsX( aArguments );
75 
76     // parse data
77     bool bCategoriesUsed = false;
78     bool bSetXValues = aData.getLength()>(bCategoriesUsed?2:1);
79     for( sal_Int32 nDataIdx= 0; nDataIdx < aData.getLength(); ++nDataIdx )
80     {
81         try
82         {
83             if( bHasCategories && ! bCategoriesUsed )
84             {
85                 xCategories.set( aData[nDataIdx] );
86                 if( xCategories.is())
87                 {
88                     SetRole( xCategories->getValues(), C2U("categories"));
89                     if( bUseCategoriesAsX )
90                         bSetXValues = false;
91                 }
92                 bCategoriesUsed = true;
93             }
94             else if( !xValuesX.is() && bSetXValues )
95             {
96                 xValuesX.set( aData[nDataIdx] );
97                 if( xValuesX.is())
98                     SetRole( xValuesX->getValues(), C2U("values-x"));
99             }
100             else
101             {
102                 aSequencesVec.push_back( aData[nDataIdx] );
103                 if( aData[nDataIdx].is())
104                     SetRole( aData[nDataIdx]->getValues(), C2U("values-y"));
105             }
106         }
107         catch( uno::Exception & ex )
108         {
109             ASSERT_EXCEPTION( ex );
110         }
111     }
112 
113     // create DataSeries
114     vector< Reference< data::XLabeledDataSequence > >::const_iterator
115           aSequencesVecIt = aSequencesVec.begin();
116 
117     sal_Int32 nSeriesIndex = 0;
118     vector< Reference< XDataSeries > > aSeriesVec;
119     aSeriesVec.reserve( aSequencesVec.size());
120 
121     Reference< data::XLabeledDataSequence > xClonedXValues = xValuesX;
122     Reference< util::XCloneable > xCloneable( xValuesX, uno::UNO_QUERY );
123 
124     for( ;aSequencesVecIt != aSequencesVec.end(); ++aSequencesVecIt, ++nSeriesIndex )
125     {
126         vector< Reference< data::XLabeledDataSequence > > aNewData;
127 
128         if( aSequencesVecIt != aSequencesVec.begin() && xCloneable.is() )
129             xClonedXValues.set( xCloneable->createClone(), uno::UNO_QUERY );
130         if( xValuesX.is() )
131             aNewData.push_back( xClonedXValues );
132 
133         aNewData.push_back( *aSequencesVecIt );
134 
135         Reference< XDataSeries > xSeries;
136         if( nSeriesIndex < aSeriesToReUse.getLength())
137             xSeries.set( aSeriesToReUse[nSeriesIndex] );
138         else
139             xSeries.set( new DataSeries( GetComponentContext() ) );
140         OSL_ASSERT( xSeries.is() );
141         Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY );
142         OSL_ASSERT( xSink.is() );
143         xSink->setData( ContainerHelper::ContainerToSequence( aNewData ) );
144 
145         aSeriesVec.push_back( xSeries );
146     }
147 
148     Sequence< Sequence< Reference< XDataSeries > > > aSeries(1);
149     aSeries[0] = ContainerHelper::ContainerToSequence( aSeriesVec );
150     return InterpretedData( aSeries, xCategories );
151 }
152 
153 chart2::InterpretedData SAL_CALL XYDataInterpreter::reinterpretDataSeries(
154     const chart2::InterpretedData& aInterpretedData )
155 {
156     InterpretedData aResult( aInterpretedData );
157 
158     sal_Int32 i=0;
159     Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
160     const sal_Int32 nCount = aSeries.getLength();
161     for( ; i<nCount; ++i )
162     {
163         try
164         {
165             Reference< data::XDataSource > xSeriesSource( aSeries[i], uno::UNO_QUERY_THROW );
166             Sequence< Reference< data::XLabeledDataSequence > > aNewSequences;
167 
168             // values-y
169             Reference< data::XLabeledDataSequence > xValuesY(
170                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-y"), false ));
171             Reference< data::XLabeledDataSequence > xValuesX(
172                 DataSeriesHelper::getDataSequenceByRole( xSeriesSource, C2U("values-x"), false ));
173             // re-use values-... as values-x/values-y
174             if( ! xValuesX.is() ||
175                 ! xValuesY.is())
176             {
177                 vector< Reference< data::XLabeledDataSequence > > aValueSeqVec(
178                     DataSeriesHelper::getAllDataSequencesByRole(
179                         xSeriesSource->getDataSequences(), C2U("values"), true ));
180                 if( xValuesX.is())
181                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesX ));
182                 if( xValuesY.is())
183                     aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesY ));
184 
185                 size_t nIndex = 0;
186                 if( ! xValuesY.is() &&
187                     aValueSeqVec.size() > nIndex )
188                 {
189                     xValuesY.set( aValueSeqVec[nIndex++] );
190                     if( xValuesY.is())
191                         SetRole( xValuesY->getValues(), C2U("values-y"));
192                 }
193 
194                 if( ! xValuesX.is() &&
195                     aValueSeqVec.size() > nIndex )
196                 {
197                     xValuesX.set( aValueSeqVec[nIndex++] );
198                     if( xValuesX.is())
199                         SetRole( xValuesY->getValues(), C2U("values-x"));
200                 }
201             }
202             if( xValuesY.is())
203             {
204                 if( xValuesX.is())
205                 {
206                     aNewSequences.realloc(2);
207                     aNewSequences[0] = xValuesX;
208                     aNewSequences[1] = xValuesY;
209                 }
210                 else
211                 {
212                     aNewSequences.realloc(1);
213                     aNewSequences[0] = xValuesY;
214                 }
215             }
216 
217             Sequence< Reference< data::XLabeledDataSequence > > aSeqs( xSeriesSource->getDataSequences());
218             if( aSeqs.getLength() != aNewSequences.getLength() )
219             {
220 #if OSL_DEBUG_LEVEL > 1
221                 sal_Int32 j=0;
222                 for( ; j<aSeqs.getLength(); ++j )
223                 {
224                     OSL_ENSURE( aSeqs[j] == xValuesY || aSeqs[j] == xValuesX, "All sequences should be used" );
225                 }
226 #endif
227                 Reference< data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY_THROW );
228                 xSink->setData( aNewSequences );
229             }
230         }
231         catch( uno::Exception & ex )
232         {
233             ASSERT_EXCEPTION( ex );
234         }
235     }
236 
237     return aResult;
238 }
239 
240 // criterion: all series must have exactly two data::XLabeledDataSequences
241 sal_Bool SAL_CALL XYDataInterpreter::isDataCompatible(
242     const chart2::InterpretedData& aInterpretedData )
243 {
244     Sequence< Reference< XDataSeries > > aSeries( FlattenSequence( aInterpretedData.Series ));
245     for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
246     {
247         try
248         {
249             Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW );
250             Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
251             if( aSeq.getLength() != 2 )
252                 return sal_False;
253         }
254         catch( uno::Exception & ex )
255         {
256             ASSERT_EXCEPTION( ex );
257         }
258     }
259 
260     return sal_True;
261 }
262 
263 } // namespace chart
264