1*cde9e8dcSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*cde9e8dcSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*cde9e8dcSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*cde9e8dcSAndrew Rist * distributed with this work for additional information 6*cde9e8dcSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*cde9e8dcSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*cde9e8dcSAndrew Rist * "License"); you may not use this file except in compliance 9*cde9e8dcSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*cde9e8dcSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*cde9e8dcSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*cde9e8dcSAndrew Rist * software distributed under the License is distributed on an 15*cde9e8dcSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*cde9e8dcSAndrew Rist * KIND, either express or implied. See the License for the 17*cde9e8dcSAndrew Rist * specific language governing permissions and limitations 18*cde9e8dcSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*cde9e8dcSAndrew Rist *************************************************************/ 21*cde9e8dcSAndrew Rist 22*cde9e8dcSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_chart2.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include "StockDataInterpreter.hxx" 28cdf0e10cSrcweir #include "DataSeries.hxx" 29cdf0e10cSrcweir #include "macros.hxx" 30cdf0e10cSrcweir #include "DataSeriesHelper.hxx" 31cdf0e10cSrcweir #include "CommonConverters.hxx" 32cdf0e10cSrcweir #include "ContainerHelper.hxx" 33cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 34cdf0e10cSrcweir #include <com/sun/star/chart2/data/XDataSink.hpp> 35cdf0e10cSrcweir 36cdf0e10cSrcweir // #include <deque> 37cdf0e10cSrcweir 38cdf0e10cSrcweir #include <vector> 39cdf0e10cSrcweir #include <algorithm> 40cdf0e10cSrcweir #include <iterator> 41cdf0e10cSrcweir 42cdf0e10cSrcweir using namespace ::com::sun::star; 43cdf0e10cSrcweir using namespace ::com::sun::star::chart2; 44cdf0e10cSrcweir using namespace ::std; 45cdf0e10cSrcweir 46cdf0e10cSrcweir using ::com::sun::star::uno::Reference; 47cdf0e10cSrcweir using ::com::sun::star::uno::Sequence; 48cdf0e10cSrcweir using ::rtl::OUString; 49cdf0e10cSrcweir using namespace ::chart::ContainerHelper; 50cdf0e10cSrcweir 51cdf0e10cSrcweir namespace chart 52cdf0e10cSrcweir { 53cdf0e10cSrcweir 54cdf0e10cSrcweir // explicit 55cdf0e10cSrcweir StockDataInterpreter::StockDataInterpreter( 56cdf0e10cSrcweir StockChartTypeTemplate::StockVariant eVariant, 57cdf0e10cSrcweir const Reference< uno::XComponentContext > & xContext ) : 58cdf0e10cSrcweir DataInterpreter( xContext ), 59cdf0e10cSrcweir m_eStockVariant( eVariant ) 60cdf0e10cSrcweir {} 61cdf0e10cSrcweir 62cdf0e10cSrcweir StockDataInterpreter::~StockDataInterpreter() 63cdf0e10cSrcweir {} 64cdf0e10cSrcweir 65cdf0e10cSrcweir StockChartTypeTemplate::StockVariant StockDataInterpreter::GetStockVariant() const 66cdf0e10cSrcweir { 67cdf0e10cSrcweir return m_eStockVariant; 68cdf0e10cSrcweir } 69cdf0e10cSrcweir 70cdf0e10cSrcweir // ____ XDataInterpreter ____ 71cdf0e10cSrcweir InterpretedData SAL_CALL StockDataInterpreter::interpretDataSource( 72cdf0e10cSrcweir const Reference< data::XDataSource >& xSource, 73cdf0e10cSrcweir const Sequence< beans::PropertyValue >& rArguments, 74cdf0e10cSrcweir const Sequence< Reference< XDataSeries > >& rSeriesToReUse ) 75cdf0e10cSrcweir throw (uno::RuntimeException) 76cdf0e10cSrcweir { 77cdf0e10cSrcweir if( ! xSource.is()) 78cdf0e10cSrcweir return InterpretedData(); 79cdf0e10cSrcweir 80cdf0e10cSrcweir Reference< data::XLabeledDataSequence > xCategories; 81cdf0e10cSrcweir Sequence< Reference< data::XLabeledDataSequence > > aData( xSource->getDataSequences() ); 82cdf0e10cSrcweir const sal_Int32 nDataCount( aData.getLength()); 83cdf0e10cSrcweir 84cdf0e10cSrcweir // sub-type properties 85cdf0e10cSrcweir const StockChartTypeTemplate::StockVariant eVar( GetStockVariant()); 86cdf0e10cSrcweir const bool bHasOpenValues (( eVar == StockChartTypeTemplate::OPEN_LOW_HI_CLOSE ) || 87cdf0e10cSrcweir ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE )); 88cdf0e10cSrcweir const bool bHasVolume (( eVar == StockChartTypeTemplate::VOL_LOW_HI_CLOSE ) || 89cdf0e10cSrcweir ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE )); 90cdf0e10cSrcweir const bool bHasCategories( HasCategories( rArguments, aData )); 91cdf0e10cSrcweir 92cdf0e10cSrcweir // necessary roles for "full series" 93cdf0e10cSrcweir // low/high/close 94cdf0e10cSrcweir sal_Int32 nNumberOfNecessarySequences( 3 ); 95cdf0e10cSrcweir if( bHasOpenValues ) 96cdf0e10cSrcweir ++nNumberOfNecessarySequences; 97cdf0e10cSrcweir if( bHasVolume ) 98cdf0e10cSrcweir ++nNumberOfNecessarySequences; 99cdf0e10cSrcweir 100cdf0e10cSrcweir // calculate number of full series (nNumOfFullSeries) and the number of remaining 101cdf0e10cSrcweir // sequences used for additional "incomplete series" (nRemaining) 102cdf0e10cSrcweir sal_Int32 nNumOfFullSeries( 0 ); 103cdf0e10cSrcweir sal_Int32 nRemaining( 0 ); 104cdf0e10cSrcweir { 105cdf0e10cSrcweir sal_Int32 nAvailableSequences( nDataCount ); 106cdf0e10cSrcweir if( bHasCategories ) 107cdf0e10cSrcweir --nAvailableSequences; 108cdf0e10cSrcweir nNumOfFullSeries = nAvailableSequences / nNumberOfNecessarySequences; 109cdf0e10cSrcweir nRemaining = nAvailableSequences % nNumberOfNecessarySequences; 110cdf0e10cSrcweir } 111cdf0e10cSrcweir sal_Int32 nCandleStickSeries = nNumOfFullSeries; 112cdf0e10cSrcweir sal_Int32 nVolumeSeries = nNumOfFullSeries; 113cdf0e10cSrcweir 114cdf0e10cSrcweir sal_Int32 nNumberOfGroups( bHasVolume ? 2 : 1 ); 115cdf0e10cSrcweir // sequences of data::XLabeledDataSequence per series per group 116cdf0e10cSrcweir Sequence< Sequence< Sequence< Reference< data::XLabeledDataSequence > > > > aSequences( nNumberOfGroups ); 117cdf0e10cSrcweir sal_Int32 nBarGroupIndex( 0 ); 118cdf0e10cSrcweir sal_Int32 nCandleStickGroupIndex( nNumberOfGroups - 1 ); 119cdf0e10cSrcweir 120cdf0e10cSrcweir // allocate space for labeled sequences 121cdf0e10cSrcweir if( nRemaining > 0 ) 122cdf0e10cSrcweir ++nCandleStickSeries; 123cdf0e10cSrcweir aSequences[nCandleStickGroupIndex].realloc( nCandleStickSeries ); 124cdf0e10cSrcweir if( bHasVolume ) 125cdf0e10cSrcweir { 126cdf0e10cSrcweir // if there are remaining sequences, the first one is taken for 127cdf0e10cSrcweir // additional close values, the second one is taken as volume, if volume 128cdf0e10cSrcweir // is used 129cdf0e10cSrcweir if( nRemaining > 1 ) 130cdf0e10cSrcweir ++nVolumeSeries; 131cdf0e10cSrcweir aSequences[nBarGroupIndex].realloc( nVolumeSeries ); 132cdf0e10cSrcweir } 133cdf0e10cSrcweir 134cdf0e10cSrcweir 135cdf0e10cSrcweir // create data 136cdf0e10cSrcweir sal_Int32 nSourceIndex = 0; // index into aData sequence 137cdf0e10cSrcweir 138cdf0e10cSrcweir // 1. categories 139cdf0e10cSrcweir if( bHasCategories ) 140cdf0e10cSrcweir { 141cdf0e10cSrcweir xCategories.set( aData[nSourceIndex] ); 142cdf0e10cSrcweir ++nSourceIndex; 143cdf0e10cSrcweir } 144cdf0e10cSrcweir 145cdf0e10cSrcweir // 2. create "full" series 146cdf0e10cSrcweir for( sal_Int32 nLabeledSeqIdx=0; nLabeledSeqIdx<nNumOfFullSeries; ++nLabeledSeqIdx ) 147cdf0e10cSrcweir { 148cdf0e10cSrcweir // bar 149cdf0e10cSrcweir if( bHasVolume ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir aSequences[nBarGroupIndex][nLabeledSeqIdx].realloc( 1 ); 152cdf0e10cSrcweir aSequences[nBarGroupIndex][nLabeledSeqIdx][0].set( aData[nSourceIndex] ); 153cdf0e10cSrcweir if( aData[nSourceIndex].is()) 154cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-y")); 155cdf0e10cSrcweir ++nSourceIndex; 156cdf0e10cSrcweir } 157cdf0e10cSrcweir 158cdf0e10cSrcweir sal_Int32 nSeqIdx = 0; 159cdf0e10cSrcweir if( bHasOpenValues ) 160cdf0e10cSrcweir { 161cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nLabeledSeqIdx].realloc( 4 ); 162cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] ); 163cdf0e10cSrcweir if( aData[nSourceIndex].is()) 164cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-first")); 165cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 166cdf0e10cSrcweir } 167cdf0e10cSrcweir else 168cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nLabeledSeqIdx].realloc( 3 ); 169cdf0e10cSrcweir 170cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] ); 171cdf0e10cSrcweir if( aData[nSourceIndex].is()) 172cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-min")); 173cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 174cdf0e10cSrcweir 175cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] ); 176cdf0e10cSrcweir if( aData[nSourceIndex].is()) 177cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-max")); 178cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 179cdf0e10cSrcweir 180cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nLabeledSeqIdx][nSeqIdx].set( aData[nSourceIndex] ); 181cdf0e10cSrcweir if( aData[nSourceIndex].is()) 182cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-last")); 183cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 184cdf0e10cSrcweir } 185cdf0e10cSrcweir 186cdf0e10cSrcweir // 3. create series with remaining sequences 187cdf0e10cSrcweir if( bHasVolume && nRemaining > 1 ) 188cdf0e10cSrcweir { 189cdf0e10cSrcweir OSL_ASSERT( nVolumeSeries > nNumOfFullSeries ); 190cdf0e10cSrcweir aSequences[nBarGroupIndex][nVolumeSeries - 1].realloc( 1 ); 191cdf0e10cSrcweir OSL_ASSERT( nDataCount > nSourceIndex ); 192cdf0e10cSrcweir if( aData[nSourceIndex].is()) 193cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-y")); 194cdf0e10cSrcweir aSequences[nBarGroupIndex][nVolumeSeries - 1][0].set( aData[nSourceIndex] ); 195cdf0e10cSrcweir ++nSourceIndex; 196cdf0e10cSrcweir --nRemaining; 197cdf0e10cSrcweir OSL_ENSURE( nRemaining, "additional bar should only be used if there is at least one more sequence for a candle stick" ); 198cdf0e10cSrcweir } 199cdf0e10cSrcweir 200cdf0e10cSrcweir // candle-stick 201cdf0e10cSrcweir if( nRemaining > 0 ) 202cdf0e10cSrcweir { 203cdf0e10cSrcweir OSL_ASSERT( nCandleStickSeries > nNumOfFullSeries ); 204cdf0e10cSrcweir const sal_Int32 nSeriesIndex = nCandleStickSeries - 1; 205cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nSeriesIndex].realloc( nRemaining ); 206cdf0e10cSrcweir OSL_ASSERT( nDataCount > nSourceIndex ); 207cdf0e10cSrcweir 208cdf0e10cSrcweir // 1. low 209cdf0e10cSrcweir sal_Int32 nSeqIdx( 0 ); 210cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] ); 211cdf0e10cSrcweir if( aData[nSourceIndex].is()) 212cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-min")); 213cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 214cdf0e10cSrcweir 215cdf0e10cSrcweir // 2. high 216cdf0e10cSrcweir if( nSeqIdx < nRemaining ) 217cdf0e10cSrcweir { 218cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] ); 219cdf0e10cSrcweir if( aData[nSourceIndex].is()) 220cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-max")); 221cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 222cdf0e10cSrcweir } 223cdf0e10cSrcweir 224cdf0e10cSrcweir // 3. close 225cdf0e10cSrcweir OSL_ENSURE( bHasOpenValues || nSeqIdx >= nRemaining, "could have created full series" ); 226cdf0e10cSrcweir if( nSeqIdx < nRemaining ) 227cdf0e10cSrcweir { 228cdf0e10cSrcweir aSequences[nCandleStickGroupIndex][nSeriesIndex][nSeqIdx].set( aData[nSourceIndex] ); 229cdf0e10cSrcweir if( aData[nSourceIndex].is()) 230cdf0e10cSrcweir SetRole( aData[nSourceIndex]->getValues(), C2U("values-last")); 231cdf0e10cSrcweir ++nSourceIndex, ++nSeqIdx; 232cdf0e10cSrcweir } 233cdf0e10cSrcweir 234cdf0e10cSrcweir // 4. open 235cdf0e10cSrcweir OSL_ENSURE( nSeqIdx >= nRemaining, "could have created full series" ); 236cdf0e10cSrcweir } 237cdf0e10cSrcweir 238cdf0e10cSrcweir // create DataSeries 239cdf0e10cSrcweir Sequence< Sequence< Reference< XDataSeries > > > aResultSeries( nNumberOfGroups ); 240cdf0e10cSrcweir sal_Int32 nGroupIndex, nReUsedSeriesIdx = 0; 241cdf0e10cSrcweir for( nGroupIndex=0; nGroupIndex<nNumberOfGroups; ++nGroupIndex ) 242cdf0e10cSrcweir { 243cdf0e10cSrcweir const sal_Int32 nNumSeriesData = aSequences[nGroupIndex].getLength(); 244cdf0e10cSrcweir aResultSeries[nGroupIndex].realloc( nNumSeriesData ); 245cdf0e10cSrcweir for( sal_Int32 nSeriesIdx = 0; nSeriesIdx < nNumSeriesData; ++nSeriesIdx, ++nReUsedSeriesIdx ) 246cdf0e10cSrcweir { 247cdf0e10cSrcweir try 248cdf0e10cSrcweir { 249cdf0e10cSrcweir Reference< XDataSeries > xSeries; 250cdf0e10cSrcweir if( nReUsedSeriesIdx < rSeriesToReUse.getLength()) 251cdf0e10cSrcweir xSeries.set( rSeriesToReUse[nReUsedSeriesIdx] ); 252cdf0e10cSrcweir else 253cdf0e10cSrcweir xSeries.set( new DataSeries( GetComponentContext() ) ); 254cdf0e10cSrcweir OSL_ASSERT( xSeries.is() ); 255cdf0e10cSrcweir Reference< data::XDataSink > xSink( xSeries, uno::UNO_QUERY_THROW ); 256cdf0e10cSrcweir OSL_ASSERT( xSink.is() ); 257cdf0e10cSrcweir xSink->setData( aSequences[nGroupIndex][nSeriesIdx] ); 258cdf0e10cSrcweir aResultSeries[nGroupIndex][nSeriesIdx].set( xSeries ); 259cdf0e10cSrcweir } 260cdf0e10cSrcweir catch( uno::Exception & ex ) 261cdf0e10cSrcweir { 262cdf0e10cSrcweir ASSERT_EXCEPTION( ex ); 263cdf0e10cSrcweir } 264cdf0e10cSrcweir } 265cdf0e10cSrcweir } 266cdf0e10cSrcweir 267cdf0e10cSrcweir return InterpretedData( aResultSeries, xCategories ); 268cdf0e10cSrcweir } 269cdf0e10cSrcweir 270cdf0e10cSrcweir // criterion: there must be two groups for stock-charts with volume and all 271cdf0e10cSrcweir // series must have the correct number of data::XLabeledDataSequences 272cdf0e10cSrcweir 273cdf0e10cSrcweir // todo: skip first criterion? (to allow easy switch from stock-chart without 274cdf0e10cSrcweir // volume to one with volume) 275cdf0e10cSrcweir sal_Bool SAL_CALL StockDataInterpreter::isDataCompatible( 276cdf0e10cSrcweir const InterpretedData& aInterpretedData ) 277cdf0e10cSrcweir throw (uno::RuntimeException) 278cdf0e10cSrcweir { 279cdf0e10cSrcweir // high/low/close 280cdf0e10cSrcweir sal_Int32 nNumberOfNecessarySequences = 3; 281cdf0e10cSrcweir // open 282cdf0e10cSrcweir StockChartTypeTemplate::StockVariant eVar( GetStockVariant()); 283cdf0e10cSrcweir if( ( eVar == StockChartTypeTemplate::OPEN_LOW_HI_CLOSE ) || 284cdf0e10cSrcweir ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE )) 285cdf0e10cSrcweir ++nNumberOfNecessarySequences; 286cdf0e10cSrcweir // volume 287cdf0e10cSrcweir bool bHasVolume = (( eVar == StockChartTypeTemplate::VOL_LOW_HI_CLOSE ) || 288cdf0e10cSrcweir ( eVar == StockChartTypeTemplate::VOL_OPEN_LOW_HI_CLOSE )); 289cdf0e10cSrcweir 290cdf0e10cSrcweir // 1. correct number of sub-types 291cdf0e10cSrcweir if( aInterpretedData.Series.getLength() < (bHasVolume ? 2 : 1 )) 292cdf0e10cSrcweir return sal_False; 293cdf0e10cSrcweir 294cdf0e10cSrcweir // 2. a. volume -- use default check 295cdf0e10cSrcweir if( bHasVolume ) 296cdf0e10cSrcweir { 297cdf0e10cSrcweir if( ! DataInterpreter::isDataCompatible( 298cdf0e10cSrcweir InterpretedData( Sequence< Sequence< Reference< XDataSeries > > >( 299cdf0e10cSrcweir aInterpretedData.Series.getConstArray(), 1 ), 300cdf0e10cSrcweir aInterpretedData.Categories ))) 301cdf0e10cSrcweir return sal_False; 302cdf0e10cSrcweir } 303cdf0e10cSrcweir 304cdf0e10cSrcweir // 2. b. candlestick 305cdf0e10cSrcweir { 306cdf0e10cSrcweir OSL_ASSERT( aInterpretedData.Series.getLength() > (bHasVolume ? 1 : 0)); 307cdf0e10cSrcweir Sequence< Reference< XDataSeries > > aSeries( aInterpretedData.Series[(bHasVolume ? 1 : 0)] ); 308cdf0e10cSrcweir if(!aSeries.getLength()) 309cdf0e10cSrcweir return sal_False; 310cdf0e10cSrcweir for( sal_Int32 i=0; i<aSeries.getLength(); ++i ) 311cdf0e10cSrcweir { 312cdf0e10cSrcweir try 313cdf0e10cSrcweir { 314cdf0e10cSrcweir Reference< data::XDataSource > xSrc( aSeries[i], uno::UNO_QUERY_THROW ); 315cdf0e10cSrcweir Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSrc->getDataSequences()); 316cdf0e10cSrcweir if( aSeq.getLength() != nNumberOfNecessarySequences ) 317cdf0e10cSrcweir return sal_False; 318cdf0e10cSrcweir } 319cdf0e10cSrcweir catch( uno::Exception & ex ) 320cdf0e10cSrcweir { 321cdf0e10cSrcweir ASSERT_EXCEPTION( ex ); 322cdf0e10cSrcweir } 323cdf0e10cSrcweir } 324cdf0e10cSrcweir } 325cdf0e10cSrcweir 326cdf0e10cSrcweir // 2. c. additional series 327cdf0e10cSrcweir // ignore 328cdf0e10cSrcweir 329cdf0e10cSrcweir return sal_True; 330cdf0e10cSrcweir } 331cdf0e10cSrcweir 332cdf0e10cSrcweir InterpretedData SAL_CALL StockDataInterpreter::reinterpretDataSeries( 333cdf0e10cSrcweir const InterpretedData& aInterpretedData ) 334cdf0e10cSrcweir throw (uno::RuntimeException) 335cdf0e10cSrcweir { 336cdf0e10cSrcweir // prerequisite: StockDataInterpreter::isDataCompatible() returned true 337cdf0e10cSrcweir return aInterpretedData; 338cdf0e10cSrcweir } 339cdf0e10cSrcweir 340cdf0e10cSrcweir } // namespace chart 341