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