fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / model / template / StockDataInterpreter.cxx
blob364800c31392f1f3b550cf811f7c3e56cb748016
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "StockDataInterpreter.hxx"
21 #include "DataSeries.hxx"
22 #include "macros.hxx"
23 #include "DataSeriesHelper.hxx"
24 #include "CommonConverters.hxx"
25 #include "ContainerHelper.hxx"
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/chart2/data/XDataSink.hpp>
29 #include <vector>
30 #include <algorithm>
31 #include <iterator>
33 using namespace ::com::sun::star;
34 using namespace ::com::sun::star::chart2;
35 using namespace ::std;
37 using ::com::sun::star::uno::Reference;
38 using ::com::sun::star::uno::Sequence;
39 using namespace ::chart::ContainerHelper;
41 namespace chart
44 // explicit
45 StockDataInterpreter::StockDataInterpreter(
46 StockChartTypeTemplate::StockVariant eVariant,
47 const Reference< uno::XComponentContext > & xContext ) :
48 DataInterpreter( xContext ),
49 m_eStockVariant( eVariant )
52 StockDataInterpreter::~StockDataInterpreter()
55 // ____ XDataInterpreter ____
56 InterpretedData SAL_CALL StockDataInterpreter::interpretDataSource(
57 const Reference< data::XDataSource >& xSource,
58 const Sequence< beans::PropertyValue >& rArguments,
59 const Sequence< Reference< XDataSeries > >& rSeriesToReUse )
60 throw (uno::RuntimeException, std::exception)
62 if( ! xSource.is())
63 return InterpretedData();
65 Reference< data::XLabeledDataSequence > xCategories;
66 Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() );
67 const sal_Int32 nDataCount( aData.getLength());
69 // sub-type properties
70 const StockChartTypeTemplate::StockVariant eVar( GetStockVariant());
71 const bool bHasOpenValues (( eVar == StockChartTypeTemplate::OPEN_LOW_HI_CLOSE ) ||
72 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ));
73 const bool bHasVolume (( eVar == StockChartTypeTemplate::VOL_LOW_HI_CLOSE ) ||
74 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ));
75 const bool bHasCategories( HasCategories( rArguments, aData ));
77 // necessary roles for "full series"
78 // low/high/close
79 sal_Int32 nNumberOfNecessarySequences( 3 );
80 if( bHasOpenValues )
81 ++nNumberOfNecessarySequences;
82 if( bHasVolume )
83 ++nNumberOfNecessarySequences;
85 // calculate number of full series (nNumOfFullSeries) and the number of remaining
86 // sequences used for additional "incomplete series" (nRemaining)
87 sal_Int32 nNumOfFullSeries( 0 );
88 sal_Int32 nRemaining( 0 );
90 sal_Int32 nAvailableSequences( nDataCount );
91 if( bHasCategories )
92 --nAvailableSequences;
93 nNumOfFullSeries = nAvailableSequences / nNumberOfNecessarySequences;
94 nRemaining = nAvailableSequences % nNumberOfNecessarySequences;
96 sal_Int32 nCandleStickSeries = nNumOfFullSeries;
97 sal_Int32 nVolumeSeries = nNumOfFullSeries;
99 sal_Int32 nNumberOfGroups( bHasVolume ? 2 : 1 );
100 // sequences of data::XLabeledDataSequence per series per group
101 Sequence< Sequence< Sequence< Reference< data::XLabeledDataSequence > > > > aSequences( nNumberOfGroups );
102 sal_Int32 nBarGroupIndex( 0 );
103 sal_Int32 nCandleStickGroupIndex( nNumberOfGroups - 1 );
105 // allocate space for labeled sequences
106 if( nRemaining > 0 )
107 ++nCandleStickSeries;
108 aSequences[nCandleStickGroupIndex].realloc( nCandleStickSeries );
109 if( bHasVolume )
111 // if there are remaining sequences, the first one is taken for
112 // additional close values, the second one is taken as volume, if volume
113 // is used
114 if( nRemaining > 1 )
115 ++nVolumeSeries;
116 aSequences[nBarGroupIndex].realloc( nVolumeSeries );
119 // create data
120 sal_Int32 nSourceIndex = 0; // index into aData sequence
122 // 1. categories
123 if( bHasCategories )
125 xCategories.set( aData[nSourceIndex] );
126 ++nSourceIndex;
129 // 2. create "full" series
130 for( sal_Int32 nLabeledSeqIdx=0; nLabeledSeqIdx<nNumOfFullSeries; ++nLabeledSeqIdx )
132 // bar
133 if( bHasVolume )
135 aSequences[nBarGroupIndex][nLabeledSeqIdx].realloc( 1 );
136 aSequences[nBarGroupIndex][nLabeledSeqIdx][0].set( aData[nSourceIndex] );
137 if( aData[nSourceIndex].is())
138 SetRole( aData[nSourceIndex]->getValues(), "values-y");
139 ++nSourceIndex;
142 sal_Int32 nSeqIdx = 0;
143 if( bHasOpenValues )
145 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx].realloc( 4 );
146 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
147 if( aData[nSourceIndex].is())
148 SetRole( aData[nSourceIndex]->getValues(), "values-first");
149 ++nSourceIndex, ++nSeqIdx;
151 else
152 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx].realloc( 3 );
154 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
155 if( aData[nSourceIndex].is())
156 SetRole( aData[nSourceIndex]->getValues(), "values-min");
157 ++nSourceIndex, ++nSeqIdx;
159 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
160 if( aData[nSourceIndex].is())
161 SetRole( aData[nSourceIndex]->getValues(), "values-max");
162 ++nSourceIndex, ++nSeqIdx;
164 aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] );
165 if( aData[nSourceIndex].is())
166 SetRole( aData[nSourceIndex]->getValues(), "values-last");
167 ++nSourceIndex, ++nSeqIdx;
170 // 3. create series with remaining sequences
171 if( bHasVolume && nRemaining > 1 )
173 OSL_ASSERT( nVolumeSeries > nNumOfFullSeries );
174 aSequences[nBarGroupIndex][nVolumeSeries - 1].realloc( 1 );
175 OSL_ASSERT( nDataCount > nSourceIndex );
176 if( aData[nSourceIndex].is())
177 SetRole( aData[nSourceIndex]->getValues(), "values-y");
178 aSequences[nBarGroupIndex][nVolumeSeries - 1][0].set( aData[nSourceIndex] );
179 ++nSourceIndex;
180 --nRemaining;
181 OSL_ENSURE( nRemaining, "additional bar should only be used if there is at least one more sequence for a candle stick" );
184 // candle-stick
185 if( nRemaining > 0 )
187 OSL_ASSERT( nCandleStickSeries > nNumOfFullSeries );
188 const sal_Int32 nSeriesIndex = nCandleStickSeries - 1;
189 aSequences[nCandleStickGroupIndex][nSeriesIndex].realloc( nRemaining );
190 OSL_ASSERT( nDataCount > nSourceIndex );
192 // 1. low
193 sal_Int32 nSeqIdx( 0 );
194 aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] );
195 if( aData[nSourceIndex].is())
196 SetRole( aData[nSourceIndex]->getValues(), "values-min");
197 ++nSourceIndex, ++nSeqIdx;
199 // 2. high
200 if( nSeqIdx < nRemaining )
202 aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] );
203 if( aData[nSourceIndex].is())
204 SetRole( aData[nSourceIndex]->getValues(), "values-max");
205 ++nSourceIndex, ++nSeqIdx;
208 // 3. close
209 OSL_ENSURE( bHasOpenValues || nSeqIdx >= nRemaining, "could have created full series" );
210 if( nSeqIdx < nRemaining )
212 aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] );
213 if( aData[nSourceIndex].is())
214 SetRole( aData[nSourceIndex]->getValues(), "values-last");
215 ++nSourceIndex, ++nSeqIdx;
218 // 4. open
219 OSL_ENSURE( nSeqIdx >= nRemaining, "could have created full series" );
222 // create DataSeries
223 Sequence< Sequence< Reference< XDataSeries > > > aResultSeries( nNumberOfGroups );
224 sal_Int32 nGroupIndex, nReUsedSeriesIdx = 0;
225 for( nGroupIndex=0; nGroupIndex<nNumberOfGroups; ++nGroupIndex )
227 const sal_Int32 nNumSeriesData = aSequences[nGroupIndex].getLength();
228 aResultSeries[nGroupIndex].realloc( nNumSeriesData );
229 for( sal_Int32 nSeriesIdx = 0; nSeriesIdx < nNumSeriesData; ++nSeriesIdx, ++nReUsedSeriesIdx )
233 Reference< XDataSeries > xSeries;
234 if( nReUsedSeriesIdx < rSeriesToReUse.getLength())
235 xSeries.set( rSeriesToReUse[nReUsedSeriesIdx] );
236 else
237 xSeries.set( new DataSeries( GetComponentContext() ) );
238 OSL_ASSERT( xSeries.is() );
239 Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY_THROW );
240 OSL_ASSERT( xSink.is() );
241 xSink->setData( aSequences[nGroupIndex][nSeriesIdx] );
242 aResultSeries[nGroupIndex][nSeriesIdx].set( xSeries );
244 catch( const uno::Exception & ex )
246 ASSERT_EXCEPTION( ex );
251 return InterpretedData( aResultSeries, xCategories );
254 // criterion: there must be two groups for stock-charts with volume and all
255 // series must have the correct number of data::XLabeledDataSequences
257 // todo: skip first criterion? (to allow easy switch from stock-chart without
258 // volume to one with volume)
259 sal_Bool SAL_CALL StockDataInterpreter::isDataCompatible(
260 const InterpretedData& aInterpretedData )
261 throw (uno::RuntimeException, std::exception)
263 // high/low/close
264 sal_Int32 nNumberOfNecessarySequences = 3;
265 // open
266 StockChartTypeTemplate::StockVariant eVar( GetStockVariant());
267 if( ( eVar == StockChartTypeTemplate::OPEN_LOW_HI_CLOSE ) ||
268 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ))
269 ++nNumberOfNecessarySequences;
270 // volume
271 bool bHasVolume = (( eVar == StockChartTypeTemplate::VOL_LOW_HI_CLOSE ) ||
272 ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE ));
274 // 1. correct number of sub-types
275 if( aInterpretedData.Series.getLength() < (bHasVolume ? 2 : 1 ))
276 return sal_False;
278 // 2. a. volume -- use default check
279 if( bHasVolume )
281 if( ! DataInterpreter::isDataCompatible(
282 InterpretedData( Sequence< Sequence< Reference< XDataSeries > > >(
283 aInterpretedData.Series.getConstArray(), 1 ),
284 aInterpretedData.Categories )))
285 return sal_False;
288 // 2. b. candlestick
290 OSL_ASSERT( aInterpretedData.Series.getLength() > (bHasVolume ? 1 : 0));
291 Sequence< Reference< XDataSeries > > aSeries( aInterpretedData.Series[(bHasVolume ? 1 : 0)] );
292 if(!aSeries.getLength())
293 return sal_False;
294 for( sal_Int32 i=0; i<aSeries.getLength(); ++i )
298 Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW );
299 Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences());
300 if( aSeq.getLength() != nNumberOfNecessarySequences )
301 return sal_False;
303 catch( const uno::Exception & ex )
305 ASSERT_EXCEPTION( ex );
310 // 2. c. additional series
311 // ignore
313 return sal_True;
316 InterpretedData SAL_CALL StockDataInterpreter::reinterpretDataSeries(
317 const InterpretedData& aInterpretedData )
318 throw (uno::RuntimeException, std::exception)
320 // prerequisite: StockDataInterpreter::isDataCompatible() returned true
321 return aInterpretedData;
324 } // namespace chart
326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */