1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "StockDataInterpreter.hxx"
31 #include "DataSeries.hxx"
33 #include "DataSeriesHelper.hxx"
34 #include "CommonConverters.hxx"
35 #include "ContainerHelper.hxx"
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/chart2/data/XDataSink.hpp>
43 using namespace ::com::sun::star
;
44 using namespace ::com::sun::star::chart2
;
45 using namespace ::std
;
47 using ::com::sun::star::uno::Reference
;
48 using ::com::sun::star::uno::Sequence
;
49 using ::rtl::OUString
;
50 using namespace ::chart::ContainerHelper
;
56 StockDataInterpreter::StockDataInterpreter(
57 StockChartTypeTemplate::StockVariant eVariant
,
58 const Reference
< uno::XComponentContext
> & xContext
) :
59 DataInterpreter( xContext
),
60 m_eStockVariant( eVariant
)
63 StockDataInterpreter::~StockDataInterpreter()
66 StockChartTypeTemplate::StockVariant
StockDataInterpreter::GetStockVariant() const
68 return m_eStockVariant
;
71 // ____ XDataInterpreter ____
72 InterpretedData SAL_CALL
StockDataInterpreter::interpretDataSource(
73 const Reference
< data::XDataSource
>& xSource
,
74 const Sequence
< beans::PropertyValue
>& rArguments
,
75 const Sequence
< Reference
< XDataSeries
> >& rSeriesToReUse
)
76 throw (uno::RuntimeException
)
79 return InterpretedData();
81 Reference
< data::XLabeledDataSequence
> xCategories
;
82 Sequence
< Reference
< data::XLabeledDataSequence
> > aData( xSource
->getDataSequences() );
83 const sal_Int32
nDataCount( aData
.getLength());
85 // sub-type properties
86 const StockChartTypeTemplate::StockVariant
eVar( GetStockVariant());
87 const bool bHasOpenValues (( eVar
== StockChartTypeTemplate::OPEN_LOW_HI_CLOSE
) ||
88 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
));
89 const bool bHasVolume (( eVar
== StockChartTypeTemplate::VOL_LOW_HI_CLOSE
) ||
90 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
));
91 const bool bHasCategories( HasCategories( rArguments
, aData
));
93 // necessary roles for "full series"
95 sal_Int32
nNumberOfNecessarySequences( 3 );
97 ++nNumberOfNecessarySequences
;
99 ++nNumberOfNecessarySequences
;
101 // calculate number of full series (nNumOfFullSeries) and the number of remaining
102 // sequences used for additional "incomplete series" (nRemaining)
103 sal_Int32
nNumOfFullSeries( 0 );
104 sal_Int32
nRemaining( 0 );
106 sal_Int32
nAvailableSequences( nDataCount
);
108 --nAvailableSequences
;
109 nNumOfFullSeries
= nAvailableSequences
/ nNumberOfNecessarySequences
;
110 nRemaining
= nAvailableSequences
% nNumberOfNecessarySequences
;
112 sal_Int32 nCandleStickSeries
= nNumOfFullSeries
;
113 sal_Int32 nVolumeSeries
= nNumOfFullSeries
;
115 sal_Int32
nNumberOfGroups( bHasVolume
? 2 : 1 );
116 // sequences of data::XLabeledDataSequence per series per group
117 Sequence
< Sequence
< Sequence
< Reference
< data::XLabeledDataSequence
> > > > aSequences( nNumberOfGroups
);
118 sal_Int32
nBarGroupIndex( 0 );
119 sal_Int32
nCandleStickGroupIndex( nNumberOfGroups
- 1 );
121 // allocate space for labeled sequences
123 ++nCandleStickSeries
;
124 aSequences
[nCandleStickGroupIndex
].realloc( nCandleStickSeries
);
127 // if there are remaining sequences, the first one is taken for
128 // additional close values, the second one is taken as volume, if volume
132 aSequences
[nBarGroupIndex
].realloc( nVolumeSeries
);
137 sal_Int32 nSourceIndex
= 0; // index into aData sequence
142 xCategories
.set( aData
[nSourceIndex
] );
146 // 2. create "full" series
147 for( sal_Int32 nLabeledSeqIdx
=0; nLabeledSeqIdx
<nNumOfFullSeries
; ++nLabeledSeqIdx
)
152 aSequences
[nBarGroupIndex
][nLabeledSeqIdx
].realloc( 1 );
153 aSequences
[nBarGroupIndex
][nLabeledSeqIdx
][0].set( aData
[nSourceIndex
] );
154 if( aData
[nSourceIndex
].is())
155 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-y"));
159 sal_Int32 nSeqIdx
= 0;
162 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
].realloc( 4 );
163 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
164 if( aData
[nSourceIndex
].is())
165 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-first"));
166 ++nSourceIndex
, ++nSeqIdx
;
169 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
].realloc( 3 );
171 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
172 if( aData
[nSourceIndex
].is())
173 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-min"));
174 ++nSourceIndex
, ++nSeqIdx
;
176 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
177 if( aData
[nSourceIndex
].is())
178 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-max"));
179 ++nSourceIndex
, ++nSeqIdx
;
181 aSequences
[nCandleStickGroupIndex
][nLabeledSeqIdx
][nSeqIdx
].set( aData
[nSourceIndex
] );
182 if( aData
[nSourceIndex
].is())
183 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-last"));
184 ++nSourceIndex
, ++nSeqIdx
;
187 // 3. create series with remaining sequences
188 if( bHasVolume
&& nRemaining
> 1 )
190 OSL_ASSERT( nVolumeSeries
> nNumOfFullSeries
);
191 aSequences
[nBarGroupIndex
][nVolumeSeries
- 1].realloc( 1 );
192 OSL_ASSERT( nDataCount
> nSourceIndex
);
193 if( aData
[nSourceIndex
].is())
194 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-y"));
195 aSequences
[nBarGroupIndex
][nVolumeSeries
- 1][0].set( aData
[nSourceIndex
] );
198 OSL_ENSURE( nRemaining
, "additional bar should only be used if there is at least one more sequence for a candle stick" );
204 OSL_ASSERT( nCandleStickSeries
> nNumOfFullSeries
);
205 const sal_Int32 nSeriesIndex
= nCandleStickSeries
- 1;
206 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
].realloc( nRemaining
);
207 OSL_ASSERT( nDataCount
> nSourceIndex
);
210 sal_Int32
nSeqIdx( 0 );
211 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
][nSeqIdx
].set( aData
[nSourceIndex
] );
212 if( aData
[nSourceIndex
].is())
213 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-min"));
214 ++nSourceIndex
, ++nSeqIdx
;
217 if( nSeqIdx
< nRemaining
)
219 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
][nSeqIdx
].set( aData
[nSourceIndex
] );
220 if( aData
[nSourceIndex
].is())
221 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-max"));
222 ++nSourceIndex
, ++nSeqIdx
;
226 OSL_ENSURE( bHasOpenValues
|| nSeqIdx
>= nRemaining
, "could have created full series" );
227 if( nSeqIdx
< nRemaining
)
229 aSequences
[nCandleStickGroupIndex
][nSeriesIndex
][nSeqIdx
].set( aData
[nSourceIndex
] );
230 if( aData
[nSourceIndex
].is())
231 SetRole( aData
[nSourceIndex
]->getValues(), C2U("values-last"));
232 ++nSourceIndex
, ++nSeqIdx
;
236 OSL_ENSURE( nSeqIdx
>= nRemaining
, "could have created full series" );
240 Sequence
< Sequence
< Reference
< XDataSeries
> > > aResultSeries( nNumberOfGroups
);
241 sal_Int32 nGroupIndex
, nReUsedSeriesIdx
= 0;
242 for( nGroupIndex
=0; nGroupIndex
<nNumberOfGroups
; ++nGroupIndex
)
244 const sal_Int32 nNumSeriesData
= aSequences
[nGroupIndex
].getLength();
245 aResultSeries
[nGroupIndex
].realloc( nNumSeriesData
);
246 for( sal_Int32 nSeriesIdx
= 0; nSeriesIdx
< nNumSeriesData
; ++nSeriesIdx
, ++nReUsedSeriesIdx
)
250 Reference
< XDataSeries
> xSeries
;
251 if( nReUsedSeriesIdx
< rSeriesToReUse
.getLength())
252 xSeries
.set( rSeriesToReUse
[nReUsedSeriesIdx
] );
254 xSeries
.set( new DataSeries( GetComponentContext() ) );
255 OSL_ASSERT( xSeries
.is() );
256 Reference
< data::XDataSink
> xSink( xSeries
, uno::UNO_QUERY_THROW
);
257 OSL_ASSERT( xSink
.is() );
258 xSink
->setData( aSequences
[nGroupIndex
][nSeriesIdx
] );
259 aResultSeries
[nGroupIndex
][nSeriesIdx
].set( xSeries
);
261 catch( const uno::Exception
& ex
)
263 ASSERT_EXCEPTION( ex
);
268 return InterpretedData( aResultSeries
, xCategories
);
271 // criterion: there must be two groups for stock-charts with volume and all
272 // series must have the correct number of data::XLabeledDataSequences
274 // todo: skip first criterion? (to allow easy switch from stock-chart without
275 // volume to one with volume)
276 sal_Bool SAL_CALL
StockDataInterpreter::isDataCompatible(
277 const InterpretedData
& aInterpretedData
)
278 throw (uno::RuntimeException
)
281 sal_Int32 nNumberOfNecessarySequences
= 3;
283 StockChartTypeTemplate::StockVariant
eVar( GetStockVariant());
284 if( ( eVar
== StockChartTypeTemplate::OPEN_LOW_HI_CLOSE
) ||
285 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
))
286 ++nNumberOfNecessarySequences
;
288 bool bHasVolume
= (( eVar
== StockChartTypeTemplate::VOL_LOW_HI_CLOSE
) ||
289 ( eVar
== StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE
));
291 // 1. correct number of sub-types
292 if( aInterpretedData
.Series
.getLength() < (bHasVolume
? 2 : 1 ))
295 // 2. a. volume -- use default check
298 if( ! DataInterpreter::isDataCompatible(
299 InterpretedData( Sequence
< Sequence
< Reference
< XDataSeries
> > >(
300 aInterpretedData
.Series
.getConstArray(), 1 ),
301 aInterpretedData
.Categories
)))
307 OSL_ASSERT( aInterpretedData
.Series
.getLength() > (bHasVolume
? 1 : 0));
308 Sequence
< Reference
< XDataSeries
> > aSeries( aInterpretedData
.Series
[(bHasVolume
? 1 : 0)] );
309 if(!aSeries
.getLength())
311 for( sal_Int32 i
=0; i
<aSeries
.getLength(); ++i
)
315 Reference
< data::XDataSource
> xSrc( aSeries
[i
], uno::UNO_QUERY_THROW
);
316 Sequence
< Reference
< data::XLabeledDataSequence
> > aSeq( xSrc
->getDataSequences());
317 if( aSeq
.getLength() != nNumberOfNecessarySequences
)
320 catch( const uno::Exception
& ex
)
322 ASSERT_EXCEPTION( ex
);
327 // 2. c. additional series
333 InterpretedData SAL_CALL
StockDataInterpreter::reinterpretDataSeries(
334 const InterpretedData
& aInterpretedData
)
335 throw (uno::RuntimeException
)
337 // prerequisite: StockDataInterpreter::isDataCompatible() returned true
338 return aInterpretedData
;
343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */