1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: StockDataInterpreter.cxx,v $
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"
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>
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
;
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
)
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"
101 sal_Int32
nNumberOfNecessarySequences( 3 );
103 ++nNumberOfNecessarySequences
;
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
);
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
129 ++nCandleStickSeries
;
130 aSequences
[nCandleStickGroupIndex
].realloc( nCandleStickSeries
);
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
138 aSequences
[nBarGroupIndex
].realloc( nVolumeSeries
);
143 sal_Int32 nSourceIndex
= 0; // index into aData sequence
148 xCategories
.set( aData
[nSourceIndex
] );
152 // 2. create "full" series
153 for( sal_Int32 nLabeledSeqIdx
=0; nLabeledSeqIdx
<nNumOfFullSeries
; ++nLabeledSeqIdx
)
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"));
165 sal_Int32 nSeqIdx
= 0;
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
;
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
] );
204 OSL_ENSURE( nRemaining
, "additional bar should only be used if there is at least one more sequence for a candle stick" );
210 OSL_ASSERT( nCandleStickSeries
> nNumOfFullSeries
);
211 const sal_Int32 nSeriesIndex
= nCandleStickSeries
- 1;
212 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
].realloc( nRemaining
);
213 OSL_ASSERT( nDataCount
> nSourceIndex
);
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
;
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
;
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
;
242 OSL_ENSURE( nSeqIdx
>= nRemaining
, "could have created full series" );
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
] );
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
)
288 sal_Int32 nNumberOfNecessarySequences
= 3;
290 StockChartTypeTemplate::StockVariant
eVar( GetStockVariant());
291 if( ( eVar
== StockChartTypeTemplate::OPEN_LOW_HI_CLOSE
) ||
292 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
))
293 ++nNumberOfNecessarySequences
;
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 ))
302 // 2. a. volume -- use default check
305 if( ! DataInterpreter::isDataCompatible(
306 InterpretedData( Sequence
< Sequence
< Reference
< XDataSeries
> > >(
307 aInterpretedData
.Series
.getConstArray(), 1 ),
308 aInterpretedData
.Categories
, aInterpretedData
.UnusedData
)))
314 OSL_ASSERT( aInterpretedData
.Series
.getLength() > (bHasVolume
? 1 : 0));
315 Sequence
< Reference
< XDataSeries
> > aSeries( aInterpretedData
.Series
[(bHasVolume
? 1 : 0)] );
316 if(!aSeries
.getLength())
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
)
327 catch( uno::Exception
& ex
)
329 ASSERT_EXCEPTION( ex
);
334 // 2. c. additional series
340 InterpretedData SAL_CALL
StockDataInterpreter::reinterpretDataSeries(
341 const InterpretedData
& aInterpretedData
)
342 throw (uno::RuntimeException
)
344 // prerequisite: StockDataInterpreter::isDataCompatible() returned true
345 return aInterpretedData
;