Update ooo320-m1
[ooovba.git] / chart2 / source / model / template / StockDataInterpreter.cxx
blob1fa91afada4f1a2516cc7b2fa88882379dd3efd1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: StockDataInterpreter.cxx,v $
10 * $Revision: 1.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
34 #include "StockDataInterpreter.hxx"
35 #include "DataSeries.hxx"
36 #include "macros.hxx"
37 #include "DataSeriesHelper.hxx"
38 #include "CommonConverters.hxx"
39 #include "ContainerHelper.hxx"
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/chart2/data/XDataSink.hpp>
43 // #include <deque>
45 #include <vector>
46 #include <algorithm>
47 #include <iterator>
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::chart2;
51 using namespace ::std;
53 using ::com::sun::star::uno::Reference;
54 using ::com::sun::star::uno::Sequence;
55 using ::rtl::OUString;
56 using namespace ::chart::ContainerHelper;
58 namespace chart
61 // explicit
62 StockDataInterpreter::StockDataInterpreter(
63 StockChartTypeTemplate::StockVariant eVariant,
64 const Reference< uno::XComponentContext > & xContext ) :
65 DataInterpreter( xContext ),
66 m_eStockVariant( eVariant )
69 StockDataInterpreter::~StockDataInterpreter()
72 StockChartTypeTemplate::StockVariant StockDataInterpreter::GetStockVariant() const
74 return m_eStockVariant;
77 // ____ XDataInterpreter ____
78 InterpretedData SAL_CALL StockDataInterpreter::interpretDataSource(
79 const Reference< data::XDataSource >& xSource,
80 const Sequence< beans::PropertyValue >& rArguments,
81 const Sequence< Reference< XDataSeries > >& rSeriesToReUse )
82 throw (uno::RuntimeException)
84 if( ! xSource.is())
85 return InterpretedData();
87 Reference< data::XLabeledDataSequence > xCategories;
88 Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() );
89 const sal_Int32 nDataCount( aData.getLength());
91 // sub-type properties
92 const StockChartTypeTemplate::StockVariant eVar( GetStockVariant());
93 const bool bHasOpenValues (( eVar == StockChartTypeTemplate::OPEN_LOW_HI_CLOSE ) ||
94 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ));
95 const bool bHasVolume (( eVar == StockChartTypeTemplate::VOL_LOW_HI_CLOSE ) ||
96 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ));
97 const bool bHasCategories( HasCategories( rArguments, aData ));
99 // necessary roles for "full series"
100 // low/high/close
101 sal_Int32 nNumberOfNecessarySequences( 3 );
102 if( bHasOpenValues )
103 ++nNumberOfNecessarySequences;
104 if( bHasVolume )
105 ++nNumberOfNecessarySequences;
107 // calculate number of full series (nNumOfFullSeries) and the number of remaining
108 // sequences used for additional "incomplete series" (nRemaining)
109 sal_Int32 nNumOfFullSeries( 0 );
110 sal_Int32 nRemaining( 0 );
112 sal_Int32 nAvailableSequences( nDataCount );
113 if( bHasCategories )
114 --nAvailableSequences;
115 nNumOfFullSeries = nAvailableSequences / nNumberOfNecessarySequences;
116 nRemaining = nAvailableSequences % nNumberOfNecessarySequences;
118 sal_Int32 nCandleStickSeries = nNumOfFullSeries;
119 sal_Int32 nVolumeSeries = nNumOfFullSeries;
121 sal_Int32 nNumberOfGroups( bHasVolume ? 2 : 1 );
122 // sequences of data::XLabeledDataSequence per series per group
123 Sequence< Sequence< Sequence< Reference< data::XLabeledDataSequence > > > > aSequences( nNumberOfGroups );
124 sal_Int32 nBarGroupIndex( 0 );
125 sal_Int32 nCandleStickGroupIndex( nNumberOfGroups - 1 );
127 // allocate space for labeled sequences
128 if( nRemaining > 0 )
129 ++nCandleStickSeries;
130 aSequences[nCandleStickGroupIndex].realloc( nCandleStickSeries );
131 if( bHasVolume )
133 // if there are remaining sequences, the first one is taken for
134 // additional close values, the second one is taken as volume, if volume
135 // is used
136 if( nRemaining > 1 )
137 ++nVolumeSeries;
138 aSequences[nBarGroupIndex].realloc( nVolumeSeries );
142 // create data
143 sal_Int32 nSourceIndex = 0; // index into aData sequence
145 // 1. categories
146 if( bHasCategories )
148 xCategories.set( aData[nSourceIndex] );
149 ++nSourceIndex;
152 // 2. create "full" series
153 for( sal_Int32 nLabeledSeqIdx=0; nLabeledSeqIdx<nNumOfFullSeries; ++nLabeledSeqIdx )
155 // bar
156 if( bHasVolume )
158 aSequences[nBarGroupIndex][nLabeledSeqIdx].realloc( 1 );
159 aSequences[nBarGroupIndex][nLabeledSeqIdx][0].set( aData[nSourceIndex] );
160 if( aData[nSourceIndex].is())
161 SetRole( aData[nSourceIndex]->getValues(), C2U("values-y"));
162 ++nSourceIndex;
165 sal_Int32 nSeqIdx = 0;
166 if( bHasOpenValues )
168 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx].realloc( 4 );
169 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
170 if( aData[nSourceIndex].is())
171 SetRole( aData[nSourceIndex]->getValues(), C2U("values-first"));
172 ++nSourceIndex, ++nSeqIdx;
174 else
175 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx].realloc( 3 );
177 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
178 if( aData[nSourceIndex].is())
179 SetRole( aData[nSourceIndex]->getValues(), C2U("values-min"));
180 ++nSourceIndex, ++nSeqIdx;
182 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
183 if( aData[nSourceIndex].is())
184 SetRole( aData[nSourceIndex]->getValues(), C2U("values-max"));
185 ++nSourceIndex, ++nSeqIdx;
187 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
188 if( aData[nSourceIndex].is())
189 SetRole( aData[nSourceIndex]->getValues(), C2U("values-last"));
190 ++nSourceIndex, ++nSeqIdx;
193 // 3. create series with remaining sequences
194 if( bHasVolume && nRemaining > 1 )
196 OSL_ASSERT( nVolumeSeries > nNumOfFullSeries );
197 aSequences[nBarGroupIndex][nVolumeSeries - 1].realloc( 1 );
198 OSL_ASSERT( nDataCount > nSourceIndex );
199 if( aData[nSourceIndex].is())
200 SetRole( aData[nSourceIndex]->getValues(), C2U("values-y"));
201 aSequences[nBarGroupIndex][nVolumeSeries - 1][0].set( aData[nSourceIndex] );
202 ++nSourceIndex;
203 --nRemaining;
204 OSL_ENSURE( nRemaining, "additional bar should only be used if there is at least one more sequence for a candle stick" );
207 // candle-stick
208 if( nRemaining > 0 )
210 OSL_ASSERT( nCandleStickSeries > nNumOfFullSeries );
211 const sal_Int32 nSeriesIndex = nCandleStickSeries - 1;
212 aSequences[nCandleStickGroupIndex][nSeriesIndex].realloc( nRemaining );
213 OSL_ASSERT( nDataCount > nSourceIndex );
215 // 1. low
216 sal_Int32 nSeqIdx( 0 );
217 aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] );
218 if( aData[nSourceIndex].is())
219 SetRole( aData[nSourceIndex]->getValues(), C2U("values-min"));
220 ++nSourceIndex, ++nSeqIdx;
222 // 2. high
223 if( nSeqIdx < nRemaining )
225 aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] );
226 if( aData[nSourceIndex].is())
227 SetRole( aData[nSourceIndex]->getValues(), C2U("values-max"));
228 ++nSourceIndex, ++nSeqIdx;
231 // 3. close
232 OSL_ENSURE( bHasOpenValues || nSeqIdx >= nRemaining, "could have created full series" );
233 if( nSeqIdx < nRemaining )
235 aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] );
236 if( aData[nSourceIndex].is())
237 SetRole( aData[nSourceIndex]->getValues(), C2U("values-last"));
238 ++nSourceIndex, ++nSeqIdx;
241 // 4. open
242 OSL_ENSURE( nSeqIdx >= nRemaining, "could have created full series" );
245 // create DataSeries
246 Sequence< Sequence< Reference< XDataSeries > > > aResultSeries( nNumberOfGroups );
247 sal_Int32 nGroupIndex, nReUsedSeriesIdx = 0;
248 for( nGroupIndex=0; nGroupIndex<nNumberOfGroups; ++nGroupIndex )
250 const sal_Int32 nNumSeriesData = aSequences[nGroupIndex].getLength();
251 aResultSeries[nGroupIndex].realloc( nNumSeriesData );
252 for( sal_Int32 nSeriesIdx = 0; nSeriesIdx < nNumSeriesData; ++nSeriesIdx, ++nReUsedSeriesIdx )
256 Reference< XDataSeries > xSeries;
257 if( nReUsedSeriesIdx < rSeriesToReUse.getLength())
258 xSeries.set( rSeriesToReUse[nReUsedSeriesIdx] );
259 else
260 xSeries.set( new DataSeries( GetComponentContext() ) );
261 OSL_ASSERT( xSeries.is() );
262 Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY_THROW );
263 OSL_ASSERT( xSink.is() );
264 xSink->setData( aSequences[nGroupIndex][nSeriesIdx] );
265 aResultSeries[nGroupIndex][nSeriesIdx].set( xSeries );
267 catch( uno::Exception & ex )
269 ASSERT_EXCEPTION( ex );
274 const Sequence< Reference< data::XLabeledDataSequence > > aUnusedData;//@todo remove the unused data concept completely
275 return InterpretedData( aResultSeries, xCategories, aUnusedData );
278 // criterion: there must be two groups for stock-charts with volume and all
279 // series must have the correct number of data::XLabeledDataSequences
281 // todo: skip first criterion? (to allow easy switch from stock-chart without
282 // volume to one with volume)
283 sal_Bool SAL_CALL StockDataInterpreter::isDataCompatible(
284 const InterpretedData& aInterpretedData )
285 throw (uno::RuntimeException)
287 // high/low/close
288 sal_Int32 nNumberOfNecessarySequences = 3;
289 // open
290 StockChartTypeTemplate::StockVariant eVar( GetStockVariant());
291 if( ( eVar == StockChartTypeTemplate::OPEN_LOW_HI_CLOSE ) ||
292 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ))
293 ++nNumberOfNecessarySequences;
294 // volume
295 bool bHasVolume = (( eVar == StockChartTypeTemplate::VOL_LOW_HI_CLOSE ) ||
296 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ));
298 // 1. correct number of sub-types
299 if( aInterpretedData.Series.getLength() < (bHasVolume ? 2 : 1 ))
300 return sal_False;
302 // 2. a. volume -- use default check
303 if( bHasVolume )
305 if( ! DataInterpreter::isDataCompatible(
306 InterpretedData( Sequence< Sequence< Reference< XDataSeries > > >(
307 aInterpretedData.Series.getConstArray(), 1 ),
308 aInterpretedData.Categories, aInterpretedData.UnusedData )))
309 return sal_False;
312 // 2. b. candlestick
314 OSL_ASSERT( aInterpretedData.Series.getLength() > (bHasVolume ? 1 : 0));
315 Sequence< Reference< XDataSeries > > aSeries( aInterpretedData.Series[(bHasVolume ? 1 : 0)] );
316 if(!aSeries.getLength())
317 return sal_False;
318 for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
322 Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW );
323 Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
324 if( aSeq.getLength() != nNumberOfNecessarySequences )
325 return sal_False;
327 catch( uno::Exception & ex )
329 ASSERT_EXCEPTION( ex );
334 // 2. c. additional series
335 // ignore
337 return sal_True;
340 InterpretedData SAL_CALL StockDataInterpreter::reinterpretDataSeries(
341 const InterpretedData& aInterpretedData )
342 throw (uno::RuntimeException)
344 // prerequisite: StockDataInterpreter::isDataCompatible() returned true
345 return aInterpretedData;
348 } // namespace chart