LCOV - code coverage report
Current view: top level - chart2/source/view/charttypes - VSeriesPlotter.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1075 1242 86.6 %
Date: 2015-06-13 12:38:46 Functions: 82 89 92.1 %
Legend: Lines: hit not hit

          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             : #include "VSeriesPlotter.hxx"
      21             : #include "AbstractShapeFactory.hxx"
      22             : #include "chartview/ExplicitValueProvider.hxx"
      23             : 
      24             : #include "CommonConverters.hxx"
      25             : #include "macros.hxx"
      26             : #include "ViewDefines.hxx"
      27             : #include "ObjectIdentifier.hxx"
      28             : #include "StatisticsHelper.hxx"
      29             : #include "PlottingPositionHelper.hxx"
      30             : #include "LabelPositionHelper.hxx"
      31             : #include "ChartTypeHelper.hxx"
      32             : #include "Clipping.hxx"
      33             : #include "servicenames_charttypes.hxx"
      34             : #include "NumberFormatterWrapper.hxx"
      35             : #include "ContainerHelper.hxx"
      36             : #include "DataSeriesHelper.hxx"
      37             : #include "RegressionCurveHelper.hxx"
      38             : #include "VLegendSymbolFactory.hxx"
      39             : #include "FormattedStringHelper.hxx"
      40             : #include "ResId.hxx"
      41             : #include "Strings.hrc"
      42             : #include "RelativePositionHelper.hxx"
      43             : #include "DateHelper.hxx"
      44             : #include "DiagramHelper.hxx"
      45             : #include "defines.hxx"
      46             : 
      47             : //only for creation: @todo remove if all plotter are uno components and instantiated via servicefactory
      48             : #include "BarChart.hxx"
      49             : #include "PieChart.hxx"
      50             : #include "AreaChart.hxx"
      51             : #include "CandleStickChart.hxx"
      52             : #include "BubbleChart.hxx"
      53             : #include "NetChart.hxx"
      54             : #include <unonames.hxx>
      55             : 
      56             : #include <com/sun/star/chart/ErrorBarStyle.hpp>
      57             : #include <com/sun/star/chart/TimeUnit.hpp>
      58             : #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
      59             : #include <com/sun/star/container/XChild.hpp>
      60             : #include <com/sun/star/chart2/RelativePosition.hpp>
      61             : #include <editeng/unoprnms.hxx>
      62             : #include <tools/color.hxx>
      63             : #include <rtl/ustrbuf.hxx>
      64             : #include <rtl/math.hxx>
      65             : #include <basegfx/vector/b2dvector.hxx>
      66             : #include <com/sun/star/drawing/LineStyle.hpp>
      67             : #include <com/sun/star/util/XCloneable.hpp>
      68             : 
      69             : #include <svx/unoshape.hxx>
      70             : 
      71             : #include <functional>
      72             : #include <map>
      73             : #include <unordered_map>
      74             : 
      75             : #include <boost/ptr_container/ptr_map.hpp>
      76             : 
      77             : namespace chart {
      78             : 
      79             : using namespace ::com::sun::star;
      80             : using namespace ::com::sun::star::chart2;
      81             : using ::com::sun::star::uno::Reference;
      82             : using ::com::sun::star::uno::Sequence;
      83             : 
      84       12548 : VDataSeriesGroup::CachedYValues::CachedYValues()
      85             :         : m_bValuesDirty(true)
      86             :         , m_fMinimumY(0.0)
      87       12548 :         , m_fMaximumY(0.0)
      88             : {
      89       12548 : }
      90             : 
      91         104 : VDataSeriesGroup::VDataSeriesGroup()
      92             :         : m_aSeriesVector()
      93             :         , m_bMaxPointCountDirty(true)
      94             :         , m_nMaxPointCount(0)
      95         104 :         , m_aListOfCachedYValues()
      96             : {
      97         104 : }
      98             : 
      99        3042 : VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries )
     100             :         : m_aSeriesVector(1,pSeries)
     101             :         , m_bMaxPointCountDirty(true)
     102             :         , m_nMaxPointCount(0)
     103        3042 :         , m_aListOfCachedYValues()
     104             : {
     105        3042 : }
     106             : 
     107       16739 : VDataSeriesGroup::~VDataSeriesGroup()
     108             : {
     109       16739 : }
     110             : 
     111        3146 : void VDataSeriesGroup::deleteSeries()
     112             : {
     113             :     //delete all data series help objects:
     114        3146 :     ::std::vector< VDataSeries* >::const_iterator aIter = m_aSeriesVector.begin();
     115        3146 :     const ::std::vector< VDataSeries* >::const_iterator aEnd  = m_aSeriesVector.end();
     116        6244 :     for( ; aIter != aEnd; ++aIter )
     117             :     {
     118        3098 :         delete *aIter;
     119             :     }
     120        3146 :     m_aSeriesVector.clear();
     121        3146 : }
     122             : 
     123          56 : void VDataSeriesGroup::addSeries( VDataSeries* pSeries )
     124             : {
     125          56 :     m_aSeriesVector.push_back(pSeries);
     126          56 :     m_bMaxPointCountDirty=true;
     127          56 : }
     128             : 
     129          56 : sal_Int32 VDataSeriesGroup::getSeriesCount() const
     130             : {
     131          56 :     return m_aSeriesVector.size();
     132             : }
     133             : 
     134        1074 : VSeriesPlotter::VSeriesPlotter( const uno::Reference<XChartType>& xChartTypeModel
     135             :                                , sal_Int32 nDimensionCount, bool bCategoryXAxis )
     136             :         : PlotterBase( nDimensionCount )
     137             :         , m_pMainPosHelper( 0 )
     138             :         , m_xChartTypeModel(xChartTypeModel)
     139             :         , m_xChartTypeModelProps( uno::Reference< beans::XPropertySet >::query( xChartTypeModel ))
     140             :         , m_aZSlots()
     141             :         , m_bCategoryXAxis(bCategoryXAxis)
     142             :         , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY)
     143             :         , m_aNullDate(30,12,1899)
     144             :         , m_xColorScheme()
     145             :         , m_pExplicitCategoriesProvider(0)
     146        1074 :         , m_bPointsWereSkipped(false)
     147             : {
     148             :     SAL_WARN_IF(!m_xChartTypeModel.is(),"chart2","no XChartType available in view, fallback to default values may be wrong");
     149        1074 : }
     150             : 
     151        2148 : VSeriesPlotter::~VSeriesPlotter()
     152             : {
     153             :     //delete all data series help objects:
     154        1074 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
     155        1074 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
     156        2220 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
     157             :     {
     158        1146 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
     159        1146 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
     160        4292 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
     161             :         {
     162        3146 :             aXSlotIter->deleteSeries();
     163             :         }
     164        1146 :         aZSlotIter->clear();
     165             :     }
     166        1074 :     m_aZSlots.clear();
     167             : 
     168        1074 :     tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
     169        2170 :     while( aPosIt != m_aSecondaryPosHelperMap.end() )
     170             :     {
     171          22 :         PlottingPositionHelper* pPosHelper = aPosIt->second;
     172          22 :         delete pPosHelper;
     173             : 
     174          22 :         ++aPosIt;
     175             :     }
     176        1074 :     m_aSecondaryPosHelperMap.clear();
     177             : 
     178        1074 :     m_aSecondaryValueScales.clear();
     179        1074 : }
     180             : 
     181        3098 : void VSeriesPlotter::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
     182             : {
     183             :     //take ownership of pSeries
     184             : 
     185             :     OSL_PRECOND( pSeries, "series to add is NULL" );
     186        3098 :     if(!pSeries)
     187        3098 :         return;
     188             : 
     189        3098 :     if(m_bCategoryXAxis)
     190             :     {
     191        2993 :         if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() )
     192           0 :             pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() );
     193             :         else
     194        2993 :             pSeries->setCategoryXAxis();
     195             :     }
     196             :     else
     197             :     {
     198         105 :         if( m_pExplicitCategoriesProvider )
     199         105 :             pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() );
     200             :     }
     201             : 
     202        3098 :     if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
     203             :     {
     204             :         //new z slot
     205         246 :         ::std::vector< VDataSeriesGroup > aZSlot;
     206         246 :         aZSlot.push_back( VDataSeriesGroup(pSeries) );
     207         246 :         m_aZSlots.push_back( aZSlot );
     208             :     }
     209             :     else
     210             :     {
     211             :         //existing zslot
     212        2852 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
     213             : 
     214        2852 :         if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
     215             :         {
     216             :             //append the series to already existing x series
     217        2796 :             rXSlots.push_back( VDataSeriesGroup(pSeries) );
     218             :         }
     219             :         else
     220             :         {
     221             :             //x slot is already occupied
     222             :             //y slot decides what to do:
     223             : 
     224          56 :             VDataSeriesGroup& rYSlots = rXSlots[xSlot];
     225          56 :             sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
     226             : 
     227          56 :             if( ySlot < -1 )
     228             :             {
     229             :                 //move all existing series in the xSlot to next slot
     230             :                 //@todo
     231             :                 OSL_FAIL( "Not implemented yet");
     232             :             }
     233          56 :             else if( ySlot == -1 || ySlot >= nYSlotCount)
     234             :             {
     235             :                 //append the series to already existing y series
     236          56 :                 rYSlots.addSeries(pSeries);
     237             :             }
     238             :             else
     239             :             {
     240             :                 //y slot is already occupied
     241             :                 //insert at given y and x position
     242             : 
     243             :                 //@todo
     244             :                 OSL_FAIL( "Not implemented yet");
     245             :             }
     246             :         }
     247             :     }
     248             : }
     249             : 
     250           0 : drawing::Direction3D VSeriesPlotter::getPreferredDiagramAspectRatio() const
     251             : {
     252           0 :     drawing::Direction3D aRet(1.0,1.0,1.0);
     253           0 :     if (!m_pPosHelper)
     254           0 :         return aRet;
     255             : 
     256           0 :     drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
     257           0 :     aRet.DirectionZ = aScale.DirectionZ*0.2;
     258           0 :     if(aRet.DirectionZ>1.0)
     259           0 :         aRet.DirectionZ=1.0;
     260           0 :     if(aRet.DirectionZ>10)
     261           0 :         aRet.DirectionZ=10;
     262           0 :     return aRet;
     263             : }
     264             : 
     265           0 : bool VSeriesPlotter::keepAspectRatio() const
     266             : {
     267           0 :     return true;
     268             : }
     269             : 
     270          37 : void VSeriesPlotter::releaseShapes()
     271             : {
     272          37 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
     273          37 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
     274          74 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
     275             :     {
     276          37 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
     277          37 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
     278         103 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
     279             :         {
     280          66 :             ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
     281             : 
     282          66 :             ::std::vector< VDataSeries* >::iterator             aSeriesIter = pSeriesList->begin();
     283          66 :             const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
     284             : 
     285             :             //iterate through all series in this x slot
     286         132 :             for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
     287             :             {
     288          66 :                 VDataSeries* pSeries( *aSeriesIter );
     289          66 :                 pSeries->releaseShapes();
     290             :             }
     291             :         }
     292             :     }
     293          37 : }
     294             : 
     295       11664 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries
     296             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     297             : {
     298       11664 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xGroupShape );
     299       11664 :     if( !xShapes.is() )
     300             :     {
     301             :         //create a group shape for this series and add to logic target:
     302        3106 :         xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
     303        3106 :         pDataSeries->m_xGroupShape = xShapes;
     304             :     }
     305       11664 :     return xShapes;
     306             : }
     307             : 
     308         344 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
     309             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     310             : {
     311         344 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xFrontSubGroupShape );
     312         344 :     if(!xShapes.is())
     313             :     {
     314             :         //ensure that the series group shape is already created
     315         328 :         uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
     316             :         //ensure that the back child is created first
     317         328 :         this->getSeriesGroupShapeBackChild( pDataSeries, xTarget );
     318             :         //use series group shape as parent for the new created front group shape
     319         328 :         xShapes = createGroupShape( xSeriesShapes );
     320         328 :         pDataSeries->m_xFrontSubGroupShape = xShapes;
     321             :     }
     322         344 :     return xShapes;
     323             : }
     324             : 
     325         656 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
     326             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     327             : {
     328         656 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xBackSubGroupShape );
     329         656 :     if(!xShapes.is())
     330             :     {
     331             :         //ensure that the series group shape is already created
     332         328 :         uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
     333             :         //use series group shape as parent for the new created back group shape
     334         328 :         xShapes = createGroupShape( xSeriesShapes );
     335         328 :         pDataSeries->m_xBackSubGroupShape = xShapes;
     336             :     }
     337         656 :     return xShapes;
     338             : }
     339             : 
     340        1674 : uno::Reference< drawing::XShapes > VSeriesPlotter::getLabelsGroupShape( VDataSeries& rDataSeries
     341             :                                         , const uno::Reference< drawing::XShapes >& xTextTarget )
     342             : {
     343             :     //xTextTarget needs to be a 2D shape container always!
     344             : 
     345        1674 :     uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xLabelsGroupShape );
     346        1674 :     if(!xShapes.is())
     347             :     {
     348             :         //create a 2D group shape for texts of this series and add to text target:
     349         375 :         xShapes = m_pShapeFactory->createGroup2D( xTextTarget, rDataSeries.getLabelsCID() );
     350         375 :         rDataSeries.m_xLabelsGroupShape = xShapes;
     351             :     }
     352        1674 :     return xShapes;
     353             : }
     354             : 
     355        3669 : uno::Reference< drawing::XShapes > VSeriesPlotter::getErrorBarsGroupShape( VDataSeries& rDataSeries
     356             :                                         , const uno::Reference< drawing::XShapes >& xTarget
     357             :                                         , bool bYError )
     358             : {
     359             :     uno::Reference< ::com::sun::star::drawing::XShapes > &rShapeGroup =
     360        3669 :             bYError ? rDataSeries.m_xErrorYBarsGroupShape : rDataSeries.m_xErrorXBarsGroupShape;
     361             : 
     362        3669 :     uno::Reference< drawing::XShapes > xShapes( rShapeGroup );
     363        3669 :     if(!xShapes.is())
     364             :     {
     365             :         //create a group shape for this series and add to logic target:
     366         880 :         xShapes = this->createGroupShape( xTarget,rDataSeries.getErrorBarsCID(bYError) );
     367         880 :         rShapeGroup = xShapes;
     368             :     }
     369        3669 :     return xShapes;
     370             : 
     371             : }
     372             : 
     373        1700 : OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
     374             :                 , sal_Int32 nPointIndex
     375             :                 , double fValue
     376             :                 , bool bAsPercentage )
     377             : {
     378        1700 :     OUString aNumber;
     379             : 
     380        1700 :     if( m_apNumberFormatterWrapper.get())
     381             :     {
     382        1700 :         sal_Int32 nNumberFormatKey = 0;
     383        1700 :         if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) )
     384         297 :             nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage);
     385        1403 :         else if( bAsPercentage )
     386             :         {
     387         143 :             sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() );
     388         143 :             if( nPercentFormat != -1 )
     389         143 :                 nNumberFormatKey = nPercentFormat;
     390             :         }
     391             :         else
     392             :         {
     393        1260 :             if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
     394         156 :                 nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
     395             :             else
     396        1104 :                 nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
     397             :         }
     398        1700 :         if(nNumberFormatKey<0)
     399           0 :             nNumberFormatKey=0;
     400             : 
     401        1700 :         sal_Int32 nLabelCol = 0;
     402             :         bool bColChanged;
     403        3400 :         aNumber = m_apNumberFormatterWrapper->getFormattedString(
     404        1700 :                 nNumberFormatKey, fValue, nLabelCol, bColChanged );
     405             :         //@todo: change color of label if bColChanged is true
     406             :     }
     407             :     else
     408             :     {
     409           0 :         sal_Unicode cDecSeparator = '.';//@todo get this locale dependent
     410           0 :         aNumber = ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G /*rtl_math_StringFormat*/
     411           0 :             , 3/*DecPlaces*/ , cDecSeparator, false /*bEraseTrailingDecZeros*/ );
     412             :     }
     413        1700 :     return aNumber;
     414             : }
     415             : 
     416        1674 : uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Reference< drawing::XShapes >& xTarget
     417             :                     , VDataSeries& rDataSeries
     418             :                     , sal_Int32 nPointIndex
     419             :                     , double fValue
     420             :                     , double fSumValue
     421             :                     , const awt::Point& rScreenPosition2D
     422             :                     , LabelAlignment eAlignment
     423             :                     , sal_Int32 nOffset )
     424             : {
     425        1674 :     uno::Reference< drawing::XShape > xTextShape;
     426             : 
     427             :     try
     428             :     {
     429        1674 :         awt::Point aScreenPosition2D(rScreenPosition2D);
     430        1674 :         if(LABEL_ALIGN_LEFT==eAlignment)
     431          12 :             aScreenPosition2D.X -= nOffset;
     432        1662 :         else if(LABEL_ALIGN_RIGHT==eAlignment)
     433          44 :             aScreenPosition2D.X += nOffset;
     434        1618 :         else if(LABEL_ALIGN_TOP==eAlignment)
     435        1415 :             aScreenPosition2D.Y -= nOffset;
     436         203 :         else if(LABEL_ALIGN_BOTTOM==eAlignment)
     437           0 :             aScreenPosition2D.Y += nOffset;
     438             : 
     439             :         uno::Reference< drawing::XShapes > xTarget_ =
     440             :             m_pShapeFactory->createGroup2D(
     441             :                 getLabelsGroupShape(rDataSeries, xTarget),
     442        1674 :                 ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(), nPointIndex));
     443             : 
     444             :         //check whether the label needs to be created and how:
     445        1674 :         DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex );
     446             : 
     447        1674 :         if( !pLabel )
     448           0 :             return xTextShape;
     449             : 
     450             :         //prepare legend symbol
     451             : 
     452             :         // get the font size for the label through the "CharHeight" property
     453             :         // attached to the passed data series entry.
     454             :         // (By tracing font height values it results that for pie chart the
     455             :         // font size is not the same for all labels, but here no font size
     456             :         // modification occurs).
     457        1674 :         float fViewFontSize( 10.0 );
     458             :         {
     459        1674 :             uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
     460        1674 :             if( xProps.is() )
     461        1674 :                 xProps->getPropertyValue( "CharHeight") >>= fViewFontSize;
     462             :             // pt -> 1/100th mm
     463        1674 :             fViewFontSize *= (2540.0f / 72.0f);
     464             :         }
     465             : 
     466             :         // the font height is used for computing the size of an optional legend
     467             :         // symbol to be prepended to the text label.
     468        3348 :         Reference< drawing::XShape > xSymbol;
     469        1674 :         if(pLabel->ShowLegendSymbol)
     470             :         {
     471          16 :             sal_Int32 nSymbolHeight = static_cast< sal_Int32 >( fViewFontSize * 0.6  );
     472          16 :             awt::Size aCurrentRatio = getPreferredLegendKeyAspectRatio();
     473          16 :             sal_Int32 nSymbolWidth = aCurrentRatio.Width;
     474          16 :             if( aCurrentRatio.Height > 0 )
     475             :             {
     476          16 :                 nSymbolWidth = nSymbolHeight* aCurrentRatio.Width/aCurrentRatio.Height;
     477             :             }
     478          16 :             awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeight );
     479             : 
     480          16 :             if( rDataSeries.isVaryColorsByPoint() )
     481          16 :                 xSymbol.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent, rDataSeries, nPointIndex, xTarget_, m_xShapeFactory ) );
     482             :             else
     483           0 :                 xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent, rDataSeries, xTarget_, m_xShapeFactory ) );
     484             : 
     485             :         }
     486             :         //prepare text
     487        3348 :         OUStringBuffer aText;
     488        3348 :         OUString aSeparator(" ");
     489        1674 :         double fRotationDegrees = 0.0;
     490             :         try
     491             :         {
     492        1674 :             uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
     493        1674 :             if(xPointProps.is())
     494             :             {
     495        1674 :                 xPointProps->getPropertyValue( "LabelSeparator" ) >>= aSeparator;
     496             :                 // Extract the optional text rotation through the
     497             :                 // "TextRotation" property attached to the passed data point.
     498        1674 :                 xPointProps->getPropertyValue( "TextRotation" ) >>= fRotationDegrees;
     499        1674 :             }
     500             :         }
     501           0 :         catch( const uno::Exception& e )
     502             :         {
     503             :             ASSERT_EXCEPTION( e );
     504             :         }
     505             : 
     506             :         // check if data series entry percent value and absolute value have to
     507             :         // be appended to the text label, and what should be the separator
     508             :         // character (comma, space, new line). In case it is a new line we get
     509             :         // a multi-line label.
     510        1674 :         bool bMultiLineLabel = aSeparator == "\n";
     511        1674 :         sal_Int32 nLineCountForSymbolsize = 0;
     512             :         {
     513        1674 :             if(pLabel->ShowCategoryName)
     514             :             {
     515        1339 :                 if( m_pExplicitCategoriesProvider )
     516             :                 {
     517        1339 :                     Sequence< OUString > aCategories( m_pExplicitCategoriesProvider->getSimpleCategories() );
     518        1339 :                     if( nPointIndex >= 0 && nPointIndex < aCategories.getLength() )
     519             :                     {
     520        1339 :                         aText.append( aCategories[nPointIndex] );
     521        1339 :                         ++nLineCountForSymbolsize;
     522        1339 :                     }
     523             :                 }
     524             :             }
     525             : 
     526        1674 :             if(pLabel->ShowNumber)
     527             :             {
     528        1535 :                 OUString aNumber = getLabelTextForValue(rDataSeries, nPointIndex, fValue, false);
     529        1535 :                 if( !aNumber.isEmpty() )
     530             :                 {
     531        1535 :                     if(!aText.isEmpty())
     532        1268 :                         aText.append(aSeparator);
     533        1535 :                     aText.append(aNumber);
     534        1535 :                     ++nLineCountForSymbolsize;
     535        1535 :                 }
     536             :             }
     537             : 
     538        1674 :             if(pLabel->ShowNumberInPercent)
     539             :             {
     540         165 :                 if(fSumValue==0.0)
     541           0 :                     fSumValue=1.0;
     542         165 :                 fValue /= fSumValue;
     543         165 :                 if( fValue < 0 )
     544           0 :                     fValue*=-1.0;
     545             : 
     546         165 :                 OUString aPercentage = getLabelTextForValue(rDataSeries, nPointIndex, fValue, true);
     547         165 :                 if( !aPercentage.isEmpty() )
     548             :                 {
     549         165 :                     if(!aText.isEmpty())
     550          97 :                         aText.append(aSeparator);
     551         165 :                     aText.append(aPercentage);
     552         165 :                     ++nLineCountForSymbolsize;
     553         165 :                 }
     554             :             }
     555             :         }
     556             :         //prepare properties for multipropertyset-interface of shape
     557             :         tNameSequence* pPropNames;
     558             :         tAnySequence* pPropValues;
     559        1674 :         if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) )
     560           0 :             return xTextShape;
     561             : 
     562             :         // set text alignment for the text shape to be created.
     563        1674 :         LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
     564             : 
     565             :         //create text shape
     566        5022 :         xTextShape = AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->
     567             :             createText( xTarget_, aText.makeStringAndClear()
     568        3348 :                         , *pPropNames, *pPropValues, AbstractShapeFactory::makeTransformation( aScreenPosition2D ) );
     569             : 
     570        1674 :         if( !xTextShape.is() )
     571           0 :             return xTextShape;
     572             : 
     573             :         // in case text is rotated, the transformation property of the text
     574             :         // shape is modified.
     575        1674 :         const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
     576        1674 :         if( fRotationDegrees != 0.0 )
     577             :         {
     578         134 :             const double fDegreesPi( fRotationDegrees * ( F_PI / -180.0 ) );
     579         134 :             uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY );
     580         134 :             if( xProp.is() )
     581         134 :                 xProp->setPropertyValue( "Transformation", AbstractShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) );
     582         134 :             LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
     583             :         }
     584             : 
     585             :         // in case legend symbol has to be displayed, text shape position is
     586             :         // slightly changed.
     587        1674 :         if( xSymbol.is() )
     588             :         {
     589          16 :             const awt::Point aOldTextPos( xTextShape->getPosition() );
     590          16 :             awt::Point aNewTextPos( aOldTextPos );
     591             : 
     592          16 :             awt::Point aSymbolPosition( aUnrotatedTextPos );
     593          16 :             awt::Size aSymbolSize( xSymbol->getSize() );
     594          16 :             awt::Size aTextSize( xTextShape->getSize() );
     595             : 
     596          16 :             sal_Int32 nXDiff = aSymbolSize.Width + static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm
     597          16 :             if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 )
     598          16 :                 nLineCountForSymbolsize = 1;
     599          16 :             aSymbolPosition.Y += ((aTextSize.Height/nLineCountForSymbolsize)/4);
     600             : 
     601          16 :             if(LABEL_ALIGN_LEFT==eAlignment
     602          16 :                 || LABEL_ALIGN_LEFT_TOP==eAlignment
     603          16 :                 || LABEL_ALIGN_LEFT_BOTTOM==eAlignment)
     604             :             {
     605           0 :                 aSymbolPosition.X -= nXDiff;
     606             :             }
     607          16 :             else if(LABEL_ALIGN_RIGHT==eAlignment
     608          16 :                 || LABEL_ALIGN_RIGHT_TOP==eAlignment
     609          16 :                 || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment )
     610             :             {
     611           0 :                 aNewTextPos.X += nXDiff;
     612             :             }
     613          16 :             else if(LABEL_ALIGN_TOP==eAlignment
     614          16 :                 || LABEL_ALIGN_BOTTOM==eAlignment
     615          16 :                 || LABEL_ALIGN_CENTER==eAlignment )
     616             :             {
     617          16 :                 aSymbolPosition.X -= nXDiff/2;
     618          16 :                 aNewTextPos.X += nXDiff/2;
     619             :             }
     620             : 
     621          16 :             xSymbol->setPosition( aSymbolPosition );
     622          16 :             xTextShape->setPosition( aNewTextPos );
     623        1674 :         }
     624             :     }
     625           0 :     catch( const uno::Exception& e )
     626             :     {
     627             :         ASSERT_EXCEPTION( e );
     628             :     }
     629             : 
     630        1674 :     return xTextShape;
     631             : }
     632             : 
     633             : namespace
     634             : {
     635         498 : double lcl_getErrorBarLogicLength(
     636             :     const uno::Sequence< double > & rData,
     637             :     uno::Reference< beans::XPropertySet > xProp,
     638             :     sal_Int32 nErrorBarStyle,
     639             :     sal_Int32 nIndex,
     640             :     bool bPositive,
     641             :     bool bYError )
     642             : {
     643             :     double fResult;
     644         498 :     ::rtl::math::setNan( & fResult );
     645             :     try
     646             :     {
     647         498 :         switch( nErrorBarStyle )
     648             :         {
     649             :             case ::com::sun::star::chart::ErrorBarStyle::NONE:
     650           0 :                 break;
     651             :             case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
     652           0 :                 fResult = StatisticsHelper::getVariance( rData );
     653           0 :                 break;
     654             :             case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
     655           0 :                 fResult = StatisticsHelper::getStandardDeviation( rData );
     656           0 :                 break;
     657             :             case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
     658             :             {
     659         480 :                 double fPercent = 0;
     660        1680 :                 if( xProp->getPropertyValue( bPositive
     661             :                                              ? OUString("PositiveError")
     662        1200 :                                              : OUString("NegativeError") ) >>= fPercent )
     663             :                 {
     664        1440 :                     if( nIndex >=0 && nIndex < rData.getLength() &&
     665        1440 :                         ! ::rtl::math::isNan( rData[nIndex] ) &&
     666         480 :                         ! ::rtl::math::isNan( fPercent ))
     667             :                     {
     668         480 :                         fResult = rData[nIndex] * fPercent / 100.0;
     669             :                     }
     670             :                 }
     671             :             }
     672         480 :             break;
     673             :             case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
     674           0 :                 xProp->getPropertyValue( bPositive
     675             :                                          ? OUString("PositiveError")
     676           0 :                                          : OUString("NegativeError") ) >>= fResult;
     677           0 :                 break;
     678             :             case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
     679             :             {
     680             :                 // todo: check if this is really what's called error-margin
     681           0 :                 double fPercent = 0;
     682           0 :                 if( xProp->getPropertyValue( bPositive
     683             :                                              ? OUString("PositiveError")
     684           0 :                                              : OUString("NegativeError") ) >>= fPercent )
     685             :                 {
     686             :                     double fMaxValue;
     687           0 :                     ::rtl::math::setInf(&fMaxValue, true);
     688           0 :                     const double* pValues = rData.getConstArray();
     689           0 :                     for(sal_Int32 i=0; i<rData.getLength(); ++i, ++pValues)
     690             :                     {
     691           0 :                         if(fMaxValue<*pValues)
     692           0 :                             fMaxValue=*pValues;
     693             :                     }
     694           0 :                     if( ::rtl::math::isFinite( fMaxValue ) &&
     695           0 :                         ::rtl::math::isFinite( fPercent ))
     696             :                     {
     697           0 :                         fResult = fMaxValue * fPercent / 100.0;
     698             :                     }
     699             :                 }
     700             :             }
     701           0 :             break;
     702             :             case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
     703           0 :                 fResult = StatisticsHelper::getStandardError( rData );
     704           0 :                 break;
     705             :             case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA:
     706             :             {
     707          18 :                 uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY );
     708          18 :                 if( xErrorBarData.is())
     709             :                     fResult = StatisticsHelper::getErrorFromDataSource(
     710          18 :                         xErrorBarData, nIndex, bPositive, bYError);
     711             :             }
     712          18 :             break;
     713             :         }
     714             :     }
     715           0 :     catch( const uno::Exception & e )
     716             :     {
     717             :         ASSERT_EXCEPTION( e );
     718             :     }
     719             : 
     720         498 :     return fResult;
     721             : }
     722             : 
     723         339 : void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection
     724             :                 , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex )
     725             : {
     726         339 :     double fFixedWidth = 200.0;
     727             : 
     728         339 :     aMainDirection.normalize();
     729         339 :     ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
     730         339 :     aOrthoDirection.normalize();
     731             : 
     732         678 :     ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY );
     733         678 :     ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0;
     734         678 :     ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0;
     735             : 
     736         339 :     AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex );
     737         678 :     AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex );
     738         339 : }
     739             : 
     740         339 : ::basegfx::B2DVector lcl_getErrorBarMainDirection(
     741             :               const drawing::Position3D& rStart
     742             :             , const drawing::Position3D& rBottomEnd
     743             :             , PlottingPositionHelper* pPosHelper
     744             :             , const drawing::Position3D& rUnscaledLogicPosition
     745             :             , bool bYError )
     746             : {
     747             :     ::basegfx::B2DVector aMainDirection = ::basegfx::B2DVector( rStart.PositionX - rBottomEnd.PositionX
     748         339 :                                               , rStart.PositionY - rBottomEnd.PositionY );
     749         339 :     if( !aMainDirection.getLength() )
     750             :     {
     751             :         //get logic clip values:
     752           0 :         double MinX = pPosHelper->getLogicMinX();
     753           0 :         double MinY = pPosHelper->getLogicMinY();
     754           0 :         double MaxX = pPosHelper->getLogicMaxX();
     755           0 :         double MaxY = pPosHelper->getLogicMaxY();
     756           0 :         double fZ = pPosHelper->getLogicMinZ();
     757             : 
     758           0 :         if( bYError )
     759             :         {
     760             :             //main direction has constant x value
     761           0 :             MinX = rUnscaledLogicPosition.PositionX;
     762           0 :             MaxX = rUnscaledLogicPosition.PositionX;
     763             :         }
     764             :         else
     765             :         {
     766             :             //main direction has constant y value
     767           0 :             MinY = rUnscaledLogicPosition.PositionY;
     768           0 :             MaxY = rUnscaledLogicPosition.PositionY;
     769             :         }
     770             : 
     771           0 :         drawing::Position3D aStart = pPosHelper->transformLogicToScene( MinX, MinY, fZ, false );
     772           0 :         drawing::Position3D aEnd = pPosHelper->transformLogicToScene( MaxX, MaxY, fZ, false );
     773             : 
     774           0 :         aMainDirection = ::basegfx::B2DVector( aStart.PositionX - aEnd.PositionX
     775           0 :                                               , aStart.PositionY - aEnd.PositionY );
     776             :     }
     777         339 :     if( !aMainDirection.getLength() )
     778             :     {
     779             :         //@todo
     780             :     }
     781         339 :     return aMainDirection;
     782             : }
     783             : 
     784         747 : drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper* pPosHelper
     785             :     , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/, bool bClip )
     786             : {
     787         747 :     if(!pPosHelper)
     788           0 :         return drawing::Position3D(0,0,0);
     789         747 :     pPosHelper->doLogicScaling( 0,&fY,&fZ );
     790         747 :     if(bClip)
     791         747 :         pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ );
     792         747 :     return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false );
     793             : }
     794             : 
     795             : } // anonymous namespace
     796             : 
     797        3669 : void VSeriesPlotter::createErrorBar(
     798             :       const uno::Reference< drawing::XShapes >& xTarget
     799             :     , const drawing::Position3D& rUnscaledLogicPosition
     800             :     , const uno::Reference< beans::XPropertySet > & xErrorBarProperties
     801             :     , const VDataSeries& rVDataSeries
     802             :     , sal_Int32 nIndex
     803             :     , bool bYError /* = true */
     804             :     , double* pfScaledLogicX
     805             :     )
     806             : {
     807        3669 :     if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
     808           0 :         return;
     809             : 
     810        3669 :     if( ! xErrorBarProperties.is())
     811           0 :         return;
     812             : 
     813             :     try
     814             :     {
     815        3669 :         bool bShowPositive = false;
     816        3669 :         bool bShowNegative = false;
     817        3669 :         sal_Int32 nErrorBarStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE;
     818             : 
     819        3669 :         xErrorBarProperties->getPropertyValue( "ShowPositiveError") >>= bShowPositive;
     820        3669 :         xErrorBarProperties->getPropertyValue( "ShowNegativeError") >>= bShowNegative;
     821        3669 :         xErrorBarProperties->getPropertyValue( "ErrorBarStyle") >>= nErrorBarStyle;
     822             : 
     823        3669 :         if(!bShowPositive && !bShowNegative)
     824        6840 :             return;
     825             : 
     826         249 :         if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
     827           0 :             return;
     828             : 
     829         249 :         if (!m_pPosHelper)
     830           0 :             return;
     831             : 
     832         249 :         drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition);
     833         249 :         if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION)
     834             :         {
     835           0 :             if (bYError)
     836           0 :                 aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue();
     837             :             else
     838           0 :                 aUnscaledLogicPosition.PositionX = rVDataSeries.getXMeanValue();
     839             :         }
     840             : 
     841         249 :         bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar
     842         249 :         bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar
     843         249 :         drawing::Position3D aMiddle(aUnscaledLogicPosition);
     844         249 :         const double fX = aUnscaledLogicPosition.PositionX;
     845         249 :         const double fY = aUnscaledLogicPosition.PositionY;
     846         249 :         const double fZ = aUnscaledLogicPosition.PositionZ;
     847         249 :         double fScaledX = fX;
     848         249 :         if( pfScaledLogicX )
     849           0 :             fScaledX = *pfScaledLogicX;
     850             :         else
     851         249 :             m_pPosHelper->doLogicScaling( &fScaledX, 0, 0 );
     852             : 
     853         249 :         aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fY, fZ, true );
     854             : 
     855         249 :         drawing::Position3D aNegative(aMiddle);
     856         249 :         drawing::Position3D aPositive(aMiddle);
     857             : 
     858         249 :         uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() );
     859             : 
     860         249 :         if( bShowPositive )
     861             :         {
     862         249 :             double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true, bYError );
     863         249 :             if( ::rtl::math::isFinite( fLength ) )
     864             :             {
     865         249 :                 double fLocalX = fX;
     866         249 :                 double fLocalY = fY;
     867         249 :                 if( bYError )
     868             :                 {
     869         249 :                     fLocalY+=fLength;
     870         249 :                     aPositive = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
     871             :                 }
     872             :                 else
     873             :                 {
     874           0 :                     fLocalX+=fLength;
     875           0 :                     aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
     876             :                 }
     877         249 :                 bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
     878             :             }
     879             :             else
     880           0 :                 bShowPositive = false;
     881             :         }
     882             : 
     883         249 :         if( bShowNegative )
     884             :         {
     885         249 :             double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false, bYError );
     886         249 :             if( ::rtl::math::isFinite( fLength ) )
     887             :             {
     888         249 :                 double fLocalX = fX;
     889         249 :                 double fLocalY = fY;
     890         249 :                 if( bYError )
     891             :                 {
     892         249 :                     fLocalY-=fLength;
     893         249 :                     aNegative = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
     894             :                 }
     895             :                 else
     896             :                 {
     897           0 :                     fLocalX-=fLength;
     898           0 :                     aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
     899             :                 }
     900         249 :                 bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
     901             :             }
     902             :             else
     903           0 :                 bShowNegative = false;
     904             :         }
     905             : 
     906         249 :         if(!bShowPositive && !bShowNegative)
     907           0 :             return;
     908             : 
     909         498 :         drawing::PolyPolygonShape3D aPoly;
     910             : 
     911         249 :         sal_Int32 nSequenceIndex=0;
     912         249 :         if( bShowNegative )
     913         249 :             AddPointToPoly( aPoly, aNegative, nSequenceIndex );
     914         249 :         AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
     915         249 :         if( bShowPositive )
     916         249 :             AddPointToPoly( aPoly, aPositive, nSequenceIndex );
     917             : 
     918         249 :         if( bShowNegative && bCreateNegativeBorder )
     919             :         {
     920         171 :             ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
     921         171 :             nSequenceIndex++;
     922         171 :             lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
     923             :         }
     924         249 :         if( bShowPositive && bCreatePositiveBorder )
     925             :         {
     926         168 :             ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
     927         168 :             nSequenceIndex++;
     928         168 :             lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex );
     929             :         }
     930             : 
     931         498 :         uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( xTarget, PolyToPointSequence( aPoly) );
     932         498 :         setMappedProperties( xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() );
     933             :     }
     934           0 :     catch( const uno::Exception & e )
     935             :     {
     936             :         ASSERT_EXCEPTION( e );
     937             :     }
     938             : 
     939             : }
     940             : 
     941           0 : void VSeriesPlotter::createErrorBar_X( const drawing::Position3D& rUnscaledLogicPosition
     942             :                             , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
     943             :                             , const uno::Reference< drawing::XShapes >& xTarget
     944             :                             , double* pfScaledLogicX )
     945             : {
     946           0 :     if(m_nDimension!=2)
     947           0 :         return;
     948             :     // error bars
     949           0 :     uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getXErrorBarProperties(nPointIndex));
     950           0 :     if( xErrorBarProp.is())
     951             :     {
     952             :         uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
     953           0 :             this->getErrorBarsGroupShape(rVDataSeries, xTarget, false) );
     954             : 
     955             :         createErrorBar( xErrorBarsGroup_Shapes
     956             :             , rUnscaledLogicPosition, xErrorBarProp
     957             :             , rVDataSeries, nPointIndex
     958             :             , false /* bYError */
     959           0 :             , pfScaledLogicX );
     960           0 :     }
     961             : }
     962             : 
     963       10750 : void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition
     964             :                             , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
     965             :                             , const uno::Reference< drawing::XShapes >& xTarget
     966             :                             , double* pfScaledLogicX )
     967             : {
     968       10750 :     if(m_nDimension!=2)
     969       11273 :         return;
     970             :     // error bars
     971       10227 :     uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex));
     972       10227 :     if( xErrorBarProp.is())
     973             :     {
     974             :         uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
     975        3669 :             this->getErrorBarsGroupShape(rVDataSeries, xTarget, true) );
     976             : 
     977             :         createErrorBar( xErrorBarsGroup_Shapes
     978             :             , rUnscaledLogicPosition, xErrorBarProp
     979             :             , rVDataSeries, nPointIndex
     980             :             , true /* bYError */
     981        3669 :             , pfScaledLogicX );
     982       10227 :     }
     983             : }
     984             : 
     985        3005 : void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries,
     986             :                             const uno::Reference< drawing::XShapes >& xTarget,
     987             :                             const uno::Reference< drawing::XShapes >& xEquationTarget,
     988             :                             bool bMaySkipPoints )
     989             : {
     990        3005 :     if(m_nDimension!=2)
     991         298 :         return;
     992        2856 :     uno::Reference< XRegressionCurveContainer > xContainer( rVDataSeries.getModel(), uno::UNO_QUERY );
     993        2856 :     if(!xContainer.is())
     994           0 :         return;
     995             : 
     996        2856 :     if (!m_pPosHelper)
     997           0 :         return;
     998             : 
     999        5712 :     uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList = xContainer->getRegressionCurves();
    1000             : 
    1001        2916 :     for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
    1002             :     {
    1003          60 :         uno::Reference< XRegressionCurveCalculator > xCalculator( aCurveList[nN]->getCalculator() );
    1004          60 :         if( !xCalculator.is())
    1005           0 :             continue;
    1006             : 
    1007         120 :         uno::Reference< beans::XPropertySet > xProperties( aCurveList[nN], uno::UNO_QUERY );
    1008             : 
    1009          60 :         bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
    1010             : 
    1011          60 :         sal_Int32 aDegree = 2;
    1012          60 :         sal_Int32 aPeriod = 2;
    1013          60 :         double aExtrapolateForward = 0.0;
    1014          60 :         double aExtrapolateBackward = 0.0;
    1015          60 :         bool aForceIntercept = false;
    1016          60 :         double aInterceptValue = 0.0;
    1017             : 
    1018          60 :         if ( xProperties.is() && !bAverageLine )
    1019             :         {
    1020          23 :             xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
    1021          23 :             xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
    1022          23 :             xProperties->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward;
    1023          23 :             xProperties->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward;
    1024          23 :             xProperties->getPropertyValue( "ForceIntercept") >>= aForceIntercept;
    1025          23 :             if (aForceIntercept)
    1026           7 :                 xProperties->getPropertyValue( "InterceptValue") >>= aInterceptValue;
    1027             :         }
    1028             : 
    1029          60 :         double fChartMinX = m_pPosHelper->getLogicMinX();
    1030          60 :         double fChartMaxX = m_pPosHelper->getLogicMaxX();
    1031             : 
    1032          60 :         double fMinX = fChartMinX;
    1033          60 :         double fMaxX = fChartMaxX;
    1034             : 
    1035          60 :         double fPointScale = 1.0;
    1036             : 
    1037          60 :         if( !bAverageLine )
    1038             :         {
    1039          23 :             rVDataSeries.getMinMaxXValue(fMinX, fMaxX);
    1040          23 :             fMaxX += aExtrapolateForward;
    1041          23 :             fMinX -= aExtrapolateBackward;
    1042             : 
    1043          23 :             fPointScale = (fMaxX - fMinX) / (fChartMaxX - fChartMinX);
    1044             :         }
    1045             : 
    1046          60 :         xCalculator->setRegressionProperties(aDegree, aForceIntercept, aInterceptValue, aPeriod);
    1047          60 :         xCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() );
    1048          60 :         sal_Int32 nPointCount = 100 * fPointScale;
    1049             : 
    1050          60 :         if ( nPointCount < 2 )
    1051           0 :             nPointCount = 2;
    1052             : 
    1053         120 :         std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales());
    1054         120 :         uno::Reference< chart2::XScaling > xScalingX;
    1055         120 :         uno::Reference< chart2::XScaling > xScalingY;
    1056          60 :         if( aScales.size() >= 2 )
    1057             :         {
    1058          60 :             xScalingX.set( aScales[0].Scaling );
    1059          60 :             xScalingY.set( aScales[1].Scaling );
    1060             :         }
    1061             : 
    1062             :         uno::Sequence< geometry::RealPoint2D > aCalculatedPoints(
    1063          60 :             xCalculator->getCurveValues(
    1064             :                             fMinX, fMaxX, nPointCount,
    1065         120 :                             xScalingX, xScalingY, bMaySkipPoints ));
    1066             : 
    1067          60 :         nPointCount = aCalculatedPoints.getLength();
    1068             : 
    1069         120 :         drawing::PolyPolygonShape3D aRegressionPoly;
    1070          60 :         aRegressionPoly.SequenceX.realloc(1);
    1071          60 :         aRegressionPoly.SequenceY.realloc(1);
    1072          60 :         aRegressionPoly.SequenceZ.realloc(1);
    1073          60 :         aRegressionPoly.SequenceX[0].realloc(nPointCount);
    1074          60 :         aRegressionPoly.SequenceY[0].realloc(nPointCount);
    1075          60 :         aRegressionPoly.SequenceZ[0].realloc(nPointCount);
    1076             : 
    1077          60 :         sal_Int32 nRealPointCount = 0;
    1078             : 
    1079         712 :         for(sal_Int32 nP = 0; nP < aCalculatedPoints.getLength(); ++nP)
    1080             :         {
    1081         652 :             double fLogicX = aCalculatedPoints[nP].X;
    1082         652 :             double fLogicY = aCalculatedPoints[nP].Y;
    1083         652 :             double fLogicZ = 0.0; //dummy
    1084             : 
    1085             :             // fdo#51656: don't scale mean value lines
    1086         652 :             if(!bAverageLine)
    1087         578 :                 m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ );
    1088             : 
    1089        2608 :             if(!rtl::math::isNan(fLogicX) && !rtl::math::isInf(fLogicX) &&
    1090        1956 :                !rtl::math::isNan(fLogicY) && !rtl::math::isInf(fLogicY) &&
    1091        1956 :                !rtl::math::isNan(fLogicZ) && !rtl::math::isInf(fLogicZ) )
    1092             :             {
    1093         652 :                 aRegressionPoly.SequenceX[0][nRealPointCount] = fLogicX;
    1094         652 :                 aRegressionPoly.SequenceY[0][nRealPointCount] = fLogicY;
    1095         652 :                 nRealPointCount++;
    1096             :             }
    1097             :         }
    1098          60 :         aRegressionPoly.SequenceX[0].realloc(nRealPointCount);
    1099          60 :         aRegressionPoly.SequenceY[0].realloc(nRealPointCount);
    1100          60 :         aRegressionPoly.SequenceZ[0].realloc(nRealPointCount);
    1101             : 
    1102         120 :         drawing::PolyPolygonShape3D aClippedPoly;
    1103          60 :         Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly );
    1104          60 :         aRegressionPoly = aClippedPoly;
    1105          60 :         m_pPosHelper->transformScaledLogicToScene( aRegressionPoly );
    1106             : 
    1107          60 :         awt::Point aDefaultPos;
    1108          60 :         if( aRegressionPoly.SequenceX.getLength() && aRegressionPoly.SequenceX[0].getLength() )
    1109             :         {
    1110          54 :             VLineProperties aVLineProperties;
    1111          54 :             aVLineProperties.initFromPropertySet( xProperties );
    1112             : 
    1113             :             //create an extra group shape for each curve for selection handling
    1114             :             uno::Reference< drawing::XShapes > xRegressionGroupShapes =
    1115         108 :                 createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) );
    1116             :             uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1117         108 :                 xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties );
    1118          54 :             AbstractShapeFactory::setShapeName( xShape, "MarkHandles" );
    1119         108 :             aDefaultPos = xShape->getPosition();
    1120             :         }
    1121             : 
    1122             :         // curve equation and correlation coefficient
    1123         120 :         uno::Reference< beans::XPropertySet > xEquationProperties( aCurveList[nN]->getEquationProperties());
    1124          60 :         if( xEquationProperties.is())
    1125             :         {
    1126             :             createRegressionCurveEquationShapes(
    1127             :                 rVDataSeries.getDataCurveEquationCID( nN ),
    1128             :                 xEquationProperties, xEquationTarget, xCalculator,
    1129          60 :                 aDefaultPos );
    1130             :         }
    1131        2916 :     }
    1132             : }
    1133             : 
    1134          60 : void VSeriesPlotter::createRegressionCurveEquationShapes(
    1135             :     const OUString & rEquationCID,
    1136             :     const uno::Reference< beans::XPropertySet > & xEquationProperties,
    1137             :     const uno::Reference< drawing::XShapes >& xEquationTarget,
    1138             :     const uno::Reference< chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator,
    1139             :     awt::Point aDefaultPos )
    1140             : {
    1141             :     OSL_ASSERT( xEquationProperties.is());
    1142          60 :     if( !xEquationProperties.is())
    1143          45 :         return;
    1144             : 
    1145          60 :     bool bShowEquation = false;
    1146          60 :     bool bShowCorrCoeff = false;
    1147          60 :     OUString aSep( "\n" );
    1148         240 :     if(( xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation ) &&
    1149         180 :        ( xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCorrCoeff ))
    1150             :     {
    1151          60 :         if( ! (bShowEquation || bShowCorrCoeff))
    1152          45 :             return;
    1153             : 
    1154          15 :         OUStringBuffer aFormula;
    1155          15 :         sal_Int32 nNumberFormatKey = 0;
    1156          15 :         xEquationProperties->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey;
    1157             : 
    1158          15 :         if( bShowEquation )
    1159             :         {
    1160          15 :             if( m_apNumberFormatterWrapper.get())
    1161             :             {
    1162          45 :                 aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
    1163             :                     m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
    1164          30 :                     nNumberFormatKey );
    1165             :             }
    1166             :             else
    1167             :             {
    1168           0 :                 aFormula = xRegressionCurveCalculator->getRepresentation();
    1169             :             }
    1170             : 
    1171          15 :             if( bShowCorrCoeff )
    1172             :             {
    1173           8 :                 aFormula.append( aSep );
    1174             :             }
    1175             :         }
    1176          15 :         if( bShowCorrCoeff )
    1177             :         {
    1178           8 :             aFormula.append( "R" );
    1179           8 :             aFormula.append( sal_Unicode( 0x00b2 ));
    1180           8 :             aFormula.append( " = ");
    1181           8 :             double fR( xRegressionCurveCalculator->getCorrelationCoefficient());
    1182           8 :             if( m_apNumberFormatterWrapper.get())
    1183             :             {
    1184           8 :                 sal_Int32 nLabelCol = 0;
    1185             :                 bool bColChanged;
    1186             :                 aFormula.append(
    1187             :                     m_apNumberFormatterWrapper->getFormattedString(
    1188           8 :                         nNumberFormatKey, fR*fR, nLabelCol, bColChanged ));
    1189             :                 //@todo: change color of label if bColChanged is true
    1190             :             }
    1191             :             else
    1192             :             {
    1193           0 :                 sal_Unicode aDecimalSep( '.' );//@todo get this locale dependent
    1194             :                 aFormula.append( ::rtl::math::doubleToUString(
    1195           0 :                                      fR*fR, rtl_math_StringFormat_G, 4, aDecimalSep, true ));
    1196             :             }
    1197             :         }
    1198             : 
    1199          15 :         awt::Point aScreenPosition2D;
    1200          15 :         chart2::RelativePosition aRelativePosition;
    1201          15 :         if( xEquationProperties->getPropertyValue( "RelativePosition") >>= aRelativePosition )
    1202             :         {
    1203             :             //@todo decide whether x is primary or secondary
    1204          12 :             double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width;
    1205          12 :             double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height;
    1206          12 :             aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
    1207          12 :             aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
    1208             :         }
    1209             :         else
    1210           3 :             aScreenPosition2D = aDefaultPos;
    1211             : 
    1212          15 :         if( !aFormula.isEmpty())
    1213             :         {
    1214             :             // set fill and line properties on creation
    1215          15 :             tNameSequence aNames;
    1216          30 :             tAnySequence  aValues;
    1217          15 :             PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues );
    1218             : 
    1219             :             uno::Reference< drawing::XShape > xTextShape = m_pShapeFactory->createText(
    1220             :                 xEquationTarget, aFormula.makeStringAndClear(),
    1221          30 :                 aNames, aValues, AbstractShapeFactory::makeTransformation( aScreenPosition2D ));
    1222             : 
    1223             :             OSL_ASSERT( xTextShape.is());
    1224          15 :             if( xTextShape.is())
    1225             :             {
    1226          15 :                 AbstractShapeFactory::setShapeName( xTextShape, rEquationCID );
    1227          15 :                 awt::Size aSize( xTextShape->getSize() );
    1228             :                 awt::Point aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
    1229          15 :                     aScreenPosition2D, aSize, aRelativePosition.Anchor ) );
    1230             :                 //ensure that the equation is fully placed within the page (if possible)
    1231          15 :                 if( (aPos.X + aSize.Width) > m_aPageReferenceSize.Width )
    1232           0 :                     aPos.X = m_aPageReferenceSize.Width - aSize.Width;
    1233          15 :                 if( aPos.X < 0 )
    1234           0 :                     aPos.X = 0;
    1235          15 :                 if( (aPos.Y + aSize.Height) > m_aPageReferenceSize.Height )
    1236           0 :                     aPos.Y = m_aPageReferenceSize.Height - aSize.Height;
    1237          15 :                 if( aPos.Y < 0 )
    1238           0 :                     aPos.Y = 0;
    1239          15 :                 xTextShape->setPosition(aPos);
    1240          15 :             }
    1241          15 :         }
    1242          15 :     }
    1243             : }
    1244             : 
    1245       11176 : void VSeriesPlotter::setMappedProperties(
    1246             :           const uno::Reference< drawing::XShape >& xTargetShape
    1247             :         , const uno::Reference< beans::XPropertySet >& xSource
    1248             :         , const tPropertyNameMap& rMap
    1249             :         , tPropertyNameValueMap* pOverwriteMap )
    1250             : {
    1251       11176 :     uno::Reference< beans::XPropertySet > xTargetProp( xTargetShape, uno::UNO_QUERY );
    1252       11176 :     PropertyMapper::setMappedProperties(xTargetProp,xSource,rMap,pOverwriteMap);
    1253       11176 : }
    1254             : 
    1255           0 : void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution, const Date& rNullDate )
    1256             : {
    1257           0 :     m_nTimeResolution = TimeResolution;
    1258           0 :     m_aNullDate = rNullDate;
    1259           0 : }
    1260             : 
    1261             : // MinimumAndMaximumSupplier
    1262           0 : long VSeriesPlotter::calculateTimeResolutionOnXAxis()
    1263             : {
    1264           0 :     long nRet = ::com::sun::star::chart::TimeUnit::YEAR;
    1265           0 :     if( m_pExplicitCategoriesProvider )
    1266             :     {
    1267           0 :         const std::vector< DatePlusIndex >&  rDateCategories = m_pExplicitCategoriesProvider->getDateCategories();
    1268           0 :         std::vector< DatePlusIndex >::const_iterator aIt = rDateCategories.begin(), aEnd = rDateCategories.end();
    1269           0 :         Date aNullDate(30,12,1899);
    1270           0 :         if( m_apNumberFormatterWrapper.get() )
    1271           0 :             aNullDate = m_apNumberFormatterWrapper->getNullDate();
    1272           0 :         if( aIt!=aEnd )
    1273             :         {
    1274           0 :             Date aPrevious(aNullDate); aPrevious+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
    1275           0 :             ++aIt;
    1276           0 :             for(;aIt!=aEnd;++aIt)
    1277             :             {
    1278           0 :                 Date aCurrent(aNullDate); aCurrent+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
    1279           0 :                 if( ::com::sun::star::chart::TimeUnit::YEAR == nRet )
    1280             :                 {
    1281           0 :                     if( DateHelper::IsInSameYear( aPrevious, aCurrent ) )
    1282           0 :                         nRet = ::com::sun::star::chart::TimeUnit::MONTH;
    1283             :                 }
    1284           0 :                 if( ::com::sun::star::chart::TimeUnit::MONTH == nRet )
    1285             :                 {
    1286           0 :                     if( DateHelper::IsInSameMonth( aPrevious, aCurrent ) )
    1287           0 :                         nRet = ::com::sun::star::chart::TimeUnit::DAY;
    1288             :                 }
    1289           0 :                 if( ::com::sun::star::chart::TimeUnit::DAY == nRet )
    1290           0 :                     break;
    1291           0 :                 aPrevious=aCurrent;
    1292             :             }
    1293             :         }
    1294             :     }
    1295           0 :     return nRet;
    1296             : }
    1297        2162 : double VSeriesPlotter::getMinimumX()
    1298             : {
    1299             :     double fMinimum, fMaximum;
    1300        2162 :     getMinimumAndMaximiumX( fMinimum, fMaximum );
    1301        2162 :     return fMinimum;
    1302             : }
    1303        2162 : double VSeriesPlotter::getMaximumX()
    1304             : {
    1305             :     double fMinimum, fMaximum;
    1306        2162 :     getMinimumAndMaximiumX( fMinimum, fMaximum );
    1307        2162 :     return fMaximum;
    1308             : }
    1309             : 
    1310        2166 : double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
    1311             : {
    1312        2166 :     if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
    1313             :     {
    1314             :         double fMinY, fMaxY;
    1315         124 :         this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
    1316         124 :         return fMinY;
    1317             :     }
    1318             : 
    1319             :     double fMinimum, fMaximum;
    1320        2042 :     ::rtl::math::setInf(&fMinimum, false);
    1321        2042 :     ::rtl::math::setInf(&fMaximum, true);
    1322        4126 :     for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
    1323             :     {
    1324        2084 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
    1325        7952 :         for(size_t nN =0; nN<rXSlots.size();nN++ )
    1326             :         {
    1327             :             double fLocalMinimum, fLocalMaximum;
    1328        5868 :             rXSlots[nN].calculateYMinAndMaxForCategoryRange(
    1329        5868 :                                 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
    1330        5868 :                                 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
    1331        5868 :                                 , isSeparateStackingForDifferentSigns( 1 )
    1332       23472 :                                 , fLocalMinimum, fLocalMaximum, nAxisIndex );
    1333        5868 :             if(fMaximum<fLocalMaximum)
    1334        3792 :                 fMaximum=fLocalMaximum;
    1335        5868 :             if(fMinimum>fLocalMinimum)
    1336        3694 :                 fMinimum=fLocalMinimum;
    1337             :         }
    1338             :     }
    1339        2042 :     if(::rtl::math::isInf(fMinimum))
    1340          78 :         ::rtl::math::setNan(&fMinimum);
    1341        2042 :     return fMinimum;
    1342             : }
    1343             : 
    1344        2166 : double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
    1345             : {
    1346        2166 :     if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
    1347             :     {
    1348             :         double fMinY, fMaxY;
    1349         124 :         this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
    1350         124 :         return fMaxY;
    1351             :     }
    1352             : 
    1353             :     double fMinimum, fMaximum;
    1354        2042 :     ::rtl::math::setInf(&fMinimum, false);
    1355        2042 :     ::rtl::math::setInf(&fMaximum, true);
    1356        4126 :     for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
    1357             :     {
    1358        2084 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
    1359        7952 :         for(size_t nN =0; nN<rXSlots.size();nN++ )
    1360             :         {
    1361             :             double fLocalMinimum, fLocalMaximum;
    1362        5868 :             rXSlots[nN].calculateYMinAndMaxForCategoryRange(
    1363        5868 :                                 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
    1364        5868 :                                 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
    1365        5868 :                                 , isSeparateStackingForDifferentSigns( 1 )
    1366       23472 :                                 , fLocalMinimum, fLocalMaximum, nAxisIndex );
    1367        5868 :             if(fMaximum<fLocalMaximum)
    1368        3792 :                 fMaximum=fLocalMaximum;
    1369        5868 :             if(fMinimum>fLocalMinimum)
    1370        3694 :                 fMinimum=fLocalMinimum;
    1371             :         }
    1372             :     }
    1373        2042 :     if(::rtl::math::isInf(fMaximum))
    1374          78 :         ::rtl::math::setNan(&fMaximum);
    1375        2042 :     return fMaximum;
    1376             : }
    1377             : 
    1378         104 : double VSeriesPlotter::getMinimumZ()
    1379             : {
    1380             :     //this is the default for all charts without a meaningfull z axis
    1381         104 :     return 1.0;
    1382             : }
    1383         104 : double VSeriesPlotter::getMaximumZ()
    1384             : {
    1385         104 :     if( 3!=m_nDimension || !m_aZSlots.size() )
    1386           0 :         return getMinimumZ()+1;
    1387         104 :     return m_aZSlots.size();
    1388             : }
    1389             : 
    1390             : namespace
    1391             : {
    1392        8374 :     bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis )
    1393             :     {
    1394             :         // default implementation: true for Y axes, and for value X axis
    1395        8374 :         if( nDimensionIndex == 0 )
    1396        4060 :             return !bCategoryXAxis;
    1397        4314 :         if( nDimensionIndex == 1 )
    1398        4216 :             return true;
    1399          98 :         return false;
    1400             :     }
    1401             : }
    1402             : 
    1403        4352 : bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex )
    1404             : {
    1405        4352 :     return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
    1406             : }
    1407             : 
    1408        4332 : bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
    1409             : {
    1410             :     // do not expand axes in 3D charts
    1411        4332 :     return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
    1412             : }
    1413             : 
    1414        4344 : bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex )
    1415             : {
    1416             :     // default implementation: only for Y axis
    1417        4344 :     return nDimensionIndex == 1;
    1418             : }
    1419             : 
    1420        4344 : bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex )
    1421             : {
    1422             :     // default implementation: only for Y axis
    1423        4344 :     return nDimensionIndex == 1;
    1424             : }
    1425             : 
    1426       31462 : bool VSeriesPlotter::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex )
    1427             : {
    1428             :     // default implementation: only for Y axis
    1429       31462 :     return nDimensionIndex == 1;
    1430             : }
    1431             : 
    1432        4324 : void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
    1433             : {
    1434        4324 :     ::rtl::math::setInf(&rfMinimum, false);
    1435        4324 :     ::rtl::math::setInf(&rfMaximum, true);
    1436             : 
    1437        4324 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1438        4324 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    1439        8732 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1440             :     {
    1441        4408 :         ::std::vector< VDataSeriesGroup >::const_iterator      aXSlotIter = aZSlotIter->begin();
    1442        4408 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1443       16596 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1444             :         {
    1445             :             double fLocalMinimum, fLocalMaximum;
    1446       12188 :             aXSlotIter->getMinimumAndMaximiumX( fLocalMinimum, fLocalMaximum );
    1447       12188 :             if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinimum )
    1448        4320 :                 rfMinimum = fLocalMinimum;
    1449       12188 :             if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaximum )
    1450        4320 :                 rfMaximum = fLocalMaximum;
    1451             :         }
    1452             :     }
    1453        4324 :     if(::rtl::math::isInf(rfMinimum))
    1454           4 :         ::rtl::math::setNan(&rfMinimum);
    1455        4324 :     if(::rtl::math::isInf(rfMaximum))
    1456           4 :         ::rtl::math::setNan(&rfMaximum);
    1457        4324 : }
    1458             : 
    1459         248 : void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
    1460             : {
    1461         248 :     ::rtl::math::setInf(&rfMinY, false);
    1462         248 :     ::rtl::math::setInf(&rfMaxY, true);
    1463             : 
    1464         248 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1465         248 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    1466         496 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1467             :     {
    1468         248 :         ::std::vector< VDataSeriesGroup >::const_iterator      aXSlotIter = aZSlotIter->begin();
    1469         248 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1470         716 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1471             :         {
    1472             :             double fLocalMinimum, fLocalMaximum;
    1473         468 :             aXSlotIter->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex );
    1474         468 :             if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinY )
    1475         260 :                 rfMinY = fLocalMinimum;
    1476         468 :             if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaxY )
    1477         316 :                 rfMaxY = fLocalMaximum;
    1478             :         }
    1479             :     }
    1480         248 :     if(::rtl::math::isInf(rfMinY))
    1481          24 :         ::rtl::math::setNan(&rfMinY);
    1482         248 :     if(::rtl::math::isInf(rfMaxY))
    1483          24 :         ::rtl::math::setNan(&rfMaxY);
    1484         248 : }
    1485             : 
    1486        1039 : sal_Int32 VSeriesPlotter::getPointCount() const
    1487             : {
    1488        1039 :     sal_Int32 nRet = 0;
    1489             : 
    1490        1039 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1491        1039 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
    1492             : 
    1493        2151 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1494             :     {
    1495        1112 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1496        1112 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1497             : 
    1498        4201 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1499             :         {
    1500        3089 :             sal_Int32 nPointCount = aXSlotIter->getPointCount();
    1501        3089 :             if( nPointCount>nRet )
    1502        1039 :                 nRet = nPointCount;
    1503             :         }
    1504             :     }
    1505        1039 :     return nRet;
    1506             : }
    1507             : 
    1508        1074 : void VSeriesPlotter::setNumberFormatsSupplier(
    1509             :     const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier )
    1510             : {
    1511        1074 :     m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier ));
    1512        1074 : }
    1513             : 
    1514        1074 : void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme )
    1515             : {
    1516        1074 :     m_xColorScheme = xColorScheme;
    1517        1074 : }
    1518             : 
    1519        1074 : void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider )
    1520             : {
    1521        1074 :     m_pExplicitCategoriesProvider = pExplicitCategoriesProvider;
    1522        1074 : }
    1523             : 
    1524       85343 : sal_Int32 VDataSeriesGroup::getPointCount() const
    1525             : {
    1526       85343 :     if(!m_bMaxPointCountDirty)
    1527       82263 :         return m_nMaxPointCount;
    1528             : 
    1529        3080 :     sal_Int32 nRet = 0;
    1530        3080 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = m_aSeriesVector.begin();
    1531        3080 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
    1532             : 
    1533        6112 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter)
    1534             :     {
    1535        3032 :         sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
    1536        3032 :         if( nPointCount>nRet )
    1537        2976 :             nRet = nPointCount;
    1538             :     }
    1539        3080 :     m_nMaxPointCount=nRet;
    1540        3080 :     m_aListOfCachedYValues.clear();
    1541        3080 :     m_aListOfCachedYValues.resize(m_nMaxPointCount);
    1542        3080 :     m_bMaxPointCountDirty=false;
    1543        3080 :     return nRet;
    1544             : }
    1545             : 
    1546       20876 : sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
    1547             : {
    1548       20876 :     sal_Int32 nRet = 0;
    1549       20876 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = m_aSeriesVector.begin();
    1550       20876 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
    1551             : 
    1552       20876 :     if( aSeriesIter != aSeriesEnd )
    1553       20876 :         nRet = (*aSeriesIter)->getAttachedAxisIndex();
    1554             : 
    1555       20876 :     return nRet;
    1556             : }
    1557             : 
    1558       12188 : void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
    1559             : {
    1560       12188 :     const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
    1561             : 
    1562       12188 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
    1563       12188 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
    1564             : 
    1565       12188 :     ::rtl::math::setInf(&rfMinimum, false);
    1566       12188 :     ::rtl::math::setInf(&rfMaximum, true);
    1567             : 
    1568       24600 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1569             :     {
    1570       12412 :         sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
    1571       65984 :         for(sal_Int32 nN=0;nN<nPointCount;nN++)
    1572             :         {
    1573       53572 :             double fX = (*aSeriesIter)->getXValue( nN );
    1574       53572 :             if( ::rtl::math::isNan(fX) )
    1575           4 :                 continue;
    1576       53568 :             if(rfMaximum<fX)
    1577       52360 :                 rfMaximum=fX;
    1578       53568 :             if(rfMinimum>fX)
    1579       12188 :                 rfMinimum=fX;
    1580             :         }
    1581             :     }
    1582       12188 :     if(::rtl::math::isInf(rfMinimum))
    1583           0 :         ::rtl::math::setNan(&rfMinimum);
    1584       12188 :     if(::rtl::math::isInf(rfMaximum))
    1585           0 :         ::rtl::math::setNan(&rfMaximum);
    1586       12188 : }
    1587             : 
    1588             : namespace {
    1589             : 
    1590             : /**
    1591             :  * Keep track of minimum and maximum Y values for one or more data series.
    1592             :  * When multiple data series exist, that indicates that the data series are
    1593             :  * stacked.
    1594             :  *
    1595             :  * <p>For each X value, we calculate separate Y value ranges for each data
    1596             :  * series in the first pass.  In the second pass, we calculate the minimum Y
    1597             :  * value by taking the absolute minimum value of all data series, whereas
    1598             :  * the maxium Y value is the sum of all the series maximum Y values.</p>
    1599             :  *
    1600             :  * <p>Once that's done for all X values, the final min / max Y values get
    1601             :  * calculated by taking the absolute min / max Y values across all the X
    1602             :  * values.</p>
    1603             :  */
    1604         468 : class PerXMinMaxCalculator
    1605             : {
    1606             :     typedef std::pair<double, double> MinMaxType;
    1607             :     typedef std::map<size_t, MinMaxType> SeriesMinMaxType;
    1608             :     typedef boost::ptr_map<double, SeriesMinMaxType> GroupMinMaxType;
    1609             :     typedef std::unordered_map<double, MinMaxType> TotalStoreType;
    1610             :     GroupMinMaxType maSeriesGroup;
    1611             :     size_t mnCurSeries;
    1612             : 
    1613             : public:
    1614         468 :     PerXMinMaxCalculator() : mnCurSeries(0) {}
    1615             : 
    1616         468 :     void nextSeries() { ++mnCurSeries; }
    1617             : 
    1618        1452 :     void setValue(double fX, double fY)
    1619             :     {
    1620        1452 :         SeriesMinMaxType* pStore = getByXValue(fX); // get storage for given X value.
    1621        1452 :         if (!pStore)
    1622             :             // This shouldn't happen!
    1623        1452 :             return;
    1624             : 
    1625        1452 :         SeriesMinMaxType::iterator it = pStore->lower_bound(mnCurSeries);
    1626        1452 :         if (it != pStore->end() && !pStore->key_comp()(mnCurSeries, it->first))
    1627             :         {
    1628           0 :             MinMaxType& r = it->second;
    1629             :             // A min-max pair already exists for this series.  Update it.
    1630           0 :             if (fY < r.first)
    1631           0 :                 r.first = fY;
    1632           0 :             if (r.second < fY)
    1633           0 :                 r.second = fY;
    1634             :         }
    1635             :         else
    1636             :         {
    1637             :             // No existing pair. Insert a new one.
    1638             :             pStore->insert(
    1639             :                 it, SeriesMinMaxType::value_type(
    1640        1452 :                     mnCurSeries, MinMaxType(fY,fY)));
    1641             :         }
    1642             :     }
    1643             : 
    1644         468 :     void getTotalRange(double& rfMin, double& rfMax) const
    1645             :     {
    1646         468 :         rtl::math::setNan(&rfMin);
    1647         468 :         rtl::math::setNan(&rfMax);
    1648             : 
    1649         468 :         TotalStoreType aStore;
    1650         468 :         getTotalStore(aStore);
    1651             : 
    1652         468 :         if (aStore.empty())
    1653         536 :             return;
    1654             : 
    1655         400 :         TotalStoreType::const_iterator it = aStore.begin(), itEnd = aStore.end();
    1656         400 :         rfMin = it->second.first;
    1657         400 :         rfMax = it->second.second;
    1658        1452 :         for (++it; it != itEnd; ++it)
    1659             :         {
    1660        1052 :             if (rfMin > it->second.first)
    1661         648 :                 rfMin = it->second.first;
    1662        1052 :             if (rfMax < it->second.second)
    1663         144 :                 rfMax = it->second.second;
    1664         400 :         }
    1665             :     }
    1666             : 
    1667             : private:
    1668             :     /**
    1669             :      * Parse all data and reduce them into a set of global Y value ranges per
    1670             :      * X value.
    1671             :      */
    1672         468 :     void getTotalStore(TotalStoreType& rStore) const
    1673             :     {
    1674         468 :         TotalStoreType aStore;
    1675         468 :         GroupMinMaxType::const_iterator it = maSeriesGroup.begin(), itEnd = maSeriesGroup.end();
    1676        1920 :         for (; it != itEnd; ++it)
    1677             :         {
    1678        1452 :             double fX = it->first;
    1679             : 
    1680        1452 :             const SeriesMinMaxType& rSeries = *it->second;
    1681        1452 :             SeriesMinMaxType::const_iterator itSeries = rSeries.begin(), itSeriesEnd = rSeries.end();
    1682        2904 :             for (; itSeries != itSeriesEnd; ++itSeries)
    1683             :             {
    1684        1452 :                 double fYMin = itSeries->second.first, fYMax = itSeries->second.second;
    1685        1452 :                 TotalStoreType::iterator itr = aStore.find(fX);
    1686        1452 :                 if (itr == aStore.end())
    1687             :                     // New min-max pair for give X value.
    1688             :                     aStore.insert(
    1689        1452 :                         TotalStoreType::value_type(fX, std::pair<double,double>(fYMin,fYMax)));
    1690             :                 else
    1691             :                 {
    1692           0 :                     MinMaxType& r = itr->second;
    1693           0 :                     if (fYMin < r.first)
    1694           0 :                         r.first = fYMin; // min y-value
    1695             : 
    1696           0 :                     r.second += fYMax; // accumulative max y-value.
    1697             :                 }
    1698             :             }
    1699             :         }
    1700         468 :         rStore.swap(aStore);
    1701         468 :     }
    1702             : 
    1703        1452 :     SeriesMinMaxType* getByXValue(double fX)
    1704             :     {
    1705        1452 :         GroupMinMaxType::iterator it = maSeriesGroup.find(fX);
    1706        1452 :         if (it == maSeriesGroup.end())
    1707             :         {
    1708             :             std::pair<GroupMinMaxType::iterator,bool> r =
    1709        1452 :                 maSeriesGroup.insert(fX, new SeriesMinMaxType);
    1710             : 
    1711        1452 :             if (!r.second)
    1712             :                 // insertion failed.
    1713           0 :                 return NULL;
    1714             : 
    1715        1452 :             it = r.first;
    1716             :         }
    1717             : 
    1718        1452 :         return it->second;
    1719             :     }
    1720             : };
    1721             : 
    1722             : }
    1723             : 
    1724         468 : void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
    1725             :     double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
    1726             : {
    1727         468 :     ::rtl::math::setNan(&rfMinY);
    1728         468 :     ::rtl::math::setNan(&rfMaxY);
    1729             : 
    1730         468 :     if (m_aSeriesVector.empty())
    1731             :         // No data series.  Bail out.
    1732         468 :         return;
    1733             : 
    1734         468 :     PerXMinMaxCalculator aRangeCalc;
    1735         468 :     std::vector<VDataSeries*>::const_iterator it = m_aSeriesVector.begin(), itEnd = m_aSeriesVector.end();
    1736         936 :     for (; it != itEnd; ++it)
    1737             :     {
    1738         468 :         const VDataSeries* pSeries = *it;
    1739         468 :         if (!pSeries)
    1740           0 :             continue;
    1741             : 
    1742        2376 :         for (sal_Int32 i = 0, n = pSeries->getTotalPointCount(); i < n; ++i)
    1743             :         {
    1744        1908 :             if (nAxisIndex != pSeries->getAttachedAxisIndex())
    1745         216 :                 continue;
    1746             : 
    1747        1692 :             double fX = pSeries->getXValue(i);
    1748        1692 :             if (rtl::math::isNan(fX))
    1749           4 :                 continue;
    1750             : 
    1751        1688 :             if (fX < fMinX || fX > fMaxX)
    1752             :                 // Outside specified X range.  Skip it.
    1753           0 :                 continue;
    1754             : 
    1755        1688 :             double fY = pSeries->getYValue(i);
    1756        1688 :             if (::rtl::math::isNan(fY))
    1757         236 :                 continue;
    1758             : 
    1759        1452 :             aRangeCalc.setValue(fX, fY);
    1760             :         }
    1761         468 :         aRangeCalc.nextSeries();
    1762             :     }
    1763             : 
    1764         468 :     aRangeCalc.getTotalRange(rfMinY, rfMaxY);
    1765             : }
    1766             : 
    1767       82254 : void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
    1768             :         , bool bSeparateStackingForDifferentSigns
    1769             :         , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
    1770             : {
    1771       82254 :     ::rtl::math::setInf(&rfMinimumY, false);
    1772       82254 :     ::rtl::math::setInf(&rfMaximumY, true);
    1773             : 
    1774       82254 :     sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues
    1775       82254 :     if(nCategoryIndex<0 || nCategoryIndex>=nPointCount || m_aSeriesVector.empty())
    1776       80606 :         return;
    1777             : 
    1778       71354 :     CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex];
    1779       71354 :     if( !aCachedYValues.m_bValuesDirty )
    1780             :     {
    1781             :         //return cached values
    1782       58806 :         rfMinimumY = aCachedYValues.m_fMinimumY;
    1783       58806 :         rfMaximumY = aCachedYValues.m_fMaximumY;
    1784       58806 :         return;
    1785             :     }
    1786             : 
    1787             :     double fTotalSum, fPositiveSum, fNegativeSum, fFirstPositiveY, fFirstNegativeY;
    1788       12548 :     ::rtl::math::setNan( &fTotalSum );
    1789       12548 :     ::rtl::math::setNan( &fPositiveSum );
    1790       12548 :     ::rtl::math::setNan( &fNegativeSum );
    1791       12548 :     ::rtl::math::setNan( &fFirstPositiveY );
    1792       12548 :     ::rtl::math::setNan( &fFirstNegativeY );
    1793             : 
    1794       12548 :     ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
    1795       12548 :     ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = m_aSeriesVector.end();
    1796             : 
    1797       12548 :     if( bSeparateStackingForDifferentSigns )
    1798             :     {
    1799       21304 :         for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1800             :         {
    1801       10746 :             if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
    1802         133 :                 continue;
    1803             : 
    1804       10613 :             double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
    1805       10613 :             double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
    1806             : 
    1807       10613 :             if( fValueMaxY >= 0 )
    1808             :             {
    1809       10436 :                 if( ::rtl::math::isNan( fPositiveSum ) )
    1810       10248 :                     fPositiveSum = fFirstPositiveY = fValueMaxY;
    1811             :                 else
    1812         188 :                     fPositiveSum += fValueMaxY;
    1813             :             }
    1814       10613 :             if( fValueMinY < 0 )
    1815             :             {
    1816         152 :                 if(::rtl::math::isNan( fNegativeSum ))
    1817         152 :                     fNegativeSum = fFirstNegativeY = fValueMinY;
    1818             :                 else
    1819           0 :                     fNegativeSum += fValueMinY;
    1820             :             }
    1821             :         }
    1822       10558 :         rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
    1823       10558 :         rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
    1824             :     }
    1825             :     else
    1826             :     {
    1827        4094 :         for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1828             :         {
    1829        2104 :             if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
    1830         283 :                 continue;
    1831             : 
    1832        1821 :             double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
    1833        1821 :             double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
    1834             : 
    1835        1821 :             if( ::rtl::math::isNan( fTotalSum ) )
    1836             :             {
    1837        1707 :                 rfMinimumY = fValueMinY;
    1838        1707 :                 rfMaximumY = fTotalSum = fValueMaxY;
    1839             :             }
    1840             :             else
    1841             :             {
    1842         114 :                 fTotalSum += fValueMaxY;
    1843         114 :                 if( rfMinimumY > fTotalSum )
    1844          24 :                     rfMinimumY = fTotalSum;
    1845         114 :                 if( rfMaximumY < fTotalSum )
    1846          78 :                     rfMaximumY = fTotalSum;
    1847             :             }
    1848             :         }
    1849             :     }
    1850             : 
    1851       12548 :     aCachedYValues.m_fMinimumY = rfMinimumY;
    1852       12548 :     aCachedYValues.m_fMaximumY = rfMaximumY;
    1853       12548 :     aCachedYValues.m_bValuesDirty = false;
    1854       12548 :     m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues;
    1855             : }
    1856             : 
    1857       11736 : void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
    1858             :         sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
    1859             :         , bool bSeparateStackingForDifferentSigns
    1860             :         , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
    1861             : {
    1862             :     //@todo maybe cache these values
    1863       11736 :     ::rtl::math::setInf(&rfMinimumY, false);
    1864       11736 :     ::rtl::math::setInf(&rfMaximumY, true);
    1865             : 
    1866             :     //iterate through the given categories
    1867       11736 :     if(nStartCategoryIndex<0)
    1868           0 :         nStartCategoryIndex=0;
    1869       11736 :     if(nEndCategoryIndex<0)
    1870           0 :         nEndCategoryIndex=0;
    1871       73140 :     for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ )
    1872             :     {
    1873       61404 :         double fMinimumY; ::rtl::math::setNan(&fMinimumY);
    1874       61404 :         double fMaximumY; ::rtl::math::setNan(&fMaximumY);
    1875             : 
    1876             :         this->calculateYMinAndMaxForCategory( nCatIndex
    1877       61404 :             , bSeparateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex );
    1878             : 
    1879       61404 :         if(rfMinimumY > fMinimumY)
    1880       22692 :             rfMinimumY = fMinimumY;
    1881       61404 :         if(rfMaximumY < fMaximumY)
    1882       24476 :             rfMaximumY = fMaximumY;
    1883             :     }
    1884       11736 : }
    1885             : 
    1886        1538 : double VSeriesPlotter::getTransformedDepth() const
    1887             : {
    1888        1538 :     double MinZ = m_pMainPosHelper->getLogicMinZ();
    1889        1538 :     double MaxZ = m_pMainPosHelper->getLogicMaxZ();
    1890        1538 :     m_pMainPosHelper->doLogicScaling( 0, 0, &MinZ );
    1891        1538 :     m_pMainPosHelper->doLogicScaling( 0, 0, &MaxZ );
    1892        1538 :     return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ);
    1893             : }
    1894             : 
    1895          88 : void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
    1896             :                 throw (uno::RuntimeException)
    1897             : {
    1898          88 :     if( nAxisIndex<1 )
    1899          88 :         return;
    1900             : 
    1901          88 :     m_aSecondaryValueScales[nAxisIndex]=rScale;
    1902             : }
    1903             : 
    1904       13359 : PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
    1905             : {
    1906       13359 :     PlottingPositionHelper* pRet = 0;
    1907       13359 :     if(nAxisIndex>0)
    1908             :     {
    1909         270 :         tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
    1910         270 :         if( aPosIt != m_aSecondaryPosHelperMap.end() )
    1911             :         {
    1912         248 :             pRet = aPosIt->second;
    1913             :         }
    1914          22 :         else if (m_pPosHelper)
    1915             :         {
    1916          22 :             tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex );
    1917          22 :             if( aScaleIt != m_aSecondaryValueScales.end() )
    1918             :             {
    1919          22 :                 pRet = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second );
    1920          22 :                 m_aSecondaryPosHelperMap[nAxisIndex] = pRet;
    1921             :             }
    1922             :         }
    1923             :     }
    1924       13359 :     if( !pRet )
    1925       13089 :         pRet = m_pMainPosHelper;
    1926       13359 :     if(pRet)
    1927       13359 :         pRet->setTimeResolution( m_nTimeResolution, m_aNullDate );
    1928       13359 :     return *pRet;
    1929             : }
    1930             : 
    1931           0 : void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ )
    1932             : {
    1933           0 : }
    1934             : 
    1935         883 : VDataSeries* VSeriesPlotter::getFirstSeries() const
    1936             : {
    1937         883 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
    1938         883 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
    1939         883 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1940             :     {
    1941         883 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1942         883 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd  = aZSlotIter->end();
    1943             : 
    1944         883 :         if( aXSlotIter != aXSlotEnd )
    1945             :         {
    1946         883 :             VDataSeriesGroup aSeriesGroup( *aXSlotIter );
    1947         883 :             if( aSeriesGroup.m_aSeriesVector.size() )
    1948             :             {
    1949         883 :                 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
    1950         883 :                 if(pSeries)
    1951         883 :                     return pSeries;
    1952           0 :             }
    1953             :         }
    1954             :     }
    1955           0 :     return 0;
    1956             : }
    1957             : 
    1958          55 : uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
    1959             : {
    1960          55 :     ::std::vector< OUString > aRetVector;
    1961             : 
    1962         110 :     OUString aRole;
    1963          55 :     if( m_xChartTypeModel.is() )
    1964          55 :         aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
    1965             : 
    1966          55 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
    1967          55 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
    1968         122 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1969             :     {
    1970          67 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1971          67 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd  = aZSlotIter->end();
    1972             : 
    1973          67 :         if( aXSlotIter != aXSlotEnd )
    1974             :         {
    1975          67 :             VDataSeriesGroup aSeriesGroup( *aXSlotIter );
    1976          67 :             if( aSeriesGroup.m_aSeriesVector.size() )
    1977             :             {
    1978          67 :                 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
    1979          67 :                 uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : 0 );
    1980          67 :                 if( xSeries.is() )
    1981             :                 {
    1982          67 :                     OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
    1983          67 :                     aRetVector.push_back( aSeriesName );
    1984          67 :                 }
    1985          67 :             }
    1986             :         }
    1987             :     }
    1988         110 :     return ContainerHelper::ContainerToSequence( aRetVector );
    1989             : }
    1990             : 
    1991             : namespace
    1992             : {
    1993             : struct lcl_setRefSizeAtSeriesGroup : public ::std::unary_function< VDataSeriesGroup, void >
    1994             : {
    1995        1074 :     explicit lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize ) : m_aRefSize( aRefSize ) {}
    1996        3042 :     void operator()( VDataSeriesGroup & rGroup )
    1997             :     {
    1998        3042 :         ::std::vector< VDataSeries* >::iterator aIt( rGroup.m_aSeriesVector.begin());
    1999        3042 :         const ::std::vector< VDataSeries* >::iterator aEndIt( rGroup.m_aSeriesVector.end());
    2000        6140 :         for( ; aIt != aEndIt; ++aIt )
    2001        3098 :             (*aIt)->setPageReferenceSize( m_aRefSize );
    2002        3042 :     }
    2003             : 
    2004             : private:
    2005             :     awt::Size m_aRefSize;
    2006             : };
    2007             : } // anonymous namespace
    2008             : 
    2009        1074 : void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize )
    2010             : {
    2011        1074 :     m_aPageReferenceSize = rPageRefSize;
    2012             : 
    2013             :     // set reference size also at all data series
    2014             : 
    2015        1074 :     ::std::vector< VDataSeriesGroup > aSeriesGroups( FlattenVector( m_aZSlots ));
    2016             :     ::std::for_each( aSeriesGroups.begin(), aSeriesGroups.end(),
    2017        1074 :                      lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize ));
    2018        1074 : }
    2019             : 
    2020             : //better performance for big data
    2021        1074 : void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution )
    2022             : {
    2023        1074 :     m_aCoordinateSystemResolution = rCoordinateSystemResolution;
    2024        1074 : }
    2025             : 
    2026        1074 : bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
    2027             : {
    2028        1074 :     return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel );
    2029             : }
    2030             : 
    2031        1016 : bool VSeriesPlotter::shouldSnapRectToUsedArea()
    2032             : {
    2033        1016 :     if( m_nDimension == 3 )
    2034          49 :         return false;
    2035         967 :     return true;
    2036             : }
    2037             : 
    2038         946 : std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries(
    2039             :               const awt::Size& rEntryKeyAspectRatio
    2040             :             , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion
    2041             :             , const Reference< beans::XPropertySet >& xTextProperties
    2042             :             , const Reference< drawing::XShapes >& xTarget
    2043             :             , const Reference< lang::XMultiServiceFactory >& xShapeFactory
    2044             :             , const Reference< uno::XComponentContext >& xContext
    2045             :             )
    2046             : {
    2047         946 :     std::vector< ViewLegendEntry > aResult;
    2048             : 
    2049         946 :     if( xTarget.is() )
    2050             :     {
    2051             :         //iterate through all series
    2052         946 :         bool bBreak = false;
    2053         946 :         bool bFirstSeries = true;
    2054         946 :         ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
    2055         946 :         const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    2056        1892 :         for( ; aZSlotIter!=aZSlotEnd && !bBreak; ++aZSlotIter )
    2057             :         {
    2058         946 :             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
    2059         946 :             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    2060        3499 :             for( ; aXSlotIter!=aXSlotEnd && !bBreak; ++aXSlotIter )
    2061             :             {
    2062        2553 :                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
    2063        2553 :                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
    2064        2553 :                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
    2065             :                 //iterate through all series in this x slot
    2066        5154 :                 for( ; aSeriesIter!=aSeriesEnd && !bBreak; ++aSeriesIter )
    2067             :                 {
    2068        2601 :                     VDataSeries* pSeries( *aSeriesIter );
    2069        2601 :                     if(!pSeries)
    2070           0 :                         continue;
    2071             : 
    2072             :                     std::vector< ViewLegendEntry > aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio,
    2073        2601 :                             *pSeries, xTextProperties, xTarget, xShapeFactory, xContext ) );
    2074             : 
    2075             :                     //add series entries to the result now
    2076             : 
    2077             :                     // use only the first series if VaryColorsByPoint is set for the first series
    2078        2601 :                     if( bFirstSeries && pSeries->isVaryColorsByPoint() )
    2079          28 :                         bBreak = true;
    2080        2601 :                     bFirstSeries = false;
    2081             : 
    2082             :                     // add entries reverse if chart is stacked in y-direction and the legend is not wide.
    2083             :                     // If the legend is wide and we have a stacked bar-chart the normal order
    2084             :                     // is the correct one
    2085        2601 :                     bool bReverse = false;
    2086        2601 :                     if( eLegendExpansion != ::com::sun::star::chart::ChartLegendExpansion_WIDE )
    2087             :                     {
    2088        2521 :                         StackingDirection eStackingDirection( pSeries->getStackingDirection() );
    2089        2521 :                         bReverse = ( eStackingDirection == StackingDirection_Y_STACKING );
    2090             : 
    2091             :                         //todo: respect direction of axis in future
    2092             :                     }
    2093             : 
    2094        2601 :                     if(bReverse)
    2095          56 :                         aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
    2096             :                     else
    2097        2545 :                         aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() );
    2098        2601 :                 }
    2099             :             }
    2100             :         }
    2101             :     }
    2102             : 
    2103         946 :     return aResult;
    2104             : }
    2105             : 
    2106         902 : ::std::vector< VDataSeries* > VSeriesPlotter::getAllSeries()
    2107             : {
    2108         902 :     ::std::vector< VDataSeries* > aAllSeries;
    2109         902 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator            aZSlotIter = m_aZSlots.begin();
    2110         902 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
    2111        1804 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    2112             :     {
    2113         902 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
    2114         902 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    2115        3376 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    2116             :         {
    2117        2474 :             ::std::vector< VDataSeries* > aSeriesList = aXSlotIter->m_aSeriesVector;
    2118        2474 :             aAllSeries.insert( aAllSeries.end(), aSeriesList.begin(), aSeriesList.end() );
    2119        2474 :         }
    2120             :     }
    2121         902 :     return aAllSeries;
    2122             : }
    2123             : 
    2124             : namespace
    2125             : {
    2126         179 : bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine )
    2127             : {
    2128         179 :     bool bHasVisibleLine = false;
    2129         179 :     rbHasDashedLine = false;
    2130         179 :     drawing::LineStyle aLineStyle = drawing::LineStyle_NONE;
    2131         179 :     if( xProps.is() && ( xProps->getPropertyValue( "LineStyle") >>= aLineStyle ) )
    2132             :     {
    2133         179 :         if( aLineStyle != drawing::LineStyle_NONE )
    2134         148 :             bHasVisibleLine = true;
    2135         179 :         if( aLineStyle == drawing::LineStyle_DASH )
    2136           0 :             rbHasDashedLine = true;
    2137             :     }
    2138         179 :     return bHasVisibleLine;
    2139             : }
    2140             : 
    2141        2488 : bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine )
    2142             : {
    2143        2488 :     bool bHasRegressionCurves = false;
    2144        2488 :     Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
    2145        2488 :     if( xRegrCont.is())
    2146             :     {
    2147        2488 :         Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves() );
    2148        2488 :         sal_Int32 i = 0, nCount = aCurves.getLength();
    2149        2515 :         for( i=0; i<nCount; ++i )
    2150             :         {
    2151          27 :             if( aCurves[i].is() )
    2152             :             {
    2153          27 :                 bHasRegressionCurves = true;
    2154          27 :                 lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine );
    2155             :             }
    2156        2488 :         }
    2157             :     }
    2158        2488 :     return bHasRegressionCurves;
    2159             : }
    2160             : }
    2161        3330 : LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle()
    2162             : {
    2163        3330 :     return LegendSymbolStyle_BOX;
    2164             : }
    2165             : 
    2166         962 : awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio()
    2167             : {
    2168         962 :     awt::Size aRet(1000,1000);
    2169         962 :     if( m_nDimension==3 )
    2170          60 :         return aRet;
    2171             : 
    2172         902 :     bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle_LINE);
    2173         902 :     bool bHasLines = false;
    2174         902 :     bool bHasDashedLines = false;
    2175         902 :     ::std::vector< VDataSeries* > aAllSeries( getAllSeries() );
    2176         902 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = aAllSeries.begin();
    2177         902 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = aAllSeries.end();
    2178             :     //iterate through all series
    2179        3390 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    2180             :     {
    2181        2488 :         if( bSeriesAllowsLines )
    2182             :         {
    2183         152 :             bool bCurrentDashed = false;
    2184         152 :             if( lcl_HasVisibleLine( (*aSeriesIter)->getPropertiesOfSeries(), bCurrentDashed ) )
    2185             :             {
    2186         126 :                 bHasLines = true;
    2187         126 :                 if( bCurrentDashed )
    2188             :                 {
    2189           0 :                     bHasDashedLines = true;
    2190           0 :                     break;
    2191             :                 }
    2192             :             }
    2193             :         }
    2194        2488 :         bool bRegressionHasDashedLines=false;
    2195        2488 :         if( lcl_HasRegressionCurves( **aSeriesIter, bRegressionHasDashedLines ) )
    2196             :         {
    2197          13 :             bHasLines = true;
    2198          13 :             if( bRegressionHasDashedLines )
    2199             :             {
    2200           0 :                 bHasDashedLines = true;
    2201           0 :                 break;
    2202             :             }
    2203             :         }
    2204             :     }
    2205         902 :     if( bHasLines )
    2206             :     {
    2207          72 :         if( bHasDashedLines )
    2208           0 :             aRet = awt::Size(1600,-1);
    2209             :         else
    2210          72 :             aRet = awt::Size(800,-1);
    2211             :     }
    2212         902 :     return aRet;
    2213             : }
    2214             : 
    2215        2539 : uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ )
    2216             : {
    2217        2539 :     return uno::Any();
    2218             : }
    2219             : 
    2220        2573 : Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForSeries(
    2221             :                   const awt::Size& rEntryKeyAspectRatio
    2222             :                 , const VDataSeries& rSeries
    2223             :                 , const Reference< drawing::XShapes >& xTarget
    2224             :                 , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
    2225             : {
    2226             : 
    2227        2573 :     LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
    2228        2573 :     uno::Any aExplicitSymbol( this->getExplicitSymbol( rSeries ) );
    2229             : 
    2230             :     VLegendSymbolFactory::tPropertyType ePropType =
    2231        2573 :         VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
    2232             : 
    2233             :     // todo: maybe the property-style does not solely depend on the
    2234             :     // legend-symbol type
    2235        2573 :     switch( eLegendSymbolStyle )
    2236             :     {
    2237             :         case LegendSymbolStyle_LINE:
    2238         152 :             ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
    2239         152 :             break;
    2240             :         default:
    2241        2421 :             break;
    2242             :     };
    2243             :     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2244             :         xTarget, eLegendSymbolStyle, xShapeFactory
    2245        2573 :             , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
    2246             : 
    2247        2573 :     return xShape;
    2248             : }
    2249             : 
    2250         124 : Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForPoint(
    2251             :                   const awt::Size& rEntryKeyAspectRatio
    2252             :                 , const VDataSeries& rSeries
    2253             :                 , sal_Int32 nPointIndex
    2254             :                 , const Reference< drawing::XShapes >& xTarget
    2255             :                 , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
    2256             : {
    2257             : 
    2258         124 :     LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
    2259         124 :     uno::Any aExplicitSymbol( this->getExplicitSymbol(rSeries,nPointIndex) );
    2260             : 
    2261             :     VLegendSymbolFactory::tPropertyType ePropType =
    2262         124 :         VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
    2263             : 
    2264             :     // todo: maybe the property-style does not solely depend on the
    2265             :     // legend-symbol type
    2266         124 :     switch( eLegendSymbolStyle )
    2267             :     {
    2268             :         case LegendSymbolStyle_LINE:
    2269           0 :             ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
    2270           0 :             break;
    2271             :         default:
    2272         124 :             break;
    2273             :     };
    2274             : 
    2275             :     // the default properties for the data point are the data series properties.
    2276             :     // If a data point has own attributes overwrite them
    2277         124 :     Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() );
    2278         248 :     Reference< beans::XPropertySet > xPointSet( xSeriesProps );
    2279         124 :     if( rSeries.isAttributedDataPoint( nPointIndex ) )
    2280          96 :         xPointSet.set( rSeries.getPropertiesOfPoint( nPointIndex ));
    2281             : 
    2282             :     // if a data point has no own color use a color fom the diagram's color scheme
    2283         124 :     if( ! rSeries.hasPointOwnColor( nPointIndex ))
    2284             :     {
    2285          28 :         Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY );
    2286          28 :         if( xCloneable.is() && m_xColorScheme.is() )
    2287             :         {
    2288          28 :             xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY );
    2289          28 :             Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY );
    2290          28 :             if( xChild.is())
    2291           0 :                 xChild->setParent( xSeriesProps );
    2292             : 
    2293             :             OSL_ASSERT( xPointSet.is());
    2294          28 :             xPointSet->setPropertyValue(
    2295          28 :                 "Color", uno::makeAny( m_xColorScheme->getColorByIndex( nPointIndex )));
    2296          28 :         }
    2297             :     }
    2298             : 
    2299             :     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2300         248 :         xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol ));
    2301             : 
    2302         248 :     return xShape;
    2303             : }
    2304             : 
    2305        2601 : std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
    2306             :               const awt::Size& rEntryKeyAspectRatio
    2307             :             , const VDataSeries& rSeries
    2308             :             , const Reference< beans::XPropertySet >& xTextProperties
    2309             :             , const Reference< drawing::XShapes >& xTarget
    2310             :             , const Reference< lang::XMultiServiceFactory >& xShapeFactory
    2311             :             , const Reference< uno::XComponentContext >& xContext
    2312             :             )
    2313             : {
    2314        2601 :     std::vector< ViewLegendEntry > aResult;
    2315             : 
    2316        2601 :     if( ! ( xShapeFactory.is() && xTarget.is() && xContext.is() ) )
    2317           0 :         return aResult;
    2318             : 
    2319             :     try
    2320             :     {
    2321        2601 :         ViewLegendEntry aEntry;
    2322        5031 :         OUString aLabelText;
    2323        2601 :         bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint();
    2324        2601 :         if( bVaryColorsByPoint )
    2325             :         {
    2326          28 :             Sequence< OUString > aCategoryNames;
    2327          28 :             if( m_pExplicitCategoriesProvider )
    2328          28 :                 aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories();
    2329             : 
    2330         136 :             for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
    2331             :             {
    2332             :                 // symbol
    2333         108 :                 uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2334             : 
    2335             :                 // create the symbol
    2336             :                 Reference< drawing::XShape > xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio,
    2337         216 :                     rSeries, nIdx, xSymbolGroup, xShapeFactory ) );
    2338             : 
    2339             :                 // set CID to symbol for selection
    2340         108 :                 if( xShape.is() )
    2341             :                 {
    2342         108 :                     aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2343             : 
    2344         108 :                     OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) );
    2345         108 :                     aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2346         216 :                     OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2347         216 :                     AbstractShapeFactory::setShapeName( xShape, aCID );
    2348             :                 }
    2349             : 
    2350             :                 // label
    2351         108 :                 aLabelText = aCategoryNames[nIdx];
    2352         108 :                 if( xShape.is() || !aLabelText.isEmpty() )
    2353             :                 {
    2354         108 :                     aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
    2355         108 :                     aResult.push_back(aEntry);
    2356             :                 }
    2357         136 :             }
    2358             :         }
    2359             :         else
    2360             :         {
    2361             :             // symbol
    2362        2573 :             uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2363             : 
    2364             :             // create the symbol
    2365             :             Reference< drawing::XShape > xShape( this->createLegendSymbolForSeries(
    2366        5146 :                 rEntryKeyAspectRatio, rSeries, xSymbolGroup, xShapeFactory ) );
    2367             : 
    2368             :             // set CID to symbol for selection
    2369        2573 :             if( xShape.is())
    2370             :             {
    2371        2573 :                 aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2372             : 
    2373        2573 :                 OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2374        5146 :                 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2375        5146 :                 AbstractShapeFactory::setShapeName( xShape, aCID );
    2376             :             }
    2377             : 
    2378             :             // label
    2379        2573 :             aLabelText = ( DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y") );
    2380        2573 :             aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
    2381             : 
    2382        5146 :             aResult.push_back(aEntry);
    2383             :         }
    2384             : 
    2385             :         // don't show legend entry of regression curve & friends if this type of chart
    2386             :         // doesn't support statistics #i63016#, fdo#37197
    2387        2601 :         if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ))
    2388         171 :             return aResult;
    2389             : 
    2390        4860 :         Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
    2391        2430 :         if( xRegrCont.is())
    2392             :         {
    2393        2430 :             Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
    2394        2430 :             sal_Int32 i = 0, nCount = aCurves.getLength();
    2395        2457 :             for( i=0; i<nCount; ++i )
    2396             :             {
    2397          27 :                 if( aCurves[i].is() )
    2398             :                 {
    2399             :                     //label
    2400          27 :                     OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
    2401          27 :                     replaceParamterInString( aResStr, "%SERIESNAME", aLabelText );
    2402          27 :                     aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
    2403             : 
    2404             :                     // symbol
    2405          54 :                     uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2406             : 
    2407             :                     // create the symbol
    2408             :                     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2409             :                         xSymbolGroup, LegendSymbolStyle_LINE, xShapeFactory,
    2410          27 :                         Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
    2411          81 :                         VLegendSymbolFactory::PROP_TYPE_LINE, uno::Any() ));
    2412             : 
    2413             :                     // set CID to symbol for selection
    2414          27 :                     if( xShape.is())
    2415             :                     {
    2416          27 :                         aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2417             : 
    2418          27 :                         bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
    2419          27 :                         ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
    2420          27 :                         OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
    2421          27 :                         aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2422          54 :                         OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2423          54 :                         AbstractShapeFactory::setShapeName( xShape, aCID );
    2424             :                     }
    2425             : 
    2426          54 :                     aResult.push_back(aEntry);
    2427             :                 }
    2428        2430 :             }
    2429        2430 :         }
    2430             :     }
    2431           0 :     catch( const uno::Exception & ex )
    2432             :     {
    2433             :         ASSERT_EXCEPTION( ex );
    2434             :     }
    2435        2430 :     return aResult;
    2436             : }
    2437             : 
    2438        1074 : VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
    2439             :     const uno::Reference<XChartType>& xChartTypeModel
    2440             :     , sal_Int32 nDimensionCount
    2441             :     , bool bExcludingPositioning )
    2442             : {
    2443        1074 :     if (!xChartTypeModel.is())
    2444           0 :         return NULL;
    2445             : 
    2446        1074 :     OUString aChartType = xChartTypeModel->getChartType();
    2447             : 
    2448        1074 :     VSeriesPlotter* pRet=NULL;
    2449        1074 :     if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) )
    2450         884 :         pRet = new BarChart(xChartTypeModel,nDimensionCount);
    2451         190 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) )
    2452           0 :         pRet = new BarChart(xChartTypeModel,nDimensionCount);
    2453         190 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) )
    2454           4 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,true);
    2455         186 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) )
    2456          85 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true);
    2457         101 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) )
    2458          53 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
    2459          48 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) )
    2460           3 :         pRet = new BubbleChart(xChartTypeModel,nDimensionCount);
    2461          45 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
    2462          37 :         pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning );
    2463           8 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
    2464           0 :         pRet = new NetChart(xChartTypeModel,nDimensionCount,true,new PolarPlottingPositionHelper());
    2465           8 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
    2466           2 :         pRet = new NetChart(xChartTypeModel,nDimensionCount,false,new PolarPlottingPositionHelper());
    2467           6 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
    2468           6 :         pRet = new CandleStickChart(xChartTypeModel,nDimensionCount);
    2469             :     else
    2470           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
    2471        1074 :     return pRet;
    2472             : }
    2473             : 
    2474          57 : } //namespace chart
    2475             : 
    2476             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11