LCOV - code coverage report
Current view: top level - chart2/source/model/template - StockDataInterpreter.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 97 138 70.3 %
Date: 2012-08-25 Functions: 6 7 85.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 126 418 30.1 %

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

Generated by: LCOV version 1.10