tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / chart2 / source / model / template / StockDataInterpreter.cxx
blob75e0bb439c727d22c46be103808540f7cf4e2d7a
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 <sal/config.h>
22 #include <cstddef>
24 #include "StockDataInterpreter.hxx"
25 #include "StockChartTypeTemplate.hxx"
26 #include <DataSeries.hxx>
27 #include <comphelper/diagnose_ex.hxx>
29 using namespace ::com::sun::star;
30 using namespace ::com::sun::star::chart2;
32 using ::com::sun::star::uno::Reference;
33 using ::com::sun::star::uno::Sequence;
35 namespace chart
38 // explicit
39 StockDataInterpreter::StockDataInterpreter(
40 StockChartTypeTemplate::StockVariant eVariant ) :
41 m_eStockVariant( eVariant )
44 StockDataInterpreter::~StockDataInterpreter()
47 // ____ XDataInterpreter ____
48 InterpretedData StockDataInterpreter::interpretDataSource(
49 const Reference< data::XDataSource >& xSource,
50 const Sequence< beans::PropertyValue >& rArguments,
51 const std::vector< rtl::Reference< ::chart::DataSeries > >& rSeriesToReUse )
53 if( ! xSource.is())
54 return InterpretedData();
56 uno::Reference< chart2::data::XLabeledDataSequence > xCategories;
57 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = DataInterpreter::getDataSequences(xSource);
58 const sal_Int32 nDataCount( aData.size());
60 // sub-type properties
61 const StockChartTypeTemplate::StockVariant eVar( GetStockVariant());
62 const bool bHasOpenValues (( eVar == StockChartTypeTemplate::StockVariant::Open ) ||
63 ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen ));
64 const bool bHasVolume (( eVar == StockChartTypeTemplate::StockVariant::Volume ) ||
65 ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen ));
66 const bool bHasCategories( HasCategories( rArguments, aData ));
68 // necessary roles for "full series"
69 // low/high/close
70 sal_Int32 nNumberOfNecessarySequences( 3 );
71 if( bHasOpenValues )
72 ++nNumberOfNecessarySequences;
73 if( bHasVolume )
74 ++nNumberOfNecessarySequences;
76 // calculate number of full series (nNumOfFullSeries) and the number of remaining
77 // sequences used for additional "incomplete series" (nRemaining)
78 sal_Int32 nNumOfFullSeries( 0 );
79 sal_Int32 nRemaining( 0 );
81 sal_Int32 nAvailableSequences( nDataCount );
82 if( bHasCategories )
83 --nAvailableSequences;
84 nNumOfFullSeries = nAvailableSequences / nNumberOfNecessarySequences;
85 nRemaining = nAvailableSequences % nNumberOfNecessarySequences;
87 sal_Int32 nCandleStickSeries = nNumOfFullSeries;
88 sal_Int32 nVolumeSeries = nNumOfFullSeries;
90 sal_Int32 nNumberOfGroups( bHasVolume ? 2 : 1 );
91 // sequences of data::XLabeledDataSequence per series per group
92 std::vector< std::vector< std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > > > aSequences( nNumberOfGroups );
93 const sal_Int32 nBarGroupIndex( 0 );
94 const sal_Int32 nCandleStickGroupIndex( nNumberOfGroups - 1 );
96 // allocate space for labeled sequences
97 if( nRemaining > 0 )
98 ++nCandleStickSeries;
99 aSequences[nCandleStickGroupIndex].resize( nCandleStickSeries );
100 auto & pCandleStickGroup = aSequences[nCandleStickGroupIndex];
101 if( bHasVolume )
103 // if there are remaining sequences, the first one is taken for
104 // additional close values, the second one is taken as volume, if volume
105 // is used
106 if( nRemaining > 1 )
107 ++nVolumeSeries;
108 aSequences[nBarGroupIndex].resize( nVolumeSeries );
110 auto & pBarGroup = aSequences[nBarGroupIndex];
112 // create data
113 sal_Int32 nSourceIndex = 0; // index into aData sequence
115 // 1. categories
116 if( bHasCategories )
118 xCategories = aData[nSourceIndex];
119 ++nSourceIndex;
122 // 2. create "full" series
123 for( sal_Int32 nLabeledSeqIdx=0; nLabeledSeqIdx<nNumOfFullSeries; ++nLabeledSeqIdx )
125 // bar
126 if( bHasVolume )
128 pBarGroup[nLabeledSeqIdx].resize( 1 );
129 pBarGroup[nLabeledSeqIdx][0] = aData[nSourceIndex];
130 if( aData[nSourceIndex].is())
131 SetRole( aData[nSourceIndex]->getValues(), u"values-y"_ustr);
132 ++nSourceIndex;
135 sal_Int32 nSeqIdx = 0;
136 if( bHasOpenValues )
138 pCandleStickGroup[nLabeledSeqIdx].resize( 4 );
139 pCandleStickGroup[nLabeledSeqIdx][nSeqIdx] = aData[nSourceIndex];
140 if( aData[nSourceIndex].is())
141 SetRole( aData[nSourceIndex]->getValues(), u"values-first"_ustr);
142 ++nSourceIndex;
143 ++nSeqIdx;
145 else
146 pCandleStickGroup[nLabeledSeqIdx].resize( 3 );
147 auto & pLabeledSeq = pCandleStickGroup[nLabeledSeqIdx];
149 pLabeledSeq[nSeqIdx] = aData[nSourceIndex];
150 if( aData[nSourceIndex].is())
151 SetRole( aData[nSourceIndex]->getValues(), u"values-min"_ustr);
152 ++nSourceIndex;
153 ++nSeqIdx;
155 pLabeledSeq[nSeqIdx] = aData[nSourceIndex];
156 if( aData[nSourceIndex].is())
157 SetRole( aData[nSourceIndex]->getValues(), u"values-max"_ustr);
158 ++nSourceIndex;
159 ++nSeqIdx;
161 pLabeledSeq[nSeqIdx] = aData[nSourceIndex];
162 if( aData[nSourceIndex].is())
163 SetRole( aData[nSourceIndex]->getValues(), u"values-last"_ustr);
164 ++nSourceIndex;
165 ++nSeqIdx;
168 // 3. create series with remaining sequences
169 if( bHasVolume && nRemaining > 1 )
171 OSL_ASSERT( nVolumeSeries > nNumOfFullSeries );
172 pBarGroup[nVolumeSeries - 1].resize( 1 );
173 OSL_ASSERT( nDataCount > nSourceIndex );
174 if( aData[nSourceIndex].is())
175 SetRole( aData[nSourceIndex]->getValues(), u"values-y"_ustr);
176 pBarGroup[nVolumeSeries - 1][0] = aData[nSourceIndex];
177 ++nSourceIndex;
178 --nRemaining;
179 OSL_ENSURE( nRemaining, "additional bar should only be used if there is at least one more sequence for a candle stick" );
182 // candle-stick
183 if( nRemaining > 0 )
185 OSL_ASSERT( nCandleStickSeries > nNumOfFullSeries );
186 const sal_Int32 nSeriesIndex = nCandleStickSeries - 1;
187 pCandleStickGroup[nSeriesIndex].resize( nRemaining );
188 auto & pLabeledSeq = pCandleStickGroup[nSeriesIndex];
189 OSL_ASSERT( nDataCount > nSourceIndex );
191 // 1. low
192 sal_Int32 nSeqIdx( 0 );
193 pLabeledSeq[nSeqIdx] = aData[nSourceIndex];
194 if( aData[nSourceIndex].is())
195 SetRole( aData[nSourceIndex]->getValues(), u"values-min"_ustr);
196 ++nSourceIndex;
197 ++nSeqIdx;
199 // 2. high
200 if( nSeqIdx < nRemaining )
202 pLabeledSeq[nSeqIdx] = aData[nSourceIndex];
203 if( aData[nSourceIndex].is())
204 SetRole( aData[nSourceIndex]->getValues(), u"values-max"_ustr);
205 ++nSourceIndex;
206 ++nSeqIdx;
209 // 3. close
210 OSL_ENSURE( bHasOpenValues || nSeqIdx >= nRemaining, "could have created full series" );
211 if( nSeqIdx < nRemaining )
213 pLabeledSeq[nSeqIdx] = aData[nSourceIndex];
214 if( aData[nSourceIndex].is())
215 SetRole( aData[nSourceIndex]->getValues(), u"values-last"_ustr);
216 ++nSourceIndex;
217 ++nSeqIdx;
220 // 4. open
221 OSL_ENSURE( nSeqIdx >= nRemaining, "could have created full series" );
224 // create DataSeries
225 std::vector< std::vector< rtl::Reference< DataSeries > > > aResultSeries( nNumberOfGroups );
226 sal_Int32 nGroupIndex;
227 std::size_t nReUsedSeriesIdx = 0;
228 for( nGroupIndex=0; nGroupIndex<nNumberOfGroups; ++nGroupIndex )
230 const sal_Int32 nNumSeriesData = aSequences[nGroupIndex].size();
231 aResultSeries[nGroupIndex].resize( nNumSeriesData );
232 auto & pResultSerie = aResultSeries[nGroupIndex];
233 for( sal_Int32 nSeriesIdx = 0; nSeriesIdx < nNumSeriesData; ++nSeriesIdx, ++nReUsedSeriesIdx )
237 rtl::Reference< DataSeries > xSeries;
238 if( nReUsedSeriesIdx < rSeriesToReUse.size())
239 xSeries = rSeriesToReUse[nReUsedSeriesIdx];
240 else
241 xSeries = new DataSeries;
242 assert( xSeries.is() );
243 xSeries->setData( aSequences[nGroupIndex][nSeriesIdx] );
244 pResultSerie[nSeriesIdx] = std::move(xSeries);
246 catch( const uno::Exception & )
248 DBG_UNHANDLED_EXCEPTION("chart2");
253 return { std::move(aResultSeries), xCategories };
256 // criterion: there must be two groups for stock-charts with volume and all
257 // series must have the correct number of data::XLabeledDataSequences
259 // todo: skip first criterion? (to allow easy switch from stock-chart without
260 // volume to one with volume)
261 bool StockDataInterpreter::isDataCompatible(
262 const InterpretedData& aInterpretedData )
264 // high/low/close
265 std::size_t nNumberOfNecessarySequences = 3;
266 // open
267 StockChartTypeTemplate::StockVariant eVar( GetStockVariant());
268 if( ( eVar == StockChartTypeTemplate::StockVariant::Open ) ||
269 ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen ))
270 ++nNumberOfNecessarySequences;
271 // volume
272 bool bHasVolume = (( eVar == StockChartTypeTemplate::StockVariant::Volume ) ||
273 ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen ));
275 // 1. correct number of sub-types
276 if( aInterpretedData.Series.size() < (bHasVolume ? 2U : 1U ))
277 return false;
279 // 2. a. volume -- use default check
280 if( bHasVolume )
282 if( ! DataInterpreter::isDataCompatible(
283 { std::vector< std::vector< rtl::Reference< DataSeries > > >{
284 aInterpretedData.Series[0] },
285 aInterpretedData.Categories }))
286 return false;
289 // 2. b. candlestick
291 OSL_ASSERT( aInterpretedData.Series.size() > (bHasVolume ? 1U : 0U));
292 const std::vector< rtl::Reference< DataSeries > > & aSeries = aInterpretedData.Series[(bHasVolume ? 1 : 0)];
293 if(aSeries.empty())
294 return false;
295 for( rtl::Reference< DataSeries > const & dataSeries : aSeries )
299 if( dataSeries->getDataSequences2().size() != nNumberOfNecessarySequences )
300 return false;
302 catch( const uno::Exception & )
304 DBG_UNHANDLED_EXCEPTION("chart2");
309 // 2. c. additional series
310 // ignore
312 return true;
315 InterpretedData StockDataInterpreter::reinterpretDataSeries(
316 const InterpretedData& aInterpretedData )
318 // prerequisite: StockDataInterpreter::isDataCompatible() returned true
319 return aInterpretedData;
322 uno::Any StockDataInterpreter::getChartTypeSpecificData(
323 const OUString& sKey )
325 if( sKey == "stock variant" )
327 StockChartTypeTemplate::StockVariant eStockVariant( GetStockVariant());
328 std::map< StockChartTypeTemplate::StockVariant, sal_Int32 > aTranslation {
329 { StockChartTypeTemplate::StockVariant::NONE, 0 },
330 { StockChartTypeTemplate::StockVariant::Open, 1 },
331 { StockChartTypeTemplate::StockVariant::Volume, 2 },
332 { StockChartTypeTemplate::StockVariant::VolumeOpen, 3 }
334 return uno::Any( aTranslation[eStockVariant] );
336 return uno::Any();
339 } // namespace chart
341 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */