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