1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
31 #include "StockDataInterpreter.hxx"
32 #include "DataSeries.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>
46 using namespace ::com::sun::star
;
47 using namespace ::com::sun::star::chart2
;
48 using namespace ::std
;
50 using ::com::sun::star::uno::Reference
;
51 using ::com::sun::star::uno::Sequence
;
52 using ::rtl::OUString
;
53 using namespace ::chart::ContainerHelper
;
59 StockDataInterpreter::StockDataInterpreter(
60 StockChartTypeTemplate::StockVariant eVariant
,
61 const Reference
< uno::XComponentContext
> & xContext
) :
62 DataInterpreter( xContext
),
63 m_eStockVariant( eVariant
)
66 StockDataInterpreter::~StockDataInterpreter()
69 StockChartTypeTemplate::StockVariant
StockDataInterpreter::GetStockVariant() const
71 return m_eStockVariant
;
74 // ____ XDataInterpreter ____
75 InterpretedData SAL_CALL
StockDataInterpreter::interpretDataSource(
76 const Reference
< data::XDataSource
>& xSource
,
77 const Sequence
< beans::PropertyValue
>& rArguments
,
78 const Sequence
< Reference
< XDataSeries
> >& rSeriesToReUse
)
79 throw (uno::RuntimeException
)
82 return InterpretedData();
84 Reference
< data::XLabeledDataSequence
> xCategories
;
85 Sequence
< Reference
< data::XLabeledDataSequence
> > aData( xSource
->getDataSequences() );
86 const sal_Int32
nDataCount( aData
.getLength());
88 // sub-type properties
89 const StockChartTypeTemplate::StockVariant
eVar( GetStockVariant());
90 const bool bHasOpenValues (( eVar
== StockChartTypeTemplate::OPEN_LOW_HI_CLOSE
) ||
91 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
));
92 const bool bHasVolume (( eVar
== StockChartTypeTemplate::VOL_LOW_HI_CLOSE
) ||
93 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
));
94 const bool bHasCategories( HasCategories( rArguments
, aData
));
96 // necessary roles for "full series"
98 sal_Int32
nNumberOfNecessarySequences( 3 );
100 ++nNumberOfNecessarySequences
;
102 ++nNumberOfNecessarySequences
;
104 // calculate number of full series (nNumOfFullSeries) and the number of remaining
105 // sequences used for additional "incomplete series" (nRemaining)
106 sal_Int32
nNumOfFullSeries( 0 );
107 sal_Int32
nRemaining( 0 );
109 sal_Int32
nAvailableSequences( nDataCount
);
111 --nAvailableSequences
;
112 nNumOfFullSeries
= nAvailableSequences
/ nNumberOfNecessarySequences
;
113 nRemaining
= nAvailableSequences
% nNumberOfNecessarySequences
;
115 sal_Int32 nCandleStickSeries
= nNumOfFullSeries
;
116 sal_Int32 nVolumeSeries
= nNumOfFullSeries
;
118 sal_Int32
nNumberOfGroups( bHasVolume
? 2 : 1 );
119 // sequences of data::XLabeledDataSequence per series per group
120 Sequence
< Sequence
< Sequence
< Reference
< data::XLabeledDataSequence
> > > > aSequences( nNumberOfGroups
);
121 sal_Int32
nBarGroupIndex( 0 );
122 sal_Int32
nCandleStickGroupIndex( nNumberOfGroups
- 1 );
124 // allocate space for labeled sequences
126 ++nCandleStickSeries
;
127 aSequences
[nCandleStickGroupIndex
].realloc( nCandleStickSeries
);
130 // if there are remaining sequences, the first one is taken for
131 // additional close values, the second one is taken as volume, if volume
135 aSequences
[nBarGroupIndex
].realloc( nVolumeSeries
);
140 sal_Int32 nSourceIndex
= 0; // index into aData sequence
145 xCategories
.set( aData
[nSourceIndex
] );
149 // 2. create "full" series
150 for( sal_Int32 nLabeledSeqIdx
=0; nLabeledSeqIdx
<nNumOfFullSeries
; ++nLabeledSeqIdx
)
155 aSequences
[nBarGroupIndex
][nLabeledSeqIdx
].realloc( 1 );
156 aSequences
[nBarGroupIndex
][nLabeledSeqIdx
][0].set( aData
[nSourceIndex
] );
157 if( aData
[nSourceIndex
].is())
158 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-y"));
162 sal_Int32 nSeqIdx
= 0;
165 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
].realloc( 4 );
166 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
167 if( aData
[nSourceIndex
].is())
168 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-first"));
169 ++nSourceIndex
, ++nSeqIdx
;
172 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
].realloc( 3 );
174 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
175 if( aData
[nSourceIndex
].is())
176 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-min"));
177 ++nSourceIndex
, ++nSeqIdx
;
179 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
180 if( aData
[nSourceIndex
].is())
181 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-max"));
182 ++nSourceIndex
, ++nSeqIdx
;
184 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
185 if( aData
[nSourceIndex
].is())
186 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-last"));
187 ++nSourceIndex
, ++nSeqIdx
;
190 // 3. create series with remaining sequences
191 if( bHasVolume
&& nRemaining
> 1 )
193 OSL_ASSERT( nVolumeSeries
> nNumOfFullSeries
);
194 aSequences
[nBarGroupIndex
][nVolumeSeries
- 1].realloc( 1 );
195 OSL_ASSERT( nDataCount
> nSourceIndex
);
196 if( aData
[nSourceIndex
].is())
197 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-y"));
198 aSequences
[nBarGroupIndex
][nVolumeSeries
- 1][0].set( aData
[nSourceIndex
] );
201 OSL_ENSURE( nRemaining
, "additional bar should only be used if there is at least one more sequence for a candle stick" );
207 OSL_ASSERT( nCandleStickSeries
> nNumOfFullSeries
);
208 const sal_Int32 nSeriesIndex
= nCandleStickSeries
- 1;
209 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
].realloc( nRemaining
);
210 OSL_ASSERT( nDataCount
> nSourceIndex
);
213 sal_Int32
nSeqIdx( 0 );
214 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
][nSeqIdx
].set( aData
[nSourceIndex
] );
215 if( aData
[nSourceIndex
].is())
216 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-min"));
217 ++nSourceIndex
, ++nSeqIdx
;
220 if( nSeqIdx
< nRemaining
)
222 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
][nSeqIdx
].set( aData
[nSourceIndex
] );
223 if( aData
[nSourceIndex
].is())
224 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-max"));
225 ++nSourceIndex
, ++nSeqIdx
;
229 OSL_ENSURE( bHasOpenValues
|| nSeqIdx
>= nRemaining
, "could have created full series" );
230 if( nSeqIdx
< nRemaining
)
232 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
][nSeqIdx
].set( aData
[nSourceIndex
] );
233 if( aData
[nSourceIndex
].is())
234 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-last"));
235 ++nSourceIndex
, ++nSeqIdx
;
239 OSL_ENSURE( nSeqIdx
>= nRemaining
, "could have created full series" );
243 Sequence
< Sequence
< Reference
< XDataSeries
> > > aResultSeries( nNumberOfGroups
);
244 sal_Int32 nGroupIndex
, nReUsedSeriesIdx
= 0;
245 for( nGroupIndex
=0; nGroupIndex
<nNumberOfGroups
; ++nGroupIndex
)
247 const sal_Int32 nNumSeriesData
= aSequences
[nGroupIndex
].getLength();
248 aResultSeries
[nGroupIndex
].realloc( nNumSeriesData
);
249 for( sal_Int32 nSeriesIdx
= 0; nSeriesIdx
< nNumSeriesData
; ++nSeriesIdx
, ++nReUsedSeriesIdx
)
253 Reference
< XDataSeries
> xSeries
;
254 if( nReUsedSeriesIdx
< rSeriesToReUse
.getLength())
255 xSeries
.set( rSeriesToReUse
[nReUsedSeriesIdx
] );
257 xSeries
.set( new DataSeries( GetComponentContext() ) );
258 OSL_ASSERT( xSeries
.is() );
259 Reference
< data::XDataSink
> xSink( xSeries
, uno::UNO_QUERY_THROW
);
260 OSL_ASSERT( xSink
.is() );
261 xSink
->setData( aSequences
[nGroupIndex
][nSeriesIdx
] );
262 aResultSeries
[nGroupIndex
][nSeriesIdx
].set( xSeries
);
264 catch( uno::Exception
& ex
)
266 ASSERT_EXCEPTION( ex
);
271 return InterpretedData( aResultSeries
, xCategories
);
274 // criterion: there must be two groups for stock-charts with volume and all
275 // series must have the correct number of data::XLabeledDataSequences
277 // todo: skip first criterion? (to allow easy switch from stock-chart without
278 // volume to one with volume)
279 sal_Bool SAL_CALL
StockDataInterpreter::isDataCompatible(
280 const InterpretedData
& aInterpretedData
)
281 throw (uno::RuntimeException
)
284 sal_Int32 nNumberOfNecessarySequences
= 3;
286 StockChartTypeTemplate::StockVariant
eVar( GetStockVariant());
287 if( ( eVar
== StockChartTypeTemplate::OPEN_LOW_HI_CLOSE
) ||
288 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
))
289 ++nNumberOfNecessarySequences
;
291 bool bHasVolume
= (( eVar
== StockChartTypeTemplate::VOL_LOW_HI_CLOSE
) ||
292 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
));
294 // 1. correct number of sub-types
295 if( aInterpretedData
.Series
.getLength() < (bHasVolume
? 2 : 1 ))
298 // 2. a. volume -- use default check
301 if( ! DataInterpreter::isDataCompatible(
302 InterpretedData( Sequence
< Sequence
< Reference
< XDataSeries
> > >(
303 aInterpretedData
.Series
.getConstArray(), 1 ),
304 aInterpretedData
.Categories
)))
310 OSL_ASSERT( aInterpretedData
.Series
.getLength() > (bHasVolume
? 1 : 0));
311 Sequence
< Reference
< XDataSeries
> > aSeries( aInterpretedData
.Series
[(bHasVolume
? 1 : 0)] );
312 if(!aSeries
.getLength())
314 for( sal_Int32 i
=0; i
<aSeries
.getLength(); ++i
)
318 Reference
< data::XDataSource
> xSrc( aSeries
[i
], uno::UNO_QUERY_THROW
);
319 Sequence
< Reference
< data::XLabeledDataSequence
> > aSeq( xSrc
->getDataSequences());
320 if( aSeq
.getLength() != nNumberOfNecessarySequences
)
323 catch( uno::Exception
& ex
)
325 ASSERT_EXCEPTION( ex
);
330 // 2. c. additional series
336 InterpretedData SAL_CALL
StockDataInterpreter::reinterpretDataSeries(
337 const InterpretedData
& aInterpretedData
)
338 throw (uno::RuntimeException
)
340 // prerequisite: StockDataInterpreter::isDataCompatible() returned true
341 return aInterpretedData
;