1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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>
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
;
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
)
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"
79 sal_Int32
nNumberOfNecessarySequences( 3 );
81 ++nNumberOfNecessarySequences
;
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
);
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
107 ++nCandleStickSeries
;
108 aSequences
[nCandleStickGroupIndex
].realloc( nCandleStickSeries
);
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
116 aSequences
[nBarGroupIndex
].realloc( nVolumeSeries
);
120 sal_Int32 nSourceIndex
= 0; // index into aData sequence
125 xCategories
.set( aData
[nSourceIndex
] );
129 // 2. create "full" series
130 for( sal_Int32 nLabeledSeqIdx
=0; nLabeledSeqIdx
<nNumOfFullSeries
; ++nLabeledSeqIdx
)
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");
142 sal_Int32 nSeqIdx
= 0;
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
;
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
] );
181 OSL_ENSURE( nRemaining
, "additional bar should only be used if there is at least one more sequence for a candle stick" );
187 OSL_ASSERT( nCandleStickSeries
> nNumOfFullSeries
);
188 const sal_Int32 nSeriesIndex
= nCandleStickSeries
- 1;
189 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
].realloc( nRemaining
);
190 OSL_ASSERT( nDataCount
> nSourceIndex
);
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
;
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
;
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
;
219 OSL_ENSURE( nSeqIdx
>= nRemaining
, "could have created full series" );
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
] );
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
)
264 sal_Int32 nNumberOfNecessarySequences
= 3;
266 StockChartTypeTemplate::StockVariant
eVar( GetStockVariant());
267 if( ( eVar
== StockChartTypeTemplate::OPEN_LOW_HI_CLOSE
) ||
268 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
))
269 ++nNumberOfNecessarySequences
;
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 ))
278 // 2. a. volume -- use default check
281 if( ! DataInterpreter::isDataCompatible(
282 InterpretedData( Sequence
< Sequence
< Reference
< XDataSeries
> > >(
283 aInterpretedData
.Series
.getConstArray(), 1 ),
284 aInterpretedData
.Categories
)))
290 OSL_ASSERT( aInterpretedData
.Series
.getLength() > (bHasVolume
? 1 : 0));
291 Sequence
< Reference
< XDataSeries
> > aSeries( aInterpretedData
.Series
[(bHasVolume
? 1 : 0)] );
292 if(!aSeries
.getLength())
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
)
303 catch( const uno::Exception
& ex
)
305 ASSERT_EXCEPTION( ex
);
310 // 2. c. additional series
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
;
326 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */