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

Generated by: LCOV version 1.10