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